6. Anwendung von Shellscripten: Hoch- und Runterfahren des Systems

Inhalt:

6.1 Vor dem Betriebssystem

  1. Booten des Kernels (von Platte: BIOS/Firmware, First/Second Stage Bootloader; Netboot), Singleuser Mode (Kernel + Shell, ohne Netzwerk oder irgendwelcher Dienste, Terminals, ...), Multiuser Mode (Netzwerk, Terminals, ...)

    Zum Laden des Kernels bestehen abhängig von Hardware bzw. Firmware mehrere Möglichkeiten:

    1. BIOS/Firmware -> Kernel
    2. BIOS/Firmware -> First Stage Bootloader (von Platte/Band/Netz) -> Kernel
    3. BIOS/Firmware -> Ggf. First Stage Bootloader (von Platte/Band/Netz) -> Ggf. Second Stage Bootloader -> Kernel

    Details zum Booten von PCs: So bootet Minix

    Das Problem beim 1-Stage-Ansatz (mittlere Grafik) ist, dass beim Updaten des Kernels (mv vmlinuz vmlinuz.old, cp .../vmlinuz vmlinuz) der Kernel an einee neuen Blocknummer beginnt, der mbr aber noch auf die alte Blocknummer zugreift. Abhilfe: "lilo" starten, das die neue 1. Blocknummer in den mbr schreibt.

  2. Methoden zum Starten der Services für den Multiuser Mode:

6.2 Das System V "init"-Konzept

  1. Grundlage für die folgenden Betrachtungen bildet Solaris 9

  2. Übersicht:

    Anhand einer Steuerdatei (/etc/inittab) wird das System in einen bestimmten Zustand (Run-Level) gesetzt. Dazu werden bestimmte Dienste (Scripten) abgearbeitet

  3. Runlevels bei System V Release 4 / Sun Solaris:

  4. Wechseln der Runlevel: init <runlevel>

  5. Aufbau /etc/inittab: id:runlevel(s):aktion:programm

    Beispiele:

    ap::sysinit:/sbin/autopush -f /etc/iu.ap
    ap::sysinit:/sbin/soconfig -f /etc/sock2path
    fs::sysinit:/sbin/rcS sysinit           >/dev/msglog 2<>/dev/msglog </dev/console
    is:3:initdefault:
    p3:s1234:powerfail:/usr/sbin/shutdown -y -i5 -g0 >/dev/msglog 2<>/dev/msglog
    sS:s:wait:/sbin/rcS                     >/dev/msglog 2<>/dev/msglog </dev/console
    s0:0:wait:/sbin/rc0                     >/dev/msglog 2<>/dev/msglog </dev/console
    s1:1:respawn:/sbin/rc1                  >/dev/msglog 2<>/dev/msglog </dev/console
    s2:23:wait:/sbin/rc2                    >/dev/msglog 2<>/dev/msglog </dev/console
    s3:3:wait:/sbin/rc3                     >/dev/msglog 2<>/dev/msglog </dev/console
    s5:5:wait:/sbin/rc5                     >/dev/msglog 2<>/dev/msglog </dev/console
    s6:6:wait:/sbin/rc6                     >/dev/msglog 2<>/dev/msglog </dev/console
    fw:0:wait:/sbin/uadmin 2 0              >/dev/msglog 2<>/dev/msglog </dev/console
    of:5:wait:/sbin/uadmin 2 6              >/dev/msglog 2<>/dev/msglog </dev/console
    rb:6:wait:/sbin/uadmin 2 1              >/dev/msglog 2<>/dev/msglog </dev/console
    sc:234:respawn:/usr/lib/saf/sac -t 300
    co:234:respawn:/usr/lib/saf/ttymon -g -h -p "`uname -n` console login: " -T sun-color -d /dev/console -l console -m ldterm,ttcompat
    
    

    Neu einlesen der Inittab nach Änderung:

    # init q
    # 
  6. System in einen anderen Runlevel setzen. Beispiele:
    # init 6                  # reboot
    # 
    Die weiteren Ausgaben erfolgen auf der Console.

  7. /sbin/rc[0-6S]:

    Shell Scripten, die das System in den angegebenen Runlevel bringen. Von init via /etc/inittab aufgerufen.

    rfhpc8320# cd /sbin
    rfhpc8320# ls rc*
    rc0  rc1  rc2  rc3  rc5  rc6  rcS 
  8. /etc/rc?.d/[KS]*:

    Scripten, die beim Wechsel in den jeweiligen Runlevel durch /sbin/rcX abgearbeitet werden:

    1. /etc/rcX.d/K* werden mit Argument "stop"
    2. /etc/rcX.d/S* werden mit Argument "start"
    aufgerufen.

    Befehle Starten und Beenden eines Dienstes sind üblicherweise im selben Script untergebracht und werden mit Hilfe des uebergebene Arguments (start bzw. stop) ausgeführt.

    Auszug aus /sbin/rc3:

    if [ -d /etc/rc3.d ]; then
            for f in /etc/rc3.d/K*; do
                    if [ -s $f ]; then
                            case $f in
                                    *.sh)   .        $f ;;
                                    *)      /sbin/sh $f stop ;;
                            esac
                    fi
            done
    
            for f in /etc/rc3.d/S*; do
                    if [ -s $f ]; then
                            case $f in
                                    *.sh)   .        $f ;;
                                    *)      /sbin/sh $f start ;;
                            esac
                    fi
            done
    fi     
    Beispielscripten für Runlevel 0 (Shutdown):
    rfhpc8303% ls /etc/rc0.d
    K00ANNOUNCE       K33efcode         K40nscd           K43inet
    K05apache-1.3.26  K34ncad           K40sf880dr        K50asppp
    K05frame5         K34ncalogd        K40syslog         K52llc2
    K05oracle-8.1.5   K35volmgt         K40xntpd          K68picld
    K05upclient       K36sendmail       K41autofs         K83devfsadm
    K06mipagent       K36utmpd          K41ldap.client    K90dhcpagent
    K07dmi            K36wbem           K41nfs.client     K98lu
    K07snmpdx         K37power          K41rpc            xK16apache
    K10dtlogin        K39lp             K41slpd
    K28nfs.server     K39spc            K42inetsvc
    K33audit          K40cron           K42sckm 
    Beispielscripten für Runlevel 2 (Multiuser Mode ohne Netzwerk-Dienste):
    rfhpc8303% ls /etc/rc2.d
    K06mipagent        S47asppp           S74autofs          S88utmpd
    K07dmi             S69inet            S74syslog          S92volmgt
    K07snmpdx          S70uucp            S75cron            S93cacheos.finish
    K28nfs.server      S71ldap.client     S75savecore        S94ncalogd
    README             S71rpc             S76nscd            S95ncad
    S01MOUNTFSYS       S71sysid.sys       S80PRESERVE        S99audit
    S05RMTMPFILES      S72autoinstall     S80kdmconfig       S99kdelogin
    S20sysetup         S72inetsvc         S80lp              oldS99dtlogin
    S21perf            S72slpd            S80spc             xS74xntpd
    S30sysid.net       S73cachefs.daemon  S85power
    S40llc2            S73nfs.client      S88sendmail 
    Beispielscripten für Runlevel 3 (Multiuser Mode mit Netzwerk-Diensten, Client):
    rfhpc8303% ls /etc/rc3.d
    README              S77dmi              S95openssh-3.2.3p1  S95rdate
    S15nfs.server       S80mipagent         S95postboot         xS76snmpdx
    Beispielscripten für Runlevel 3 (Multiuser Mode mit Netzwerk-Diensten, Server):
    rfhs8012% ls /etc/rc3.d
    README            S95apache-1.3.26  xS25mdlogd        xS80mipagent
    S15nfs.server     S95frame5         xS50apache
    S93openssh        S95upclient       xS76snmpdx
    S94oracle-9.0.1   S99fix_console    xS77dmi
  9. /etc/init.d:
    Da das Script zum Starten eines Dienstes (üblich: Runlevel 3) in einem anderen Verzeichnis stehen muß als zum Beenden (Runlevel 0) ist es üblich, das Script via Hardlinks in beide Verzeichnisse zu linken. Zusätzlich existiert das Verzeichnis, das alle Scripten enthält. Sie Start/Stop-Scripten in den verschiedenen rc?.d Verzeichnissen sind üblicherweise Hardlinks auf das zugehörige Script in /etc/init.d. (Grund für Hardlinks: System V kannte lange Zeit keine Symlinks).

    Beispiel:

    $ ls -li ../*.d/*nfs.client*
        407335 -rwxr--r--   3 root     sys          836 Jan  5  2000 ../init.d/nfs.client
        407335 -rwxr--r--   3 root     sys          836 Jan  5  2000 ../rc0.d/K41nfs.client
        407335 -rwxr--r--   3 root     sys          836 Jan  5  2000 ../rc2.d/S73nfs.client     
    Auflistung aller in /etc/init.d vorhandenen Dienste:
    rfhpc8303% ls /etc/init.d
    ANNOUNCE        cachefs.root    init.snmpdx     ncakmod.old     sendmail
    MOUNTFSYS       cacheos         initboot        ncalogd         slpd
    PRESERVE        cacheos.finish  initpcihpc      network         spc
    README          coreadm         initpcmcia      network.old     standardmounts
    RMTMPFILES      cron            kdelogin        nfs.client      sysetup
    acct            devfsadm        keymap          nfs.server      sysid.net
    acctadm         devfsadm.old    ldap.client     nscd            sysid.sys
    asppp           devlinks        llc2            opensshd        syslog
    asppp.old       dhcpagent       lp              pcmcia          ufs_quota
    audit           drvconfig       mipagent        perf            utmpd
    autofs          dtlogin         mkdtab          power           uucp
    autoinstall     inetinit        ncad            rootusr         volmgt
    buildmnttab     inetsvc         ncad.old        rpc             webstart
    cachefs.daemon  init.dmi        ncakmod         savecore        xntpd     
  10. Beispielscript: /etc/init.d/sendmail

    $ cat /etc/init.d/sendmail
    #!/sbin/sh
    #
    #ident  "@(#)sendmail   1.12    97/05/29 SMI"   /* SVr4.0 1.5 */
    #
    # /etc/init.d/sendmail - Start/Stop the sendmail daemon
    #
    # Copyright (c) 1997 by Sun Microsystems, Inc.
    # All Rights Reserved.
    #
    
    #
    # The network and streams should already be built by the time
    # this script runs.
    #
    # If sendmail is already executing, don't re-execute it.
    #
    PATH=/usr/bin:/bin
    
    case $1 in 
    'start')
            if [ -f /usr/lib/sendmail -a -f /etc/mail/sendmail.cf ]; then
                    if [ ! -d /var/spool/mqueue ]
                    then
                            mkdir /var/spool/mqueue
                            chown root /var/spool/mqueue
                            chgrp staff /var/spool/mqueue
                            chmod 750 /var/spool/mqueue
                    fi
                    /usr/lib/sendmail -bd -q1h; 
            fi
    
            if /usr/sbin/mount -p | /usr/bin/nawk '
                    BEGIN { s = 1; }
                    $3 == "/var/mail" && $4 == "nfs" && $7 !~ /actimeo=0/ && $7 !~ /noac/ { s = 0;}
            END { exit s; }'
            then
                    /usr/bin/logger -p mail.crit "WARNING: /var/mail is NFS-mounted without setting actimeo=0,"
                    /usr/bin/logger -p mail.crit "this can cause mailbox locking and access problems."
            fi
            ;;
    'stop')
            pid=`/usr/bin/ps -eo pid,comm | /usr/bin/awk '{ if ($2 == "/usr/lib/sendmail") print $1 }'`
            if test "$pid"
            then
                    kill $pid
            fi
            ;;
    *)
            echo "usage: /etc/rc2.d/S88sendmail {start|stop}"
            ;;
    esac
    
  11. Dienst manuell anhalten:
    # sh /etc/init.d/sendmail stop 
  12. Dienst manuell neu starten:
    # sh /etc/init.d/sendmail start 
    Ein "restart" ist zwar bei einigen Unix-Implementierungen vorhanden, jedoch nicht Standard!

  13. Dienst permanent abstellen:
    $ cd /etc/rc2.d
    $ ls *login*
    S99kdelogin    oldS99dtlogin
    $
    $ ls -li ../*.d/*kdelogin*
        478974 lrwxrwxrwx   2 root     other         32 Jan  4  2001 ../init.d/kdelogin -> /soft/kde-1.1.1/install/kdelogin
        478974 lrwxrwxrwx   2 root     other         32 Jan  4  2001 ../rc2.d/S99kdelogin -> /soft/kde-1.1.1/install/kdelogin
    $
    $ ls -li ../*.d/*dtlogin*
        407371 -rwxr--r--   5 root     sys         2804 Dec  2  1999 ../init.d/dtlogin
        407371 -rwxr--r--   5 root     sys         2804 Dec  2  1999 ../rc0.d/K10dtlogin
        407371 -rwxr--r--   5 root     sys         2804 Dec  2  1999 ../rc1.d/K10dtlogin
        407371 -rwxr--r--   5 root     sys         2804 Dec  2  1999 ../rc2.d/oldS99dtlogin
        407371 -rwxr--r--   5 root     sys         2804 Dec  2  1999 ../rcS.d/K10dtlogin
    
         
  14. Dienst installieren:

6.3 Alternativen

    Das System V init-Konzept trifft Design-Entscheidungen für die folgenden Probleme:
    1. Permanentes An/Abschalten von Diensten: Bei System V durch kopieren/linken der Start/Kill-Scripte in's entsprechende rc?.d Verzeichnis, das rc-Script ist dafür verantwortlich, das Vorhandensein der Konfigurationsdateien etc. abzufragen und den Dienst dann ggf. nicht zu starten.

      Eine mögliche Alternative besteht hier in einer eigenen Konfigurationsdatei bzw. einem Interface, mit dessen Hilfe festgelegt wird welches rc-Script -- obwohl im rc?.d-Verzeichnis vorhanden -- ueberhaupt gestartet wird, s.u.

    2. Start-Reihenfolge, in der Dienste gestartet werden: Die Reihenfolge, in der die rc-Scripte gestartet werden ist durch die Nummern im Dateinamen festgelegt (z.B. S01MOUNTFSYS vor S99kdelogin) die dann mit Hilfe von Wildcard-Expansion in /sbin/rc? sortiert werden.

      Eine mögliche Alternative ist hier ein Provides/Requires-Mechanismus, s.u.

    Mögliche Alternativen zur System V Implementierung die auch real existieren werden im Folgenden vorgestellt.

  1. Alternative zum permanenten an/abschalten von Diensten: rc.conf/chkconfig

    Bei System V werden rc-Scripten gestartet wenn sie im entsprechenden rc?.d-Verzeichnis existieren. Falls ein Dienst nicht konfiguriert ist muss dies abgeprueft und der Dienst ggf. nicht gestartet werden. Beispiele hierfür sind senndmail, NIS und NFS bei Solaris.

    Eine Alternative ist, Dienste zwar im rc?.d-Verzeichnis zu haben, aber anhand einer gesonderten Konfigurationsdatei zu bestimmen, welches Script/Dienst gestartet wird. Zu finden ist dies bei NetBSD in der Datei /etc/rc.conf (vgl. rc.conf(5)) und bei Irix in einem mittels chkconfig(1M) gesteuerten Interfaces.

    Beispiel NetBSD:

    Beispiel Irix:
  2. Alternative zur Start-Reihenfolge: Provides/Requires-Mechanismus

    Alternative zur Reihenfolge mit Nummern: Provides/Requires-Mechanismus, z.B. in Shell-Scripten:

      sendmail:
      #!/bin/sh
      # PROVIDE: mail
      # REQUIRE: network
      ... 
      inet:
      #!/bin/sh
      # PROVIDE: network
      # REQUIRE: -
      ... 
    Die offensichtliche Reihenfolge hier ist:
    1. inet
    2. sendmail

    Angewandt wird ein solcher Provides/Requires-Mechanismus z.B. bei NetBSD und FreeBSD, das Bestimmen der Reihenfolge geschieht mit Hilfe des Programmes rcorder(8). Die einzelnen Scripten in /etc/rc.d werden hier in der Reihenfolge beim booten ausgefuehrt, wie sie in /etc/rc von rcorder(8) ermittelt wird:

    Grafik mit den Abhaengigkeiten des NetBSD rc.d Systems, ermittelt aus den provides/requires-Angaben und dot(1): PDF.

  3. Hybrid-Systeme für die Start-Reihenfolge

    Beim Init-Konzept wie bei System V stellt sich die Frage, wie die Nummern der Scripten in den rcX.d-Verzeichnissen ermittelt werden. Eine Möglichkeit hierzu ist, bei der permanenten Installation und Deinstallation von Diensten die Nummern anhand eines Provides/Requires-Mechanismus' automatisch ermitteln zu lassen.

    Z.B. für das obrige Beispiel:

    1. S01inet
    2. S02sendmail

    Wenn die Dateien mit Nummern versehen werden greift anschließend der "normale" rc-Mechanismus. Zu finden ist ein solches hybride System z.B. bei SuSE Linux, vgl. insserv(8):

           insserv enables an installed  system  init  script  (`boot
           script')  by  reading  the  comment  header of the script,
           e.g.:
    
             ### BEGIN INIT INFO
             # Provides:       boot_facility_1 [ boot_facility_2 ...]
             # Required-Start: boot_facility_1 [ boot_facility_2 ...]
             # Required-Stop:  boot_facility_1 [ boot_facility_2 ...]
             # X-UnitedLinux-Should-Start: boot_facility_1 [ boot_facility_2 ...]
             # X-UnitedLinux-Should-Stop:  boot_facility_1 [ boot_facility_2 ...]
             # Default-Start:  run_level_1 [ run_level_2 ...]
             # Default-Stop:   run_level_1 [ run_level_2 ...]
             # Description:    multiline_description
             ### END INIT INFO
    
           and calculating  the  dependencies  between  all  scripts.
           Please note, that the Required-Stop, X-UnitedLinux-Should-
           Stop, and Default-Stop are ignored in SuSE Linux,  because
           the  SuSE  boot  script  concept  uses a differential link
           scheme (see init.d(7)).  With known dependencies and  run-
           level(s)  insserv sets and reorders the corresponding sym-
           bolic links of the concerned  runlevels  directories  (see
           init.d(7)).  Known runlevels are:
           
           ...
  4. Andere:

Literatur

(Übung)
(c) Copyright 1998-2006 Hubert Feyrer <hubert@feyrer.de>
$Id: 06-booting.html,v 1.21 2010-03-26 14:27:34 feyrer Exp $