#!/bin/bash
#---------------------------------------------------------------
# Project         : Mandriva Linux
# Module          : rpm-rebuilder
# File            : chrooted-install
# Version         : $Id: chrooted-install,v 1.20 2005/10/03 14:27:49 gbeauchesne Exp $
# Author          : Frederic Lepied
# Created On      : Sun Oct 22 20:03:40 2000
#---------------------------------------------------------------

set -e				# abort on error
#set -x				# output commands before executing them

export LC_ALL=C

if [ `whoami` != root ]; then
    echo "must be run by root" 1>&2
    exit 1
fi

SSH_PORT=24
rpmbin=/bin/rpm
SERVICE=chroot

RPM_REBUILDER_LIB=${RPM_REBUILDER_LIB=/usr/share/rpm-rebuilder}
USE_URPMI=1

usage() {
cat 1>&2 <<EOF
usage: `basename $0` [<options>] <root dest> <install dir> [<dir>...]
    options: -u <user> (create a user with name <user>)
	     -i <uid> (use <uid> for new user)
             -r (ask root password)
	     -p <port> (use <port> for sshd. default is $SSH_PORT. For no sshd support use 0.)
	     -b <rpmbin> (the path to the rpm command)
	     -s <service name> (the name of the service to add to /etc/init.d. Use an empty name if you don't want to create a service.)
	     -S <host>:<path> (nfs spec to be mounted on /SRPMS)
	     -R rebuild the rpm database after installing the base with the new rpm
	     -A runs the rpm scriptlets after installing the base system
	     -y install ypbind and configure it like in the host system
	     -m use pam_mkhomedir in pam config of sshd
             -U use urpmi to install basesystem (default)
	     --no-urpmi do not use urpmi to handle the installation of packages
	     --media <media> urpmi media to bootstrap the system
             -N no password for user
	     -f force to start even if the root directory already exists
EOF
}

while [ -n "$*" ]; do
    case $1 in
	-u) shift; user=$1; shift;;
	-i) shift; uid="-u $1"; shift;;
	-r) rootpass=1; shift;;
	-R) rebuild=1; shift;;
	-p) shift; SSH_PORT=$1; shift;;
	-b) shift; rpmbin=$1; shift;;    
	-s) shift; SERVICE=$1; shift;;    
	-S) shift; srpms=$1; shift;;
	-A) shift; SCRIPT_AFTER=1;;
	-y) shift; YPBIND=1;;
	-m) shift; PAM_MKHOMEDIR=1;;
	-U) shift; USE_URPMI=1;;
	--no-urpmi) shift; USE_URPMI="";;
	--media) shift; media="$1"; shift;;
	--distrib) USE_DISTRIB=1; shift;;
	--bind) USE_BIND=1; shift;;
	-N) shift; NO_PASSWORD=1;;
	-f) shift; FORCE=1;;
	*) break;;
    esac
done

if [ $# -lt 2 ]; then
    echo "invalid number of args" 1>&2
    usage
    exit 1
fi

root=$1
instdir=$2
shift
shift
dirs=$*

mdir() {
    if [ ! -d $1 ]; then
	echo "creating $1"
	mkdir -p $1
    fi
}

lmount() {
	if [ -n "$USE_BIND" ]; then
		mnt="mount -obind,ro $1 $2"
	else
	    case $1 in
		*:*)
		    mnt="mount -orsize=8192,wsize=8192,ro $1 $2"
		    ;;
		*)
		    mnt="mount -orsize=8192,wsize=8192,ro localhost:$1 $2"
		    ;;
	     esac
     	fi
     	eval $mnt
     	if [ -z "$allmnt" ]; then
		allmnt=$mnt
     	else
		allmnt="$allmnt;$mnt"
	fi
}

runscript() {
    interp=`chroot $root /bin/rpm -q --qf "%{$2}" $1`
    script=`chroot $root /bin/rpm -q --qf "%{$3}" $1`
    
    if [ -n "$script" -a "$script" != "(none)" ]; then
	if [ -z "$interp" -o "$interp" = "(none)" ]; then
	    interp=/bin/sh
	fi
	echo "$1: executing $3 through $interp:"
	echo "$script" | chroot $root $interp
    fi
}

runscripts() {
    for p in `chroot $root /bin/rpm -qa`; do
	runscript $p PREINPROG PREIN
	runscript $p POSTINPROG POSTIN
    done
}

# sanity checks

if [ "$FORCE" != 1 -a -d $root ]; then
    echo "$root already exist" 1>&2
    exit 1
fi

# nfs mount the install dir
mdir $root/export
lmount $instdir $root/export

# test if we only have the RPMS or the full install tree
if [ -d $root/export/Mandrake/RPMS ]; then
    rpms=$root/export/Mandrake/RPMS
    inst=/export/Mandrake/RPMS
    basedir=$root/export/Mandrake/base
elif [ -d $root/export/media/main ]; then
    rpms=$root/export/media/main
    inst=/export/media/main
    basedir=$root/export/media/media_info
else
    echo "no such dir $instdir/Mandrake/RPMS" 1>&2
    exit 1
fi

# create the needed files and dirs to fool the packages
mkdir -p $root/etc/sysconfig $root/dev/pts $root/etc/urpmi $root/lib
touch $root/etc/ld.so.conf $root/etc/mtab $root/etc/urpmi/urpmi.cfg
mknod  $root/dev/null c 1 3
chmod a+rw $root/dev/null
mknod  $root/dev/urandom c 1 9
chmod a+rw $root/dev/urandom

cat >  $root/etc/fstab <<EOF
none /proc proc defaults 0 0
none /dev/pts devpts defaults 0 0
EOF

# workaround a bug
touch $root/etc/sysconfig/system

# install rpm database
mdir $root/var/lib/rpm
$rpmbin --root $root --initdb

if [ -n "$USE_URPMI" ]; then
    default_rpms=" filesystem mount urpmi lsof findutils gzip passwd net-tools"
    if [ -n "$USE_DISTRIB" ]; then
    	    urpmi --use-distrib $root/export --root $root --auto --no-verify-rpm $default_rpms || :
    elif [ -n "$media" ]; then
	urpmi --media "$media" --root $root --auto --no-verify-rpm $default_rpms || :
    else
	urpmi --root $root --auto --no-verify-rpm $default_rpms || :
    fi
else
    # install basessytem
    cd $rpms

    base=`$RPM_REBUILDER_LIB/head-grep.py '^basesystem' < $basedir/depslist.ordered | fgrep -v kernel | grep -v 'locales-[a-z]' | cut -d ' ' -f 1 | sed 's/\(.*mdk\).*/\1/'`

    basefiles=""

    for f in $base; do
	basefiles="$basefiles $f*.rpm"
    done

    basefiles="$basefiles libatk1.0_0-[0-9]* mkinitrd-[0-9]* kernel-2*[0-9]* db2-[0-9]* libgdbm2-[0-9]* libopenssl0-[0-9]* libopenssl0.[0-9].[0-9]-[0-9]* libgdbm[0-9]-[0-9]* openssl-[0-9]* libopenssl-[0-9]* libopenssl[0-9].[0-9].[0-9]-[0-9]* wget-[0-9]* rpmtools-[0-9]* perl-[0-9]* lsof-[0-9]* eject-[0-9]* perl-gettext-[0-9]* libgettext* gettext-[0-9]* perl-DateManip-[0-9]* perl-URPM-[0-9]* perl-Locale-gettext-[0-9]* gnupg-[0-9]*"

    if [ -n "$SCRIPT_AFTER" ]; then
	$rpmbin --root $root -ivh  --noscripts --noorder $basefiles || :
    else
	$rpmbin --root $root -ivh $basefiles || :
    fi

    if [ -n "$rebuild" ]; then
	# rebuild the databases for the case we haven't used the same version of rpm as the one installed
	echo "Rebuilding the rpm databases"
	chroot $root /bin/rpm --rebuilddb
    fi

    # we have installed with --noscripts so run the scripts afterward
    if [ -n "$SCRIPT_AFTER" ]; then
	runscripts
    fi

    # make sure urpmi is installed
    chroot $root /bin/sh -c "/bin/rpm -ivh $inst/urpmi-[0-9]*" || :
fi

# update urpmi database
chroot $root urpmi.addmedia local file:/$inst

if [ $SSH_PORT != 0 ]; then
# install an openssh server
    chroot $root urpmi --no-verify-rpm --auto --force --no-verify-rpm openssh-server || :
    tar c -C /etc ssh | tar xv -C $root/etc
    perl -p -i -e "s/#?Port 22/Port $SSH_PORT/" $root/etc/ssh/sshd_config

    if [ -n "$PAM_MKHOMEDIR" ]; then
	echo "Installing pam_mkhomedir in pam.d/sshd"
	echo "session    required     pam_mkhomedir.so" >> $root/etc/pam.d/sshd
    fi

    # unmout all
    chroot $root urpmi lsof filesystem || :
    cd /
    umount $root/export
    mkdir -p $root/proc
    chroot $root mount -t proc none /proc || :
    pids=`chroot $root lsof -t /proc`
    kill -9 $pids || :
    sleep 1
    chroot $root umount /proc || :
fi


if [ -n "$YPBIND" -a -r /etc/yp.conf ]; then
    echo "Installing ypbind"
    chroot $root urpmi --auto --force --no-verify-rpm ypbind || :
    cp /etc/yp.conf $root/etc/
    YPBINDSTART="chroot $root service ypbind start"
    YPBINDSTOP="chroot $root service ypbind stop"
else
    perl -p -i -e 's/nisplus.*nis//' $root/etc/nsswitch.conf
fi

# copy local config files
cp -p /etc/resolv.conf /etc/hosts $root/etc/
if [ -f /etc/rpm/macros ]; then
    cp -p /etc/rpm/macros $root/etc/rpm
fi

# fill fstab fir /SRPMS
if [ -n "$srpms" ]; then
    mkdir $root/SRPMS
    cat >> $root/etc/fstab <<EOF
$srpms	/SRPMS	nfs	rsize=8192,wsize=8192,ro 0 0
EOF
fi

# install a startup script
service=/etc/rc.d/init.d/$SERVICE

if [ -n "$SERVICE" -a ! -f $service -a $SSH_PORT != 0 ]; then

# start at level 61 to be started after nfs and sshd

cat > $service <<EOF
#! /bin/sh
#
# chkconfig: 2345 61 25
# description: start an sshd daemon on a chrooted system
# processname: sshd
# pidfile: $root/var/run/sshd.pid

# Get config.
. /etc/sysconfig/network

# Get functions
. /etc/rc.d/init.d/functions

# Check that networking is up.
if [ \${NETWORKING} = "no" ]
then
	exit 0
fi

# See how we were called.
case "\$1" in
  start)
	echo -n "Starting $SERVICE environment: "
	$allmnt
	chroot $root mount -a
	chroot $root service sshd start
	$YPBINDSTART
	echo
	touch /var/lock/subsys/$SERVICE
	;;
  stop)
	echo -n "Stopping chrooted environment: "
	chroot $root service sshd stop
	$YPBINDSTOP
	chroot $root umount -a
	umount $root/export

	echo
	rm -f /var/lock/subsys/$SERVICE
	;;
  status)
	status $SERVICE
	;;
  restart)
	\$0 stop
	\$0 start
	;;
  *)
	echo "Usage: $SERVICE {start|stop|status|restart}"
	exit 1
esac

exit 0

EOF
chmod +x $service
chkconfig --add $SERVICE
$service start

elif [ -z "$SERVICE" ]; then
    chroot $root mount -a
fi

# post install stuff

chroot $root pwconv

if [ -n "$rootpass" ]; then
    echo "Enter root password for chrooted environment"
    chroot $root passwd
fi

if [ -n "$user" ]; then
    chroot $root adduser $uid $user
    if [ -z "$NO_PASSWORD" ]; then
	echo "Enter password for user $user"
	chroot $root passwd $user
    fi
fi

if [ $SSH_PORT != 0 ]; then
    echo "install completed on $root (ssh port is $SSH_PORT)"
else
    echo "install completed on $root"
fi

# chrooted-install ends here
