#!/bin/sh
<<@

LILO QUICK INSTALLATION	                      Version 22.5 of 15-Dec-2003
-----------------------                       ---------------------------

This installation script installs LILO and generates the configuration file
/etc/lilo.conf. It uses safe defaults for most configuration options.
Please read the documentation (preferably the more complete LaTeX version,
doc.tex) before making changes to the configuration generated by QuickInst.

To run QuickInst, simply type

./QuickInst

If the normally used root partition is mounted below root (e.g. during
system installation), set the environment variable ROOT to the name of the
directory on which the root partition is mounted and run QuickInst, e.g.

ROOT=/root ./QuickInst

A subshell can be spawned at each prompt. Type  !  to get an interactive
shell that has to be left with  exit . Type  !command args ...  to execute
a command and immediately return to QuickInst.

QuickInst can only be used to install LILO on IDE (AT-BUS) or SCSI hard
disks. The LILO version must be 22 or later, the kernel should be 2.0.4
or later. Owners of some disk adapters may have to create a DISK section
(see section "Disk geometry" in the accompanying documentation) to describe
the disk geometry.

WARNING: QuickInst may get confused if you're running it in a directory
	 that contains a mixture of old and new LILO distributions. To be
	 safe, always extract new LILO distributions in their own, new
	 directory.

------------- End of description. What follows is program code. -------------
@

CFG_SUFFIX=/etc
CFG_DIR=$ROOT$CFG_SUFFIX
CFG_FILE=$CFG_DIR/lilo.conf
BOOT_SUFFIX=/boot
BOOT_DIR=$ROOT$BOOT_SUFFIX
SBIN_DIR=$ROOT/sbin

locate()
{
    var=$1
    while shift && [ ! -z "$1" ]; do
	for p in `echo $PATH | sed 's/:/ /g'`; do
	    if [ -x $p/$1 ]; then
		eval $var=$p/$1
		return 0
	    fi
	done
    done
    return 1
}

probe()
{
    [ ! -z "`dd if=$1 bs=1 count=1 2>/dev/null | tr '\0' x`" ]
    return
}

bootflag()
{
    [ "XY" = "`(dd of=/dev/null bs=510 count=1; dd bs=2 count=1 |
      tr -c '\125\252' . | tr '\125\252' XY) <$1 2>/dev/null`" ]
    return
}

krnltype()
{
    if [ "YX" = "`(dd bs=2 count=1 | tr -c '\001\013' . | tr '\001\013' XY) \
      <$1 2>/dev/null`" ]; then
	echo compound
    else
	echo image
    fi
}

get()
{
    while true; do
	echo -n "$1 "
	if [ -z "$3" ]; then
	    echo -n "(no default) "
	else
	    echo -n "[$3] "
	fi
	read line
	line="`echo "$line" | sed 's/^ *\([^ ]\(\|.*[^ ]\)\) *$/\1/'`"
	if [ -z "$line" ]; then
	    if [ -z "$3" ]; then
		echo "No default, please specify a value."
		continue
	    fi
	    line=$3
	fi
	if [ "x$line" = "x!" ]; then
	    cat <<EOF

Starting a sub-shell. Type  exit  to return.

EOF
	    ${SHELL:-sh}
	    echo
	    continue
	fi
	if echo "$line" | grep '^!' >/dev/null; then
	    sh -c "`echo \"$line\" | sed 's/^!//'`"
	else
	    eval $2="$line"
	    break
	fi
    done
}

yesno()
{
    while true; do
	get "$1" line $2
	if echo "$line" | egrep -i '^y(|e(|s))$' >/dev/null; then
	    return 0
	fi
	if echo "$line" | egrep -i '^no?$' >/dev/null; then
	    return 1
	fi
	echo "YES or NO, please."
    done
}


askinitrd()
{
    idef=""
    for nn in /initrd /boot/initrd $ROOT/initrd $ROOT/boot/initrd; do
	if [ -f $ROOT/$nn ]; then
	    idef=$nn
	    break
	fi
    done

    if yesno "Does this kernel need an inital ramdisk?" no; then
	    get "Initial ramdisk" initrd "$idef"
	    if [ -f $initrd ]; then
		echo "  initrd = $initrd" >>$CFG_FILE.tmp
		return 0
	    else
		echo "$initrd  does not exist."
		echo "You must specify an absolute path"
		echo "#  initrd = $initrd    # file not found" >>$CFG_FILE.tmp
		return 1
	    fi
    fi
}



#####################################################
# start of the actual script
#####################################################

echo
if [ $ROOT/etc/lilo = `pwd` ]; then
    cat <<EOF
You can't run QuickInst in /etc/lilo ! Please cd to the directory that
contains your LILO source files and try again.

EOF
    exit 1
fi

if id | grep 'uid=0(' >/dev/null; then : ; else
    echo "You probably have to be root to install LILO."
    echo
    if yesno "Try to install LILO anyway ?" no; then : ; else
	echo
	exit 1
    fi
    echo
fi

badlib=""
if [ "`echo 'X(Y)' | sed 's/\(X\)(Y)/\1/'`" != "X" ]; then
    echo "Your sed doesn't behave like sed."
    badlib=y
fi
if [ "`echo 'X(Y)' | grep '^X(Y)'`" != "X(Y)" ]; then
    echo "Your grep doesn't behave like grep."
    badlib=y
fi
if [ "`echo 'X(Y)' | egrep '^(X)\(Y\)'`" != "X(Y)" ]; then
    echo "Your egrep doesn't behave like egrep."
    badlib=y
fi
if [ ! -z "$badlib" ]; then
    echo "Your libraries might be broken."
    echo
    exit 1
fi

cat <<EOF
QuickInst configures LILO and installs it on your hard disk. It should only be
used for first-time installations, _not_ to update or modify an existing
installation of LILO. It will _not_ generate a valid installation with versions
of LILO below 22.

The installation procedure can be interrupted by pressing ^C at any time. When
at a prompt, a sub-shell can be invoked with the exclamation mark.

EOF
if yesno "Continue ?" yes; then : ; else
    echo
    exit 0
fi
echo

replace=""
if [ -d $BOOT_DIR -a \( -f boot.b -o -f first.S \) ]; then
    cat <<EOF
A directory $BOOT_SUFFIX already exists. If you're installing a new version of
LILO now, QuickInst has to replace the old files with the new ones.

EOF
    if yesno "Replace old files ?" yes; then
	replace=y
    fi
    echo
fi

if [ -f $ROOT/etc/lilo/install -a ! -L $ROOT/etc/lilo/install -a \
  "$replace" != "y" ]; then
    cat <<EOF
/etc/lilo/install is a regular file and not a symbolic link. It should be
a symbolic link to /sbin/lilo (see INCOMPAT for details).

EOF
    if yesno "Replace install by a link ?" yes; then
	ln -sf $SBIN_DIR/lilo $ROOT/etc/lilo/install
    fi
    echo
fi

noinst=""
if [ -f $CFG_DIR/disktab ]; then
    if [ "#|" = "`sed 1q <$CFG_DIR/disktab`" ]; then
	cat <<EOF
$CFG_DIR/disktab is a Shoelace-style parameter table. It is
incompatible with LILO and most likely obsolete.

EOF
	if yesno "Remove $CFG_DIR/disktab ?" yes; then
	    rm -f $CFG_DIR/disktab
	else
	    if yesno "Proceed anyway ?" no; then
		cat <<EOF

Okay, but QuickInst won't automatically invoke LILO at the end of the
configuration session, because you have to get rid of disktab first.
EOF
		noinst=y
	    else
		echo Terminating
		exit 1
	    fi
	fi
	echo
    fi
fi

echo
if [ ! -f $BOOT_DIR/boot.b -o ! -z "$replace" ]; then
    if [ ! -f boot.b ]; then
	if [ ! -f first.S ]; then
	    cat <<EOF
LILO is not installed and I don't know how to make it. Please cd to the
directory where your LILO source lives and try again.

EOF
	    exit 1
	fi
	if [ ! -f /usr/include/linux/config.h ]; then
	    cat <<EOF
The kernel header files appear to be missing. Please install them, then try
QuickInst again.

EOF
	    exit 1
	fi
	if [ ! -f /usr/include/linux/autoconf.h ]; then
	    cat <<EOF
(Creating dummy /usr/include/linux/autoconf.h)

EOF
	    touch /usr/include/linux/autoconf.h
	fi
	cat <<EOF
Making LILO ...

EOF
	if make; then : ; else exit; fi
	echo
    fi
    cat <<EOF
Installing LILO ...

EOF
    if make install; then : ; else exit; fi
    echo
fi

if [ ! -x $SBIN_DIR/lilo ]; then
    cat <<EOF
$SBIN_DIR/lilo is missing. Don't know how to proceed ...

EOF
    exit 1
fi

version="`$SBIN_DIR/lilo -V 2>/dev/null | sed 's/LILO version \(0\.\)\?//' | sed 's/\..*//'`"
# echo LILO version $version is installed
if [ -z "$version" ]; then
    cat <<EOF
Incompatible version of LILO. Expecting 22 (or later), found 10 or older.

EOF
    exit 1
fi
if [ "$version" -lt 22 ]; then
    cat <<EOF
Incompatible version of LILO. Expecting 22 (or later), found $version

EOF
    exit 1
fi

#if [ ! -x ./activate ]; then
#    cat <<EOF
#activate  is not in the current directory. Please cd to your LILO source
#directory and run QuickInst again.
#EOF
#fi

if [ -d $ROOT/etc/lilo -a ! -x $ROOT/etc/lilo/install ]; then
    ln -s $SBIN_DIR/lilo $ROOT/etc/lilo/install
fi


if [ -f $CFG_FILE ]; then
    cat <<EOF

There is an existing configuration file:  "$CFG_FILE"

EOF
    if yesno "Do you wish to generate a new \"$CFG_FILE\"" no ; then :
    else
	echo
	echo "Running $SBIN_DIR/lilo" ...
	echo
	if $SBIN_DIR/lilo ; then
		echo 
	else
	    cat <<EOF

Errors were noted in the running of the newly installed LILO with the
old configuration file.  You will have to edit the file and re-run
$SBIN_DIR/lilo to install the new boot loader.

Exiting ...
EOF
	fi
	exit
    fi
fi

dev="`find /dev -maxdepth 1 -type b -name '[hs]da' | sed 's,/[hs]da$,,;1q'`"
if [ -z "$dev" ]; then
    cat <<EOF
(Can't locate hda or sda device in /dev or in a subdirectory or it.
 Assuming disk devices live in /dev)
EOF
    dev="/dev"
else
    echo "(Disk devices live in $dev)"
fi
echo

echo "Gathering configuration data ..."

second=/dev/sdb

if [ -L $dev/hda ]; then
    cat <<EOF

$dev/hda is a symbolic link. Assuming your first disk is $dev/sda

EOF
    first=$dev/sda
    if probe $dev/sdb; then
	second=$dev/sdb
    fi
else
    if probe $dev/hda; then
	first=$dev/hda
	if probe $dev/hdb; then
	    second=$dev/hdb
	else
	    if probe $dev/sda; then
		second=$dev/sda
	    fi
	fi
    else
	if probe $dev/sda; then
	    first=$dev/sda
	    if probe $dev/sdb; then
		second=$dev/sdb
	    fi
	else
	    cat <<EOF

Unable to determine what your first disk is. (Tried $dev/hda
and $dev/sda, but none of them appears to exist.)
Sorry, this is a fatal error.

EOF
	    exit 1
	fi
    fi
fi
root=""
if locate path rootdev rdev setroot; then
    root=`$path | awk '{ print $1 }'`
    echo
    echo "(/ is mounted on $root)"
fi
boot=""
if echo $root | grep "^${first}[1-4]*\$" >/dev/null; then
    boot=$root
fi

cat <<EOF

Please specify the name of the device where the LILO boot sector should be
stored. (Suggested locations are the Linux root partition or the MBR of your
first drive).

EOF
while true; do
    get "Device name" inp $boot
    if echo "$inp" | grep / >/dev/null; then : ; else
	inp="/dev/$inp"
    fi
    if echo "$inp" | egrep \
      "^${first}\$|^${first}[1-4]\$|^${second}\$|^${second}[1-4]\$" \
      >/dev/null; then
	if true -o probe "$inp"; then
	    boot=$inp
	    break
	else
	    cat <<EOF
No such device exists. Type  !ls {$first,$second}[1-4]  for a list
of possible names.
EOF
	fi
    else
	cat <<EOF
This is not a valid device name. Try names like $first or
${first}1
EOF
    fi
done

on_second=
curr_first=$first
curr_second=$second

if echo "$boot" | grep "$second" >/dev/null; then
    cat <<EOF

You have decided to put the LILO boot sector on your SECOND disk ($second).

This may indicate an unusual configuration. Please indicate your future
plans by selecting one of the following choices:

  keep    if you do not intend to change the disk configuration, i.e.
          your current first disk stays first and your current second
          disk stays second.

  swap    if you intend to swap $first and $second after
          installing LILO, either by physically swapping the two
	  disks, or by configuring your BIOS to make them appear
	  as if they had changed places. (The latter choice needs
          BIOS support.)

  remove  if you intend to remove your current first disk ($first)
          after installing LILO and to use your current second disk
          as the first disk.

EOF
    while true; do
	get "Your choice" line keep
	if echo "$line" | egrep -i '^k(|e(|ep?))$' >/dev/null; then
	    break
        fi
        if echo "$line" | egrep -i '^r(|e(|m(|o(|ve?))))$' >/dev/null; then
            on_second=remove
	    first=$second
	    second=
	    break
        fi
	if echo "$line" | egrep -i '^s(|w(|ap?))$' >/dev/null; then
            on_second=swap
	    tmp=$first
	    first=$second
	    second=$tmp
	    break
        fi
        echo "KEEP, REMOVE, or SWAP, please."
    done
fi

if [ ! -z "$on_second" ]; then
    cat <<EOF

Please note that the configuration generated in this session is only
valid for the current hardware configuration. If you are removing or
(physically) swapping disks, you will have to update the configuration
in order to reflect the changed system configuration.

You can do this either by running QuickInst again or directly by
editing the configuration file $CFG_FILE
EOF
fi

if [ "$boot" = "$first" ]; then
    cat <<EOF

You are about to install LILO on your MBR. If there are other operating
systems on your hard disk, LILO will act as a boot manager for them. You
have to specify each operating system in your LILO configuration. (More
about this later.)
EOF
fi

if echo "$boot" | grep '^$first[1-4]$' >/dev/null; then
    if [ "`dd if=$first bs=1 count=4 skip=2 2>/dev/null | \
      tr -c 'LIO' '?'`" = "LILO" -o \
      "`dd if=$first bs=1 count=4 skip=6 2>/dev/null | \
      tr -c 'LIO' '?'`" = "LILO" ]; then

	cat <<EOF

There appears to be a LILO boot sector on $first. Because you're
installing LILO's boot sector on a regular partition now, it is very
likely that the old boot sector will no longer start correctly. Unless
you're very sure of what you're doing, you should therefore replace it by
a "standard" MBR before attempting to boot from the hard disk. (E.g. use
MS-DOS 5.0's FDISK /MBR  or, better,  $SBIN_DIR/lilo -M $first  )
EOF
    fi
fi

disk=`echo $boot | sed 's/[1-4]$//'`
oldboot=`$SBIN_DIR/lilo -A $disk 2>/dev/null`
newboot=""
if [ $boot != "$oldboot" -a ! -z "`echo "$boot" | sed 's|'$dev'/[sh]d.||'`" ];
  then
    echo
    if [ -z "$oldboot" ]; then
	echo "There's no active partition on $disk"
	msg="Activate $boot ?"
    else
	echo "Currently active partition of $disk is $oldboot"
	msg="Change it to $boot ?"
    fi
    if yesno "$msg"; then
	newboot=`echo $boot | sed 's,'$dev'/[sh]da,,'`
	cat <<EOF

Partition $newboot of $disk will be made active as soon as the LILO
installation is complete.
EOF
    else
	cat <<EOF

Please don't forget to configure the boot manager you are using to boot LILO
from $boot.
EOF
    fi
fi

kernel=""
for n in /vmlinuz /boot/vmlinuz /linux /boot/linux /zImage /boot/zImage; do
    if [ -f $ROOT/$n ]; then
	kernel=$n
	break
    fi
done

cat <<EOF

Please specify the name of the kernel image file you want to boot by default.
You may list the $ROOT/boot directory with:  !ls $ROOT/boot/vm*

EOF
while true; do
    get "Default kernel" inp $kernel
    if [ -f "$ROOT$inp" ]; then
	if echo "$inp" | grep '^/' >/dev/null; then
	    kernel=$inp
	    break
	else
	    echo "Use only absolute path names, e.g. /linux"
	fi
    else
	echo "No such file."
    fi
done

cat <<EOF >$CFG_FILE.tmp
# LILO configuration created by QuickInst 22.5  `date | tr -s x ' '`

boot = $boot
prompt		# always expect prompt
timeout = 150	# wait 15 seconds
vga = normal	# force sane state
lba32		# 'linear' is deprecated
delay = 30	# delay 3 seconds if there is a stored command line
#serial = 0,1200n8	# uncomment to use COM1 too
read-only	# initailly mount roots r/o
EOF
if [ "$on_second" = swap ]; then
cat <<EOF >>$CFG_FILE.tmp
disk = $curr_first	# disks will be swapped
  bios = 0x81
disk = $curr_second
  bios = 0x80
EOF
fi
if [ "$on_second" = remove ]; then
cat <<EOF >>$CFG_FILE.tmp
disk = $curr_first	# disk will be removed
  inaccessible
disk = $curr_second
  bios = 0x80
EOF
fi
cat <<EOF >>$CFG_FILE.tmp
root = current	# use "current" root
`krnltype $kernel` = $kernel
EOF
if [ "`echo $kernel | sed 's,/\([^/]*\)$,\1,'`" != "linux" ]; then
    echo "  label = linux" >>$CFG_FILE.tmp
fi

# add any initrd, if needed
askinitrd

echo
if yesno "Define additional kernels ?" no; then
    default=""
    for n in $kernel.old /vmlinux.old /boot/vmlinuz.old /linux.old \
      /boot/linux.old /zImage.old /boot/zImage.old; do
	if [ -f $ROOT/$n ]; then
	    default=$n
	    break
	fi
    done
    cat <<EOF

Specify the names of additional kernels now. Use "done" (without the quotes)
to stop adding kernels.

EOF
    while true; do
	get "Kernel" inp $default
	if [ done = "$inp" ]; then
	    break
	fi
	if echo "$inp" | grep '^/' >/dev/null; then
	    echo "`krnltype $inp` = $inp" >>$CFG_FILE.tmp
	    if [ ! -f $ROOT$inp ]; then
		echo "File doesn't exist now. - Making entry optional."
		echo "  optional" >>$CFG_FILE.tmp
	    fi
	    askinitrd
	else
	    echo "Use only absolute path names, e.g. /linux"
	fi
	default="done"
    done
fi

if [ "$boot" = "$first" ]; then
    cat <<EOF

If you want to boot other operating systems than Linux from your hard disk,
you should configure them now. LILO will take over the entire boot process,
so any currently installed partition switchers or boot managers will stop
to work. (If this scares you, just hit ^C and read the manual.)
EOF
fi

echo
if yesno "Define additional operating systems (e.g. MS-DOS) ?" no; then
    cat <<EOF

Specify the names of devices that contain boot sectors of additional operating
systems now. You might want to run  fdisk  or  efdisk  to list the partition
table(s) of your hard disk(s) in order to obtain the device names. Use "done"
(without the quotes) to stop adding operating systems.

EOF
    default=""
    default_lbl=dos
    while true; do
	get "Device name" inp $default
	if [ done = "$inp" ]; then
	    break
	fi
	if echo "$inp" | grep '^'$dev'/[hs]d[ab][1-4]$' >/dev/null; then
	    if probe "$inp"; then
		if bootflag $inp; then
		    loader=""
		    if echo "$inp" | egrep "^${second}[1-4]\$" >/dev/null; then
			echo "It's on your second disk. Is this ..."
			if yesno "... OS/2 ?"; then
			    loader="os2_d.b"
			else
			    if yesno "... OS using the BIOS (e.g. DOS) ?"; then
				loader="chain.b"
			    fi
			fi
		    fi
		    (
			echo "other = $inp"
			echo -n "  table = "
			echo $inp | sed 's/[1-4]$//'
			if [ ! -z "$loader" ]; then
			    echo "  loader = $BOOT_DIR/$loader"
			fi
		    ) >>$CFG_FILE.tmp
		    get "Label" inp $default_lbl
		    default_lbl=""
		    default="done"
		    echo "  label = $inp" >>$CFG_FILE.tmp
		else
		    echo "$inp does not have a valid boot signature."
		fi
	    else
		cat <<EOF
No such device exists. Type  !ls $dev/[hs]d[ab][1-4]  for a list of
possible names.
EOF
	    fi
	else
	    echo "Expecting names like $dev/hda1, $dev/sda3, etc."
	fi
    done
    if [ -z "$default_lbl" ]; then
	cat <<EOF

In order to choose the desired kernel or operating system, hold down a shift
key at boot time, when LILO displays "LILO", until the prompt "boot:" appears.
Then enter the label name. You can get a list of available names by pressing
[Tab] (at the boot prompt).
EOF
    fi
fi

if [ -f $CFG_FILE ]; then
    cat <<EOF

An old version of the configuration file $CFG_FILE already exists.

QuickInst will proceed as follows:
 - rename $CFG_FILE to $CFG_FILE.old
 - copy the new configuration file to $CFG_FILE

Type  !cat $CFG_FILE.tmp  if you want to check the new configuration file.

EOF
    if yesno "Proceed ?" yes; then
	mv $CFG_FILE $CFG_FILE.old
    else
	cat <<EOF

Leaving the new configuration file in $CFG_FILE.tmp

EOF
	exit
    fi
fi
mv $CFG_FILE.tmp $CFG_FILE

if [ ! -z "$noinst" ]; then
    cat <<EOF

LILO is now configured. However, automated installation is not possible now,
because you still have an incompatible $CFG_DIR/disktab file. Please
remove that file or specify an alternate name for the disk parameter table
in $CFG_DIR/lilo.conf before trying to run $SBIN_DIR/lilo

EOF
    exit
fi

cat <<EOF

Ready to install LILO's boot sector on your hard disk.
Type  !cat $CFG_FILE  if you want to check the configuration file.

EOF
if yesno "Test LILO installation now ?" yes; then
    echo
    tmpbase=${TMPDIR:-/tmp}/lilo_quickinstall
    rm -rf $tmpbase
    mkdir $tmpbase || {
	echo "Could not create temporary directory."
	exit 1
    }

    outfile=$tmpbase/out$$
    errflag=$tmpbase/err$$
    (
	if
	    $SBIN_DIR/lilo -t 2>&1
	then : ; else
	    touch $errflag
	fi
    ) | tee $outfile
    if [ -f $errflag ]; then
	rm $errflag
	if egrep 'geo_query_dev HDIO_|: Got bad geometry' <$outfile >/dev/null
	  then
	    cat <<EOF

LILO is unable to obtain geometry information for your SCSI disk. Please
create a DISK section in the configuration file in which the necessary
parameters are described. See also section "Disk geometry" in the
accompanying documentation.

EOF
	    exit
	fi
	cat <<EOF

Something went wrong. Verify your input and try to minimize the complexity of
the settings, e.g. by omitting additional kernels and operating systems.

EOF
	exit
    fi
    if grep '^Warning: ' <$outfile >/dev/null; then
	cat <<EOF
The following warning messages may indicate some potential problems with your
configuration. The boot sector has not been changed yet.

EOF
	grep '^Warning: ' <$outfile
	echo
    fi
    rm -rf $tmpbase
    echo
    if yesno "Install LILO now ?" yes; then
	cat <<EOF

You see now the output of the map installer with verbose progress reporting
enabled. It will list all items that are installed for booting. Additionally,
if there are have been warnings, they will be repeated again.

EOF
        if $SBIN_DIR/lilo -v; then : ; else
	    cat <<EOF

Something went wrong, sorry. Verify your input and try to minimize the
complexity of the settings, e.g. by omitting additional kernels and operating
systems.

EOF
	    exit
	fi
    fi
    if [ ! -z "$newboot" ]; then
	$SBIN_DIR/lilo -A $disk $newboot
    fi
fi
echo
echo "Done."
echo
