Commit yaboot 1.3.0
[yaboot.git] / ybin / yabootconfig
1 #! /bin/sh
2
3 ###############################################################################
4 ##
5 ## yabootconfig generates a simple /etc/yaboot.conf
6 ## Copyright (C) 2001 Ethan Benson
7 ##
8 ## This program is free software; you can redistribute it and/or
9 ## modify it under the terms of the GNU General Public License
10 ## as published by the Free Software Foundation; either version 2
11 ## of the License, or (at your option) any later version.
12 ##
13 ## This program is distributed in the hope that it will be useful,
14 ## but WITHOUT ANY WARRANTY; without even the implied warranty of
15 ## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 ## GNU General Public License for more details.
17 ##
18 ## You should have received a copy of the GNU General Public License
19 ## along with this program; if not, write to the Free Software
20 ## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
21 ##
22 ###############################################################################
23
24 PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin"
25 ## allow to run out of /target in boot-floppies
26 if [ -n "$PATH_PREFIX" ] ; then
27     PATH="${PATH}:${PATH_PREFIX}/sbin:${PATH_PREFIX}/bin:${PATH_PREFIX}/usr/sbin:${PATH_PREFIX}/usr/bin:${PATH_PREFIX}/usr/local/sbin:${PATH_PREFIX}/usr/local/bin"
28 fi
29 PRG="${0##*/}"
30 VERSION=1.0.3
31 CHROOT=/
32 ## $CONFIG is relative to $CHROOT
33 CONFIG=etc/yaboot.conf
34 NOINSTALL=0
35 QUIET=0
36 SIGINT="$PRG: Interrupt caught ... exiting"
37 export LC_COLLATE=C
38
39 ## catch signals, clean up temporary file
40 trap "cleanup" 0
41 trap "exit 129" 1
42 trap "echo 1>&2 $SIGINT ; exit 130" 2
43 trap "exit 131" 3
44 trap "exit 143" 15
45
46 ## check for printf, use it if possible otherwise fall back on
47 ## unreliable echo -e -n ("SUS" says echo shall support no switches)
48 if [ "$(printf printf_test 2>/dev/null)" = printf_test ] ; then
49     PRINTF=printf
50 else
51     PRINTF="echo -e -n"
52 fi
53
54 ## make sure echo is not lame if we must use it.
55 if [ "$PRINTF" != printf ] ; then
56     if [ "$(echo -e -n echo_test)" != "echo_test" ] ; then
57         echo 1>&2 "$PRG: printf unavailable and echo is broken, sorry."
58         exit 1
59     fi
60 fi
61
62 ## make fake `id' if its missing, outputs 0 since if its missing we
63 ## are probably running on boot floppies and thus are root.
64 if (command -v id > /dev/null 2>&1) ; then 
65     true
66 else
67     id()
68     {
69     echo 0
70     }
71 fi
72
73 ## --version output
74 version()
75 {
76 echo \
77 "$PRG $VERSION
78 Written by Ethan Benson
79
80 Copyright (C) 2001 Ethan Benson
81 This is free software; see the source for copying conditions.  There is NO
82 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
83 }
84
85 ## --help output.
86 usage()
87 {
88 echo \
89 "Usage: $PRG [OPTION]...
90 Generate a working /etc/yaboot.conf.
91
92   -t, --chroot               set root directory $PRG should work from
93   -r, --root                 set root partition, Example: /dev/hda3
94                                default: determined from {chroot}/etc/fstab
95   -b, --boot                 set bootstrap partition, Example: /dev/hda2
96                                default: first type: Apple_Bootstrap partition
97       --kernel-args          add an append= line with specified arguments
98   -q, --quiet                don't ask any questions/confirmation
99       --noinstall            don't automatically run mkofboot
100   -h, --help                 display this help and exit
101   -V, --version              output version information and exit"
102 }
103
104 confirm()
105 {
106     $PRINTF \
107 "yaboot is the Linux Loader for PowerPC.  $PRG sets up your system to boot directly
108 from your hard disk, without the need for a boot CD, floppy or a network boot.\n"
109 [ "$NOINSTALL" = 0 ] && $PRINTF "Install yaboot bootstrap on $BOOT to boot Linux from $ROOT? [Yes] "
110 [ "$NOINSTALL" = 1 ] && $PRINTF "Create simple ${CHROOT}${CONFIG} to boot Linux from $ROOT? [Yes] "
111     read ans
112     case "$ans" in
113         Y|y|Yes|yes|YES|"")
114         echo "Creating a simple ${CHROOT}${CONFIG}..."
115         return 0
116         ;;
117         *)
118         if [ "$NOINSTALL" = 0 ] ; then
119             $PRINTF "Create simple ${CHROOT}${CONFIG} without installing the bootstrap? [Yes] "
120             read ans
121             case "$ans" in
122                 Y|y|Yes|yes|YES|"")
123                 NOINSTALL=1
124                 echo 1>&2 "Creating a simple ${CHROOT}${CONFIG}..."
125                 return 0
126                 ;;
127                 *)
128                 echo "OK, quitting"
129                 return 1
130                 ;;
131             esac
132         else
133             echo "OK, quitting"
134             return 1
135         fi
136         ;;
137     esac
138 }
139
140 ## find out whether we have mac-fdisk or pdisk (they work the same)
141 ckmacfdisk()
142 {
143     if (command -v mac-fdisk > /dev/null 2>&1) ; then
144         FDISK=mac-fdisk
145     elif (command -v pdisk > /dev/null 2>&1) ; then
146         FDISK=pdisk
147     else
148         echo 1>&2 "$PRG: Unable to locate mac-fdisk"
149         return 1
150     fi
151
152     if [ ! -x `command -v $FDISK` 2> /dev/null ] ; then
153         echo 1>&2 "$PRG: `command -v $FDISK`: Permission denied"
154         return 1
155     fi
156     return 0
157 }
158
159 ## find out if we have ddisk or fdisk (fdisk for dos labels) debian
160 ## uses both names
161 ckfdisk()
162 {
163     if (command -v ddisk > /dev/null 2>&1) ; then
164         FDISK=ddisk
165     elif (command -v fdisk > /dev/null 2>&1) ; then
166         FDISK=fdisk
167     else
168         echo 1>&2 "$PRG: Unable to locate fdisk"
169         return 1
170     fi
171
172     if [ ! -x `command -v $FDISK` 2> /dev/null ] ; then
173         echo 1>&2 "$PRG: `command -v $FDISK`: Permission denied"
174         return 1
175     fi
176     return 0
177 }
178
179 ## find bootstrap partition, supports IBM CHRP with msdos disklabels
180 findbootblock()
181 {
182     ## mac partition table magic == ER
183     if [ "$(dd if="$DISK" bs=2 count=1 2> /dev/null)" = ER ] ; then
184         ckmacfdisk || return 1
185         if [ "$FDISK" = pdisk ] ; then
186             ## handle braindamaged pdisk
187             BOOT="$(v=`$FDISK -l "$DISK" 2>/dev/null | grep '\<Apple_Bootstrap\>'` ; echo ${v%%:*})"
188             if [ -n "$BOOT" ] ; then
189                 BOOT="${DISK}${BOOT}"
190             fi
191         else
192             BOOT="$(v=`$FDISK -l "$DISK" 2>/dev/null | grep '\<Apple_Bootstrap\>'` ; echo ${v%%[ ]*})"
193         fi
194         if [ -z "$BOOT" ] ; then
195             echo 1>&2 "$PRG: Unable to locate bootstrap partition on $DISK..."
196             echo 1>&2 "$PRG: You must create an 800K type: Apple_Bootstrap partition to make the disk bootable"
197             return 1
198         fi
199     else
200         ckfdisk || return 1
201         BOOT="$(v=`$FDISK -l "$DISK" 2>/dev/null | grep '\<PPC PReP Boot\>'` ; echo ${v%%[ ]*})"
202         if [ -z "$BOOT" ] ; then
203             echo 1>&2 "$PRG: Unable to locate bootstrap partition on $DISK..."
204             echo 1>&2 "$PRG: You must create an 800K type: 0x41 PPC PReP Boot partition to make the disk bootable"
205             return 1
206         fi
207     fi
208     return 0
209 }
210
211 ## if readlink is missing use a kludge
212 if (command -v readlink > /dev/null 2>&1) ; then
213     true
214 else
215     readlink()
216     {
217         SYMTARGET="$(v=`ls -l "$2" 2>/dev/null` ; echo ${v##*> })"
218         if [ -n "$SYMTARGET" ] ; then
219             echo "$SYMTARGET"
220             return 0
221         else
222             return 1
223         fi
224     }
225 fi
226
227 ## we have to do some things differently with a retarded devfs name.
228 ckdevfs()
229 {
230     case "$1" in
231         /dev/ide/*|/dev/scsi/*|/dev/discs/*)
232         return 0
233         ;;
234         *)
235         return 1
236         ;;
237     esac
238 }
239
240 cleanup()
241 {
242     if [ -n "$TMPCONF" ] ; then rm -f "$TMPCONF" ; fi
243     return 0
244 }
245
246 ##########
247 ## Main ##
248 ##########
249
250 if [ $# != 0 ] ; then
251     while true ; do
252         case "$1" in 
253             -V|--version)
254                 version
255                 exit 0
256                 ;;
257             -h|--help)
258                 usage
259                 exit 0
260                 ;;
261             -t|--chroot)
262                 if [ -n "$2" ] ; then
263                     CHROOT="$2"
264                     shift 2
265                 else
266                     echo 1>&2 "$PRG: option requires an argument $1"
267                     echo 1>&2 "Try \`$PRG --help' for more information."
268                     exit 1
269                 fi
270                 ;;
271             -b|--boot)
272                 if [ -n "$2" ] ; then
273                     BOOT="$2"
274                     shift 2
275                 else
276                     echo 1>&2 "$PRG: option requires an argument $1"
277                     echo 1>&2 "Try \`$PRG --help' for more information."
278                     exit 1
279                 fi
280                 ;;
281             -r|--root)
282                 if [ -n "$2" ] ; then
283                     ROOT="$2"
284                     shift 2
285                 else
286                     echo 1>&2 "$PRG: option requires an argument $1"
287                     echo 1>&2 "Try \`$PRG --help' for more information."
288                     exit 1
289                 fi
290                 ;;
291             --kernel-args)
292                 if [ -n "$2" ] ; then
293                     KERNARGS="$2"
294                     shift 2
295                 else
296                     echo 1>&2 "$PRG: option requires an argument $1"
297                     echo 1>&2 "Try \`$PRG --help' for more information."
298                     exit 1
299                 fi
300                 ;;
301             -q|--quiet)
302                 QUIET=1
303                 shift 1
304                 ;;
305             --noinstall)
306                 NOINSTALL=1
307                 shift 1
308                 ;;
309             "")
310                 break
311                 ;;
312             *)
313                 echo 1>&2 "$PRG: unrecognized option \`$1'"
314                 echo 1>&2 "Try \`$PRG --help' for more information."
315                 exit 1
316                 ;;
317         esac
318     done
319 fi
320
321 if [ `id -u` != 0 ] ; then
322     echo 1>&2 "$PRG: You are not root, go away"
323     exit 1
324 fi
325
326 ## we need /proc because df does
327 if [ ! -f /proc/uptime ] ; then
328     echo 1>&2 "$PRG: This utility requires the /proc filesystem"
329     exit 1
330 fi
331
332 ## check that chroot exists
333 if [ -d "$CHROOT" ] ; then
334     ## HACK: add trailing / to chroot, otherwise are paths later get b0rked.
335     case "$CHROOT" in
336         */)
337         true
338         ;;
339         *)
340         CHROOT="${CHROOT}/"
341         ;;
342     esac
343 elif [ ! -e "$CHROOT" ] ; then
344     echo 1>&2 "$PRG: $CHROOT: No such file or directory"
345     exit 1
346 elif [ ! -d "$CHROOT" ] ; then
347     echo 1>&2 "$PRG: $CHROOT: Not a directory"
348     exit 1
349 fi
350
351 ## make sure the chroot is an actual root filesystem
352 if [ ! -f "${CHROOT}etc/fstab" ] ; then
353     echo 1>&2 "$PRG: $CHROOT does not appear to be a valid root filesystem"
354     exit 1
355 fi
356
357 ## find / device
358 if [ -z "$ROOT" ] ; then
359     ## IMPORTANT! that last substitution is [<space><tab>] thats all ash will grok
360     ROOT="$(v=`grep '[[:blank:]]/[[:blank:]]' ${CHROOT}etc/fstab` ; echo ${v%%[         ]*})"
361     if [ -z "$ROOT" ] ; then
362         echo 1>&2 "$PRG: Could not determine root partition, aborting..."
363         exit 1
364     fi
365 fi
366
367 ## make sure root device exists
368 if [ ! -e "$ROOT" ] ; then
369     echo 1>&2 "$PRG: $ROOT: No such file or directory"
370     exit 1
371 fi
372
373 ## find root disk.
374 if ckdevfs "$ROOT" ; then
375     DISK="${ROOT%/*}/disc"
376 else
377     DISK="${ROOT%%[0-9]*}"
378 fi
379 if [ -z "$DISK" ] ; then
380     echo 1>&2 "$PRG: Could not determine root disk, aborting..."
381     exit 1
382 fi
383
384 ## make sure main disk exists
385 if [ ! -e "$DISK" ] ; then
386     echo 1>&2 "$PRG: $DISK: No such file or directory"
387     exit 1
388 fi
389
390 ## find bootstrap partition
391 if [ -z "$BOOT" ] ; then
392     findbootblock || exit 1
393 fi
394
395 ## make sure bootstrap device exists
396 if [ ! -e "$BOOT" ] ; then
397     echo 1>&2 "$PRG: $BOOT: No such file or directory"
398     exit 1
399 fi
400
401 ## sanity check
402 for i in "$DISK" "$ROOT" "$BOOT" ; do
403     if [ ! -b "$i" ] ; then
404         echo 1>&2 "$PRG: $i: Not a block device"
405         exit 1
406     fi
407 done
408
409 ## unless --quiet ask permission to proceed
410 if [ "$QUIET" = 0 ] ; then
411     confirm || exit 2
412 fi
413
414 ## find the kernel in the usual places and (if not --quiet) ask the
415 ## user if we cannot find one.
416 if [ -f "${CHROOT}vmlinux" ] ; then
417     KERNEL="${CHROOT}vmlinux"
418 elif [ -f "${CHROOT}boot/vmlinux" ] ; then
419     KERNEL="${CHROOT}boot/vmlinux"
420 elif [ -f "${CHROOT}boot/vmlinux-`uname -r`" ] ; then
421     KERNEL="${CHROOT}boot/vmlinux-`uname -r`"
422 elif [ -f "${CHROOT}vmlinux-`uname -r`" ] ; then
423     KERNEL="${CHROOT}vmlinux-`uname -r`"
424 elif [ "$QUIET" = 0 ] ; then
425     echo 1>&2 "$PRG: Cannot find a kernel, please locate one"
426     while true ; do
427         $PRINTF 1>&2 "Enter path to a kernel image: "
428         read KERN
429         if [ -f "$KERN" ] ; then
430             KERNEL="$KERN"
431             break
432         elif [ ! -e "$KERN" ] ; then
433             echo 1>&2 "$PRG: $KERN: No such file or directory"
434         elif [ -d "$KERN" ] ; then
435             echo 1>&2 "$PRG: $KERN: Is a directory"
436         else
437             echo 1>&2 "$PRG: $KERN: Is not a regular file"
438         fi
439     done
440 else
441     echo 1>&2 "$PRG: Cannot find a kernel, aborting..."
442     exit 1
443 fi
444
445 ## get partition number the kernel lives on, and the OF device= name
446 ## of the whole disk.
447 KERNDEV="$(v=`df "$KERNEL" 2> /dev/null | grep ^/dev/` ; echo ${v%%[ ]*})"
448 KERNDIR="$(v=`df "$KERNEL" 2> /dev/null | grep ^/dev/` ; echo ${v##*[ ]})"
449 LINKDEV="$(v=`df "${KERNEL%/*}/" 2>/dev/null | grep ^/dev/` ; echo ${v%%[ ]*})"
450 PARTITION="${KERNDEV##*[a-z]}"
451
452 if ckdevfs "$KERNDEV" ; then
453     KERNELDISK="${KERNDEV%/*}/disc"
454 else
455     KERNELDISK="${KERNDEV%%[0-9]*}"
456 fi
457
458 ## sanity check
459 for i in "$KERNDEV" "$KERNDIR" "$LINKDEV" "$PARTITION" "$KERNELDISK" ; do
460     if [ -z "$i" ] ; then
461         echo 1>&2 "$PRG: Could not determine necessary information, aborting..."
462         exit 1
463     fi
464 done
465
466 ## check for cross device symlink
467 if [ -L "$KERNEL" ] ; then
468     if [ "$KERNDEV" != "$LINKDEV" ] ; then
469         echo 1>&2 "$PRG: Warning: Cross device symlink $KERNEL, using it's target instead"
470         KERNEL="$(readlink -f "$KERNEL" 2>/dev/null)"
471         if [ ! -f "$KERNEL" ] ; then
472             echo 1>&2 "$PRG: Unable to canonicalize symlink's target.  Do not create cross device symlinks."
473             exit 1
474         fi
475     fi
476 fi
477
478 ## only powermacs appear to need device=
479 if (cat /proc/cpuinfo 2>/dev/null | grep -q pmac-generation 2> /dev/null) ; then
480     DEVICE="\ndevice=$(ofpath $KERNELDISK)"
481     if [ $? != 0 ] ; then
482         echo 1>&2 "$PRG: Unable to determine OpenFirmware device name to $KERNELDISK, aborting..."
483         exit 1
484     fi
485 fi
486
487 ## IBM hardware needs fstype=raw for ybin
488 if (cat /proc/cpuinfo 2>/dev/null | grep ^machine | grep -q 'CHRP IBM') ; then
489     FSTYPE="\nfstype=raw"
490 fi
491
492 ## if there is a separate /boot partition we must strip off the /boot
493 ## mountpoint or else yaboot will not find the kernel.
494 if [ "$KERNDIR" != "$CHROOT" ] ; then
495     IMAGE="${KERNEL##*$KERNDIR}"
496 else
497     IMAGE="$KERNEL"
498 fi
499
500 ## fix chrooted path
501 if [ "$CHROOT" != / ] ; then
502     IMAGE="${IMAGE##*$CHROOT}"
503 fi
504
505 ## fix relative path (caused by chroot path fix)
506 case "$IMAGE" in
507     /*)
508     true
509     ;;
510     *)
511     IMAGE="/${IMAGE}"
512     ;;
513 esac
514
515 ## figure out if yaboot is installed in /usr/local or not
516 if [ -f /usr/local/lib/yaboot/yaboot ] ; then
517     INSTALL=/usr/local/lib/yaboot/yaboot
518 elif [ -f /usr/lib/yaboot/yaboot ] ; then
519     INSTALL=/usr/lib/yaboot/yaboot
520 else
521     echo 1>&2 "$PRG: yaboot is not installed correctly"
522     exit 1
523 fi
524
525 ## newworld powermacs need the ofboot first stage loader
526 if [ "$(v=`cat /proc/cpuinfo 2>/dev/null | grep pmac-generation` ; echo ${v##*:})" = NewWorld ] ; then
527     if [ -f /usr/local/lib/yaboot/ofboot ] ; then
528         OFBOOT="\nmagicboot=/usr/local/lib/yaboot/ofboot"
529     elif [ -f /usr/lib/yaboot/ofboot ] ; then
530         OFBOOT="\nmagicboot=/usr/lib/yaboot/ofboot"
531     else
532         echo 1>&2 "$PRG: yaboot is not installed correctly"
533         exit 1
534     fi
535 fi    
536
537 ## check for properly (read debian) packaged yaboot.
538 if [ -d ${CHROOT}usr/share/doc/yaboot/examples ] ; then
539     HEADER="## see also: /usr/share/doc/yaboot/examples for example configurations.\n"
540 fi
541
542 ## setup append line
543 if [ -n "$KERNARGS" ] ; then
544     APPEND="\tappend=\"${KERNARGS}\"\n"
545 fi
546
547 ## generate global section of yaboot.conf
548 GLOBAL="## yaboot.conf generated by $PRG $VERSION
549 ##
550 ## run: \"man yaboot.conf\" for details. Do not make changes until you have!!
551 ${HEADER}##
552 ## For a dual-boot menu, add one or more of: 
553 ## bsd=/dev/hdaX, macos=/dev/hdaY, macosx=/dev/hdaZ\n
554 boot=${BOOT}${FSTYPE:-}${DEVICE:-}
555 partition=$PARTITION
556 root=$ROOT
557 timeout=30
558 install=${INSTALL}${OFBOOT:-}\n"
559
560 ## generate image= section
561 IMAGES="
562 image=$IMAGE
563 \tlabel=Linux
564 \tread-only\n${APPEND:-}"
565
566 ## safely create a tmp file then move it into place after we are sure
567 ## it was written.
568 TMPCONF=`mktemp -q "${CHROOT}${CONFIG}.XXXXXX"`
569 if [ $? != 0 ] ; then
570     echo 1>&2 "$PRG: Unable to write to ${CHROOT}${CONFIG%/*}"
571     exit 1
572 fi
573
574 $PRINTF "${GLOBAL}${IMAGES}" > "$TMPCONF"
575 if [ $? != 0 ] ; then
576     echo 1>&2 "$PRG: Unable to write temporary file ${TMPCONF}, aborting..."
577     exit 1
578 fi
579
580 ## rotate backups of /etc/yaboot.conf, 3 backups are kept
581 if [ -f "${CHROOT}${CONFIG}.old" ] ; then
582     for i in 1 0 ; do
583         if [ -f "${CHROOT}${CONFIG}.old.${i}" ] ; then
584             mv -f "${CHROOT}${CONFIG}.old.$i" "${CHROOT}${CONFIG}.old.$(($i + 1))"
585             if [ $? != 0 ] ; then
586                 echo 1>&2 "$PRG: Unable to make backup of existing ${CHROOT}${CONFIG}.old.$i, aborting..."
587                 exit 1
588             fi
589         fi
590     done
591
592     mv -f "${CHROOT}${CONFIG}.old" "${CHROOT}${CONFIG}.old.0"
593     if [ $? != 0 ] ; then
594         echo 1>&2 "$PRG: Unable to make backup of existing ${CHROOT}${CONFIG}.old, aborting..."
595         exit 1
596     fi
597 fi
598
599 ## backup /etc/yaboot.conf
600 if [ -f "${CHROOT}${CONFIG}" ] ; then
601     mv -f "${CHROOT}${CONFIG}" "${CHROOT}${CONFIG}.old"
602     if [ $? != 0 ] ; then
603         echo 1>&2 "$PRG: Unable to make backup of existing ${CHROOT}${CONFIG}, aborting..."
604         exit 1
605     fi
606 fi
607
608 ## move new config into place
609 mv -f "${TMPCONF}" "${CHROOT}${CONFIG}"
610 if [ $? != 0 ] ; then
611     echo "$PRG: Unable to write file ${CHROOT}${CONFIG}"
612     exit 1
613 else
614     ## nothing sensitive in generated config, comply with debian policy
615     chmod 644 "${CHROOT}${CONFIG}"
616 fi
617
618 ## tell mkofboot where to find the config file if necessary
619 if [ "${CHROOT}${CONFIG}" != /etc/yaboot.conf ] ; then
620     YBINARGS="-C ${CHROOT}${CONFIG}"
621 fi
622
623 ## run mkofboot to install the bootstrap, unless --noinstall
624 if [ "$NOINSTALL" = 0 ] ; then
625     if (command -v mkofboot 2>&1 > /dev/null) ; then
626         [ "$QUIET" = 0 ] && echo "Running mkofboot to make the disk bootable..."
627         mkofboot -f $YBINARGS || exit 1
628         [ "$QUIET" = 0 ] && echo "Done"
629     else
630         echo 1>&2 "$PRG: yaboot is not installed correctly, not running mkofboot"
631         exit 1
632     fi
633 fi
634
635 exit 0