A bootfolyamat
(Néhány zh-kérdés hozzáadva) |
a (link a linuxkonfos előadásra) |
||
779. sor: | 779. sor: | ||
* http://www-128.ibm.com/developerworks/library/l-linuxboot/index.html - Egy egész jó, viszonylag friss leírás a Linux bootfolyamatáról |
* http://www-128.ibm.com/developerworks/library/l-linuxboot/index.html - Egy egész jó, viszonylag friss leírás a Linux bootfolyamatáról |
||
+ | * A [http://konf2006.linux.hu/ VIII. GNU/Linux Szakmai Konferencián] a témáról tartott [[Extrém rendszeradminisztráció: djbware és társai|előadásom]] |
||
== Potenciális ZH-kérdések == |
== Potenciális ZH-kérdések == |
A lap 2006. november 23., 23:16-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
Elindította a háttérben, majd megvárja, amíg a gyermekfolyamat kilép. Van ennek értelme?
} ;; 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.
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
- Elég lenne, ha le tudná futtatni, ami kell a rendszerinduláshoz
- 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
- 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:
- daemontools (részben)
- runit (teljesen)
- initng (házi feladat)
- Solaris SMF (házi feladat)
- egyéb (házi feladat :)
5 Ajánlott irodalom
- http://www-128.ibm.com/developerworks/library/l-linuxboot/index.html - Egy egész jó, viszonylag friss leírás a Linux bootfolyamatáról
- A VIII. GNU/Linux Szakmai Konferencián a témáról tartott előadásom
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?