#! /bin/sh

###############################################################################
##
## ybin (YaBoot INstaller) installs/updates the yaboot bootloader.
## Copyright (C) 2000 Ethan Benson
##
## This program is free software; you can redistribute it and/or
## modify it under the terms of the GNU General Public License
## as published by the Free Software Foundation; either version 2
## of the License, or (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License          
## along with this program; if not, write to the Free Software                
## Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
##
###############################################################################

PATH="/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"
PRG=`echo ${0##*/}`
SIGINT="$PRG: Interrupt caught ... exiting"
VERSION=0.30
DEBUG=0
VERBOSE=0
#DIST="Debian GNU/Linux 2.2 (potato)"

## catch signals, clean up junk in /tmp.
trap "cleanup" 0
trap "exit 129" 1
trap "echo 1>&2 $SIGINT ; exit 130" 2
trap "exit 131" 3
trap "exit 143" 15

## allow for seamless transition to unified yaboot/ybin config file.
## also really allow for non-existent config file.
if [ -f /etc/ybin.conf ] ; then
    CONF=/etc/ybin.conf
    bootconf=/etc/yaboot.conf
    ERR=" Error in $CONF:"
elif [ -f /etc/yaboot.conf ] ; then 
    CONF=/etc/yaboot.conf
    bootconf=$CONF
    ERR=" Error in $CONF:"
else
    CONF=/dev/null
    bootconf=/dev/null
fi

## support the $TMPDIR variable as we should.
TMP="${TMPDIR:-/tmp}"

## define default configuration
## no default for magicboot since it hopefully will not be required forever.
boot=unconfigured

## allow default to work on packaged and non-packaged yaboot, also
## allow backwords compatible
if [ -f /usr/local/lib/yaboot/yaboot ] ; then
    install=/usr/local/lib/yaboot/yaboot
elif [ -f /usr/lib/yaboot/yaboot ] ; then
    install=/usr/lib/yaboot/yaboot
else
    install=/boot/yaboot
fi

usemount=no
fstype=hfs
hfstype=tbxi
hfscreator=UNIX
bless=yes
protect=no
hide=no
nonvram=0
delay=10
defaultos=linux
brokenosx=no
cdrom=no
network=no
of=no

## yaboot autoconf defaults
label=Linux
timeout=20
image=/vmlinux
partition=3
root=/dev/hda3
device=hd:

## this program behaves differently based on how its called, this
## ensures that nothing nasty happens if someone makes a bogus
## symlink.
case "$PRG" in
    ybin)
    ;;
    mkofboot)
    ;;
    *)
    echo 1>&2 "This program must be called as either \`ybin' or \`mkofboot'"
    exit 1
    ;;
esac

## check for printf, use it if possible otherwise fall back on
## unreliable echo -e -n ("SUS" says echo shall support no switches)

if [ -x /bin/printf -o -x /usr/bin/printf ] ; then
    PRINTF=printf
else
    PRINTF="echo -e -n"
fi

## make fake `id' if its missing, outputs 0 since if its missing we
## are probably running on boot floppies and thus are root.
if command -v id > /dev/null 2>&1 ; then 
    true
else
    id()
    {
    echo 0
    }
fi

## --version output
version()
{
echo \
"$PRG $VERSION
Written by Ethan Benson

Copyright (C) 2000 Ethan Benson
This is free software; see the source for copying conditions.  There is NO
warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE."
}

## --help output.
usage() 
{ 
echo \
"Usage: $PRG [OPTION]...
Update/install bootloader onto a bootstrap partition.

  -b, --boot                 set bootstrap partition device [ -b /dev/hda2 ]
  -o, --ofboot               set bootstrap partition OpenFirmware device [ -o hd:2 ]
  -i, --install              pathname to the actual bootloader binary
                               default: /usr/{local/}lib/yaboot/yaboot same as
                               install= in config file [ -i bootloader_file ]
  -C, --config               use alternate configuration file (ybin and yaboot)
			       [ -C config_file ]
  -m, --magicboot            pathname to a OpenFirmware magicboot (CHRP) script
      --filesystem           set the filesystem type of the bootstrap partition
                               options are hfs and msdos [ --filesystem hfs ]
                               default is hfs
      --type                 set the HFS file type given to the boot file
			       if a magicboot script is used it will get this 
			       type default: tbxi (HFS only)
      --creator              set the HFS creator code to all files 
			       default: UNIX (HFS only)
      --nobless              don't bless the root directory, this should only 
                               be used if you are using a MacOS boot partition
			       as the bootstrap partition (not recommended)
  -M, --mount                don't use userspace hfsutils to modify the 
			       bootstrap instead try and mount the filesystem 
                               directly.  Note that attributes cannot be set
			       this way and you will have to manually modify
			       OpenFirmware to make your system bootable.
      --protect              set the read-only (locked) bit on all bootstrap 
			       files
      --hide                 set the invisible bit on all bootstrap files
                               this is useful of you don't want them to be 
                               visible from MacOS.
      --nonvram              do not update the boot-device variable in nvram.
      --device               yaboot auto configuration: sets the OF boot device
			       default: hd:
      --partition            yaboot auto configuration: sets the partition 
			       number of the root partition. default: 3
      --timeout              yaboot auto configuration: sets the time yaboot
			       will wait for user input before booting default
                               image default: 20 (2 seconds)
      --image                yaboot auto configuration: sets the path to the 
			       kernel image. default: /vmlinux
      --label                yaboot auto configuration: sets the image label
                               default: Linux
      --root                 yaboot auto configuration: sets the root device
                               default: /dev/hda3
      --force                don't ever ask confirmation
  -v, --verbose              make $PRG more verbose. 
      --debug                print boring junk only useful for debugging
  -h, --help                 display this help and exit
  -V, --version              output version information and exit"
}

## configuration file parsing, not slow anymore! 
parseconf()
{
case "$1" in 
    str)
       v=`grep "^$2[\ ,=]" "$CONF"` ; echo "${v#*=}"
       ;;
    flag)
       grep "^$2\>" "$CONF" > /dev/null && echo 0 || echo 1
       ;;
    ck)
       grep "^$2[\ ,=]" "$CONF" > /dev/null && echo 0 || echo 1
       ;;
esac
}

## check for existence of a configuration file, and make sure we have
## read permission.
confexist()
{
    if [ ! -e "$CONF" ] ; then
	echo 1>&2 "$PRG: $CONF: No such file or directory"
	return 1
    elif [ ! -f "$CONF" ] ; then
	echo 1>&2 "$PRG: $CONF: Not a regular file"
	return 1
    elif [ ! -r "$CONF" ] ; then
	echo 1>&2 "$PRG: $CONF: Permission denied"
	return 1
    else 
	return 0
    fi
}

## check to make sure the configuration file is sane and correct.
## maybe this is an insane ammount of error checking, but I want to
## make sure (hopfully) nothing unexpected ever happens.  and i just
## like useful errors from programs.  every error just marks an error
## variable so we give the user as much info as possible before we
## abandon ship.

checkconf()
{
    if [ ! -e "$boot" ] ; then
	echo 1>&2 "$PRG: $boot: No such file or directory"
	CONFERR=1
    elif [ ! -b "$boot" -a ! -f "$boot" ] ; then
	echo 1>&2 "$PRG: $boot: Not a regular file or block device"
	CONFERR=1
    elif [ ! -w "$boot" -o ! -r "$boot" ] ; then
	[ -z "$mntpoint" ] && echo 1>&2 "$PRG: $boot: Permission denied"
	[ -z "$mntpoint" ] && CONFERR=1
    fi

    if [ ! -e "$install" ] ; then
	echo 1>&2 "$PRG: $install: No such file or directory"
	CONFERR=1
    elif [ ! -f "$install" ] ; then
	echo 1>&2 "$PRG: $bootconf: Not a regular file" 
	CONFERR=1
    elif [ ! -r "$install" ] ; then
	echo 1>&2 "$PRG: $install: Permission denied"
	CONFERR=1
    fi

    if [ "$bootconf" = auto ] ; then
	true
    elif [ ! -e "$bootconf" ] ; then
	echo 1>&2 "$PRG: $bootconf: No such file or directory"
	CONFERR=1
    elif [ ! -f "$bootconf" ] ; then
	echo 1>&2 "$PRG: $bootconf: Not a regular file" 
	CONFERR=1
    elif [ ! -r "$bootconf" ] ; then
	echo 1>&2 "$PRG: $bootconf: Permission denied"
	CONFERR=1
    fi

    if [ "$magicboot" ] ; then
	if [ ! -e "$magicboot" ] ; then
	    echo 1>&2 "$PRG: $magicboot: No such file or directory"
	    CONFERR=1
	elif [ ! -f "$magicboot" ] ; then
	    echo 1>&2 "$PRG: $magicboot: Not a regular file" 
	    CONFERR=1
	elif [ ! -r "$magicboot" ] ; then
	    echo 1>&2 "$PRG: $magicboot: Permission denied"
	    CONFERR=1
	fi
    fi

    case "$fstype" in
	hfs|msdos)
	 ;;
	*)
	 if [ "$ARGFS" = 1 ] ; then
	    echo 1>&2 "$PRG: --filesystem must be either \`hfs' or \`msdos'"
	 else
	    echo 1>&2 "$PRG:$ERR \`fstype' must be either \`hfs' or \`msdos'"
	 fi
	 CONFERR=1
	 ;;
    esac

    ## if we are not using HFS filesystems we don't care about HFS
    ## specific options.
    if [ "$fstype" = hfs ] ; then
	if [ `echo ${#hfstype}` != 4 ] ; then
	    if [ "$ARGTP" = 1 ] ; then
		echo 1>&2 "$PRG: --type must be 4 characters"
	    else
		echo 1>&2 "$PRG:$ERR \`hfstype' must be 4 characters"
	    fi
	    CONFERR=1
	fi
	
	if [ `echo ${#hfscreator}` != 4 ] ; then
	    if [ "$ARGCT" = 1 ] ; then
		echo 1>&2 "$PRG: --creator must be 4 characters"
	    else
		echo 1>&2 "$PRG:$ERR \`hfscreator' must be 4 characters"
	    fi
	    CONFERR=1
	fi
    fi

    if [ -n "$mntpoint" ] ; then
	## standard checks
	if [ ! -e "$mntpoint" ] ; then
	    echo 1>&2 "$PRG: $mntpoint: No such file or directory"
	    CONFERR=1
	elif [ ! -d "$mntpoint" ] ; then
	    echo 1>&2 "$PRG: $mntpoint: Not a directory" 
	    CONFERR=1
	elif [ ! -w "$mntpoint" -o ! -r "$mntpoint" ] ; then
	    echo 1>&2 "$PRG: $mntpoint: Permission denied"
	    CONFERR=1
	elif [ ! -O "$mntpoint" -a `id -u` != 0 ] ; then
	    echo 1>&2 "$PRG: $mntpoint: Permission denied (not owner)"
	    CONFERR=1
	fi

	## make sure no embedded spaces exist
	echo "$mntpoint" | grep -q [[:space:]]
	if [ $? = 0 ] ; then
	    echo 1>&2 "$PRG:$ERR \`mntpoint=$mntpoint' contains embedded spaces, don't use lame filenames"
	    CONFERR=1
	fi

	## make sure $mntpoint is on $boot, this matters to nvram updating
	if [ "$(v=`df "$mntpoint" 2> /dev/null | grep ^/dev/` ; echo ${v%%[ ]*})" != "$boot" -a -d "$mntpoint" ] ; then
	    echo 1>&2 "$PRG: $mntpoint is not located on $boot"
	    CONFERR=1
	    ## more then one subdirectory deep is not supported. no sed available on boot floppies ( / -> \ )
	elif [ "$mntpoint" != "$(v=`df "$mntpoint" 2> /dev/null | grep ^/dev/` ; echo ${v##*[ ]})" ] ; then
	    echo "$(v=`df "$mntpoint" 2>/dev/null | grep ^/dev/`; m=${v##*[ ]}; echo "${mntpoint##*$m/}")" | grep -q /
	    if [ $? = 0 ] ; then
		echo 1>&2 "$PRG:$ERR $mntpoint is more then one subdirectory deep from root of $boot"
		CONFERR=1
	    else
		OFDIR="$(v=`df "$mntpoint" 2>/dev/null | grep ^/dev/`; m=${v##*[ ]}; echo "${mntpoint##*$m/}")"
	    fi
	fi

	if [ "$usemount" = no ] ; then
	    echo 1>&2 "$PRG:$ERR \`mntpoint=' requires \`usemount' be set"
	    CONFERR=1
	fi
    fi

    case "$defaultos" in 
	linux|Linux)
	    defaultos=bootyaboot
	    ;;
	bootyaboot)
	    ;;
	macos)
	    defaultos=bootmacos
	    if [ -z "$macos" ] ; then
		echo 1>&2 "$PRG:$ERR no entry for \`macos' found, but defaultos is set to \`macos'"
		CONFERR=1
	    fi
	    ;;
	macosx)
	    defaultos=bootmacosx
	    if [ -z "$macosx" ] ; then
		echo 1>&2 "$PRG:$ERR no entry for \`macosx' found, but defaultos is set to \`macosx'"
		CONFERR=1
	    fi
	    ;;
	darwin)
	    defaultos=bootdarwin
	    if [ -z "$darwin" ] ; then
		echo 1>&2 "$PRG:$ERR no entry for \`darwin' found, but defaultos is set to \`darwin'"
		CONFERR=1
	    fi
	    ;;
	*)
	    echo 1>&2 "$PRG:$ERR \`defaultos' must be either \`linux', \`macos' or \`macosx'"
	    CONFERR=1
	    ;;
    esac

    if [ "$nonvram" = 0 ] ; then
	
	## see if nvsetenv exists and is executable
	if command -v nvsetenv > /dev/null 2>&1 ; then
	    [ -x `command -v nvsetenv` ] || MISSING=1 ; else MISSING=1
	fi

	## i check this myself to avoid misleading error
	## messages. nvsetenv should REALLY support --version.
	if [ ! -e /dev/nvram ] ; then
	    echo 1>&2 "$PRG: /dev/nvram: No such file or directory"
	    nonvram=1
	elif [ ! -c /dev/nvram ] ; then
	    echo 1>&2 "$PRG: /dev/nvram: Not a character device"
	    nonvram=1
	elif [ ! -w /dev/nvram -o ! -r /dev/nvram ] ; then
	    echo 1>&2 "$PRG: /dev/nvram: Permission denied"
	    nonvram=1
	fi

	if [ "$nonvram" = 0 ] ; then
	    ## if nvsetenv exists see if its the old broken version
	    if [ "$MISSING" != 1 ] ; then
		nvsetenv --version > /dev/null 2>&1 || OLD=1
	    else
		nonvram=1
		echo 1>&2 "$PRG: Warning: \`nvsetenv' could not be found, nvram will not be updated"
	    fi
	    
	    if [ "$OLD" = 1 ] ; then
		nonvram=1
		echo 1>&2 "$PRG: Warning: Incompatible version of \`nvsetenv', nvram will not be updated"
	    fi
	fi

	if [ -f "$boot" ] ; then
	    echo 1>&2 "$PRG: $boot is a regular file, disabling nvram updating"
	    nonvram=1
	fi
    fi

    ## check for newworld mac. use cat hack due to /proc wierdness.
    ## do not bail if we are on an OldWorld only warn. 
    if [ "$(v=`cat /proc/cpuinfo 2> /dev/null | grep pmac-generation` ; echo ${v##*:})" = NewWorld ] ; then
	true
    elif [ "$(v=`cat /proc/cpuinfo 2> /dev/null | grep pmac-generation` ; echo ${v##*:})" = OldWorld ] ; then
	echo 1>&2 "$PRG: Warning: This is an OldWorld PowerMac, $boot will not be bootable on this machine"
	[ "$nonvram" = 0 ] && echo 1>&2 "$PRG: OldWorld PowerMac, nvram will not be updated"
	nonvram=1
    else
	echo 1>&2 "$PRG: Warning: Unknown architecture, nvram will not be updated"
	nonvram=1
    fi

    if [ "$CONFERR" = 1 ] ; then 
	return 1
    else 
	return 0
    fi
}

convertpath()
{
    ## figure out bootstrap device OF pathname if user did not supply it.

    if [ -z "$ofboot" ] ; then
	[ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$boot'..."
	ofboot="$(ofpath $boot)"
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: Unable to find OpenFirmware path for boot=$boot"
	    echo 1>&2 "$PRG: Please add ofboot=<path> where <path> is the OpenFirmware path to $boot to $CONF"
	    CONVERR=1
	fi
	[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: ofboot set to \`$ofboot'"
    fi

    ## figure out OF device path for macos/macosx if user supplied a unix device node.

    if [ -n "$macos" ] ; then
	case "$macos" in 
	    /dev/*)
		[ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$macos'..."
		smacos="$macos"
		macos="$(ofpath $macos)"
		if [ $? != 0 ] ; then
		    echo 1>&2 "$PRG: Unable to determine OpenFirmware path for macos=$smacos"
		    echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for macos=$smacos in $CONF"
		    CONVERR=1
		fi
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macos set to \`$macos' from \`$smacos'"
		;;
	    *)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macos left alone: \`$macos'"
		;;
	esac
    fi

    if [ -n "$macosx" ] ; then
	case "$macosx" in
	    /dev/*)
		[ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$macosx'..."
		smacosx="$macosx"
		macosx="$(ofpath $macosx)"
		if [ $? != 0 ] ; then
		    echo 1>&2 "$PRG: Unable to determine OpenFirmware path for macosx=$smacosx"
		    echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for macosx=$smacosx in $CONF"
		    CONVERR=1
		fi
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macosx set to \`$macosx' from \`$smacosx'"
		;;
	    *)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: macosx left alone: \`$macosx'"
		;;
	esac
    fi

    if [ -n "$darwin" ] ; then
	case "$darwin" in
	    /dev/*)
		[ "$VERBOSE" = 1 ] && echo "$PRG: Finding OpenFirmware device path to \`$darwin'..."
		sdarwin="$darwin"
		darwin="$(ofpath $darwin)"
		if [ $? != 0 ] ; then
		    echo 1>&2 "$PRG: Unable to determine OpenFirmware path for darwin=$sdarwin"
		    echo 1>&2 "$PRG: Try specifying the real OpenFirmware path for darwin=$sdarwin in $CONF"
		    CONVERR=1
		fi
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: darwin set to \`$darwin' from \`$sdarwin'"
		;;
	    *)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: darwin left alone: \`$darwin'"
		;;
	esac
    fi

    if [ "$CONVERR" = 1 ] ; then 
	return 1
    else 
	return 0
    fi
}

## make sure the hfsutils we need are installed and executable.

checkhfsutils()
{
    if command -v hmount > /dev/null 2>&1 ; then 
	[ -x `command -v hmount` ] || FAIL=1 ; else FAIL=1 ; fi
    if command -v humount > /dev/null 2>&1 ; then 
	[ -x `command -v humount` ] || FAIL=1 ; else FAIL=1 ; fi
    if command -v hcopy > /dev/null 2>&1 ; then
	[ -x `command -v hcopy` ] || FAIL=1 ; else FAIL=1 ; fi
    if command -v hattrib > /dev/null 2>&1 ; then
	[ -x `command -v hattrib` ] || FAIL=1 ; else FAIL=1 ; fi
    if command -v hformat > /dev/null 2>&1 ; then
	[ -x `command -v hformat` ] || FAIL=1 ; else FAIL=1 ; fi

    if [ "$FAIL" = 1 ] ; then
	return 1
    else
	return 0
    fi
}

## install using userspace utilities rather then kernel filesytem
## support.  this would be hfsutils and mtools for dos, right now its
## only hfsutils since i am too lazy to figure out how mtools works.
## dosfs kernel support is almost without question available anyway.

util_install()
{
    ## catch signals, and humount, cleanup done by trap 0.
    trap "humount $boot ; exit 129" 1
    trap "echo 1>&2 $SIGINT ; humount $boot ; exit 130" 2
    trap "humount $boot ; exit 131" 3
    trap "humount $boot ; exit 143" 15

    ## this is just to neaten up the code below.  yaboot requires the
    ## yaboot.conf (or yaboot.cnf) filename so we just hard code that
    ## here. the new ofboot.b will have to hard code a yaboot filename
    ## due to some broken OF (and to avoid more messiness in ofboot.b).

    BTFILE=yaboot
    CFFILE=yaboot.conf

    ## if there is a magicboot script to install we will give it the
    ## hfstype (should be "tbxi") and give yaboot type "boot".  This
    ## way the right file gets loaded by OF.  Might make all filetypes
    ## configurable, but its really not important.

    if [ "$magicboot" ] ; then
	BTTYPE=boot
    else
	BTTYPE="$hfstype"
    fi

    if [ "$magicboot" ] ; then
	WRAP=`echo ${magicboot##*/}`
    fi

    ## repoint magicboot as the real first stage loader if using the
    ## modern automatic generating ofboot.b. 

    INSTALLFIRST="$PRG: Copying $magicboot to $boot..."

    if [ "$FIRST" ] ; then
	magicboot="$FIRST"
	INSTALLFIRST="$PRG: Installing first stage bootstrap: $WRAP..."
	[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: set magicboot to $FIRST"
    fi

    if [ "$fstype" = hfs ] ; then
    
	if [ "$protect" = yes ] ; then
	    LOCK="+l"
	fi
	
	if [ "$hide" = yes ] ; then
	    INVISIBLE="+i"
	fi

	## make sure the device is not mounted as a filesystem before
	## we start mucking with it directly.

	mount | grep "^$boot\>" > /dev/null
	if [ $? = 0 ] ; then
	    echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
	    return 1
	fi	    

	## hmount is really more of a way to make sure we have a valid HFS
	## filesystem before proceding, and hcopy requires it...

	[ "$VERBOSE" = 1 ] && echo "$PRG: Checking $boot for valid HFS filesystem..."
	hmount "$boot" > /dev/null
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: An error occured trying to access $boot as HFS"
	    return 1
	fi
	
	[ "$VERBOSE" = 1 ] && echo "$PRG: Copying $install to $boot..."	
	hcopy -r "$install" :"$BTFILE"
	if [ $? != 0 ] ; then 
	    echo 1>&2 "$PRG: An error occured while copying files to $boot"
	    return 1
	fi

	## config filename must be explicit to work with auto generation.

	[ "$VERBOSE" = 1 ] && echo "$PRG: Copying $bootconf to $boot..."
	hcopy -r "$bootconf" :"$CFFILE"
	if [ $? != 0 ] ; then 
	    echo 1>&2 "$PRG: An error occured while copying files to $boot"
	    return 1
	fi

	## must be explicit with target filename to avoid hfsutils
	## braindamage ("_" -> " " filename mangling)

	if [ "$magicboot" ] ; then
	    [ "$VERBOSE" = 1 ] && echo "$INSTALLFIRST"
	    hcopy -r "$magicboot" :ofboot.b
	    if [ $? != 0 ] ; then 
	       echo 1>&2 "$PRG: An error occured while copying files to $boot"
	       return 1
	    fi
	fi

	## set all file's attributes, if a magicboot script exists it
	## gets the configured hfstype instead of yaboot (should be
	## "tbxi") so it gets booted by OF.

	[ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $BTFILE..."
	hattrib -t "$BTTYPE" -c "$hfscreator" $INVISIBLE $LOCK :"$BTFILE"
	if [ $? != 0 ] ; then 
	    echo 1>&2 "$PRG: Warning: error setting attributes on $BTFILE"
	    echo 1>&2 "$PRG: This is probably bad but we'll ignore it"
	fi

	[ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $CFFILE..."
	hattrib -t "conf" -c "$hfscreator" $INVISIBLE $LOCK :"$CFFILE"
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: Warning: error setting attributes on $CFFILE"
	    echo 1>&2 "$PRG: This is probably unimportant so we'll ignore it"
	fi
	
	if [ "$magicboot" ] ; then
	    [ "$VERBOSE" = 1 ] && echo "$PRG: Setting attributes on $WRAP..."
	    hattrib -t "$hfstype" -c "$hfscreator" $INVISIBLE $LOCK :ofboot.b
	    if [ $? != 0 ] ; then
		echo 1>&2 "$PRG: Warning: error setting attributes on $WRAP"
		echo 1>&2 "$PRG: This is probably bad but we'll ignore it."
	    fi
	fi

	## bless the root directory so OF will find the boot file
	if [ "$bless" = yes ] ; then
	    [ "$VERBOSE" = 1 ] && echo "$PRG: Blessing $boot..."
	    hattrib -b :
	    if [ $? != 0 ] ; then
		echo 1>&2 "$PRG: Warning: error blessing $boot"
		echo 1>&2 "$PRG: This is probably bad but we'll ignore it"
	    fi
	fi

	## clean up the ~/.hcwd file hmount creates
	[ "$VERBOSE" = 1 ] && echo "$PRG: Cleaning up..."
	humount "$boot" > /dev/null
	sync ; sync

	## use explicit filename if we don't bless.
	if [ "$bless" = yes ] ; then
	    OFFILE='\\:tbxi'
	else
	    if [ -n "$magicboot" ] ; then
		OFFILE=ofboot.b
	    fi
	fi

	## update the boot-device variable in OF nvram.
	if [ "$nonvram" = 0 ] ; then
	    [ "$VERBOSE" = 1 ] && echo "$PRG: Updating OpenFirmware boot-device variable in nvram..."
	    [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-device=${ofboot},${OFFILE}"
	    nvsetenv boot-device "${ofboot},${OFFILE}"
	    if [ $? != 0 ] ; then
		echo 1>&2 "$PRG: An error occured while updating nvram, we'll ignore it"
	    fi
	fi

    else 
	echo 1>&2 "$PRG: mtools support is not implemented"
	echo 1>&2 "$PRG: Use --mount or add \`usemount' to $CONF"
	return 1
    fi

    return 0
}

## used by mnt_install so mntpoint= can be supported in a cleaner way.
mnt()
{
    ## we can even create bootstrap filesystem images directly if you
    ## ever wanted too.

    if [ -f "$boot" ] ; then
	loop=",loop"
    fi

    if [ -e "$TMP/bootstrap.$$" ] ; then
	echo 1>&2 "$PRG: $TMP/bootstrap.$$ exists, aborting."
	return 1
    fi

    mkdir -m 700 "$TMP/bootstrap.$$"
    if [ $? != 0 ] ; then
	echo 1>&2 "$PRG: Could not create mountpoint directory, aborting."
	return 1
    fi

    mount | grep "^$boot\>" > /dev/null
    if [ $? = 0 ] ; then
	echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
	return 1
    fi

    [ "$VERBOSE" = 1 ] && echo "$PRG: Mounting $boot..."
    mount -t "$fstype" -o rw,umask=077$loop "$boot" "$TMP/bootstrap.$$"
    if [ $? != 0 ] ; then 
	echo 1>&2 "$PRG: An error occured mounting $boot"
	return 1
    fi

    ## catch signals, set here to avoid umounting something we did not
    ## mount. cleanup done by trap 0.
    trap "umount $boot ; exit 129" 1
    trap "echo 1>&2 $SIGINT ; umount $boot ; exit 130" 2
    trap "umount $boot ; exit 131" 3
    trap "umount $boot ; exit 143" 15

    TARGET="$TMP/bootstrap.$$"
    return 0
}

## umnt funtion which checks whether we mounted anything or not, for
## mntpoint= this makes the code below cleaner IMO.
umnt()
{
    if [ -z "$mntpoint" ] ; then
    	[ "$1" = failure ] && echo 1>&2 "$PRG: Attempting to umount $boot..."
	umount "$2"
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: umount of $boot failed!"
	    return 1
	else
	    [ "$1" = failure ] && echo 1>&2 "$PRG: umount successfull"
	    return 0
	fi
    else
	return 0
    fi
}

## Use kernel filesytem drivers to mount the bootstrap partition like
## any other filesystem and copy the files there with standard un*x
## utilities. 

mnt_install()
{
    ## i have decided to just hard code the target filename to avoid
    ## more messiness in ofboot.b

    BTFILE=yaboot
  
    if [ "$fstype" = msdos ] ; then
	CFFILE=yaboot.cnf
    else
	CFFILE=yaboot.conf
    fi

    if [ "$magicboot" ] ; then
	WRAP=`echo ${magicboot##*/}`
    fi

    INSTALLFIRST="$PRG: Copying $magicboot to $boot..."

    ## repoint magicboot as the real first stage loader if using the
    ## modern automatic generating ofboot.b. 

    if [ "$FIRST" ] ; then
	magicboot="$FIRST"
	INSTALLFIRST="$PRG: Installing first stage bootstrap: $WRAP..."
	[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: set magicboot to $FIRST"
    fi

    ## call mnt() function to take care of mounting filesystem if needed
    if [ -z "$mntpoint" ] ; then
	mnt || return 1
    else
	TARGET="$mntpoint"
    fi

    [ "$VERBOSE" = 1 ] && echo "$PRG: Copying $install to $boot..."
    cp -f "$install" "$TARGET/$BTFILE" 
    if [ $? != 0 ] ; then 
	echo 1>&2 "$PRG: An error occured while copying files to $boot"
	umnt failure "$TARGET"
	return 1
    fi

    [ "$VERBOSE" = 1 ] && echo "$PRG: Copying $bootconf to $boot..."
    cp -f "$bootconf" "$TARGET/$CFFILE"
    if [ $? != 0 ] ; then 
	echo 1>&2 "$PRG: An error occured while copying files to $boot"
	umnt failure "$TARGET"
	return 1 
    fi

    if [ "$magicboot" ] ; then
	[ "$VERBOSE" = 1 ] && echo "$INSTALLFIRST"
	cp -f "$magicboot" "$TARGET/ofboot.b"
	if [ $? != 0 ] ; then 
	    echo 1>&2 "$PRG: An error occured while copying files to $boot"
	    umnt failure "$TARGET"
	    return 1 
	fi
    fi

    if [ "$protect" = yes ] ; then 
        [ "$VERBOSE" = 1 ] && echo "$PRG: Setting read-only attributes..."
	chmod a-w "$TARGET/$BTFILE"
	chmod a-w "$TARGET/$CFFILE"
	if [ "$magicboot" ] ; then
	    chmod a-w "$TARGET/ofboot.b"
	fi
    fi

    [ "$VERBOSE" = 1 ] && echo "$PRG: Cleaning up..."
    sync ; sync
    umnt success "$TARGET" || return 1

    ## make variable with a \ to avoid shell fsckage.  ugly ugly ugly.
    BS='\'
    if [ -n "$magicboot" ] ; then
	[ -n "$OFDIR" ] && OFDIR="${BS}${OFDIR}${BS}"
	OFFILE="${OFDIR}ofboot.b"
    else
	[ -n "$OFDIR" ] && OFDIR="${BS}${OFDIR}${BS}"
	OFFILE="${OFDIR}${BTFILE}"
    fi

    ## update the boot-device variable in OF nvram.
    if [ "$nonvram" = 0 ] ; then
	[ "$VERBOSE" = 1 ] && echo "$PRG: Updating OpenFirmware boot-device variable in nvram..."
	[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: boot-device=${ofboot},${OFFILE}"
	nvsetenv boot-device "${ofboot},${OFFILE}"
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: An error occured while updating nvram, we'll ignore it"
	fi
    else
	echo 1>&2 "$PRG: Warning: You must manually configure OpenFirmware to boot."
    fi

    return 0
}

## make sure the first stage ofboot generator is compatible.
checkfirststage()
{
    grep "^#%ybinscript-" "$magicboot" > /dev/null
    if [ "$?" = 0 ] ; then
	magic=`grep "^#%ybinscript-" "$magicboot"`
	ver=`echo ${magic##*-}`
	if [ "$ver" = "0.5" ] ; then
	    FIRSTSTG=compat
	    return 0
	else
	    echo 1>&2 "$PRG: Incompatible version of first stage loader $magicboot.  aborting..."
	    return 1
        fi
    else 
	FIRSTSTG=old
	return 0
    fi
}

## build the first stage loader.
mkfirststage()
{
    ## must have 7 backslashes to == \\ printf + shell = bizarre... or...
    ## make special variable to contain a \ (need \\ to make \) to work
    ## around echo -e -n brokeness.
    BS='\\'
    OS=1

    ## deal with mntpoint=
    [ -n "$OFDIR" ] && OFDIR="${BS}${OFDIR}${BS}"

    ## some misguided people insist on installing OSX on
    ## HorribleFileSystem+ instead of UFS, as a result MacOS deblesses
    ## OSX, making it unbootable. if apple localizes the filesystem hierarchy again screw it. 
    [ "$brokenosx" = yes ] && OSXBOOT="${BS}System${BS}Library${BS}CoreServices${BS}BootX"
    [ "$brokenosx" = no ] && OSXBOOT="${BS}${BS}:tbxi"

    ## assign variables for configured menu options.
    [ "$usemount" = no -a "$bless" = yes ] && YB="yaboot GNU l $ofboot ,${BS}${BS}yaboot"
    [ "$usemount" = yes -o "$bless" = no ] && YB="yaboot GNU l $ofboot ,${OFDIR}yaboot"
    [ -n "$macos" ] && OS=$(($OS + 1)) && MAC="macos MacOS m $macos ,${BS}${BS}:tbxi"
    [ -n "$macosx" ] && OS=$(($OS + 1)) && MX="macosx MacOSX x $macosx ,${OSXBOOT}"
    [ -n "$darwin" ] && OS=$(($OS + 1)) && DW="darwin Darwin d $darwin ,${BS}${BS}:tbxi"
    [ "$cdrom" = yes ] && OS=$(($OS + 1)) && CD="cd CDROM c cd: ,${BS}${BS}:tbxi"
    [ "$network" = yes ] && OS=$(($OS + 1)) && NET="net Network n enet: 0"
    [ "$of" = yes ] && OS=$(($OS + 1)) && OF="of OpenFirmware o quit now"
    [ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: OS=$OS"

    ## call ofboot, 
    ## Usage: OS-count defaultos timeout osname oslabel oskey osdev osfile ...
    [ "$DEBUG" = 1 ] && $PRINTF 1>&2 "$PRG: DEBUG: /bin/sh $magicboot $OS $defaultos $delay $YB $MAC $MX $DW $CD $NET $OF\n"
    FIRST=`/bin/sh "$magicboot" "$OS" "$defaultos" "$delay" ${YB} ${MAC} ${MX} ${DW} ${CD} ${NET} ${OF}` || return 1

    return 0
}

## mkofboot function.
mkoffs()
{
    mount | grep "^$boot\>" > /dev/null 
    if [ $? = 0 ] ; then
	echo 1>&2 "$PRG: $boot appears to be mounted! aborting."
        return 1
    fi

    case "$fstype" in 
	hfs)
	    [ "$VERBOSE" = 1 ] && echo "$PRG: Creating HFS filesystem on $boot..."
	    hformat -l bootstrap "$boot" > /dev/null
	    if [ $? != 0 ] ; then
		echo 1>&2 "$PRG: HFS filesystem creation failed!"
		return 1
	    fi
	    humount "$boot" ## otherwise we might get confused.
	    return 0
	    ;;
	msdos)
	    if command -v mkdosfs > /dev/null 2>&1 ; then 
		[ -x `command -v mkdosfs` ] || FAIL=1 ; else FAIL=1 ; fi
		if [ "$FAIL" = 1 ] ; then
		    echo 1>&2 "$PRG: mkdosfs is not installed or cannot be found"
		    return 1
		fi

	    [ "$VERBOSE" = 1 ] && echo "$PRG: Creating DOS filesystem on $boot..."
	    mkdosfs -n bootstrap "$boot" > /dev/null
            if [ $? != 0 ] ; then
		echo 1>&2 "$PRG: DOS filesystem creation failed!"
		return 1
	    fi
	    return 0
	    ;;
    esac
}

confirm()
{
    if [ "$FORCE" = yes ] ; then 
	return 0
    else
	echo 1>&2
	$PRINTF 1>&2 "$PRG: Create $fstype filesystem on $boot? [y/N] "
	read ans
	case "$ans" in 
	    y|Y)
		return 0
		;;
	    *)
		echo 1>&2 "$PRG: Abort."
		return 2
		;;
	esac
    fi
}

mkconf()
{
## defaults for this are defined at the beginning of the script with
## other variables.

echo \
"## yaboot configuration file generated by ybin $VERSION
## $DIST

device=$device
timeout=$timeout

image=$image
	label=$label
	partition=$partition
	root=$root
	read-only
" > "$TMPCONF" || return 1

[ "$DEBUG" = 1 ] && $PRINTF 1>&2 "\nDEBUG: autoconf:\n----\n" && cat "$TMPCONF" 1>&2 && echo 1>&2 "----"
return 0
}

## littering isn't nice
cleanup()
{
    ## make sure we clean up our temp file/dir if we have one
    if [ -n "$TMPCONF" ] ; then rm -f "$TMPCONF" ; fi
    if [ -n "$FIRST" ] ; then rm -f "$FIRST" ; fi
    if [ -d "$TMP/bootstrap.$$" ] ; then rmdir "$TMP/bootstrap.$$" ; fi
    return 0
}

##########
## Main ##
##########

## absurdly bloated case statement to parse command line options.
if [ $# != 0 ] ; then
    while true ; do
	case "$1" in 
	    -V|--version) 
		version
		exit 0
		;;
	    -h|--help)
		usage
		exit 0
		;;
	    --debug)
		DEBUG=1
		shift
		;;
	    -v|--verbose)
		VERBOSE=1
		shift
		;;
	    -f|--force)
		FORCE=yes
		shift
		;;
	    -b|--boot)
		if [ -n "$2" ] ; then
		    boot="$2"
		    ARGBT=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    -o|--ofboot)
		if [ -n "$2" ] ; then
		    ofboot="$2"
		    ARGOB=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    -i|--install)
		if [ -n "$2" ] ; then
		    install="$2"
		    ARGBF=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    -c|--conffile)
		if [ -n "$2" ] ; then
		    bootconf="$2"
		    ARGBC=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    -C|--config)
		if [ -n "$2" ] ; then
		    CONF="$2"
		    bootconf="$2"
		    ERR=" Error in $CONF:"
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    -m|--magicboot)
		if [ -n "$2" ] ; then
		    magicboot="$2"
		    ARGWP=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --filesystem)
		if [ -n "$2" ] ; then
		    fstype="$2"
		    ARGFS=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --type)
		if [ -n "$2" ] ; then
		    hfstype="$2"
		    ARGTP=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --creator)
		if [ -n "$2" ] ; then
		    hfscreator="$2"
		    ARGCT=1
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --nobless)
		bless=no
		ARGBS=1
		shift
		;;
	    -M|--mount)
		usemount=yes
		ARGMT=1
		shift
		;;
	    --protect)
		protect=yes
		ARGPT=1
		shift
		;;
	    --hide)
		hide=yes
		ARGHD=1
		shift
		;;
	    --nonvram)
		nonvram=1
		ARGNV=1
		shift
		;;
	    --device)
		if [ -n "$2" ] ; then
		    device="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --timeout)
		if [ -n "$2" ] ; then
		    timeout="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --image)
		if [ -n "$2" ] ; then
		    image="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --label)
		if [ -n "$2" ] ; then
		    label="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --partition)
		if [ -n "$2" ] ; then
		    partition="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    --root)
		if [ -n "$2" ] ; then
		    root="$2"
		    bootconf=auto
		    shift 2
		else
		    echo 1>&2 "$PRG: option requires an argument $1"
		    echo 1>&2 "Try \`$PRG --help' for more information."
		    exit 1
		fi
		;;
	    "")
		break
		;;
	    *)
		echo 1>&2 "$PRG: unrecognized option \`$1'"
		echo 1>&2 "Try \`$PRG --help' for more information."
		exit 1
		;;
	esac
    done
fi

## check that specified config file exists, unless its /dev/null in
## which case we assume all options are done on the command line.
if [ "$CONF" = /dev/null ] ; then 
    true
else
    confexist || exit 1
fi

## Checks if each option was defined on the command line, and if so
## don't read it from the configuration file. this avoids
## configuration options from being set null, as well as command line
## options from being clobbered.

[ "$ARGBT" != 1 -a $(parseconf ck boot) = 0 ] && boot=`parseconf str boot`
[ "$ARGOB" != 1 -a $(parseconf ck ofboot) = 0 ] && ofboot=`parseconf str ofboot`
[ "$ARGBF" != 1 -a $(parseconf ck install) = 0 ] && install=`parseconf str install`
[ "$ARGBC" != 1 -a $(parseconf ck bootconf) = 0 ] && bootconf=`parseconf str bootconf`
[ "$ARGWP" != 1 -a $(parseconf ck magicboot) = 0 ] && magicboot=`parseconf str magicboot`
[ "$ARGMT" != 1 -a $(parseconf flag usemount) = 0 ] && usemount=yes
[ "$ARGFS" != 1 -a $(parseconf ck fstype) = 0 ] && fstype=`parseconf str fstype`
[ "$ARGTP" != 1 -a $(parseconf ck hfstype) = 0 ] && hfstype=`parseconf str hfstype`
[ "$ARGCT" != 1 -a $(parseconf ck hfscreator) = 0 ] && hfscreator=`parseconf str hfscreator`
[ "$ARGBS" != 1 -a $(parseconf flag nobless) = 0 ] && bless=no
[ "$ARGPT" != 1 -a $(parseconf flag protect) = 0 ] && protect=yes
[ "$ARGHD" != 1 -a $(parseconf flag hide) = 0 ] && hide=yes
[ "$ARGNV" != 1 -a $(parseconf flag nonvram) = 0 ] && nonvram=1
[ $(parseconf ck mntpoint) = 0 ] && mntpoint=`parseconf str mntpoint`
[ $(parseconf ck delay) = 0 ] && delay=`parseconf str delay`
[ $(parseconf ck macos) = 0 ] && macos=`parseconf str macos`
[ $(parseconf ck macosx) = 0 ] && macosx=`parseconf str macosx`
[ $(parseconf flag brokenosx) = 0 ] && brokenosx=yes
[ $(parseconf ck darwin) = 0 ] && darwin=`parseconf str darwin`
[ $(parseconf ck defaultos) = 0 ] && defaultos=`parseconf str defaultos`
[ $(parseconf flag enablecdboot) = 0 ] && cdrom=yes
[ $(parseconf flag enablenetboot) = 0 ] && network=yes
[ $(parseconf flag enableofboot) = 0 ] && of=yes

## debugging output for config parsing.
if [ $DEBUG = 1 ] ; then
    echo 1>&2 "DEBUG:"
    echo 1>&2 "----configuration----"
    echo 1>&2 "CONF=$CONF"
    echo 1>&2 "boot=$boot"
    echo 1>&2 "ofboot=$ofboot"
    echo 1>&2 "install=$install"
    echo 1>&2 "bootconf=$bootconf"
    echo 1>&2 "magicboot=$magicboot"
    echo 1>&2 "usemount=$usemount"
    echo 1>&2 "mntpoint=$mntpoint"
    echo 1>&2 "fstype=$fstype"
    echo 1>&2 "hfstype=$hfstype"
    echo 1>&2 "hfscreator=$hfscreator"
    echo 1>&2 "bless=$bless"
    echo 1>&2 "protect=$protect"
    echo 1>&2 "hide=$hide"
    echo 1>&2 "nonvram=$nonvram"
    echo 1>&2 "macos=$macos"
    echo 1>&2 "macosx=$macosx"
    echo 1>&2 "darwin=$darwin"
    echo 1>&2 "defaultos=$defaultos"
    echo 1>&2 "enablecdboot=$cdrom"
    echo 1>&2 "enablenetboot=$network"
    echo 1>&2 "enableofboot=$of"
    echo 1>&2 "----end config----"
    echo 1>&2
fi

## force people to RTFM!!
if [ "$boot" = unconfigured ] ; then
    echo 1>&2 "$PRG: You must specify the device for the bootstrap partition."
    echo 1>&2 "$PRG: Try \`$PRG --help' for more information."
    exit 1
fi

## if there is no config file use the automatic generation to make a
## generic yaboot.conf. do this before the confcheck to avoid wierd errors.
if [ "$bootconf" = /dev/null ] ; then
    echo 1>&2 "$PRG: Warning: no yaboot.conf, using generic configuration."
    bootconf=auto
fi

## mntpoint is incompatible with mkofboot.
if [ "$PRG" = mkofboot -a -n "$mntpoint" ] ; then
    echo 1>&2 "$PRG: Cannot be used with \`mntpoint='"
    exit 1
fi

## check that we can use ofpath
if [ -z "$ofboot" -o -n "$macos" -o -n "$macosx" -o -n "$darwin" ] ; then
    if command -v ofpath > /dev/null 2>&1 ; then 
	[ -x `command -v ofpath` ]
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: ofpath could not be found, aborting."
	    exit 1
	fi
    else
	echo 1>&2 "$PRG: ofpath could not be found, aborting."
	exit 1
    fi
fi

## validate configuration for sanity.
checkconf || exit 1

## check if we are root if needed, if id is missing were probably
## running from boot floppies, and thus are root.
if [ "$usemount" = yes -a -z "$mntpoint" ] ; then
    if [ `id -u` != 0 ] ; then
	echo 1>&2 "$PRG: \`usemount' requires root privileges, go away."
	exit 1
    fi
fi

if [ "$fstype" = hfs ] ; then 
    checkhfsutils
    if [ $? != 0 ] ; then
	echo 1>&2 "$PRG: hfsutils is not installed or cannot be found"
	echo 1>&2 "$PRG: Try --mount if `uname -sr` supports HFS"
	exit 1
    fi
fi

## convert unix device nodes to OpenFirmware pathnames
convertpath || exit 1

## yaboot.conf autogeneration. MUST have secure mktemp to
## avoid race conditions. Debian's mktemp qualifies.
if [ "$bootconf" = auto ] ; then 
    TMPCONF=`mktemp -q "$TMP/$PRG.XXXXXX"`
    if [ $? != 0 ] ; then
	echo 1>&2 "$PRG: Cannot create temp file, aborting."
	exit 1
    fi

    mkconf
    if [ $? != 0 ] ; then 
	echo 1>&2 "$PRG: An error occured generating yaboot.conf, aborting."
	exit 1
    fi

    bootconf="$TMPCONF"
fi

checkfirststage || exit 1
    if [ "$FIRSTSTG" = compat ] ; then
	mkfirststage
	if [ $? != 0 ] ; then
	    echo 1>&2 "$PRG: An error occured while building first stage loader.  aborting..."
	    exit 1
	fi
    fi

case "$PRG" in 
    ybin)
	case "$usemount" in 
	    no)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: ybin, usemount no"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bootconf=$bootconf"
		util_install || exit 1
		exit 0
		;;
	    yes)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: ybin, usemount yes"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bootconf=$bootconf"
		mnt_install || exit 1
		exit 0
		;;
	esac
	;;
    mkofboot)
	case "$usemount" in 
	    no)
		## its not nice to erase the partition and then bail!
		if [ "$fstype" = msdos ] ; then 
		    echo 1>&2 "$PRG: mtools support is not implemented"
		    echo 1>&2 "$PRG: Use --mount or add \`usemount' to $CONF"
		    exit 1
		fi
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: mkofboot, usemount no"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bootconf=$bootconf"
		confirm || exit 2
		mkoffs || exit 1
		util_install || exit 1
		exit 0
		;;
	    yes)
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: mkofboot, usemount yes"
		[ "$DEBUG" = 1 ] && echo 1>&2 "$PRG: DEBUG: bootconf=$bootconf"
		confirm || exit 2
		mkoffs || exit 1
		mnt_install || exit 1
		exit 0
		;;
	esac
	;;
esac
		
exit 0
