Init Scripts
Het boot proces
Na het basic boot proces, welke in handen is van BIOS en Linux kernel, wordt het overgebleven werk overgelaten aan het programma init. Dit programma is verantwoordelijk voor het starten van processen, daemons, scripts en ten slotte de tty console (en deels de X server) om de login van de gebruiker voor te bereiden.
De configuratie van init is vrij simpel, maar doordat veel distributies verschillende concepten hebben gebruikt, is het erg verwarrend geworden.
De verschillen tussen de distributies zijn groter dan alleen andere namen voor bestanden en directories en liggen vooral in verschillende ideeën over het realiseren van het boot proces. Later meer over dit onderwerp.
Basis structuur van SysV
Linux kent verschillende (zogenoemde) runlevels. Met moderne distributies komt de Linux gebruiker indirect met zijn naam in contact.
Meestal wordt tijdens de installatie van het systeem de gebruiker gevraagd of hij wil inloggen op een console of gelijk met X (met behulp van xdm, gdm of kdm). In de nieuwere releases is deze vraag verdwenen en wordt de X-server automatisch gestart.
Intern gezien horen beide varianten bij verschillende runlevels. Een login met console of X is gelijk aan de runlevels 2 (Multi-User met netwerk) en runlevel 3 (Multi-User met netwerk en grafische login) respectievelijk.
Over deze twee punten zijn bijna alle distributies het eens.
Je bent echter niet beperkt tot deze runlevels. Je kunt ongelimiteerd runlevels op je systeem aanmaken en gebruiken. Standaard bestaan er bij de meeste distributies 6 runlevels, al kunnen er een paar leeg zijn.
Een gedetailleerdere beschrijving die overeenkomt met de runlevels, kan gevonden worden in /etc/inittab.
Hieronder is een stukje van de inittab van een SuSE distributie opgenomen:
| /etc/inittab (SuSE) |
# runlevel 0 is halt # runlevel S is single-user # runlevel 1 is multi-user without network # runlevel 2 is multi-user with network # runlevel 3 is multi-user with network and xdm # runlevel 6 is reboot |
Het is mogelijk om op een draaiend systeem te veranderen van runlevel. Daarvoor bestaat het commando
>> init X, waarbij X staat voor het gewenste runlevel. Op deze manier herstart je alle daemons zonder te rebooten of kun je de veranderingen aan configuratie X testen (eerst ga je naar single user mode met init S gevolgd door bijv. init 3).
Ook kan het behulpzaam zijn als je een Linux PC van het netwerk wilt halen (je had bijvoorbeeld het vermoeden dat er niet-geauthoriseerde toegang plaatsvond via het netwerk) zonder de netwerkkabel te verwijderen. Een eenvoudige
>> init Ssluit alle netwerkverbindingen en vervolgens kan de superuser zoeken naar Trojan horses.
Ook kun je zien dat een reboot of halt van het systeem, niets anders is dan overschakelen naar runlevel 6 of respectievelijk, 0. De commmando's reboot -n en halt doen hetzelfde als init 6 en init 0 respectievelijk.
Ook het default runlevel, welke wordt gebruikt tijdens het booten, is opgegeven in /etc/inittab. De entry
id:3:initdefault:definieert deze. Als je onder SuSE met Yast aangeeft dat je wilt veranderen van de grafische login naar de console login, wordt op deze regel de 3 vervangen door een 2. Dat is alles!
Configuratie
Linux zou geen Linux/Unix zijn als je niet tot het oneindige kon configureren.
Het kan erg belangrijk zijn welke hardware wordt geïnitialiseerd in welk runlevel.
Voor een laptop die mobiel gebruikt wordt in een (of meer) bedrijf(en) is ondersteuning voor de PCMCIA netwerk kaart alleen nodig als hij zich in een bedrijf bevindt. Tijdens mobiel gebruik zijn de printer drivers en alle netwerk software (drivers, apache, NFS, NIS ...) niet nodig en kunnen de bronnen worden bespaard. Dit kan erg eenvoudig worden gerealiseerd met verschillende runlevels.
Een runlevel voor stand-alone werking, een andere met een netwerk configuratie.
Het is zelfs mogelijk om verschillende runlevels voor verschillende netwerk te configureren. Als je van het ene netwerk naar het andere gaat met een draaiend systeem, hoef je niet te rebooten. Simpelweg het juiste runlevel starten en de netwerk configuratie sluit aan bij het netwerk.
Dit is echter slechts een van de vele manieren om runlevels te gebruiken.
De configuratie van runlevels is afhankelijk van de gebruikte distributie. Onder SuSE zijn de configuratie bestanden/scripts te vinden in /sbin/init.d, terwijl RedHat gebaseerde installaties ze plaatsen onder /etc/rc.d/.
Vaak bestaat er een symbolische link (verwijzing) van de ene directory naar de andere, om zo enige compatibiliteit tussen de distributies te houden (niet meer dan armzalige poging).
Helaas is consensus ver te zoeken en iedere distributeur wijst op de voordelen van zijn concept.
In de bijbehorende subdirectory vind je alle scripts voor het starten van de verschillende taken, daemons, enzovoort, die nodig zijn tijdens het starten en stoppen:
| ls /sbin/init.d/ (SuSE) |
i4l network random single alsasound i4l_hardware nfs reboot skeleton apache cron idedma nfsserver route smbfs apmd dhclient inetd scd routed sshd at dummy init.d pcmcia rstatd syslog autofs firewall irda pcnfsd rusersd usb boot gpm kbd portmap rwhod wvdial.dod halt kerneld powerfail sendmail xdm lpd pppoed serial ypclient |
Deze scripts zijn voor bijvoorbeeld het starten van de cron-daemon (cron) welke zorgt voor commando's die regelmatig worden uitgevoerd, het starten van de webserver (apache), tot de initialisatie van de USB hardware (usb).
De meeste scripts hebben een algemene structuur:
| Structuur van een Init-script |
#! /bin/sh
case "$1" in
start)
echo -n "Start service XYZ"
/path/to/XYZ
;;
stop)
echo -n "Stop service XYZ"
killall XYZ
# or /path/to/XYZ -quit if supported by the program
;;
restart)
$0 stop && $0 start
;;
status)
echo -n "Status printout of the process:"
# A command which prints out information of the running program.
;;
*)
echo "Usage: $0 {start|stop|status|restart}"
exit 1
;;
esac
|
Om aan te geven in welk runlevel een script start, plaats je een symbolische link naar het script in de subdirectory rcX.d (waarbij X staat voor het runlevel). Maar een paar details moeten genoemd worden:
De symbolische link dient een gedefinieerde naam structuur te volgen. Als het script uitgevoerd moet worden tijdens het booten, dient de naam van de link te starten met een hoofdletter "S", gevolgd door een twee-cijferig nummer dat de volgorde aangeeft waarin de scripts worden uitgevoerd en daarna de naam van het script. De scripts worden gestart vanaf S01xxxx tot S99xxxx. De parameter "start" wordt automatisch aan het script meegegeven.
De vaste volgorde in het uitvoeren van de scripts is nodig omdat veel programma's andere programma's nodig hebben voordat ze kunnen worden geïnitialiseerd. Zo kan bijvoorbeeld het netwerk pas worden gestart als de PCMCIA netwerkkaart werd geïnitialiseerd.
De processen worden op een vergelijkbare manier gestopt bij het verlaten van een runlevel. De overeenkomende scripts zijn gelinkt met het patroon K01xxxxx to K99xxxxx.
De directory /sbin/init.d/rc2.d/ van runlevel 2 zou er zo uit kunnen zien:
| ls /sbin/init.d/rc2.d/ (SuSE) |
K19cron K24ypclient S03pcmcia S19idedma K19nscd K30idedma S04dummy S20apache K19smbfs K30random S04firewall_init S20apmd K20apache K35routed S04irda S20at K20apmd K35syslog S05dhclient S20gpm K20at K36nfs S05i4l S20inetd K20gpm K37portmap S05network S20lpd K20inetd K38route S07firewall_setup S20rstatd K20lpd K40dhclient S07route S20rusersd K20rstatd K40i4l S08portmap S20rwhod K20rusersd K40network S09nfs S20sendmail K20rwhod K42pcmcia S09syslog S20sshd K20sendmail K44i4l_hardware S10kbd S21alsasound K20sshd K45dummy S10routed S21cron K21alsasound K45irda S13random S21nscd K22wvdial.dod K51firewall S16ypclient S21smbfs K23nfsserver K99kerneld S17autofs S22wvdial.dod K23pcnfsd S01kerneld S17nfsserver S99firewall_final K24autofs S03i4l_hardware S17pcnfsd |
Hier is al een verschil te zien tussen SuSE distributies en het gepresenteerde schema: Je kunt meer links in de subdirectories vinden dan je meestal zult willen starten.
Wat er overblijft ...
Zoals eerder genoemd, heeft iedere distributie zo zijn eigen idee hoe een "goed boot proces" er uit ziet.
Op het moment, terwijl er zich steeds meer op de desktop markt richten, is er een "noodzaak" om alle complexiteit van het systeem voor de gebruikers te verbergen. Deze stap omvat veel problemen omdat de gebruiker die zijn systeem niet kent, problemen niet kan repareren als die zich voordoen of het systeem naar zijn wensen inrichten.
Deze "gebruikersvriendelijke" start-up is zover doorgevoerd dat alle berichten van programma's worden onderdrukt en alleen een done of een error wordt gerapporteerd als de taak al dan niet met succes werd uitgevoerd.
Als de start faalde, krijgt de gebruiker geen aanvullende hulp en heeft het probleem om te vinden waar en hoe de fout moet worden opgelost.
Programma's die zijn geoptimaliseerd om te verbergen zijn bijvoorbeeld LPP (Homepage: http://lpp.freelords.org/) welke het boot proces compleet verbergt met kleurige boot logo's en status rapporten. Het zal slechts een kwestie van tijd zijn voor de destop-georiënteerde distributies ons zullen verrassen met deze wreedheden.
Onder SuSE ziet het Init concept er als volgt uit:
Alle geïnstalleerde en belangrijke systeemtools worden automatisch in de overeenkomende rcX.d subdirectories geplaatst. Het bestaan van init betekend niet dat het automatisch gestart wordt, maar het script bevat alleen een test van het globale configuratie bestand /etc/rc.config. In dit bestand moet de bijbehorende variabele START_XXX (bijvoorbeeld START_HTTPD voor de apache web-server) op yes worden gezet, voordat het script wordt uitgevoerd.
Het enige wat je wint is het transport van alle processen die gestart moeten worden tijdens het booten naar Yast. Voor een beginner lijkt dit eenvoudiger dan het maken van links in de /sbin/init.d subdirectories. In plaats van de controle in een ander bestand te plaatsen, zou Yast ook de symbolische links kunnen maken of verwijderen. Het resultaat zou hetzelfde zijn en meer standaard ook.
Aan de andere kant heeft YAST een zwakheid die je niet moet onderschatten. De variabelen START_XXX zijn niet langer afhankelijk van de runlevels maar beïnvloeden alle runlevels.
De enige manier om dit te omzeilen is om de links alleen in de runlevels aan te leggen waar die nodig zijn (de link naar xdm is bijvoorbeeld alleen in runlevel 3).
Als je je eigen runlevel wil maken of processen starten die door YAST alleen in geselecteerde runlevels worden beheerd, zou je het zelf moeten doen. Dit betekend dat je een link moet verwijderen of maken, eventueel dat je bestaande scripts moet vervangen door je eigen scripts.
boot.local
Als dit alles te moeilijk voor je was, zou de scripts kunnen vermijden en in plaats daarvan het bestand boot.local kunnen gebruiken. Dit is een eenvoudig script, die je kunt vinden in de /sbin/init.d directory, waarin eenvoudige commando's door de systeembeheerder kunnen worden geplaatst, om te worden gestart tijdens het booten van de PC.
Dit bestand biedt een plaats voor processen die onafhankelijk van het runlevel gestart moeten worden.
Een kort entry van het benodigde commando scheelt vaak het bouwen van een volledig init script met alle opties (start, stop, status...).
Helaas bestaan er verschillende manieren om dit te realiseren. De SuSE distributie tot versie 6.x voerde het script boot.local aan het eind uit, na het beëindigen van alle init-scripts.
Vanaf versie 7.0 wordt het boot.local aan het begin aangeroepen, voor alle init-scripts.
Dit kan belangrijk zijn omdat je meestal het boot.local bestand gebruikt voor kleine tools en programma's, waar een compleet init script teveel van het goede zou zijn.
Als de uitvoering van boot.local aan het begin is geplaatst, zullen veel programma's niet werken omdat de nodige hardware (bijvoorbeeld de netwerkkaart) mogelijk nog niet geïnitialiseerd is.
Een oplossing zou kunnen zijn om je eigen batch-bestand te maken, waarin je alle korte commando's opneemt en die je linkt vanaf alle runlevels met een link genaamd S99xxxx.
De verschillende distributies
- SuSE:
De processen die worden gestart in de init scripts worden beheerd door de programma's startproc en killproc. startproc creëert voor ieder proces dat het start een bestand met de naam proces+suffix".pid", waarin het proces ID (PID) wordt opgeslagen. Dit bestand wordt in /var/run geplaatst. Het programma killproc kan alle processen stoppen door een kill signaal te sturen naar het opgeslagen proces-ID. Tevens verwijderd killproc de bijbehorende PID bestanden.Als het starten van een proces met succes verliep, stuurt het script een $rc_done naar init, welke het succes meldt.
Als er een fout optrad, wordt er een $rc_failed vestuurd.
De tekst in $rc_done en $rc_failed kan ingesteld worden met YAST (of in /etc/rc.config).Een typisch init script (voor versie 7.0) heeft de volgende structuur:
Init-Script #! /bin/sh # . /etc/rc.status . /etc/rc.config base=${0##*/} link=${base#*[SK][0-9][0-9]} rc_reset case "$1" in start) echo -n "Starting XYZ daemon" startproc /usr/sbin/XYZ rc_status -v ;; stop) echo -n "Shutting down XYZ daemon" killproc -TERM /usr/sbin/XYZ rc_status -v ;; restart) $0 stop && $0 start rc_status ;; reload) # Commando om het configuratie bestand opnieuw te lezen ;; status) echo -n "Checking for XYZ daemon" checkproc /usr/sbin/XYZ && echo "XYZ is up" || echo "No XYZ daemon" ;; probe) # Commando om XYZ te testen ;; *) echo "Usage: $0 {start|stop|status|restart|reload|probe}" exit 1 esac rc_exitEen specialiteit van SuSE 7.0 die al genoemd is, is het starten van het script boot.local. In 7.0 is dit aan het begin geplaatst, voordat alle overige init scripts worden gestart, terwijl oudere distributies dit na alle andere init-bestanden doen.
This Dit kan tot hardware-gerelateerde problemen leiden als de hardware niet eerst was geïnitialiseerd.
Een oplossing zou kunnen zijn om je script, bijvoorbeeld /sbin/init.d/boot.last, te laten starten nadat alle scripts zijn gestart (symbolische link S99zzzboot.last -> .../boot.last. - RedHat:
Of de structuur van de scripts van RedHat het overzicht vergroten, moet je zelf uitmaken. De verschillende calls (start, stop ...) in afzonderlijke functies plaatsen, verbeterd de dingen niet echt.
Tevens wordt er een lock-bestand in de directory /var/lock/subsys/ geplaatst.Init script #! /bin/sh # # skeletond Start/Stop the skeleton daemon. # # chkconfig: 2345 90 60 # # processname: skeleton # config: /etc/skeleton # pidfile: /var/run/skeleton.pid # Source function library. . /etc/init.d/functions RETVAL=0 # See how we were called. start() { echo -n "Starting skeleton daemon: " daemon skeleton RETVAL=$? echo [ $RETVAL -eq 0 ] && touch /var/lock/subsys/skeleton return $RETVAL } stop() { echo -n "Stopping skeleton daemon: " killproc skeleton RETVAL=$? echo [ $RETVAL -eq 0 ] && rm -f /var/lock/subsys/skeleton return $RETVAL } rhstatus() { status skeleton } restart() { stop start } reload() { echo -n "Reloading skeleton daemon configuration: " killproc skeleton -HUP retval=$? echo return $RETVAL } case "$1" in start) start ;; stop) stop ;; restart) restart ;; reload) reload ;; status) rhstatus ;; condrestart) [ -f /var/lock/subsys/skeleton ] && restart || : ;; *) echo "Usage: crond {start|stop|status|restart|condrestart}" exit 1 esac exit $? - Mandrake:
Een ander skeleton als voorbeeld (de distributie zelf levert geen skeleton bestand. Voor het volgende bestand is het start script van de cron daemon als voorbeeld gebruikt.)Het init script van de Mandrake distributie heeft de eenvoudigste structuur van de drie gepresenteerde scripts en heeft bijna geen eigenschappen die afhankelijk zijn van de distributie.
Init-Script #! /bin/sh # # skeleton Start/Stop a daemon. # # chkconfig: 2345 40 60 # # processname: skeleton # config: /etc/skeleton # pidfile: /var/run/skeleton.pid # Source function library. . /etc/rc.d/init.d/functions # See how we were called. case "$1" in start) echo -n "Starting daemon skeleton: " daemon skeletond echo touch /var/lock/subsys/skeletond ;; stop) echo -n "Stopping skeleton daemon: " killproc skeletond echo rm -f /var/lock/subsys/skeletond ;; status) status skeletond ;; restart) killall -HUP skeletond ;; *) echo "Usage: skeleton {start|stop|status|restart}" exit 1 esac exit 0 - Overzicht:
Een korte lijst van skeleton bestanden voor verschillende distributies:
Hint: Speciaal geval: laptops
Het gebruik van runlevels kan een erg handige tool zij, vooral voor laptops die in verschillende netwerken worden gebruikt. Denk bijvoorbeeld aan een laptop die op het werk wordt gebruikt maar ook op je locale LAN thuis.
Gewoonlijk zul je je netwerkkaart moeten herconfigureren, de gateway en de DNS server als je van netwerk veranderde. Ook zullen er services zijn die op het werk nodig zijn, maar thuis niet (ldp, NIS, NFS ...).
Als je twee runlevels creëerde, een voor ieder netwerk, kan de juiste configuratie worden gekozen en gestart. Daarvoor kopieer een bestaand runlevel naar bijvoorbeeld rc7.d en pas je deze naar wens aan voor het bijbehorende netwerk.
Je moet niet vergeten om dit nieuwe runlevel op te geven in het bestand /etc/inittab, met name de regel
7:123:respawn:/sbin/mingetty tty7moet worden toegevoegd, omdat er anders geen console, waar je op kunt inloggen, wordt gestart.
Ook zou het configuratie bestand door een speciaal script kunnen worden vervangen, welke de bestaande netwerk configuratie kopieerd naar een backup directory en alle bestanden van de configuratie vervangt door diegene voor het huidige netwerk. Als de aanpassingen omvangrijk zijn, zou je eventueel de volledige /etc-directory kunnen vervangen. Let in ieder geval wel op dat de computer niet wordt afgesloten zonder /etc-directory, want anders kun je de volgende keer niet opstarten.
Ten slotte is er nog een entry in de LILO configuratie bestanden nodig, om het systeem tijdens het booten te vertellen welke configuratie gestart moet worden. Daarvoor kun je de distributie-entry die je tot nog toe gebruikte kopiëren en uitbreiden met een append entry:
| /etc/lilo.conf |
[...]
# entry die tot nog toe werd gebruikt
image = /boot/kernel_redhat7_z
root = /dev/hda2
label = redhat
#--nieuwe entry
image = /boot/kernel_redhat7_z
root = /dev/hda2
append = "init=/sbin/init 7"
label = firma
|
Na het commando lilo, kun je bij het volgende boot proces de optie "office" kiezen. LILO geeft de regel die je hebt opgegeven achter append aan de kernel mee en zal runlevel 7 worden gebruikt.
Dit script creëert de /etc-directory die nodig is op je kantoor en wordt het systeem aansluitende opgezet.
Zoals je kunt zien, start het systeem met verschillende configuraties, zonder een afzonderdelijke partitie te creëren.
Conclusies
Het boot proces toont duidelijk de verschillen tussen de distributies. Iedere "grote" distributie heeft zijn eigen idee hoe de runlevels worden gestructureerd en georganizeerd.
Het nadeel is duidelijk voor de gebruikers, die, zoals gebruikelijk, het overzicht verliezen als ze veranderen van distributie.
Een eenvoudige en doordachte structuur werd overhoop gegooid. Gedeeltelijk zijn de runlevel directories gevuld met een enorm aantal links die uiteindelijk niet gestart worden.
We kunnen alleen hopen dat, met komende open standaarden, we overeen kunnen komen hoe de structuur van het boot proces er uit hoort te zien.
Ik dank sh0 en zyz voor de ondersteuning met de skeleton bestanden.
Homepage: www.libertynet.de