#!/bin/bash ###################################################################### # ndebootstrap April 2006 # Horms horms@verge.net.au # # ndebootstrap # NFS-root debootstrap # Copyright (C) 2006 Horms # # Create a debian root directory, suitable for use with NFS-root, # using debootstrap. Actually, its probably useful for other things too. # debootstrap is almost there, but not quite. # # This program 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. # # This program 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 this program; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA # 02111-1307 USA # ###################################################################### # TODO: # Get a better name for this script # Pass root password in environent (encrypted?) # Pass hostname in environement or on the command line # Does the root directory need to be in /etc/fstab ? RETRY_COUNT=5 TARGET="" SUITE="" MIRROR="" SCRIPT="" set -e check_target () { [ -e "$TARGET" ] } check_target_and_error () { if check_target; then echo "\"$TARGET\" already exists, "\ "please move out of the way" >&2 exit 1 fi } check_root () { if [ "$(id -u)" != "0" ]; then echo "Need root privelages" >&2 exit 1 fi } CLEAN="" clean_up () { check_target for i in $CLEAN; do rm -r "$CLEAN" done } trap clean_up EXIT usage () { echo "Usage: ${0##*/} [OPTION...] SUITE TARGET [MIRROR [SCRIPT]]" >&2 echo " Arguments as per debootstrap(8)" >&2 exit 1 } check_ops () { local OPTS=y local ARG while [ $# -gt 0 ]; do ARG="$1"; shift if [ "${ARG##--}" != "$ARG" ]; then if [ "$OPTS" == "y" ]; then continue; else usage fi fi OPTS=n if [ -z "$SUITE" ]; then SUITE="$ARG" elif [ -z "$TARGET" ]; then TARGET="$ARG" elif [ -z "$MIRROR" ]; then MIRROR="$ARG" elif [ -z "$MIRROR" ]; then MIRROR="$ARG" else usage fi done if [ -z "$SUITE" -o -z "$TARGET" ]; then usage fi } create_etc_fstab () { check_target install -m 644 -o root -g root /dev/null "$TARGET/etc/fstab" cat > "$TARGET/etc/fstab" << __EOF__ # /etc/fstab: static file system information. # # proc /proc proc defaults 0 0 __EOF__ } create_etc_hosts () { check_target install -m 644 -o root -g root /dev/null "$TARGET/etc/hosts" cat > "$TARGET/etc/hosts" << __EOF__ 127.0.0.1 localhost ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts __EOF__ } create_etc_inittab () { check_target install -m 644 -o root -g root /dev/null "$TARGET/etc/inittab" cat > "$TARGET/etc/inittab" << __EOF__ # /etc/inittab: init(8) configuration. # $Id: inittab,v 1.91 2002/01/25 13:35:21 miquels Exp $ # The default runlevel. id:2:initdefault: # Boot-time system configuration/initialization script. # This is run first except when booting in emergency (-b) mode. si::sysinit:/etc/init.d/rcS # What to do in single-user mode. ~~:S:wait:/sbin/sulogin # /etc/init.d executes the S and K scripts upon change # of runlevel. # # Runlevel 0 is halt. # Runlevel 1 is single-user. # Runlevels 2-5 are multi-user. # Runlevel 6 is reboot. l0:0:wait:/etc/init.d/rc 0 l1:1:wait:/etc/init.d/rc 1 l2:2:wait:/etc/init.d/rc 2 l3:3:wait:/etc/init.d/rc 3 l4:4:wait:/etc/init.d/rc 4 l5:5:wait:/etc/init.d/rc 5 l6:6:wait:/etc/init.d/rc 6 # Normally not reached, but fallthrough in case of emergency. z6:6:respawn:/sbin/sulogin # What to do when CTRL-ALT-DEL is pressed. ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now # Action on special keypress (ALT-UpArrow). #kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work." # What to do when the power fails/returns. pf::powerwait:/etc/init.d/powerfail start pn::powerfailnow:/etc/init.d/powerfail now po::powerokwait:/etc/init.d/powerfail stop # /sbin/getty invocations for the runlevels. # # The "id" field MUST be the same as the last # characters of the device (after "tty"). # # Format: # ::: # # Note that on most Debian systems tty7 is used by the X Window System, # so if you want to add more getty's go ahead but skip tty7 if you run X. # 1:2345:respawn:/sbin/getty 38400 tty1 2:23:respawn:/sbin/getty 38400 tty2 3:23:respawn:/sbin/getty 38400 tty3 4:23:respawn:/sbin/getty 38400 tty4 5:23:respawn:/sbin/getty 38400 tty5 6:23:respawn:/sbin/getty 38400 tty6 # Example how to put a getty on a serial line (for a terminal) # #T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100 #T1:23:respawn:/sbin/getty -L ttyS1 9600 vt100 # Example how to put a getty on a modem line. # #T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3 __EOF__ } create_etc_passwd () { check_target install -m 644 -o root -g root /dev/null "$TARGET/etc/passwd" cat > "$TARGET/etc/passwd" << __EOF__ root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/bin/sh bin:x:2:2:bin:/bin:/bin/sh sys:x:3:3:sys:/dev:/bin/sh sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/bin/sh man:x:6:12:man:/var/cache/man:/bin/sh lp:x:7:7:lp:/var/spool/lpd:/bin/sh mail:x:8:8:mail:/var/mail:/bin/sh news:x:9:9:news:/var/spool/news:/bin/sh uucp:x:10:10:uucp:/var/spool/uucp:/bin/sh proxy:x:13:13:proxy:/bin:/bin/sh www-data:x:33:33:www-data:/var/www:/bin/sh backup:x:34:34:backup:/var/backups:/bin/sh list:x:38:38:Mailing List Manager:/var/list:/bin/sh irc:x:39:39:ircd:/var/run/ircd:/bin/sh gnats:x:41:41:Gnats Bug-Reporting System (admin):/var/lib/gnats:/bin/sh nobody:x:65534:65534:nobody:/nonexistent:/bin/sh __EOF__ } create_etc_shadow () { check_target install -m 600 -o root -g root /dev/null "$TARGET/etc/shadow" cat > "$TARGET/etc/shadow" << __EOF__ root:*:12487:0:99999:7::: daemon:*:12423:0:99999:7::: bin:*:12423:0:99999:7::: sys:*:12423:0:99999:7::: sync:*:12423:0:99999:7::: games:*:12423:0:99999:7::: man:*:12423:0:99999:7::: lp:*:12423:0:99999:7::: mail:*:12423:0:99999:7::: news:*:12423:0:99999:7::: uucp:*:12423:0:99999:7::: proxy:*:12423:0:99999:7::: postgres:*:12423:0:99999:7::: www-data:*:12423:0:99999:7::: backup:*:12423:0:99999:7::: operator:*:12423:0:99999:7::: list:*:12423:0:99999:7::: irc:*:12423:0:99999:7::: gnats:*:12423:0:99999:7::: nobody:*:12423:0:99999:7::: __EOF__ } create_etc_group () { check_target install -m 644 -o root -g root /dev/null "$TARGET/etc/group" cat > "$TARGET/etc/group" << __EOF__ root:x:0: daemon:x:1: bin:x:2: sys:x:3: adm:x:4: tty:x:5: disk:x:6: lp:x:7: mail:x:8: news:x:9: uucp:x:10: man:x:12: proxy:x:13: kmem:x:15: dialout:x:20: fax:x:21: voice:x:22: cdrom:x:24: floppy:x:25: tape:x:26: sudo:x:27: audio:x:29: dip:x:30: www-data:x:33: backup:x:34: operator:x:37: list:x:38: irc:x:39: src:x:40: gnats:x:41: shadow:x:42: utmp:x:43: video:x:44: sasl:x:45: staff:x:50: games:x:60: users:x:100: nogroup:x:65534: __EOF__ } make_root_login () { create_etc_passwd create_etc_group create_etc_shadow echo echo "Set root password" >&2 for i in $(seq 1 $RETRY_COUNT); do chroot "$TARGET" passwd root && break if [ "$i" == "$RETRY_COUNT" ]; then return 1 fi echo "Retry $i" >&2 done } make_hostname () { local hn1 local hn2 check_target echo for i in $(seq 1 $RETRY_COUNT); do echo -n "Enter hostname: " >&2 read hn1 echo -n "Retype hostname: " >&2 read hn2 [ "$hn1" == "$hn2" ] && break if [ "$i" == "$RETRY_COUNT" ]; then return 1 fi echo "Retry $i" >&2 done install -m 644 -o root -g root /dev/null "$TARGET/etc/hostname" echo "$hn1" > "$TARGET/etc/hostname" } make_nod () { check_target chroot "$TARGET" [ -e "$1" ] && return chroot "$TARGET" mknod "$1" "$2" "$3" "$4" } # Debootstrap doesn't give us quite enough devices to boot make_dev () { make_nod /dev/tty c 5 0 make_nod /dev/console c 5 1 make_nod /dev/tty1 c 4 1 make_nod /dev/tty1 c 4 2 make_nod /dev/tty1 c 4 3 make_nod /dev/tty1 c 4 4 make_nod /dev/tty5 c 4 5 make_nod /dev/tty5 c 4 6 make_nod /dev/ttyS0 c 4 64 make_nod /dev/ttyS1 c 4 65 } check_root check_ops "$@" check_target_and_error && CLEAN="$TARGET" debootstrap "$@" create_etc_fstab create_etc_hosts create_etc_inittab make_root_login make_hostname make_dev CLEAN=""