Release new version 0.11.1
[grml-autoconfig.git] / autoconfig.functions
1 #!/bin/zsh
2 # Filename:      autoconfig.functions
3 # Purpose:       basic system configuration and hardware setup for grml system
4 # Authors:       grml-team (grml.org), (c) Michael Prokop <mika@grml.org>
5 # Bug-Reports:   see http://grml.org/bugs/
6 # License:       This file is licensed under the GPL v2.
7 ################################################################################
8
9 # {{{ path, variables, signals, umask, zsh
10 export PATH="/bin:/sbin:/usr/bin:/usr/sbin"
11 DEBUG="/dev/null"
12 KERNEL="$(uname -r)"
13 ARCH="$(uname -m)"
14 umask 022
15
16 # old linuxrc version:
17 [ -d /cdrom ]      && export LIVECD_PATH=/cdrom
18 # initramfs layout until around December 2012:
19 [ -d /live/image ] && export LIVECD_PATH=/live/image
20 # initramfs layout since around December 2012:
21 [ -d /lib/live/mount/medium ] && export LIVECD_PATH=/lib/live/mount/medium
22
23 # Ignore these signals in non-interactive mode: INT, TERM, SEGV
24 [ -z "$PS1" ] && trap "" 2 3 11
25
26 # zsh stuff
27 iszsh(){
28 if [ -n "$ZSH_VERSION" ] ; then
29   return 0
30 else
31   return 1
32 fi
33 }
34 # avoid 'no matches found: ...'
35 iszsh && setopt no_nomatch # || echo "Warning: not running under zsh!"
36 # }}}
37
38 # {{{ Read in boot parameters
39 if [ -z "$CMDLINE" ]; then
40   # if CMDLINE was set from the outside, we're debugging.
41   # otherwise, take CMDLINE from Kernel and config files.
42   CMDLINE="$(cat /proc/cmdline)"
43   [ -d ${LIVECD_PATH}/bootparams/ ] && CMDLINE="$CMDLINE $(cat ${LIVECD_PATH}/bootparams/* | tr '\n' ' ')"
44   modprobe 9p 2>/dev/null || true
45   if grep -q 9p /proc/filesystems ; then
46       TAG="grml-parameters"
47       if grep -q "$TAG" /sys/bus/virtio/devices/*/mount_tag 2>/dev/null ; then
48           MOUNTDIR="$(mktemp -d)"
49           mount -t 9p -o trans=virtio,ro "$TAG" "$MOUNTDIR"
50           CMDLINE="$CMDLINE $(cat "$MOUNTDIR"/* 2>/dev/null | tr '\n' ' ')"
51           umount "$MOUNTDIR"
52           rmdir "$MOUNTDIR"
53       fi
54   fi
55 fi
56 # }}}
57
58 ### {{{ Utility Functions
59
60 # Get a bootoption's parameter: read boot command line and either
61 # echo last parameter's argument or return false.
62 getbootparam(){
63   local line
64   local ws
65   ws='   '
66   line=" $CMDLINE "
67   case "$line" in
68     *[${ws}]"$1="*)
69       result="${line##*[$ws]$1=}"
70       result="${result%%[$ws]*}"
71       echo "$result"
72       return 0 ;;
73     *) # no match?
74       return 1 ;;
75   esac
76 }
77
78 # Check boot commandline for specified option
79 checkbootparam(){
80   [ -n "$1" ] || ( echo "Error: missing argument to checkbootparam()" ; return 1 )
81   local line
82   local ws
83   ws='   '
84   line=" $CMDLINE "
85   case "$line" in
86     *[${ws}]"$1"=*|*[${ws}]"$1"[${ws}]*)
87       return 0 ;;
88     *)
89       return 1 ;;
90   esac
91 }
92
93 # Check if currently using a framebuffer
94 hasfb() {
95     [ -e /dev/fb0 ] && return 0 || return 1
96 }
97
98 # Check wheter a configuration variable (like $CONFIG_TOHD) is
99 # enabled or not
100 checkvalue(){
101   case "$1" in
102     [yY][eE][sS])     return 0 ;; # it's set to 'yes'
103     [tT][rR][uU][eE]) return 0 ;; # it's set to 'true'
104                    *) return 1 ;; # default
105   esac
106 }
107
108 # Are we using grml-small?
109 checkgrmlsmall(){
110   grep -q small /etc/grml_version 2>>$DEBUG && return 0 || return 1
111 }
112
113 # if no password is set return a random password
114 set_passwd() {
115   [ -n "$PASSWD" ] && return 0
116
117   if [ -x /usr/bin/apg ] ; then
118     PASSWD="$(apg -M NL -a 0 -m 8 -x 12 -n 1)"
119   elif [ -x /usr/bin/gpw ] ; then
120     PASSWD="$(gpw 1)"
121   elif [ -x /usr/bin/pwgen ] ; then
122     PASSWD="$(pwgen -1 8)"
123   elif [ -x /usr/bin/hexdump ] ; then
124     PASSWD="$(dd if=/dev/urandom bs=14 count=1 2>/dev/null | hexdump | awk '{print $3 $4}')"
125   elif [ -n "$RANDOM" ] ; then
126     PASSWD="grml${RANDOM}"
127   else
128     PASSWD=''
129     eerror "Empty passphrase and neither apg, gpw, pwgen, hexdump nor \$RANDOM available. Skipping."
130     eend 1
131     return 1
132   fi
133 }
134
135 ### }}}
136
137 # {{{ filesystems (proc, pts, sys) and fixes
138 mount_proc(){
139   [ -f /proc/version ] || mount -t proc /proc /proc 2>/dev/null
140 }
141
142 mount_pts(){
143   grep -q "/dev/pts" /proc/mounts || mount -t devpts /dev/pts /dev/pts 2>/dev/null
144 }
145
146 mount_sys(){
147   [ -d /sys/devices ] || mount -t sysfs /sys /sys 2>/dev/null
148 }
149 # }}}
150
151 # {{{ Check if we are running in live mode or from HD
152 INSTALLED=""
153 [ -e /etc/grml_cd ] || INSTALLED="yes"
154 # }}}
155
156 # {{{ provide information about virtual environments
157 VIRTUAL=false # assume physical system by default
158 KVM=false
159 VIRTUALBOX=false
160 VMWARE=false
161
162 if vmware-detect &>/dev/null; then
163   VIRTUAL=true; VMWARE=true; VIRTUAL_ENV='VMware'
164 elif [ "$(virt-what 2>/dev/null)" = "kvm" ] || \
165    [ "$(imvirt 2>/dev/null)" = "KVM" ] ; then
166   VIRTUAL=true; KVM=true; VIRTUAL_ENV='KVM'
167 elif [ "$(virt-what 2>/dev/null)" = "virtualbox" ] || \
168    [ "$(imvirt 2>/dev/null)" = "VirtualBox" ] ; then
169   VIRTUAL=true; VIRTUALBOX=true; VIRTUAL_ENV='VirtualBox'
170 fi
171 # }}}
172
173 # {{{ source lsb-functions , color handling
174 if checkbootparam 'nocolor'; then
175   RC_NOCOLOR=yes
176   . /etc/grml/lsb-functions
177   einfo "Disabling colors in bootsequence as requested on commandline." ; eend 0
178 else
179   . /etc/grml/lsb-functions
180   . /etc/grml_colors
181 fi
182 # }}}
183
184 # {{{ debug
185 config_debug(){
186  checkbootparam 'debug'            && BOOTDEBUG="yes"
187  checkbootparam "BOOT_IMAGE=debug" && BOOTDEBUG="yes"
188
189  rundebugshell(){
190   if [ -n "$BOOTDEBUG" ]; then
191      einfo "Starting intermediate shell stage $stage as requested by \"debug\" option."
192      if [ grep -q "debug=noscreen" "$CMDLINE" ] ; then
193         einfo "Notice that the shell does not provide job handling: ctrl-z, bg and fg won't work!"
194         einfo "Just exit the shell to continue boot process..."
195         /bin/zsh
196      else
197         eindent
198         if [ -r /etc/grml/screenrc ] ; then
199            einfo "Starting GNU screen to be able to use a full featured shell environment."
200            einfo "Just exit the shells (and therefore screen) to continue boot process..."
201            /bin/zsh -c "screen -c /etc/grml/screenrc"
202         else
203            einfo "Notice that the shell does not provide job handling: ctrl-z, bg and fg won't work!"
204            einfo "Just exit the shell to continue boot process..."
205            /bin/zsh
206         fi
207         eoutdent
208      fi
209   fi
210  }
211 }
212 # }}}
213
214 # {{{ log
215 config_log(){
216 if checkbootparam 'log' || checkbootparam 'debug' ; then
217    export DEBUG="/tmp/grml.log.`date +%Y%m%d`"
218    touch $DEBUG
219    einfo "Bootparameter log found. Log files: ${DEBUG} and /var/log/boot"
220    eindent
221      einfo "Starting bootlogd." # known to be *very* unreliable :(
222      bootlogd -r -c >>$DEBUG 2>&1 ; eend $?
223    eoutdent
224 else
225    DEBUG="/dev/null"
226 fi
227 }
228 # }}}
229
230 # {{{ set firmware timeout via bootparam
231 config_fwtimeout(){
232  if checkbootparam 'fwtimeout' ; then
233    TIMEOUT="$(getbootparam 'fwtimeout' 2>>$DEBUG)"
234    einfo "Bootoption fwtimeout found. (Re)Loading firmware_class module."
235    rmmod firmware_class >>$DEBUG 2>&1
236    modprobe firmware_class ; eend $?
237  fi
238  if [ -z "$TIMEOUT" ] ; then
239    TIMEOUT="100" # linux kernel default: 10
240  fi
241  if [ -f /sys/class/firmware/timeout ] ; then
242    einfo "Setting timeout for firmware loading to ${TIMEOUT}."
243    echo $TIMEOUT > /sys/class/firmware/timeout ; eend $?
244  fi
245 }
246 # }}}
247
248 ### {{{ language configuration / localization
249 config_language(){
250
251  einfo "Activating language settings:"
252  eindent
253
254  # people can specify $LANGUAGE and $CONSOLEFONT in a config file
255  [ -r /etc/grml/autoconfig ] && . /etc/grml/autoconfig
256
257  # check for bootoption which overrides config from /etc/grml/autoconfig
258  BOOT_LANGUAGE="$(getbootparam 'lang' 2>>$DEBUG)"
259  [ -n "$BOOT_LANGUAGE" ] && LANGUAGE="$BOOT_LANGUAGE"
260
261  # set default to 'en' in live-cd mode iff $LANGUAGE is not set yet
262  if [ -z "$INSTALLED" ] ; then
263     [ -n "$LANGUAGE" ] || LANGUAGE='en'
264  fi
265
266  if [ -x /usr/sbin/grml-setlang ] ; then
267    # if bootoption lang is used update /etc/default/locale accordingly
268    if [ -n "$BOOT_LANGUAGE" ] ; then
269      /usr/sbin/grml-setlang "$LANGUAGE"
270    # otherwise default to lang=en
271    else
272      /usr/sbin/grml-setlang "en"
273    fi
274  fi
275
276  # set console font
277  if [ -z "$CONSOLEFONT" ] ; then
278     if ! checkbootparam 'nodefaultfont' >>$DEBUG 2>&1 ; then
279        if [ -r /usr/share/consolefonts/Uni3-Terminus16.psf.gz ] ; then
280           CONSOLEFONT='Uni3-Terminus16'
281        else
282           ewarn "/usr/share/consolefonts/Uni3-Terminus16.psf.gz not available. Please upgrade package console-terminus." ; eend 1
283        fi
284        if ! hasfb ; then
285           CONSOLEFONT='Lat15-Terminus16'
286        fi
287     fi
288  fi
289
290  # export it now, so error messages get translated, too
291  [ -r /etc/default/locale ] && . /etc/default/locale
292  export LANG LANGUAGE
293
294  # configure keyboard layout, read in already set values first:
295  [ -r /etc/sysconfig/keyboard ] && . /etc/sysconfig/keyboard
296
297  # now allow keyboard override by boot commandline for later use:
298  KKEYBOARD="$(getbootparam 'keyboard' 2>>$DEBUG)"
299  [ -n "$KKEYBOARD" ] && KEYTABLE="$KKEYBOARD"
300  # notce: de/at is a bad choice, so take de-latin1-nodeadkeys instead:
301  [[ "$KKEYBOARD" == 'de' ]] && KEYTABLE=de-latin1-nodeadkeys
302  [[ "$KKEYBOARD" == 'at' ]] && KEYTABLE=de-latin1-nodeadkeys
303
304  # modify /etc/sysconfig/keyboard only in live-cd mode:
305  if [ -z "$INSTALLED" ] ; then
306
307    local LANGUAGE="$BOOT_LANGUAGE"
308    . /etc/grml/language-functions
309    # allow setting xkeyboard explicitly different than console keyboard
310    KXKEYBOARD="$(getbootparam 'xkeyboard' 2>>$DEBUG)"
311    if [ -n "$KXKEYBOARD" ]; then
312       XKEYBOARD="$KXKEYBOARD"
313       KDEKEYBOARD="$KXKEYBOARD"
314    elif [ -n "$KKEYBOARD" ]; then
315       XKEYBOARD="$KKEYBOARD"
316       KDEKEYBOARD="$KKEYBOARD"
317    fi
318
319    # duplicate of previous code to make sure /etc/grml/language-functions
320    # does not overwrite our values....
321    # now allow keyboard override by boot commandline for later use:
322    KKEYBOARD="$(getbootparam 'keyboard' 2>>$DEBUG)"
323    [ -n "$KKEYBOARD" ] && KEYTABLE="$KKEYBOARD"
324    # notce: de/at is a bad choice, so take de-latin1-nodeadkeys instead:
325    [[ "$KKEYBOARD" == 'de' ]] && KEYTABLE=de-latin1-nodeadkeys
326    [[ "$KKEYBOARD" == 'at' ]] && KEYTABLE=de-latin1-nodeadkeys
327
328    # write keyboard related variables to file for later use
329    [ -d /etc/sysconfig ] || mkdir /etc/sysconfig
330    if ! [ -e /etc/sysconfig/keyboard ] ; then
331       echo "KEYTABLE=\"$KEYTABLE\""          > /etc/sysconfig/keyboard
332       echo "XKEYBOARD=\"$XKEYBOARD\""       >> /etc/sysconfig/keyboard
333       echo "KDEKEYBOARD=\"$KDEKEYBOARD\""   >> /etc/sysconfig/keyboard
334       echo "KDEKEYBOARDS=\"$KDEKEYBOARDS\"" >> /etc/sysconfig/keyboard
335    fi
336  fi
337
338  [ -r /etc/sysconfig/keyboard ] && . /etc/sysconfig/keyboard
339
340  # activate unicode console if running within utf8 environment
341  if [ -r /etc/default/locale ] ; then
342     if grep -q "LANG=.*UTF" /etc/default/locale ; then
343        einfo "Setting up unicode environment."
344        unicode_start >>$DEBUG 2>&1 ; eend $?
345     fi
346  fi
347
348  # Set default keyboard before interactive setup
349  if [ -n "$KEYTABLE" ] ; then
350     einfo "Running loadkeys for ${WHITE}${KEYTABLE}${NORMAL} in background"
351     loadkeys -q $KEYTABLE &
352     eend $?
353  fi
354
355  # we have to set up all consoles, therefore loop it over all ttys:
356  NUM_CONSOLES=$(fgconsole --next-available 2>/dev/null)
357  if [ -n "$NUM_CONSOLES" ] ; then
358     NUM_CONSOLES=$(expr ${NUM_CONSOLES} - 1)
359     [ ${NUM_CONSOLES} -eq 1 ] && NUM_CONSOLES=6
360  fi
361  CUR_CONSOLE=$(fgconsole 2>/dev/null)
362
363  if [ -x "$(which setfont)" ] ; then
364     use_setfont=true
365  elif [ -x "$(which consolechars)" ] ; then
366     use_consolechars=true
367  else
368     eerror "Neither setfont nor consolechars tool present, can not set font."
369     eend 1
370     return 1
371  fi
372
373  if [ -n "$CHARMAP" ] ; then
374     einfo "Setting font to ${CHARMAP}"
375     RC=0
376     for vc in $(seq 0 ${NUM_CONSOLES}) ; do
377         if $use_setfont ; then
378           setfont -C /dev/tty${vc} $CHARMAP ; RC=$?
379         elif $use_consolechars ; then
380           consolechars --tty=/dev/tty${vc} -m ${CHARMAP} ; RC=$?
381         fi
382     done
383     if [ -n "$CUR_CONSOLE" ] ; then
384        [ "$CUR_CONSOLE" != "serial" ] && chvt $CUR_CONSOLE
385     fi
386     eend $RC
387  fi
388
389  if checkbootparam 'noconsolefont' ; then
390     ewarn "Skipping setting console font as requested on boot commandline." ; eend 0
391  else
392     if [ -n "$CONSOLEFONT" ] ; then
393        einfo "Setting font to ${CONSOLEFONT}"
394        RC=0
395        for vc in $(seq 0 ${NUM_CONSOLES}) ; do
396            if $use_setfont ; then
397              setfont -C /dev/tty${vc} ${CONSOLEFONT} ; RC=$?
398            elif $use_consolechars ; then
399              consolechars --tty=/dev/tty${vc} -f ${CONSOLEFONT} ; RC=$?
400            fi
401        done
402        if [ -n "$CUR_CONSOLE" ] ; then
403           [ "$CUR_CONSOLE" != "serial" ] && chvt $CUR_CONSOLE
404        fi
405        eend $RC
406     fi
407  fi
408
409  eoutdent
410 }
411 # }}}
412
413 # {{{ Set hostname
414 config_hostname(){
415   if ! checkbootparam 'hostname' ; then
416     return 0
417   fi
418
419   HOSTNAME="$(getbootparam 'hostname' 2>>$DEBUG)"
420   if [ -z "$HOSTNAME" ] && [ -x /usr/bin/random-hostname ] ; then
421     einfo "Generating random hostname as no hostname was specified."
422     HOSTNAME="$(/usr/bin/random-hostname)"
423     eend $?
424   fi
425
426   einfo "Setting hostname to $HOSTNAME as requested."
427   grml-hostname $HOSTNAME >>$DEBUG
428   eend $?
429 }
430 # }}}
431
432 # fstabuser (needed when running from harddisk with username != grml {{{
433 config_userfstab(){
434   # force load of build-in and local config
435   [ -r /etc/grml/autoconfig ] && . /etc/grml/autoconfig
436   [ -r /etc/grml/autoconfig ] && . /etc/grml/autoconfig.local
437
438   # 1st. try configured fstab user
439   if [ -n "$CONFIG_FSTAB_USER" ] ; then
440      fstabuser=$(getent passwd $CONFIG_FSTAB_USER | cut -d: -f1)
441   fi
442
443   # 2nd. use standard user id
444   [ -n "$fstabuser" ] || fstabuser=$(getent passwd 1000 | cut -d: -f1)
445
446   # 3rd. use standard user name
447   [ -n "$fstabuser" ] || fstabuser=$(getent passwd grml | cut -d: -f1)
448
449   # if not yet set fall back to 'root' user, avoid bad /etc/fstab
450   [ -n "$fstabuser" ] || fstabuser='root'
451 }
452 # }}}
453
454 # local_user (needed when running with username != grml {{{
455 config_userlocal() {
456
457   # force load of build-in and local config
458   [ -r /etc/grml/autoconfig ] && . /etc/grml/autoconfig
459   [ -r /etc/grml/autoconfig ] && . /etc/grml/autoconfig.local
460
461   # 1st. try id of primary user
462   localuser=$(getent passwd 1000 | cut -d: -f1)
463
464   # 2nd. use name standard user
465   [ -n "$localuser" ] || localuser=$(getent passwd grml | cut -d: -f1)
466 }
467 # }}}
468
469 # {{{ mount configfs
470 config_configfs() {
471   einfo "Mounting configfs"
472   CONFIGFS_DIR=/sys/kernel/config/
473   modprobe configfs 2>/dev/null 1>&2
474   if ! [  -d "$CONFIGFS_DIR" ] ; then
475     eindent
476     einfo "$CONFIGFS_DIR does not exist, can't mount directory"
477     eend 1
478     eoutdent
479   else
480     mount -t configfs configfs "$CONFIGFS_DIR" 2>/dev/null 1>&2
481     eend $?
482   fi
483 }
484 # }}}
485
486 # {{{ Set clock (Local time is more often used than GMT, so it is default)
487 config_time(){
488  # don't touch the files if running from harddisk:
489  if [ -z "$INSTALLED" ]; then
490     # The default hardware clock timezone is stated as representing local time.
491     UTC="--localtime"
492     grep -q "^UTC=" /etc/default/rcS || echo "UTC=no" >> /etc/default/rcS
493     checkbootparam 'utc'       >>$DEBUG 2>&1 && sed -i "s|^UTC=.*$|UTC=yes|" /etc/default/rcS
494     checkbootparam 'gmt'       >>$DEBUG 2>&1 && sed -i "s|^UTC=.*$|UTC=yes|" /etc/default/rcS
495     checkbootparam 'localtime' >>$DEBUG 2>&1 && sed -i "s|^UTC=.*$|UTC=no|"  /etc/default/rcS
496     grep -q -i "^UTC=yes" /etc/default/rcS && UTC="-u"
497     # hwclock uses the TZ variable
498     KTZ="$(getbootparam 'tz' 2>>$DEBUG)"
499     [ -z "$KTZ" ] && [ -r /etc/timezone ] && KTZ=$(cat /etc/timezone)
500     if [ ! -f "/usr/share/zoneinfo/$KTZ" ] ; then
501        ewarn "Warning: unknown timezone $KTZ" ; eend 1
502        KTZ="UTC"
503        ewarn "Falling back to timezone $KTZ" ; eend 0
504     fi
505
506     if ! [ -r /dev/rtc ] ; then
507       ewarn "Warning: realtime clock not available, trying to execute hwclock anyway." ; eend 0
508     fi
509
510     ERROR=$(TZ="$KTZ" hwclock $UTC -s 2>&1 | head -1) ; RC=$?
511     if [ -n "$ERROR" ] ; then
512        eindent
513        ERROR=$(TZ="$KTZ" hwclock $UTC -s --directisa 2>&1 | head -1)
514        if [ -n "$ERROR" ] ; then
515           eerror "Problem running hwclock: $ERROR" ; eend 1
516        fi
517        eoutdent
518     fi
519
520  fi
521 }
522 # }}}
523
524 # {{{ print kernel info
525 config_kernel(){
526   if $VIRTUAL && [ -n "$VIRTUAL_ENV" ] ; then
527     einfo "Running Linux Kernel $KERNEL inside $VIRTUAL_ENV" ; eend 0
528   else
529     einfo "Running Linux Kernel $KERNEL" ; eend 0
530   fi
531
532   if [ -r /proc/cpuinfo ] ; then
533     if egrep -q '^flags.*(vmx|svm)' /proc/cpuinfo ; then
534       eindent
535       einfo 'CPU(s) featuring virtualization technology detected' ; eend 0
536       eoutdent
537     fi
538   fi
539
540   if [ -d /proc/xen ] ; then
541     eindent
542     einfo 'Running kernel featuring support for Xen detected' ; eend 0
543     eoutdent
544   fi
545 }
546 # }}}
547
548 # {{{ ld.so.cache + depmod
549 config_ld_mod(){
550 if [ -n "$INSTALLED" ]; then
551  if ! [ -r /etc/grml.first.boot ] ; then
552   einfo "Running from HD for the first time, regenerate ld.so.cache and modules.dep:"
553   eindent
554 # Regenerate ld.so.cache and module dependencies on HD
555     einfo "Running ldconfig" ; ldconfig  ; eend $?
556     einfo "Running depmod"   ; depmod -a ; eend $?
557     touch /etc/grml.first.boot
558     eend 0
559   eoutdent
560  fi
561 fi
562 }
563 # }}}
564
565 # {{{ timezone
566 config_timezone(){
567  # don't touch the files if running from harddisk:
568  if [ -z "$INSTALLED" ]; then
569     KTZ="$(getbootparam 'tz' 2>>$DEBUG)"
570     if [ -n "$KTZ" ] ; then
571        if [ ! -f "/usr/share/zoneinfo/$KTZ" ]
572        then
573           ewarn "Warning: unknown timezone $KTZ"; eend 0
574        else
575           einfo "Setting timezone."
576           # update debconf
577           area=$(echo $KTZ | cut -d '/' -f1)
578           zone=$(echo $KTZ | cut -d '/' -f2)
579           echo "tzdata tzdata/Areas       select $area" | debconf-set-selections
580           echo "tzdata tzdata/Zones/$area select $zone" | debconf-set-selections
581           # update files
582           echo $KTZ > /etc/timezone
583           rm -f /etc/localtime
584           cp "/usr/share/zoneinfo/$KTZ" /etc/localtime ; eend $?
585        fi
586     fi
587  fi
588 }
589 # }}}
590
591 # small computer / nearly no ram {{{
592 config_small(){
593
594 RAM=$(/usr/bin/gawk '/MemTotal/{print $2}' /proc/meminfo)
595 # MEM=$(/usr/bin/gawk 'BEGIN{m=0};/MemFree|Cached|SwapFree/{m+=$2};END{print m}' /proc/meminfo)
596 eindent
597
598 if checkbootparam 'small'; then
599   einfo "Information: ${RAM} kB of RAM available." ; eend 0
600   einfo "Bootoption small detected. Activating small system."
601   if [ -r /etc/inittab.small ] ; then
602     mv /etc/inittab /etc/inittab.normal
603     mv /etc/inittab.small /etc/inittab
604   else
605     sed -i 's/^9/#&/' /etc/inittab
606     sed -i 's/^10/#&/' /etc/inittab
607     sed -i 's/^11/#&/' /etc/inittab
608     sed -i 's/^12/#&/' /etc/inittab
609   fi
610   /sbin/telinit q ; eend $?
611 else
612   if checkgrmlsmall ; then
613     if [[ $RAM -lt 25000 ]] ; then
614       ewarn "Information: ${RAM} kB of RAM available." ; eend 1
615       ewarn "At least 32MB of RAM should be available for grml-small." ; eend 1
616       ewarn "Use the bootoption small to save some more MB of memory usage." ; eend 0
617       ewarn "Dropping you into a rescue shell. To continue booting exit the shell." ; eend 0
618       /bin/zsh --login
619     else
620       einfo "Information: ${RAM} kB of RAM available." ; eend 0
621     fi
622   else
623     if [[ $RAM -lt 58000 ]] ; then
624       ewarn "Information: ${RAM} kB of RAM available." ; eend 1
625       ewarn "At least 64MB of RAM should be available for grml." ; eend 1
626       ewarn "Use the bootoption small to save some more MB of memory usage." ; eend 0
627       ewarn "Dropping you into a rescue shell. To continue booting exit the shell." ; eend 0
628       /bin/zsh --login
629     else
630       einfo "Information: ${RAM} kB of RAM available." ; eend 0
631     fi
632   fi
633 fi
634 eoutdent
635 }
636 # }}}
637
638 # skip startup of w3m {{{
639 config_fast(){
640 if checkbootparam 'fast'; then
641   ewarn "Bootoption fast detected. Skipping startup of grml-quickconfig."
642     sed -i '/1:/s#/usr/share/grml-scripts/run-welcome#/bin/zsh#' /etc/inittab
643   /sbin/telinit q ; eend $?
644 fi
645 }
646 # }}}
647
648 # activate serial console {{{
649 config_console(){
650 if checkbootparam 'console'; then
651   local line
652   local ws
653   ws='   '
654
655   einfo "Bootoption for serial console detected:"
656
657   line="$CMDLINE x "
658   this=""
659   line="${line#*[$ws]}"
660   local telinitq=""
661   while [ -n "$line" ]; do
662     case "$this" in
663       console=*)
664         local serial="$this"
665         local device="${this%%,*}"
666         local device="${device##*=}"
667         if echo $serial | grep -q ttyS ; then
668           local option="${serial##*,}"
669           # default (works for kvm & CO):
670           local speed="115200,57600,38400,19200,9600,4800,2400,1200";
671           # ... unless overriden by command line:
672           case "$option" in
673             115200*) speed=115200 ;;
674              57600*) speed=57600 ;;
675              38400*) speed=38400 ;;
676              19200*) speed=19200 ;;
677               9600*) speed=9600 ;;
678               4800*) speed=4800 ;;
679               2400*) speed=2400 ;;
680               1200*) speed=1200 ;;
681           esac
682           eindent
683             einfo "Activating console login on device ${device} with speed ${speed}."
684             local number="${device#ttyS}"
685             sed -i "/^T$number:/d;/^#grmlserial#/iT$number:23:respawn:/bin/bash -c \"/sbin/getty -L $device -l /usr/share/grml-scripts/run-welcome $speed vt100 || sleep 30\"" /etc/inittab
686             eend $?
687             telinitq="1"
688           eoutdent
689         fi
690         ;;
691     esac
692     this="${line%%[$ws]*}"
693     line="${line#*[$ws]}"
694   done
695
696   if [ -n "$telinitq" ]; then
697     /sbin/telinit q
698   fi
699   eend $?
700 fi
701 }
702 # }}}
703
704 # {{{ copy passwd-lockfile to ramdisk (fix unionfs-behaviour)
705 # otherwise we will get: passwd: Authentication token lock busy
706 config_fix_passwd(){
707  if [ -z "$INSTALLED" ] ; then
708   touch /etc/.pwd.lock
709  fi
710 }
711 # }}}
712
713 # {{{ CD Checker
714 config_testcd(){
715 if checkbootparam 'testcd' ; then
716   einfo "Checking CD data integrity as requested by '${WHITE}testcd${NORMAL}' boot option."
717   eindent
718
719   local ERROR=true
720   local FOUND_FILE=false
721   local logfile='/tmp/md5sum.log'
722
723   rm -f "$logfile"
724
725   for md5 in $(find "${LIVECD_PATH}" -name md5sums) ; do
726     einfo "Checking files against $md5, this may take a while..."
727
728     FOUND_FILE=true
729     OLD_PWD=$(pwd)
730     cd $(dirname "$md5")
731     md5sum -c $(basename "$md5") |& tee -a "${logfile}"
732     if [ $pipestatus[1] -eq 0 ] ; then
733       ERROR=false
734     fi
735     cd "${OLD_PWD}"
736   done
737
738   if ! $FOUND_FILE ; then
739     eerror 'Error: Could not find md5sum file' ; eend 1
740     return
741   fi
742
743   if ! $ERROR ; then
744     einfo "Everything looks OK" ; eend 0
745   else
746     eerror 'Checksum failed for theses files:' ; eend 1
747     egrep -v '(^md5sum:|OK$)' "${logfile}"
748     eerror 'Data on the medium is possibly incomplete/damaged or RAM of your system is broken.' ; eend 1
749     einfon "Hit return to continue, or press the power button to shut down system."
750     read a
751   fi
752
753   eoutdent
754 fi
755 }
756 # }}}
757
758 # {{{ blacklist specific module [ used in /etc/init.d/udev ]
759 config_blacklist(){
760 if checkbootparam 'blacklist' ; then
761  if [ -z "$INSTALLED" ]; then
762   einfo "Bootoption blacklist found."
763   BLACK="$(getbootparam 'blacklist' 2>>$DEBUG)"
764   BLACKLIST_FILE='/etc/modprobe.d/grml.conf'
765   if [ -n "$BLACK" ] ; then
766     for module in $(echo ${BLACK//,/ }) ; do
767         einfo "Blacklisting module ${module} via ${BLACKLIST_FILE}."
768         echo "# begin entry generated by config_blacklist of grml-autoconfig" >> "$BLACKLIST_FILE"
769         echo "blacklist $module"     >> "$BLACKLIST_FILE"
770         echo "alias     $module off" >> "$BLACKLIST_FILE"
771         echo "# end   entry generated by config_blacklist of grml-autoconfig" >> "$BLACKLIST_FILE" ; eend $?
772     done
773   else
774    eerror "No given module for blacklist found. Blacklisting will not work therefore."
775   fi
776  else
777   ewarn "Backlisting via bootoption is not intended for use on harddisk installations." ; eend 1
778   eindent
779    einfo "Please blacklist the module(s) manually using the 'blacklist' script."
780   eoutdent
781  fi
782 fi
783 }
784 # }}}
785
786 # {{{ ACPI
787 config_acpi(){
788 if checkbootparam 'noacpi'; then
789   ewarn "ACPI: Not loading modules as requested by boot option \"noacpi\"." ; eend 0
790 elif checkbootparam 'nogrmlacpi' ; then
791   ewarn "ACPI: Not loading modules as requested by boot option \"nogrmlacpi\"." ; eend 0
792 elif [ ! -d /proc/acpi ] ; then
793   ewarn "ACPI: Kernel support not present." ; eend 0
794 else
795   einfo "ACPI: Loading modules (disable with boot option noacpi / nogrmlacpi): "
796   eindent
797   found=""
798   for a in /lib/modules/$KERNEL/kernel/drivers/acpi/*; do
799     basename="${a##*/}"
800     basename="${basename%%.*}"
801     case "$basename" in *_acpi)
802      egrep -qi "${basename%%_acpi}" /proc/acpi/dsdt 2>>$DEBUG || continue ;;
803     esac
804     modprobe $basename >>$DEBUG 2>&1 && found="yes"
805     local BASE="$BASE $basename"
806   done
807   if [ -n "$found" ] ; then
808     einfo "$BASE"  ; eend 0
809   else
810     ewarn "(none)" ; eend 1
811   fi
812   if ! pgrep acpid >/dev/null ; then
813     einfo "Starting acpi daemon."
814     /etc/init.d/acpid start >>$DEBUG 2>&1 ; eend $?
815   else
816     ewarn "acpi daemon already running."
817     eend 0
818   fi
819   eoutdent
820 fi
821 }
822 # }}}
823
824 # {{{ Collect partitions from /proc/partitions first for enabling DMA
825 check_partitions(){
826 partitions=""
827 IDEDISKS=""
828 while read major minor blocks partition relax; do
829   partition="${partition##*/}"
830   [ -z "$partition" -o ! -e "/dev/$partition" ] && continue
831   case "$partition" in
832     hd?) IDEDISKS="$IDEDISKS $partition";;                # IDE  Harddisk, entire disk
833     sd?) ;;                                               # SCSI Harddisk, entire disk
834 #    [hs]d*) partitions="$partitions /dev/$partition";;    # IDE or SCSI disk partition
835     [hs]d*|ub*) partitions="$partitions /dev/$partition";;    # IDE, USB or SCSI disk partition
836   esac
837 done <<EOT
838 $(awk 'BEGIN{old="__start"}{if($0==old){exit}else{old=$0;if($4&&$4!="name"){print $0}}}' /proc/partitions)
839 EOT
840 }
841 check_partitions >/dev/null 2>&1 # avoid output "check_partitions:3: read-only file system"
842 # }}}
843
844 # {{{ Start brltty
845 config_brltty() {
846   if checkbootparam 'brltty' ; then
847     [ -x /lib/brltty/brltty.sh ] && /lib/brltty/brltty.sh
848   fi
849 }
850 # }}}
851
852 # {{{ Enable DMA for all IDE drives now if not disabled
853 # Notice: Already done by linuxrc, but make sure it's done also on harddisk-installed systems
854 config_dma(){
855 if checkbootparam 'nodma'; then
856   ewarn "Skipping DMA accelleration as requested on boot commandline." ; eend 0
857 else
858   for d in $(cd /proc/ide 2>>$DEBUG && echo hd[a-z]); do
859     if test -d /proc/ide/$d; then
860       if egrep -q 'using_dma[ \t]+0' /proc/ide/$d/settings 2>>$DEBUG; then
861         MODEL="$(cat /proc/ide/$d/model 2>>$DEBUG)"
862         test -z "$MODEL" && MODEL="[GENERIC IDE DEVICE]"
863         einfo "Enabling DMA acceleration for: ${WHITE}$d        ${YELLOW}[${MODEL}]${NORMAL}"
864         echo "using_dma:1" >/proc/ide/$d/settings
865         eend 0
866       fi
867     fi
868   done
869 fi
870 }
871 # }}}
872
873 # {{{ Start creating /etc/fstab with HD partitions and USB SCSI devices now
874 config_fstab(){
875
876 NOSWAP="yes" # we do not use swap by default!
877 if checkbootparam 'swap' || checkbootparam 'anyswap' ; then
878    NOSWAP=''
879    checkbootparam 'anyswap' && export ANYSWAP='yes' || export ANYSWAP=""
880 fi
881
882 # Scan for swap, config, homedir - but only in live-mode
883 if [ -z "$INSTALLED" ] ; then
884    [ -z "$NOSWAP" ] && einfo "Searching for swap partition(s) as requested."
885    GRML_IMG=""
886    GRML_SWP=""
887    HOMEDIR="$(getbootparam 'home')"
888    if [ -n "$partitions" ]; then
889       while read p m f relax; do
890         case "$p" in *fd0*|*proc*|*sys*|*\#*) continue;; esac
891         partoptions="users,exec"
892         fnew=""
893         # it's a swap partition?
894         case "$f" in swap)
895           eindent
896           if [ -n "$NOSWAP" ]; then
897              ewarn "Ignoring swap partition ${WHITE}$p${NORMAL}. (Force usage via boot option 'swap', or execute grml-swapon)"
898              eend 0
899           else
900              case "$(dd if=$p bs=1 count=6 skip=4086 2>/dev/null)" in
901                    S1SUSP|S2SUSP|pmdisk|[zZ]*)
902                      if [ -n "$ANYSWAP" ] ; then
903                         einfo "Using swap partition ${WHITE}${p}${NORMAL} [bootoption anyswap found]."
904                         swapon $p 2>>$DEBUG ; eend $?
905                      else
906                         ewarn "Suspend signature on ${WHITE}${p}${NORMAL} found, not using as swap. (Force usage via boot option: anyswap)"
907                      fi
908                      ;;
909                    *)
910                      if [[ "$p" == LABEL* ]] ; then
911                         p=$(blkid -t $p | awk -F: '{print $1}')
912                      fi
913                      if grep -q $p /proc/swaps ; then
914                         ewarn "Not using swap partition ${WHITE}${p}${NORMAL} as it is already in use." ; eend 0
915                      else
916                         if [ -b "$p" ] ; then
917                         einfo "Using swap partition ${WHITE}${p}${NORMAL}."
918                         swapon $p 2>>$DEBUG ; eend $?
919                         else
920                         ewarn "$p is not a valid block device - not using it therefore." ; eend 0
921                         fi
922                      fi
923                      ;;
924              esac # dd-check
925           fi # -n "$NOSWAP
926           eoutdent
927           continue
928           ;;
929         esac # it's a swap partition?
930
931         # mount read-only
932         MOUNTOPTS="ro"
933         case "$f" in
934           vfat|msdos|ntfs) MOUNTOPTS="$MOUNTOPTS,uid=${fstabuser},gid=${fstabuser}" ;;
935           ext2|ext3|reiserfs|jfs|reiser4|xfs) MOUNTOPTS="$MOUNTOPTS,noatime" ;;
936           *) continue ;;
937           # *) NONEFOUND='1'; continue ;;
938         esac
939
940         # use a swapfile
941         if [ -z "$NOSWAP" ] ; then
942            mount -o "$MOUNTOPTS" -t $f $p $m 2>>$DEBUG && MOUNTED=1 || continue
943            # Activate swapfile, if exists
944            SWAPFILE="$(/bin/ls -1d $m/[Gg][Rr][Mm][Ll].[Ss][Ww][Pp] 2>/dev/null)"
945         fi
946         if [ -z "$NOSWAP" -a -n "$SWAPFILE" -a -f "$SWAPFILE" ]; then
947            mount -o remount,rw $m && MOUNTED=1
948            if swapon "$SWAPFILE" 2>>$DEBUG ; then
949               eindent
950                 einfo "Using GRML swapfile ${WHITE}${SWAPFILE}${NORMAL}."
951               eoutdent
952               fnew="$SWAPFILE swap swap defaults 0 0"
953               grep -q "$fnew" "/etc/fstab" || echo "$fnew" >> /etc/fstab
954               GRML_SWP="$GRML_SWP $SWAPFILE"
955               eend 0
956            fi
957            mount -o remount,ro $m 2>>$DEBUG && MOUNTED=1
958         fi
959
960         # use a image as home
961         IMAGE="$(/bin/ls -1d $m/[Gg][Rr][Mm][Ll].[Ii][Mm][Gg] 2>/dev/null)"
962         if [ -z "$GRML_IMG" -a -n "$IMAGE" -a -f "$IMAGE" ]; then
963            if [ -n "$HOMEDIR" ]; then
964               if [ "$HOMEDIR" != "scan" -a "$HOMEDIR" != "$IMAGE" -a "$HOMEDIR" != "${IMAGE%/*.*}" ]; then
965                  continue
966               fi
967            fi
968            if type -a grml-image >/dev/null 2>&1 && grml-image "$IMAGE" </dev/console >/dev/console 2>&1; then
969               GRML_IMG="$IMAGE"
970               mount -o remount,ro $m 2>>$DEBUG && MOUNTED=1
971            fi
972         fi
973         eend 0
974
975         # Umount, if not in use
976         [ -n "$MOUNTED" ] && umount -r $m 2>/dev/null
977
978       done <<EOT
979       $(cat /etc/fstab)
980 EOT
981    fi # -n $partitions
982 fi # -z $INSTALLED
983 }
984 # }}}
985
986 # {{{ Mouse
987 config_mouse(){
988 if [ -n "$MOUSE_DEVICE" ] ; then
989   einfo "Detecting mouse: ${MOUSE_FULLNAME} at ${MOUSE_DEVICE}" ; eend $?
990 fi
991 }
992 # }}}
993
994 # {{{ IPv6 configuration
995 # Load IPv6 kernel module and print IP adresses
996 config_ipv6(){
997 if checkbootparam 'ipv6'; then
998   einfo "Enabling IPv6 as requested on boot commandline (sleeping for 2 seconds)"
999   modprobe ipv6
1000   # we probably need some time until stateless autoconfiguration has happened
1001   sleep 2
1002   NETDEVICES="$(awk -F: '/eth.:|tr.:|wlan.:/{print $1}' /proc/net/dev 2>>$DEBUG)"
1003   for DEVICE in `echo "$NETDEVICES"`; do
1004     eindent
1005       einfo "$DEVICE:"
1006       ADDRESSES="$(ifconfig $DEVICE | awk '/.*inet6 addr:.*/{print $3}')"
1007       COUNT="$(ifconfig $DEVICE | awk '/.*inet6 addr:.*/{ sum += 1};END {print sum }')"
1008       eindent
1009         for ADDR in `echo "$ADDRESSES"` ; do
1010             einfo "$ADDR"
1011         done
1012         if [ "$COUNT" -eq "0" ] ; then
1013            einfo "(none)" ; eend 1
1014         fi
1015       eoutdent
1016     eoutdent
1017   done
1018   eend 0
1019 fi
1020 }
1021 # }}}
1022
1023 # {{{ CPU-detection
1024 config_cpu(){
1025 if checkbootparam 'nocpu'; then
1026   ewarn "Skipping CPU detection as requested on boot commandline." ; eend 0
1027   return 0
1028 fi
1029
1030 if [[ $(grep -c processor /proc/cpuinfo) -gt 1 ]] ; then
1031    einfo "Found CPU:"
1032    CPU=$(awk -F: '/^processor/{printf " Processor"$2" is"};/^model name/{printf $2};/^vendor_id/{printf vendor};/^cpu MHz/{printf " %dMHz",int($2)};/^cache size/{printf ","$2" Cache"};/^$/{print ""}' /proc/cpuinfo 2>>$DEBUG)
1033    echo $CPU | sed 's/ \{1,\}/ /g'
1034    eend 0
1035 else
1036    einfo "Found CPU: `awk -F: '/^processor/{printf " Processor"$2" is"};/^model name/{printf $2};/^vendor_id/{printf vendor};/^cpu MHz/{printf " %dMHz",int($2)};/^cache size/{printf ","$2" Cache"};/^$/{print ""}' /proc/cpuinfo 2>>$DEBUG` " ; eend 0
1037 fi
1038
1039 # no cpufreq setup inside VirtualBox
1040 if $VIRTUALBOX ; then
1041    einfo 'Virtual Box detected, skipping cpufreq setup.' ; eend 0
1042    return 0
1043 fi
1044
1045 if [ -x /etc/init.d/loadcpufreq ] ; then
1046    einfo "Trying to set up cpu frequency scaling:"
1047    eindent
1048    SKIP_CPU_GOVERNOR=''
1049    LOADCPUFREQ=$(mktemp)
1050    /etc/init.d/loadcpufreq start >"$LOADCPUFREQ" 2>&1 ; RC=$?
1051    if grep -q FATAL "$LOADCPUFREQ" ; then
1052       eindent
1053         SKIP_CPU_GOVERNOR=1
1054         oldIFS="$IFS"
1055         IFS="
1056 "
1057          for line in $(grep FATAL "$LOADCPUFREQ" | sed 's/.*FATAL: //; s/ (.*)//') ; do
1058              eerror "$line" ; eend $RC
1059          done
1060          IFS="$oldIFS"
1061       eoutdent
1062    elif grep -q done "$LOADCPUFREQ" ; then
1063       MODULE=$(grep done "$LOADCPUFREQ" | sed 's/.*done (\(.*\))./\1/')
1064       if [ -n "$MODULE" -a "$MODULE" != none ]; then
1065          einfo "Loading cpufreq kernel module $MODULE" ; eend 0
1066       else
1067          SKIP_CPU_GOVERNOR=1
1068          ewarn "Could not find an appropriate kernel module for cpu frequency scaling." ; eend 1
1069       fi
1070    fi
1071
1072    rm -f $LOADCPUFREQ
1073
1074    if [ -z "$SKIP_CPU_GOVERNOR" ] ; then
1075      if grep -vq ondemand /sys/devices/system/cpu/cpu0/cpufreq/scaling_available_governors; then
1076        einfo "Loading cpufreq_ondemand"
1077        modprobe cpufreq_ondemand
1078        eend $?
1079      fi
1080
1081      einfo "Setting ondemand governor"
1082      RC=0
1083      for file in $(find /sys/devices/system/cpu/ -name scaling_governor 2>/dev/null) ; do
1084        echo ondemand > $file || RC=1
1085      done
1086      eend $RC
1087    fi # cpu-governor
1088
1089    eoutdent
1090 fi
1091 }
1092 # }}}
1093
1094 # {{{ autostart of ssh
1095 config_ssh(){
1096 if checkbootparam 'ssh' ; then
1097    local PASSWD
1098    PASSWD="$(getbootparam 'ssh' 2>>$DEBUG)"
1099
1100    config_userlocal
1101    einfo "Bootoption ssh found, trying to set password for root and user $localuser"
1102    [ -z "$localuser" ] && eend 1
1103
1104    eindent
1105    if [ -z "$PASSWD" ] ; then
1106      set_passwd && ewarn "No given password for found. Using random password: $PASSWD" && eend 0
1107    fi
1108    eoutdent
1109
1110    if [ -n "$PASSWD" ] ; then
1111       chpass_options=""
1112       if chpasswd --help 2>&1 | grep -q -- '-m,' ; then
1113         chpass_options="-m"
1114       fi
1115
1116       echo "$localuser:$PASSWD" | chpasswd $chpass_options
1117       echo "root:$PASSWD" | chpasswd $chpass_options
1118
1119       eindent
1120       ewarn "Warning: please change the password for root and user $localuser as soon as possible!"
1121       eoutdent
1122    fi
1123
1124    einfo "Starting secure shell server in background for root and user $localuser"
1125    /etc/init.d/rmnologin start >>$DEBUG 2>>$DEBUG
1126    /etc/init.d/ssh start >>$DEBUG 2>>$DEBUG &
1127    eend $?
1128
1129 fi
1130 }
1131
1132 # }}}
1133
1134 # {{{ display hostkeys of SSH server
1135 config_display_ssh_fingerprints() {
1136   if ! ls /etc/ssh/ssh_host_\*_key >/dev/null 2>&1 ; then
1137     return 0 # no SSH host keys present
1138   fi
1139
1140   einfo "SSH key fingerprints:"
1141   for file in /etc/ssh/ssh_host_*_key ; do
1142     einfon
1143     ssh-keygen -l -f $file
1144   done | column -t
1145   eend $?
1146 }
1147 # }}}
1148
1149 # {{{ autostart of x11vnc
1150 config_vnc(){
1151 if checkbootparam 'vnc' ; then
1152    config_userlocal
1153    VNC_PASSWD=''
1154    VNC_PASSWD="$(getbootparam 'vnc' 2>>$DEBUG)"
1155    einfo "Bootoption vnc found, trying to set password for user $localuser."
1156    eindent
1157    if [ -z "$VNC_PASSWD" ] ; then
1158       if [ -x /usr/bin/apg ] ; then
1159          VNC_PASSWD="$(apg -M NL -a 0 -m 8 -x 12 -n 1)"
1160       elif [ -x /usr/bin/gpw ] ; then
1161          VNC_PASSWD="$(gpw 1)"
1162       elif [ -x /usr/bin/pwgen ] ; then
1163          VNC_PASSWD="$(pwgen -1 8)"
1164       elif [ -x /usr/bin/hexdump ] ; then
1165          VNC_PASSWD="$(dd if=/dev/urandom bs=14 count=1 2>/dev/null | hexdump | awk '{print $3 $4}')"
1166       elif [ -n "$RANDOM" ] ; then
1167          VNC_PASSWD="${localuser}${RANDOM}"
1168       else
1169          VNC_PASSWD=''
1170          eerror "Empty passphrase and neither pwgen nor hexdump nor \$RANDOM found. Skipping."
1171          eend 1
1172       fi
1173
1174       if [ -n "$VNC_PASSWD" ] ; then
1175          ewarn "No given password for vnc found. Using random password: $VNC_PASSWD" ; eend 0
1176       fi
1177    fi
1178    eoutdent
1179
1180    # finally check if we have a password we can use:
1181    if [ -n "$VNC_PASSWD" ] ; then
1182
1183       VNCDIR="/home/${localuser}/.vnc"
1184       [ -d "$VNCDIR" ] || mkdir "$VNCDIR"
1185
1186       if [ ! -x /usr/bin/x11vnc ] ; then
1187          eerror "Error: x11vnc not found - can not set up vnc. Please make sure to install the x11vnc package."
1188          eend 1
1189       else
1190          /usr/bin/x11vnc -storepasswd "$VNC_PASSWD" "$VNCDIR"/passwd ; eend $?
1191          /bin/chown -R "$localuser": "$VNCDIR"
1192       fi
1193    fi
1194    if checkbootparam 'vnc_connect' ; then
1195       VNC_CONNECT=''
1196       VNC_CONNECT="$(getbootparam 'vnc_connect' 2>>$DEBUG)"
1197       einfo "Bootoption vnc_connect found, will start vnc with connect to $VNC_CONNECT."
1198       #store the options in a file
1199       VNCDIR="/home/${localuser}/.vnc"
1200       [ -d "$VNCDIR" ] || mkdir "$VNCDIR"
1201       echo " --connect $VNC_CONNECT " >> $VNCDIR/options
1202    fi
1203 fi
1204 }
1205 # }}}
1206
1207 # {{{ set password for root and default user
1208 config_passwd(){
1209 if checkbootparam 'passwd' >>$DEBUG 2>&1; then
1210   local PASSWD
1211   PASSWD="$(getbootparam 'passwd' 2>>$DEBUG)"
1212
1213   config_userlocal
1214   einfo "Bootoption passwd found, trying to set password for root and user $localuser"
1215   [ -z "$localuser" ] && eend 1
1216
1217   eindent
1218   if [ -z "$PASSWD" ] ; then
1219     set_passwd && ewarn "No given password for found. Using random password: $PASSWD" && eend 0
1220   fi
1221   eoutdent
1222
1223   if [ -n "$PASSWD" ] ; then
1224     chpass_options=""
1225     if chpasswd --help 2>&1 | grep -q -- '-m,' ; then
1226       chpass_options="-m"
1227     fi
1228
1229     echo "$localuser:$PASSWD" | chpasswd $chpass_options
1230     echo "root:$PASSWD" | chpasswd $chpass_options
1231
1232     eindent
1233     ewarn "Warning: please change the password for root and user $localuser as soon as possible!"
1234     eoutdent
1235   fi
1236
1237 fi
1238
1239 if checkbootparam 'encpasswd' >>$DEBUG 2>&1; then
1240   local PASSWD
1241   PASSWD="$(getbootparam 'encpasswd' 2>>$DEBUG)"
1242
1243   if [ -z "$PASSWD" ] ; then
1244     eerror "No hashed password found, can not set password."
1245     eend 1
1246     return
1247   fi
1248
1249   config_userlocal
1250   einfo "Bootoption encpasswd found, trying to set hashed password for root and user $localuser"
1251   [ -z "$localuser" ] && eend 1
1252
1253   if [ -n "$PASSWD" ] ; then
1254     chpass_options="-e"
1255
1256     echo "$localuser:$PASSWD" | chpasswd $chpass_options
1257     echo "root:$PASSWD" | chpasswd $chpass_options
1258
1259     eindent
1260     ewarn "Warning: please change the password for root and user $localuser as soon as possible!"
1261     eoutdent
1262   fi
1263
1264 fi
1265 }
1266 # }}}
1267
1268 # {{{ Sound
1269 config_mixer () {
1270    if ! [ -x /usr/bin/amixer ] ; then
1271       eerror "amixer binary not available. Can not set sound volumes therefore."
1272       eend 1
1273    else
1274       if ! [ -r /proc/asound/cards ] ; then
1275          ewarn "No soundcard present, skipping mixer settings therefore."
1276          eend 0
1277          return
1278       fi
1279
1280       for card in $(cat /proc/asound/cards| grep -e '^\s*[0-9]' | awk '{print $1}') ; do
1281          einfo "Configuring soundcard \"$(awk -F\[ '/^ *'$card' \[/{ FS=" "; $0=$2; print $1}' < /proc/asound/cards)\""
1282          eindent
1283
1284          if checkbootparam 'vol' ; then
1285             VOL="$(getbootparam 'vol' 2>>$DEBUG)"
1286             if [ -z "$VOL" ] ; then
1287                eerror "Bootoption vol found but no volume level/parameter given. Using defaults (75%)."
1288                VOL='75'
1289                eend 1
1290             fi
1291          else
1292             VOL='75'
1293          fi
1294
1295          if checkbootparam 'nosound' ; then
1296             einfo "Muting sound devices on request."
1297             ERROR=$(amixer -q set Master mute)
1298             RC=$?
1299             if [ -n "$ERROR" ] ; then
1300                eindent
1301                eerror "Problem muting sound devices: $ERROR"
1302                eoutdent
1303             fi
1304             eend $RC
1305          elif [ -z "$INSTALLED" ] ; then
1306             einfo "Setting mixer volumes to level ${WHITE}${VOL}${NORMAL}."
1307
1308             if checkbootparam 'micvol' ; then
1309                MICVOL="$(getbootparam 'micvol' 2>>$DEBUG)"
1310                einfo "Setting microphone to ${WHITE}${MICVOL}${NORMAL}."
1311             else
1312                MICVOL=0
1313             fi
1314
1315             CONTROLS=$(amixer -c $card scontrols | awk -F"Simple mixer control " '{print $2}')
1316             IFSOLD=${IFS:-}
1317             IFS='
1318 '
1319             for CONTROL in ${=CONTROLS} ; do
1320                if ! echo "${CONTROL}" | grep -q -i "mic" ; then
1321                    if amixer -c $card sget "${CONTROL}" | grep -q 'Capabilities:.*pswitch' ; then
1322                       amixer -c $card -q set "${CONTROL}" unmute
1323                    fi
1324                    if amixer -c $card sget "${CONTROL}" | grep -q -P 'Capabilities:.*(pvolume| volume)' ; then
1325                       amixer -c $card -q set "${CONTROL}" "${VOL}"%
1326                    fi
1327                fi
1328
1329                if [ ${MICVOL} -ne 0 ] ; then
1330                   if amixer -c $card sget "${CONTROL}" | grep -q 'Capabilities:.*cswitch' ; then
1331                      amixer -c $card -q set "${CONTROL}" unmute
1332                   fi
1333                   if amixer -c $card sget "${CONTROL}" | grep -q 'Capabilities:.*cvolume' ; then
1334                      amixer -c $card -q set "${CONTROL}" $MICVOL%
1335                   fi
1336                   eend $?
1337                fi
1338             done
1339             IFS=$IFSOLD
1340          fi # checkbootparam 'nosound'
1341          eoutdent
1342       done
1343    fi
1344 }
1345 # }}}
1346
1347 # {{{ modem detection
1348 config_modem(){
1349 if checkbootparam 'nomodem'; then
1350   ewarn "Skipping check for AC97 modem controller as requested on boot commandline." ; eend 0
1351 else
1352   if [ -x /etc/init.d/sl-modem-daemon ] ; then
1353      if lspci | grep Intel | grep -q "AC'97 Modem Controller" ; then
1354         einfo "AC97 modem controller detected. Start it running 'Start sl-modem-daemon'."
1355         eend 0
1356      fi
1357   fi
1358 fi
1359 }
1360 # }}}
1361
1362 # {{{ wondershaper
1363 config_wondershaper(){
1364  if checkbootparam 'wondershaper' ; then
1365     WONDER="$(getbootparam 'wondershaper' 2>>$DEBUG)"
1366     CMD=wondershaper
1367     DEVICE=""
1368     DOWNSTREAM=""
1369     UPSTREAM=""
1370     if [ -n "$WONDER" ]; then
1371       # Extra options
1372       DEVICE="${WONDER%%,*}"
1373       R="${WONDER#*,}"
1374       if [ -n "$R" -a "$R" != "$WONDER" ]; then
1375         WONDER="$R"
1376         DOWNSTREAM="${WONDER%%,*}"
1377         R="${WONDER#*,}"
1378         if [ -n "$R" -a "$R" != "$WONDER" ]; then
1379           WONDER="$R"
1380           UPSTREAM="${WONDER%%,*}"
1381           R="${WONDER#*,}"
1382         fi
1383       fi
1384     fi
1385     [ -n "$DEVICE" ]     && CMD="$CMD $DEVICE"
1386     [ -n "$DOWNSTREAM" ] && CMD="$CMD $DOWNSTREAM"
1387     [ -n "$UPSTREAM" ]   && CMD="$CMD $UPSTREAM"
1388     einfo "Starting wondershaper (${CMD}) in background."
1389     ( sh -c $CMD & ) && eend 0
1390  fi
1391 }
1392 # }}}
1393
1394 # {{{ syslog-ng
1395 config_syslog(){
1396  if checkbootparam 'nosyslog'; then
1397     ewarn "Not starting syslog daemon as requested on boot commandline." ; eend 0
1398  else
1399     SYSLOGD=''
1400     [ -x /etc/init.d/syslog-ng ] && SYSLOGD='syslog-ng'
1401     [ -x /etc/init.d/rsyslog   ] && SYSLOGD='rsyslog'
1402     [ -x /etc/init.d/dsyslog   ] && SYSLOGD='dsyslog'
1403     [ -x /etc/init.d/sysklogd  ] && SYSLOGD='sysklogd'
1404     [ -x /etc/init.d/inetutils-syslogd ] && SYSLOGD='inetutils-syslogd'
1405
1406     if [ -z "$SYSLOGD" ] ; then
1407        eerror "No syslog daemon found." ; eend 1
1408     else
1409        einfo "Starting $SYSLOGD in background."
1410        /etc/init.d/$SYSLOGD start >>$DEBUG &
1411        eend 0
1412     fi
1413  fi
1414 }
1415 # }}}
1416
1417 # {{{ gpm
1418 config_gpm(){
1419  if checkbootparam 'nogpm'; then
1420   ewarn "Not starting GPM as requested on boot commandline." ; eend 0
1421  else
1422    if ! [ -r /dev/input/mice ] ; then
1423       eerror "No mouse found - not starting GPM." ; eend 1
1424    else
1425       einfo "Starting gpm in background."
1426       /etc/init.d/gpm start >>$DEBUG &
1427       # ( while [ ! -e /dev/psaux ]; do sleep 5; done; /etc/init.d/gpm start >>$DEBUG ) &
1428       eend 0
1429    fi
1430  fi
1431 }
1432 # }}}
1433
1434 # {{{ services
1435 config_services(){
1436  if checkbootparam 'services' ; then
1437     SERVICE="$(getbootparam 'services' 2>>$DEBUG)"
1438     SERVICELIST=$(echo "$SERVICE" | sed 's/,/\\n/g')
1439     SERVICENL=$(echo "$SERVICE" | sed 's/,/ /g')
1440     for service in $(echo -e $SERVICELIST) ; do
1441       # support running (custom) init scripts in non-blocking mode
1442       # if they contain the keyword "DO_NO_RUN_IN_BACKGROUND".
1443       if grep -q 'DO_NO_RUN_IN_BACKGROUND' "/etc/init.d/${service}" 2>>$DEBUG ; then
1444         einfo "Starting service ${service}."
1445         /etc/init.d/${service} start >>$DEBUG
1446       else
1447         einfo "Starting service ${service} in background."
1448         /etc/init.d/${service} start >>$DEBUG &
1449       fi
1450     done
1451     eend $?
1452  fi
1453 }
1454 # }}}
1455
1456 # {{{ remote files
1457 get_remote_file() {
1458   [ "$#" -eq 2 ] || ( echo "Error: wrong parameter for get_remote_file()" ; return 1 )
1459   SOURCE=$(eval echo "$1")
1460   TARGET="$2"
1461   getconfig() {
1462   wget --timeout=10 --dns-timeout=10  --connect-timeout=10 --tries=1 \
1463        --read-timeout=10 ${SOURCE} -O ${TARGET} && return 0 || return 1
1464   }
1465   einfo "Trying to get ${WHITE}${TARGET}${NORMAL}"
1466   counter=10
1467   while ! getconfig && [[ "$counter" != 0 ]] ; do
1468     echo -n "Sleeping for 1 second and trying to get config again... "
1469     counter=$(( counter-1 ))
1470     echo "$counter tries left" ; sleep 1
1471   done
1472   if [ -s "$TARGET" ] ; then
1473     einfo "Downloading was successfull." ; eend 0
1474     einfo "md5sum of ${WHITE}${TARGET}${NORMAL}: "
1475     md5sum ${TARGET} ; eend 0
1476     return 0;
1477   else
1478     einfo "Sorry, could not fetch ${SOURCE}" ; eend 1
1479     return 1;
1480  fi
1481 }
1482 # }}}
1483
1484 # {{{ config files
1485 config_netconfig(){
1486  if checkbootparam 'netconfig' ; then
1487   CONFIG="$(getbootparam 'netconfig' 2>>$DEBUG)"
1488   CONFIGFILE='/tmp/netconfig.grml'
1489
1490   if get_remote_file ${CONFIG} ${CONFIGFILE} ; then
1491     cd / && einfo "Unpacking ${WHITE}${CONFIGFILE}${NORMAL}:" && /usr/bin/unp $CONFIGFILE $EXTRACTOPTIONS ; eend $?
1492   fi
1493
1494  fi
1495 }
1496 # }}}
1497
1498 # {{{ remote scripts
1499 config_netscript() {
1500  if checkbootparam 'netscript' ; then
1501   CONFIG="$(getbootparam 'netscript' 2>>$DEBUG)"
1502   SCRIPTFILE='/tmp/netscript.grml'
1503
1504   if get_remote_file ${CONFIG} ${SCRIPTFILE} ; then
1505     chmod +x ${SCRIPTFILE}
1506     einfo "Running ${WHITE}${SCRIPTFILE}${NORMAL}:" && NETSCRIPT=${CONFIG} ${SCRIPTFILE} ; eend $?
1507   fi
1508
1509  fi
1510 }
1511 # }}}
1512
1513 # {{{ stats
1514 config_stats() {
1515  if ! checkbootparam 'nostats' ; then
1516    BASE_URL="http://stats.grml.org/report/"
1517    ACTION_NAME=Boot
1518
1519    HOST_ID=$(cat /proc/sys/kernel/random/boot_id)
1520
1521    grep -q " lm " /proc/cpuinfo && HAS_64BIT="1" || HAS_64BIT="0"
1522    DATE_STRING=$(date +'h=%H&m=%M&s=%S')
1523    [ -e /etc/grml_version ] && VERSION=$(cat /etc/grml_version) || \
1524      VERSION=$(lsb_release -d | awk -F: '{gsub(/^[ \t]+/, "", $2); print $2}')
1525
1526    PARAMS="$( echo "$CMDLINE" | sed -e 's/=[^ ]*/=x/g' | tr " " "\n"|sort|tr "\n" " " )"
1527
1528    echo "$CMDLINE" | grep -q -e "fetch" -e "nfsroot" && BOOT="remote"
1529    [ -z "$BOOT" ] && BOOT="local"
1530
1531    ADDITIONAL_PARAMS=""
1532    ( [ -n "$COLUMNS" ] && [ -n "$LINES" ] ) && \
1533      ADDITIONAL_PARAMS="$ADDITIONAL_PARAMS&res=$((COLUMNS * 8))x$((LINES * 16))"
1534
1535    URI='$BASE_URL?action=${ACTION_NAME}\&$DATE_STRING\&unique_id=${HOST_ID}\&support_64bit=$HAS_64BIT\&version=$VERSION\&bootup=$BOOT\&params=$PARAMS$ADDITIONAL_PARAMS'
1536
1537    get_remote_file "$URI" "/dev/null"  >/dev/null 2>&1 &!
1538  fi
1539 }
1540 # }}}
1541
1542 # {{{ fix/workaround for unionfs
1543 fix_unionfs(){
1544   if [ -z "$INSTALLED" ]; then
1545    touch /var/cache/apt/*cache.bin
1546   fi
1547 }
1548 # }}}
1549
1550 # {{{ start X window system via grml-x
1551 config_x_startup(){
1552 # make sure we start X only if startx is used *before* a nostartx option
1553 # so it's possible to disable automatic X startup using nostart
1554 if checkbootparam 'startx' && ! echo "$CMDLINE" | grep -q 'startx.*nostartx' ; then
1555  if [ -x "$(which X)" ] ; then
1556   if [ -z "$INSTALLED" ] ; then
1557    WINDOWMANAGER="$(getbootparam 'startx' 2>>$DEBUG)"
1558    if [ -z "$WINDOWMANAGER" ] ; then
1559      einfo "No window manager specified. Using default one." && eend 0
1560    else
1561      einfo "Window manager ${WHITE}${WINDOWMANAGER}${NORMAL} found as bootoption." && eend 0
1562    fi
1563    einfo "Setting up and invoking grml-x ${WINDOWMANAGER}. Just exit X windows system to get full featured consoles."
1564    config_userlocal
1565  cat>|/etc/init.d/xstartup<<EOF
1566 #!/bin/sh
1567 su $localuser -c "/usr/bin/grml-x ${WINDOWMANAGER}"
1568 EOF
1569    chmod 755 /etc/init.d/xstartup
1570
1571    # adjust inittab for xstartup
1572    if grep -q '^6:' /etc/inittab ; then
1573       sed -i 's|^6:.*|6:2345:respawn:/bin/zsh --login -c "/etc/init.d/xstartup ; /usr/share/grml-scripts/run-welcome" >/dev/tty6 2>\&1 </dev/tty6|' /etc/inittab
1574    else # just append tty6 to inittab if no definition is present:
1575       echo '6:2345:respawn:/bin/zsh --login -c "/etc/init.d/xstartup ; /usr/share/grml-scripts/run-welcome" >/dev/tty6 2>&1 < /dev/tty6' >> /etc/inittab
1576    fi
1577
1578    /sbin/telinit q ; eend $?
1579
1580    if grep -q '^allowed_users=' /etc/X11/Xwrapper.config ; then
1581       sed -i 's/^allowed_users=.*/allowed_users=anybody/' /etc/X11/Xwrapper.config
1582    else
1583       echo 'allowed_users=anybody' >> /etc/X11/Xwrapper.config
1584    fi
1585
1586   else
1587     eerror "We are not running in live mode - startx will not work, skipping it."
1588     eerror " -> Please use something like xdm, gdm or kdm for starting X on a harddisk system!" ; eend 1
1589   fi
1590  else
1591    eerror "/usr/bin/X is not present on this grml flavour."
1592    eerror "  -> Boot parameter startx does not work therefore." ; eend 1
1593  fi
1594 fi
1595 }
1596 # }}}
1597
1598 # {{{ configuration framework
1599 config_extract(){
1600 if checkbootparam 'extract' ; then
1601  EXTRACT="$(getbootparam 'extract' 2>>$DEBUG)"
1602  EXTRACTOPTIONS="-- -x $EXTRACT"
1603 fi
1604 }
1605
1606 config_finddcsdir() {
1607 #  - If no GRMLCFG partition is found and noautoconfig is _not_ given
1608 #    on the command line, nothing is changed and the dcs files are
1609 #    searched within the .iso, $dcs-dir is set to the root directory
1610 #    within the .iso
1611 #  - If a GRMLCFG partition is found, $dcs-dir is set to the root of
1612 #    the GRMLCFG partition unless noautoconfig is set. If noautoconfig is
1613 #    set, $dcs-dir is set to the root directory within the .iso.
1614 #  - If myconfig=foo is set on the command line, $dcs-dir is set to
1615 #    foo, even if a GRMLCFG partition is present.
1616 DCSDIR=""
1617 DCSMP="/mnt/grml"
1618 # autoconfig, see issue673
1619 GRMLCFG="$(getbootparam 'autoconfig' 2>>$DEBUG)"
1620 [ -n "$GRMLCFG" ] || GRMLCFG="GRMLCFG"
1621 if checkbootparam 'noautoconfig' || checkbootparam 'forensic' ; then
1622   DCSDIR="${LIVECD_PATH}" # set default so it works for "scripts" boot option as expected
1623   ewarn "Skipping running automount of device(s) labeled $GRMLCFG as requested." ; eend 0
1624 else
1625   if [ -z "$INSTALLED" ] ; then
1626     if checkbootparam 'myconfig' ; then
1627       DCSDEVICE="$(getbootparam 'myconfig' 2>>$DEBUG)"
1628       if [ -z "$DCSDEVICE" ]; then
1629         eerror "Error: No device for bootoption myconfig provided." ; eend 1
1630       fi # [ -z "$DCSDEVICE" ]
1631     elif checkvalue $CONFIG_MYCONFIG; then # checkbootparam myconfig
1632       einfo "Searching for device(s) labeled with $GRMLCFG. (Disable this via boot option: noautoconfig)" ; eend 0
1633       eindent
1634       DCSDEVICE=$(blkid -t LABEL=$GRMLCFG | head -1 | awk -F: '{print $1}')
1635
1636       modprobe 9p 2>/dev/null || true
1637       if [ -z "$DCSDEVICE" ] && grep -q 9p /proc/filesystems ; then
1638           if grep -q "$GRMLCFG" /sys/bus/virtio/devices/*/mount_tag 2>/dev/null ; then
1639             einfo "Found 9p-virtio fs with mount_tag $GRMLCFG"
1640             DCSDEVICE="$GRMLCFG"
1641             MOUNTOPTIONS="ro,trans=virtio"
1642             DCSFS="9p"
1643           fi
1644       fi
1645
1646       if [ -n "$DCSDEVICE" ]; then
1647         DCSMP="/mnt/grmlcfg"
1648       fi
1649       eoutdent
1650     fi
1651
1652     # if not specified/present then assume default:
1653     if [ -z "$DCSDEVICE" ]; then
1654       DCSDIR="${LIVECD_PATH}"
1655     else
1656       eindent
1657       einfo "debs, config, scripts are read from $DCSDEVICE." ; eend 0
1658       DCSDIR="$(< /proc/mounts awk -v DCSDEV=$DCSDEVICE '{if ($1 == DCSDEV) { print $2 }}')"
1659       if [ -n "$DCSDIR" ]; then
1660         ewarn "$DCSDEVICE already mounted on $DCSDIR"; eend 0
1661       else
1662         [ -d $DCSMP ] || mkdir $DCSMP
1663         umount $DCSMP >>$DEBUG 2>&1 # make sure it is not mounted
1664         mount -o ${MOUNTOPTIONS:-ro} -t ${DCSFS:-auto} $DCSDEVICE  $DCSMP ; RC="$?"
1665         if [[ $RC == 0 ]]; then
1666           einfo "Successfully mounted $DCSDEVICE to $DCSMP (readonly)." ; eend 0
1667         else
1668           eerror "Error: mounting $DCSDEVICE to $DCSMP (readonly) failed." ; eend 1
1669         fi
1670         DCSDIR="$DCSMP"
1671       fi
1672       eoutdent
1673     fi
1674   fi
1675 fi
1676
1677 if [ -n "$DCSDIR" -a "$DCSDIR" != "${LIVECD_PATH}" ] ; then
1678   einfo "Debs, config, scripts (if present) will be read from $DCSDIR." ; eend 0
1679 elif checkbootparam 'debs' || checkbootparam 'config' || checkbootparam 'scripts'; then
1680   einfo "Debs, config, scripts will be read from the live image directly." ; eend 0
1681 fi
1682 }
1683
1684
1685 config_partconf() {
1686 if checkbootparam 'partconf' ; then
1687  MOUNTDEVICE="$(getbootparam 'partconf' 2>>$DEBUG)"
1688  if [ -n "$MOUNTDEVICE" ]; then
1689    [ -d /mnt/grml ] || mkdir /mnt/grml
1690    mount -o ro -t auto $MOUNTDEVICE /mnt/grml ; RC="$?"
1691     if [[ $RC == 0 ]]; then
1692       einfo "Successfully mounted $MOUNTDEVICE to /mnt/grml (readonly)." ; eend 0
1693       einfo "Copying files from $MOUNTDEVICE over grml system."
1694       for file in `cat /etc/grml/partconf` ; do
1695         [ -d /mnt/grml/$file ] && cp -a /mnt/grml/${file}* ${file} && echo "copied: $file"
1696         [ -f /mnt/grml/$file ] && cp -a /mnt/grml/${file}  ${file} && echo "copied: $file"
1697       done && eend 0
1698     else
1699       einfo "Could not mount $MOUNTDEVICE to /mnt/grml - sorry." ; eend 1
1700     fi # mount $MOUNTDEVICE
1701    grep -q '/mnt/grml' /proc/mounts && umount /mnt/grml
1702  else
1703    einfo "Sorry, no device for bootoption partconf provided. Skipping." ; eend 1
1704  fi # [ -n "$MOUNTDEVICE" ]
1705 fi
1706 }
1707 # }}}
1708
1709 # {{{ /cdrom/.*-options
1710 config_debs(){
1711 if checkbootparam 'debs' ; then
1712    iszsh && setopt localoptions shwordsplit
1713    DEBS="$(getbootparam 'debs' 2>>$DEBUG)"
1714    if [ -z "$DEBS" ] ; then
1715       DEBS="*.deb"
1716    fi
1717    if ! echo $DEBS | grep -q '/'; then
1718      # backwards compatibility: if no path is given get debs from debs/
1719      DEBS="debs/$DEBS"
1720    fi
1721    einfo "Tring to install debian package(s) ${DEBS}"
1722    DEBS="$(eval echo ${DCSDIR}/$DEBS)"
1723    dpkg -i $DEBS ; eend $?
1724 fi
1725 }
1726
1727 config_scripts(){
1728 if checkbootparam 'scripts' || [ "$DCSMP" = "/mnt/grmlcfg" ]; then
1729    SCRIPTS="$(getbootparam 'scripts' 2>>$DEBUG)"
1730    if [ -d ${DCSDIR}/scripts ] && [ -z "$SCRIPTS" ]; then
1731      SCRIPTS="$(cd ${DCSDIR}/scripts; /bin/ls -1d [Gg][Rr][Mm][Ll].[Ss][Hh] 2>>$DEBUG)"
1732    fi
1733    if ! echo $SCRIPTS | grep -q '/'; then
1734      # backwards compatibility: if no path is given get scripts from scripts/
1735      SCRIPTS="scripts/$SCRIPTS"
1736    fi
1737    if [ "$DCSMP" = "/mnt/grmlcfg" ]; then
1738      # we are executing from a GRMLCFG labeled fs
1739      # kick everything we have done before and start over
1740      SCRIPTS="$(cd ${DCSDIR}; /bin/ls -1d [Gg][Rr][Mm][Ll].[Ss][Hh] 2>>$DEBUG)"
1741    fi
1742    if [ -n "$SCRIPTS" ]; then
1743      SCRIPTS="${DCSDIR}/$SCRIPTS"
1744      if [ "$DCSMP" = "/mnt/grmlcfg" ]; then
1745        einfo "Trying to execute ${SCRIPTS}"
1746        sh -c $SCRIPTS
1747      elif [ -d "$SCRIPTS" ]; then
1748        einfo "Bootparameter scripts found. Trying to execute from directory ${SCRIPTS}:"
1749        run-parts --regex '.*' $SCRIPTS
1750      else
1751        einfo "Bootparameter scripts found. Trying to execute ${SCRIPTS}:"
1752        sh -c $SCRIPTS
1753      fi
1754    fi
1755 fi
1756 }
1757
1758 config_config(){
1759 if checkbootparam 'config' || [ "$DCSMP" = "/mnt/grmlcfg" ]; then
1760   CONFIG="$(getbootparam 'config' 2>>$DEBUG)"
1761   if [ -z "$CONFIG" ]; then
1762     CONFIG="$(cd ${DCSDIR}; ls -1d [Cc][Oo][Nn][Ff][Ii][Gg].[Tt][Bb][Zz] 2>>$DEBUG)"
1763   fi
1764   if [ -n "$CONFIG" ]; then
1765     if [ -d "${DCSDIR}/${CONFIG}" ] ; then
1766       einfo "Taking configuration from directory ${DCSDIR}/${CONFIG}"
1767
1768       cp -a ${DCSDIR}/${CONFIG}/* /
1769     elif [ -f "${DCSDIR}/${CONFIG}" ]; then
1770       einfo "Extracting configuration from file ${DCSDIR}/${CONFIG}"
1771
1772       cd /
1773       unp ${DCSDIR}/${CONFIG} $EXTRACTOPTIONS ; eend $?
1774     else
1775       ewarn "Sorry, could not find configuration file or directory ${DCSDIR}/${FILENAME}." ; eend 1
1776     fi
1777   fi
1778 fi
1779 }
1780 # }}}
1781
1782 # {{{ confing_umount_dcsdir
1783 config_umount_dcsdir(){
1784    # umount $DCSMP if it was mounted by finddcsdir
1785    grep -q "$DCSMP" /proc/mounts && umount "$DCSMP"
1786 }
1787 # }}}
1788
1789 # {{{ mypath
1790 config_mypath(){
1791 if checkbootparam 'mypath' ; then
1792    MY_PATH="$(getbootparam 'mypath' 2>>$DEBUG)"
1793    einfo "Bootparameter mypath found, adding ${MY_PATH} to /etc/grml/my_path"
1794    touch /etc/grml/my_path
1795    chmod 644 /etc/grml/my_path
1796    # make sure the directories exist:
1797    eindent
1798    for i in $(echo $MY_PATH | sed 's/:/\n/g') ; do
1799        if ! [ -d "$i" ] ; then
1800           einfo "Creating directory $i"
1801           mkdir -p "$i" ; eend $?
1802        fi
1803    done
1804    grep -q "${MY_PATH}" /etc/grml/my_path || echo "${MY_PATH}" >> /etc/grml/my_path ; eend $?
1805    eoutdent
1806 fi
1807 }
1808 # }}}
1809
1810 # {{{ distcc
1811 config_distcc(){
1812 if checkbootparam 'distcc' ; then
1813  OPTIONS="$(getbootparam 'distcc' 2>>$DEBUG)"
1814  if [ -n "$OPTIONS" ]; then
1815     NET=""
1816     INTERFACE=""
1817     if [ -n "$OPTIONS" ]; then
1818       NET="${OPTIONS%%,*}"
1819       R="${OPTIONS#*,}"
1820       if [ -n "$R" -a "$R" != "$OPTIONS" ]; then
1821         OPTIONS="$R"
1822         INTERFACE="${OPTIONS%%,*}"
1823         R="${OPTIONS#*,}"
1824       fi
1825     fi
1826  fi
1827  CONFIG=/etc/default/distcc
1828  sed -i "s#^STARTDISTCC=.*#STARTDISTCC=YES#"  $CONFIG
1829  sed -i "s#^ALLOWEDNETS=.*#ALLOWEDNETS=$NET#" $CONFIG
1830
1831  if [ -n "$INTERFACE" ] ; then
1832    IP=$(LANG=C ifconfig $INTERFACE | gawk -F: /"inet addr"/'{print $2}' | gawk '{print $1}')
1833
1834    counter=10
1835    while [ -z "$IP" ] && [[ "$counter" != 0 ]] ; do
1836      counter=$(( counter-1 ))
1837      ewarn "No ip address for $INTERFACE found. Sleeping for 3 seconds. $counter tries left."
1838      sleep 3
1839      IP=$(LANG=C ifconfig $INTERFACE | gawk -F: /"inet addr"/'{print $2}' | gawk '{print $1}')
1840    done
1841  fi
1842
1843  if [ -n "$IP" ] ; then
1844    sed -i "s#^LISTENER=.*#LISTENER=$IP#"      $CONFIG
1845
1846    einfo "Bootoption distcc found. Preparing setup for distcc daemon."
1847    eindent
1848     id distccd >/dev/null 2>&1 || \
1849     (
1850       einfo "Creating distcc user" ; \
1851       adduser --quiet --system --ingroup nogroup --home / --no-create-home distccd ; eend $?
1852     )
1853
1854     einfo "Starting distcc for network ${NET}, listening on ${IP}."
1855    /etc/init.d/distcc start >/dev/null ; eend $?
1856    eoutdent
1857  else
1858    eerror "No ip address for $INTERFACE found. distcc can not be used without it." ; eend 1
1859  fi
1860 fi
1861
1862 if checkbootparam 'gcc'; then
1863  GCC="$(getbootparam 'gcc' 2>>$DEBUG)"
1864  eindent
1865  einfo "Pointing /usr/bin/gcc to /usr/bin/gcc-${GCC}."
1866  eoutdent
1867  rm -f /usr/bin/gcc
1868  ln -s /usr/bin/gcc-${GCC} /usr/bin/gcc ; eend $?
1869 fi
1870
1871 if checkbootparam 'gpp'; then
1872  GPP="$(getbootparam 'gpp' 2>>$DEBUG)"
1873  eindent
1874   einfo "Pointing /usr/bin/g++ to /usr/bin/g++-${GPP}."
1875   if [ -x /usr/bin/g++-${GPP} ] ; then
1876      rm -f /usr/bin/g++
1877      ln -s /usr/bin/g++-${GPP} /usr/bin/g++ ; eend $?
1878   fi
1879   einfo "Pointing /usr/bin/cpp to /usr/bin/cpp-${GPP}."
1880   if [ -x /usr/bin/cpp-${GPP} ] ; then
1881      rm -f /usr/bin/cpp
1882      ln -s /usr/bin/cpp-${GPP} /usr/bin/cpp ; eend $?
1883   fi
1884  eoutdent
1885 fi
1886
1887 }
1888 # }}}
1889
1890 # {{{ load modules
1891 # Notice: use it only on live-cd system, if running from harddisk please
1892 # add modules to /etc/modules and activate /etc/init.d/module-init-tools
1893 # in /etc/runlevel.conf
1894 config_modules(){
1895 MODULES_FILE=/etc/grml/modules
1896 if checkbootparam 'nomodules' ; then
1897   ewarn "Skipping loading of modules defined in ${MODULES_FILE} as requested." ; eend 0
1898 elif [ -z "$INSTALLED" ]; then
1899  if [ -r $MODULES_FILE ] ; then
1900   einfo "Loading modules specified in ${MODULES_FILE}:"
1901   eindent
1902   grep '^[^#]' $MODULES_FILE | \
1903   while read module args; do
1904     [ "$module" ] || continue
1905       einfo "${module}"
1906       modprobe $module $args ; eend $?
1907   done
1908   eoutdent
1909  else
1910   ewarn "File $MODULES_FILE does not exist. Skipping loading of specific modules." ; eend 1
1911  fi
1912 fi
1913 }
1914 # }}}
1915
1916 # {{{ SW-RAID
1917 config_swraid(){
1918   [ -n "$INSTALLED" ] && return 0
1919
1920   # notice: checkbootparam "forensic" is just for users who don't know how to really use the bootoption
1921   if checkbootparam 'noraid'   || checkbootparam 'noswraid' || \
1922      checkbootparam 'forensic' || checkbootparam 'raid=noautodetect' ; then
1923      ewarn "Skipping SW-RAID code as requested on boot commandline." ; eend 0
1924   else
1925     [ -e /proc/mdstat ] || modprobe md_mod
1926     if ! [ -x /sbin/mdadm ] ; then
1927        eerror "mdadm not available, can not execute it." ; eend 1
1928     else
1929
1930        # if ! egrep -qv '^(MAILADDR.*|#.*|)$' /etc/mdadm/mdadm.conf 2>>$DEBUG ; then
1931        # find out whether we have a valid configuration file already
1932        if ! grep -q ARRAY /etc/mdadm/mdadm.conf 2>>$DEBUG ; then
1933           einfo "Creating /etc/mdadm/mdadm.conf for use with mdadm."
1934           [ -r /etc/mdadm/mdadm.conf ] && mv /etc/mdadm/mdadm.conf /etc/mdadm/mdadm.conf.old
1935           MDADM_MAILADDR__='root' /usr/share/mdadm/mkconf > /etc/mdadm/mdadm.conf ; eend $?
1936         else
1937           ewarn "/etc/mdadm/mdadm.conf looks like a configured mdadm setup, will not touch it." ; eend 0
1938        fi
1939
1940        if ! checkbootparam 'swraid' ; then
1941           eindent
1942           einfo "Just run 'Start mdadm-raid' to assemble md arrays or boot using 'swraid' as bootoption for autostart."
1943           eoutdent
1944        else
1945           einfo "Bootoption swraid found. Searching for software RAID arrays:"
1946           eindent
1947            IFSOLD=${IFS:-}
1948            IFS='
1949 '
1950            for line in $(mdadm --assemble --scan --auto=yes --symlink=no 2>&1) ; do
1951                case $line in
1952                  *'No arrays found'*)
1953                    ewarn "$line" ; eend 0
1954                    ;;
1955                  *)
1956                    einfo "$line" ; eend 0
1957                    ;;
1958                esac
1959            done
1960            IFS=$IFSOLD
1961          eoutdent
1962
1963          if [ -r /proc/mdstat ] ; then
1964             eindent
1965             MDSTAT=$(grep '^md[0-9]' /proc/mdstat)
1966             if [ -z "$MDSTAT" ] ; then
1967                ewarn "No active arrays found" ; eend 0
1968             else
1969                IFSOLD=${IFS:-}
1970                IFS='
1971 '
1972                for line in $(grep '^md[0-9]' /proc/mdstat) ; do
1973                    einfo "active arrays: $line" ; eend 0
1974                done
1975                IFS=$IFSOLD
1976             fi
1977             eoutdent
1978          fi # /proc/mdstat
1979        fi # bootoption swraid
1980
1981      fi # is /sbin/mdadm executable?
1982   fi # check for bootoptions
1983 }
1984 # }}}
1985
1986 # {{{ dmraid
1987 config_dmraid(){
1988   [ -n "$INSTALLED" ] && return 0
1989
1990   if checkbootparam 'nodmraid' ; then
1991     ewarn "Skipping dmraid code as requested on boot commandline." ; eend 0
1992     return 0
1993   fi
1994
1995   if ! [ -x /sbin/dmraid ] ; then
1996     eerror "dmraid not available, can not execute it." ; eend 1
1997     return
1998   fi
1999
2000   dmraid_wrapper() {
2001     # usage: dmraid_wrapper <dmraid_option>
2002     [ -n "$1" ] || return 1
2003
2004     IFSOLD=${IFS:-}
2005     IFS='
2006 '
2007     eindent
2008
2009     for line in $(dmraid $1 ; echo errcode:$?); do
2010       case $line in
2011         *'no block devices found'*)
2012           einfo "No block devices found" ; eend 0
2013           break
2014           ;;
2015         *'no raid disks'*)
2016           einfo "No active dmraid devices found" ; eend 0
2017           break
2018           ;;
2019         errcode:0)
2020           eend 0;
2021           ;;
2022         errcode:1)
2023           eend 1
2024           ;;
2025         *)
2026           einfo "$line"
2027           ;;
2028       esac
2029     done
2030
2031     eoutdent
2032     IFS=$IFSOLD
2033   }
2034
2035   if checkbootparam 'dmraid' ; then
2036     local ACTION="$(getbootparam 'dmraid' 2>>$DEBUG)"
2037     if [ "$ACTION" = "off" ] ; then
2038       # Deactivates all active software RAID sets:
2039       einfo "Deactivating present dmraid sets (as requested via dmraid=off):"
2040       dmraid_wrapper -an
2041     else
2042       # Activate all software RAID sets discovered:
2043       einfo "Activating present dmraid sets (as requested via dmraid):"
2044       dmraid_wrapper -ay
2045     fi
2046
2047     return
2048   fi
2049
2050   # by default (no special bootoptions) discover all software RAID devices:
2051   einfo "Searching for any present dmraid sets:"
2052   dmraid_wrapper -r
2053 }
2054 # }}}
2055
2056 # {{{ LVM (Logical Volumes)
2057 config_lvm(){
2058   [ -n "$INSTALLED" ] && return 0
2059
2060   if checkbootparam 'nolvm' ; then
2061      ewarn "Skipping LVM code as requested on boot commandline." ; eend 0
2062   else
2063     # Debian etch provides /etc/init.d/lvm only, newer suites provide /etc/init.d/lvm2
2064     if ! [ -x /sbin/lvm -a -x /sbin/lvdisplay ] || ! [ -x /etc/init.d/lvm2 -o -x /etc/init.d/lvm ] ; then
2065        eerror "LVM not available, can not execute it." ; eend 1
2066     else
2067        if lvdisplay 2>&1 | grep -v 'No volume groups found' >/dev/null 2>&1 ; then
2068           einfo "You seem to have logical volumes (LVM) on your system."
2069           eindent
2070           einfo "Just run 'Start lvm2' to activate them or boot using 'lvm' as bootoption for autostart."
2071           eend 0
2072           if checkbootparam 'lvm' ; then
2073              einfo "Bootoption LVM found. Searching for logical volumes:"
2074              /etc/init.d/lvm2 start ; eend $?
2075           fi
2076           eoutdent
2077        fi
2078     fi # check for lvm binary
2079   fi # check for bootoption nolvm
2080 }
2081 # }}}
2082
2083 # {{{ debnet: setup network based on an existing one found on a partition
2084 config_debnet(){
2085 if checkbootparam 'debnet' ; then
2086  einfo "Bootoption 'debnet' found. Searching for Debian network configuration: "
2087  /usr/sbin/debnet
2088 fi
2089 }
2090 # }}}
2091
2092 # {{{ disable console blanking
2093 config_blanking(){
2094 if checkbootparam 'noblank' ; then
2095   einfo "Bootoption noblank found. Disabling monitor blanking."
2096   setterm -blank 0 ; eend $?
2097 fi
2098 }
2099 # }}}
2100
2101 # {{{ tohd= bootoption
2102 config_tohd()
2103 {
2104   if checkbootparam 'tohd' ; then
2105      local TARGET="$(getbootparam 'tohd' 2>>$DEBUG)"
2106      if [ -z "$TARGET" ] ; then
2107         eerror "Error: tohd specified without any partition, can not continue." ; eend 1
2108         eerror "Please use something like tohd=/dev/sda9." ; eend 1
2109         return 1
2110      fi
2111
2112      if ! [ -b "$TARGET" ] ; then
2113         eerror "Error: $TARGET is not a valid block device, sorry." ; eend 1
2114         return 1
2115      fi
2116
2117      if grep -q $TARGET /proc/mounts ; then
2118         eerror "$TARGET already mounted, skipping execution of tohd therefore."
2119         eend 1
2120         return 1
2121      fi
2122
2123      local MOUNTDIR=$(mktemp -d)
2124
2125      if mount -o rw "$TARGET" "$MOUNTDIR" ; then
2126         einfo "Copyring live system to $TARGET - this might take a while"
2127         rsync -a --progress ${LIVECD_PATH}/live $MOUNTDIR
2128         sync
2129         umount "$MOUNTDIR"
2130         eend $?
2131         einfo "Booting with \"grml bootfrom=$TARGET\" should work now." ; eend 0
2132      else
2133         eerror "Error when trying to mount $TARGET, sorry."; eend 1
2134         return 1
2135      fi
2136
2137      rmdir "$MOUNTDIR"
2138   fi
2139 }
2140 # }}}
2141
2142 # {{{ debootstrap: automatic installation
2143 config_debootstrap(){
2144
2145 if checkbootparam "BOOT_IMAGE=debian2hd" || checkbootparam "debian2hd" ; then
2146
2147 einfo "Bootoption debian2hd found. Setting up environment for automatic installation via grml-debootstrap." ; eend 0
2148
2149 if ! [ -x /usr/sbin/grml-debootstrap ] ; then
2150    eindent
2151    eerror "Bootoption debian2hd found, but grml-debootstrap is not available." ; eend 1
2152    eoutdent
2153    exit 1
2154 fi
2155
2156 if checkbootparam 'target' ; then
2157   TARGET=''
2158   TARGET="$(getbootparam 'target' 2>>$DEBUG)"
2159   # notice: the following checks whether the given partition is available, if not the skip
2160   # execution of grml-debootstrap as it might result in data loss...
2161   if ! [ -r "$TARGET" ] ; then
2162      eerror "Target $TARGET does not exist. Skipping execution of grml-debootstrap therefore." ; eend 1
2163   fi
2164 else
2165   eindent
2166   eerror "No bootoption named target found, can not continue execution of grml-debootstrap." ; eend 1
2167   eoutdent
2168   exit 1
2169 fi
2170
2171 if checkbootparam 'grub' ; then
2172   GRUB=''
2173   GRUB="$(getbootparam 'grub' 2>>$DEBUG)"
2174 fi
2175
2176 if checkbootparam 'groot' ; then
2177   GROOT=''
2178   GROOT="$(getbootparam 'groot' 2>>$DEBUG)"
2179 fi
2180
2181 if checkbootparam 'release' ; then
2182   RELEASE=''
2183   RELEASE="$(getbootparam 'release' 2>>$DEBUG)"
2184 fi
2185
2186 if checkbootparam 'mirror' ; then
2187   MIRROR=''
2188   MIRROR="$(getbootparam 'mirror' 2>>$DEBUG)"
2189 fi
2190
2191 if checkbootparam 'boot_append' ; then
2192   BOOT_APPEND=''
2193   BOOT_APPEND="$(getbootparam 'boot_append' 2>>$DEBUG)"
2194 fi
2195
2196 if checkbootparam 'password' ; then
2197   PASSWORD=''
2198   PASSWORD="$(getbootparam 'password' 2>>$DEBUG)"
2199 fi
2200
2201 # now check which options are available
2202 if [ -n "TARGET" ] ; then
2203    TARGETCMD="--target $TARGET"
2204 else
2205    TARGETCMD=''
2206    eindent
2207    eerror "Target not set via bootoption. Skipping execution of grml-debootstrap therefore."; eend 1
2208    eoutdent
2209    exit 1
2210 fi
2211 [ -n "$GRUB" ]     && GRUBCMD="--grub $GRUB"               || GRUBCMD=''
2212 [ -n "$GROOT" ]    && GROOTCMD="--groot $GROOT"            || GROOTCMD=''
2213 [ -n "$RELEASE" ]  && RELEASECMD="--release $RELEASE"      || RELEASECMD=''
2214 [ -n "$MIRROR" ]   && MIRRORCMD="--mirror $MIRROR"         || MIRRORCMD=''
2215 [ -n "$PASSWORD" ] && PASSWORDCMD="--password $PASSWORD"   || PASSWORDCMD=''
2216 [ -n "$BOOT_APPEND" ] && BOOT_APPEND="--boot_append $BOOT_APPEND" || BOOT_APPEND=''
2217
2218 # and finally write script and execute it
2219 cat>|/usr/bin/grml-debootstrap_noninteractive<<EOF
2220 #!/bin/sh
2221 AUTOINSTALL='yes' grml-debootstrap $TARGETCMD $GRUBCMD $GROOTCMD $RELEASECMD $MIRRORCMD $PASSWORDCMD $BOOT_APPEND
2222 EOF
2223
2224 chmod 750  /usr/bin/grml-debootstrap_noninteractive
2225
2226 screen /usr/bin/grml-debootstrap_noninteractive
2227 einfo "Invoking a shell, just exit to continue booting..."
2228 /bin/zsh
2229
2230 fi # checkbootparam "BOOT_IMAGE=debian2hd
2231 }
2232 # }}}
2233
2234 config_virtualbox_shared_folders() {
2235 if $VIRTUALBOX ; then
2236   einfo "VirtualBox detected, trying to set up Shared Folders."
2237   if ! modinfo vboxsf &>/dev/null ; then
2238     ewarn "vboxsf driver not present, not setting up VirtualBox Shared Folders."
2239     eend 0
2240   elif ! [ -x /usr/sbin/VBoxService ] ; then
2241     ewarn "virtualbox-guest-utils not installed, not setting up VirtualBox Shared Folders."
2242     eend 0
2243   else
2244     eindent
2245
2246       einfo "Loading vboxsf driver."
2247       lsmod | grep -q vboxsf || modprobe vboxsf
2248       eend $?
2249
2250       einfo "Adjusting /dev/vboxguest."
2251       chown root:vboxsf /dev/vboxguest
2252       chmod 660 /dev/vboxguest
2253       eend $?
2254
2255       config_userfstab
2256
2257       einfo "Adding $fstabuser to group vboxsf."
2258       adduser grml vboxsf &>/dev/null
2259       eend $?
2260
2261       einfo "Starting VBoxService."
2262       VBoxService >/dev/null &
2263       eend $?
2264
2265     eoutdent
2266   fi
2267 fi
2268 }
2269
2270 # {{{ Support customization
2271 config_distri(){
2272 if checkbootparam 'distri'; then
2273   DISTRI="$(getbootparam 'distri' 2>>$DEBUG)"
2274   if [ -r "${LIVECD_PATH}"/desktop/"$DISTRI".jpg ] ; then
2275      [ -n "$BOOTDEBUG" ] && einfo "Debug: bootoption distri found and file ${LIVECD_PATH}/desktop/${DISTRI} present" && eend 0
2276      # make sure the desktop.jpg file is not a symlink, so copying does not file then
2277      [ -L /usr/share/grml/desktop.jpg ] && rm /usr/share/grml/desktop.jpg
2278      cp "${LIVECD_PATH}"/desktop/"$DISTRI".jpg /usr/share/grml/desktop.jpg
2279   fi
2280 fi
2281 }
2282 # }}}
2283
2284 ## END OF FILE #################################################################
2285 # vim:foldmethod=marker expandtab ai ft=zsh shiftwidth=2