system-vEn person frågade hur man får saker att hända när systemet startar och stoppas, enkel fråga som man inte kan svara kort på så jag skriver en inlägg om hur det fungerar.

Man kan skriva mycket om hur denna process fungerar men jag tänkt beröra den ytligt på den nivå så att man förstår hur det fungerar och kan lägga till egna skript som hanterar saker när datorn startar upp eller stängs ner.

En väldigt kort historik, det system som används i debian/raspian och Ubuntu (fram till 13.10) och Centos (fram till 6) heter SysV som är en förkortning på ett gammalt operativsystem som heter System V (släppt kring 1997) många operativsystem går nu över till Systemd som är ett annat sätt att hantera detta.

Oavsett vilket system man pratar om är systemet till för att processererna i systemet ska hanteras i rätt ordning vid upp- och nedtagning av ett system. Man kan även ha ett antal nivåer (eng run levels)  som alla har olika definition av vad som ska startas. Det finns 7 definierade nivåer 0-6 som i klassiska system definieras

Nivå (Run level)Funktion
Nivå (Run level)Funktion
0stopp, samma som halt kommandot
1enavändare textgränssnitt utan nätverk, endast konsol användes vid reparationer av operativsystemet m.m
2enanvändare textgränssnitt med nätverksstöd
3fleranvändare textgränssnitt, den normala nivån för en vanlig server
4Användes inte, egendefinierad funktion
5fleranvändare grafiskt gränssnitt, det normala för t.ex arbetsstationen med grafisk miljö
6Omstart, samma som reboot kommandot

För debian/raspian har nivåerna lite annan definition

Nivå (Run level)Funktion
Nivå (Run level)Funktion
0stopp, samma som halt kommandot
1enavändare textgränssnitt, endast konsol användes vid reparationer av operativsystemet m.m
2fleranvändarsystem text/grafisk gränssnitt, normal nivå för debian
3fleranvändarsystem text/grafisk gränssnitt
4fleranvändarsystem text/grafisk gränssnitt
5fleranvändarsystem text/grafisk gränssnitt
6Omstart, samma som reboot kommandot

Som synes i tabellen har runlevels inte någon egentlig funktion för text eller grafisk miljö i debian utan man kör normalt på nivå 2. Detta kan man se med kommandot

Första visar föregående nivå och den sista nuvarande nivå, N betyder att det inte finns någon tidigare nivå. För att byta nivå finns kommando init, där man anger önska ny nivå efter kommandot.

På raspian har detta byte ingen funktion men på andra system hade man gått från enanvändare till fleranvändare, oftast innebar det att t.ex ssh demonen startades.

I /etc finns en katalog som heter init.d där man bör lägga alla skripts som som man vill att systemet ska styra, det är också i denna katalog som kommadot service letar efter motsvarande fil, följande två kommando gör samma sak egentligen

Varje skript i denna katalog förväntas hantera minst två kommandoparametrar, start och stop dvs /etc/init.d/skriptnamn start och /etc/init.d/skriptnamn stop.  Många bygger till fler funktioner t.ex restart, status, reload m.m.

Så hur får man då skriptet att köras automatiskt?

Varje nivå (run level) har ett eget bibliotek i /etc som kan ligga direkt under /etc eller i /etc/rc.d, för debian ligger de direkt under /etc som rc0.d t.o.m rc6.d motsvarande de olika nivårena. För att ett kommando ska utföras måste det ligga med i den katalog som representerar den önskade nivån, i detta fall startas systemet upp i nivå 2 som då är /etc/rc2.d/

Om du lista filerna i katalogen med -l flaggan så ser du något liknande

alla filer börjar antingen med K eller S följt av 2 siffror och är mjuklänkar till skripts som ligger i /etc/init.d (som jag pratade om tidigare) . K och S står för Kill och Start och styr om man kör kommando med Start => start eller Kill => stop som parameter. De två siffrorna efter bokstaven anger i vilken ordning som skripten ska köras, från lågt till högt, 01 körs först och 99 sist. När man startar om eller stänger ner ett system så går det antingen i run level 0 (stop) eller 6 (reboot), om vi tittar på /etc/rc6.d/ så får man något liknande

Som du ser finns bara namn som börjar på K eftersom när man startar om systemet vill man stänga ner alla aktiv processer.

Vad finns det för fler fördelar än att saker startar upp automatisk?

Eftersom det även finns en stop funktion om man bootar om (Runlevel 6) eller stänger ner (Runlevel 0) så ger man programmet chans att skriva ner saker som finns i minnet, stänga filer m.m. Det är därför det är bättre att köra

innan man rycker strömmen, då ger man de olika processerna chans att avsluta vad de höll på med. Detta är samma sak på t.ex en Windows maskin, risken när man bara rycker ut strömmen är att man får felaktigheter i systemet, t.ex fel i information på disken då den inte han uppdatera alla information t.ex. T.ex skriver processen för diskar (gäller även t.ex windows) information om att den stängt ner filsystemet korrekt och när man starta upp datorn igen så kollar samma process om den information finns på disken annars får du information om att disken inte stängdes ner korrekt och man bör köra en diskkontroll på den.

Nu ska vi göra ett eget skript som kan startas och stoppas samtidigt med systemet, vi utgår från detta enkla skript som innehåller det minimala en start och en stop funktion.

Vi kallar det test och skapa det i /etc/init.d med

klistra in skriptet och spara, därefter gör vi det exekverbart med

Som ni kanske noterat som är skalen /bin/sh i stället för det normala /bin/bash orsaken är att när systemet startas upp så tittar det inte på vilket skal man angett på första raden i filen utan köra allt i /bin/sh. Eftersom syntaxen på vissa saker skiljer sig kan man bli lite förvirrad när man testar skriptet och använder /bin/bash och det fungerar alldeles utmärkt men när man startar om datorn så blev det något fel. Säkrast är då att hålla sig till samma skal så blir det enklare att felsöka.

Sektionen mellan ### BEGIN och ### END är en standard som kallas LSB (Linux Standard Base) som beskriver ett antal parametrar för att styra när och under vilka förutsättningar som skriptet ska köra. Required start/stop anger tjänster som ska vara tillgängliga när skripet körs, $local_fs är att filsystemet är monterat och $network är att nätverket ätt tillgängligt. Default start/stop anger vilka runlevels som tjänsten ska startas respektive stoppas. Den inställning som finns i exemplet fungerar för de flesta tillämpningar.

Vi testar att det verkar fungera

Då var det dax att få systemet att köra skriptet automatiskt, det finns ett kommand för att fixa till alla mjuklänkar som heter update-rc.d, för att lägg till en tjänst kör man för kommandot test

Man kan se att den gjort precis som vi angav i skriptet starta på runlevel 2-5, stoppa på 0,1 och 6

Man tar bort den från lista av program med kommandot

Svårare än så var det inte.

Om vi återgår till frågan jag fick så var den hur man använde push notiser för att få information när systemet startade och stoppades. Om du följt instruktionerna i artikeln Skicka push notiser till telefonen från en Raspberry Pi och man har anget API nyckeln som användare pi så se det modifierade skriptet ut så här

Viktigt att komma ihåg när man gör startskript är att man är inte inloggad som någon användare och bör alltid adressera kommandon med fulla sökvägen för att vara säker. Jag fick även lägga till variabeln HOME som normalt pekar på den inloggade användarens hemmakatalog (eftersom vi som sagt inte är inloggade) så jag pekade den på pi-användarens hemmakatalog för att den skulle hämta API nyckeln i /home/pi/.push_msg

Ett bra sätt att testa är att köra med service test start kommando i stället för /etc/init.d/test start eftersom med service kommando får man inte med alla skalvariablar som man har när man är inloggad, det var så jag upptäckte att man var tvungen att sätta HOME= i skriptet