Re: Progressbar for extracting Basefiles

Karsten Nordsiek <[email protected]>
Newsgroups gmane.linux.debian.fai
Message-ID <[email protected]>
Please find included the both files I have changed.

Hint: you need to install pv in the nfsroot

Am 18.01.23 um 15:19 schrieb Karsten Nordsiek:
> Yes that's working.
>
> I have added the -f Option
> Now it works as fine as it should
>
> thx for the hint.
>
> Regards
>
>
> Karsten Nordsiek
>
>
> Am 18.01.23 um 14:34 sch
> rieb Thomas Lange:
>>>>>>> On Wed, 18 Jan 2023 12:28:26 +0100, Karsten Nordsiek 
>>>>>>> <[email protected]> said:
>>      >     -1                   Use only first tar file matching 
>> class name.
>>      >     -c class[class]      Define classes (space separated).
>> Hmmm, it's hard to see what you have changed. A diff or git diff would
>> be much better to understand.
>>
>> My first guess is to add -f to the pv call.
>>
>>    -f, --force              output even if standard error is not a 
>> terminal
>>
>> Inside FAI we redirect the output to a pipe which also does tee into a
>> file. Or you may try to force the output (does pv use stderr?) to
>> /dev/ttyN.
>>
ftar (text/plain, 5.2 KB)
#! /bin/bash

#*********************************************************************
#
# ftar -- extract tar files using FAI classes
#
# This script is part of FAI (Fully Automatic Installation)
# Copyright (C) 2001-2017 Thomas Lange, [email protected]
# Universitaet zu Koeln
#
#*********************************************************************
# 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
#*********************************************************************

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
die() {

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

    echo "ftar: $@" >&2 # print error message
    exit $e
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
extract() {

    local file=$1
    local catname=$2

    if [ $deletefiles -eq 1 ] ; then
      cd $target/$dir && rm -f  -- .* * 2>/dev/null
      deletefiles=0
    fi

    if [ $removedir -eq 1 ]; then
        cd $target/$dir || die 4 "ERROR: cd to $target/$dir failed. Aborting."
        [ $PWD = "/" ] && die 3 "WARNING: Will not do recursive removal of directory /"
        rm -rf -- .* * 2>/dev/null
        removedir=0
    fi

    if [ $progress -eq 1 ]; then
        
	echo "ftar: extracting $file to $target/$dir" | tr -s '/'
        $catname $file | pv -f -s $(du -sb $file | awk '{print $1}') | tar $xattrs --numeric-owner -C $target/$dir $vflag -xf -
    else
    	echo "ftar: extracting $file to $target/$dir" | tr -s '/'
        $catname $file | tar $xattrs --numeric-owner -C $target/$dir $vflag -xf -
        tardone=1
        # if option -1 is set, only one class will be used
        [ $single -eq 1 ] && exit 0
    fi

}

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

    cat <<EOF
ftar, extract tar files using classes.

   Copyright (C) 2001-2017 by Thomas Lange

Usage: ftar [OPTION] ... SOURCE

   -1                   Use only first tar file matching class name.
   -c class[class]      Define classes (space separated).
   -d                   Delete all files in target before extracting.
   -D                   Create debug output.
   -h                   Show summary of options.
   -p 			Show progress indicator
   -r                   Recursively remove files in target before extracting.
   -s source_dir        Look for source files relative to source_dir.
   -t target_dir        Extract files relativ to target_dir.
   -v                   Be verbose. Not yet used.

EOF
    exit 0
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

source=$FAI/files
target=$FAI_ROOT
deletefiles=0
removedir=0
tardone=0
single=0
ignore=0
progress=0

if [ -n "$classes" ]; then
    [ -f $LOGDIR/FAI_CLASSES ] && classes=$(< $LOGDIR/FAI_CLASSES)
fi

echo $@

while getopts 1hDdrvs:t:c:i:p opt ; do
        case "$opt" in
        d) deletefiles=1 ;;
        D) debug=1 ;;
        i) ignore=1 ;;
        r) removedir=1 ;;
#        v) verbose=1 ;;
        1) single=1 ;;
        s) source=$OPTARG ;;
        t) target=$OPTARG ;;
        c) classes=$OPTARG ;;
        p) progress=1 ;;
        h) usage ;;
        esac
done
shift $((OPTIND - 1))

[ "$1" ] || usage

# detect target fstype
targetfstype=$(awk -vt="$target" '{if($2==t){print $3}}' /proc/mounts)
if [ "$targetfstype" != "nfs" ]; then
    xattrs="--xattrs --xattrs-include=*.* --selinux --acl"
else
    xattrs=
fi

# last class has highest priority
# reverse order of classes
for class in $classes; do
    revclasses="$class $revclasses"
done

[ "$debug" ] && vflag="-v"
[ "$debug" ] && echo "ftar: classes : $revclasses"
[ -z "$source" ] && die 1 "Source directory undefined."
[ -z "$target" ] && die 1 "Target directory undefined."

# currently only one directory is used
dir=$1
fpath=$source/$dir
[ -d $fpath ] || die 1 "No directory $fpath"

for c in $revclasses ; do
    # what if a directory exists which is equal to the hostname or a classname?
    [ -f $fpath/$c.tgz ]      && extract $fpath/$c.tgz zcat
    [ -f $fpath/$c.tar ]      && extract $fpath/$c.tar cat
    [ -f $fpath/$c.tar.gz ]   && extract $fpath/$c.tar.gz zcat
    [ -f $fpath/$c.tar.bz2 ]  && extract $fpath/$c.tar.bz2 bzcat
    [ -f $fpath/$c.tar.xz ]   && extract $fpath/$c.tar.xz xzcat
    [ -f $fpath/$c.txz ]      && extract $fpath/$c.txz xzcat
done

if [ $tardone -eq 0 ]; then
    if [ $ignore -eq 1 ]; then
        echo "ftar: No matching class found in $fpath"
        exit 0
    else
        die 1 "No matching class found in $fpath"
    fi
fi

exit 0
subroutines (text/plain, 39.3 KB)
#! /bin/bash

#*********************************************************************
#
# subroutines -- useful subroutines for FAI
#
# This script is part of FAI (Fully Automatic Installation)
# (c) 2000-2021 by Thomas Lange, [email protected]
# Universitaet zu Koeln
# (c) 2001-2005 by Henning Glawe, [email protected]
# 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
#*********************************************************************

# source this file, then you have these function available in the shell

# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
die() {

    # echo comment and exit installation
    [ -f $LOGDIR/skip.savelog ] || call_hook savelog
    [ -f $LOGDIR/skip.savelog ] || task_savelog
    echo "$@"
    if [ $do_init_tasks -eq 1 ] ; then
        exec bash -i
    else
        exit 99
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
defnop() {

    # define given list of subroutine names as dummy function;
    # this will fake unknown commands

    local name
    for name in "$@";do
        eval "$name () { :;}"
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:      none
# Required-Var:      $classes
# Short-Description: test if one or multiple classes are defined
### END SUBROUTINE INFO

ifclass() {

    if [ $# -eq 1 ]; then
        _ifclass $1
        return $?
    fi

    case $1 in
        -a) shift ; _ifclass_and $* ; return $? ;;
        -o) shift ; _ifclass_or $*  ; return $? ;;
    esac
}

_ifclass() {

    # check one single class
    [ "${debug:-}" ] && echo "Test if class $1 is in ${classes:-}" >&2
    # test if a class is defined
    local ret

    if [[ "${classes:-}" =~ (^|[[:space:]]+)$1($|[[:space:]]+) ]]; then
        ret=0
    else
        ret=1
    fi
    [ "${debug:-}" ] && echo "ifclass returns $ret" >&2
    return $ret
}

_ifclass_and() {

    # check if all classes are defined (logical AND)
    local cl

    for cl in $*; do
        ifclass $cl || return 1
    done
    return 0
}

_ifclass_or() {

    # check if one of the classes is defined (logical OR)
    local cl

    for cl in $*; do
        ifclass $cl && return 0
    done
    return 1
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
rwmount() {

    # remount partition read/write, for interactive use only
    mount -o rw,remount $1
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
save_dmesg() {

    [ $do_init_tasks -eq 0 ] && return
    if [ -x /usr/sbin/logtail ] ; then
      logtail -f /var/log/kern.log -o /var/lib/fai/kern.log.offset >> $LOGDIR/dmesg.log
    else
      dmesg > $LOGDIR/dmesg.log
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_csspace() {

    # umount config space if accessed via nfs
    if [[ $FAI_CONFIG_SRC =~ ^nfs:// ]]; then
        mountpoint -q $FAI && umount $FAI
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_target() {

    if [ "$target" != '/' ]; then
	# do not umount during softupdate
	umount $FAI_ROOT/proc $FAI_ROOT/sys/firmware/efi/efivars $FAI_ROOT/sys $FAI_ROOT/dev/pts $FAI_ROOT/dev 2>/dev/null
	for dir in $(mount | grep $target | grep -E -v "media/mirror|tmpfs"| awk '{print $3}' | sort -r); do
            mountpoint -q $dir && umount $dir
	done
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
cleanup_devicemapper() {

    local vgroup v
    # remove device mapper devices
    grep -q 'Executing: vgcreate' $LOGDIR/format.log 2>/dev/null
    if [ $? -eq 0 ]; then

	# write which vg should be removed, PPID is the fai-diskimage process
	> /var/run/fai/vgremove.$PPID
	vgroup=$(awk '/Executing: vgcreate/ {print $3}' $LOGDIR/format.log)
	for v in $vgroup; do
	    vgchange -an $v
	    echo vgremove -f $v >> /var/run/fai/vgremove.$PPID
	done
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
mk_zerofree_list() {

    # make a list of devices for zerofree which have an ext2/3/4 file  system
    local source fstype mpoint v

    if [ X$verbose = X1 ]; then
	v=-v
    fi
    while read -r source fstype mpoint ; do

	# skip non ext2/3/4 file systems
	case $fstype in
            ext*) : ;;
	    *) continue ;;
	esac

	if [[ $mpoint =~ $target ]]; then
	    echo "zerofree $v $source" >> /var/run/fai/zerofree.$PPID
	fi

    done < <(df --output=source,fstype,target)
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
stop_fai_installation() {

    # this subroutine should directly stop the installation process
    sendmon "TASKEND $taskname $task_error"
    echo "Error in task $taskname. Code: $task_error" >&2
    echo "Traceback: $task_error_func" >&2
    die "FATAL ERROR. Installation stopped."
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:      $task_error
# Required-Var:      $1 $2 $task_error
# Short-Description: save the maximum error code,
# Short-Description: $1 is the error that will be saved unless $2 is zero
# Short-Description: if $3 is set to 1 only $task_error is set but the
# Short-Description: installation is not stopped
### END SUBROUTINE INFO

task_error() {

    local current
    [ X$2 = X0 ] && return
    task_error_func=${FUNCNAME[*]}

    # save max error for current task
    task_local_error=$1
    current=$(< $LOGDIR/task_local_error)
    if [ $task_local_error -gt $current ]; then
	echo $task_local_error > $LOGDIR/task_local_error
    fi

    # save global max task error
    task_error=$(< $LOGDIR/task_error)
    if [ $task_local_error -gt $task_error ]; then
     task_error=$task_local_error
     echo $task_local_error > $LOGDIR/task_error
    fi
    if [ X$3 = X1 ]; then
	:
    else
	[ $task_error -gt $STOP_ON_ERROR ] && stop_fai_installation
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:      $task_error
# Required-Var:      $LOGDIR
# Short-Description: call a certain task
### END SUBROUTINE INFO

declare -A taskduration
export duration=0
task() {

    # hooks are called before a task is called
    # if a task is skipped, also its hooks are skipped
    # a hook can set the flag, so the accociated task is skipped

    local taskname=$1
    shift
    local task_local_error=0 # the error code set by every task

    echo 0 > $LOGDIR/task_local_error
    [ -f $LOGDIR/skip.$taskname ] || call_hook $taskname "$@"

    if [ -f $LOGDIR/skip.$taskname ]; then
        # skip task
        rm $LOGDIR/skip.$taskname # TODO: remove skip files at the very end
        [ X$verbose = X1 ] && echo "Skipping task_$taskname"
        sendmon "TASKSKIP $taskname"
    else
        echo "Calling task_$taskname"
        sendmon "TASKBEGIN $taskname"
        task_error_func=''
        taskduration[$taskname]=$SECONDS
        task_$taskname "$@"
        [ $duration -eq 1 ] && echo "Duration of task $taskname: " $((SECONDS-${taskduration[$taskname]}))"s"
	task_local_error=$(< $LOGDIR/task_local_error)
        sendmon "TASKEND $taskname $task_local_error"
        if [ "$task_local_error" -ne 0 ] ; then
          echo "Exit code task_$taskname: $task_local_error" >&2
        fi
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:
# Required-Var:      $classes $debug
# Short-Description: call a hook, hook.sh can define additional variables
### END SUBROUTINE INFO

call_hook() {

    local hook=$1
    shift

    local cl dflag hfile
    [ "$debug" ] && dflag="-d"

    for cl in $classes; do
        hfile=$FAI/hooks/$hook.$cl
        if [ -f $hfile -a ! -x $hfile ]; then
            echo "WARNING: Skipping $hfile because it's not executable." >&2
            continue
        fi
        if [ -f $hfile.sh -a ! -x $hfile.sh ]; then
            echo "WARNING: Skipping $hfile.sh because it's not executable." >&2
            continue
        fi
        if [ -f $hfile.source ]; then
            echo "WARNING: The suffix .source is deprecated. Use .sh instead." >&2
            # continue
        fi
        if [ -x $hfile.sh ]; then
            echo "Source hook: $hook.$cl.sh"
            sendmon "HOOK $hook.$cl.sh"
            # source this hook
            . $hfile.sh $dflag "$@"
            check_status $hook.$cl.sh $?
        fi
        if [ -x $hfile ]; then
            echo "Calling hook: $hook.$cl"
            sendmon "HOOK $hook.$cl"
            # execute the hook
            $hfile $dflag "$@"
            check_status $hook.$cl $?
        fi
        # deprecated
	if [ -x $hfile.source ]; then
            echo "Source hook: $hook.$cl.source"
            sendmon "HOOK $hook.$cl.source"
            # source this hook
            . $hfile.source $dflag "$@"
            check_status $hook.$cl.source $?
        fi
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
skiptask() {

    # mark all given tasks, so they will be skipped
    local task

    for task in "$@"; do
        echo > $LOGDIR/skip.$task # create file with size != 0
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
define_fai_flags() {

    local flag
    # FAI_FLAGS are comma separated, define all flags
    FAI_FLAGS=${FAI_FLAGS//,/ }
    echo "FAI_FLAGS: $FAI_FLAGS"
    for flag in $FAI_FLAGS; do
        # define this flag as 1
        eval "flag_$flag=1"
    done
    [ "$flag_verbose" ] && verbose=1 # for backward compability
    [ "$flag_debug" ]   && debug=1   # for backward compability
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $fai_rundate
# Requires-Var:    $DOMAIN $do_init_tasks
# Suggests-Var:    $flag_createvt $flag_sshd
# Short-Description: <task desc.>
### END SUBROUTINE INFO

task_setup() {

    # source user specific subroutines
    [ -f $FAI/hooks/subroutines ] && . $FAI/hooks/subroutines

    define_fai_flags

    # this may be moved to an external script
    if [ $do_init_tasks -eq 1 ] ; then
        # set the system time and date using rdate or/and ntpdate
        [ "$TIMESRVS_1" ] && rdate $TIMESRVS_1
        [ "$NTPSRVS_1" ]  && ntpdate -b $NTPSRVS
        [ "$flag_createvt" ] && {
            # create two virtual terminals; acces via alt-F2 and alt-F3
            echo "Press ctrl-c to interrupt FAI and to get a shell"
            openvt -c2 /bin/bash ; openvt -c3 /bin/bash
            echo "The log files are saved in /tmp/fai" > /dev/tty2
            echo "The log files are saved in /tmp/fai" > /dev/tty3
            trap 'echo "You can reboot with faireboot"; \
	          echo "The log files are saved in /tmp/fai"; \
		  cd /tmp/fai;bash' INT QUIT
        }

        # start secure shell daemon for remote access
        if [ "$flag_sshd" -a -x /usr/sbin/sshd ]; then
            pgrep -x sshd >/dev/null || /usr/sbin/sshd
        fi

        udevadm trigger
    fi
    unset flag_createvt flag_sshd

    # now you have enough time to make changes to the config space
    # only for debugging
    if [ -n "$flag_wait" ]; then
        echo "Sleeping. Now you may change the config space in $FAI."
        echo "Continue after killall sleep."
        sleep 50000
    fi

    # when did FAI start, using localtime
    : ${fai_rundate:=$(date +'%Y%m%d_%H%M%S')}
    if [ $do_init_tasks -eq 1 ]; then
        echo "Starting FAI execution - $fai_rundate"
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    none
# Requires-Var:    $FAI_ACTION
# Short-Description: call task depending on $FAI_ACTION
### END SUBROUTINE INFO

task_action() {

    if [ -z "$FAI_ACTION" ]; then
        echo "No action in \$FAI_ACTION defined."
        sendmon "TASKERROR action 21"
        task_faiend
        exit
    fi

    echo "FAI_ACTION: $FAI_ACTION"
    case $FAI_ACTION in
        install)
            if [ $target = "/" ]; then
                echo "Cowardly refusing to run a FAI installation on a running system."
                return
            fi
            echo Performing FAI installation. All data may be overwritten!
	    if [ $do_init_tasks -eq 1 -a X$flag_menu = X ] ; then
		echo -ne "\a"; sleep 1
		echo -ne "\a"; sleep 1
		echo  -e "\a"; sleep 5
	    fi
            task install
            task faiend
            ;;
        dirinstall)
            task dirinstall
            task faiend
            ;;
        softupdate)
            task softupdate
            task faiend
            ;;
        sysinfo)
            task sysinfo
            task_faiend
            die Now you have a shell.
            ;;
        inventory)
            task inventory
            task_faiend
            die Now you have a shell.
            ;;
        *)
            if [ -f $FAI/hooks/$FAI_ACTION ]; then
                echo "Calling user defined action: $FAI_ACTION"
                $FAI/hooks/$FAI_ACTION
		task_faiend
            else
                echo "ERROR: User defined action $FAI/hooks/$FAI_ACTION not found." >&2
                sendmon "TASKERROR action 22"
                task_faiend
            fi
            ;;
    esac
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $classes $cfclasses
# Requires-Var:    $LOGDIR
# Suggests-Var:    $renewclass
# Short-Description: define FAI classes and store them in several shell variables
### END SUBROUTINE INFO

task_defclass() {

    if [ ! -d $FAI/class ]; then
        sendmon "TASKERROR defclass 21"
        echo "Subdirectory $FAI/class missing in config space. Following subdirectories are found:"
        find $FAI -maxdepth 1 -type d -printf "%p\n"
        die "Aborting."
    fi

    # new script for defining classes; variables imported: $LOGDIR, $verbose, $debug
    if [ $renewclass -eq 1 ]; then
        # reevaluate new list of classes
        fai-class -T $FAI/class $LOGDIR/FAI_CLASSES
	# check task error again
	local lerr=$(< $LOGDIR/task_local_error)
	task_error $lerr

        classes=$(< $LOGDIR/FAI_CLASSES)
    elif [ -n "$cmdlineclasses" ]; then
        classes=$cmdlineclasses
    elif [ ! -f /var/lib/fai/FAI_CLASSES ]; then
        # use classes defined at installation time
        die "Try to read classes from /var/lib/fai/FAI_CLASSES. Failed. Aborting."
    else
        classes=$(< /var/lib/fai/FAI_CLASSES)
    fi
    echo "List of all classes: " ${classes:-}

    # define classes as: a.b.c.d for cfengine -D
    # this doesn't work without echo
    cfclasses=$(echo ${classes:-})
    cfclasses=${cfclasses// /.}
    [ "${debug:-}" ] && echo "cfclasses: $cfclasses"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_defvar() {

    local showvar=1 # TODO: new FAI_FLAG or always set when verbose is used
    [ "$showvar" ] && set -x
    . $1 </dev/null
    [ "$showvar" ] && set +x
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_defvar() {

    local svar=$LOGDIR/showvar.log
    local odir=$(pwd)
    cd $FAI/class
    for class in ${classes:-} ; do
        if [ -f $class.var -a -r $class.var ]; then
            [ X$verbose = X1 ] && echo "Executing $class.var"
            # show only lines with ++, we cannot use a pipe, since it would call
            # _devfar in a subprocess. Then, variables are not defined
            _defvar $class.var > $svar 2>&1
            grep -P '^\+\+ \w+=' $svar| sed -e 's/\(.*PW\)=.*$/\1=XXXXXXXXXXXXX/'
            rm $svar
        fi
    done

    # /fai/class/* scripts or hooks can write variable definitions
    # to additonal.var. now source these definitions
    if [ -f $LOGDIR/additional.var -a -r $LOGDIR/additional.var ]; then
        echo "Defining variables from additional.var"
        _defvar $LOGDIR/additional.var > $svar 2>&1
        grep ^++ $svar
        rm $svar
    fi
    unset class svar
    # now all variables are defined. Dump them to variables.log, so we can sources them if needed
    set | perl -ne 'print if /^\w\w+=/ and not /^(EUID|PPID|SHELLOPTS|UID|rootpw|ROOTPW|USERPW|HOME|PWD|BASHOPTS)|\(/' > $LOGDIR/variables.log
    # another approach is to use this. A slightly different format, but seems to be robust.
    # declare -x > $LOGDIR/variables.log
    cd $odir
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_mountdisks() {

    [ ! -f $LOGDIR/fstab ] && die "No $LOGDIR/fstab created."
    # mount swap space
    if [ $do_init_tasks -eq 1 ]; then
	local sd
	for sd in $SWAPLIST; do
            swapon -p1 $sd && [ X$verbose = X1 ] && echo "Enable swap device $sd"
	done
    fi
    mount2dir $FAI_ROOT $LOGDIR/fstab
    if [ "$?" -ne 0 ]; then
        sendmon "TASKERROR mountdisks 885"
        task_error 885
    fi
    if [ $do_init_tasks -eq 1 ] && ! mountpoint -q $target; then
        echo "$target is not a mount point. Check your disk_config file."
        sendmon "TASKERROR mountdisks 886"
        task_error 886
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_configure() {

    fai-do-scripts $FAI/scripts
    task_error 420 $?
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_tests() {

    if [ ! -d $FAI/tests ]; then
	return
    fi
    fai-do-scripts $FAI/tests  # always returns 0 atm
    # check if any test failed
    if [ -f $LOGDIR/test.log ]; then
        if grep -q "FAILED with " $LOGDIR/test.log; then
            sendmon "TASKERROR tests 312"
            task_error 312
            return 1
        fi
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_savelog() {

    mkdir -p $FAI_ROOT/var/{lib,log}/fai
    fai-savelog -l
    [ -f $LOGDIR/FAI_CLASSES ] && cp -pu $LOGDIR/FAI_CLASSES $FAI_ROOT/var/lib/fai
    [ -f $LOGDIR/disk_var.sh ] && cp -pu $LOGDIR/disk_var.sh $FAI_ROOT/var/lib/fai
    fai-savelog -r
    task_error 410 $?
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Description: Always called as last FAI task
### END SUBROUTINE INFO
task_faiend() {

    local dir cdromdevice
    : ${flag_reboot:=0}
    : ${flag_halt:=0}

    # reboot/halt without prompting if FAI_FLAG reboot or halt is set
    # wait for keypress if neither flag reboot nor halt is set
    if [ $do_init_tasks -eq 1 -a "$flag_reboot" -eq 0 -a "$flag_halt" -eq 0 ]; then
        echo "Press <RETURN> to reboot (do not remove your removable medium yet)."
        read
    fi

    sendmon "TASKEND faiend 0"

    cd /
    mk_zerofree_list
    umount_target
    cleanup_devicemapper
    if [ $do_init_tasks -eq 0 ]; then
	echo "Log files are saved in $LOGDIR"
	return 0
    fi
    killall -q sshd systemd-udevd rsyslogd
    umount $FAI_ROOT/proc $FAI_ROOT/sys/firmware/efi/efivars $FAI_ROOT/sys $FAI_ROOT/dev/pts 2>/dev/null
    umount -arf 2>/dev/null

    echo "Rebooting $HOSTNAME now"
    sendmon "TASKEND reboot 0"
    # reboot or halt?
    if [ "$flag_halt" -gt "0" ]; then
        exec halt -dfp
    else
        exec reboot -df
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_install() {

    echo $$ > $stamp

    save_dmesg

    task partition
    task mountdisks
    task extrbase
    task debconf
    task repository
    task updatebase
    task instsoft
    task configure
    task tests
    task finish
    task chboot

    rm -f $stamp
    save_dmesg    # save again, because new messages could be created
    task savelog

    if [ -f $stamp ]; then
        echo "Error while executing commands in subshell." >&2
        echo -n "$stamp was not removed. PID of running process: "
        cat $stamp
        sendmon "TASKERROR install 21"
        die "Please look at the log files in $LOGDIR for errors." >&2
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_dirinstall() {

    mkdir -p $FAI_ROOT
    FAI_ROOT=$(cd $FAI_ROOT;pwd)
    xstamp=${FAI_ROOT//\//=}
    stamp=/var/run/fai/dirinstall-$xstamp
    unset xstamp
    clean_exit() {
        rm -f $stamp
        [ -z "$FAI_ROOT" ] && return
        # sometimes mountpoint may be mounted twice, so try to umount them twice
        mountpoint -q $FAI_ROOT/proc && umount $FAI_ROOT/proc
        mountpoint -q $FAI_ROOT/sys  && umount $FAI_ROOT/sys
        mountpoint -q $FAI_ROOT/proc && umount $FAI_ROOT/proc
        mountpoint -q $FAI_ROOT/sys  && umount $FAI_ROOT/sys
        mountpoint -q $FAI_ROOT/dev/pts && umount $FAI_ROOT/dev/pts
        mountpoint -q $FAI_ROOT/run/udev && umount $FAI_ROOT/run/udev
        # sometimes umount $FAI_ROOT/dev fails, because a process is
        # still running in the background and accesses /dev
        # this occured sometimes when using dirinst and a long package
        # list if dhelp.postinst is starting an index process in the
        # bg which did not finished until the installation was finished.
        mountpoint -q $FAI_ROOT/dev && umount $FAI_ROOT/dev
        mkramdisk -au 2>/dev/null
    }
    trap 'clean_exit' INT QUIT EXIT



    [ -f "$stamp" ] && {
       echo -n "fai dirinstall into directory $FAI_ROOT already running or was aborted before. PID: "
       cat $stamp
       echo "You may remove $stamp and try again."
       exit 1
    }

    echo $$ > $stamp
    echo "Installing into directory $FAI_ROOT"
    task extrbase
    [ -f $target/etc/fstab ] || touch $target/etc/fstab
    task debconf
    task repository
    task updatebase
    task instsoft
    task configure
    task tests
    task finish
    clean_exit

    rm -f $stamp
    unset LOGUSER # so logfile are not saved to remote
    task savelog

    if [ -f $stamp ]; then
        echo "Error while executing commands in subshell." >&2
        echo -n "$stamp was not removed. PID of running process: "
        cat $stamp
        sendmon "TASKERROR install 21"
        die "Please look at the log files in $LOGDIR for errors." >&2
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_softupdate() {

    echo Performing FAI system update. All data may be overwritten!
    stamp=/var/run/fai/fai_softupdate_is_running
    [ -f "$stamp" ] && die "Lock file $stamp found. Another fai softupdate is already running. Aborting."
    echo $$ > $stamp
    trap "rm -f $stamp" INT QUIT EXIT

    # the following copy operation is required to make $LOGDIR a reliable source
    # for disk_var.sh
    # use the last disk_var during update if available
    [ -f /var/lib/fai/disk_var.sh ] && cp -p /var/lib/fai/disk_var.sh $LOGDIR

    save_dmesg

    task debconf
    task repository
    task updatebase
    task instsoft
    task configure
    task tests
    task finish

    rm -f $stamp
    # save again, because new messages could be created
    save_dmesg
    task savelog
    umount_csspace

    if [ -f $stamp ]; then
        echo "Error while executing commands in subshell." >&2
        echo -n "$stamp was not removed. PID of running process: "
        cat $stamp
        sendmon "TASKERROR softupdate 21"
        die "Please look at the log files in $LOGDIR for errors." >&2
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

catnc() {
    # cat but no comment lines
    grep -E -v "^#" $@
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $disklist
# Requires-Var:
# Short-Description: create list of available disks
### END SUBROUTINE INFO

set_disk_info() {

    # the variable holds a space separated list of devices
    disklist=$(fai-disk-info | sort | tr '\n' ' ')
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
eval_cmdline() {

    # parse kernel parameters and define variables
    local word cmdline

    echo "Kernel currently running: "
    uname -rsmo
    cmdline="$(</proc/cmdline)"
    echo "Kernel parameters: $cmdline"
    for word in $cmdline; do
	if echo "$word" | grep -E -q '^[a-zA-Z0-9_]+=' ; then
            eval "export $word"
	fi
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
read_fai_monitor_vars() {

    # read variables which are received from the fai-monitor
    if [ ! -s /run/initramfs/fai-variables ]; then
	return
    fi

    eval $(grep FAI_CONFIG_SRC /run/initramfs/fai-variables)
    eval $(grep FAI_FLAGS /run/initramfs/fai-variables)
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $faimond $sendid $SERVER $monserver
# Requires-Var:    $LOGDIR $FAI
# Suggests-Var:    $monserver $FAI_SENDID $FAI_MONITOR_PORT
# Short-Description: <task desc.>
### END SUBROUTINE INFO

task_confdir() {

    if [ $do_init_tasks -eq 1 ] ; then

	read_fai_monitor_vars
        eval_cmdline

        get-boot-info
        echo "Reading $LOGDIR/boot.log"
        . $LOGDIR/boot.log
        unset T170 T171 T172 ROOT_PATH BOOTFILE

        printk=${printk:-6}
        echo $printk > /proc/sys/kernel/printk
        create_resolv_conf
        if [ -x /usr/sbin/rsyslogd ]; then
            /usr/sbin/rsyslogd
        fi
    fi
    define_fai_flags

    if [ -z "$SERVER" ]; then
        # since SERVER is not set (by DHCP) we extract it from FAI_CONFIG_SRC
        # extract server name from FAI_CONFIG_SRC and delete user@ from string
        SERVER=$(expr match "$FAI_CONFIG_SRC" '.*://\([^/]*\)/.*' | sed -e 's/.*@//')
        if [ -n "$SERVER" ]; then
          echo "Setting SERVER=$SERVER. Value extracted from FAI_CONFIG_SRC."
        else
          SERVER=$(awk '{if($2 == "/live/image") print $1;}' /proc/mounts | cut -d ':' -f 1)
          if [ -n "$SERVER" ]; then
            echo "Setting SERVER=$SERVER. Value extracted from NFSROOT."
          else
            echo "NO SERVER FOUND FOR FAI_CONFIG_SRC"
          fi
        fi
    fi

    # check if monitor server is available
    : ${monserver:=$SERVER}
    : ${FAI_MONITOR_PORT:=4711}

    if [ -z "$monserver" ]; then
        echo "No monitor daemon defined."
        faimond=0
    else
        faimond=1
	if [ -n "$NIC1" ]; then
	    MAC=$(< /sys/class/net/$NIC1/address)
            PXE="01-"${MAC//:/-}
	fi

        : ${FAI_SENDID:=host} # set default if undefined
        case "$FAI_SENDID" in
            host) sendid=$HOSTNAME ;;
            mac)  sendid=$MAC ;;
            pxe)  sendid=$PXE ;;
            *)    sendid=$FAI_SENDID ;;
        esac

        if sendmon check; then
            echo "Monitoring to server $monserver enabled."
            sendmon "TASKBEGIN confdir"
        else
            faimond=0
            echo "Can't connect to monserver on $monserver port $FAI_MONITOR_PORT. Monitoring disabled."
        fi
    fi

    local mdir=/lib/modules/$(uname -r)
    if [ $do_init_tasks -eq 1 ] && [ ! -d $mdir ]; then
        echo "ERROR: The running kernel does not match the kernel modules inside the nfsroot."
        echo "ERROR: Kernel modules directory $mdir not available. Only found:"
        ls -d /lib/modules/*
        echo ""
        task_error 790
    fi

    get-config-dir || {
        echo "Problems accessing the config space."
        die ""
    }
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $BOOT_DEVICE $ROOT_PARTITION $BOOT_PARTITION $SWAPLIST
# Requires-Var:    $LOGDIR $LOGDIR/disk_var.sh
# Short-Description: partition local hard disks
### END SUBROUTINE INFO

task_partition() {

    if [ X$USE_SETUP_STORAGE = X1 ]; then
        echo "WARNING: The variable USE_SETUP_STORAGE is not needed any more." >&2
        echo "setup-storage is now the default tool for partitioning."
    fi

    [ ! -s $LOGDIR/disk_var.sh ] && setup-storage -X |& tee $LOGDIR/format.log

    # if we've created device mapper devices, do cleanup on error
    grep -q 'Executing: vgcreate' $LOGDIR/format.log 2>/dev/null
    if [ $? -eq 0 ]; then
	trap "umount_target;cleanup_devicemapper" QUIT EXIT
    fi

    # partitioning tool must create $LOGDIR/disk_var.sh file
    if [ ! -s $LOGDIR/disk_var.sh ]; then
        local conffile=$(grep "Using config file:" $LOGDIR/format.log | cut -d: -f2 )
        if [ -n "$conffile" ]; then
            echo ""
            echo "This is your disk_config file:"
            cat $conffile
        fi
        echo ""
        task_error 710
        sendmon "TASKERROR partition 21"
        die "Partitioning tool did not create $LOGDIR/disk_var.sh file."
    fi
    # now define variable for root and boot partition and boot device
    . $LOGDIR/disk_var.sh
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    none
# Requires-Var:    $NFSROOT
# Suggests-Var:
# Short-Description: <task desc.>
### END SUBROUTINE INFO

call_debootstrap() {

    local targetarch
    local dversion=$(dpkg-query -Wf '${Version}\n' debootstrap)
    echo "Creating base system using debootstrap version $dversion"

    # Check if we need cross architecture debootstrap
    targetarch=$(expr "$FAI_DEBOOTSTRAP_OPTS" : '.*--arch=\([^[:space:]]*\)' || true)
    hostarch1=$(dpkg --print-architecture)

    _debootstrap=qemu-debootstrap
    if [ -z "$targetarch" ]; then
	_debootstrap=debootstrap
	targetarch=$hostarch1
    else
	if [ $targetarch = $hostarch1 ]; then
	_debootstrap=debootstrap
	fi
    fi
    for arch in $(dpkg --print-foreign-architectures); do
        if [ $targetarch = $arch ]; then
	        _debootstrap=debootstrap
            break
        fi
    done
    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 $FAI_ROOT $2"
    LC_ALL=C $_debootstrap $FAI_DEBOOTSTRAP_OPTS $1 $FAI_ROOT $2
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    none
# Requires-Var:    $FAI_ROOT $do_init_tasks $NFSROOT $LOGDIR
# Suggests-Var:    $FAI_DEBOOTSTRAP
# Short-Description: extrace minimal base file into target
### END SUBROUTINE INFO

task_extrbase() {

    local fs=$FAI_ROOT/etc/fstab

    fetch-basefile
    # remember, ftar extracts into $FAI_ROOT by default, so / means $FAI_ROOT/
    # copy the base file class based if it exists
    [ -d $FAI/basefiles ] && ftar -p -1v -s $FAI/basefiles /
    if [ $? -ne 0 ]; then
        if [ $do_init_tasks -eq 1 ]; then
	    ftar -p -1v -c base -s /var/tmp /
        else
	    [ -d $NFSROOT/var/tmp ] &&
               ftar -p -1v -c base -s $NFSROOT/var/tmp /
        fi

        # if no base file was extracted, call debootstrap
        if [ ! -d $FAI_ROOT/etc ]; then
            echo "No base file found. Calling debootstrap."
            [ -z "$FAI_DEBOOTSTRAP" ] && die "\$FAI_DEBOOTSTRAP undefined. Aborting"
            call_debootstrap $FAI_DEBOOTSTRAP
            task_error 801 $?
        fi
    fi

    # now check if this is a cross architecture installation, and install qemu user static if needed
    check-cross-arch $FAI_ROOT
    # now we can copy fstab
    [ -f $LOGDIR/fstab ] && cp -S.old -bp $LOGDIR/fstab $fs
    # copy crypttab, if setup-storage created one
    [ -f $LOGDIR/crypttab ] && cp -p $LOGDIR/crypttab $FAI_ROOT/etc/crypttab
    # make /var/lib/dpkg a ramdisk
    mkramdisk -a
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:
# Requires-Var:    $FAI_ROOT $MNTPOINT $romountopt
# Suggests-Var:    $FAI_DEBMIRROR $debug
# Short-Description: mount Debian mirror via NFS
### END SUBROUTINE INFO

mount_mirror() {

    # mount debian mirror directory
    [ "$FAI_DEBMIRROR" ] || return   # nothing to do
    mkdir -p ${FAI_ROOT}${MNTPOINT}
    if mount $romountopt $FAI_DEBMIRROR ${FAI_ROOT}${MNTPOINT}; then
      [ "$debug" ] && echo "Mirror mounted from $FAI_DEBMIRROR to ${FAI_ROOT}${MNTPOINT}"
    else
      sendmon "TASKERROR repository $?"
      die "Can't mount $FAI_DEBMIRROR"
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_debconf () {

    if [ ! -d $FAI/debconf ]; then
        echo "Can't find debconf directory $FAI/debconf. Skipping preseeding."
        task_error 2
        return
    fi
    fai-debconf $FAI/debconf
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    none
# Requires-Var:    $classes $FAI $FAI_ROOT $FAI_ETC_DIR $FAI_ALLOW_UNSIGNED
# Suggests-Var:
# Short-Description: prepare access to package repository
### END SUBROUTINE INFO

task_repository () {

    # check for old hooks for task prepareapt
    local hook cl hfile
    hook=prepareapt
    for cl in ${classes:-}; do
        hfile=$FAI/hooks/$hook.$cl
        if [ -f $hfile ]; then
            echo "WARNING: The task prepareapt is obsolete. It was renamed to task repository. Please rename your hook $hfile to repository.$cl." >&2
            continue
        fi
        if [ -f $hfile.source ]; then
            echo "WARNING: The task prepareapt is obsolete. It was renamed to task repository. Please rename your hook $hfile.source to repository.$cl.source." >&2
            continue
        fi
    done

    if [ X$verbose = X1 ]; then
	v=-v
    fi

    [ $do_init_tasks -eq 1 ] && FAI_ETC_DIR=/etc

    # some generale network files are needed on the client
    # resolv.conf is needed, /etc/hosts is useful in /target
    # use a file from the config space or from /etc inside the nfsroot
    if ! fcopy -BM $v /etc/resolv.conf ; then
        if [ "$(readlink -f /etc/resolv.conf)" = "$(readlink -f $FAI_ROOT/etc/resolv.conf)" ] ; then
            :
	    # no need for copy since both are pointing to the same file
        else
            [ -f /etc/resolv.conf ] && cp $v /etc/resolv.conf $FAI_ROOT/etc
        fi
    fi
    if ! fcopy -M $v /etc/hosts ; then
	[ X$FAI_ROOT = X/ ] || cp $v -bS.orig /etc/hosts $FAI_ROOT/etc
    fi

    # apt specific things
    if ! fcopy -SBM $v /etc/apt/sources.list; then
	[ -f $FAI_ETC_DIR/apt/sources.list ] && cp $v $FAI_ETC_DIR/apt/sources.list $FAI_ROOT/etc/apt
    fi
    if ! fcopy -BM $v /etc/apt/preferences; then
        [ -f $FAI_ETC_DIR/apt/preferences ] && cp $v $FAI_ETC_DIR/apt/preferences $FAI_ROOT/etc/apt
    fi
    fcopy -SBMir /etc/apt # copy all other apt config files from the config space

    if [ X$FAI_ALLOW_UNSIGNED = X1 ]; then
        cat <<EOF > $FAI_ROOT/etc/apt/apt.conf.d/10fai
APT::Get::AllowUnauthenticated "true";
Acquire::AllowInsecureRepositories "true";
Aptitude::CmdLine::Ignore-Trust-Violations yes;
EOF
    else
	rm -f $FAI_ROOT/etc/apt/apt.conf.d/10fai
    fi

    # add apt keys for all classes
    for keyfile in ${classes:-}; do
        if [  -f $FAI/package_config/$keyfile.gpg ]; then
	    echo "Copying APT key $keyfile.gpg to target"
	    cp -v --preserve=timestamp $FAI/package_config/$keyfile.gpg $FAI_ROOT/etc/apt/trusted.gpg.d/
	    continue
        fi
        [ ! -f $FAI/package_config/$keyfile.asc ] && continue
        echo "Copying APT key from $keyfile.asc to $keyfile.asc.gpg "
        rm -f $FAI_ROOT/etc/apt/trusted.gpg.d/$keyfile.asc.gpg
        gpg --batch -o $FAI_ROOT/etc/apt/trusted.gpg.d/$keyfile.asc.gpg --dearmor $FAI/package_config/$keyfile.asc
    done

    # mount Debian mirror via NFS if needed
    mount_mirror
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_updatebase() {

    # maybe the base system is not up to date

    if [ X$verbose = X1 ]; then
        updatebase </dev/null |& tee -a $LOGDIR/software.log
        task_error 474 ${PIPESTATUS[0]}
    else
        updatebase </dev/null >> $LOGDIR/software.log 2>&1
        task_error 474 $?
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_instsoft() {

    if [ X$verbose = X1 ]; then
	echo "Installing software may take a while"
    fi
    if [ "$debug" ]; then
        install_packages | tee -a $LOGDIR/software.log
        task_error 471 ${PIPESTATUS[0]}
    elif [ X$verbose = X1 ]; then
        install_packages </dev/null |& tee -a $LOGDIR/software.log
        task_error 471 ${PIPESTATUS[0]}
    else
        install_packages </dev/null >> $LOGDIR/software.log 2>&1
        task_error 471 $?
    fi
    # This almost indicates an error
    grep -E "^E:" $LOGDIR/software.log && task_error 472
    grep "Couldn't find any package whose name or description matched" $LOGDIR/software.log && task_error 321
    grep -q "E: Sub-process /usr/bin/dpkg returned an error code" $LOGDIR/software.log && task_error 620
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_finish() {

    mkramdisk -au # umount ramdisk
    if [ $do_init_tasks -eq 1 ] ; then
        # show some local information
        df -PTh | grep -E ':|^/|^Filesystem'
        # show rx and tx bytes of network device
        grep . /sys/class/net/*/statistics/*x_bytes | perl -ane 'm#/sys/class/net/(.+)/statistics/(.+):(\d+)# && ($3) && ($1 ne lo) && printf "%s %s %.2f Mbytes\n",$1,$2,$3/1000000 '
        swapoff -a
    else
        df -PTh | grep -E "^Filesystem|$target"
    fi

    # undo fake of all programs made by fai
    fai-divert -R
    rm -f $FAI_ROOT/etc/apt/apt.conf.d/{10,90}fai
    echo -n "FAI finished at: ";date
    echo "The $FAI_ACTION took $(($(cut -d . -f 1 /proc/uptime) - start_seconds)) seconds."
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_chboot() {

    # the whole subroutine may be an externel script

    [ -z "$LOGUSER" ] && return # silently return from subroutine

    local frsh remotesh
    local doexit=0
    local hostname
    read hostname < /proc/sys/kernel/hostname
    local ipaddr=$(grep IPADDR $LOGDIR/boot.log | cut -d= -f2 | sed "s/'//g")
    local nexttest=$(grep -E -s ^NEXTTEST= $LOGDIR/test.log | cut -d= -f2)

    case "$FAI_LOGPROTO" in
        ftp) remotesh=ssh ;;
        ssh) remotesh=ssh ;;
        rsh) remotesh=rsh ;;
	*) echo "ERROR: Unknown value for \$FAI_LOGPROTO." ;;
    esac
    frsh="$remotesh -l $LOGUSER ${SERVER}"

    if [ -z "$SERVER" ] ; then
        echo "SERVER not defined. Can't change network boot configuration"
        task_error 2
        doexit=1
    fi
    [ $doexit -eq 1 ] && return

    # change boot device (local disk or network) when using PXE
    # first test if rsh to server works
    $frsh true >/dev/null 2>&1
    if [ $? -ne 0 ]; then
        task_error 3
        echo "WARNING: $frsh failed. Can't call fai-chboot on the install server." >&2
    else
        if [ -n "$nexttest" ]; then
                # for test sequences, we want the system to reinstall immediately with
                # with different class setup
            $frsh /usr/sbin/fai-chboot -k ADDCLASSES=$nexttest -FIv $ipaddr $MAC
        else
                # remove pxe config, so host will use default and boot from local disk
            $frsh /usr/sbin/fai-chboot -vd $ipaddr $MAC
        fi
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sendmon() {

    # send message to monitor daemon
    echo "$*" >> $LOGDIR/fai-monitor.log
    [ "$faimond" -eq 0 ] && return 0
    echo "$sendid $*" | nc -w 8 $monserver $FAI_MONITOR_PORT 2>/dev/null
    return $?
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.