#!/bin/sh
#$Id: mkimage.sh,v 1.10 2008/11/20 20:08:13 khorben Exp $
#Copyright (c) 2008 Pierre Pronchery <khorben@defora.org>
#This file is part of Nothing
#Nothing 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.
#
#Nothing 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 Nothing; if not, write to the Free Software
#Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
#TODO
#- fix debugging for non-root users


#public
DEBUG=0
DOMAIN='defora.air'
HOSTNAME='kos'
IMAGE="$PWD/nothing-$HOSTNAME.img"
IMAGE_BS='1024'
IMAGE_COUNT='498456'
PACKAGES='ap13-php4 apache gnupg netcat php4-posix php4-sqlite postfix screen shared-mime-info sqlite vim'
SANDBOX="$PWD/sandbox"
USERNAME=`id -un`
DISTFILES="$PWD/distfiles/pub/NetBSD"
VND='vnd0'
X11_TYPE='none'

NETBSD_MIRROR='ftp3.de.netbsd.org'
NETBSD_VERSION='4.0'
NETBSD_ARCH=`uname -m`
NETBSD_KERNEL='GENERIC'
PKG_PATH="ftp://$NETBSD_MIRROR/pub/NetBSD/packages/$NETBSD_VERSION/$NETBSD_ARCH/All"

#private
MIRROR="ftp://$NETBSD_MIRROR/pub/NetBSD/NetBSD-$NETBSD_VERSION"
MIRROR_KERNEL="$MIRROR/$NETBSD_ARCH/binary/kernel"
MIRROR_SETS="$MIRROR/$NETBSD_ARCH/binary/sets"

#commands
SUDO=''
if [ "$UID" != "0" ]; then
	SUDO='sudo '
fi
if [ "$DEBUG" != "0" ]; then
	SUDO="debug $SUDO"
fi

CHMOD='chmod'
CHROOT="${SUDO}chroot"
CP='cp -f'
DD='dd'
ENV='env -i'
FDISK="${SUDO}fdisk"
GREP='grep'
INSTALLBOOT="${SUDO}installboot"
LN='ln -sf'
MAKEDEV="${SUDO}sh MAKEDEV"
MBRLABEL="${SUDO}mbrlabel"
MD5='md5'
MKDIR='mkdir -p'
MOUNT="${SUDO}mount"
MV='mv -f'
NEWFS="${SUDO}newfs"
PKG_ADD='pkg_add'
PROGRESS='progress'
RM='rm -f'
RMDIR='rmdir'
TAR='tar'
TOUCH='touch'
UMOUNT="${SUDO}umount"
VNCONFIG="${SUDO}vnconfig"
WGET='wget'


#functions
#chroot_do
chroot_do()
{
	$CHROOT "$SANDBOX" $ENV HOME="/root" PATH="$PATH" PKG_PATH="$PKG_PATH" $@
}


#debug
debug()
{
	echo "Executing privileged operation:"
	echo "- current directory: '$PWD'"
	echo "- requested command: '$@'"
	echo -n "Press <enter> to continue or <CTRL+C> to stop"
	read enter
	$@
}


#download
download()
{
	[ $# -ne 2 ] && return 1
	$WGET "$1" -O "$2"
}


#main
umask 022

#prepare sandbox
$UMOUNT "$SANDBOX"
$VNCONFIG -u "$VND"
$MKDIR "$SANDBOX"						|| exit 2
echo "Creating new image ($((IMAGE_BS * IMAGE_COUNT / 1048576)) MB):"
$PROGRESS -f /dev/zero $DD of="$IMAGE" bs="${IMAGE_BS}" count="${IMAGE_COUNT}"
$FDISK -Ffi "$IMAGE"						|| exit 2
SIZE=$((IMAGE_COUNT * IMAGE_BS / 512 - 63))
$FDISK -Ffu0s "169/63/$SIZE" "$IMAGE"				|| exit 2
$FDISK -Ffa0 "$IMAGE"						|| exit 2
$VNCONFIG -c "$VND" "$IMAGE"					|| exit 2
$MBRLABEL -frw "$VND"						|| exit 2
$NEWFS "${VND}e"						|| exit 2
$MOUNT "/dev/${VND}e" "$SANDBOX"				|| exit 2

#download and extract sets
DISTSETS="$DISTFILES/NetBSD-$NETBSD_VERSION/$NETBSD_ARCH/binary/sets"
$MKDIR "$DISTSETS"
$WGET "$MIRROR_SETS/MD5" -O - | while read NMD5 FILENAME EQUALS HASH JUNK; do
	SET="${FILENAME#(}"
	SET="${SET%)}"
	OUTPUT="$DISTSETS/$SET"

	#do not download if not necessary
	[ "comp${SET#comp}" = "$SET" ] && continue
	[ "games${SET#games}" = "$SET" ] && continue
	[ "kern-${SET#kern-}" = "$SET" ] && continue
	[ "$X11_TYPE" != 'native' -a "x${SET#x}" = "$SET" ] && continue

	#if already exists check hash
	if [ -f "$OUTPUT" ]; then
		$MD5 "$OUTPUT" | while read OMD5 OFILENAME OEQUALS OHASH OJUNK;
		do
			[ "$HASH" = "$OHASH" ] || $RM "$OUTPUT"
			break
		done
	fi

	#if does not exist download and check hash
	if [ ! -f "$OUTPUT" ]; then
		download "$MIRROR_SETS/$SET" "$OUTPUT"

		$MD5 "$OUTPUT" | while read OMD5 OFILENAME OEQUALS OHASH OJUNK;
		do
			if [ ! "$HASH" = "$OHASH" ]; then
				echo "Set: $SET, server hash: $HASH does not" \
					" match local hash: $OHASH"
				exit
			fi
			break
		done
	fi

	#extract
	echo "Extracting set $SET:"
	(cd "$SANDBOX" && $PROGRESS -f "$OUTPUT" ${SUDO}$TAR -xpzf -) || exit 2
done

#download kernel
echo "Installing kernel:"
#FIXME verify MD5 as well
${SUDO}$WGET "$MIRROR_KERNEL/netbsd-$NETBSD_KERNEL.gz" -O "$SANDBOX/netbsd"
${SUDO}$CHMOD 0755 "$SANDBOX/netbsd"

#create remaining directories
$SUDO$MKDIR "$SANDBOX/kern"

#generate device nodes
echo -n "Generating device nodes:"
(cd "$SANDBOX/dev" && $MAKEDEV all) &&
echo " done"

#make partition bootable
echo -n "Making partition bootable:"
${SUDO}$CP "$SANDBOX/usr/mdec/boot" "$SANDBOX/boot"		|| exit 2
$INSTALLBOOT -m "$NETBSD_ARCH" -o 'console=com0,speed=115200' "/dev/r${VND}e" /usr/mdec/bootxx_ffsv1
echo " done"

#making partition read-only
for i in /var/log /var/run /var/tmp; do
	${SUDO}$RM -r "$SANDBOX/$i"
	${SUDO}$MKDIR "$SANDBOX/$i"
	${SUDO}$LN "/tmp/$i" "$SANDBOX/$i"
done
${SUDO}$CHMOD 1777 "$SANDBOX/tmp/var/tmp"
for i in p q r s; do
	for j in 0 1 2 3 4 5 6 7 8 9 a b c d e f; do
		${SUDO}$RM "$SANDBOX/dev/tty$i$j"
		${SUDO}$LN "/tmp/dev/tty$i$j" "$SANDBOX/dev/tty$i$j"
	done
done

#configure
echo -n "Configuring system:"
#fstab
${SUDO}sh -c "cat >> \"$SANDBOX/etc/fstab\"" << EOF
/dev/wd0e / ffs ro 1 1
/dev/null /tmp mfs rw,-s=16m
kernfs /kern kernfs rw
EOF
echo -n " fstab"

#hosts
${SUDO}sh -c "cat >> \"$SANDBOX/etc/hosts\"" << EOF
127.0.0.1	localhost.localdomain	localhost
::1		localhost.localdomain	localhost
127.0.0.1	$HOSTNAME.$DOMAIN	$HOSTNAME
EOF
echo -n " hosts"

#ksh
chroot_do chsh -s /bin/ksh root
echo -n " ksh"

#localtime
${SUDO}$LN '/usr/share/zoneinfo/Europe/Berlin' "$SANDBOX/etc/localtime"
echo -n " localtime"

#motd
${SUDO}sh -c "cat > \"$SANDBOX/etc/motd\"" << EOF
NetBSD $NETBSD_VERSION ($NETBSD_KERNEL)

Welcome to NetBSD!

EOF
echo -n " motd"

#myname
${SUDO}sh -c "cat >> \"$SANDBOX/etc/myname\"" << EOF
$HOSTNAME.$DOMAIN
EOF
echo -n " myname"

#rc.conf
${SUDO}sh -c "cat >> \"$SANDBOX/etc/rc.conf\"" << EOF
rc_configured=YES

accounting=NO
clear_tmp=NO
mountro=YES
no_swap=YES
savecore=NO
update_motd=NO
virecover=NO

#services
inetd=NO
postfix=NO
sendmail=NO
sshd=NO
syslogd=YES		syslogd_flags="-s -p /var/run/log -p /var/chroot/squid/d
ev/log"

#packages
apache=YES
EOF
echo -n " rc.conf"

#rc.d/mountro
${SUDO}sh -c "cat > \"$SANDBOX/etc/rc.d/mountro\"" << EOF
#!/bin/sh

# PROVIDE: mountro
# REQUIRE: root
# BEFORE: mountcritlocal

\$_rc_subr_loaded . /etc/rc.subr

name="mountro"
start_cmd="mountro_start"
stop_cmd=":"

mountro_start ()
{
	mount /tmp
	for i in dev var/run var/tmp; do
		mkdir -p "/tmp/\$i"
	done
	(cd /tmp/dev && sh /dev/MAKEDEV pty0 pty1 pty2 pty3)
	chmod 1777 /tmp/var/tmp
	if [ -f /etc/nologin ]; then
		mount -uo rw /
		rm -f /etc/nologin
		mount -uo ro /
	fi
}

load_rc_config \$name
run_rc_command "\$1"
EOF
${SUDO}$CHMOD 755 "$SANDBOX/etc/rc.d/mountro"
echo -n " mountro"

#resolv
${SUDO}sh -c "cat >> \"$SANDBOX/etc/resolv.conf\"" << EOF
search $DOMAIN
EOF
$GREP '^nameserver' '/etc/resolv.conf' \
		| ${SUDO}sh -c "cat >> \"$SANDBOX/etc/resolv.conf\""
echo -n " resolv"

echo

#configuring users
echo -n "Configuring users:"
${SUDO}$MKDIR "$SANDBOX/home/$USERNAME"
chroot_do groupadd -g 1000 "$USERNAME"
chroot_do useradd -d "/home/$USERNAME" -G 'wheel' -u 1000 -g "$USERNAME" \
		  -s '/bin/ksh' "$USERNAME"
echo -n " $USERNAME"

echo

#install packages
echo "Installing packages:"
chroot_do $PKG_ADD $PACKAGES					|| exit 2

#configure packages
echo -n "Configuring packages:"
for i in $PACKAGES; do
	[ ! -f "packages/$i" ] && continue
	echo -n " $i"
	. "packages/$i"
done

echo


#host-specific
if [ -d "hosts/$HOSTNAME.$DOMAIN" ]; then
	echo "Configuring host: "
	(cd "hosts/$HOSTNAME.$DOMAIN" && ${SUDO}$TAR -cf - *) \
		| (cd "$SANDBOX" && ${SUDO}$TAR -xpvvf -)
	echo
fi

#end of main
$UMOUNT "$SANDBOX"						|| exit 2
$VNCONFIG -u "$VND"						|| exit 2

