grub-install.in 13 KB

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