#! /bin/bash

#*********************************************************************
#
# fai-make-nfsroot -- create nfsroot directory and add additional packages
#
# This script is part of FAI (Fully Automatic Installation)
# (c) 2000-2022 by Thomas Lange, lange@cs.uni-koeln.de
# Universitaet zu Koeln
# (c) 2004      by Henning Glawe, glaweh@physik.fu-berlin.de
# Freie Universitaet Berlin
#
#*********************************************************************
# 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.
#
# A copy of the GNU General Public License is available as
# `/usr/share/common-licences/GPL' in the Debian GNU/Linux distribution
# or on the World Wide Web at http://www.gnu.org/copyleft/gpl.html.  You
# can also obtain it by writing to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
#*********************************************************************

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
usage() {

    cat <<-EOF
	Copyright (C) 1999-2022 Thomas Lange

	Usage: fai-make-nfsroot [OPTIONS]
	Create an NFSROOT for FAI.
	Read the man pages pages fai-make-nfsroot(8).
EOF
    exit 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
die() {

    local e=$1   # first parameter is the exit code
    shift

    echo "ERROR: $@"
    echo "Log file written to /var/log/fai/fai-make-nfsroot.log"
    exit $e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
check_nfsroot() {

    set +e
    # simple test, to see if important thing are available inside the nfsroot
    if [ ! -x $NFSROOT/usr/bin/dracut ]; then
        die 1 "dracut was not installed into the nfsroot."
    fi

    if [ ! -e $NFSROOT/sbin/init ]; then
        die 1 "sysvinit-core was not installed into the nfsroot."
    fi

    readlink $NFSROOT/sbin/init | grep -q systemd
    if [ $? -eq 0 ]; then
        die 1 "Do not use systemd inside the nfsroot."
    fi

    echo "FAI packages and related packages inside the nfsroot:"
    $ROOTCMD dpkg-query -W -f='${Package;-18} ${Version}\n' fai-client fai-nfsroot fai-setup-storage dracut-network dracut dracut-live dracut-squash 2>/dev/null

    # check if all important packages are installed
    n=$($ROOTCMD dpkg-query -l fai-client fai-nfsroot fai-setup-storage dracut-network dracut 2>/dev/null|grep -c -E ^ii)
    if [ $n -ne 5 ]; then
	echo "ERROR: Some essential packages are missing."
	bad_exit
    fi

    local files=$(ls $NFSROOT/boot/initrd* 2>/dev/null)
    [ -z "$files" ] && die 1 "No initrd installed."
    grep -E -q "^ERROR: |^E: Sub-process |^dpkg: error processing |^dpkg: dependency problems" /var/log/fai/fai-make-nfsroot.log && bad_exit
    return 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

PATH=/usr/local/bin:/usr/local/sbin:/bin:/sbin:/usr/bin:/usr/sbin

merror="properly"
exitcode=0
sshpreserve=0
adjust=0
generic=0
force=0
usexz=1
full=1

# option e currently does nothing
while getopts aghervc:C:B:fkKpPUzsN opt ; do
    case "$opt" in
        a) adjust=1 ;;
        g) generic=1 ;;
        z) usexz=0 ;;
        c) classes=$OPTARG
	   classes=${classes//,/ } ;;
        C) cfdir=$OPTARG ;;
        B) basetgz=$OPTARG
           if [ ! -r "$basetgz" ] ; then
               die 7 "Specified $basetgz can not be read."
           fi
           ;;
        v) verbose=1 ; v=-v ;;
        U) die 1 "Option -U is not supported any more." ;;
        r) die 1 "Option -r is not supported any more." ;;
        f) force=1 ;;
        k) kinstall=1 ;;
        K) kremove=1;;
        N) nonfree=NONFREE ;;
        h) usage ;;
        e) expert=1 ;; # a dummy option, that only fai-setup uses
        p) sshpreserve=1 ;;
        P) sshpreserve=2 ;;
        s) full=0 ;; # do only install a smaller list of packages
        ?) exit 5 ;; # error in option parsing
    esac
done

[ $(id -u) != "0" ] && die 9 "Run this program as root."

set -e
shopt -s nullglob

# use FAI_ETC_DIR from environment variable
if [ -n "$FAI_ETC_DIR" -a -z "$cfdir" ]; then
    echo "Using environment variable \$FAI_ETC_DIR."
fi
[ -z "$cfdir" ] && cfdir=${FAI_ETC_DIR:=/etc/fai}
cfdir=$(readlink -f $cfdir) # canonicalize path
[ ! -d "$cfdir" ] && die 6 "$cfdir is not a directory"

[ X$verbose = X1 ] && echo "Using configuration files from $cfdir"
. $cfdir/fai.conf
: ${FAI:=/var/lib/fai/config} # default value
: ${MNTPOINT:=/media/mirror}  # default value

# read config file for this tool
[ -f "$cfdir/nfsroot.conf" ] || die 8 "Can't read $cfdir/nfsroot.conf"
. $cfdir/nfsroot.conf

# IMO this may be removed, since all information should be included into sources.list
[ -z "$NFSROOT" ] && die 1 "\$NFSROOT is not set. Please check your settings in $cfdir/nfsroot.conf."
[ -z "$TFTPROOT" ] && die 1 "\$TFTPROOT is not set. Please check your settings in $cfdir/nfsroot.conf."
[ ! -d "$cfdir/apt" ] && die 1 "$cfdir/apt/ does not exists. Can't continue."

oldnfsroot=$NFSROOT
deldir=$NFSROOT

set +e
if [ -z "$ROOTCMD" ]; then
    # check if unshare can be used (e.g. not possible in some container environments)
    unshare --fork --kill-child --mount-proc chroot / ls >/dev/null 2>&1
    if [ $? -eq 0 ]; then
        ROOTCMD="unshare --fork --kill-child --mount-proc chroot $NFSROOT"
    else
        ROOTCMD="chroot $NFSROOT"
    fi
fi
set -e
export DEBIAN_FRONTEND=noninteractive

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
adjust_nfsroot() {

    # add install server specific data (like network parameters) into the nfsroot
    # a generic nfsroot must already be available
    trap '' EXIT
    add_etc_hosts_entries
    set_root_pw
    call_verbose setup_ssh
    exit 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
bad_exit() {

    merror="with errors"
    exitcode=1
    echo "An error occured during fai-make-nfsroot."
    echo "Please fix the error or try fai-make-nfsroot -v"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
call_verbose() {

    if [ X$verbose = X1 ]; then
        "$@"
        return $?
    else
        "$@" > /dev/null
        return $?
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setclasses() {

    local iarch distro c
    # Export all the information we have about the system
    iarch=$($ROOTCMD dpkg --print-architecture|tr /a-z/ /A-Z/)
    distro=$(. $NFSROOT/etc/os-release; echo ${ID} ${ID}_${VERSION_ID} | tr '[:lower:].' '[:upper:]_')

    # do we want to install the full list of packages?
    if [ $full = 1 ]; then
	c=FULL
    fi
    export classes="NFSROOT $c $iarch $distro $nonfree $classes"
    if [ X$verbose = X1 ] ; then
      echo Classes are set to $classes
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setup_ssh() {

    # nothing to do if no ssh is available in nfsroot
    [ -f $NFSROOT/usr/bin/ssh ] || return 0

    # enable root login
    sed -i -e '/PermitRootLogin/d' $NFSROOT/etc/ssh/sshd_config
    ainsl $NFSROOT/etc/ssh/sshd_config 'PermitRootLogin yes'

    if [ $sshpreserve -ge 1 ]; then
        tar -C $NFSROOT -xf $tmptar
        rm $tmptar
        return 0
    fi

    mkdir -p -m 700 $NFSROOT/root/.ssh
    if [ -n "$LOGUSER" ] ; then
        loguserhome=$(eval "cd ~$LOGUSER 2>/dev/null && pwd;true")
        [ -f $loguserhome/.ssh/known_hosts ] && cp $loguserhome/.ssh/known_hosts $NFSROOT/root/.ssh/known_hosts
        [ -d $loguserhome/.ssh ] && {
            [ -f $loguserhome/.ssh/id_ed25519 ] &&
               cp -p $loguserhome/.ssh/id_ed25519* $NFSROOT/root/.ssh/
            [ -f $loguserhome/.ssh/id_rsa ] &&
               cp -p $loguserhome/.ssh/id_rsa* $NFSROOT/root/.ssh/
        }
    fi

    if [ -f "$SSH_IDENTITY" ]; then
        install -m0644 $SSH_IDENTITY $NFSROOT/root/.ssh/authorized_keys
        echo You can log into install clients without password using $SSH_IDENTITY
    fi

# seting StrictHostKeyChecking to no inside the nfsroot would enable
# easy login to the install server even if the host key is not known

}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
set_root_pw() {

    [ $generic = 1 ] && return # do nothing here if we generate a generic nfsroot
    # set root pw inside the nfsroot
    $ROOTCMD usermod -p "$FAI_ROOTPW" root
    return # do not copy fai files at all
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
call_debootstrap() {

    local targetarch hostarch1 hostarch2 _debootstrap
    [ -z "$FAI_DEBOOTSTRAP" ] && die 4 "\$FAI_DEBOOTSTRAP not defined."

    # check if NFSROOT directory is mounted with bad options
    fs=$(df -P $NFSROOT | tail -1 | awk '{print $6}')
    if mount | grep "on $fs " |  awk '{print $6}' | grep -E -q "nosuid|nodev"; then
        die 1 "NFSROOT directory $NFSROOT is mounted using nosuid or nodev. Aborting"
    fi
    local dversion=$(dpkg-query -Wf '${Version}\n' debootstrap)
    echo "Creating base system using debootstrap version $dversion"

    # Check if we need cross architecture debootstrap
    targetarch=$(echo "$(expr "$FAI_DEBOOTSTRAP_OPTS" : '.*--arch[=[:space:]]\([^[:space:]]*\)' || true)" | tail -n 1)
    hostarch1=$(dpkg --print-architecture)
    hostarch2=$(dpkg --print-foreign-architectures)
    if [ -z "$hostarch2" ]; then
        hostarch2=$hostarch1
    fi

    _debootstrap=qemu-debootstrap
    if [ -z "$targetarch" ]; then
	_debootstrap=debootstrap
    else
	if [ $targetarch = $hostarch1 -o $targetarch = $hostarch2 ]; then
	_debootstrap=debootstrap
	fi
    fi
    if [ $_debootstrap = "qemu-debootstrap" ]; then
	if ! command -v $_debootstrap >&/dev/null; then
	    die 1 "qemu-debootstrap not found. Please install the package qemu-user-static."
	fi
    fi

    echo "Calling $_debootstrap $FAI_DEBOOTSTRAP_OPTS $1 $NFSROOT $2"
    LC_ALL=C call_verbose $_debootstrap $FAI_DEBOOTSTRAP_OPTS $1 $NFSROOT $2
    if [ $? -ne 0 ]; then
        echo "ERROR: $_debootstrap did not complete successfully."
        echo "This is mostly caused by a broken mirror."
        echo "Please check your mirror or use an official mirror."
        [ X$verbose = X1 ] || echo "Call fai-make-nfsroot -v for better debugging."
        exit 10
    fi

    if [ ! -f $NFSROOT/usr/bin/apt-get ]; then
        echo "No apt-get executable available inside the NFSROOT."
        echo "Maybe $_debootstrap did not finish successfully. Aborting."
        [ X$verbose = X1 ] || echo "Call fai-make-nfsroot -v for better debugging."
        exit 11
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
add_etc_hosts_entries() {

    # some default entries
    ainsl -as $NFSROOT/etc/hosts "127.0.0.1 localhost"
    ainsl     $NFSROOT/etc/hosts "# Following entries are specific to your environment"
    ainsl $v  $NFSROOT/etc/hosts "$NFSROOT_ETC_HOSTS"

    # add entries for all network devices
    local ips=$(ip -br ad show up| awk '/UP / {if ($3) print $3}' |sed -e 's#\/[0-9]\+##g')

    local line
    for eth in $ips; do
        line=$(getent hosts $eth || true)
        if [ -n "$line" ] ; then
            ainsl $v $NFSROOT/etc/hosts "$line"
        else
            echo "Warning: no hostname for $eth found, not adding to /etc/hosts."
        fi
    done

    if [ -f /etc/resolv.conf ]; then
        cp -Lp $v /etc/resolv.conf $NFSROOT/etc/resolv.conf-installserver
        cp -Lp $v /etc/resolv.conf $NFSROOT/etc/resolv.conf # this is needed during fai-make-nfsroot
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
create_base() {

    command -v debootstrap >&/dev/null || die 1 "Can't find debootstrap command. Aborting."
    call_debootstrap $FAI_DEBOOTSTRAP
    $ROOTCMD apt-get clean
    rm -f $NFSROOT/etc/resolv.conf $NFSROOT/etc/hostname $NFSROOT/etc/udev/rules.d/70-persistent-net.rules $NFSROOT/var/lib/dbus/machine-id
    > $NFSROOT/etc/machine-id
    if [ $usexz -eq 0 ]; then
        echo "Creating base.tar.zst"
    else
        echo "Creating base.tar.xz"
    fi
    tar --xattrs --acls --one-file-system -C $NFSROOT -cf $NFSROOT/var/tmp/base.tar --exclude var/tmp/base.tar --exclude 'var/lib/apt/lists/*_*' .
    if [ $usexz -eq 1 ]; then
        nice xz -q $NFSROOT/var/tmp/base.tar &
    else
        nice zstd --rm -q -7 -T4 $NFSROOT/var/tmp/base.tar &
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extract_base() {

    if cd $NFSROOT ; then
      printf "Extracting $basetgz: "
      case $basetgz in
          *tar.zst|*.tzst)
              tar --xattrs --acls --xattrs-include=* -C $NFSROOT --zstd -xpf "$basetgz" || die 1 "Error while extracting ${basetgz} in ${NFSROOT}."
              cp -p "$basetgz" $NFSROOT/var/tmp/base.tar.zst
              ;;

            *tar.xz|*.txz)
              tar --xattrs --acls --xattrs-include=* -C $NFSROOT -Jxpf "$basetgz" || die 1 "Error while extracting ${basetgz} in ${NFSROOT}."
              cp -p "$basetgz" $NFSROOT/var/tmp/base.tar.xz
              ;;
            *)
                die 14 "Unknow file name suffix"
          esac
      echo done
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
create_nfsroot() {

    local fslist

    mkdir -p $NFSROOT/$FAI
    cd $NFSROOT || die 1 "Can't cd to $NFSROOT"

    if [ -n "$basetgz" ] ; then
      extract_base
    else
      create_base
    fi
    touch .THIS_IS_THE_FAI_NFSROOT
    # save the list of all packages in the base.tar.zst
    $ROOTCMD dpkg --get-selections | awk '/install$/ {print $1}' > var/tmp/base-pkgs.lis

    if [ -n "$FAI_DEBMIRROR" ]; then
        [ X$verbose = X1 ] && echo "Mounting $FAI_DEBMIRROR to $NFSROOT/$MNTPOINT."
        mkdir -p $NFSROOT/$MNTPOINT
        mount -o ro,noatime $FAI_DEBMIRROR $NFSROOT/$MNTPOINT || \
                die 1 "Can't mount $FAI_DEBMIRROR to $NFSROOT/$MNTPOINT."
    fi

    # liloconfig, dump needs this file
    > etc/fstab

    # we need these option before installing the first package. So we
    # can't put this into fai-nfsroot /etc/apt/apt.conf.d/90fai
    cat >$NFSROOT/etc/apt/apt.conf.d/10fai <<EOF
APT::Install-Recommends no;
APT::Get::AllowUnauthenticated true;
Acquire::AllowInsecureRepositories "true";
Aptitude::CmdLine::Ignore-Trust-Violations yes;
Acquire::Languages none;
Acquire::Check-Valid-Until false;
EOF

    # currently we do not want to use systemd, but CD booting, also we
    # do not need all those filesystems inside the initrd
    mkdir $NFSROOT/etc/dracut.conf.d
    echo 'omit_dracutmodules+=" dracut-systemd systemd systemd-initrd systemd-networkd "' > $NFSROOT/etc/dracut.conf.d/12-no-systemd.conf
    echo 'add_dracutmodules+=" network-legacy "' >>  $NFSROOT/etc/dracut.conf.d/12-no-systemd.conf
    if [ $full = 1 ];then
	echo 'add_dracutmodules+=" livenet "' > $NFSROOT/etc/dracut.conf.d/13-add-cd-support.conf
	fslist="nfs lockd ext4"
    else
	echo 'add_dracutmodules+=" dmsquash-live "' > $NFSROOT/etc/dracut.conf.d/13-add-cd-support.conf
	fslist="ext4"
    fi
    echo 'hostonly="no"' > $NFSROOT/etc/dracut.conf.d/20-generic-image.conf
    cat <<EOF > $NFSROOT/etc/dracut.conf.d/01-omit.conf
omit_dracutmodules+=" btrfs crypt dash lvm resume usrmount modsign mdraid shutdown dracut-systemd systemd systemd-initrd systemd-networkd virtfs "
filesystems="$fslist"
EOF

    local fname=$(readlink -f $cfdir/apt/sources.list)
    if [ -d $fname ]; then
        fcopy -s $cfdir/apt -t $NFSROOT/etc/apt sources.list
    else
        # this copies sources.list into the nfsroot
        cp -aL $cfdir/apt $NFSROOT/etc
    fi

    add_etc_hosts_entries

    # use a proxy if variable is defined
    if [ -n "$APTPROXY" ]; then
	echo "Acquire::http::Proxy \"$APTPROXY\";" > $NFSROOT/etc/apt/apt.conf.d/02proxy
    fi

    [ X$verbose = X1 ] && echo "Upgrading $NFSROOT"
    LC_ALL=C call_verbose upgrade_nfsroot
    LC_ALL=C add_packages_nfsroot

    # patch udev rules for lvm
    if [ -f $NFSROOT/etc/udev/rules.d/69-lvm-metad.rules ] &&
           [ -f $NFSROOT/usr/share/fai/udev.patch ]; then
        $ROOTCMD patch --verbose -p0 < /usr/share/fai/udev.patch
    fi

    # remove file diversion, then create initrd
    rm $NFSROOT/etc/kernel/postinst.d/dracut
    $ROOTCMD dpkg-divert --rename --remove /etc/kernel/postinst.d/dracut
    $ROOTCMD dpkg-reconfigure dracut

    set_root_pw

    # set timezone in nfsroot
    cp -fH /etc/timezone  etc/timezone
    cp -a /etc/localtime etc/localtime
    ln -sf ../proc/self/mounts etc/mtab

    ln -s /usr/sbin/fai etc/init.d/rcS

    echo "AUTO -all" > etc/mdadm/mdadm.conf # do not activate RAID arrays
    # this second rm of the same file is needed!
    rm -f etc/udev/rules.d/70-persistent-net.rules
    # remove Ubuntu-specific rules to auto-start volume groups, which confuses
    # setup-storage
    rm -f lib/udev/rules.d/85-lvm2.rules
    # definition for loopback device
    mkdir -p etc/network
    echo "iface lo inet loopback" > etc/network/interfaces

    cat >> root/.profile <<-EOF
	PATH=/usr/local/sbin:/usr/local/bin:/usr/lib/fai:/bin:/sbin:/usr/bin:/usr/sbin:
	export PATH
	. /usr/lib/fai/subroutines
	set -a
	. /tmp/fai/variables.log 2>/dev/null
EOF

}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
upgrade_nfsroot() {

    local pkgs

    mkdir -p $NFSROOT/dev/pts
    mount -t proc   /proc  $NFSROOT/proc
    mount -t sysfs  /sys   $NFSROOT/sys
    mount -t devpts devpts $NFSROOT/dev/pts
    /usr/lib/fai/mkramdisk $NFSROOT/var/lib/dpkg $NFSROOT/var/cache
    mkdir $NFSROOT/etc/mdadm; touch $NFSROOT/etc/mdadm/mdadm.conf # stop mdadm from calling mkconf

    # add any 3rd party repository keys that you may need installed into the NFSROOT
    if [ -d $cfdir/apt/keys ]; then
        local f
        for f in $(find $cfdir/apt/keys -type f -name '*.gpg'); do
            cp $f $NFSROOT/etc/apt/trusted.gpg.d
        done
    fi

    if [ $full = 1 ];then
	pkgs=nfs-common
    fi

    $ROOTCMD apt-get update
    # disable generating the initrd
    fdivert /etc/kernel/postinst.d/dracut
    $ROOTCMD ln -s /bin/true /etc/kernel/postinst.d/dracut

    # fai-nfsroot must be sucessfully installed before anything else
    $ROOTCMD apt-get -yf --no-install-recommends install fai-nfsroot dracut-config-generic dracut-live dracut-network dracut-squash
    $ROOTCMD apt-get -y dist-upgrade
    # patch dracut. Do not fail if network is not available
    local fn=$(find $NFSROOT/usr/lib/dracut/modules.d/ -name net-genrules.sh)
    sed -i -e 's/exit 1/exit 0/' $fn
    fdivert /usr/sbin/update-grub
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
add_packages_nfsroot() {

    export FAI_ROOT=$NFSROOT
    local err

    setclasses
    > $NFSROOT/var/lib/dpkg/available
    install_packages -l -p$cfdir > $NFSROOT/var/tmp/packages.nfsroot
    echo "Adding additional packages to $NFSROOT:"
    cat $NFSROOT/var/tmp/packages.nfsroot
    set +e
    call_verbose install_packages $v -p$cfdir
    err=$?
    if [ $err -ne 0 ]; then
	die 12 "install_packages had exit code: $err"
    fi
    set -e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_dirs() {

    cd /
    [ -d $NFSROOT/proc/self ] && umount $NFSROOT/proc
    [ -d $NFSROOT/sys/class ] && umount $NFSROOT/sys
    [ -d $NFSROOT/proc/self ] && die 1 "/proc still mounted inside the nfsroot."
    umount $NFSROOT/dev/pts 2> /dev/null || true

    if mount | grep -q "on $NFSROOT/var/lib/dpkg type tmpfs" ; then
        /usr/lib/fai/mkramdisk -u $NFSROOT/var/lib/dpkg $NFSROOT/var/cache
    fi

    if [ -n "$FAI_DEBMIRROR" ]; then
        test -d $NFSROOT/$MNTPOINT && umount $NFSROOT/$MNTPOINT || true
	rmdir $NFSROOT/$MNTPOINT || true
    fi
    # show directories still mounted on nfsroot
    mount | grep " on $NFSROOT " || true
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
setup_tftp(){

    # tftp environment
    rm -f $NFSROOT/boot/*.bak
    mkdir -p $TFTPROOT/pxelinux.cfg
    chmod a+r $NFSROOT/boot/initrd.img-* || die 9 "No initrd was created. Check the package name of the linux-image package in /etc/fai/NFSROOT."
    cp -p $v $NFSROOT/boot/vmlinu?-* $NFSROOT/boot/initrd.img-* $TFTPROOT
    cp -u $v $NFSROOT/usr/lib/PXELINUX/lpxelinux.0 $TFTPROOT/pxelinux.0
    if [ -f $NFSROOT/usr/lib/syslinux/modules/bios/ldlinux.c32 ]; then
	cp -u $NFSROOT/usr/lib/syslinux/modules/bios/ldlinux.c32 $TFTPROOT
    fi
    if [ -f $NFSROOT/usr/lib/syslinux/modules/efi64/ldlinux.e64 ]; then
	cp -u $NFSROOT/usr/lib/syslinux/modules/efi64/ldlinux.e64 $TFTPROOT
    fi
    if [ -f $NFSROOT/usr/lib/SYSLINUX.EFI/efi64/syslinux.efi ]; then
	cp -u $NFSROOT/usr/lib/SYSLINUX.EFI/efi64/syslinux.efi $TFTPROOT
    fi
    if [ X$verbose = X1 ]; then
	echo "TFTP environment prepared. Enable DHCP and start the TFTP daemon on root $TFTPROOT."
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
fdivert() {

    local item
    for item in "$@"; do
        LC_ALL=C $ROOTCMD dpkg-divert --quiet --add --rename $item
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
run_hooks() {

    local file
    [ -z "$NFSROOT_HOOKS" ] && return 0
    [ -d "$NFSROOT_HOOKS" ] || return 0

    echo "Running hooks..."
    for file in $(run-parts --lsbsysinit --list "$NFSROOT_HOOKS"); do
        . $file $v
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -
write_variables() {

    local varfile=/var/log/fai/variables
    local fai_version=$($ROOTCMD dpkg-query -W -f='${Version}' fai-client)

    # remove old values from file
    [ -s $varfile ] && sed -i -e '/FAI_VERSION/d' -e '/NFSROOT/d' $varfile
    echo "FAI_VERSION=$fai_version" >> $varfile
    echo "NFSROOT=$NFSROOT" >> $varfile
}
# - - - - - - - - - - - - - - - - - - - - - - - - - -

# main routine

trap 'echo "Aborting";umount_dirs' EXIT
trap "bad_exit" ERR

[ $adjust = 1 ] && adjust_nfsroot

# remove all kernels from nfsroot
[ -n "$kremove" ] && {
    echo "Removing all kernels from NFSROOT."
    LC_ALL=C $ROOTCMD apt-get -qq purge linux-image\*
    exit
}

# just upgrade the nfsroot and install packages into it
[ -n "$kinstall" ] && {
    trap "true" EXIT
    echo "Upgrading nfsroot and installing new packages into the nfsroot."
    $ROOTCMD apt-get update
    $ROOTCMD apt-get -y dist-upgrade
    LC_ALL=C add_packages_nfsroot
    setup_tftp
    run_hooks
    umount_dirs
    trap "true" EXIT
    echo "fai-make-nfsroot finished $merror."
    exit $exitcode
}

# repeat message, so it will appear in the log file
rm -f  /var/log/fai/fai-make-nfsroot.log
[ X$verbose = X1 ] && echo "Using configuration files from $cfdir" > /var/log/fai/fai-make-nfsroot.log

{
if [ -d $NFSROOT ] && [ "$force" -ne 1 ] ; then
    echo "-----------------------------------------------------------------"
    echo "Error: $NFSROOT exists already." >&2
    echo "Neither force nor update option present, exiting." >&2
    echo "-----------------------------------------------------------------"
    echo "NOTE: Use -f option to force overwriting an existing nfsroot."
    echo "      Use -k option to update/install packages defined in NFSROOT config."
    exit 1
fi

echo "Creating FAI nfsroot in $NFSROOT"

if [ $sshpreserve -ge 1 ]; then
    [ -d $NFSROOT/root/.ssh ] || echo "Cannot preserve non-existing $NFSROOT/root/.ssh."
    tmptar=$(mktemp) || die 12 "Cannot create tmp file"
    pdirs="root/.ssh"
    if [ $sshpreserve -eq 2 ]; then
	pdirs="root/.ssh etc/ssh/ssh_host_*"
    fi
    export pdirs
    [ X$verbose = X1 ] && echo "Preserving $pdirs from inside the nfsroot."
    (
	cd $NFSROOT || exit # needed for * in $pdirs to work
	tar -C $NFSROOT -cf $tmptar $pdirs
    )
    unset pdirs
fi

if [ -d $NFSROOT/proc ]; then
    umount $NFSROOT/dev/pts >&/dev/null || true
    [ -L $NFSROOT/proc/self ] && umount $NFSROOT/proc || true
    [ -L $NFSROOT/proc/self ] && die 1 "/proc is still mounted inside the nfsroot."
    umount $NFSROOT/$MNTPOINT  2>/dev/null || true # it's safer to try to umount
    # remove old nfsroot using a background process
    rm -rf $deldir/../.will-now-be-deleted
    mv $deldir $deldir/../.will-now-be-deleted
    if [ $? -eq 1 ]; then
        rm -rf $deldir
    else
        nice rm -rf $deldir/../.will-now-be-deleted &
    fi
fi

create_nfsroot
setup_tftp
call_verbose setup_ssh
run_hooks
check_nfsroot
write_variables

if [ $generic = 1 ]; then
    # remove fai.conf which comes from package fai-client
    rm -f $NFSROOT/etc/hosts $NFSROOT/etc/resolv.conf* $NFSROOT/etc/fai/fai.conf $NFSROOT/var/lib/apt/lists/*_*
    ainsl -as $NFSROOT/etc/hosts "127.0.0.1 localhost"
fi

umount_dirs

# Wait for background jobs to finish
BGJOBS=$(jobs -p)
if [ -n "$BGJOBS" ]; then
    echo "Waiting for background jobs to finish"
    jobs
    for job in $BGJOBS; do
        wait $job
    done
fi

echo "fai-make-nfsroot finished $merror."
exit $exitcode
} |& tee -a /var/log/fai/fai-make-nfsroot.log
RC=${PIPESTATUS[0]}
umount_dirs
trap "true" EXIT
if [ $generic = 0 ]; then
    cp -p /var/log/fai/fai-make-nfsroot.log $NFSROOT/var/tmp
    msg="and $NFSROOT/var/tmp"
fi
echo "Log file written to /var/log/fai/fai-make-nfsroot.log $msg"
exit ${RC}