#! /bin/sh # $Id$ #********************************************************************* # # subroutines -- useful subroutines for FAI # # This script is part of FAI (Fully Automatic Installation) # (c) 2000-2002 by Thomas Lange, lange@informatik.uni-koeln.de # 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., # 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. #********************************************************************* # source this file, then you have these function available in the shell # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - die() { # echo comment and exit installation echo "$@" exec bash } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - defnop() { # define given list of subroutine names as dummy function; # this will fake unknown commands local name for name in "$@";do eval "$name () { :;}" done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - islinux() { # test is we are running on Linux # [ X$OS_TYPE = X ] && OS_TYPE=`uname -s | tr '[A-Z]' '[a-z]' if [ X$OS_TYPE = Xlinux ]; then return 0 else return 1 fi } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ifclass() { [ "$debug" ] && set +vx # test if a class is defined local cl local ret=1 for cl in $classes; do [ x$cl = x$1 ] && ret=0 && break done [ "$debug" ] && set -vx return $ret } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - create_resolv_conf() { # can be an extern script # create a resolv.conf using the DHCP or BOOTP information if [ "$DNSSRVS" ]; then [ "$DOMAIN" ] && echo "domain $DOMAIN" >/tmp/etc/resolv.conf for dnshost in $DNSSRVS ; do echo "nameserver $dnshost" >>/tmp/etc/resolv.conf done fi } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - rwmount() { # remount partition read/write mount -o rw,remount $1 } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - save_dmesg() { dmesg > $LOGDIR/dmesg.log } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - wait_for_jobs() { # can be an extern script # wait for running (background) jobs to finish (e.g. update-auctex-elisp) local i=0 while (jobsrunning); do [ $(($i % 3)) -eq 0 ] && echo "Waiting for background jobs to finish." i=$(($i+1)) sleep 10 done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - 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 [ -f $LOGDIR/skip.$taskname ] || call_hook $taskname if [ -f $LOGDIR/skip.$taskname ]; then # skip task rm $LOGDIR/skip.$taskname [ "$verbose" ] && echo "Skiping task_$taskname" else echo "Calling task_$taskname" task_$taskname fi } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - call_hook() { local hook=$1 local cl dflag hfile [ "$debug" ] && dflag="-d" for cl in $classes; do hfile=$FAI/hooks/${hook}.$cl if [ -x $hfile ]; then echo "Call hook: $hook.$cl" # execute the hook $hfile $dflag # is that really good? Makes sense if hostname would # be the first hook. # execute only one hook if return value is 42 # [ $? -eq 42 ] && return fi if [ -x $hfile.source ]; then echo "Source hook: $hook.$cl.source" # source this hook . $hfile.source $dflag fi done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - skiptask() { # mark all given tasks, so they will be skipped local tasklist="$@" local task for task in $tasklist; do > $LOGDIR/skip.$task done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - get_fai_dir() { # get /fai directory; mount it or get it from a cvs repository if [ -z "$FAI_LOCATION" ]; then [ "$debug" ] && echo "Warning $0: \$FAI_LOCATION not defined." get_fai_cvs else mount $romountopt $FAI_LOCATION $FAI && echo "$FAI mounted from $FAI_LOCATION" fi # source user specific subroutines [ -f $FAI/hooks/subroutines ] && . $FAI/hooks/subroutines } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - get_fai_cvs() { # subroutine which gets $FAI (/fai) configuration directory from # a cvs repository. You can redefine this subroutine if you need # access via ftp, http, or from a database if [ "$FAI_CVSROOT" ] ; then local TAG="" echo "Checking out CVS" [ -n "$FAI_CVSTAG" ] && TAG="-r $FAI_CVSTAG" export FAI_CONFIG_AREA=$FAI export FAI=/tmp/$(basename $FAI_CONFIG_AREA) [ "$debug" ] && echo "\$FAI now points to $FAI" if [ -d "$FAI_CONFIG_AREA" ] ; then echo "Config found at $FAI_CONFIG_AREA: Copying" cp -a $FAI_CONFIG_AREA $FAI fi cd /tmp cvs -q -d"$FAI_CVSROOT" co -P -d $(basename "$FAI") \ $TAG $FAI_CVSMODULE > $LOGDIR/cvs.log else echo "Warning $0: Neither \$FAI_LOCATION nor \$FAI_CVSROOT are defined." fi } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - define_fai_flags() { # FAI_FLAGS are now comma separated, define all flags FAI_FLAGS=`echo $FAI_FLAGS | sed -e 's/,/ /g'` for flag in $FAI_FLAGS; do # define this flag as 1 eval "$flag=1" [ "$verbose" ] && echo "FAI_FLAGS: $flag=1" done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_setup() { local flag # set the system time and date using rdate or/and ntpdate [ "$TIMESRVS_1" ] && rdate $TIMESRVS_1 [ "$NTPSRVS_1" ] && ntpdate -b -v $NTPSRVS define_fai_flags DNSDOMAIN=$DOMAIN # cfengine 1.5.3 can't use $DOMAIN devnull=/dev/null [ "$debug" ] && devnull=/dev/console # not yet used, maybe use a hook for that # if [ "$FAI_EXTRA_MOUNT" ]; then # mount $romountopt -n $FAI_EXTRA_MOUNT && echo "$FAI_EXTRA_MOUNT mounted" # fi [ "$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 trap 'echo "You can reboot with faireboot";bash' INT QUIT } # start secure shell daemon for remote access [ "$sshd" -a -x /usr/sbin/sshd ] && /usr/sbin/sshd disk_info # get and define all information of local disks # when did FAI start, using localtime RUNDATE=$(date +'%Y%m%d_%H%M%S') cat >> $rcsfaivar <<-EOM RUNDATE=$RUNDATE FAI_ACTION=$FAI_ACTION LOGDIR=$LOGDIR EOM } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_action() { echo "FAI_ACTION: $FAI_ACTION" case $FAI_ACTION in install) echo Performing FAI installation. All data may be overwritten! task install ;; sysinfo) echo Showing system information. task sysinfo die Now you have a shell. ;; backup) echo Doing backup of multiple partitions. task backup ;; *) if [ -f $FAI/hooks/$FAI_ACTION ]; then echo "Calling user defined action: $FAI_ACTION" $FAI/hooks/$FAI_ACTION else echo "ERROR: User defined action $FAI/hooks/$FAI_ACTION not found." task_faiend fi ;; esac } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_defclass() { local class # new script for defining classes; variables imported: $LOGDIR, $verbose, $debug fai-class $FAI/class $LOGDIR/FAI_CLASSES classes=`cat $LOGDIR/FAI_CLASSES` # also define all classes in reverse order ($revclasses) for class in $classes ; do revclasses="$class $revclasses" done # 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" } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_defvar() { local class cd $FAI/class for class in $classes ; do if [ -f $class.var ]; then [ "$verbose" ] && echo "Executing $class.var" [ "$debug" ] && set -vx . $class.var > $LOGDIR/shell.log 2>&1 $shelldebug ./$file >> $LOGDIR/shell.log 2>&1 ;; *"cfengine script"*) echo "Executing cfengine: $file" echo "===== cfengine: $file =====" >> $LOGDIR/cfengine.log 2>&1 ./$file --no-lock -v -f $file -D${cfclasses} >> $LOGDIR/cfengine.log 2>&1 ;; *"perl script"*) echo "Executing perl: $file" echo "===== perl: $file =====" >> $LOGDIR/perl.log 2>&1 ./$file >> $LOGDIR/perl.log 2>&1 ;; *"expect script"*) echo "Executing expect: $file" echo "===== expect: $file =====" >> $LOGDIR/expect.log 2>&1 ./$file >> $LOGDIR/expect.log 2>&1 ;; *) echo "File $file has unsupported type $filetype." ;; esac } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_savelog() { fai-savelog -l fai-savelog -r } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_faiend() { wait_for_jobs echo "Press to reboot or ctrl-c to execute a shell" # reboot without prompting if FAI_FLAG reboot is set [ -z $reboot ] && read echo "Rebooting $HOSTNAME now" cd / sync umount -ar exec reboot -dfi } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_backup() { die "Task backup not yet used. But you can use the hook backup." # NOT YET USED. IT'S ONLY AN IDEA # FAI_BACKUP_LIST contains backup options # proposed format: "hda1 hda3 hda12 sda2 '0 0 1 1'" # list of devices list of backup levels # this subroutine is not yet tested, not yet used # It's only an idea how a backup could be made # local partition # fai-mount-disk # for partition in $SAVE_DEVICES ; do # tar cf - $FAI_ROOT/$partition | $FAI_REMOTESH -l $LOGUSER $SERVER dd if= of=$HOSTNAME.$partition.tar # dump 0f $LOGUSER@$SERVER:backup/$HOSTNAME/$partition.dmp $FAI_ROOT/$partition # done } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - task_install() { > $stamp save_dmesg load_keymap_consolechars task partition task mountdisks task extrbase task mirror task updatebase task instsoft task configure task finish date echo -e "FAI finished.\a" task chboot rm -f $stamp # save again, because new messages could be created save_dmesg task savelog if [ -f $stamp ]; then echo "Error while executing commands in subshell." echo "$stamp was not removed." die "Please look at the log files in $LOGDIR for errors." fi task faiend } # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -