#!/bin/bash
# vim: set nowrap ts=8:
#
# bootstrap a box using evms and debootstrap
#
# hint:
# script -t 2>timing
# bash evms-bootstrap.sh [removeall]
#
# bugs to Jürgen E. Fischer <fischer@linux-buechse.de>
#
# Use at own risk

set -e

HOSTNAME=www

USERNAME=jef
IP_ADDRESS=88.198.11.231
IP_BROADCAST=88.198.11.255
IP_NETMASK=255.255.255.224
IP_GATEWAY=88.198.11.225

BLKDEV0=sda
BLKDEV1=sdb
#BLKDEV2=hdd
#BLKDEV2=hdc
#BLKDEV3=hdd
BLKDEVO=0	# offset for preexisting partitions (Dell/HP rescue)

apt-get install rdate debootstrap
 
ARCH=amd64

DIST=etch
VG=sys
ROOT=/target
CHUNKSIZE=256KB

NETDEV=rtl8150

if [ "$ARCH" = "i386" ]; then
	#KERNEL=2.6.16-2-k7
	KERNEL=2.6.16-2-686-smp
	GRUBDIR=/lib/grub/i386-pc
else
	KERNEL=2.6.16-2-amd64-k8-smp
	GRUBDIR=/usr/lib/grub/x86_64-pc
fi

LOCALE="de_DE ISO-8859-1, de_DE.UTF-8 UTF-8, de_DE.UTF-8@euro UTF-8, de_DE@euro ISO-8859-15"
AREA=Europe
TIMEZONE=Berlin
KEYBOARD=de-latin1-nodeadkeys

BOOTSIZE=512MB
ROOTSIZE=3GB
SWAPSIZE=2GB
TMPSIZE=1GB
VARSIZE=5GB
HOMESIZE=1GB

MIRRORMAINMETHOD="http"
MIRRORMAINHOST="ftp2.de.debian.org"
MIRRORMAINDIR="/debian/"
MIRRORSEC="http://$MIRRORMAINHOST/debian-security/"
MIRRORMAIN="$MIRRORMAINMETHOD://$MIRRORMAINHOST$MIRRORMAINDIR"

mkfs() {
	if ! [ -b /dev/evms/root ]; then
		/sbin/evms_activate

		>/tmp/create.evms

		if [ "${BLKDEVO}" == 0 ]; then
			cat <<EOF >>/tmp/create.evms
asm:DosSegMgr={}, ${BLKDEV0}:
EOF
		fi

		cat <<EOF >>/tmp/create.evms
create:segment, ${BLKDEV0}_freespace1, size=$BOOTSIZE, offset=0, primary=true, bootable=true:
create:segment, ${BLKDEV0}_freespace1, offset=0, primary=true:
EOF

		if [ -n "${BLKDEV1}" ]; then 
			if [ "${BLKDEVO}" == 0 ]; then
				cat <<EOF >>/tmp/create.evms
asm:DosSegMgr={}, ${BLKDEV1}:
EOF
			fi

			cat <<EOF >>/tmp/create.evms
create:segment, ${BLKDEV1}_freespace1, size=$BOOTSIZE, offset=0, primary=true, bootable=true:
create:segment, ${BLKDEV1}_freespace1, offset=0, primary=true:
create:region, MDRaid1RegMgr={}, ${BLKDEV0}$(( BLKDEVO+1 )), ${BLKDEV1}$(( BLKDEVO+1 )):
EOF

			if [ -n "${BLKDEV2}" ]; then
				if [ "${BLKDEVO}" == 0 ]; then
					cat <<EOF >/tmp/create.evms
asm:DosSegMgr={}, ${BLKDEV2}:
EOF
				fi

				cat <<EOF >>/tmp/create.evms
create:segment, ${BLKDEV2}_freespace1, size=$BOOTSIZE, offset=0, primary=true, bootable=true:
create:segment, ${BLKDEV2}_freespace1, offset=0, primary=true:
EOF

				if [ -z "${BLKDEV3}" ]; then
					# 3 disks
					# 1 2 3
					# B B X md0 (raid1+boot) md1 (raid1+swap?)
					# R R R md2 (raid5+lvm)
					cat <<EOF >>/tmp/create.evms
create:region, MDRaid5RegMgr={chunksize=$CHUNKSIZE}, ${BLKDEV0}$(( BLKDEVO+2 )), ${BLKDEV1}$(( BLKDEVO+2 )), ${BLKDEV2}$(( BLKDEVO+2 )):
EOF
					BOOTDEV=md/md0
					LVMDEV=md/md1
					# FIXME: what to use ${BLKDEV2}$((BLKDEVO+1)) for
				else
					# 4 disks
					# 1 2 3 4
					# B B S S md0 (raid1+boot) md1 (raid1+swap?)
					# R R R R md2 (raid5+lvm)
					cat <<EOF >>/tmp/create.evms
asm:DosSegMgr={}, ${BLKDEV3}:
create:segment, ${BLKDEV3}_freespace1, size=$BOOTSIZE, offset=0, primary=true, bootable=true:
create:segment, ${BLKDEV3}_freespace1, offset=0, primary=true:

create:region, MDRaid1RegMgr={}, ${BLKDEV2}$(( BLKDEVO+1 )), ${BLKDEV3}$(( BLKDEVO+1 )):
create:region, MDRaid5RegMgr={chunksize=$CHUNKSIZE}, ${BLKDEV0}$(( BLKDEVO+2 )), ${BLKDEV1}$(( BLKDEVO+2 )), ${BLKDEV2}$(( BLKDEVO+2 )), ${BLKDEV3}$(( BLKDEVO+2 )):
EOF
					BOOTDEV=md/md0
					LVMDEV=md/md2
					# FIXME: what to use md1 for
				fi

			else
				# 2 disks
				# 1 2
				# B B md0 (raid1+boot)
				# R R md1 (raid1+lvm)
				cat <<EOF >>/tmp/create.evms
create:region, MDRaid1RegMgr={}, ${BLKDEV0}$(( BLKDEVO+2 )), ${BLKDEV1}$(( BLKDEVO+2 )):
EOF

				BOOTDEV=md/md0
				LVMDEV=md/md1
			fi

#			echo 1000000 >/proc/sys/dev/raid/speed_limit_min
#			echo 1000000 >/proc/sys/dev/raid/speed_limit_max
		else
			# 1 disk
			# B 
			# R (lvm)
			BOOTDEV=${BLKDEV0}$(( BLKDEVO+1 ))
			LVMDEV=${BLKDEV0}$(( BLKDEVO+2 ))
		fi

		cat <<EOF >>/tmp/create.evms
create:volume, ${BOOTDEV}, name=boot:
format:XFS={}, /dev/evms/boot:

create:container, LVM2={name="$VG"}, $LVMDEV:

create:region, LVM2={name=root, size=$ROOTSIZE}, lvm2/$VG/Freespace:
create:volume, lvm2/$VG/root, Name=root:
format:XFS={},/dev/evms/root:

create:region, LVM2={name=tmp, size=$TMPSIZE}, lvm2/$VG/Freespace:
create:volume, lvm2/$VG/tmp, Name=tmp:
format:XFS={},/dev/evms/tmp:

create:region, LVM2={name=home, size=$HOMESIZE}, lvm2/$VG/Freespace:
create:volume, lvm2/$VG/home, Name=home:
format:XFS={},/dev/evms/home:

create:region, LVM2={name=var, size=$VARSIZE}, lvm2/$VG/Freespace:
create:volume, lvm2/$VG/var, Name=var:
format:XFS={},/dev/evms/var:

create:region, LVM2={name=swap, size=$SWAPSIZE}, lvm2/$VG/Freespace:
create:volume, lvm2/$VG/swap, Name=swap:
format:SWAPFS={},/dev/evms/swap:

quit
EOF

		evms -c -f /tmp/create.evms
	fi
}

removeall() {
	evms_activate

	if [ "$BLKDEVO" -ne 0 ]; then
		echo removeall only with BLKDEVO zero >&2
		exit 1
	fi

	for vol in $(evms_query volumes); do
		case $vol in
		*loop*)
			;;
		*)
			echo "Unformatting and deleting $vol" >&2
			echo unformat:$vol:
			echo delete:$vol:
			;;
		esac
	done >/tmp/remove.evms

	if [ -s /tmp/remove.evms ]; then
		evms -c -f /tmp/remove.evms 2>/dev/null || true
	fi

	skip="md/md*"

	for t in regions containers regions segments; do
		for o in $(evms_query $t); do
			case $o in
			*/Freespace|*_mbr|*_ebr[0-9]|*_freespace[0-9]*|*loop*)
				;;
			$skip)	
				;;
			*) 
				echo "Deleting $o" >&2
				echo d:$o:
				;;
			esac
		done >/tmp/remove.evms

		skip=""

		if [ -s /tmp/remove.evms ]; then
			evms -c -f /tmp/remove.evms 2>/dev/null || true
		fi
	done 
	
	for disk in $(evms_query disks); do
		case $disk in
		*loop*) 
			;;
		*)
			echo "Removing segment manager $disk" >&2
			echo "remove:$disk:" | evms -s 2>/dev/null || true
			;;
		esac
	done
}

do_mount() {
	swapon /dev/evms/swap

	[ -d $ROOT ] && rmdir $ROOT

	mkdir $ROOT; mount /dev/evms/root $ROOT

	for i in boot var tmp home; do
		[ -d $ROOT/$i ] || mkdir $ROOT/$i
		mount /dev/evms/$i $ROOT/$i
	done

	[ -d $ROOT/opt ] || mkdir $ROOT/opt

	chmod 1777 $ROOT/tmp

	touch /tmp/mount.done
}

do_umount() {
	cat /proc/mounts | tac | while read dev mp r; do
		case $mp in
		$ROOT*)
			if ! umount -f $mp 2>/dev/null; then
				fuser -s -m -k -1 $mp || true
				sleep 2
				if ! umount -f $mp 2>/dev/null; then
					fuser -s -m -k $mp || true
					sleep 5
					if ! umount -f $mp 2>/dev/null; then
						echo "umount of $mp failed" >&2
						umount -l $mp || true
					fi
				fi
			fi
			;;
		esac
	done

	swapoff /dev/evms/swap 2>/dev/null || true
	rm /tmp/mount.done 2>/dev/null || true
}

CHROOT="/usr/sbin/chroot $ROOT"

unset LANG LANGUAGE
unset $(set | grep ^LC_ | sed -e "s/=.*$//")
export PATH=/sbin:/usr/sbin:/bin:/usr/bin:/usr/local/sbin:/usr/local/bin

rdate zeit.fu-berlin.de
loadkeys $KEYBOARD
umask 0022

hostname $HOSTNAME
hwclock --systohc --utc

mount /proc 2>/dev/null || true
mount /sys  2>/dev/null || true

if [ "$1" = "removeall" -a ! -f /tmp/removeall.done ]; then
	do_umount
	removeall
	touch /tmp/removeall.done
	rm /tmp/mkfs.done 2>/dev/null || true
	exit
fi

if ! [ -f /tmp/mkfs.done ]; then
	mkfs
	touch /tmp/mkfs.done
	rm /tmp/debootstrap.done 2>/dev/null || true
fi

if ! [ -f /tmp/mount.done ]; then
	do_umount
	do_mount
fi

if ! [ -f /tmp/debootstrap.done ]; then
	until debootstrap $DIST $ROOT $MIRRORMAIN; do
		echo debootstrap failed: $?
		sleep 10
	done
	touch /tmp/debootstrap.done
fi

[ -d $ROOT/etc ] || mkdir $ROOT/etc

cat <<EOF >$ROOT/etc/fstab
/dev/evms/root		/		xfs	defaults	0	0
/dev/evms/boot		/boot		xfs	defaults	0	0
/dev/evms/var		/var		xfs	defaults	0	0
/dev/evms/tmp		/tmp		xfs	defaults	0	0
/dev/evms/home		/home		xfs	defaults	0	0

proc			/proc		proc	defaults	0	0
sysfs			/sys		sysfs	defaults	0	0
devpts			/dev/pts	devpts	defaults	0	0

/dev/evms/swap		swap		swap	defaults	0	0
EOF

echo $NETDEV >>$ROOT/etc/modules
echo $HOSTNAME >$ROOT/etc/hostname

cat <<EOF >$ROOT/etc/hosts
127.0.0.1 localhost $HOSTNAME
EOF

cat <<EOF >$ROOT/etc/kernel-img.conf
do_symlinks=yes
do_initrd=yes
postinst_hook = update-grub
postrm_hook   = update-grub
EOF

[ -d $ROOT/etc/network ] || mkdir $ROOT/etc/network

cat <<EOF >$ROOT/etc/network/interfaces
auto lo
iface lo inet loopback

auto eth0
iface eth0 inet static
	address		$IP_ADDRESS
	broadcast	$IP_BROADCAST
	netmask		$IP_NETMASK
	gateway		$IP_GATEWAY
EOF

cat <<EOF >$ROOT/etc/network/options
ip_forward=yes
spoofprotect=yes
syncookies=no
EOF

[ -d $ROOT/etc/apt/apt.conf.d ] || mkdir -p $ROOT/etc/apt/apt.conf.d

cat <<EOF >$ROOT/etc/apt/apt.conf.d/stable
APT::Default-Release "stable";
EOF

$CHROOT mount /proc || true
$CHROOT mount /sys || true

# adapt using debconf-get-selections(8) on a preconfigured box or
# preceed with
#cat <<EOF >/dev/null
$CHROOT debconf-set-selections <<EOF
debconf	debconf/frontend	select	Noninteractive
debconf	debconf/priority	select	critical
base-config	base-config/intro	note 
base-config	base-config/login	note 
base-config	mirror/suite	select	stable
base-config	apt-setup/badedit	select	
base-config	apt-setup/cd/another	boolean	false
base-config	apt-setup/cd/dev	string	
base-config	apt-setup/country	select	enter information manually
base-config	apt-setup/uri_type	select	$MIRRORMAINMETHOD
base-config	apt-setup/hostname	string	$MIRRORMAINHOST
base-config	apt-setup/directory	string	$MIRRORMAINDIR
base-config	apt-setup/contrib	boolean	false
base-config	apt-setup/non-free	boolean	false
base-config	apt-setup/another	boolean	false
base-config	apt-setup/security-updates	boolean	false
base-config	tzconfig/change_timezone	boolean	false
base-config	tzconfig/gmt	boolean	true
base-config	tzconfig/geographic_area	select	$AREA
unknown	tzconfig/select_zone/$AREA	select	$TIMEZONE
dictionaries-common	dictionaries-common/default-ispell	select	american (American English)
dictionaries-common	dictionaries-common/default-wordlist	select	american (American English)
dictionaries-common	dictionaries-common/move_old_usr_dict	boolean	true
dictionaries-common	dictionaries-common/old_wordlist_link	boolean	true
dictionaries-common	dictionaries-common/remove_old_usr_dict_link	boolean	false
tasksel	tasksel/first	multiselect	
tasksel	tasksel/tasks	multiselect	Mail server
locales	locales/default_environment_locale	select	None
locales	locales/locales_to_be_generated	multiselect	$LOCALE
passwd	passwd/md5	boolean	true
passwd	passwd/shadow	boolean	true
exim4-config	exim4/dc_eximconfig_configtype	select	local delivery only; not on a network 
exim4-config	exim4/dc_local_interfaces	string	127.0.0.1
exim4-config	exim4/dc_other_hostnames	string	$HOSTNAME
exim4-config	exim4/dc_postmaster	string	$USERNAME
exim4-config	exim4/exim3_upgrade	boolean	true
exim4-config	exim4/mailname	string	$HOSTNAME
exim4-config	exim4/no_config	boolean	true
exim4-config	exim4/use_split_config	boolean	false
ssh	ssh/SUID_client	boolean	true
ssh	ssh/disable_cr_auth	boolean	false
ssh	ssh/new_config	boolean	true
ssh	ssh/protocol2_only	boolean	true
ssh	ssh/run_sshd	boolean	true
ssh	ssh/use_old_init_script	boolean	true
mdadm	mdadm/autostart	boolean	false
mdadm	mdadm/mail_to	string	root
mdadm	mdadm/start_daemon	boolean	true
EOF

$CHROOT mount -t devpts devpts /dev/pts || true
#$CHROOT base-config new || true

$CHROOT apt-get --force-yes -y install less vim xfsprogs evms evms-ncurses evms-cli udev locales console-common bzip2 cron-apt ssh

cat <<EOF >>$ROOT/etc/apt/sources.list
deb $MIRRORSEC	etch/updates	main
EOF

$CHROOT apt-get -y remove --purge ispell ppp pppoe pppoeconf pppconfig nvi nano
$CHROOT apt-get update
$CHROOT apt-get -y upgrade

perl -i -pe "s/FSCKFIX=no/FSCKFIX=yes/" $ROOT/etc/default/rcS
perl -i -pe "s/UTC=no/UTC=yes/" $ROOT/etc/default/rcS
perl -i -pe "s/DELAYLOGIN=yes/DELAYLOGIN=no/" $ROOT/etc/default/rcS
perl -i -pe "s/device_size_prompt = yes/device_size_prompt = no/" $ROOT/etc/evms.conf
perl -i -pe 's/KLOGD=""/KLOGD="-c 2 -k \/boot\/System.map-\$(uname -r)"/' $ROOT/etc/init.d/klogd

$CHROOT /usr/sbin/install-keymap $KEYBOARD || true

$CHROOT /sbin/evms_activate
$CHROOT apt-get -y install yaird grub grub-doc

cp -a $ROOT/$GRUBDIR $ROOT/boot/grub

cat <<EOF >$ROOT/boot/grub/menu.lst
default saved
timeout 5

### BEGIN AUTOMAGIC KERNELS LIST

## ## Start Default Options ##
# kopt=root=/dev/evms/root ro
# groot=(hd0,$BLKDEVO)
## ## End Default Options ##

### END DEBIAN AUTOMAGIC KERNELS LIST

EOF

cat <<EOF >$ROOT/boot/grub/default
0
#
#
#
#
#
#
#
#
#
#
# WARNING: If you want to edit this file directly, do not remove any line
# from this file, including this warning. Using \`grub-set-default' is
# strongly recommended.
EOF

$CHROOT apt-get -y install linux-image-$KERNEL

$CHROOT debconf-set-selections <<EOF
debconf	debconf/frontend	select	Dialog
debconf	debconf/priority	select	medium
EOF


$CHROOT tzconfig
$CHROOT passwd -e root

$CHROOT adduser $USERNAME

set +e

do_umount

rmdir $ROOT

swapoff -a

if [ -n "${BLKDEV1}" -a -f /dev/md0 ]; then
	until mdadm -D /dev/md0 |grep -qs "State : clean"; do
		echo "Waiting for rebuild to complete..."
		sleep 30
	done
fi

grub --no-floppy --batch <<EOF
device (hd0) /dev/$BLKDEV0
root (hd0,$BLKDEVO)
setup (hd0)
quit
EOF

if [ -n "${BLKDEV1}" ]; then
	grub --no-floppy --batch <<EOF
device (hd0) /dev/$BLKDEV1
root (hd0,$BLKDEVO)
setup (hd0)
quit
EOF
fi


sync

rm /tmp/create.evms /tmp/remove.evms /tmp/removeall.done /tmp/mkfs.done /tmp/mount.done /tmp/debootstrap.done 2>/dev/null

