#!/bin/sh

set -e

LC_ALL=C
export LC_ALL

if [ -f /etc/ltsp/ltsp-build-client.conf ]; then
  . /etc/ltsp/ltsp-build-client.conf
fi

get_help() {
cat << EOF
 --root <rootpath>  default root path
 --dist <dist>  debian distribution
 --components "<component1 component2>"  archive components
 --mirror  <mirror>  archive mirror url
 --extra-mirror "<mirror> <dist> <components>" additional mirror
 --security-mirror "<mirror> <dist> <components>" security mirror
 --exclude "package1,package2,package3"  exclude packages from base system
 --early-packages "<package1 package2>" list of initial packages to install
 --late-packages  "<package1 package2>" list of additional packages to install, after configuration tweaks (such as kernel)
 --serial-console  enable serial console
 --arch "i386|powerpc" builds an i386 chroot on amd64 or a powerpc chroot on ppc64. Errors if called on unsupported arch.
 --debconf-seeds  load debconf pre-seeding files in the chroot
 --help  display this help
 --apt-keys "<key1 key2>" keys to add to the apt keyring
EOF
}

# Create a policy-rc.d to stop maintainer scripts using invoke-rc.d from
# running init scripts during installation
make_policyrcd() {
    cat > $ROOT/usr/sbin/policy-rc.d <<EOF
#!/bin/sh
exit 101
EOF
    chmod a+rx $ROOT/usr/sbin/policy-rc.d
}
remove_policyrcd() {
    rm -f $ROOT/usr/sbin/policy-rc.d
}

# This way to make start-stop-daemon do not work on upgrades, when
# start-stop-daemon is replaced with a new version.  I tried to use
# dpkg-divert to solve this, but am not sure I got it right. [pere
# 2004-07-29]
make_dummy_start_stop_daemon() {
    cat > $ROOT/sbin/start-stop-daemon.dummy <<EOF
#!/bin/sh
echo 1>&2
echo 'Warning: Fake start-stop-daemon called, doing nothing.' 1>&2
exit 0
EOF
    chmod a+rx $ROOT/sbin/start-stop-daemon.dummy
    chroot $ROOT dpkg-divert --add --local --rename /sbin/start-stop-daemon
    ln -s start-stop-daemon.dummy $ROOT/sbin/start-stop-daemon
}
remove_dummy_start_stop_daemon() {
    rm $ROOT/sbin/start-stop-daemon
    chroot $ROOT dpkg-divert --remove --local --rename /sbin/start-stop-daemon
}
on_exit() {
    remove_dummy_start_stop_daemon
    remove_policyrcd

    # umount bind mounts
    for dir in $umounts ; do
	umount $dir
    done
}

rc_cleanup() {
    LEVEL=$1; shift

    if [ $(echo $LEVEL| grep [2-5]) ]; then
        suffix="2 3 4 5"
        echo "Cleaning up startup links in init levels: $suffix ..."
    else
        suffix=$LEVEL
        echo "Cleaning up startup links in rc$suffix.d ..."
    fi

    RC_DIR=$(ls $ROOT/etc/rc$LEVEL.d/)

    for match in $@; do
        RC_DIR=$(echo "$RC_DIR"|sed "s/S[0-9]*$match$//g")
    done

    for link in $RC_DIR; do
        if [ ! $(echo $link|grep ^K) ]; then
            name=$(echo $link|sed s/^[S,K,0-9]*//g)
            printf -v seq_number %.2s $(echo $link|sed s/[a-z,\.,S,K,-]*//g)

            if [ ! README = $name ]; then
                chroot $ROOT update-rc.d -f $name remove 2>&1 >/dev/null
                chroot $ROOT update-rc.d $name stop $seq_number $suffix . 2>&1 >/dev/null
            fi
        fi
    done
}

# process commandline arguments
while [ "$#" -gt "0" ]; do
  case $1 in
    --root) ROOT="$2"
      test "$#" -gt "0" && shift
      ;;
    --dist) DIST="$2"
      test "$#" -gt "0" && shift
      ;;
    --components) COMPONENTS="$2"
      test "$#" -gt "0" && shift
      ;;
    --mirror) MIRROR="$2"
      test "$#" -gt "0" && shift
      ;;
    --extra-mirror) EXTRA_MIRROR="$2"
      test "$#" -gt "0" && shift
      ;;
    --exclude) EXCLUDE="$2"
      test "$#" -gt "0" && shift
      ;;
    --security-mirror) SECURITY_MIRROR="$2"
      test "$#" -gt "0" && shift
      ;;
    --early-packages) EARLY_PACKAGES="$2"
      test "$#" -gt "0" && shift
      ;;
    --late-packages) LATE_PACKAGES="$2"
      test "$#" -gt "0" && shift
      ;;
    --apt-keys) APT_KEYS="$2"
      test "$#" -gt "0" && shift
      ;;
    --arch) ARCH_OPT="$2"
      test "$#" -gt "0" && shift
      case $ARCH_OPT in
        i386)
	  case $(dpkg --print-architecture) in
	    amd64|ia64|i386)
	        ARCH=i386
	        ;;
	    *)
	        echo "ERROR: --arch i386 called on unsupported arch: "$(dpkg --print-architecture)
	        exit 1
	        ;;
	  esac
	  ;;
	powerpc)
	  case $(dpkg --print-architecture) in
            ppc64|powerpc)
 	       ARCH=powerpc
 	       ;;
 	    *)
 	       echo "ERROR: --arch powerpc called on unsupported arch: "$(dpkg --print-architecture)
 	       exit 1
 	       ;;
          esac
          ;;
        *)
	  echo "ERROR: unsupported --arch argument: "$ARCH_OPT
	  exit 1
	  ;;
      esac	  
      ;;
    --help) get_help
      exit 0
      ;;
    --serial-console) use_serial_console="true"
      ;;
    --debconf-seeds) DEBCONF_SEEDS="$2"
      test "$#" -gt "0" && shift
      ;;
    *) echo "ERROR: unknown option: $1"
      get_help
      exit 1
      ;;
  esac
  test "$#" -gt "0" && shift
done

test -z "$ARCH" && ARCH=$(dpkg --print-architecture)
test -z "$ROOT" && ROOT=/opt/ltsp/$ARCH
test -z "$DIST" && DIST=dapper

case $ARCH in
	i386)
	KERNEL_ARCH=386
	;;
	amd64)
	KERNEL_ARCH=amd64-generic
	;;
	*)
	KERNEL_ARCH=$ARCH
	;;
esac

# set defaults based on dist
case $DIST in
  sarge|etch|sid) 
    test -z "$COMPONENTS" && COMPONENTS="main"
    test -z "$MIRROR" && MIRROR="http://http.us.debian.org/debian"
    test -z "$EARLY_PACKAGES" && EARLY_PACKAGES="x-window-system-core ltsp-client discover1 mdetect xresprobe udhcpc udev devfsd"
    test -z "$LATE_PACKAGES" && LATE_PACKAGES="kernel-image-netbootable"
    test -z "$EXCLUDE" && EXCLUDE="libpcap0.7,libgnutls11,liblockfile1,libpcre3,libtasn1-2,libopencdk8,liblzo1,info,manpages,man-db,libgcrypt11,libgdbm3,libgpg-error0,groff-base,at,cron,logrotate,exim4-config,exim4,exim4-base,exim4-daemon-light,ipchains,mailx,pppconfig,pppoe,pppoeconf,tasksel,base-config,apt-utils,dhcp-client,fdutils,iptables,ppp,whiptail"
    ;;
esac

# set defaults
test -z "$MIRROR" && MIRROR=http://archive.ubuntu.com/ubuntu
test -z "$COMPONENTS" && COMPONENTS="main restricted"
test -z "$EARLY_PACKAGES" && EARLY_PACKAGES="x-window-system-core ltsp-client discover1 laptop-detect xresprobe esound inputattach usplash ldm"
test -z "$LATE_PACKAGES" && LATE_PACKAGES="linux-image-$KERNEL_ARCH"
test -z "$RCS_WHITELIST" &&  RCS_WHITELIST="mountvirtfs hostname.sh keymap.sh loopback udev mountdevsubfs module-init-tools procps.sh etc-setserial ltsp-client-setup setserial console-screen.sh xorg-common"
test -z "$RC2_WHITELIST" && RC2_WHITELIST="ltsp-client nbd-client usplash rmnologin stop-bootlogd"

if [ -d $ROOT ] ; then
    echo "NOTE: Root directory $ROOT already exists.  This might lead to problems."
fi

if [ -n "$EXTRA_MIRROR" ] && [ -z "$(echo $EXTRA_MIRROR | awk '{print $2}')" ]; then
  echo "NOTE: adding default dist and components to extra mirror:"
  EXTRA_MIRROR="$EXTRA_MIRROR $DIST $COMPONENTS"
  echo "$EXTRA_MIRROR"
fi

if [ -n "$SECURITY_MIRROR" ] && [ -z "$(echo $SECURITY_MIRROR | awk '{print $2}')" ]; then
  echo "NOTE: adding default dist and components to security mirror:"
  SECURITY_MIRROR="$SECURITY_MIRROR $DIST/updates $COMPONENTS"
  echo "$SECURITY_MIRROR"
fi

if [ -n "$EXCLUDE" ] ; then
    DEBOOTSTRAPOPTS="$DEBOOTSTRAPOPTS --exclude=$EXCLUDE"
fi

# Install base packages
debootstrap $DEBOOTSTRAPOPTS --arch $ARCH $DIST $ROOT $MIRROR

# Root password is empty by default, lock it
chroot $ROOT passwd -l root

if [ -n "$DEBCONF_SEEDS" ]; then
  # load debconf preseeding files
  for seed in $DEBCONF_SEEDS; do
    cat $seed | chroot $ROOT debconf-set-selections
  done
fi

# move sources.list aside
test -f $ROOT/etc/apt/sources.list && mv -vf $ROOT/etc/apt/sources.list $ROOT/etc/apt/sources.list.old
for mirror in "$MIRROR $DIST $COMPONENTS" "$EXTRA_MIRROR" "$SECURITY_MIRROR"; do
  if [ -n "$mirror" ]; then
    echo "deb $mirror" >> $ROOT/etc/apt/sources.list
    case $mirror in
      file:///*) dir="$(echo $mirror | awk '{print $1}' | sed -e 's,^file://,,g')"      
        mkdir -p $ROOT/$dir
        mount --bind $dir $ROOT/$dir
        umounts="$umounts $ROOT/$dir"
        ;;
    esac  
  fi
done

trap on_exit EXIT
make_policyrcd
make_dummy_start_stop_daemon

# add keys to the apt keyring
for key in $APT_KEYS ; do
  cat $key | chroot $ROOT apt-key add -
done

APT_EXTRA_OPTS="-o Acquire::gpgv::Options::=--ignore-time-conflict"

chroot $ROOT apt-get $APT_EXTRA_OPTS update

DEBIAN_FRONTEND=noninteractive
export DEBIAN_FRONTEND

# some packages require proc to be mounted
chroot $ROOT mount -t proc proc /proc && umounts="$umounts $ROOT/proc"

# get package updates for base system
chroot $ROOT apt-get $APT_EXTRA_OPTS -y dist-upgrade

# Install remaining packages
chroot $ROOT apt-get $APT_EXTRA_OPTS -y install $EARLY_PACKAGES </dev/null

# Setup for kernel install
cat <<EOF > $ROOT/etc/kernel-img.conf
warn_initrd = No
do_symlinks = yes
relative_links = yes
link_in_boot = yes
do_bootloader = no
EOF

if [ -f $ROOT/etc/mkinitramfs/initramfs.conf ] && [ -d $ROOT/usr/share/doc/initramfs-tools ]; then
  # configuring for initramfs-tools
  echo "ramdisk=/usr/sbin/mkinitramfs" >> $ROOT/etc/kernel-img.conf
  sed -i -e 's/^BOOT=.*$/BOOT=nfs/' -e 's/MODULES=.*$/MODULES=netboot/' $ROOT/etc/mkinitramfs/initramfs.conf
elif [ -f $ROOT/etc/mkinitrd/mkinitrd.conf ] && [ -d $ROOT/usr/share/doc/initrd-netboot-tools ]; then
  # configuring for initrd-netboot-tools
  sed -i -e 's/^ROOT=.*$/ROOT=""/' -e 's/^MODULES=.*$/MODULES=none/' $ROOT/etc/mkinitrd/mkinitrd.conf
else
  echo "WARNING: no known network boot methods found..."
  echo "tried initramfs-tools and initrd-netboot-tools"
  echo "manual configuration may be required"
fi

# Install additional packages, such as the kernel
chroot $ROOT apt-get $APT_EXTRA_OPTS -y install $LATE_PACKAGES </dev/null

ltsp-update-kernels
ltsp-update-sshkeys

echo "ltsp" > $ROOT/etc/hostname
touch $ROOT/etc/hosts

touch $ROOT/etc/nbd-client

# Pass default X keyboard config from server to the client
debconf-get-selections | egrep 'xserver-.+/config/inputdevice/keyboard' | \
  chroot $ROOT debconf-set-selections

if [ -e /etc/console/boottime.kmap.gz ]; then
  cp /etc/console/boottime.kmap.gz $ROOT/etc/console/boottime.kmap.gz
fi

# Avoid the need to update mtab.  Save memory on ramdisk
rm $ROOT/etc/mtab
ln -s /proc/mounts $ROOT/etc/mtab

# Quiet down fsck during boot
echo "proc /proc proc defaults 0 0" > $ROOT/etc/fstab

chroot $ROOT apt-get clean

# enable serial console
if [ "true" = "$use_serial_console" ] && [ -z "$(egrep ^T0 $ROOT/etc/inittab)" ]; then
  echo "Enabling serial console..."
  echo "T0:2345:respawn:/sbin/getty -L ttyS0 38400 screen" >> "$ROOT/etc/inittab"
fi

rc_cleanup S $RCS_WHITELIST
rc_cleanup 2 $RC2_WHITELIST

# Export LTSP chroot using NFS to the LTSP client network
if ! grep -q '^/opt/ltsp' /etc/exports ; then
            cat <<EOF >> /etc/exports
# Automatically added by ltsp-server
/opt/ltsp       *(ro,no_root_squash,async)
EOF
            invoke-rc.d nfs-kernel-server reload
fi
