prepare to upload
[debian/elilo] / debian / elilo.sh
1 #! /bin/bash
2
3 ###############################################################################
4 ##
5 ## elilo installs efi bootloader onto a bootstrap partition (based on ybin)
6 ## Copyright (C) 2001 Ethan Benson
7 ##
8 ## This program is free software; you can redistribute it and/or
9 ## modify it under the terms of the GNU General Public License
10 ## as published by the Free Software Foundation; either version 2
11 ## of the License, or (at your option) any later version.
12 ##
13 ## This program is distributed in the hope that it will be useful,
14 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ## GNU General Public License for more details.
17 ##
18 ## You should have received a copy of the GNU General Public License
19 ## along with this program; if not, write to the Free Software
20 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 ##
22 ###############################################################################
23
24 PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
25 ## allow to run out of /target in boot-floppies
26 if [ -n "$PATH_PREFIX" ] ; then
27     PATH="${PATH}:${PATH_PREFIX}/sbin:${PATH_PREFIX}/bin:${PATH_PREFIX}/usr/sbin:${PATH_PREFIX}/usr/bin:${PATH_PREFIX}/usr/local/sbin:${PATH_PREFIX}/usr/local/bin"
28 fi
29 PRG="${0##*/}"
30 SIGINT="$PRG: Interrupt caught ... exiting"
31 VERSION=##VERSION##
32 DEBUG=0
33 VERBOSE=0
34 TMP="${TMPDIR:-/tmp}"
35 TARGET=
36 # Beware, /EFI/debian occurs with double backslashes in the script too
37 # so change those as well as EFIROOT, if need be.
38 EFIROOT=/EFI/debian
39 export LC_COLLATE=C
40
41 ARCHITECTURE=$(dpkg --print-installation-architecture)
42
43 ## catch signals, clean up junk in /tmp.
44 trap "cleanup" 0
45 trap "cleanup; exit 129" HUP
46 trap "echo 1>&2 $SIGINT ; cleanup; exit 130" INT
47 trap "cleanup; exit 131" QUIT
48 trap "cleanup; exit 143" TERM
49
50 ## define default config file
51 CONF=/etc/elilo.conf
52 bootconf=$CONF
53 ERR=" Error in $CONF:"
54
55 ## define default configuration
56 boot=unconfigured
57
58 ## allow default to work on packaged and non-packaged elilo. 
59 if [ -f /usr/local/lib/elilo/elilo.efi ] ; then
60     install=/usr/local/lib/elilo/elilo.efi
61 elif [ -f /usr/lib/elilo/elilo.efi ] ; then
62     install=/usr/lib/elilo/elilo.efi
63 fi
64
65 ## defaults
66 efiboot=0
67 autoconf=0
68 fstype=vfat
69 umountproc=0
70
71 ## elilo autoconf defaults
72 label=Linux
73 timeout=20
74 root=/dev/sda3
75
76 # image default is controlled by /etc/kernel-img.conf, if it exists
77 if [ -f /etc/kernel-img.conf ] &&
78         grep -E -qi "^(image|link)_in_boot *= *yes" /etc/kernel-img.conf; then
79     image=/boot/vmlinuz
80     initrdline=initrd=/boot/initrd.img
81     initrdoldline=initrd=/boot/initrd.img.old
82 else
83     image=/vmlinuz
84     initrdline=initrd=/initrd.img
85     initrdoldline=initrd=/initrd.img.old
86 fi
87 if [ -f /etc/kernel-img.conf ] &&
88         ! grep -qi "^do_initrd *= *yes" /etc/kernel-img.conf; then
89     initrdline=
90     initrdoldline=
91 fi
92
93 ## make fake `id' if its missing, outputs 0 since if its missing we
94 ## are probably running on boot floppies and thus are root.
95 if (command -v id > /dev/null 2>&1) ; then 
96     true
97 else
98     id()
99     {
100     echo 0
101     }
102 fi
103
104 ## --version output
105 version()
106 {
107 echo \
108 "$PRG $VERSION
109 Written by Richard Hirst, based on work by Ethan Benson
110
111 This is free software; see the source for copying conditions.  There is NO
112 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
113 }
114
115 ## --help output.
116 usage()
117 {
118 echo \
119 "Usage: $PRG [OPTION]...
120 Update/install bootloader onto a bootstrap partition.
121
122   -b, --boot                 set bootstrap partition device [ -b /dev/sda1 ]
123   -i, --install              pathname to the actual bootloader binary
124                                default: /usr/{local/}lib/elilo/elilo.efi
125   -C, --config               use alternate configuration file [ -C config_file ]
126       --autoconf             auto-generate a /etc/elilo.conf
127       --efiboot              elilo auto configuration: create an efi boot
128                                manager entry for elilo
129       --timeout              elilo auto configuration: sets the time elilo
130                                will wait for user input before booting default
131                                image default: 20 (2 seconds)
132       --image                elilo auto configuration: sets the path to the
133                                kernel image. default: /vmlinuz
134       --label                elilo auto configuration: sets the image label
135                                default: Linux
136       --root                 elilo auto configuration: sets the root device
137                                default: /dev/sda3
138       --format               create a new FAT filesystem on the boot partition
139   -v, --verbose              make $PRG more verbose
140       --debug                print boring junk only useful for debugging
141   -h, --help                 display this help and exit
142   -V, --version              output version information and exit"
143 }
144
145 ## we have to do some things differently with a retarded devfs name.
146 ckdevfs()
147 {
148     case "$1" in
149         /dev/ide/*|/dev/scsi/*|/dev/discs/*)
150         return 0
151         ;;
152     *)
153         return 1
154         ;;
155     esac
156 }
157
158 ## the SmartArray RAID controllers use /dev/cciss/c0d0p1 kinds of names...
159 ckcciss()
160 {
161     case "$1" in
162         /dev/cciss/*)
163         return 0
164         ;;
165     *)
166         return 1
167         ;;
168     esac
169 }
170
171
172 ## configuration file parsing. FIXME: need a method which can parse
173 ## image= sections.
174 parseconf()
175 {
176 case "$1" in
177     str)
178        v=`grep "^$2[\ ,=]" "$CONF"` ; echo "${v#*=}"
179        ;;
180     flag)
181        grep "^$2\>" "$CONF" > /dev/null && echo 0 || echo 1
182        ;;
183     ck)
184        grep "^$2[\ ,=]" "$CONF" > /dev/null && echo 0 || echo 1
185        ;;
186 esac
187 }
188
189 ## check for existence of a configuration file, and make sure we have
190 ## read permission.
191 confexist()
192 {
193     if [ ! -e "$CONF" ] ; then
194         echo 1>&2 "$PRG: $CONF: No such file or directory"
195         return 1
196     elif [ ! -f "$CONF" ] ; then
197         echo 1>&2 "$PRG: $CONF: Not a regular file"
198         return 1
199     elif [ ! -r "$CONF" ] ; then
200         echo 1>&2 "$PRG: $CONF: Permission denied"
201         return 1
202     else
203         return 0
204     fi
205 }
206
207 ## check to make sure the configuration file is sane and correct.
208 ## maybe this is an insane ammount of error checking, but I want to
209 ## make sure (hopefully) nothing unexpected ever happens.  and i just
210 ## like useful errors from programs.  every error just marks an error
211 ## variable so we give the user as much info as possible before we
212 ## abandon ship.
213 checkconf()
214 {
215     if [ -L "$boot" ] ; then
216         oldboot=$boot
217         boot=$(readlink -f $oldboot)
218         echo 1>&2 "$PRG: $oldboot is a symbolic link, using $boot instead"
219     fi
220     if [ ! -e "$boot" ] ; then
221         echo 1>&2 "$PRG: $boot: No such file or directory"
222         CONFERR=1
223     elif [ ! -b "$boot" ] && [ ! -f "$boot" ] ; then
224         echo 1>&2 "$PRG: $boot: Not a regular file or block device"
225         CONFERR=1
226     elif [ ! -w "$boot" ] || [ ! -r "$boot" ] ; then
227         echo 1>&2 "$PRG: $boot: Permission denied"
228         CONFERR=1
229     fi
230
231     ## sanity check, make sure boot=bootstrap and not something dumb
232     ## like /dev/hda
233     case "$boot" in
234         *hda)
235             echo 1>&2 "$PRG:$ERR \`boot=$boot' would result in the destruction of all data on $boot"
236             CONFERR=1
237             ;;
238         *sda)
239             echo 1>&2 "$PRG:$ERR \`boot=$boot' would result in the destruction of all data on $boot"
240             CONFERR=1
241             ;;
242         *disc)
243             echo 1>&2 "$PRG:$ERR \`boot=$boot' would result in the destruction of all data on $boot"
244             CONFERR=1
245             ;;
246     esac
247
248     ## now make sure its not something dumb like the root partition
249     ROOT="$(v=`df / 2> /dev/null | grep ^/dev/` ; echo ${v%%[ ]*})"
250     BOOT="$(v=`df /boot 2> /dev/null | grep ^/dev/` ; echo ${v%%[ ]*})"
251     if [ "$boot" = "$ROOT" ] ; then
252         echo 1>&2 "$PRG:$ERR \`boot=$boot' would result in the destruction of the root filesystem"
253         CONFERR=1
254     elif [ "$boot" = "$BOOT" ] ; then
255         echo 1>&2 "$PRG:$ERR \`boot=$boot' would result in the destruction of the /boot filesystem"
256         CONFERR=1
257     fi
258
259     ## Make sure boot is not already mounted
260     mount | grep "^$boot " > /dev/null
261     if [ $? = 0 ] ; then
262         echo 1>&2 "$PRG: $boot appears to be mounted"
263         CONFERR=1
264     fi
265
266     if [ ! -e "$install" ] ; then
267         echo 1>&2 "$PRG: $install: No such file or directory"
268         CONFERR=1
269     elif [ ! -f "$install" ] ; then
270         echo 1>&2 "$PRG: $install: Not a regular file"
271         CONFERR=1
272     elif [ ! -r "$install" ] ; then
273         echo 1>&2 "$PRG: $install: Permission denied"
274         CONFERR=1
275     fi
276
277     if [ ! -e "$bootconf" ] ; then
278         echo 1>&2 "$PRG: $bootconf: No such file or directory"
279         CONFERR=1
280     elif [ ! -f "$bootconf" ] ; then
281         echo 1>&2 "$PRG: $bootconf: Not a regular file"
282         CONFERR=1
283     elif [ ! -r "$bootconf" ] ; then
284         echo 1>&2 "$PRG: $bootconf: Permission denied"
285         CONFERR=1
286     fi
287
288     # efibootmgr needs efivars, make sure kernel module is loaded
289     if modprobe -q efivars ; then
290         echo "Loaded efivars kernel module to enable use of efibootmgr"
291     fi
292
293     if [ ! -d /proc/efi/vars ] && [ ! -d /sys/firmware/efi/vars ] && [ "$efiboot" = 1 ] ; then
294         echo 1>&2 "$PRG: no efi/vars under /proc or /sys/firmware, boot menu not updated"
295         efiboot=0
296     fi
297
298     if [ "$efiboot" = 1 ] ; then
299         ## see if efibootmgr exists and is executable
300         if (command -v efibootmgr > /dev/null 2>&1) ; then
301             [ -x `command -v efibootmgr` ] || MISSING=1 ; else MISSING=1
302         fi
303
304         if [ "$MISSING" = 1 ] ; then
305             efiboot=0
306             echo 1>&2 "$PRG: Warning: \`efibootmgr' could not be found, boot menu not updated"
307         fi
308
309         if [ -f "$boot" ] ; then
310             echo 1>&2 "$PRG: $boot is a regular file, disabling boot menu update"
311             efiboot=0
312         fi
313     fi
314
315     if [ "$CONFERR" = 1 ] ; then
316         return 1
317     else
318         return 0
319     fi
320 }
321
322
323 mnt()
324 {
325     ## we can even create bootstrap filesystem images directly if you
326     ## ever wanted too.
327     if [ -f "$boot" ] ; then
328         loop=",loop"
329     fi
330
331     if [ -e "$TMP/bootstrap.$$" ] ; then
332         echo 1>&2 "$PRG: $TMP/bootstrap.$$ exists, aborting."
333         return 1
334     fi
335
336     mkdir -m 700 "$TMP/bootstrap.$$"
337     if [ $? != 0 ] ; then
338         echo 1>&2 "$PRG: Could not create mountpoint directory, aborting."
339         return 1
340     fi
341
342     mount | grep "^$boot " > /dev/null
343     if [ $? = 0 ] ; then
344         echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
345         return 1
346     fi
347
348     [ "$VERBOSE" = 1 ] && echo "$PRG: Mounting $boot..."
349     mount -t "$fstype" -o codepage=437,iocharset=iso8859-1,rw,noexec,umask=077$loop "$boot" "$TMP/bootstrap.$$"
350     if [ $? != 0 ] ; then
351         echo 1>&2 "$PRG: An error occured mounting $boot"
352         return 1
353     fi
354
355     TARGET="$TMP/bootstrap.$$"
356     return 0
357 }
358
359 copyfiles()
360 {
361     BTFILE=elilo.efi
362     CFFILE=elilo.conf
363     imagefiles=`grep '^image[[:space:]]*=' $bootconf | \
364                 sed 's/^image[[:space:]]*=[[:space:]]*//' | grep -v ':'`
365     initrdfiles=`grep '^[[:space:]]*initrd[[:space:]]*=' $bootconf | \
366                 sed 's/.*=[[:space:]]*//' | grep -v ':'`
367     vmmfiles=`grep '^[[:space:]]*vmm[[:space:]]*=' $bootconf | \
368                 sed 's/.*=[[:space:]]*//' | grep -v ':'`
369
370     ## Point of no return, removing the old EFI/debian tree
371     rm -rf $TARGET/$EFIROOT
372     if [ $? != 0 ]; then
373         echo 2>&1 "$PRG: Failed to delete old boot files, aborting"
374         return 1
375     fi
376     mkdir -p $TARGET/$EFIROOT
377
378     ## Add a README to warn that this tree is deleted every time elilo is run
379     echo -ne "\
380 This directory tree is managed by /usr/sbin/elilo, and is deleted and\n\
381 recreated every time elilo runs.  Any local changes will be lost.\n\
382 " > $TARGET/$EFIROOT/README.TXT
383
384     ## this is probably insecure on modern filesystems, but i think
385     ## safe on crippled hfs/dosfs.
386     [ "$VERBOSE" = 1 ] && echo "$PRG: Installing primary bootstrap $install onto $boot..."
387     cp -f "$install" "$TARGET/$EFIROOT/$BTFILE"
388     if [ $? != 0 ] ; then
389         echo 1>&2 "$PRG: An error occured while writing to $boot"
390         return 1
391     fi
392
393     [ "$VERBOSE" = 1 ] && echo "$PRG: Installing $bootconf on $boot..."
394     ## we comment out boot= and install=, because they are only really
395     ## needed in the /etc/elilo.conf file, and elilo.efi currently
396     ## doesn't understand them.  We also need to add /EFI/debian on to
397     ## the front of any paths that don't contain colons (device paths),
398     ## and replace tabs with spaces.
399     sed -e "s|^boot[[:space:]]*=|# &|" -e "s|^install[[:space:]]*=|# &|" \
400         -e "s|\t| |g" \
401         -e "s|\(^image[[:space:]]*=[[:space:]]*\)\([^:]*\)$|\1$EFIROOT\2|" \
402         -e "s|\(^[[:space:]]*initrd[[:space:]]*=[[:space:]]*\)\([^:]*\)$|\1$EFIROOT\2|" \
403         -e "s|\(^[[:space:]]*vmm[[:space:]]*=[[:space:]]*\)\([^:]*\)$|\1$EFIROOT\2|" \
404         < "$bootconf" > "$TARGET/$EFIROOT/$CFFILE"
405     if [ $? != 0 ] ; then
406         echo 1>&2 "$PRG: An error occured while writing to $boot"
407         return 1
408     fi
409
410     [ "$DEBUG" = 1 ] && echo "----" && cat "$TARGET/$EFIROOT/$CFFILE" && echo "----"
411
412     for i in $imagefiles $initrdfiles $vmmfiles; do
413         [ "$VERBOSE" = 1 ] && echo "$PRG: Installing $i on $boot..."
414         if [ -f $i ]; then
415             mkdir -p `dirname "$TARGET/$EFIROOT/$i"`
416             if [ $? != 0 ] ; then
417                 echo 1>&2 "$PRG: An error occured creating directory `dirname $EFIROOT/$i` on $boot"
418                 return 1
419             fi
420             cp -f "$i" "$TARGET/$EFIROOT/$i"
421             if [ $? != 0 ] ; then
422                 echo 1>&2 "$PRG: An error occured writing $i to $boot"
423                 return 1
424             fi
425         else
426             echo "$PRG: Warning: $i not found"
427         fi
428     done
429
430     sync ; sync
431
432     ## update the boot-device variable in EFI.
433     if [ "$efiboot" = 1 ] ; then
434         [ "$VERBOSE" = 1 ] && echo "$PRG: Updating EFI boot-device variable..."
435         efiquiet="-q"
436         [ "$VERBOSE" = 1 ] && efiquiet=""
437         if ckdevfs "$boot" ; then
438             BOOTDISK="${boot%/*}/disc"
439             BOOTPART="${boot##*part}"
440         elif ckcciss "$boot" ; then
441             BOOTDISK="${boot%p[0-9]*}"
442             BOOTPART="${boot##*[a-z]}"
443         else
444             BOOTDISK="${boot%%[0-9]*}"
445             BOOTPART="${boot##*[a-z]}"
446         fi
447         if [ -z "$BOOTDISK" ] || [ -z "$BOOTPART" ] ; then
448             echo 2>&1 "$PRG: Could not determine boot disk, aborting..."
449             return 1
450         fi
451
452         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-disk      = $BOOTDISK"
453         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-partition = $BOOTPART"
454         # delete other entries with name "Debian GNU/Linux"
455         for b in `efibootmgr | grep "Debian GNU/Linux" | awk '{print substr($1,5,4) }'`; do
456             efibootmgr $efiquiet -b $b -B
457         done
458         # Add a new entry for this installation
459         efibootmgr $efiquiet -c -d $BOOTDISK -p $BOOTPART -w -L "Debian GNU/Linux" \
460                 -l \\EFI\\debian\\elilo.efi -u -- elilo -C \\EFI\\debian\\elilo.conf
461         if [ $? != 0 ] ; then
462             echo 1>&2 "$PRG: An error occured while updating boot menu, we'll ignore it"
463         fi
464         # Now, if 2nd and 3rd boot entries are for floppy and CD/DVD,
465         # move them up to 1st and 2nd, making our entry the 3rd.
466         bootorder=$(efibootmgr | sed -n 's/^BootOrder: \(.*\)$/\1/p')
467         boot1st=$(echo $bootorder | sed -n "s/\(....\).*$/\1/p")
468         boot2nd=$(echo $bootorder | sed -n "s/....,\(....\).*$/\1/p")
469         boot3rd=$(echo $bootorder | sed -n "s/....,....,\(....\).*$/\1/p")
470         boot456=$(echo $bootorder | sed -n "s/....,....,....\(.*\).*$/\1/p")
471         name2nd=$(efibootmgr | sed -n "s/^Boot$boot2nd[\*] \(.*\)$/\1/p")
472         name3rd=$(efibootmgr | sed -n "s/^Boot$boot3rd[\*] \(.*\)$/\1/p")
473         name23="@$name2nd@$name3rd"
474         if ( echo $name23 | grep -qi "@floppy" ); then
475             if ( echo $name23 | grep -qi "@cd") || ( echo $name23 | grep -qi "@dvd"); then
476                 efibootmgr $efiquiet -o $boot2nd,$boot3rd,$boot1st$boot456
477             fi
478         fi
479     fi
480
481     return 0
482 }
483
484 ## mkefifs function.
485 mkefifs()
486 {
487     mount | grep "^$boot\>" > /dev/null
488     if [ $? = 0 ] ; then
489         echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
490         return 1
491     fi
492
493     if (command -v mkdosfs > /dev/null 2>&1) ; then
494         [ -x `command -v mkdosfs` ] || FAIL=1 ; else FAIL=1 ; fi
495         if [ "$FAIL" = 1 ] ; then
496             echo 1>&2 "$PRG: mkdosfs is not installed or cannot be found"
497             return 1
498         fi
499
500     [ "$VERBOSE" = 1 ] && echo "$PRG: Creating DOS filesystem on $boot..."
501     mkdosfs -n bootstrap "$boot" > /dev/null
502     if [ $? != 0 ] ; then
503         echo 1>&2 "$PRG: DOS filesystem creation failed!"
504         return 1
505     fi
506     return 0
507 }
508
509 mkconf()
510 {
511 ## defaults for this are defined at the beginning of the script with
512 ## other variables.
513
514 # We want to create an append= line from the current /proc/cmdline,
515 # so things like console=ttyS0 get picked up automatically.
516 # We also want to filter out bits of cmdline we are not interested in.
517
518 if [ -f /proc/cmdline ]; then
519   cmdline=`cat /proc/cmdline`
520 else
521   echo 1>&2 "$PRG: Warning: couldn't read /proc/cmdline, may need to add append=... to elilo.conf"
522   cmdline=""
523 fi
524
525 append=`echo $cmdline | tr ' ' '\n' | grep "^console=" | tr '\n' ' '`
526 if [ ! -z "$append" ]; then append="append=\"$append\""; fi
527
528 echo \
529 "## elilo configuration file generated by elilo $VERSION
530
531 install=$install
532 boot=$boot
533 delay=$timeout
534 default=$label
535 " > "$TMPCONF" || return 1
536
537 if [ "$ARCHITECTURE" = "ia64" ]
538 then
539   echo "relocatable" >> "$TMPCONF" || return 1
540 fi
541
542 echo \
543 "$append
544
545 image=$image
546         label=$label
547         root=$root
548         read-only
549         $initrdline
550
551 image=${image}.old
552         label=${label}OLD
553         root=$root
554         read-only
555         $initrdoldline
556 " >> "$TMPCONF" || return 1
557
558     ## Copy the new elilo.conf to /etc
559     if [ -f $CONF ]; then
560         echo 1>&2 "$PRG: backing up existing $CONF as ${CONF}-"
561         rm -f ${CONF}-
562         mv $CONF ${CONF}-
563     fi
564     cp -f "$TMPCONF" "$CONF"
565     if [ $? != 0 ] ; then
566         echo 1>&2 "$PRG: An error occured while writing to $conf"
567         return 1
568     fi
569
570 return 0
571 }
572
573 # check partition will be big enough for all we want to add to it
574
575 chkspace()
576 {
577     imagefiles=`grep '^image[[:space:]]*=' $bootconf | \
578                 sed 's/^image[[:space:]]*=[[:space:]]*//' | grep -v ':'`
579     initrdfiles=`grep '^[[:space:]]*initrd[[:space:]]*=' $bootconf | \
580                 sed 's/.*=[[:space:]]*//' | grep -v ':'`
581     vmmfiles=`grep '^[[:space:]]*vmm[[:space:]]*=' $bootconf | \
582                 sed 's/.*=[[:space:]]*//' | grep -v ':'`
583     bytesneeded=`cat $imagefiles $initrdfiles $vmmfiles $install $bootconf 2>/dev/null | wc -c`
584     # convert to KB, allowing 5% overhead
585     kbneeded=$(( bytesneeded / 1024 + bytesneeded / 20480 ))
586     kbavailable=$(df -P -k $TARGET | sed -n "s|^$boot[[:space:]]\+[0-9]\+[[:space:]]\+[0-9]\+[[:space:]]\+\([0-9]\+\).*$|\1|p")
587     if [ -z $kbavailable ]; then
588         echo 2>&1 "$PRG: unable to determine space on $boot, aborting"
589         return 1
590     fi
591     if [ -d $TARGET/$EFIROOT ]; then
592         kbused=$(du -ks $TARGET/$EFIROOT | sed -n "s/[  ].*$//p")
593     else
594         kbused=0
595     fi
596     [ "$VERBOSE" = 1 ] && echo "$PRG: ${kbneeded}KB needed, ${kbavailable}KB free, ${kbused}KB to reuse"
597     kbavailable=$(( kbavailable + kbused ))
598     if [ "$kbavailable" -lt "$kbneeded" ] ; then
599         echo 1>&2 "$PRG: Insufficient space on $boot, need ${kbneeded}KB, only ${kbavailable}KB available"
600         return 1
601     fi
602 return 0
603 }
604
605
606 ## take out the trash.
607 cleanup()
608 {
609     if [ -n "$TARGET" ]; then
610         TARGET=
611         [ "$VERBOSE" = 1 ] && echo "$PRG: Unmounting $boot"
612         umount "$boot"
613         [ $? != 0 ] && echo 2>&1 "$PRG: Warning, failed to unmount $TARGET"
614     fi
615     if [ -n "$TMPCONF" ] ; then rm -f "$TMPCONF" ; fi
616     if [ -d "$TMP/bootstrap.$$" ] ; then rmdir "$TMP/bootstrap.$$" ; fi
617     if [ "$umountproc" = 1 ] ; then umount /proc ; fi
618     return 0
619 }
620
621 ##########
622 ## Main ##
623 ##########
624
625 ## absurdly bloated case statement to parse command line options.
626 if [ $# != 0 ] ; then
627     while true ; do
628         case "$1" in 
629             -V|--version)
630                 version
631                 exit 0
632                 ;;
633             -h|--help)
634                 usage
635                 exit 0
636                 ;;
637             --debug)
638                 DEBUG=1
639                 shift
640                 ;;
641             -v|--verbose)
642                 VERBOSE=1
643                 shift
644                 ;;
645             --force)
646                 # allow --force for now, boot-floppies 3.0.20 and
647                 # systemconfigurator use that instead of --format
648                 echo 1>&2 "$PRG: Warning: --force is now deprecated.  Use --for\mat."
649                 echo 1>&2 "Try \`$PRG --help' for more information."
650                 FORMAT=yes
651                 shift
652                 ;;
653             --format)
654                 FORMAT=yes
655                 shift
656                 ;;
657             --autoconf)
658                 autoconf=1
659                 shift
660                 ;;
661             -b|--boot)
662                 if [ -n "$2" ] ; then
663                     boot="$2"
664                     ARGBT=1
665                     shift 2
666                 else
667                     echo 1>&2 "$PRG: option requires an argument $1"
668                     echo 1>&2 "Try \`$PRG --help' for more information."
669                     exit 1
670                 fi
671                 ;;
672             -i|--install)
673                 if [ -n "$2" ] ; then
674                     install="$2"
675                     ARGBF=1
676                     shift 2
677                 else
678                     echo 1>&2 "$PRG: option requires an argument $1"
679                     echo 1>&2 "Try \`$PRG --help' for more information."
680                     exit 1
681                 fi
682                 ;;
683             -C|--config)
684                 if [ -n "$2" ] ; then
685                     CONF="$2"
686                     bootconf="$2"
687                     ERR=" Error in $CONF:"
688                     shift 2
689                 else
690                     echo 1>&2 "$PRG: option requires an argument $1"
691                     echo 1>&2 "Try \`$PRG --help' for more information."
692                     exit 1
693                 fi
694                 ;;
695             --efiboot)
696                 efiboot=1
697                 ARGNV=1
698                 shift
699                 ;;
700             --timeout)
701                 if [ -n "$2" ] ; then
702                     timeout="$2"
703                     bootconf=auto
704                     shift 2
705                 else
706                     echo 1>&2 "$PRG: option requires an argument $1"
707                     echo 1>&2 "Try \`$PRG --help' for more information."
708                     exit 1
709                 fi
710                 ;;
711             --image)
712                 if [ -n "$2" ] ; then
713                     image="$2"
714                     bootconf=auto
715                     shift 2
716                 else
717                     echo 1>&2 "$PRG: option requires an argument $1"
718                     echo 1>&2 "Try \`$PRG --help' for more information."
719                     exit 1
720                 fi
721                 ;;
722             --label)
723                 if [ -n "$2" ] ; then
724                     label="$2"
725                     bootconf=auto
726                     shift 2
727                 else
728                     echo 1>&2 "$PRG: option requires an argument $1"
729                     echo 1>&2 "Try \`$PRG --help' for more information."
730                     exit 1
731                 fi
732                 ;;
733             --root)
734                 if [ -n "$2" ] ; then
735                     root="$2"
736                     bootconf=auto
737                     shift 2
738                 else
739                     echo 1>&2 "$PRG: option requires an argument $1"
740                     echo 1>&2 "Try \`$PRG --help' for more information."
741                     exit 1
742                 fi
743                 ;;
744             "")
745                 break
746                 ;;
747             *)
748                 echo 1>&2 "$PRG: unrecognized option \`$1'"
749                 echo 1>&2 "Try \`$PRG --help' for more information."
750                 exit 1
751                 ;;
752         esac
753     done
754 fi
755
756 ## check that are root
757 if [ `id -u` != 0 ] ; then
758     echo 1>&2 "$PRG: requires root privileges, go away."
759     exit 1
760 fi
761
762 ## check that autoconf options are only specified with --autoconf
763 if [ "$bootconf" = "auto" ] && [ "$autoconf" = "0" ] ; then
764     echo 1>&2 "$PRG: Auto-config options specified without --autoconf."
765     exit 1;
766 fi
767
768 ## check that specified config file exists, unless we are to generate it,
769 ## which case we assume all options are done on the command line.
770 if [ "$autoconf" = "0" ] ; then
771     confexist || exit 1
772 fi
773
774 ## /proc is needed to parse /proc/partitions, etc.
775 if [ ! -f /proc/uptime ]; then
776     [ "$VERBOSE" = 1 ] && echo "$PRG: Mounting /proc..."
777     mount -t proc proc /proc 2> /dev/null
778     if [ $? != 0 ]; then
779         echo 1>&2 "$PRG: Failed to mount /proc, aborting."
780         exit 1
781     fi
782     umountproc=1
783 fi
784
785 # We need vfat support, so make sure it is loaded
786 modprobe vfat >/dev/null 2>&1
787
788 ## elilo.conf autogeneration. MUST have secure mktemp to
789 ## avoid race conditions. Debian's mktemp qualifies.
790 if [ "$autoconf" = "1" ] ; then
791     TMPCONF=`mktemp -q "$TMP/$PRG.XXXXXX"`
792     if [ $? != 0 ] ; then
793         echo 1>&2 "$PRG: Could not create temporary file, aborting."
794         exit 1
795     fi
796     mkconf
797     if [ $? != 0 ] ; then
798         echo 1>&2 "$PRG: An error occured generating elilo.conf, aborting."
799         exit 1
800     fi
801
802     bootconf="$TMPCONF"
803 fi
804
805 ## Checks if each option was defined on the command line, and if so
806 ## don't read it from the configuration file. this avoids
807 ## configuration options from being set null, as well as command line
808 ## options from being clobbered.
809 [ "$ARGBT" != 1 ] && [ $(parseconf ck boot) = 0 ] && boot=`parseconf str boot`
810
811 ## ffs!! rtfm! foad!
812 if [ "$boot" = unconfigured ] ; then
813     echo 1>&2 "$PRG: You must specify the device for the bootstrap partition. (ie: -b /dev/hdaX)"
814     echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
815     exit 1
816 fi
817
818 ## validate configuration for sanity.
819 checkconf || exit 1
820
821 if [ "$FORMAT" = "yes" ]; then
822     mkefifs || exit 1
823 fi
824
825 [ "$VERBOSE" = 1 ] && echo "$PRG: Checking filesystem on $boot..."
826 dosfsck $boot > /dev/null
827 if [ $? != 0 ]; then
828     echo 1>&2 "$PRG: Filesystem on $boot is corrupt, please fix that and rerun $PRG."
829     exit 1
830 fi
831
832 mnt || exit 1
833 chkspace || exit 1
834 copyfiles || exit 1
835
836 umount $TARGET
837 if [ $? != 0 ]; then
838     echo 1>&2 "$PRG: Failed to unmount $boot"
839     exit 1
840 fi
841 TARGET=
842
843 [ "$VERBOSE" = 1 ] && echo "$PRG: Installation complete."
844
845 exit 0