#! /bin/bash

# Script to create an initial LILO config file.
#
# Usage:
#   mk_lilo_conf [root_dir] [ -m mbr_device ] [ -v vga_fb_mode ] [ -a partition_spec ]
#                [ -d disk_param ] [ -d ... ]
#                [ -o other_system_entry ] [ -o ... ]
#
#   root_dir: the directory the root partition is mounted to (defaults to "/")
#   mbr_device: the device that gets the MBR (if any; default: no MBR is written)
#   vga_fb_mode: frame buffer mode in hex, *without* any leading "0x"
#   partition_spec: "disk_devicepart_nr"
#     disk_device: device name (e.g. /dev/sda)
#     part_nr: partition number (1 - 4)
#   disk_param: "disk_device bios_nr"
#     disk_device: device name (e.g. /dev/sda)
#     bios_nr: bios drive number (e.g. 0x80)
#   other_system_entry: (table is optional)
#     "partition label [table]"
#
# NOTE: the *order* of options is important: root_dir first, then "-m",
# then "-v", then "-d" and finally "-o"!
#
# Example:
#
# mk_lilo_conf /blub -m /dev/hda -v 301 -a /dev/hda1 \
#              -d "/dev/sda 0x80" -d "/dev/hda 0x81" \
#              -o "/dev/hda1 dos" -o "/dev/hda2 win /dev/hda"
#
# As an alternative, specify the root & boot devices via environment
# variables. e.g.: rootdev=/dev/hda bootdev=/dev/hda1 mk_lilo_conf
#
# If no boot device could be found, the root device is taken instead.
#
# To make a bootable floppy, specify /dev/fd0 as mbr_device.
#
# If kernel & initrd exceed the 1023 cylinder limit *and* LILO is to be installed
# on a floppy, a complete boot disk is created (using syslinux).
#
# on errors:
#   exit code > 0
#
# Version 1.08
#
# Author: Steffen Winterfeldt <wfeldt@suse.de>
# (c) 1999 SuSE GmbH

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# general configurable parameters

# the kernel images to use; must be in $boot_dir
kernels="vmlinuz vmlinuz.shipped"

# LILO entry names (corresponding to $kernels)
lilolabels="linux failsafe"

# initial ram disks (corresponding to $kernels); dto. in $boot_dir
initrds="initrd initrd.shipped"

# if we need an append line (*not* for the frame buffer vga=xxxx argument)
#append=

# for frame buffers; the number *must* be in hex, without any leading 0x
# e.g. vga=0301
# vga=

# show boot prompt and wait for $prompt/10 seconds (empty -> no prompt)
prompt=80

# lilo config (may be empty -> no lilo configured)
lilo=/etc/lilo.conf

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# adapt these only if needed

# *full* paths
boot_dir=/boot

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
# should be nothing to change below...

tmp_msg=/tmp/msg$$

clean_up () {
  rm -f $tmp_msg
}

error () {
  echo "$2"
  clean_up
  exit $1
}

get_device () {
  x1=`mount 2>/dev/null | grep "on $1 " | | egrep -v "^rootfs|^/dev/root"`
  x2=`echo \`echo "$x1" | wc -l\``
  x3=`echo "$x1" | cut -f 1 -d " "`

  if [ "$x2" = 1 -a -b "$x3" ] ; then
    echo "$x3"
  fi
}

write_lilo_conf_global () {
  xx1=
  [ "$bootdev" ] && xx1=$bootdev
  [ "$mbr" -a "$mbr" != "$floppy" ] && xx1=$mbr
  cat <<-blubber >>$tmp_msg
	boot	= $xx1
	change-rules
	reset
	read-only
	menu-scheme = Wb:kw:Wb:Wb
	blubber
  [ "$linear" ] && echo "linear" >>$tmp_msg
  [ "$lba32" ] && echo "lba32" >>$tmp_msg
  if [ "$1" ] ; then
    echo "prompt" >>$tmp_msg
    echo "timeout	= $1" >>$tmp_msg
  fi
  if [ "$message" ] ; then
    echo "message	= $message" >>$tmp_msg
  fi
  echo >>$tmp_msg
}

write_lilo_conf_linux () {
  xx3=
  [ "$initrd" ] && xx3="  initrd = $initrd"
  if [ "$lilolabel" = failsafe ] ; then
    xx4="$append"
    [ "$xx4" ] && xx4=" $xx4"
    append="ide=nodma apm=off acpi=off vga=normal nosmp maxcpus=0 disableapic 3$xx4";
  fi
  xx4=
  [ "$append" ] && xx4="  append = \"$append\""
  xx5=
  [ "$vga" ] && xx5=$(($vga))
  cat <<-blubber >>$tmp_msg
	  image  = $kernel
	  label  = $lilolabel
	  root   = $rootdev
	blubber
  [ "$xx5" ] && echo "  vga    = $xx5" >>$tmp_msg
  [ "$xx3" ] && echo "$xx3" >>$tmp_msg
  [ "$xx4" ] && echo "$xx4" >>$tmp_msg
  [ "$kernel" != /boot/vmlinuz ] && echo "  optional" >>$tmp_msg
  echo >>$tmp_msg
}

write_lilo_conf_other () {
  other=$1;
  shift
  label=$@
  cat <<-blubber >>$tmp_msg
	  other  = $other
	  label  = $label
	blubber
  echo >>$tmp_msg
}

write_lilo_conf_memtest () {
  [ -f "$root_dir$boot_dir/memtest.bin" ] || return
  echo "  image  = $boot_dir/memtest.bin" >>$tmp_msg
  echo "  label  = memtest86" >>$tmp_msg
  echo >>$tmp_msg
}

write_lilo_conf_disk () {
  cat <<-blubber >>$tmp_msg
	disk	= $1
	  bios	= $2
	blubber
}

if [ "${1:0:1}" != "-" ] ; then
  root_dir="$1"
  shift
else
  root_dir=
fi

[ "$floppy" ] || floppy=/dev/fd0
[ "$root_dir" ] || root_dir=/
if [ -z "$rootdev" ] ; then
    rootdev=`get_device "$root_dir"`
    [ "$rootdev" ] || error 11 "usage: mk_lilo_conf [root_dir]"
fi
echo "using \"$rootdev\" as root device (mounted on \"$root_dir\")"

root_dirx="$root_dir"
[ "$root_dirx" = / ] && root_dirx=
if [ -z "$bootdev" ] ; then
    bootdev=`get_device "$root_dirx$boot_dir"`
    [ "$bootdev" ] || bootdev="$rootdev"
fi
echo "using \"$bootdev\" as boot partition (mounted on \"$root_dirx$boot_dir\")"

initrd_a=($initrds)
lilolabels_a=($lilolabels)

message="$boot_dir/message"
[ -f "$message" ] || message=

llog="$root_dir$boot_dir/lilo.log"
echo -n >$llog

mbr=
if [ "$1" = "-m" -a "$2" ] ; then
  mbr="$2"
  shift 2
fi

vga=
if [ "$1" = "-v" -a "$2" ] ; then
  vga="$2"
  shift 2
fi

if [ "$1" = "-a" -a "$2" ] ; then
  shopt -s extglob
  a1=${2%%+([0-9])}        
  a2=${2:${#a1}}
  a3=${2%/*}
  [ "$a3" = /dev/rd -o "$a3" = /dev/ida -o "$a3" = /dev/cciss ] && a1=${a1%%p}
  shopt -u extglob
  echo "activate $a1 $a2" >>$llog
  activate $a1 $a2 >>$llog 2>&1
  shift 2
fi

rm -f "$tmp_msg"

while [ "$1" = "-d" -a "$2" ] ; do
  write_lilo_conf_disk $2
  shift 2
done

write_lilo_conf_global $prompt

kernel_idx=0
for k in $kernels ; do

  kernel="$boot_dir/$k"
  [ -f "$root_dirx/$kernel" ] || {
    echo "no such kernel image: \"$root_dirx/$kernel\""
    kernel_idx=$((kernel_idx+1))
    continue
  }

  initrd="$boot_dir/${initrd_a[$kernel_idx]}"

  lilolabel="${lilolabels_a[$kernel_idx]}"

  echo -n "creating lilo entry for kernel \"$kernel\" (as \"$lilolabel\"), "

  if [ -f "$root_dirx$initrd" ] ; then
    echo "initrd \"$root_dirx$initrd\""
  else
    echo "no initrd"
    initrd=
  fi

  write_lilo_conf_linux

  kernel_idx=$((kernel_idx+1))

done

while [ "$1" = "-o" -a "$2" ] ; do
  write_lilo_conf_other $2
  shift 2
done

write_lilo_conf_memtest

cp $tmp_msg $root_dir$lilo || error 13 "failed to install lilo config file"

rm -f $root_dir$boot_dir/floppy

if [ "$mbr" ] ; then
  b="$bootdev"
  [ "$mbr" = "$floppy" ] && b="$floppy"
  case "$b" in
    /dev/md?)
      # do not try to install lilo into a raid partition
    ;;
    *)
      lilo -v -v -v -r $root_dir -b $b -m $boot_dir/map2 >>$llog 2>&1 || {
        if [ "$mbr" = "$floppy" ] ; then
          if grep -s -q 'Cylinder number is too big' $llog ; then
            export rootdev
            mk_boot_floppy || error 21 "mk_boot_floppy failed"
            dd if=$root_dir$boot_dir/floppy of=$floppy bs=36b 2>/dev/null || error 14 "floppy write failed"
            exit 0
          else
            error 15 "lilo failed"
          fi
        else
          error 16 "lilo failed"
        fi
      }
      echo "===========================" >>$llog
    ;;
  esac
fi
lilo -v -v -v -r $root_dir >>$llog 2>&1 || error 17 "lilo failed"

clean_up

