This file is indexed.

/usr/lib/fai/subroutines is in fai-client 4.0.8~deb7u1.

This file is owned by root:root, with mode 0o755.

The actual contents of the file can be viewed below.

   1
   2
   3
   4
   5
   6
   7
   8
   9
  10
  11
  12
  13
  14
  15
  16
  17
  18
  19
  20
  21
  22
  23
  24
  25
  26
  27
  28
  29
  30
  31
  32
  33
  34
  35
  36
  37
  38
  39
  40
  41
  42
  43
  44
  45
  46
  47
  48
  49
  50
  51
  52
  53
  54
  55
  56
  57
  58
  59
  60
  61
  62
  63
  64
  65
  66
  67
  68
  69
  70
  71
  72
  73
  74
  75
  76
  77
  78
  79
  80
  81
  82
  83
  84
  85
  86
  87
  88
  89
  90
  91
  92
  93
  94
  95
  96
  97
  98
  99
 100
 101
 102
 103
 104
 105
 106
 107
 108
 109
 110
 111
 112
 113
 114
 115
 116
 117
 118
 119
 120
 121
 122
 123
 124
 125
 126
 127
 128
 129
 130
 131
 132
 133
 134
 135
 136
 137
 138
 139
 140
 141
 142
 143
 144
 145
 146
 147
 148
 149
 150
 151
 152
 153
 154
 155
 156
 157
 158
 159
 160
 161
 162
 163
 164
 165
 166
 167
 168
 169
 170
 171
 172
 173
 174
 175
 176
 177
 178
 179
 180
 181
 182
 183
 184
 185
 186
 187
 188
 189
 190
 191
 192
 193
 194
 195
 196
 197
 198
 199
 200
 201
 202
 203
 204
 205
 206
 207
 208
 209
 210
 211
 212
 213
 214
 215
 216
 217
 218
 219
 220
 221
 222
 223
 224
 225
 226
 227
 228
 229
 230
 231
 232
 233
 234
 235
 236
 237
 238
 239
 240
 241
 242
 243
 244
 245
 246
 247
 248
 249
 250
 251
 252
 253
 254
 255
 256
 257
 258
 259
 260
 261
 262
 263
 264
 265
 266
 267
 268
 269
 270
 271
 272
 273
 274
 275
 276
 277
 278
 279
 280
 281
 282
 283
 284
 285
 286
 287
 288
 289
 290
 291
 292
 293
 294
 295
 296
 297
 298
 299
 300
 301
 302
 303
 304
 305
 306
 307
 308
 309
 310
 311
 312
 313
 314
 315
 316
 317
 318
 319
 320
 321
 322
 323
 324
 325
 326
 327
 328
 329
 330
 331
 332
 333
 334
 335
 336
 337
 338
 339
 340
 341
 342
 343
 344
 345
 346
 347
 348
 349
 350
 351
 352
 353
 354
 355
 356
 357
 358
 359
 360
 361
 362
 363
 364
 365
 366
 367
 368
 369
 370
 371
 372
 373
 374
 375
 376
 377
 378
 379
 380
 381
 382
 383
 384
 385
 386
 387
 388
 389
 390
 391
 392
 393
 394
 395
 396
 397
 398
 399
 400
 401
 402
 403
 404
 405
 406
 407
 408
 409
 410
 411
 412
 413
 414
 415
 416
 417
 418
 419
 420
 421
 422
 423
 424
 425
 426
 427
 428
 429
 430
 431
 432
 433
 434
 435
 436
 437
 438
 439
 440
 441
 442
 443
 444
 445
 446
 447
 448
 449
 450
 451
 452
 453
 454
 455
 456
 457
 458
 459
 460
 461
 462
 463
 464
 465
 466
 467
 468
 469
 470
 471
 472
 473
 474
 475
 476
 477
 478
 479
 480
 481
 482
 483
 484
 485
 486
 487
 488
 489
 490
 491
 492
 493
 494
 495
 496
 497
 498
 499
 500
 501
 502
 503
 504
 505
 506
 507
 508
 509
 510
 511
 512
 513
 514
 515
 516
 517
 518
 519
 520
 521
 522
 523
 524
 525
 526
 527
 528
 529
 530
 531
 532
 533
 534
 535
 536
 537
 538
 539
 540
 541
 542
 543
 544
 545
 546
 547
 548
 549
 550
 551
 552
 553
 554
 555
 556
 557
 558
 559
 560
 561
 562
 563
 564
 565
 566
 567
 568
 569
 570
 571
 572
 573
 574
 575
 576
 577
 578
 579
 580
 581
 582
 583
 584
 585
 586
 587
 588
 589
 590
 591
 592
 593
 594
 595
 596
 597
 598
 599
 600
 601
 602
 603
 604
 605
 606
 607
 608
 609
 610
 611
 612
 613
 614
 615
 616
 617
 618
 619
 620
 621
 622
 623
 624
 625
 626
 627
 628
 629
 630
 631
 632
 633
 634
 635
 636
 637
 638
 639
 640
 641
 642
 643
 644
 645
 646
 647
 648
 649
 650
 651
 652
 653
 654
 655
 656
 657
 658
 659
 660
 661
 662
 663
 664
 665
 666
 667
 668
 669
 670
 671
 672
 673
 674
 675
 676
 677
 678
 679
 680
 681
 682
 683
 684
 685
 686
 687
 688
 689
 690
 691
 692
 693
 694
 695
 696
 697
 698
 699
 700
 701
 702
 703
 704
 705
 706
 707
 708
 709
 710
 711
 712
 713
 714
 715
 716
 717
 718
 719
 720
 721
 722
 723
 724
 725
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
 736
 737
 738
 739
 740
 741
 742
 743
 744
 745
 746
 747
 748
 749
 750
 751
 752
 753
 754
 755
 756
 757
 758
 759
 760
 761
 762
 763
 764
 765
 766
 767
 768
 769
 770
 771
 772
 773
 774
 775
 776
 777
 778
 779
 780
 781
 782
 783
 784
 785
 786
 787
 788
 789
 790
 791
 792
 793
 794
 795
 796
 797
 798
 799
 800
 801
 802
 803
 804
 805
 806
 807
 808
 809
 810
 811
 812
 813
 814
 815
 816
 817
 818
 819
 820
 821
 822
 823
 824
 825
 826
 827
 828
 829
 830
 831
 832
 833
 834
 835
 836
 837
 838
 839
 840
 841
 842
 843
 844
 845
 846
 847
 848
 849
 850
 851
 852
 853
 854
 855
 856
 857
 858
 859
 860
 861
 862
 863
 864
 865
 866
 867
 868
 869
 870
 871
 872
 873
 874
 875
 876
 877
 878
 879
 880
 881
 882
 883
 884
 885
 886
 887
 888
 889
 890
 891
 892
 893
 894
 895
 896
 897
 898
 899
 900
 901
 902
 903
 904
 905
 906
 907
 908
 909
 910
 911
 912
 913
 914
 915
 916
 917
 918
 919
 920
 921
 922
 923
 924
 925
 926
 927
 928
 929
 930
 931
 932
 933
 934
 935
 936
 937
 938
 939
 940
 941
 942
 943
 944
 945
 946
 947
 948
 949
 950
 951
 952
 953
 954
 955
 956
 957
 958
 959
 960
 961
 962
 963
 964
 965
 966
 967
 968
 969
 970
 971
 972
 973
 974
 975
 976
 977
 978
 979
 980
 981
 982
 983
 984
 985
 986
 987
 988
 989
 990
 991
 992
 993
 994
 995
 996
 997
 998
 999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
#! /bin/bash

#*********************************************************************
#
# subroutines -- useful subroutines for FAI
#
# This script is part of FAI (Fully Automatic Installation)
# (c) 2000-2012 by Thomas Lange, lange@informatik.uni-koeln.de
# Universitaet zu Koeln
# (c) 2001-2005 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
#*********************************************************************

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

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

    # echo comment and exit installation
    task_savelog
    echo "$@"
    if [ X$FAI_ACTION = Xinstall ]; 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() {

    if [ -r /var/run/fai/kern.log.offset ] ; then
      logtail -t -f /var/log/kern.log -o /var/run/fai/kern.log.offset > $LOGDIR/dmesg.log
    else
      dmesg > $LOGDIR/dmesg.log
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
umount_csspace() {

    # umount config space if accessed via nfs
    echo $FAI_CONFIG_SRC | grep -q ^nfs://
    if [ $? -eq 0 ]; then
        mountpoint -q $FAI && umount $FAI
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
jobsrunning() {

    # test if jobs are running
    ps r | egrep -qv "ps r|TIME COMMAND|rcS"
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
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 += 1 ))
        sleep 10
    done
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
stop_fai_installation() {

    # this subroutine should directly stop the installation process
    sendmon "TASKEND $taskname $task_error"
    echo "Error in task $taskname. 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
### END SUBROUTINE INFO

task_error() {

    [ X$2 = X0 ] && return
    task_error_func=${FUNCNAME[*]}
    [ $1 -gt $task_error ] && task_error=$1
    [ $task_error -gt $STOP_ON_ERROR ] && stop_fai_installation
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:      $task_error
# Required-Var:      $LOGDIR
# Short-Description: call a certain task
### END SUBROUTINE INFO

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

    [ -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
        [ "$verbose" ] && echo "Skiping task_$taskname"
        sendmon "TASKSKIP $taskname"
    else
        echo "Calling task_$taskname"
        sendmon "TASKBEGIN $taskname"
        task_error=0   # task can set this variable to indicate an error
        task_error_func=''
        task_$taskname "$@"
        sendmon "TASKEND $taskname $task_error"
        if [ "$task_error" -ne 0 ] ; then
          echo "Exit code task_$taskname: $task_error" >&2
        fi
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:
# Required-Var:      $classes $debug
# Short-Description: call a hook, hook.source 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.source -a ! -x $hfile.source ]; then
            echo "WARNING: Skipping $hfile.source because it's not executable." >&2
            continue
        fi
        if [ -x $hfile ]; then
            echo "Calling hook: $hook.$cl"
            sendmon "HOOK $hook.$cl"
            # execute the hook
            $hfile $dflag "$@"
            check_status $hook.$cl $?
        fi
        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
            trap 'echo "You can reboot with faireboot";bash' INT QUIT
        }

        # start secure shell daemon for remote access
        mkdir -p /var/run/sshd # ubuntu fix for 9.10
        [ "$flag_sshd" -a -x /usr/sbin/sshd ] && /usr/sbin/sshd
    fi
    unset flag_createvt flag_sshd

    # 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 [ $do_init_tasks -eq 0 ]; then
                echo "Cowardly refusing to run a FAI installation on a running system."
                return
            fi
            echo Performing FAI installation. All data may be overwritten!
            echo -ne "\a"; sleep 1
            echo -ne "\a"; sleep 1
            echo  -e "\a"; sleep 5
            task install
            task faiend
            ;;
        dirinstall)
            task dirinstall
            task faiend
            ;;
        softupdate)
            echo Performing FAI system update. All data may be overwritten!
            task softupdate
            task faiend
            ;;
        sysinfo)
            echo Showing system information.
            task sysinfo
            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
            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
        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"
    # define a bash hash with all class names. Without this, ifclass does not work
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
_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
            [ "$verbose" ] && 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 ^++ $svar
            rm $svar
        fi
    done

    echo "Defining variables from additional.var"
    # /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
        _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|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
    local sd
    for sd in $SWAPLIST; do
        swapon -p1 $sd && [ "$verbose" ] && echo "Enable swap device $sd"
    done
    mount2dir $FAI_ROOT $LOGDIR/fstab
    if [ "$?" -ne 0 ]; then
        sendmon "TASKERROR mountdisks 885"
        task_error 885
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_configure() {

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

    if [ -d $FAI/tests ]; then
        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
    else
        echo "WARNING: Subdirectory tests/ not found. No tests run." >&2
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
task_savelog() {

    mkdir -p $FAI_ROOT/var/{lib,log}/fai
    rm -f /var/run/fai/kern.log.offset
    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
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Description: Always called as last FAI task
### END SUBROUTINE INFO
task_faiend() {

    local dir cdromdevice
    [ $do_init_tasks -eq 0 ] && return 0
    wait_for_jobs
    : ${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 [ "$flag_reboot" -eq 0 -a "$flag_halt" -eq 0 ]; then
        echo "Press <RETURN> to reboot."
        read
    else
        sleep 10
    fi

    sendmon "TASKEND faiend 0"
    echo "Rebooting $HOSTNAME now"
    sendmon "TASKEND reboot 0"
    cd /
    sync

    killall -q sshd udevd
    if [ -f /etc/RUNNING_FROM_FAICD ]; then
        echo 1 > /proc/sys/dev/cdrom/autoeject
        cat > $target/tmp/rebootCD <<'EOF'
#! /bin/bash
 device=$1
eject -m /dev/$device 2>/dev/null >/dev/null
echo "Remove CDROM and press <RETURN> to continue reboot"
read
eject -t /dev/$device 2>/dev/null >/dev/null
EOF

        #reboot or halt?
        if [ "$flag_halt" -gt "0" ]; then
            echo "exec halt -dfp" >> $target/tmp/rebootCD
        else
            echo "exec reboot -df" >> $target/tmp/rebootCD
        fi


        chmod +x $target/tmp/rebootCD
        sync
        for dir in $(mount | grep $target | awk '{print $3}' | sort -r); do
            mount -o remount,ro $dir
        done
        cdromdevice=$(awk '/ name:/ {print $3}' /proc/sys/dev/cdrom/info)
        chroot $target /tmp/rebootCD $cdromdevice
        # never reached, because chroot will reboot the machine
        die "Internal error when calling /tmp/rebootCD." >&2
    fi
    umount $FAI_ROOT/proc
    umount -arf 2>/dev/null

    # reboot or halt?
    if [ "$flag_halt" -gt "0" ]; then
        exec halt -dfip;
    else
        exec reboot -dfi;
    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
        # 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() {

    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

    defnop wait_for_jobs
    save_dmesg

    task debconf
    task repository
    task updatebase
    task instsoft
    task configure
    task tests
    date
    [ -f /proc/uptime ] && echo "The $FAI_ACTION took $[$(cut -d . -f 1 /proc/uptime)-$start_seconds] seconds."

    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
    egrep -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

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

}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### BEGIN SUBROUTINE INFO
# Provides-Var:    $faimond $sendhostname $SERVER $monserver
# Requires-Var:    $LOGDIR $FAI
# Suggests-Var:    $monserver
# Short-Description: <task desc.>
### END SUBROUTINE INFO

task_confdir() {

    if [ $do_init_tasks -eq 1 ] ; then
        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
        rsyslogd -c3

        create_resolv_conf
    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/.*@//')
        echo "Set \$SERVER=$SERVER. Value extracted from FAI_CONFIG_SRC"
    fi

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

    if [ -z "$monserver" ]; then
        echo "No monitor daemon defined."
        faimond=0
    else
        faimond=1
        sendhostname=$HOSTNAME # save current hostname
        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 4711. Monitoring disabled."
        fi
    fi

    get-config-dir || {
        echo "Problems accessing the config space."
        die ""
    }

    # 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
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
### 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 2>&1 | tee $LOGDIR/format.log

    # partitioning tool must create $LOGDIR/disk_var.sh file
    if [ ! -s $LOGDIR/disk_var.sh ]; then
        task_error 710
        cat $LOGDIR/format.log
        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 dversion=$(dpkg -l debootstrap | grep debootstrap | cut -f7 -d' ')
    echo "Creating base system using debootstrap version $dversion"
    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
    echo "Unpacking Debian base archive"
    # 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 -1v -s $FAI/basefiles /
    if [ $? -ne 0 ]; then
        if [ $do_init_tasks -eq 1 ]; then
            ftar -1v -c base -s /var/tmp /
        else
            [ -d $NFSROOT/live/filesystem.dir/var/tmp ] &&
               ftar -1v -c base -s $NFSROOT/live/filesystem.dir/var/tmp /
            [ -d $NFSROOT/var/tmp ] &&
               ftar -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 we can copy fstab
    [ -f $fs ] && mv $fs $fs.old
    [ -f $LOGDIR/fstab ] && cp -p $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 mirror $?"
      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

    [ $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 -BMv /etc/resolv.conf ; then
        if test -L $FAI_ROOT/etc/resolv.conf && \
            [ $(readlink -f /etc/resolv.conf) = $(readlink -f $FAI_ROOT/etc/resolv.conf) ] ; then
            echo "/etc/resolv.conf + $FAI_ROOT/etc/resolv.conf are already pointing to the same file."
        else
            cp -v /etc/resolv.conf $FAI_ROOT/etc
        fi
    fi
    fcopy -BMv /etc/hosts || cp -v /etc/hosts $FAI_ROOT/etc

    # apt specific things
    fcopy -BMv /etc/apt/sources.list || cp -v $FAI_ETC_DIR/apt/sources.list $FAI_ROOT/etc/apt
    if fcopy -BMv /etc/apt/preferences; then
        [ -f $FAI_ETC_DIR/apt/preferences ] && cp -v $FAI_ETC_DIR/apt/preferences $FAI_ROOT/etc/apt
    fi
    fcopy -Mir /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";
Aptitude::CmdLine::Ignore-Trust-Violations yes;
EOF
    fi

    # add apt keys for signed repositories

    declare -A keys
    # remember all available *.asc files
    for f in `cd $FAI/package_config; ls *.asc 2>/dev/null`; do
        keys["$f"]=1
    done

    # add apt keys for all classes
    for keyfile in ${classes:-}; do
        [ ! -f $FAI/package_config/$keyfile.asc ] && continue
        echo -n "Loading APT key from $keyfile.asc "
        cat $FAI/package_config/$keyfile.asc | $ROOTCMD apt-key add -
        unset keys["$keyfile.asc"]
    done

    # print which *.asc files were not loaded
    if [ ${#keys[@]} -ne 0 ]; then
        echo "Following apt keys are not loaded:"
        for i in "${!keys[@]}"; do
            echo "$i"
        done
        echo "You have to rename them to match a class name."
    fi

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

    # maybe the base system is not up to date

    if [ "$verbose" ]; then
        updatebase </dev/null 2>&1 | 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() {

    echo "Installing software may take a while"
    if [ "$debug" ]; then
        install_packages | tee -a $LOGDIR/software.log
        task_error 471 ${PIPESTATUS[0]}
    elif [ "$verbose" ]; then
        install_packages </dev/null 2>&1 | 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
    egrep "^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() {

    if [ $do_init_tasks -eq 1 ] ; then
        # show some local information
        df -PTh | egrep ':|^/|^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
    fi

    mkramdisk -au # umount ramdisk
    # undo fake of all programs made by fai
    fai-divert -R
    rm -f $FAI_ROOT/etc/apt/apt.conf.d/{10,90}fai
    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=$(hostname)
    local ipaddr=$(grep IPADDR $LOGDIR/boot.log | cut -d= -f2 | sed "s/'//g")
    local nexttest=$(egrep -s ^NEXTTEST= $LOGDIR/test.log | cut -d= -f2)

    case "$FAI_LOGPROTO" in
        ftp) remotesh=ssh ;;
        ssh) remotesh=ssh ;;
        rsh) remotesh=rsh ;;
    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
        else
                # remove pxe config, so host will use default and boot from local disk
            $frsh /usr/sbin/fai-chboot -vd $ipaddr
        fi
    fi
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
sendmon() {

    # send message to monitor daemon
    echo "$*" >> $LOGDIR/fai-monitor.log
    [ "$faimond" -eq 0 ] && return 0
    echo "$sendhostname $*" | nc -w 8 $monserver 4711 2>/dev/null
    return $?
}
# - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -