A bootfolyamat

A Unix/Linux szerverek üzemeltetése wikiből
(Változatok közti eltérés)
a (Az init tevékenysége: kicsit részletesebb magyarázatok)
a (Bajok az inittel: nincs elég runlevel)
651. sor: 651. sor:
 
* Nem indítja újra a szolgáltatásokat, ha kilépnek (kivéve, ha az inittabból futtatjuk őket)
 
* Nem indítja újra a szolgáltatásokat, ha kilépnek (kivéve, ha az inittabból futtatjuk őket)
 
* De a respawnoló szolgáltatásokat egyáltalán nem lehet szelektíven leállítani - csak runlevelváltással
 
* De a respawnoló szolgáltatásokat egyáltalán nem lehet szelektíven leállítani - csak runlevelváltással
  +
** Viszont ahhoz kevés a használható runlevel, hogy minden reális szolgáltatáskombinációhoz külön legyen egy
 
* Az initscript örökli az őt indító shell környezetét
 
* Az initscript örökli az őt indító shell környezetét
 
** Vagyis parancssorból indítva a szolgáltatást nem biztos, hogy ugyanazt csinálja majd, mint bootkor
 
** Vagyis parancssorból indítva a szolgáltatást nem biztos, hogy ugyanazt csinálja majd, mint bootkor
658. sor: 659. sor:
   
 
A szolgáltatás leállításához általában valamilyen signalt (pl. TERM) kell küldeni a szolgáltatáshoz tartozó processznek.
 
A szolgáltatás leállításához általában valamilyen signalt (pl. TERM) kell küldeni a szolgáltatáshoz tartozó processznek.
  +
 
Csakhogy: mi a PID-ja ennek a processznek?
 
Csakhogy: mi a PID-ja ennek a processznek?
   

A lap 2007. október 15., 23:06-kori változata

Lássuk, hogyan bootol egy olyan Unix, ami nem BSD (a BSD-szerűségek egy kicsit másképp csinálják; ennek kidolgozása egy lehetséges házi feladat). Kivesézzük, mi a baj az ún. SystemV inittel, és megismerünk néhány alternatívát.

Tartalomjegyzék

1 A bootloader

A számítógép bekapcsolás után inicializálja magát (ez architektúránként mást és mást jelent), majd "valahonnan" betölt egy programot, amit elindít. Honnan?

  • konzol :)
  • lyukkártya, lyukszalag :)
  • diszk
  • cd
  • usb
  • hálózat (PXE, házi feladat)

Ez a program a bootloader (vagy egy idő után az lesz). A bootloader feladata betölteni és elindítani az operációs rendszert. Ezt a témát itt most nem lihegjük túl: mindenki látott már LILOt és grubot is.

Az initrd betöltése is a bootloader feladata.

2 A kernel

A kernel inicializálja a hardvert és elindítja az init folyamatot, ami 1-es PID-del fut és ennek köszönhetően számos signalt nem kap meg (a HUP és a PWR signalt igen). Ez initrd használata esetén nem pont így van - init helyett általában egy script indul el, ami betölti a rootfs felmountolásához szükséges modulokat, majd be is mountolja a rootfst, pivot_root-tal odavált, majd egy exec chroot /sbin/init jellegű paranccsal meghívja a tényleges initet.

3 Az init

Az init(8) először is beolvassa a /etc/inittabot. Nézzünk erre egy példát:

# /etc/inittab: init(8) configuration.
# $Id: inittab,v 1.8 1998/05/10 10:37:50 miquels Exp $

# The default runlevel.
id:2:initdefault:

# Boot-time system configuration/initialization script.
# This is run first except when booting in emergency (-b) mode.
si::sysinit:/etc/init.d/rcS

# What to do in single-user mode.
~~:S:wait:/sbin/sulogin

# /etc/init.d executes the S and K scripts upon change
# of runlevel.
#
# Runlevel 0 is halt.
# Runlevel 1 is single-user.
# Runlevels 2-5 are multi-user.
# Runlevel 6 is reboot.

l0:0:wait:/etc/init.d/rc 0
l1:1:wait:/etc/init.d/rc 1
l2:2:wait:/etc/init.d/rc 2
l3:3:wait:/etc/init.d/rc 3
l4:4:wait:/etc/init.d/rc 4
l5:5:wait:/etc/init.d/rc 5
l6:6:wait:/etc/init.d/rc 6
# Normally not reached, but fallthrough in case of emergency.
z6:6:respawn:/sbin/sulogin

# What to do when CTRL-ALT-DEL is pressed.
ca:12345:ctrlaltdel:/sbin/shutdown -t1 -a -r now

# Action on special keypress (ALT-UpArrow).
kb::kbrequest:/bin/echo "Keyboard Request--edit /etc/inittab to let this work."

# What to do when the power fails/returns.
pf::powerwait:/etc/init.d/powerfail start
pn::powerfailnow:/etc/init.d/powerfail now
po::powerokwait:/etc/init.d/powerfail stop

# /sbin/getty invocations for the runlevels.
#
# The "id" field MUST be the same as the last
# characters of the device (after "tty").
#
# Format:
#  <id>:<runlevels>:<action>:<process>
1:2345:respawn:/sbin/mingetty tty1
2:23:respawn:/sbin/mingetty tty2
3:23:respawn:/sbin/mingetty tty3
4:23:respawn:/sbin/mingetty tty4
5:23:respawn:/sbin/mingetty tty5
6:23:respawn:/sbin/mingetty tty6

# Example how to put a getty on a serial line (for a terminal)
#
#T0:23:respawn:/sbin/getty -L ttyS0 9600 vt100
T1:23:respawn:/sbin/getty -L ttyS1 9600 vt320

# Example how to put a getty on a modem line.
#
#T3:23:respawn:/sbin/mgetty -x0 -s 57600 ttyS3

Az init számos kulcsszót ismer, ezek közül néhány:

  • initdefault: ez az alapértelmezett runlevel, amibe bootkor váltani kell
  • sysinit: ezzel kezdődik a bootfolyamat
  • boot: a sysinit után kell lefuttatni
  • bootwait: mint a boot, de meg is kell várni, amíg végez
  • wait: az adott runlevelbe váltáskor le kell futtatni és meg kell várni, amíg kilép
  • once: az adott runlevelbe váltáskor le kell futtatni
  • respawn: az adott programot újra kell indítani, amikor kilép
  • ondemand: elvileg lehetnének ondemand runlevelek (a, b és c), amikbe "váltáskor" az adott program elindul, de a rendszer amúgy abban a runlevelben marad, amelyikben volt. Használja ezt bárki is?
  • power*: UPS-kezeléssel függ össze, nemigen szokás használni (van helyette pl. nut, ami megér egy házi feladatot)
  • ctrlaltdel: ezt kell lefuttatni, ha a user a konzolnál megnyomta a ctrl+alt+delt (más Unixon hogy van ez?)
  • kbrequest: egy billentyűkombinációhoz hozzárendelhetjük ezt az eseményt; ha a megfelelő gombokat megnyomják, lefut a megadott program. Lehet vele pl. billentyűzetkiosztást váltani. :)

3.1 A runlevel fogalma

A runlevel ("futási szint"?) elvileg véges sok szolgáltatáskombináció közül az egyik.

  • A 0-ás runlevel a rendszerleállítást "szokta" jelenteni
  • Az 1-es a single user módot
  • A 6-os az újraindítást
  • A többit elvileg szabadon definiálhatjuk
    • De minek?
    • Nem jellemző, hogy egy számítógép többféle komplex szolgáltatáscsomag közül hol az egyiket, hol a másikat nyújtaná

A runlevelekhez (a SystemV init esetén) tartozik egy-egy könyvtár, amiben symlinkek vannak az egyes szolgáltatásokat elindító ill. leállító scriptekre.

Runlevelváltáskor először a leállítóscriptek futnak "stop", majd az indítóscriptek "start" paraméterrel.

Ami K-val kezdődik, az leállítóscript, ami S-sel, az indítóscript. Az első betű utáni két szám a sorrendet adja meg.

Pl:

/etc/rc2.d# ls -la
total 7
drwxr-xr-x  2 root root 1024 Sep  6 00:05 .
drwxr-xr-x 69 root root 5120 Oct  4 15:35 ..
-rw-r--r--  1 root root  556 Jul 25 19:52 README
lrwxrwxrwx  1 root root   16 Aug  1 20:12 K01valami -> ../init.d/valami
lrwxrwxrwx  1 root root   18 Aug  1 20:12 S10sysklogd -> ../init.d/sysklogd
lrwxrwxrwx  1 root root   15 Aug  1 20:12 S11klogd -> ../init.d/klogd
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S16openvpn -> ../init.d/openvpn
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S20hddtemp -> ../init.d/hddtemp
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S20makedev -> ../init.d/makedev
lrwxrwxrwx  1 root root   23 Aug 29 18:49 S20openbsd-inetd -> ../init.d/openbsd-inetd
lrwxrwxrwx  1 root root   15 Sep  6 00:05 S20pound -> ../init.d/pound
lrwxrwxrwx  1 root root   15 Aug  1 20:12 S20qmail -> ../init.d/qmail
lrwxrwxrwx  1 root root   15 Aug  1 20:12 S20rsync -> ../init.d/rsync
lrwxrwxrwx  1 root root   23 Aug  1 20:12 S20smartmontools -> ../init.d/smartmontools
lrwxrwxrwx  1 root root   13 Aug  1 20:12 S20ssh -> ../init.d/ssh
lrwxrwxrwx  1 root root   14 Aug 29 17:36 S20xend -> ../init.d/xend
lrwxrwxrwx  1 root root   20 Aug 29 17:36 S21xendomains -> ../init.d/xendomains
lrwxrwxrwx  1 root root   13 Aug 30 11:35 S23ntp -> ../init.d/ntp
lrwxrwxrwx  1 root root   15 Aug 30 18:21 S25mdadm -> ../init.d/mdadm
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S50systune -> ../init.d/systune
lrwxrwxrwx  1 root root   14 Aug  1 20:12 S89cron -> ../init.d/cron
lrwxrwxrwx  1 root root   20 Aug  1 20:12 S98munin-node -> ../init.d/munin-node
lrwxrwxrwx  1 root root   22 Aug  1 20:12 S99firewall -> /etc/firewall/firewall
lrwxrwxrwx  1 root root   19 Aug  1 20:12 S99rmnologin -> ../init.d/rmnologin
lrwxrwxrwx  1 root root   23 Aug  1 20:12 S99stop-bootlogd -> ../init.d/stop-bootlogd
lrwxrwxrwx  1 root root   12 Aug 30 18:39 S99ud -> ../init.d/ud

3.2 Az init tevékenysége

Először elindítja a sysinit jelzéssel ellátott programot; Debianon ez a /etc/init.d/rcS. Nézzük, mit csinál:

#! /bin/sh
#
# rcS
#
# Call all S??* scripts in /etc/rcS.d/ in numerical/alphabetical order
#

exec /etc/init.d/rc S

OK, akkor nézzük a /etc/init.d/rc-t (figyelem, valóságos szörnyszülött):

#! /bin/sh
#
# rc
#
# Starts/stops services on runlevel changes.
#
# Optimization: A start script is not run when the service was already
# configured to run in the previous runlevel.  A stop script is not run
# when the the service was already configured not to run in the previous
# runlevel.
#
# Authors:
#       Miquel van Smoorenburg <miquels@cistron.nl>
#       Bruce Perens <Bruce@Pixar.com>

PATH=/sbin:/bin:/usr/sbin:/usr/bin
export PATH

# Un-comment the following for debugging.
# debug=echo

# Specify method used to enable concurrent init.d scripts.
# Valid options are 'none', 'shell' and 'startpar'
CONCURRENCY=none

Ez aránylag új: korábban nem lehetett párhuzamosítani az initscriptek futtatását. Most sem feltétlenül jó ötlet.


# Make sure the name survive changing the argument list
scriptname="$0"

umask 022

on_exit() {
    echo "error: '$scriptname' exited outside the expected code flow."
}
trap on_exit EXIT # Enable emergency handler

Ez azért kell, mert így legalább látjuk, ha valahol lukra fut.


# Ignore CTRL-C only in this shell, so we can interrupt subprocesses.
trap ":" INT QUIT TSTP

# Set onlcr to avoid staircase effect.
stty onlcr 0>&1

Megkérjük a terminált, hogy minden soremelés után írjon ki egy kocsivisszát is.


# Decide if usplash progress bar should be activated or not.  Override
# in /etc/default/rcS if required.
if type usplash_write >/dev/null 2>&1; then
    SPLASH=true
else
    SPLASH=false
fi

Nagyon fontos: grafikus splashscreen támogatása, színes-szagos bitkolbásszal...


# Now find out what the current and what the previous runlevel are.

runlevel=$RUNLEVEL
# Get first argument. Set new runlevel to this argument.
[ "$1" != "" ] && runlevel=$1
if [ "$runlevel" = "" ]
then
        echo "Usage: $scriptname <runlevel>" >&2
        exit 1
fi
previous=$PREVLEVEL
[ "$previous" = "" ] && previous=N

export runlevel previous

if [ S = "$runlevel" ]
then
        #
        # See if system needs to be setup. This is ONLY meant to
        # be used for the initial setup after a fresh installation!
        #
        if [ -x /sbin/unconfigured.sh ]
        then
                /sbin/unconfigured.sh
        fi
fi

. /etc/default/rcS
export VERBOSE

Itt a /etc/default/rcS file-ból konfigurációs változókat olvasunk be. Ezek közül az egyik a VERBOSE, amit a gyermekfolyamatainkkal is meg akarunk osztani.


#
# Stub to do progress bar ticks (currently just for usplash) on startup
#
startup_progress() {
    $@
    if [ "$SPLASH" = true ] ; then
        step=$(($step + $step_change))
        progress=$(($step * $progress_size / $num_steps + $first_step))
        usplash_write "PROGRESS $progress" || true
    fi
}

#
# Start script or program.
#

Most fogjuk definiálni a startup() függvényt aszerint, hogy mi az értéke a CONCURRENCY változónak:

case "$CONCURRENCY" in
  none)
        startup() {
                action=$1
                shift
                scripts="$@"
                sh=sh
                # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced
                # However, some important packages currently contain .sh scripts
                # that do "exit" at some point, thus killing this process.  Bad!
                #[ S = "$runlevel" ] && sh=.
                for script in $scripts ; do
                        case "$script" in
                          *.sh)
                                if [ "." = "$sh" ] ; then
                                        set "$action"

Ez itt azt csinálta, hogy az "$action"-t írta a $1-be; ezután majd source-olja a meghívandó scriptet.

                                        RC_SAVE_PATH="$PATH"
                                        startup_progress $debug . "$script"
                                        PATH="$RC_SAVE_PATH"

A PATH-os trükközés azért kell, hogy a meghívott script - ami ugyanebben a shellben fut - ne tudja elbarmolni a PATH változót.

                                else
                                        startup_progress $debug $sh "$script" $action
                                fi
                                ;;
                          *)
                                startup_progress $debug "$script" $action
                                ;;
                        esac
                done
        }
        ;;
  shell)
        startup() {
                action=$1
                shift
                scripts="$@"
                sh=sh
                # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced
                # However, some important packages currently contain .sh scripts
                # that do "exit" at some point, thus killing this process.  Bad!
                #[ S = "$runlevel" ] && sh=.
                backgrounded=0
                for script in $scripts ; do
                        case "$script" in
                          *.sh)
                                if [ "." = "$sh" ] ; then
                                        set "$action"
                                        RC_SAVE_PATH="$PATH"
                                        startup_progress $debug . "$script"
                                        PATH="$RC_SAVE_PATH"
                                else
                                        startup_progress $debug $sh "$script" $action
                                fi
                                ;;
                          *)
                                startup_progress $debug "$script" $action &
                                backgrounded=1
                                ;;
                        esac
                done
                [ 1 = "$backgrounded" ] && wait

Itt a nem .sh végű initscripteket párhuzamosan elindítja a háttérben, majd megvárja, amíg mind kilép.

        }
        ;;
  startpar)
        startup() {
                action=$1
                shift
                scripts="$@"
                sh=sh
                # Debian Policy §9.3.1 requires .sh scripts in runlevel S to be sourced
                # However, some important packages currently contain .sh scripts
                # that do "exit" at some point, thus killing this process.  Bad!
                #[ S = "$runlevel" ] && sh=.
                # Make sure .sh scripts are sourced in runlevel S
                if [ "." = "$sh" ] ; then
                        newscripts=
                        for script in $scripts ; do
                                case "$script" in
                                  *.sh)
                                        set "$action"
                                        RC_SAVE_PATH="$PATH"
                                        startup_progress $debug . "$script"
                                        PATH="$RC_SAVE_PATH"
                                        ;;
                                  *)
                                        newscripts="$newscripts $script"
                                        ;;
                                esac
                        done
                        scripts="$newscripts"

scripts itt már csak azokat a scripteket tartalmazza, amiket nem tudunk source-olni.

                fi

                # startpar is not able to handle time jumps.  So the
                # hwclock.sh scripts should not be executed from
                # within startpar.  The .sh hack above make this
                # problem irrelevant. [pere 2005-09-10]
                [ -n "$scripts" ] && startup_progress $debug startpar -a $action $scripts

A startpar párhuzamosan lefuttatja a megadott scripteket, és ügyesen összefésüli a kimenetüket. Azt érezzük, hogy ez itt desktop-gányolás - kit érdekel, milyen gyorsan bootol be a szerver? Úgyse rebootoljuk minden évben... :)

        }
        ;;
esac

# Is there an rc directory for this new runlevel?
if [ -d /etc/rc$runlevel.d ]

Megnézzük, van-e rc1.d, rc2.d stb. jellegű könyvtár ahhoz a runlevelhez, amibe váltanunk kell.

then
        # Find out where in the progress bar the initramfs got to.
        PROGRESS_STATE=0
        if [ -f /dev/.initramfs/progress_state ]; then
            . /dev/.initramfs/progress_state
        fi

        # Split the remaining portion of the progress bar into thirds
        progress_size=$(((100 - $PROGRESS_STATE) / 3))

Ezek megint fontos bitkolbászos teendők.

        case "$runlevel" in
                0|6)
                        ACTION=stop
                        # Count down from 0 to -100 and use the entire bar
                        first_step=0
                        progress_size=100
                        step_change=-1
                        ;;
                S)
                        ACTION=start
                        # Begin where the initramfs left off and use 2/3
                        # of the remaining space
                        first_step=$PROGRESS_STATE
                        progress_size=$(($progress_size * 2))
                        step_change=1
                        ;;
                *)
                        ACTION=start
                        # Begin where rcS left off and use the final 1/3 of
                        # the space (by leaving progress_size unchanged)
                        first_step=$(($progress_size * 2 + $PROGRESS_STATE))
                        step_change=1
                        ;;
        esac

        if [ "$SPLASH" = true ] ; then
            # Count the number of scripts we need to run (for usplash
            # progress bar)
            num_steps=0
            for s in /etc/rc$runlevel.d/[SK]*; do
                case "${s##/etc/rc$runlevel.d/S??}" in
                 gdm|xdm|kdm|reboot|halt)
                    break
                    ;;
                esac
                num_steps=$(($num_steps + 1))
            done
            step=0
        fi

        # First, run the KILL scripts.
        if [ "$previous" != N ]
        then
                # Run all scripts with the same level in parallel
                CURLEVEL=""
                for s in /etc/rc$runlevel.d/K*

Végigmegyünk az összes, az adott runlevelhez tartozó K-val kezdődő nevű scripten.

                do
                        level=$(echo $s | sed 's/.*\/K\([0-9][0-9]\).*/\1/')

Csak a K betű után álló két számot nézzük.

                        if [ "$level" = "$CURLEVEL" ]
                        then
                                continue
                        fi

Ha ez a sorszám már volt, akkor ugrunk a következő scriptre.

                        CURLEVEL=$level
                        SCRIPTS=""
                        for i in /etc/rc$runlevel.d/K$level*

Itt pedig "egyszerre" le fogjuk futtatni az összes olyat, ami az aktuális sorszámot viseli.

                        do
                                # Check if the script is there.
                                [ ! -f $i ] && continue

                                #
                                # Find stop script in previous runlevel but
                                # no start script there.
                                #
                                suffix=${i#/etc/rc$runlevel.d/K[0-9][0-9]}
                                previous_stop=/etc/rc$previous.d/K[0-9][0-9]$suffix
                                previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
                                #
                                # If there is a stop script in the previous level
                                # and _no_ start script there, we don't
                                # have to re-stop the service.
                                #
                                [ -f $previous_stop ] && [ ! -f $previous_start ] && continue

Hurrá! Ennyi szüttyögéssel kioptimalizáltunk egy scriptfuttatást! Halleluja!

                                # Stop the service.
                                SCRIPTS="$SCRIPTS $i"
                        done
                        startup stop $SCRIPTS

Ez ugyebár az a startup() függvény, amit fent okosan egy case utasításon belül deklaráltunk, valószínűleg azért, hogy ha valamelyik source-olt script játszik a CONCURRENCY változó értékével, akkor ne változzon meg a startup() függvény viselkedése. Persze a script új startup() függvényt is definiálhat...

                done
        fi

        # Now run the START scripts for this runlevel.
        # Run all scripts with the same level in parallel

Ez most ugyanaz lesz, mint az előbb, csak az S-sel kezdődő nevű scriptekre.

        CURLEVEL=""
        step=0
        for s in /etc/rc$runlevel.d/S*
        do
                level=$(echo $s | sed 's/.*\/S\([0-9][0-9]\).*/\1/')
                if [ "$level" = "$CURLEVEL" ]
                then
                        continue
                fi
                CURLEVEL=$level
                SCRIPTS=""
                for i in /etc/rc$runlevel.d/S$level*
                do
                        [ ! -f $i ] && continue

                        if [ "$previous" != N ]
                        then
                                #
                                # Find start script in previous runlevel and
                                # stop script in this runlevel.
                                #
                                suffix=${i#/etc/rc$runlevel.d/S[0-9][0-9]}
                                stop=/etc/rc$runlevel.d/K[0-9][0-9]$suffix
                                previous_start=/etc/rc$previous.d/S[0-9][0-9]$suffix
                                #
                                # If there is a start script in the previous level
                                # and _no_ stop script in this level, we don't
                                # have to re-start the service.
                                #
                                [ -f $previous_start ] && [ ! -f $stop ] && continue
                        fi
                        SCRIPTS="$SCRIPTS $i"
                done
                startup $ACTION $SCRIPTS
        done
fi

if [ S = "$runlevel" ]
then
        #
        # For compatibility, run the files in /etc/rc.boot too.
        #
        [ -d /etc/rc.boot ] && run-parts /etc/rc.boot

        #
        # Finish setup if needed. The comment above about
        # /sbin/unconfigured.sh applies here as well!
        #
        if [ -x /sbin/setup.sh ]
        then
                /sbin/setup.sh
        fi
fi

trap - EXIT # Disable emergency handler

exit 0

Az első runlevel, amibe váltunk, az S. Nézzük, mi történik ebben a runlevelben egy átlagos szerveren:

/etc/rcS.d# ls -la
total 7
drwxr-xr-x  2 root root 1024 Sep  4 16:35 .
drwxr-xr-x 69 root root 5120 Oct  4 15:35 ..
-rw-r--r--  1 root root  785 Jul 25 19:51 README
lrwxrwxrwx  1 root root   24 Aug  1 20:12 S02mountkernfs.sh -> ../init.d/mountkernfs.sh
lrwxrwxrwx  1 root root   18 Aug  1 20:12 S04bootlogd -> ../init.d/bootlogd
lrwxrwxrwx  1 root root   26 Aug  1 20:12 S04mountdevsubfs.sh -> ../init.d/mountdevsubfs.sh
lrwxrwxrwx  1 root root   16 Aug 30 17:35 S07hdparm -> ../init.d/hdparm
lrwxrwxrwx  1 root root   22 Aug  1 20:12 S10checkroot.sh -> ../init.d/checkroot.sh
lrwxrwxrwx  1 root root   14 Aug 31 19:23 S10udev -> ../init.d/udev
lrwxrwxrwx  1 root root   25 Aug 29 18:19 S18hwclockfirst.sh -> ../init.d/hwclockfirst.sh
lrwxrwxrwx  1 root root   24 Aug  1 20:12 S18ifupdown-clean -> ../init.d/ifupdown-clean
lrwxrwxrwx  1 root root   27 Aug  1 20:12 S20module-init-tools -> ../init.d/module-init-tools
lrwxrwxrwx  1 root root   18 Aug  1 20:12 S20modutils -> ../init.d/modutils
lrwxrwxrwx  1 root root   20 Aug 29 18:19 S22hwclock.sh -> ../init.d/hwclock.sh
lrwxrwxrwx  1 root root   26 Aug  1 20:12 S25libdevmapper1.02 -> ../init.d/libdevmapper1.02
lrwxrwxrwx  1 root root   20 Aug 30 18:21 S25mdadm-raid -> ../init.d/mdadm-raid
lrwxrwxrwx  1 root root   13 Aug  1 20:12 S26lvm -> ../init.d/lvm
lrwxrwxrwx  1 root root   20 Aug  1 20:12 S30checkfs.sh -> ../init.d/checkfs.sh
lrwxrwxrwx  1 root root   19 Aug  1 20:12 S30procps.sh -> ../init.d/procps.sh
lrwxrwxrwx  1 root root   21 Aug  1 20:12 S35mountall.sh -> ../init.d/mountall.sh
lrwxrwxrwx  1 root root   31 Aug  1 20:12 S36mountall-bootclean.sh -> ../init.d/mountall-bootclean.sh
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S36mtab.sh -> ../init.d/mtab.sh
lrwxrwxrwx  1 root root   18 Aug  1 20:12 S39ifupdown -> ../init.d/ifupdown
lrwxrwxrwx  1 root root   21 Aug  1 20:12 S40hostname.sh -> ../init.d/hostname.sh
lrwxrwxrwx  1 root root   20 Aug  1 20:12 S40networking -> ../init.d/networking
lrwxrwxrwx  1 root root   21 Aug  1 20:12 S45mountnfs.sh -> ../init.d/mountnfs.sh
lrwxrwxrwx  1 root root   31 Aug  1 20:12 S46mountnfs-bootclean.sh -> ../init.d/mountnfs-bootclean.sh
lrwxrwxrwx  1 root root   20 Aug 29 18:23 S47lm-sensors -> ../init.d/lm-sensors
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S51ntpdate -> ../init.d/ntpdate
lrwxrwxrwx  1 root root   21 Aug  1 20:12 S55bootmisc.sh -> ../init.d/bootmisc.sh
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S55urandom -> ../init.d/urandom
lrwxrwxrwx  1 root root   17 Aug  1 20:12 S70nviboot -> ../init.d/nviboot
lrwxrwxrwx  1 root root   24 Aug  1 20:12 S70screen-cleanup -> ../init.d/screen-cleanup
lrwxrwxrwx  1 root root   14 Aug 29 18:22 S75sudo -> ../init.d/sudo
lrwxrwxrwx  1 root root   30 Aug  1 20:12 S99stop-bootlogd-single -> ../init.d/stop-bootlogd-single

Miután ezek lefutottak, mehetünk a 2-es runlevelbe (listát l. fent).

Ha a runlevelváltás sikerült, elindulnak a mingetty-k és beléphetünk a konzolon.

3.3 Az init használata

  • Van egy -b opciója, aminek a hatására a sysinitet sem hajtja végre, hanem egyből single user módba megy
  • init u hatására az init végrehajt egy exec('/sbin/init')-et - így lehet frissíteni
  • init q vagy HUP signal hatására újraolvassa az inittabot
  • init runlevel hatására az adott runlevelbe vált

4 Bajok az inittel

  • Aránylag bonyolult maga az init program; ellenkezik a Unix-filozófiával, hogy több mindent csinál.
    • Elég lenne, ha le tudná futtatni, ami kell a rendszerinduláshoz
      • Ez lehetne egyetlen program is
    • A respawnt is csinálhatná külső program
    • UPS-kezelést pláne
  • Minden shellscriptes trükközés ellenére lassú
  • Nem indítja újra a szolgáltatásokat, ha kilépnek (kivéve, ha az inittabból futtatjuk őket)
  • De a respawnoló szolgáltatásokat egyáltalán nem lehet szelektíven leállítani - csak runlevelváltással
    • Viszont ahhoz kevés a használható runlevel, hogy minden reális szolgáltatáskombinációhoz külön legyen egy
  • Az initscript örökli az őt indító shell környezetét
    • Vagyis parancssorból indítva a szolgáltatást nem biztos, hogy ugyanazt csinálja majd, mint bootkor
  • Nem triviális leállítani egy szolgáltatást, vagy signalt küldeni neki

4.1 Szolgáltatások leállítása á la init

A szolgáltatás leállításához általában valamilyen signalt (pl. TERM) kell küldeni a szolgáltatáshoz tartozó processznek.

Csakhogy: mi a PID-ja ennek a processznek?

A "megoldás": pidfile. De:

  • A pidfile-t le lehet törölni, felül lehet írni
  • Ha a program kilép, a megadott PIDdel indulhat másik processz - ha ennek küldjük a signalt, az Nem Jó

Így aztán ilyen megoldások születnek:


ENV="env -i LANG=C PATH=/usr/local/bin:/usr/bin:/bin"
APACHE2="$ENV /usr/sbin/apache2"
APACHE2CTL="$ENV /usr/sbin/apache2ctl"

apache_stop() {
        PID=""
        PIDFILE=""
        AP_CONF=/etc/apache2/apache2.conf

        # apache2 allows more than PidFile entry in the config but only the
        # last found in the config is used; we attempt to follow includes
        # here, but only first-level includes are supported, not nested ones

        for i in $AP_CONF `awk '$1 ~ /^\s*[Ii]nclude$/ && $2 ~ /^\// {print $2}' $AP_CONF`; do
                PIDFILE=`grep -i ^PidFile $i | tail -n 1 | awk '{print $2}'`
                if [ -e "$PIDFILE" ]; then
                        PID=`cat $PIDFILE`
                fi
        done
        
        errors=`$APACHE2 -t 2>&1`
        if [ $? = 0 ]; then
                # if the config is ok then we just stop normally

                if [ -n "$PID" ]
                then
                        $APACHE2CTL stop

                        CNT=0
                        while [ 1 ]
                        do
                                CNT=$(expr $CNT + 1)
                
                                [ ! -d /proc/$PID ] && break	# Versenyhelyzet...

                                if [ $CNT -gt 60 ]
                                then
                                        if [ "$VERBOSE" != "no" ]; then
                                                echo " ... failed!"
                                                echo "Apache2 failed to honor the stop command, please investigate the situation by hand."
                                        fi
                                        return 1
                                fi

                                sleep 1
                        done
                else
                        if [ "$VERBOSE" != "no" ]; then
                                echo -n " ... no pidfile found! not running?"	# Te vagy a számítógép, mondd meg te, hogy fut-e!
                        fi
                fi

        else
                [ "$VERBOSE" != "no" ] && echo "$errors"

                # if we are here something is broken and we need to try
                # to exit as nice and clean as possible

                # if pidof is null for some reasons the script exits automagically
                # classified as good/unknown feature
                PIDS=`pidof apache2` || true

                REALPID=0
                # if there is a pid we need to verify that belongs to apache2
                # for real
                for i in $PIDS; do
                        if [ "$i" = "$PID" ]; then
                                # in this case the pid stored in the
                                # pidfile matches one of the pidof apache
                                # so a simple kill will make it
                                REALPID=1
                        fi
                done

                if [ $REALPID = 1 ]; then
                        # in this case everything is nice and dandy
                        # and we kill apache2
                        kill $PID
                else
                        # this is the worst situation... just kill all of them
                        #for i in $PIDS; do
                        #       kill $i
                        #done
                        # Except, we can't do that, because it's very, very bad
                        if [ "$PIDS" ] && [ "$VERBOSE" != "no" ]; then
                                echo " ... failed!"
                                echo "You may still have some apache2 processes running.  There are"
                                echo "processes named 'apache2' which do not match your pid file,"
                                echo "and in the name of safety, we've left them alone.  Please review"
                                echo "the situation by hand."
                        fi
                        return 1
                fi
        fi
}

Rossz nézni.

Alternatívát kínál:

5 Ajánlott irodalom

6 Potenciális ZH-kérdések

  • Sorolj fel legalább három különböző kulcsszót a /etc/inittabból; mire valók, mikor szokás őket használni? (Pl: "A kbrequest opcióval megadott program akkor fog lefutni, amikor a konzolon lenyomjuk azt a billentyűkombinációt, amihez a 'kbrequest' kódját rendeltük; alapértelmezés szerint nincs ilyen, és a kbrequestnek alapértelmezett felhasználása sincs. Lehet pl. billentyűzetkiosztás-váltásra, vagy a cd unmountolására és kidobására használni.")
  • Mi a runlevel?
  • Ismertesd az rc.d-mechanizmus működését! Mikor érdemes használni? Mik az előnyei (és mihez képest)?
  • Hogyan történik a runlevelek közötti váltás System V init használata esetén? (Nem az a kérdés, hogyan kell kiváltani, hanem hogy milyen folyamat játszódik le runlevel-váltás közben.)
  • Milyen problémák vannak a System V inittel?
  • Miért nehéz a System V init használata esetén egy daemonizált szolgáltatás leállítása?
Személyes eszközök