591e04e070d2724943a26922af173b17301b55a8
[yaboot.git] / ybin / ybin
1 #! /bin/sh
2
3 ###############################################################################
4 ##
5 ## ybin (YaBoot INstaller) installs/updates the yaboot bootloader.
6 ## Copyright (C) 2000, 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=1.3
32 DEBUG=0
33 VERBOSE=0
34 TMP="${TMPDIR:-/tmp}"
35 export LC_COLLATE=C
36
37 ## catch signals, clean up junk in /tmp.
38 trap "cleanup" 0
39 trap "exit 129" 1
40 trap "echo 1>&2 $SIGINT ; exit 130" 2
41 trap "exit 131" 3
42 trap "exit 143" 15
43
44 ## allow for non-existent config file, in which case it will be
45 ## generated from command line arguments.
46 if [ -f /etc/yaboot.conf ] ; then
47     CONF=/etc/yaboot.conf
48     bootconf=$CONF
49     ERR=" Error in $CONF:"
50 else
51     CONF=/dev/null
52     bootconf=/dev/null
53 fi
54
55 ## define default configuration
56 boot=unconfigured
57
58 ## allow default to work on packaged and non-packaged yaboot. 
59 ## no default for magicboot since it is not required everywhere.
60 if [ -f /usr/local/lib/yaboot/yaboot ] ; then
61     install=/usr/local/lib/yaboot/yaboot
62 elif [ -f /usr/lib/yaboot/yaboot ] ; then
63     install=/usr/lib/yaboot/yaboot
64 fi
65
66 ## defaults
67 usemount=no
68 fstype=hfs
69 hfstype=tbxi
70 hfscreator=UNIX
71 bless=yes
72 protect=no
73 hide=no
74 nonvram=0
75 defaultos=linux
76 brokenosx=no
77 cdrom=no
78 network=no
79 of=no
80 fgcolor=white
81 bgcolor=black
82
83 ## yaboot autoconf defaults
84 label=Linux
85 timeout=40
86 image=/vmlinux
87 partition=3
88 root=/dev/hda3
89 device=hd:
90
91 ## this program behaves differently based on how its called, this
92 ## ensures that nothing nasty happens if someone makes a bogus
93 ## symlink.
94 case "$PRG" in
95     ybin)
96     ;;
97     mkofboot)
98     ;;
99     *)
100     echo 1>&2 "This program must be called as either \`ybin' or \`mkofboot'"
101     exit 1
102     ;;
103 esac
104
105 ## check for printf, use it if possible otherwise fall back on
106 ## unreliable echo -e -n ("SUS" says echo shall support no switches)
107 if [ "$(printf printf_test 2>/dev/null)" = printf_test ] ; then
108     PRINTF=printf
109 else
110     PRINTF="echo -e -n"
111 fi
112
113 ## make fake `id' if its missing, outputs 0 since if its missing we
114 ## are probably running on boot floppies and thus are root.
115 if (command -v id > /dev/null 2>&1) ; then 
116     true
117 else
118     id()
119     {
120     echo 0
121     }
122 fi
123
124 ## --version output
125 version()
126 {
127 echo \
128 "$PRG $VERSION
129 Written by Ethan Benson
130
131 Copyright (C) 2000, 2001 Ethan Benson
132 This is free software; see the source for copying conditions.  There is NO
133 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
134 }
135
136 ## --help output.
137 usage()
138 {
139 echo \
140 "Usage: $PRG [OPTION]...
141 Update/install bootloader onto a bootstrap partition.
142
143   -b, --boot                 set bootstrap partition device [ -b /dev/hda2 ]
144   -o, --ofboot               set bootstrap partition OpenFirmware device
145                                default: automatically determined [ -o hd:2 ]
146   -i, --install              pathname to the actual bootloader binary
147                                default: /usr/{local/}lib/yaboot/yaboot same as
148                                install= in config file [ -i bootloader_file ]
149   -C, --config               use alternate configuration file (ybin and yaboot)
150                                [ -C config_file ]
151   -m, --magicboot            pathname to a OpenFirmware magicboot (CHRP) script
152       --filesystem           set the filesystem type of the bootstrap partition
153                                available options are hfs, msdos, and raw
154                                [ --filesystem hfs ] default is hfs
155       --nobless              don't bless the root directory, this should only
156                                be used if you are using a MacOS boot partition
157                                as the bootstrap partition (not recommended)
158   -M, --mount                don't use userspace hfsutils to modify the
159                                bootstrap instead try and mount the filesystem
160                                directly.  Note that attributes cannot be set
161                                this way and you will have to manually modify
162                                OpenFirmware to make your system bootable
163       --protect              set the read-only (locked) bit on all bootstrap
164                                files
165       --hide                 set the invisible bit on all bootstrap files
166                                this is useful of you don't want them to be
167                                visible from MacOS.
168       --nonvram              do not update the boot-device variable in nvram.
169       --device               yaboot auto configuration: sets the OF boot device
170                                default: hd:
171       --partition            yaboot auto configuration: sets the partition
172                                number of the root partition. default: 3
173       --timeout              yaboot auto configuration: sets the time yaboot
174                                will wait for user input before booting default
175                                image default: 40 (4 seconds)
176       --image                yaboot auto configuration: sets the path to the
177                                kernel image. default: /vmlinux
178       --label                yaboot auto configuration: sets the image label
179                                default: Linux
180       --root                 yaboot auto configuration: sets the root device
181                                default: /dev/hda3
182       --force                don't ever ask for confirmation
183   -v, --verbose              make $PRG more verbose
184       --debug                print boring junk only useful for debugging
185   -h, --help                 display this help and exit
186   -V, --version              output version information and exit"
187 }
188
189 ## configuration file parsing. FIXME: need a method which can parse
190 ## image= sections.
191 parseconf()
192 {
193 case "$1" in
194     str)
195        v=`grep "^$2[\ ,=]" "$CONF"` ; echo "${v#*=}"
196        ;;
197     flag)
198        grep "^$2\>" "$CONF" > /dev/null && echo 0 || echo 1
199        ;;
200     ck)
201        grep "^$2[\ ,=]" "$CONF" > /dev/null && echo 0 || echo 1
202        ;;
203 esac
204 }
205
206 ## check for existence of a configuration file, and make sure we have
207 ## read permission.
208 confexist()
209 {
210     if [ ! -e "$CONF" ] ; then
211         echo 1>&2 "$PRG: $CONF: No such file or directory"
212         return 1
213     elif [ ! -f "$CONF" ] ; then
214         echo 1>&2 "$PRG: $CONF: Not a regular file"
215         return 1
216     elif [ ! -r "$CONF" ] ; then
217         echo 1>&2 "$PRG: $CONF: Permission denied"
218         return 1
219     else
220         return 0
221     fi
222 }
223
224 ## check to make sure the configuration file is sane and correct.
225 ## maybe this is an insane ammount of error checking, but I want to
226 ## make sure (hopfully) nothing unexpected ever happens.  and i just
227 ## like useful errors from programs.  every error just marks an error
228 ## variable so we give the user as much info as possible before we
229 ## abandon ship.
230 checkconf()
231 {
232     if [ ! -e "$boot" ] ; then
233         echo 1>&2 "$PRG: $boot: No such file or directory"
234         local CONFERR=1
235     elif [ ! -b "$boot" -a ! -f "$boot" ] ; then
236         echo 1>&2 "$PRG: $boot: Not a regular file or block device"
237         local CONFERR=1
238     elif [ ! -w "$boot" -o ! -r "$boot" ] ; then
239         [ -z "$mntpoint" ] && echo 1>&2 "$PRG: $boot: Permission denied"
240         [ -z "$mntpoint" ] && CONFERR=1
241     fi
242
243     if [ ! -e "$install" ] ; then
244         echo 1>&2 "$PRG: $install: No such file or directory"
245         local CONFERR=1
246     elif [ ! -f "$install" ] ; then
247         echo 1>&2 "$PRG: $bootconf: Not a regular file"
248         local CONFERR=1
249     elif [ ! -r "$install" ] ; then
250         echo 1>&2 "$PRG: $install: Permission denied"
251         local CONFERR=1
252     fi
253
254     if [ "$bootconf" = auto ] ; then
255         true
256     elif [ ! -e "$bootconf" ] ; then
257         echo 1>&2 "$PRG: $bootconf: No such file or directory"
258         local CONFERR=1
259     elif [ ! -f "$bootconf" ] ; then
260         echo 1>&2 "$PRG: $bootconf: Not a regular file"
261         local CONFERR=1
262     elif [ ! -r "$bootconf" ] ; then
263         echo 1>&2 "$PRG: $bootconf: Permission denied"
264         local CONFERR=1
265     fi
266
267     if [ -n "$magicboot" ] ; then
268         if [ ! -e "$magicboot" ] ; then
269             echo 1>&2 "$PRG: $magicboot: No such file or directory"
270             local CONFERR=1
271         elif [ ! -f "$magicboot" ] ; then
272             echo 1>&2 "$PRG: $magicboot: Not a regular file"
273             local CONFERR=1
274         elif [ ! -r "$magicboot" ] ; then
275             echo 1>&2 "$PRG: $magicboot: Permission denied"
276             local CONFERR=1
277         fi
278     fi
279
280     case "$fstype" in
281         hfs|msdos|raw)
282          ;;
283         *)
284          if [ "$ARGFS" = 1 ] ; then
285             echo 1>&2 "$PRG: --filesystem must be either \`hfs', \`msdos', or \`raw'"
286          else
287             echo 1>&2 "$PRG:$ERR \`fstype' must be either \`hfs', \`msdos', or \`raw'"
288          fi
289          local CONFERR=1
290          ;;
291     esac
292
293     ## if we are not using HFS filesystems we don't care about HFS
294     ## specific options.
295     if [ "$fstype" = hfs ] ; then
296         if [ `echo ${#hfstype}` != 4 ] ; then
297             if [ "$ARGTP" = 1 ] ; then
298                 echo 1>&2 "$PRG: --type must be 4 characters"
299             else
300                 echo 1>&2 "$PRG:$ERR \`hfstype' must be 4 characters"
301             fi
302             local CONFERR=1
303         fi
304         
305         if [ `echo ${#hfscreator}` != 4 ] ; then
306             if [ "$ARGCT" = 1 ] ; then
307                 echo 1>&2 "$PRG: --creator must be 4 characters"
308             else
309                 echo 1>&2 "$PRG:$ERR \`hfscreator' must be 4 characters"
310             fi
311             local CONFERR=1
312         fi
313     fi
314
315     ## some options are not compatible with fstype=raw
316     if [ "$fstype" = raw ] ; then
317         if [ -n "$mntpoint" ] ; then
318             echo 1>&2 "$PRG:$ERR \`mntpoint' is not compatible with fstype=raw"
319             local CONFERR=1
320         fi
321         if [ "$usemount" = yes ] ; then
322             echo 1>&2 "$PRG:$ERR \`usemount' is not compatible with fstype=raw"
323             local CONFERR=1
324         fi
325         if [ -n "$magicboot" ] ; then
326             echo 1>&2 "$PRG:$ERR \`magicboot' scripts cannot be used with fstype=raw"
327             local CONFERR=1
328         fi
329     fi
330
331     if [ -n "$mntpoint" ] ; then
332         ## standard checks
333         if [ ! -e "$mntpoint" ] ; then
334             echo 1>&2 "$PRG: $mntpoint: No such file or directory"
335             local CONFERR=1
336         elif [ ! -d "$mntpoint" ] ; then
337             echo 1>&2 "$PRG: $mntpoint: Not a directory"
338             local CONFERR=1
339         elif [ ! -w "$mntpoint" -o ! -r "$mntpoint" ] ; then
340             echo 1>&2 "$PRG: $mntpoint: Permission denied"
341             local CONFERR=1
342         elif [ ! -O "$mntpoint" -a `id -u` != 0 ] ; then
343             echo 1>&2 "$PRG: $mntpoint: Permission denied (not owner)"
344             local CONFERR=1
345         fi
346
347         ## make sure no embedded spaces exist
348         echo "$mntpoint" | grep -q [[:space:]]
349         if [ $? = 0 ] ; then
350             echo 1>&2 "$PRG:$ERR \`mntpoint=$mntpoint' contains embedded spaces, don't use lame filenames"
351             local CONFERR=1
352         fi
353
354         ## make sure $mntpoint is on $boot, this matters to nvram updating.
355         if [ "$(v=`df "$mntpoint" 2> /dev/null | grep ^/dev/` ; echo ${v%%[ ]*})" != "$boot" -a -d "$mntpoint" ] ; then
356             echo 1>&2 "$PRG: $mntpoint is not located on $boot"
357             local CONFERR=1
358             ## more then one subdirectory deep is not supported. no sed available on boot floppies ( / -> \ )
359         elif [ "$mntpoint" != "$(v=`df "$mntpoint" 2> /dev/null | grep ^/dev/` ; echo ${v##*[ ]})" ] ; then
360             echo "$(v=`df "$mntpoint" 2>/dev/null | grep ^/dev/`; m=${v##*[ ]}; echo "${mntpoint##*$m/}")" | grep -q /
361             if [ $? = 0 ] ; then
362                 echo 1>&2 "$PRG:$ERR $mntpoint is more then one subdirectory deep from root of $boot"
363                 local CONFERR=1
364             else
365                 OFDIR="$(v=`df "$mntpoint" 2>/dev/null | grep ^/dev/`; m=${v##*[ ]}; echo "${mntpoint##*$m/}")"
366             fi
367         fi
368
369         if [ "$usemount" = no ] ; then
370             echo 1>&2 "$PRG:$ERR \`mntpoint=' requires \`usemount' be set"
371             local CONFERR=1
372         fi
373     fi
374
375     if [ -n "$magicboot" ] ; then
376         case "$defaultos" in 
377             linux|Linux|GNU|Gnu|gnu)
378                 defaultos=bootyaboot
379                 ;;
380             bootyaboot)
381                 ;;
382             bsd)
383                 defaultos=bootbsd
384                 if [ -z "$bsd" ] ; then
385                     echo 1>&2 "$PRG:$ERR no entry for \`bsd' found, but defaultos is set to \`bsd'"
386                     local CONFERR=1
387                 fi
388                 ;;
389             macos)
390                 defaultos=bootmacos
391                 if [ -z "$macos" ] ; then
392                     echo 1>&2 "$PRG:$ERR no entry for \`macos' found, but defaultos is set to \`macos'"
393                     local CONFERR=1
394                 fi
395                 ;;
396             macosx)
397                 defaultos=bootmacosx
398                 if [ -z "$macosx" ] ; then
399                     echo 1>&2 "$PRG:$ERR no entry for \`macosx' found, but defaultos is set to \`macosx'"
400                     local CONFERR=1
401                 fi
402                 ;;
403             darwin)
404                 defaultos=bootdarwin
405                 if [ -z "$darwin" ] ; then
406                     echo 1>&2 "$PRG:$ERR no entry for \`darwin' found, but defaultos is set to \`darwin'"
407                     local CONFERR=1
408                 fi
409                 ;;
410             *)
411                 echo 1>&2 "$PRG:$ERR \`defaultos' must be either \`linux', \`bsd', \`macos' or \`macosx'"
412                 local CONFERR=1
413                 ;;
414         esac
415     fi
416
417     ## nvsetenv requires /proc
418     if [ ! -f /proc/uptime -a "$nonvram" = 0 ] ; then
419         echo 1>&2 "$PRG: /proc filesystem is not mounted, nvram will not be updated"
420         nonvram=1
421     fi
422
423     if [ "$nonvram" = 0 ] ; then
424         ## see if nvsetenv exists and is executable
425         if (command -v nvsetenv > /dev/null 2>&1) ; then
426             [ -x `command -v nvsetenv` ] || MISSING=1 ; else MISSING=1
427         fi
428
429         if [ "$nonvram" = 0 ] ; then
430             ## if nvsetenv exists see if its the old broken version
431             if [ "$MISSING" != 1 ] ; then
432                 nvsetenv --version > /dev/null 2>&1 || OLD=1
433             else
434                 nonvram=1
435                 echo 1>&2 "$PRG: Warning: \`nvsetenv' could not be found, nvram will not be updated"
436             fi
437
438             if [ "$OLD" = 1 ] ; then
439                 ## i check this myself to avoid misleading error
440                 ## messages. nvsetenv should REALLY support --version.
441                 if [ ! -e /dev/nvram ] ; then
442                     echo 1>&2 "$PRG: /dev/nvram: No such file or directory"
443                     echo 1>&2 "$PRG: Warning: nvram will not be updated"
444                     nonvram=1
445                 elif [ ! -c /dev/nvram ] ; then
446                     echo 1>&2 "$PRG: /dev/nvram: Not a character device"
447                     echo 1>&2 "$PRG: Warning: nvram will not be updated"
448                     nonvram=1
449                 elif [ ! -w /dev/nvram -o ! -r /dev/nvram ] ; then
450                     echo 1>&2 "$PRG: /dev/nvram: Permission denied"
451                     echo 1>&2 "$PRG: Warning: nvram will not be updated"
452                     nonvram=1
453                 else
454                     nonvram=1
455                     echo 1>&2 "$PRG: Warning: Incompatible version of \`nvsetenv', nvram will not be updated"
456                 fi
457             fi
458         fi
459
460         if [ -f "$boot" ] ; then
461             echo 1>&2 "$PRG: $boot is a regular file, disabling nvram updating"
462             nonvram=1
463         fi
464     fi
465
466     ## check for newworld mac. use cat hack due to /proc wierdness.
467     ## do not bail if we are on an OldWorld only warn (very loudly).
468     if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:})" = NewWorld ] ; then
469         true
470     elif [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:})" = OldWorld ] ; then
471         echo 1>&2
472         echo 1>&2 '@@@@@@@@@@@@@@ WARNING!! WARNING!! WARNING!! @@@@@@@@@@@@@@'
473         echo 1>&2 "$PRG: Warning: This is an OldWorld PowerMac, $boot will **NOT** be bootable on this machine"
474         echo 1>&2 "$PRG: Oldworld PowerMacs need to use the quik bootloader, not yaboot"
475         echo 1>&2 '@@@@@@@@@@@@@@ WARNING!! WARNING!! WARNING!! @@@@@@@@@@@@@@'
476         echo 1>&2
477         [ "$nonvram" = 0 ] && echo 1>&2 "$PRG: OldWorld PowerMac, nvram will not be updated"
478         nonvram=1
479     elif (cat /proc/cpuinfo 2>/dev/null | grep ^motherboard | grep -q AAPL) ; then
480         echo 1>&2
481         echo 1>&2 '@@@@@@@@@@@@@@ WARNING!! WARNING!! WARNING!! @@@@@@@@@@@@@@'
482         echo 1>&2 "$PRG: Warning: This is an OldWorld PowerMac, $boot will **NOT** be bootable on this machine"
483         echo 1>&2 "$PRG: Oldworld PowerMacs need to use the quik bootloader, not yaboot"
484         echo 1>&2 '@@@@@@@@@@@@@@ WARNING!! WARNING!! WARNING!! @@@@@@@@@@@@@@'
485         echo 1>&2
486         [ "$nonvram" = 0 ] && echo 1>&2 "$PRG: OldWorld PowerMac, nvram will not be updated"
487         nonvram=1
488     elif (cat /proc/cpuinfo 2> /dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
489         ## IBM hardware does not need nvram update AFAICT
490         nonvram=1
491         ADDNOTE=yes
492     else
493         #echo 1>&2 "$PRG: Warning: Unknown archetecture, $boot may not be bootable on this machine"
494         [ "$nonvram" = 0 ] && echo 1>&2 "$PRG: Warning: Unknown architecture, nvram will not be updated"
495         nonvram=1
496     fi
497
498     ## convert human readable color values from config to proper color
499     ## codes
500     case "$fgcolor" in
501         black) fgc=0 ;; blue) fgc=1 ;; green) fgc=2 ;; cyan) fgc=3 ;;
502         red) fgc=4 ;; purple) fgc=5 ;; brown) fgc=6 ;; light-gray) fgc=7 ;;
503         dark-gray) fgc=8 ;; light-blue) fgc=9 ;; light-green) fgc=a ;;
504         light-cyan) fgc=b ;; light-red) fgc=c ;; light-purple) fgc=d ;;
505         yellow) fgc=e ;; white) fgc=f ;;
506         *)
507         echo 1>&2 "$PRG:$ERR Invalid fgcolor: \`$fgcolor'"
508         local CONFERR=1
509         ;;
510     esac
511     case "$bgcolor" in
512         black) bgc=0 ;; blue) bgc=1 ;; green) bgc=2 ;; cyan) bgc=3 ;;
513         red) bgc=4 ;; purple) bgc=5 ;; brown) bgc=6 ;; light-gray) bgc=7 ;;
514         dark-gray) bgc=8 ;; light-blue) bgc=9 ;; light-green) bgc=a ;;
515         light-cyan) bgc=b ;; light-red) bgc=c ;; light-purple) bgc=d ;;
516         yellow) bgc=e ;; white) bgc=f ;;
517         *)
518         echo 1>&2 "$PRG:$ERR Invalid bgcolor: \`$bgcolor'"
519         local CONFERR=1
520         ;;
521     esac
522
523     ## if delay is not set use yaboot's timeout
524     if [ -z "$delay" ] ; then
525         delay="$(($timeout / 10))"
526     fi
527
528     if [ "$CONFERR" = 1 ] ; then
529         return 1
530     else
531         return 0
532     fi
533 }
534
535
536 ## if readlink is missing use a kludge
537 if (command -v readlink > /dev/null 2>&1) ; then
538     true
539 else
540     readlink()
541     {
542         SYMTARGET="$(v=`ls -l "$2" 2>/dev/null` ; echo ${v##*> })"
543         if [ -n "$SYMTARGET" ] ; then
544             echo "$SYMTARGET"
545             return 0
546         else
547             return 1
548         fi
549     }
550 fi
551
552 ## /etc/yaboot.conf with password should not be world readable.
553 permcheck()
554 {
555 if [ -L "$bootconf" ] ; then
556     local realfile="$(readlink -f "$bootconf")" || return 0
557 else
558     local realfile="$bootconf"
559 fi
560
561 ## don't bother if we could not read the symlink
562 [ -z "$realfile" ] && return 0
563 [ ! -f "$realfile" ] && return 0
564
565 ## get permissions, and don't bother checking if we can't
566 local PERM=`v=$(ls -l "$realfile" 2>/dev/null) ; echo ${v%% *}`
567 [ -z "$PERM" ] && return 0
568 [ `echo ${#PERM}` != 10 ] && return 0
569
570 case "$PERM" in
571     -rw-------|-r--------)
572       if [ ! -O "$realfile" -a `id -u` = 0 ] ; then
573          echo 1>&2 "$PRG: Warning: $bootconf is not owned by root"
574       fi
575       ;;
576     -rw-r-----|-r--r-----)
577       if [ ! -O "$realfile" -a `id -u` = 0 ] ; then
578          echo 1>&2 "$PRG: Warning: $bootconf is not owned by root"
579       fi
580       if [ ! -G "$realfile" -a `id -g` = 0 ] ; then
581          echo 1>&2 "$PRG: Warning: $bootconf is not owned by group root"
582       fi
583       ;;
584     -r--r--r--|-rw-r--r--|-rw-rw-r--|-rw-rw-rw-|-rw-rw----)
585       echo 1>&2 "$PRG: Warning: Insecure permissions on $bootconf: $PERM should be -rw-------"
586       ;;
587     *)
588       echo 1>&2 "$PRG: Warning: Incorrect permissions on $bootconf: $PERM should be -rw-------"
589       ;;
590 esac
591 }
592
593 convertpath()
594 {
595     ## figure out bootstrap device OF pathname if user did not supply it.
596     if [ -z "$ofboot" ] ; then
597         [ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$boot'..."
598         ofboot="$(ofpath $boot)"
599         if [ $? != 0 ] ; then
600             echo 1>&2 "$PRG: Unable to find OpenFirmware path for boot=$boot"
601             echo 1>&2 "$PRG: Please add ofboot=<path> where <path> is the OpenFirmware path to $boot to $CONF"
602             local CONVERR=1
603         fi
604         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: ofboot set to \`$ofboot'"
605     fi
606
607     ## figure out OF device path for macos/macosx if user supplied a unix device node.
608     if [ -n "$bsd" ] ; then
609         case "$bsd" in
610             /dev/*)
611                 [ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$bsd'..."
612                 local sbsd="$bsd"
613                 bsd="$(ofpath $bsd)"
614                 if [ $? != 0 ] ; then
615                     echo 1>&2 "$PRG: Unable to determine OpenFirmware path for bsd=$sbsd"
616                     echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for bsd=$sbsd in $CONF"
617                     local CONVERR=1
618                 fi
619                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bsd set to \`$bsd' from \`$sbsd'"
620                 ;;
621             *)
622                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bsd left alone: \`$bsd'"
623                 ;;
624         esac
625     fi
626
627     if [ -n "$macos" ] ; then
628         case "$macos" in
629             /dev/*)
630                 [ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$macos'..."
631                 local smacos="$macos"
632                 macos="$(ofpath $macos)"
633                 if [ $? != 0 ] ; then
634                     echo 1>&2 "$PRG: Unable to determine OpenFirmware path for macos=$smacos"
635                     echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for macos=$smacos in $CONF"
636                     local CONVERR=1
637                 fi
638                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macos set to \`$macos' from \`$smacos'"
639                 ;;
640             *)
641                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macos left alone: \`$macos'"
642                 ;;
643         esac
644     fi
645
646     if [ -n "$macosx" ] ; then
647         case "$macosx" in
648             /dev/*)
649                 [ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$macosx'..."
650                 local smacosx="$macosx"
651                 macosx="$(ofpath $macosx)"
652                 if [ $? != 0 ] ; then
653                     echo 1>&2 "$PRG: Unable to determine OpenFirmware path for macosx=$smacosx"
654                     echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for macosx=$smacosx in $CONF"
655                     local CONVERR=1
656                 fi
657                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macosx set to \`$macosx' from \`$smacosx'"
658                 ;;
659             *)
660                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macosx left alone: \`$macosx'"
661                 ;;
662         esac
663     fi
664
665     if [ -n "$darwin" ] ; then
666         case "$darwin" in
667             /dev/*)
668                 [ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$darwin'..."
669                 local sdarwin="$darwin"
670                 darwin="$(ofpath $darwin)"
671                 if [ $? != 0 ] ; then
672                     echo 1>&2 "$PRG: Unable to determine OpenFirmware path for darwin=$sdarwin"
673                     echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for darwin=$sdarwin in $CONF"
674                     local CONVERR=1
675                 fi
676                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: darwin set to \`$darwin' from \`$sdarwin'"
677                 ;;
678             *)
679                 [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: darwin left alone: \`$darwin'"
680                 ;;
681         esac
682     fi
683
684     if [ "$CONVERR" = 1 ] ; then
685         return 1
686     else
687         return 0
688     fi
689 }
690
691 ## make sure the hfsutils we need are installed and executable.
692 checkhfsutils()
693 {
694     if (command -v hmount > /dev/null 2>&1) ; then
695         [ -x `command -v hmount` ] || FAIL=1 ; else FAIL=1 ; fi
696     if (command -v humount > /dev/null 2>&1) ; then
697         [ -x `command -v humount` ] || FAIL=1 ; else FAIL=1 ; fi
698     if (command -v hcopy > /dev/null 2>&1) ; then
699         [ -x `command -v hcopy` ] || FAIL=1 ; else FAIL=1 ; fi
700     if (command -v hattrib > /dev/null 2>&1) ; then
701         [ -x `command -v hattrib` ] || FAIL=1 ; else FAIL=1 ; fi
702     if (command -v hformat > /dev/null 2>&1) ; then
703         [ -x `command -v hformat` ] || FAIL=1 ; else FAIL=1 ; fi
704
705     if [ "$FAIL" = 1 ] ; then
706         return 1
707     else
708         return 0
709     fi
710 }
711
712 ## This is gross, IBM CHRP OF needs a .note added to the yaboot
713 ## binary, nobody knows whether this note will affect PowerMac OF or
714 ## not (or could in the future). 
715 hack_yaboot()
716 {
717     local YBDIR="${install%/*}"
718     if [ -x "$YBDIR/addnote" ] ; then
719         TMPYABOOT=`mktemp -q "$TMP/yaboot.XXXXXX"`
720         if [ $? != 0 ] ; then
721             echo 1>&2 "$PRG: Could not create temporary file, aborting."
722             return 1
723         else
724             if (cat "$install" > "$TMPYABOOT" 2> /dev/null) ; then
725                 install="$TMPYABOOT"
726             else
727                 echo 1>&2 "$PRG: Could not create temporary file, aborting."
728                 return 1
729             fi
730         fi
731         [ "$DEBUG" = 1 ] && echo "$PRG: Embedding CHRP note section in temp yaboot..."
732         "$YBDIR/addnote" "$install" > /dev/null 2>&1
733         if [ $? != 0 ] ; then
734             echo 1>&2 "$PRG: Could not install note section required by your architecture"
735             return 1
736         fi
737     else
738         echo 1>&2 "$PRG: Your architecture requires $YBDIR/addnote which cannot be found"
739         return 1
740     fi
741     return 0
742 }
743
744 ## install using userspace utilities rather then kernel filesytem
745 ## support.  hfsutils only, mtools not supported.
746 util_install()
747 {
748     ## catch signals, and humount, cleanup done by trap 0.
749     trap "humount $boot ; exit 129" 1
750     trap "echo 1>&2 $SIGINT ; humount $boot ; exit 130" 2
751     trap "humount $boot ; exit 131" 3
752     trap "humount $boot ; exit 143" 15
753
754     ## filenames on bootstrap partition. ofboot hard codes yaboot.
755     local BTFILE=yaboot
756     local CFFILE=yaboot.conf
757
758     ## if there is a magicboot script to install we will give it the
759     ## hfstype (should be "tbxi") and give yaboot type "boot".
760     if [ "$magicboot" ] ; then
761         local BTTYPE=boot
762     else
763         local BTTYPE="$hfstype"
764     fi
765
766     if [ -n "$magicboot" ] ; then
767         local WRAP="${magicboot##*/}"
768     fi
769
770     ## set verbose messages here so they don't show temporary file paths
771     local INSTALLFIRST="$PRG: Installing first stage bootstrap $magicboot onto $boot..."
772     local INSTALLPRIMARY="$PRG: Installing primary bootstrap $install onto $boot..."
773
774     ## repoint magicboot as the real first stage loader if using the
775     ## modern automatic generating ofboot.b.
776     if [ -n "$FIRST" ] ; then   
777         magicboot="$FIRST"
778         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: set magicboot to $FIRST"
779     fi
780
781     ## gross hack, add note section for IBM CHRP
782     if [ "$ADDNOTE" = yes ] ; then
783         hack_yaboot || return 1
784     fi
785
786     if [ "$fstype" = hfs ] ; then
787         if [ "$protect" = yes ] ; then
788             local LOCK="+l"
789         fi
790         
791         if [ "$hide" = yes ] ; then
792             local INVISIBLE="+i"
793         fi
794
795         ## make sure the device is not mounted as a filesystem before
796         ## we start mucking with it directly.
797         mount | grep "^$boot\>" > /dev/null
798         if [ $? = 0 ] ; then
799             echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
800             return 1
801         fi
802
803         ## hmount is really more of a way to make sure we have a valid HFS
804         ## filesystem before proceding, and hcopy requires it...
805         hmount "$boot" > /dev/null
806         if [ $? != 0 ] ; then
807             echo 1>&2 "$PRG: $boot appears to have never had a bootstrap installed, please run mkofboot"
808             return 1
809         fi
810
811         ## must be explicit with target filename to avoid hfsutils
812         ## braindamage ("_" -> " " filename mangling) also avoid
813         ## ambiguity in the bootstrap partition.
814         if [ -n "$magicboot" ] ; then
815             [ "$VERBOSE" = 1 ] && echo "$INSTALLFIRST"
816             hcopy -r "$magicboot" :ofboot.b
817             if [ $? != 0 ] ; then
818                echo 1>&2 "$PRG: An error occured while writing to $boot"
819                return 1
820             fi
821         fi
822
823         [ "$VERBOSE" = 1 ] && echo "$INSTALLPRIMARY"
824         hcopy -r "$install" :"$BTFILE"
825         if [ $? != 0 ] ; then
826             echo 1>&2 "$PRG: An error occured while writing to $boot"
827             return 1
828         fi
829
830         [ "$VERBOSE" = 1 ] && echo "$PRG: Installing $bootconf to $boot..."
831         hcopy -r "$bootconf" :"$CFFILE"
832         if [ $? != 0 ] ; then
833             echo 1>&2 "$PRG: An error occured while writing to $boot"
834             return 1
835         fi
836
837         ## set all file's attributes, if a magicboot script exists it
838         ## gets the configured hfstype instead of yaboot (should be
839         ## "tbxi") so it gets booted by OF.
840         if [ "$magicboot" ] ; then
841             [ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $WRAP..."
842             hattrib -t "$hfstype" -c "$hfscreator" $INVISIBLE $LOCK :ofboot.b
843             if [ $? != 0 ] ; then
844                 echo 1>&2 "$PRG: Warning: error setting attributes on $WRAP"
845                 echo 1>&2 "$PRG: This is probably bad but we'll ignore it."
846             fi
847         fi
848
849         [ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $BTFILE..."
850         hattrib -t "$BTTYPE" -c "$hfscreator" $INVISIBLE $LOCK :"$BTFILE"
851         if [ $? != 0 ] ; then
852             echo 1>&2 "$PRG: Warning: error setting attributes on $BTFILE"
853             echo 1>&2 "$PRG: This is probably bad but we'll ignore it"
854         fi
855
856         [ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $CFFILE..."
857         hattrib -t "conf" -c "$hfscreator" $INVISIBLE $LOCK :"$CFFILE"
858         if [ $? != 0 ] ; then
859             echo 1>&2 "$PRG: Warning: error setting attributes on $CFFILE"
860             echo 1>&2 "$PRG: This is probably unimportant so we'll ignore it"
861         fi
862
863         ## bless the root directory so OF will find the boot file
864         if [ "$bless" = yes ] ; then
865             [ "$VERBOSE" = 1 ] && echo "$PRG: Blessing $boot with Holy Penguin Pee..."
866             hattrib -b :
867             if [ $? != 0 ] ; then
868                 echo 1>&2 "$PRG: Warning: error blessing $boot"
869                 echo 1>&2 "$PRG: This is probably bad but we'll ignore it"
870             fi
871         fi
872
873         ## clean up the ~/.hcwd file hmount creates
874         humount "$boot" > /dev/null
875         sync ; sync
876
877         ## use explicit filename if we don't bless.
878         if [ "$bless" = yes ] ; then
879             local OFFILE='\\:tbxi'
880         else
881             if [ -n "$magicboot" ] ; then
882                 local OFFILE=ofboot.b
883             else
884                 local OFFILE="$BTFILE"
885             fi
886         fi
887
888         ## update the boot-device variable in OF nvram.
889         if [ "$nonvram" = 0 ] ; then
890             [ "$VERBOSE" = 1 ] && echo "$PRG: Updating OpenFirmware boot-device variable in nvram..."
891             [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-device=${ofboot},${OFFILE}"
892             nvsetenv boot-device "${ofboot},${OFFILE}"
893             if [ $? != 0 ] ; then
894                 echo 1>&2 "$PRG: An error occured while updating nvram, we'll ignore it"
895             fi
896         fi
897
898     else
899         echo 1>&2 "$PRG: mtools support is not implemented"
900         echo 1>&2 "$PRG: Use --mount or add \`usemount' to $CONF"
901         return 1
902     fi
903
904     return 0
905 }
906
907 ## used by mnt_install so mntpoint= can be supported in a cleaner way.
908 mnt()
909 {
910     ## we can even create bootstrap filesystem images directly if you
911     ## ever wanted too.
912     if [ -f "$boot" ] ; then
913         local loop=",loop"
914     fi
915
916     if [ -e "$TMP/bootstrap.$$" ] ; then
917         echo 1>&2 "$PRG: $TMP/bootstrap.$$ exists, aborting."
918         return 1
919     fi
920
921     mkdir -m 700 "$TMP/bootstrap.$$"
922     if [ $? != 0 ] ; then
923         echo 1>&2 "$PRG: Could not create mountpoint directory, aborting."
924         return 1
925     fi
926
927     mount | grep "^$boot\>" > /dev/null
928     if [ $? = 0 ] ; then
929         echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
930         return 1
931     fi
932
933     [ "$VERBOSE" = 1 ] && echo "$PRG: Mounting $boot..."
934     mount -t "$fstype" -o rw,umask=077$loop "$boot" "$TMP/bootstrap.$$"
935     if [ $? != 0 ] ; then
936         echo 1>&2 "$PRG: An error occured mounting $boot"
937         return 1
938     fi
939
940     ## catch signals, set here to avoid umounting something we did not
941     ## mount. cleanup done by trap 0.
942     trap "umount $boot ; exit 129" 1
943     trap "echo 1>&2 $SIGINT ; umount $boot ; exit 130" 2
944     trap "umount $boot ; exit 131" 3
945     trap "umount $boot ; exit 143" 15
946
947     TARGET="$TMP/bootstrap.$$"
948     return 0
949 }
950
951 ## umnt funtion which checks whether we mounted anything or not, for
952 ## mntpoint= this makes the code below cleaner IMO.
953 umnt()
954 {
955     if [ -z "$mntpoint" ] ; then
956         [ "$1" = failure ] && echo 1>&2 "$PRG: Attempting to umount $boot..."
957         umount "$2"
958         if [ $? != 0 ] ; then
959             echo 1>&2 "$PRG: umount of $boot failed!"
960             return 1
961         else
962             [ "$1" = failure ] && echo 1>&2 "$PRG: umount successfull"
963             return 0
964         fi
965     else
966         return 0
967     fi
968 }
969
970 ## Use kernel filesytem drivers to mount the bootstrap partition like
971 ## any other filesystem and copy the files there with standard un*x
972 ## utilities.
973 mnt_install()
974 {
975     local BTFILE=yaboot
976   
977     ## msdosfs is broken, yaboot may not support this filename.
978     if [ "$fstype" = msdos ] ; then
979         local CFFILE=yaboot.cnf
980     else
981         local CFFILE=yaboot.conf
982     fi
983
984     if [ "$magicboot" ] ; then
985         local WRAP="${magicboot##*/}"
986     fi
987
988     ## set verbose messages here so they don't show temporary file paths
989     local INSTALLFIRST="$PRG: Installing first stage bootstrap $magicboot onto $boot..."
990     local INSTALLPRIMARY="$PRG: Installing primary bootstrap $install onto $boot..."
991
992     ## repoint magicboot as the real first stage loader if using the
993     ## modern automatic generating ofboot.b.
994     if [ "$FIRST" ] ; then
995         magicboot="$FIRST"
996         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: set magicboot to $FIRST"
997     fi
998
999     ## gross hack, add note section for IBM CHRP
1000     if [ "$ADDNOTE" = yes ] ; then
1001         hack_yaboot || return 1
1002     fi
1003
1004     ## call mnt() function to take care of mounting filesystem if needed
1005     if [ -z "$mntpoint" ] ; then
1006         mnt || return 1
1007     else
1008         TARGET="$mntpoint"
1009     fi
1010
1011     ## this is probably insecure on modern filesystems, but i think
1012     ## safe on crippled hfs/dosfs. user should ensure mntpoint= is safe.
1013     if [ -n "$magicboot" ] ; then
1014         [ "$VERBOSE" = 1 ] && echo "$INSTALLFIRST"
1015         cp -f "$magicboot" "$TARGET/ofboot.b"
1016         if [ $? != 0 ] ; then
1017             echo 1>&2 "$PRG: An error occured while writing to $boot"
1018             umnt failure "$TARGET"
1019             return 1
1020         fi
1021     fi
1022
1023     [ "$VERBOSE" = 1 ] && echo "$INSTALLFIRST"
1024     cp -f "$install" "$TARGET/$BTFILE"
1025     if [ $? != 0 ] ; then
1026         echo 1>&2 "$PRG: An error occured while writing to $boot"
1027         umnt failure "$TARGET"
1028         return 1
1029     fi
1030
1031     [ "$VERBOSE" = 1 ] && echo "$PRG: Installing $bootconf on $boot..."
1032     cp -f "$bootconf" "$TARGET/$CFFILE"
1033     if [ $? != 0 ] ; then
1034         echo 1>&2 "$PRG: An error occured while writing to $boot"
1035         umnt failure "$TARGET"
1036         return 1
1037     fi
1038
1039     if [ "$protect" = yes ] ; then
1040         [ "$VERBOSE" = 1 ] && echo "$PRG: Setting read-only attributes..."
1041         chmod a-w "$TARGET/$BTFILE"
1042         chmod a-w "$TARGET/$CFFILE"
1043         if [ "$magicboot" ] ; then
1044             chmod a-w "$TARGET/ofboot.b"
1045         fi
1046     fi
1047
1048     sync ; sync
1049     umnt success "$TARGET" || return 1
1050
1051     ## make variable with a \ to avoid shell fsckage.  ugly ugly ugly.
1052     local BS='\'
1053     if [ -n "$magicboot" ] ; then
1054         [ -n "$OFDIR" ] && OFDIR="${BS}${OFDIR}${BS}"
1055         local OFFILE="${OFDIR}ofboot.b"
1056     else
1057         [ -n "$OFDIR" ] && OFDIR="${BS}${OFDIR}${BS}"
1058         local OFFILE="${OFDIR}${BTFILE}"
1059     fi
1060
1061     ## update the boot-device variable in OF nvram.
1062     if [ "$nonvram" = 0 ] ; then
1063         [ "$VERBOSE" = 1 ] && echo "$PRG: Updating OpenFirmware boot-device variable in nvram..."
1064         [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-device=${ofboot},${OFFILE}"
1065         nvsetenv boot-device "${ofboot},${OFFILE}"
1066         if [ $? != 0 ] ; then
1067             echo 1>&2 "$PRG: An error occured while updating nvram, we'll ignore it"
1068         fi
1069     else
1070         echo 1>&2 "$PRG: Warning: You must manually configure OpenFirmware to boot."
1071     fi
1072
1073     return 0
1074 }
1075
1076 ## raw installation, for IBM RS/6000 hardware, yaboot is dded to the
1077 ## bootstrap partition. 
1078 raw_install()
1079 {
1080     ## make sure the device is not mounted as a filesystem before
1081     ## we start mucking with it directly.
1082     mount | grep "^$boot\>" > /dev/null
1083     if [ $? = 0 ] ; then
1084         echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
1085         return 1
1086     fi
1087
1088     ## set verbosity message before munging the yaboot pathname
1089     local INSTALLPRIMARY="$PRG: Installing primary bootstrap $install onto $boot..."
1090
1091     ## gross hack, add note section for IBM CHRP
1092     if [ "$ADDNOTE" = yes ] ; then
1093         hack_yaboot || return 1
1094     fi
1095
1096     [ "$VERBOSE" = 1 ] && echo "$INSTALLPRIMARY"
1097     dd if=/dev/zero of="$boot" bs=512 count=1600 > /dev/null 2>&1
1098     dd if="$install" of="$boot" bs=512 > /dev/null 2>&1
1099     if [ $? != 0 ] ; then
1100         echo 1>&2 "$PRG: Installation failed."
1101         return 1
1102     fi
1103     sync ; sync
1104     [ "$VERBOSE" = 1 ] && echo "$PRG: Installation successful"
1105 }
1106
1107 ## make sure the first stage ofboot generator is compatible.
1108 checkfirststage()
1109 {
1110     grep -q "^#%ybinscript-" "$magicboot" 2> /dev/null
1111     if [ "$?" = 0 ] ; then
1112         local magic=`grep "^#%ybinscript-" "$magicboot"`
1113         local ver="${magic##*-}"
1114         if [ "$ver" = "1.1" ] ; then
1115             FIRSTSTG=compat
1116             return 0
1117         else
1118             echo 1>&2 "$PRG: Incompatible version of first stage loader $magicboot.  aborting..."
1119             return 1
1120         fi
1121     else
1122         FIRSTSTG=old
1123         return 0
1124     fi
1125 }
1126
1127 ## build the first stage loader.
1128 mkfirststage()
1129 {
1130     ## must have 7 backslashes to == \\ printf + shell = bizarre... or,
1131     ## make special variable to contain a \ (need \\ to make \) to work
1132     ## around echo -e -n brokeness.
1133     local BS='\\'
1134     local OS=1
1135
1136     ## deal with mntpoint=
1137     [ -n "$OFDIR" ] && local OFDIR="${BS}${OFDIR}${BS}"
1138
1139     ## some misguided people insist on installing OSX on
1140     ## HorribleFileSystem+ instead of UFS, as a result MacOS deblesses
1141     ## OSX, making it unbootable. if apple localizes the filesystem hierarchy again screw it.
1142     [ "$brokenosx" = yes ] && local OSXBOOT="${BS}System${BS}Library${BS}CoreServices${BS}BootX"
1143     [ "$brokenosx" = no ] && local OSXBOOT="${BS}${BS}:tbxi"
1144
1145     ## assign variables for configured menu options.
1146     [ "$usemount" = no -a "$bless" = yes ] && local YB="yaboot GNU l $ofboot ,${BS}${BS}yaboot"
1147     [ "$usemount" = yes -o "$bless" = no ] && local YB="yaboot GNU l $ofboot ,${OFDIR}yaboot"
1148     [ -n "$bsd" ] && OS="$(($OS + 1))" && local BSD="bsd BSD b $bsd ,${BS}ofwboot.elf"
1149     [ -n "$macos" ] && OS="$(($OS + 1))" && local MAC="macos MacOS m $macos ,${BS}${BS}:tbxi"
1150     [ -n "$macosx" ] && OS="$(($OS + 1))" && local MX="macosx MacOSX x $macosx ,${OSXBOOT}"
1151     [ -n "$darwin" ] && OS="$(($OS + 1))" && local DW="darwin Darwin d $darwin ,${BS}${BS}:tbxi"
1152     [ "$cdrom" = yes ] && OS="$(($OS + 1))" && local CD="cd CDROM c cd: ,${BS}${BS}:tbxi"
1153     [ "$network" = yes ] && OS="$(($OS + 1))" && local NET="net Network n enet: 0"
1154     [ "$of" = yes ] && OS="$(($OS + 1))" && local OF="of OpenFirmware o quit now"
1155     [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: OS=$OS"
1156
1157     ## call ofboot,
1158     ## Usage: OS-count defaultos timeout fgc bgc osname oslabel oskey osdev osfile ...
1159     [ "$DEBUG" = 1 ] && $PRINTF 1>&2 "$PRG: DEBUG: /bin/sh $magicboot $OS $defaultos $delay $fbc $bgc $YB $BSD $MAC $MX $DW $CD $NET $OF\n"
1160     FIRST="$(/bin/sh "$magicboot" "$OS" "$defaultos" "$delay" $fgc $bgc ${YB} ${BSD} ${MAC} ${MX} ${DW} ${CD} ${NET} ${OF})" || return 1
1161
1162     return 0
1163 }
1164
1165 ## mkofboot function.
1166 mkoffs()
1167 {
1168     mount | grep "^$boot\>" > /dev/null
1169     if [ $? = 0 ] ; then
1170         echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
1171         return 1
1172     fi
1173
1174     case "$fstype" in
1175         hfs)
1176             [ "$VERBOSE" = 1 ] && echo "$PRG: Creating HFS filesystem on $boot..."
1177             if (command -v dd > /dev/null 2>&1) ; then
1178                 dd if=/dev/zero of="$boot" bs=512 count=1600 > /dev/null 2>&1
1179             fi
1180             hformat -l bootstrap "$boot" > /dev/null
1181             if [ $? != 0 ] ; then
1182                 echo 1>&2 "$PRG: HFS filesystem creation failed!"
1183                 return 1
1184             fi
1185             humount "$boot" ## otherwise we might get confused.
1186             return 0
1187             ;;
1188         msdos)
1189             if (command -v mkdosfs > /dev/null 2>&1) ; then
1190                 [ -x `command -v mkdosfs` ] || FAIL=1 ; else FAIL=1 ; fi
1191                 if [ "$FAIL" = 1 ] ; then
1192                     echo 1>&2 "$PRG: mkdosfs is not installed or cannot be found"
1193                     return 1
1194                 fi
1195
1196             [ "$VERBOSE" = 1 ] && echo "$PRG: Creating DOS filesystem on $boot..."
1197             if (command -v dd > /dev/null 2>&1) ; then
1198                 dd if=/dev/zero of="$boot" bs=512 count=1600 > /dev/null 2>&1
1199             fi  
1200             mkdosfs -n bootstrap "$boot" > /dev/null
1201             if [ $? != 0 ] ; then
1202                 echo 1>&2 "$PRG: DOS filesystem creation failed!"
1203                 return 1
1204             fi
1205             return 0
1206             ;;
1207     esac
1208 }
1209
1210 confirm()
1211 {
1212     if [ "$FORCE" = yes ] ; then
1213         return 0
1214     else
1215         echo 1>&2
1216         [ "$fstype" = raw ] && $PRINTF 1>&2 "$PRG: Overwrite contents of $boot with $install? [y/N] "
1217         [ "$fstype" != raw ] && $PRINTF 1>&2 "$PRG: Create $fstype filesystem on $boot? [y/N] "
1218         read ans
1219         case "$ans" in
1220             y|Y)
1221                 return 0
1222                 ;;
1223             *)
1224                 echo 1>&2 "$PRG: Abort."
1225                 return 2
1226                 ;;
1227         esac
1228     fi
1229 }
1230
1231 ## for fstype=raw check if an ELF binary has already been dded.
1232 luserck()
1233 {
1234     if [ "$(dd if="$boot" bs=1 skip=1 count=3 2>/dev/null)" = ELF ] ; then
1235         return 0
1236     else
1237         echo 1>&2 "$PRG: This partition has never had yaboot installed before, please run mkofboot"
1238         return 1
1239     fi
1240 }
1241
1242 mkconf()
1243 {
1244 ## defaults for this are defined at the beginning of the script with
1245 ## other variables.
1246
1247 echo \
1248 "## yaboot configuration file generated by ybin $VERSION
1249
1250 device=$device
1251 timeout=$timeout
1252
1253 image=$image
1254         label=$label
1255         partition=$partition
1256         root=$root
1257         read-only
1258 " > "$TMPCONF" || return 1
1259
1260 [ "$DEBUG" = 1 ] && $PRINTF 1>&2 "\nDEBUG: autoconf:\n----\n" && cat "$TMPCONF" 1>&2 && echo 1>&2 "----"
1261 return 0
1262 }
1263
1264 ## take out the trash.
1265 cleanup()
1266 {
1267     if [ -n "$TMPCONF" ] ; then rm -f "$TMPCONF" ; fi
1268     if [ -n "$FIRST" ] ; then rm -f "$FIRST" ; fi
1269     if [ -n "$TMPYABOOT" ] ; then rm -f "$TMPYABOOT" ; fi
1270     if [ -d "$TMP/bootstrap.$$" -a "$usemount" = yes ] ; then rmdir "$TMP/bootstrap.$$" ; fi
1271     return 0
1272 }
1273
1274 ##########
1275 ## Main ##
1276 ##########
1277
1278 ## absurdly bloated case statement to parse command line options.
1279 if [ $# != 0 ] ; then
1280     while true ; do
1281         case "$1" in 
1282             -V|--version)
1283                 version
1284                 exit 0
1285                 ;;
1286             -h|--help)
1287                 usage
1288                 exit 0
1289                 ;;
1290             --debug)
1291                 DEBUG=1
1292                 shift
1293                 ;;
1294             -v|--verbose)
1295                 VERBOSE=1
1296                 shift
1297                 ;;
1298             -f|--force)
1299                 FORCE=yes
1300                 shift
1301                 ;;
1302             -b|--boot)
1303                 if [ -n "$2" ] ; then
1304                     boot="$2"
1305                     ARGBT=1
1306                     shift 2
1307                 else
1308                     echo 1>&2 "$PRG: option requires an argument $1"
1309                     echo 1>&2 "Try \`$PRG --help' for more information."
1310                     exit 1
1311                 fi
1312                 ;;
1313             -o|--ofboot)
1314                 if [ -n "$2" ] ; then
1315                     ofboot="$2"
1316                     ARGOB=1
1317                     shift 2
1318                 else
1319                     echo 1>&2 "$PRG: option requires an argument $1"
1320                     echo 1>&2 "Try \`$PRG --help' for more information."
1321                     exit 1
1322                 fi
1323                 ;;
1324             -i|--install)
1325                 if [ -n "$2" ] ; then
1326                     install="$2"
1327                     ARGBF=1
1328                     shift 2
1329                 else
1330                     echo 1>&2 "$PRG: option requires an argument $1"
1331                     echo 1>&2 "Try \`$PRG --help' for more information."
1332                     exit 1
1333                 fi
1334                 ;;
1335             -C|--config)
1336                 if [ -n "$2" ] ; then
1337                     CONF="$2"
1338                     bootconf="$2"
1339                     ERR=" Error in $CONF:"
1340                     shift 2
1341                 else
1342                     echo 1>&2 "$PRG: option requires an argument $1"
1343                     echo 1>&2 "Try \`$PRG --help' for more information."
1344                     exit 1
1345                 fi
1346                 ;;
1347             -m|--magicboot)
1348                 if [ -n "$2" ] ; then
1349                     magicboot="$2"
1350                     ARGWP=1
1351                     shift 2
1352                 else
1353                     echo 1>&2 "$PRG: option requires an argument $1"
1354                     echo 1>&2 "Try \`$PRG --help' for more information."
1355                     exit 1
1356                 fi
1357                 ;;
1358             --filesystem)
1359                 if [ -n "$2" ] ; then
1360                     fstype="$2"
1361                     ARGFS=1
1362                     shift 2
1363                 else
1364                     echo 1>&2 "$PRG: option requires an argument $1"
1365                     echo 1>&2 "Try \`$PRG --help' for more information."
1366                     exit 1
1367                 fi
1368                 ;;
1369             --nobless)
1370                 bless=no
1371                 ARGBS=1
1372                 shift
1373                 ;;
1374             -M|--mount)
1375                 usemount=yes
1376                 ARGMT=1
1377                 shift
1378                 ;;
1379             --protect)
1380                 protect=yes
1381                 ARGPT=1
1382                 shift
1383                 ;;
1384             --hide)
1385                 hide=yes
1386                 ARGHD=1
1387                 shift
1388                 ;;
1389             --nonvram)
1390                 nonvram=1
1391                 ARGNV=1
1392                 shift
1393                 ;;
1394             --device)
1395                 if [ -n "$2" ] ; then
1396                     device="$2"
1397                     bootconf=auto
1398                     shift 2
1399                 else
1400                     echo 1>&2 "$PRG: option requires an argument $1"
1401                     echo 1>&2 "Try \`$PRG --help' for more information."
1402                     exit 1
1403                 fi
1404                 ;;
1405             --timeout)
1406                 if [ -n "$2" ] ; then
1407                     timeout="$2"
1408                     bootconf=auto
1409                     shift 2
1410                 else
1411                     echo 1>&2 "$PRG: option requires an argument $1"
1412                     echo 1>&2 "Try \`$PRG --help' for more information."
1413                     exit 1
1414                 fi
1415                 ;;
1416             --image)
1417                 if [ -n "$2" ] ; then
1418                     image="$2"
1419                     bootconf=auto
1420                     shift 2
1421                 else
1422                     echo 1>&2 "$PRG: option requires an argument $1"
1423                     echo 1>&2 "Try \`$PRG --help' for more information."
1424                     exit 1
1425                 fi
1426                 ;;
1427             --label)
1428                 if [ -n "$2" ] ; then
1429                     label="$2"
1430                     bootconf=auto
1431                     shift 2
1432                 else
1433                     echo 1>&2 "$PRG: option requires an argument $1"
1434                     echo 1>&2 "Try \`$PRG --help' for more information."
1435                     exit 1
1436                 fi
1437                 ;;
1438             --partition)
1439                 if [ -n "$2" ] ; then
1440                     partition="$2"
1441                     bootconf=auto
1442                     shift 2
1443                 else
1444                     echo 1>&2 "$PRG: option requires an argument $1"
1445                     echo 1>&2 "Try \`$PRG --help' for more information."
1446                     exit 1
1447                 fi
1448                 ;;
1449             --root)
1450                 if [ -n "$2" ] ; then
1451                     root="$2"
1452                     bootconf=auto
1453                     shift 2
1454                 else
1455                     echo 1>&2 "$PRG: option requires an argument $1"
1456                     echo 1>&2 "Try \`$PRG --help' for more information."
1457                     exit 1
1458                 fi
1459                 ;;
1460             "")
1461                 break
1462                 ;;
1463             *)
1464                 echo 1>&2 "$PRG: unrecognized option \`$1'"
1465                 echo 1>&2 "Try \`$PRG --help' for more information."
1466                 exit 1
1467                 ;;
1468         esac
1469     done
1470 fi
1471
1472 ## check that specified config file exists, unless its /dev/null in
1473 ## which case we assume all options are done on the command line.
1474 if [ "$CONF" = /dev/null ] ; then
1475     true
1476 else
1477     confexist || exit 1
1478 fi
1479
1480 ## if there is no config file use the automatic generation to make a
1481 ## generic yaboot.conf. do this before the confcheck to avoid wierd errors.
1482 if [ "$bootconf" = /dev/null ] ; then
1483     if (command -v yabootconfig > /dev/null 2>&1) ; then
1484         echo 1>&2 "$PRG: Warning: no /etc/yaboot.conf, running yabootconfig to make one"
1485         yabootconfig --noinstall --quiet
1486         if [ $? != 0 ] ; then
1487             echo 1>&2 "$PRG: yabootconfig failed, please supply a valid /etc/yaboot.conf"
1488             echo 1>&2 "$PRG: You may also use $PRG's --boot, --image, --partition, and --device switches"
1489             echo 1>&2 "$PRG: These switches will cause $PRG to generate a basic yaboot.conf on the fly"
1490             exit 1
1491         else
1492             CONF=/etc/yaboot.conf
1493             bootconf=$CONF
1494             ERR=" Error in $CONF:"
1495             confexist || exit 1
1496         fi
1497     fi
1498 fi
1499
1500 ## Checks if each option was defined on the command line, and if so
1501 ## don't read it from the configuration file. this avoids
1502 ## configuration options from being set null, as well as command line
1503 ## options from being clobbered.
1504 [ "$ARGBT" != 1 -a $(parseconf ck boot) = 0 ] && boot=`parseconf str boot`
1505 [ "$ARGOB" != 1 -a $(parseconf ck ofboot) = 0 ] && ofboot=`parseconf str ofboot`
1506 [ "$ARGBF" != 1 -a $(parseconf ck install) = 0 ] && install=`parseconf str install`
1507 [ "$ARGWP" != 1 -a $(parseconf ck magicboot) = 0 ] && magicboot=`parseconf str magicboot`
1508 [ "$ARGMT" != 1 -a $(parseconf flag usemount) = 0 ] && usemount=yes
1509 [ "$ARGFS" != 1 -a $(parseconf ck fstype) = 0 ] && fstype=`parseconf str fstype`
1510 [ "$ARGBS" != 1 -a $(parseconf flag nobless) = 0 ] && bless=no
1511 [ "$ARGPT" != 1 -a $(parseconf flag protect) = 0 ] && protect=yes
1512 [ "$ARGHD" != 1 -a $(parseconf flag hide) = 0 ] && hide=yes
1513 [ "$ARGNV" != 1 -a $(parseconf flag nonvram) = 0 ] && nonvram=1
1514 [ $(parseconf ck hfstype) = 0 ] && hfstype=`parseconf str hfstype`
1515 [ $(parseconf ck hfscreator) = 0 ] && hfscreator=`parseconf str hfscreator`
1516 [ $(parseconf ck mntpoint) = 0 ] && mntpoint=`parseconf str mntpoint`
1517 [ $(parseconf ck delay) = 0 ] && delay=`parseconf str delay`
1518 [ $(parseconf ck timeout) = 0 ] && timeout=`parseconf str timeout`
1519 [ $(parseconf ck bsd) = 0 ] && bsd=`parseconf str bsd`
1520 [ $(parseconf ck macos) = 0 ] && macos=`parseconf str macos`
1521 [ $(parseconf ck macosx) = 0 ] && macosx=`parseconf str macosx`
1522 [ $(parseconf ck darwin) = 0 ] && darwin=`parseconf str darwin`
1523 [ $(parseconf ck defaultos) = 0 ] && defaultos=`parseconf str defaultos`
1524 [ $(parseconf ck fgcolor) = 0 ] && fgcolor=`parseconf str fgcolor`
1525 [ $(parseconf ck bgcolor) = 0 ] && bgcolor=`parseconf str bgcolor`
1526 [ $(parseconf ck icon) = 0 ] && export YBINOFICON=`parseconf str icon`
1527 [ $(parseconf flag enablecdboot) = 0 ] && cdrom=yes
1528 [ $(parseconf flag enablenetboot) = 0 ] && network=yes
1529 [ $(parseconf flag enableofboot) = 0 ] && of=yes
1530 [ $(parseconf flag brokenosx) = 0 ] && brokenosx=yes
1531
1532 ## ffs!! rtfm! foad!
1533 if [ "$boot" = unconfigured ] ; then
1534     echo 1>&2 "$PRG: You must specify the device for the bootstrap partition. (ie: boot=/dev/hdaX)"
1535     echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
1536     exit 1
1537 fi
1538
1539 ## if there is still no config file use the automatic generation to make a
1540 ## generic yaboot.conf. do this before the confcheck to avoid wierd errors.
1541 if [ "$bootconf" = /dev/null ] ; then
1542     echo 1>&2 "$PRG: Warning: no yaboot.conf, using generic configuration."
1543     bootconf=auto
1544 fi
1545
1546 ## mntpoint is incompatible with mkofboot.
1547 if [ "$PRG" = mkofboot -a -n "$mntpoint" ] ; then
1548     echo 1>&2 "$PRG: Cannot be used with \`mntpoint='"
1549     exit 1
1550 fi
1551
1552 ## validate configuration for sanity.
1553 checkconf || exit 1
1554
1555 ## check that we can use ofpath, its only needed for magicboot script
1556 ## building and nvram updates.
1557 if [ -n "$magicboot" -o "$nonvram" = 0 ] ; then
1558     if [ -z "$ofboot" -o -n "$macos" -o -n "$macosx" -o -n "$darwin" ] ; then
1559         if (command -v ofpath > /dev/null 2>&1) ; then
1560             [ -x `command -v ofpath` ]
1561             if [ $? != 0 ] ; then
1562                 echo 1>&2 "$PRG: ofpath could not be found, aborting."
1563                 exit 1
1564             fi
1565         else
1566             echo 1>&2 "$PRG: ofpath could not be found, aborting."
1567             exit 1
1568         fi
1569     fi
1570 fi
1571
1572 ## if password is set in yaboot.conf make sure permissions on that
1573 ## file are safe, warn if not.
1574 if (grep -q '^[[:space:]]*password[[:space:]]*=' "$bootconf" > /dev/null 2>&1) ; then
1575     permcheck
1576 fi
1577
1578 ## check if we are root if needed.
1579 if [ "$usemount" = yes -a -z "$mntpoint" ] ; then
1580     if [ `id -u` != 0 ] ; then
1581         echo 1>&2 "$PRG: \`usemount' requires root privileges, go away."
1582         exit 1
1583     fi
1584 fi
1585
1586 if [ "$fstype" = hfs ] ; then
1587     checkhfsutils
1588     if [ $? != 0 ] ; then
1589         echo 1>&2 "$PRG: hfsutils is not installed or cannot be found"
1590         echo 1>&2 "$PRG: Try --mount if `uname -sr` supports HFS"
1591         exit 1
1592     fi
1593 fi
1594
1595 ## convert unix device nodes to OpenFirmware pathnames
1596 if [ -n "$magicboot" -o "$nonvram" = 0 ] ; then
1597     convertpath || exit 1
1598 fi
1599
1600 ## yaboot.conf autogeneration. MUST have secure mktemp to
1601 ## avoid race conditions. Debian's mktemp qualifies.
1602 if [ "$bootconf" = auto ] ; then
1603     TMPCONF=`mktemp -q "$TMP/$PRG.XXXXXX"`
1604     if [ $? != 0 ] ; then
1605         echo 1>&2 "$PRG: Could not create temporary file, aborting."
1606         exit 1
1607     fi
1608
1609     mkconf
1610     if [ $? != 0 ] ; then
1611         echo 1>&2 "$PRG: An error occured generating yaboot.conf, aborting."
1612         exit 1
1613     fi
1614
1615     bootconf="$TMPCONF"
1616 fi
1617
1618 if [ -n "$magicboot" ] ; then
1619     checkfirststage || exit 1
1620     if [ "$FIRSTSTG" = compat ] ; then
1621         mkfirststage
1622         if [ $? != 0 ] ; then
1623             echo 1>&2 "$PRG: An error occured while building first stage loader.  aborting..."
1624             exit 1
1625         fi
1626     fi
1627 fi
1628
1629 case "$PRG" in
1630     ybin)
1631         case "$usemount" in
1632             no)
1633                 if [ "$fstype" = raw ] ; then
1634                     luserck || exit 1
1635                     raw_install || exit 1
1636                 else
1637                     util_install || exit 1
1638                 fi
1639                 exit 0
1640                 ;;
1641             yes)
1642                 mnt_install || exit 1
1643                 exit 0
1644                 ;;
1645         esac
1646         ;;
1647     mkofboot)
1648         case "$usemount" in
1649             no)
1650                 ## its not nice to erase the partition and then bail!
1651                 if [ "$fstype" = msdos ] ; then
1652                     echo 1>&2 "$PRG: mtools support is not implemented"
1653                     echo 1>&2 "$PRG: Use --mount or add \`usemount' to $CONF"
1654                     exit 1
1655                 fi
1656                 confirm || exit 2
1657                 if [ "$fstype" = raw ] ; then
1658                     raw_install || exit 1
1659                 else
1660                     mkoffs || exit 1
1661                     util_install || exit 1
1662                 fi
1663                 [ "$VERBOSE" = 1 ] && echo "$PRG: Installation complete."
1664                 exit 0
1665                 ;;
1666             yes)
1667                 confirm || exit 2
1668                 mkoffs || exit 1
1669                 mnt_install || exit 1
1670                 [ "$VERBOSE" = 1 ] && echo "$PRG: Installation complete."
1671                 exit 0
1672                 ;;
1673         esac
1674         ;;
1675 esac
1676
1677 exit 0