1.18 2005-05-06
Runlevely Boot systému

Během bootování systému si pravděpodobně všimnete toho, jak po monitoru ubíhá poměrně hodně textu. Budete-li pozorní, zjistíte, že při každém rebootu jde o ty samé informace. Pořadí těchto akcí se nazývá bootovací sekvence a je (do značné míry) pevně daná.

Nejprve bootloader načte do paměti obraz jádra (určený v konfiguračním souboru) a předá jej CPU k provedení. Kernel si poté zinicializuje potřebné datové struktury a pochody a spustí proces init.

Tento proces postupně namountuje všechny potřebné souborové systémy (určeno v /etc/fstab) a spustí různé soubory z adresáře /etc/init.d, které se starají o spuštění služeb, které potřebujete k bezproblémovému provozu počítače.

Nakonec, když jsou všechny skripty provedeny, aktivuje init terminály (ve většině případů pouze virtuální konzole ukryté za Alt-F1, Alt-F2 atd) pomocí procesu agetty. Ten se postará o to, abyste se byli schopni přihlásit - spustí login.

Init skripty

init samozřejmě neprovádí skripty z adresáře /etc/init.d náhodně. Nejen, že dodržuje jejich správné pořadí, ale provádí jenom ty, které má. Všechny potřebné informace má k dispozici v adresáři /etc/runlevels.

Nejprve spouští init ty skripty z /etc/init.d, na které vede odkaz z /etc/runlevels/boot. Většinou je pořadí spouštění určeno abecedně, ale některé skripty obsahují informace o závislostech, podle kterých systém zjistí, že je potřeba nejdříve spustit jiný skript.

Po zpracování /etc/runlevels/boot pokračuje init skripty, na které vede symbolický odkaz z in /etc/runlevels/default. Znovu platí, že pořadí jejich spuštění je určeno abecedně, a případné závislosti jsou dodrženy.

Jak init pracuje

Samozřejmě se init o tom všem nerozhoduje sám; potřebuje konfigurační soubor, který mu říká, co má dělat. Tento soubor se jmenuje /etc/inittab.

Pamatujete-li si na bootovací sekvenci, jistě si vzpomenete i na to, že jako první byly připojeny potřebné souborové systémy. Tuto akci obstará následující řádek v /etc/inittab:

si::sysinit:/sbin/rc sysinit

Tento řádek říká initu, že pro inicializaci systému musí musí spustit /sbin/rc sysinit. Skript /sbin/rc se o ni postará; můžeme tedy říci, že init toho moc nedělá - úkol pouze převede na jiný proces.

Jako druhý krok init provede všechny skripty, na které vedou symbolické odkazy z /etc/runlevels/boot, viz tento řádek:

rc::bootwait:/sbin/rc boot

O samotné provedení úkolu se opět stará skript rc. Povšimněte si, že parametr předaný skriptu (boot) je zároveň i jméno použitého adresáře uvnitř /etc/runlevels.

Nyní se init podívá do svého konfiguračního souboru, aby zjistil, v jakém runlevelu má systém běžet. Řádka z /etc/inittab:

id:3:initdefault:

V tomto případě (který bude používat většina uživatelů Gentoo) je číslo runlevelu 3. init tedy zjistí, že musí spustit runlevel 3:

l0:0:wait:/sbin/rc shutdown
l1:S1:wait:/sbin/rc single
l2:2:wait:/sbin/rc nonetwork
l3:3:wait:/sbin/rc default
l4:4:wait:/sbin/rc default
l5:5:wait:/sbin/rc default
l6:6:wait:/sbin/rc reboot

Opět vidíme, že řádka definující runlevel 3 používá ke spuštění služeb skript rc, nyní s parametrem default. Parametr předaný skriptu rc se znovu shoduje se jménem adresáře z /etc/runlevels.

rc skončí svoji práci, init se rozhodne, jaké virtuální konzole má aktivovat a jaké programy na nich spustit:

c1:12345:respawn:/sbin/agetty 38400 tty1 linux
c2:12345:respawn:/sbin/agetty 38400 tty2 linux
c3:12345:respawn:/sbin/agetty 38400 tty3 linux
c4:12345:respawn:/sbin/agetty 38400 tty4 linux
c5:12345:respawn:/sbin/agetty 38400 tty5 linux
c6:12345:respawn:/sbin/agetty 38400 tty6 linux
Co je to runlevel?

Ukázali jsme, že se init při rozhodování o tom, do jakého runlevelu vstoupit, drží číselného schématu. Runlevel je stav, ve kterém Váš systém běží; váží se k němu skripty (skripty runlevelu nebo init skripty), které musí být spuštěny, když systém do runlevelu vstupuje a nebo jej ukončuje.

V Gentoo je definováno sedm runlevelů: tři pro vnitřní potřebu a čtyři uživatelsky definované. Runlevely pro vnitřní potřebu jsou sysinit, shutdown a reboot a dělají to, co jejich jména napovídají - starají se o inicializaci systému, jeho vypnutí a restart.

Uživatelsky definované runlevely jsou ty, které používají podadresář /etc/runlevels - boot, default, nonetwork a single. Runlevel boot spouští všechny nezbytné služby, které dále používají další runlevely. Zbývající tři runlevely se odlišují počtem a druhy služeb, které spouští: runlevel default slouží pro běžný chod systému, nonetwork pro dobu, kdy není potřeba síť, a single tehdy, je-li potřeba opravit systém.

Práce s init skripty

Skripty, které spouští proces rc, se nazývají init skripty. Každý ze skriptů uložených v /etc/init.d může být spuštěn s parametry start, stop, restart, pause, zap, status, ineed, iuse, needsme, usesme nebo broken.

Pro spuštění, zastavení a nebo restart služby (a zároveň všech služeb, které na ní závisí), slouží parametry start, stop a restart:

# /etc/init.d/postfix start
Pouze služby, které ji potřebují, jsou zastaveny nebo restartovány. Další na ní závislé služby (ty, které ji používají, ale nepotřebují), nejsou dotčeny.

Chcete-li zastavit službu, ale ne další služby, které na ní závisí, můžete použít parametr pause:

# /etc/init.d/postfix pause

Chcete-li vědět, v jakém stavu se daná služba právě nachází (zda běží, je ukončená a nebo pozastavená), můžete použít argument status:

# /etc/init.d/postfix status

Říká-li informace o stavu, že služba běží, avšak Vy víte, že ne, můžete tuto informaci změnit pomocí argumentu zap:

# /etc/init.d/postfix zap

Pro zjištění závislostí služby můžete použít iuse či ineed. Parametr ineed vypíše seznam služeb, které služba aktuální ke svému chodu opravdu potřebuje; iuse naproti tomu ukáže ty služby, které daná služba používat může, ale ke správné funkci je nutně nevyžaduje.

# /etc/init.d/postfix ineed

Podobně se můžete dotázat na služby, které danou službu potřebují (needsme) nebo mohou používat (usesme):

# /etc/init.d/postfix needsme

Konečně, je možné požádat i o výpis závislostí, které služba vyžaduje, ale které chybí:

# /etc/init.d/postfix broken
Práce s rc-update Co je rc-update?

Init systém Gentoo používá pro rozhodování o pořadí spouštění služeb strom závislostí. Protože jeho udržování je poměrně zdlouhavé a únavné, vytvořili jsme nástroje, které správu runlevelů a init skriptů usnadňují.

Nástrojem rc-update můžete do runlevelu přidávat a odebírat skripty, a on se sám postará o zavolání skriptu depscan.sh pro znovuvytvoření stromu závislostí

Přidání a odebírání služeb

Během instalace Gentoo jste již init skripty přidávali do runlevelu "default". Tehdy jste možná ještě neměli páru, k čemu onen "default" slouží, ale teď už byste to vědět měli. Skript rc-update vyžaduje i druhý argument definující akci k provedení: add, del nebo show.

Pro přidání či odebrání init skriptu jednoduše spusťte rc-update s argumentem add (přidání) nebo del (odebrání) následovaným jménem init skriptu a runlevelem. Například takto:

# rc-update del postfix default

Příkaz rc-update show zobrazí dostupné init skripty a patřičné runlevely, ve kterých jsou skripty aktivní:

# rc-update show
Konfigurace služeb K čemu další konfigurace?

Init skripty mohou být poměrně komplexní, a proto není vhodné, aby je měnili uživatelé sami, kvůli riziku zanesení chyb. Služby je však potřeba konfigurovat, například někdy můžete potřebovat předat samotné službě další parametry.

Druhým důvodem k tomu, abychom udržovali informace o konfiguraci mimo init skript jsou aktualizace, resp. zamezení obavám o to, že o svoji konfiguraci během aktualizace přejdete.

Adresář /etc/conf.d

Konfigurace služeb je v Gentoo snadná - každý konfigurovatelný init skript má svůj soubor v adresáři /etc/conf.d. Kupříkladu konfigurace init skriptu apache2 (/etc/init.d/apache2) se provádí v souboru /etc/conf.d/apache2; tento obsahuje parametry předávané serveru Apache 2 při jeho spuštění:

APACHE2_OPTS="-D PHP4"

V těchto konfiguračních souborech nenajdete nic než proměnné, ovlivňující chování daného init skriptu, a samozřejmě komentáře. Formát je podobný jako v /etc/make.conf.

Psaní init skriptu Musím?

Ne, psaní init skriptů většinou není nutné, protože Gentoo poskytuje skripty připravené k použití. Avšak je možné, že jste si nainstalovali nějakou službu, která není v Portage, a v takovém případě si budete muset init skript pravděpodobně vytvořit.

Nepoužívejte init skript, který není napsaný přímo pro Gentoo -- formát jiných distribucí není s naším kompatibilní!

Schéma

Základní uspořádání init skriptu je ukázáno níže:

#!/sbin/runscript

depend() {
  (informace o závislostech)
}

start() {
  (příkazy potřebné pro start služby)
}

stop() {
  (příkazy nezbytné pro zastavení služby)
}

restart() {
  (příkazy potřebné pro restart služby)
}

Každý init skript musí obsahovat funkci start(), všechny další sekce jsou volitelné.

Závislosti

Můžete definovat dva druhy závislostí: use a need. Jak již bylo zmíněno výše, need je striktnější než use. Obě dvě akceptují buď jméno služby, kterou potřebujete či používáte a nebo virtuální závislost.

Virtuální závislost může být poskytovaná více službami. Váš init skript může například záviset na systémovém loggeru, avšak protože jich je více možných (metalogd, syslog-ng, sysklogd,...), a služba nemůže přes need záviset na všech (žádný rozumný systém nemá všechny nainstalované a spouštěné), použijete virtuální závislost, poskytovanou pomocí provide.

Podívejme se na na informace o závislostech pro službu postfix:

depend() {
  need net
  use logger dns
  provide mta
}

Jak můžete vidět, služba postfix:

  • vyžaduje (virtuální) závislost net (kterou poskytuje například /etc/init.d/net.eth0)
  • používá (virtuální) závislost logger (kterou poskytuje například /etc/init.d/syslog-ng)
  • používá (virtuální) závislost dns (kterou poskytuje například /etc/init.d/named)
  • poskytuje (virtuální) závislost mta (která je společná pro všechny mailservery)
Kontrola pořadí

V některých případech nebudete nějakou službu potřebovat, ale přejete si, aby byla ta Vaše spuštěna před (before) nebo až po (after) nějaké jiné, pokud je tato v systému přítomná (povšimněte si podmínky - již nejde o závislost) a zároveň je ve stejném runlevelu (opět podmínka - v úvahu jsou brány pouze služby ve stejném runlevelu). Takového chování můžete dosáhnout pomocí nastavení before nebo after.

Jako příklad se podíváme na nastavení služby portmap:

depend() {
  need net
  before inetd
  before xinetd
}

Také můžete použít metaznak "*", který znamená "všechny služby v runlevelu", avšak není to doporučeno.

depend() {
  before *
}
Standardní funkce

Dále je potřeba definovat funkci start(), která musí obsahovat všechny příkazy potřebné ke spuštění služby. Je doporučeno použít funkce ebegin a eend, aby uživatel viděl, co se děje:

start() {
  ebegin "Starting my_service"
  start-stop-daemon --start --quiet --exec /path/to/my_service
  eend $?
}

Potřebujete-li více příkladů funkce start(), přečtěte si, prosím, zdrojové kódy dostupných init skriptů v adresáři /etc/init.d. Příkaz start-stop-daemon má výbornou manuálovou stránku, potřebujete-li další informace:

# man start-stop-daemon

Další funkce, které můžete definovat, jsou stop a restart, není to však povinné! Náš init systém je natolik inteligentní, že pokud používáte start-stop-daemon, doplní si tyto funkce sám.

Syntax init skriptů používaných v Gentoo je kompatibilní s Bourne Again Shellem (bash), čili v nich můžete používat rozšíření bashe.

Přidání vlastních možností

Chcete-li, aby Vaše init skripty podporovaly více voleb než ty, na které jsme zatím narazili, měli byste je přidat do proměnné opts a definovat funkci se jménem shodným, jako má daná možnost. Například pro volbu restartdelay:

opts="${opts} restartdelay"

restartdelay() {
  stop()
  sleep 3    # Před novým spuštěním počkej 3 sekundy
  start()
}
Proměnné pro konfiguraci služeb

Abyste mohli využívat konfiguraci v /etc/conf.d, nemusíte dělat vůbec nic - když je váš skript spuštěn, provede se "source" všech těchto souborů (tj. proměnné z nich budou k dispozici):

  • /etc/conf.d/<Váš init skript>
  • /etc/conf.d/basic
  • /etc/rc.conf

Zároveň pokud Váš init skript poskytuje virtuální závislost (například net), bude soubor s ní asociovaný rovněž zpracován (například /etc/conf.d/net).

Změna výchozího chování Kdo by to mohl použít?

Mnoho uživatelů notebooků tuto situaci zná - doma chcete spouštět net.eth0, ale na cestách ne, protože během nich síť k dispozici nemáte. S Gentoo můžete změnit chování runlevelů k obrazu svému.

Můžete si například přidat druhý "výchozí" runlevel, do kterého mlžete nabootovat, s přiřazenými patřičnými skripty. Při spuštění počítače si budete moci vybrat, který runlevel se má zavést.

Použití SOFTLEVEL

Nejprve vytvořte adresář pro svůj "druhý" výchozí runlevel. Jako příklad vytvoříme runlevel offline:

# mkdir /etc/runlevels/offline

Přidejte nezbytné init skripty do nově vytvořeného adresáře. Například pokud chcete mít přesnou kopii současného runlevelu default, avšak bez net.eth0:

# ls /etc/runlevels/default
acpid  domainname  local  net.eth0  netmount  postfix  syslog-ng  vixie-cron
# rc-update add acpid offline
# rc-update add domainname offline
# rc-update add local offline
# rc-update add syslog-ng offline
# rc-update add vixie-cron offline

Nyní změňte konfiguraci svého bootloaderu a přidejte novou položku pro runlevel default. Například pro /boot/grub/grub.conf:

title Gentoo Linux Offline Usage
  root (hd0,0)
  kernel (hd0,0)/kernel-2.4.25 root=/dev/hda3 softlevel=offline

Voila, to je všechno. Když nyní při bootování Vašeho systému vyberete nově přidanou položku, runlevel offline bude použit místo výchozího default.

Použití BOOTLEVEL

Použití bootlevelu je úplně stejné jako softlevel, jediný rozdíl je, že místo druhého runlevelu "default" definujete druhý runlevel "boot".