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