1
|
#! /bin/sh
|
2
|
|
3
|
# Install GRUB on your drive.
|
4
|
# Copyright (C) 1999,2000,2001,2002,2003,2004 Free Software Foundation, Inc.
|
5
|
#
|
6
|
# This file is free software; you can redistribute it and/or modify it
|
7
|
# under the terms of the GNU General Public License as published by
|
8
|
# the Free Software Foundation; either version 2 of the License, or
|
9
|
# (at your option) any later version.
|
10
|
#
|
11
|
# This program is distributed in the hope that it will be useful, but
|
12
|
# WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14
|
# General Public License for more details.
|
15
|
#
|
16
|
# You should have received a copy of the GNU General Public License
|
17
|
# along with this program; if not, write to the Free Software
|
18
|
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
19
|
|
20
|
# Initialize some variables.
|
21
|
prefix=/usr/local
|
22
|
exec_prefix=${prefix}
|
23
|
sbindir=${exec_prefix}/sbin
|
24
|
libdir=/usr/local/share
|
25
|
PACKAGE=grub
|
26
|
VERSION=0.97
|
27
|
host_cpu=i386
|
28
|
host_os=freebsd7.0
|
29
|
host_vendor=freebsd
|
30
|
pkglibdir=${libdir}/${PACKAGE}/${host_cpu}-${host_vendor}
|
31
|
|
32
|
grub_shell=${sbindir}/grub
|
33
|
grub_set_default=${sbindir}/grub-set-default
|
34
|
log_file=/tmp/grub-install.log.$$
|
35
|
img_file=/tmp/grub-install.img.$$
|
36
|
rootdir=
|
37
|
grub_prefix=/boot/grub
|
38
|
|
39
|
install_device=
|
40
|
no_floppy=
|
41
|
force_lba=
|
42
|
recheck=no
|
43
|
debug=no
|
44
|
|
45
|
# look for secure tempfile creation wrappers on this platform
|
46
|
if test -x /bin/tempfile; then
|
47
|
mklog="/bin/tempfile --prefix=grub"
|
48
|
mkimg="/bin/tempfile --prefix=grub"
|
49
|
elif test -x /bin/mktemp; then
|
50
|
mklog="/bin/mktemp /tmp/grub-install.log.XXXXXX"
|
51
|
mkimg="/bin/mktemp /tmp/grub-install.img.XXXXXX"
|
52
|
else
|
53
|
mklog=""
|
54
|
mkimg=""
|
55
|
fi
|
56
|
|
57
|
# Usage: usage
|
58
|
# Print the usage.
|
59
|
usage () {
|
60
|
cat <<EOF
|
61
|
Usage: grub-install [OPTION] install_device
|
62
|
Install GRUB on your drive.
|
63
|
|
64
|
-h, --help print this message and exit
|
65
|
-v, --version print the version information and exit
|
66
|
--root-directory=DIR install GRUB images under the directory DIR
|
67
|
instead of the root directory
|
68
|
--grub-shell=FILE use FILE as the grub shell
|
69
|
--no-floppy do not probe any floppy drive
|
70
|
--force-lba force GRUB to use LBA mode even for a buggy
|
71
|
BIOS
|
72
|
--recheck probe a device map even if it already exists
|
73
|
|
74
|
INSTALL_DEVICE can be a GRUB device name or a system device filename.
|
75
|
|
76
|
grub-install copies GRUB images into the DIR/boot directory specfied by
|
77
|
--root-directory, and uses the grub shell to install grub into the boot
|
78
|
sector.
|
79
|
|
80
|
Report bugs to <bug-grub@gnu.org>.
|
81
|
EOF
|
82
|
}
|
83
|
|
84
|
# Usage: convert os_device
|
85
|
# Convert an OS device to the corresponding GRUB drive.
|
86
|
# This part is OS-specific.
|
87
|
convert () {
|
88
|
# First, check if the device file exists.
|
89
|
if test -e "$1"; then
|
90
|
:
|
91
|
else
|
92
|
echo "$1: Not found or not a block device." 1>&2
|
93
|
exit 1
|
94
|
fi
|
95
|
|
96
|
# Break the device name into the disk part and the partition part.
|
97
|
case "$host_os" in
|
98
|
linux*)
|
99
|
tmp_disk=`echo "$1" | sed -e 's%\([sh]d[a-z]\)[0-9]*$%\1%' \
|
100
|
-e 's%\(d[0-9]*\)p[0-9]*$%\1%' \
|
101
|
-e 's%\(fd[0-9]*\)$%\1%' \
|
102
|
-e 's%/part[0-9]*$%/disc%' \
|
103
|
-e 's%\(c[0-7]d[0-9]*\).*$%\1%'`
|
104
|
tmp_part=`echo "$1" | sed -e 's%.*/[sh]d[a-z]\([0-9]*\)$%\1%' \
|
105
|
-e 's%.*d[0-9]*p%%' \
|
106
|
-e 's%.*/fd[0-9]*$%%' \
|
107
|
-e 's%.*/floppy/[0-9]*$%%' \
|
108
|
-e 's%.*/\(disc\|part\([0-9]*\)\)$%\2%' \
|
109
|
-e 's%.*c[0-7]d[0-9]*p%%'`
|
110
|
;;
|
111
|
gnu*)
|
112
|
tmp_disk=`echo "$1" | sed 's%\([sh]d[0-9]*\).*%\1%'`
|
113
|
tmp_part=`echo "$1" | sed "s%$tmp_disk%%"` ;;
|
114
|
freebsd[234]* | kfreebsd*-gnu)
|
115
|
tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%r\1%' \
|
116
|
| sed 's%r\{0,1\}\(da[0-9]*\).*$%r\1%'`
|
117
|
tmp_part=`echo "$1" \
|
118
|
| sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
|
119
|
| sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"`
|
120
|
;;
|
121
|
freebsd[567]*)
|
122
|
tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([saw]d[0-9]*\).*$%\1%' \
|
123
|
| sed 's%r\{0,1\}\(da[0-9]*\).*$%\1%'`
|
124
|
tmp_part=`echo "$1" \
|
125
|
| sed "s%.*/r\{0,1\}[saw]d[0-9]\(s[0-9]*[a-h]\)%\1%" \
|
126
|
| sed "s%.*/r\{0,1\}da[0-9]\(s[0-9]*[a-h]\)%\1%"`
|
127
|
;;
|
128
|
netbsd* | knetbsd*-gnu)
|
129
|
tmp_disk=`echo "$1" | sed 's%r\{0,1\}\([sw]d[0-9]*\).*$%r\1d%' \
|
130
|
| sed 's%r\{0,1\}\(fd[0-9]*\).*$%r\1a%'`
|
131
|
tmp_part=`echo "$1" \
|
132
|
| sed "s%.*/r\{0,1\}[sw]d[0-9]\([abe-p]\)%\1%"`
|
133
|
;;
|
134
|
*)
|
135
|
echo "grub-install does not support your OS yet." 1>&2
|
136
|
exit 1 ;;
|
137
|
esac
|
138
|
|
139
|
# Get the drive name.
|
140
|
tmp_drive=`grep -v '^#' $device_map | grep "$tmp_disk *$" \
|
141
|
| sed 's%.*\(([hf]d[0-9][a-g0-9,]*)\).*%\1%'`
|
142
|
|
143
|
# If not found, print an error message and exit.
|
144
|
if test "x$tmp_drive" = x; then
|
145
|
echo "$1 does not have any corresponding BIOS drive." 1>&2
|
146
|
exit 1
|
147
|
fi
|
148
|
|
149
|
if test "x$tmp_part" != x; then
|
150
|
# If a partition is specified, we need to translate it into the
|
151
|
# GRUB's syntax.
|
152
|
case "$host_os" in
|
153
|
linux*)
|
154
|
echo "$tmp_drive" | sed "s%)$%,`expr $tmp_part - 1`)%" ;;
|
155
|
gnu*)
|
156
|
if echo $tmp_part | grep "^s" >/dev/null; then
|
157
|
tmp_pc_slice=`echo $tmp_part \
|
158
|
| sed "s%s\([0-9]*\)[a-g]*$%\1%"`
|
159
|
tmp_drive=`echo "$tmp_drive" \
|
160
|
| sed "s%)%,\`expr "$tmp_pc_slice" - 1\`)%"`
|
161
|
fi
|
162
|
if echo $tmp_part | grep "[a-g]$" >/dev/null; then
|
163
|
tmp_bsd_partition=`echo "$tmp_part" \
|
164
|
| sed "s%[^a-g]*\([a-g]\)$%\1%"`
|
165
|
tmp_drive=`echo "$tmp_drive" \
|
166
|
| sed "s%)%,$tmp_bsd_partition)%"`
|
167
|
fi
|
168
|
echo "$tmp_drive" ;;
|
169
|
freebsd* | kfreebsd*-gnu)
|
170
|
if echo $tmp_part | grep "^s" >/dev/null; then
|
171
|
tmp_pc_slice=`echo $tmp_part \
|
172
|
| sed "s%s\([0-9]*\)[a-h]*$%\1%"`
|
173
|
tmp_drive=`echo "$tmp_drive" \
|
174
|
| sed "s%)%,\`expr "$tmp_pc_slice" - 1\`)%"`
|
175
|
fi
|
176
|
if echo $tmp_part | grep "[a-h]$" >/dev/null; then
|
177
|
tmp_bsd_partition=`echo "$tmp_part" \
|
178
|
| sed "s%s\{0,1\}[0-9]*\([a-h]\)$%\1%"`
|
179
|
tmp_drive=`echo "$tmp_drive" \
|
180
|
| sed "s%)%,$tmp_bsd_partition)%"`
|
181
|
fi
|
182
|
echo "$tmp_drive" ;;
|
183
|
netbsd* | knetbsd*-gnu)
|
184
|
if echo $tmp_part | grep "^[abe-p]$" >/dev/null; then
|
185
|
tmp_bsd_partition=`echo "$tmp_part" \
|
186
|
| sed "s%\([a-p]\)$%\1%"`
|
187
|
tmp_drive=`echo "$tmp_drive" \
|
188
|
| sed "s%)%,$tmp_bsd_partition)%"`
|
189
|
fi
|
190
|
echo "$tmp_drive" ;;
|
191
|
esac
|
192
|
else
|
193
|
# If no partition is specified, just print the drive name.
|
194
|
echo "$tmp_drive"
|
195
|
fi
|
196
|
}
|
197
|
|
198
|
# Usage: resolve_symlink file
|
199
|
# Find the real file/device that file points at
|
200
|
resolve_symlink () {
|
201
|
tmp_fname=$1
|
202
|
# Resolve symlinks
|
203
|
while test -L $tmp_fname; do
|
204
|
tmp_new_fname=`ls -al $tmp_fname | sed -n 's%.*-> \(.*\)%\1%p'`
|
205
|
if test -z "$tmp_new_fname"; then
|
206
|
echo "Unrecognized ls output" 2>&1
|
207
|
exit 1
|
208
|
fi
|
209
|
|
210
|
# Convert relative symlinks
|
211
|
case $tmp_new_fname in
|
212
|
/*) tmp_fname="$tmp_new_fname"
|
213
|
;;
|
214
|
*) tmp_fname="`echo $tmp_fname | sed 's%/[^/]*$%%'`/$tmp_new_fname"
|
215
|
;;
|
216
|
esac
|
217
|
done
|
218
|
echo "$tmp_fname"
|
219
|
}
|
220
|
|
221
|
# Usage: find_device file
|
222
|
# Find block device on which the file resides.
|
223
|
find_device () {
|
224
|
# For now, this uses the program `df' to get the device name, but is
|
225
|
# this really portable?
|
226
|
tmp_fname=`df $1/ | sed -n 's%.*\(/dev/[^ ]*\).*%\1%p'`
|
227
|
|
228
|
if test -z "$tmp_fname"; then
|
229
|
echo "Could not find device for $1" 2>&1
|
230
|
exit 1
|
231
|
fi
|
232
|
|
233
|
tmp_fname=`resolve_symlink $tmp_fname`
|
234
|
|
235
|
echo "$tmp_fname"
|
236
|
}
|
237
|
|
238
|
# Check the arguments.
|
239
|
for option in "$@"; do
|
240
|
case "$option" in
|
241
|
-h | --help)
|
242
|
usage
|
243
|
exit 0 ;;
|
244
|
-v | --version)
|
245
|
echo "grub-install (GNU GRUB ${VERSION})"
|
246
|
exit 0 ;;
|
247
|
--root-directory=*)
|
248
|
rootdir=`echo "$option" | sed 's/--root-directory=//'` ;;
|
249
|
--grub-shell=*)
|
250
|
grub_shell=`echo "$option" | sed 's/--grub-shell=//'` ;;
|
251
|
--no-floppy)
|
252
|
no_floppy="--no-floppy" ;;
|
253
|
--force-lba)
|
254
|
force_lba="--force-lba" ;;
|
255
|
--recheck)
|
256
|
recheck=yes ;;
|
257
|
# This is an undocumented feature...
|
258
|
--debug)
|
259
|
debug=yes ;;
|
260
|
-*)
|
261
|
echo "Unrecognized option \`$option'" 1>&2
|
262
|
usage
|
263
|
exit 1
|
264
|
;;
|
265
|
*)
|
266
|
if test "x$install_device" != x; then
|
267
|
echo "More than one install_devices?" 1>&2
|
268
|
usage
|
269
|
exit 1
|
270
|
fi
|
271
|
install_device="${option}" ;;
|
272
|
esac
|
273
|
done
|
274
|
|
275
|
if test "x$install_device" = x; then
|
276
|
echo "install_device not specified." 1>&2
|
277
|
usage
|
278
|
exit 1
|
279
|
fi
|
280
|
|
281
|
# If the debugging feature is enabled, print commands.
|
282
|
if test $debug = yes; then
|
283
|
set -x
|
284
|
fi
|
285
|
|
286
|
# Initialize these directories here, since ROOTDIR was initialized.
|
287
|
case "$host_os" in
|
288
|
netbsd* | openbsd*)
|
289
|
# Because /boot is used for the boot block in NetBSD and OpenBSD, use /grub
|
290
|
# instead of /boot/grub.
|
291
|
grub_prefix=/grub
|
292
|
bootdir=${rootdir}
|
293
|
;;
|
294
|
*)
|
295
|
# Use /boot/grub by default.
|
296
|
bootdir=${rootdir}/boot
|
297
|
;;
|
298
|
esac
|
299
|
|
300
|
grubdir=${bootdir}/grub
|
301
|
device_map=${grubdir}/device.map
|
302
|
|
303
|
# Check if GRUB is installed.
|
304
|
# This is necessary, because the user can specify "grub --read-only".
|
305
|
set $grub_shell dummy
|
306
|
if test -f "$1"; then
|
307
|
:
|
308
|
else
|
309
|
echo "$1: Not found." 1>&2
|
310
|
exit 1
|
311
|
fi
|
312
|
|
313
|
if test -f "$pkglibdir/stage1"; then
|
314
|
:
|
315
|
else
|
316
|
echo "${pkglibdir}/stage1: Not found." 1>&2
|
317
|
exit 1
|
318
|
fi
|
319
|
|
320
|
if test -f "$pkglibdir/stage2"; then
|
321
|
:
|
322
|
else
|
323
|
echo "${pkglibdir}/stage2: Not found." 1>&2
|
324
|
exit 1
|
325
|
fi
|
326
|
|
327
|
# Don't check for *stage1_5, because it is not fatal even if any
|
328
|
# Stage 1.5 does not exist.
|
329
|
|
330
|
# Create the GRUB directory if it is not present.
|
331
|
test -d "$bootdir" || mkdir "$bootdir" || exit 1
|
332
|
test -d "$grubdir" || mkdir "$grubdir" || exit 1
|
333
|
|
334
|
# If --recheck is specified, remove the device map, if present.
|
335
|
if test $recheck = yes; then
|
336
|
rm -f $device_map
|
337
|
fi
|
338
|
|
339
|
# Create the device map file if it is not present.
|
340
|
if test -f "$device_map"; then
|
341
|
:
|
342
|
else
|
343
|
# Create a safe temporary file.
|
344
|
test -n "$mklog" && log_file=`$mklog`
|
345
|
|
346
|
$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
347
|
quit
|
348
|
EOF
|
349
|
if grep "Error [0-9]*: " $log_file >/dev/null; then
|
350
|
cat $log_file 1>&2
|
351
|
exit 1
|
352
|
fi
|
353
|
|
354
|
rm -f $log_file
|
355
|
fi
|
356
|
|
357
|
# Make sure that there is no duplicated entry.
|
358
|
tmp=`sed -n '/^([fh]d[0-9]*)/s/\(^(.*)\).*/\1/p' $device_map \
|
359
|
| sort | uniq -d | sed -n 1p`
|
360
|
if test -n "$tmp"; then
|
361
|
echo "The drive $tmp is defined multiple times in the device map $device_map" 1>&2
|
362
|
exit 1
|
363
|
fi
|
364
|
|
365
|
# Check for INSTALL_DEVICE.
|
366
|
case "$install_device" in
|
367
|
/dev/*)
|
368
|
install_device=`resolve_symlink "$install_device"`
|
369
|
install_drive=`convert "$install_device"`
|
370
|
# I don't know why, but some shells wouldn't die if exit is
|
371
|
# called in a function.
|
372
|
if test "x$install_drive" = x; then
|
373
|
exit 1
|
374
|
fi ;;
|
375
|
\([hf]d[0-9]*\))
|
376
|
install_drive="$install_device" ;;
|
377
|
[hf]d[0-9]*)
|
378
|
# The GRUB format with no parenthesis.
|
379
|
install_drive="($install_device)" ;;
|
380
|
*)
|
381
|
echo "Format of install_device not recognized." 1>&2
|
382
|
usage
|
383
|
exit 1 ;;
|
384
|
esac
|
385
|
|
386
|
# Get the root drive.
|
387
|
root_device=`find_device ${rootdir}`
|
388
|
bootdir_device=`find_device ${bootdir}`
|
389
|
|
390
|
# Check if the boot directory is in the same device as the root directory.
|
391
|
if test "x$root_device" != "x$bootdir_device"; then
|
392
|
# Perhaps the user has a separate boot partition.
|
393
|
root_device=$bootdir_device
|
394
|
grub_prefix="/grub"
|
395
|
fi
|
396
|
|
397
|
# Convert the root device to a GRUB drive.
|
398
|
root_drive=`convert "$root_device"`
|
399
|
if test "x$root_drive" = x; then
|
400
|
exit 1
|
401
|
fi
|
402
|
|
403
|
# Check if the root directory exists in the same device as the grub
|
404
|
# directory.
|
405
|
grubdir_device=`find_device ${grubdir}`
|
406
|
|
407
|
if test "x$grubdir_device" != "x$root_device"; then
|
408
|
# For now, cannot deal with this situation.
|
409
|
cat <<EOF 1>&2
|
410
|
You must set the root directory by the option --root-directory, because
|
411
|
$grubdir does not exist in the root device $root_device.
|
412
|
EOF
|
413
|
exit 1
|
414
|
fi
|
415
|
|
416
|
# Copy the GRUB images to the GRUB directory.
|
417
|
for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do
|
418
|
rm -f $file || exit 1
|
419
|
done
|
420
|
for file in \
|
421
|
${pkglibdir}/stage1 ${pkglibdir}/stage2 ${pkglibdir}/*stage1_5; do
|
422
|
cp -f $file ${grubdir} || exit 1
|
423
|
done
|
424
|
|
425
|
# Make a default file.
|
426
|
${grub_set_default} --root-directory=${rootdir} default
|
427
|
|
428
|
# Make sure that GRUB reads the same images as the host OS.
|
429
|
test -n "$mkimg" && img_file=`$mkimg`
|
430
|
test -n "$mklog" && log_file=`$mklog`
|
431
|
|
432
|
for file in ${grubdir}/stage1 ${grubdir}/stage2 ${grubdir}/*stage1_5; do
|
433
|
count=5
|
434
|
tmp=`echo $file | sed "s|^${grubdir}|${grub_prefix}|"`
|
435
|
while test $count -gt 0; do
|
436
|
$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
437
|
dump ${root_drive}${tmp} ${img_file}
|
438
|
quit
|
439
|
EOF
|
440
|
if grep "Error [0-9]*: " $log_file >/dev/null; then
|
441
|
:
|
442
|
elif cmp $file $img_file >/dev/null; then
|
443
|
break
|
444
|
fi
|
445
|
sleep 1
|
446
|
count=`expr $count - 1`
|
447
|
done
|
448
|
if test $count -eq 0; then
|
449
|
echo "The file $file not read correctly." 1>&2
|
450
|
echo
|
451
|
fi
|
452
|
done
|
453
|
|
454
|
rm -f $img_file
|
455
|
rm -f $log_file
|
456
|
|
457
|
# Create a safe temporary file.
|
458
|
test -n "$mklog" && log_file=`$mklog`
|
459
|
|
460
|
# Now perform the installation.
|
461
|
$grub_shell --batch $no_floppy --device-map=$device_map <<EOF >$log_file
|
462
|
root $root_drive
|
463
|
setup $force_lba --stage2=$grubdir/stage2 --prefix=$grub_prefix $install_drive
|
464
|
quit
|
465
|
EOF
|
466
|
|
467
|
if grep "Error [0-9]*: " $log_file >/dev/null || test $debug = yes; then
|
468
|
cat $log_file 1>&2
|
469
|
exit 1
|
470
|
fi
|
471
|
|
472
|
rm -f $log_file
|
473
|
|
474
|
# Prompt the user to check if the device map is correct.
|
475
|
echo "Installation finished. No error reported."
|
476
|
echo "This is the contents of the device map $device_map."
|
477
|
echo "Check if this is correct or not. If any of the lines is incorrect,"
|
478
|
echo "fix it and re-run the script \`grub-install'."
|
479
|
echo
|
480
|
|
481
|
cat $device_map
|
482
|
|
483
|
# Bye.
|
484
|
exit 0
|