Démoni
Démon (anglicky daemon) je program, jehož účelem je zpomalit start systému a zabírat systémové zdroje, aniž by o něm uživatel něco věděl.
Ale ne, teď vážně, démoni jsou programy, které běží ve vašem počítači na pozadí, bez přímé komunikace s uživatelem. Obvykle čekají na nějakou událost, kterou pak ošetří. Jako démon běží třeba databázový server, který čeká na požadavky databázového klienta, http server, který čeká na požadavek od http prohlížeče, tisková fronta atp.
V této kapitole vám ukáži, jak napsat démona a jak nakonfigurovat jeho automatické spouštění při startu.
Démon
Démon je program jako každý jiný. Jen musíte zajistit jeho spuštění na pozadí a to, aby se neukončil, když ukončíte svoje sezení (odhlásíte se z terminálu, kde byl program spuštěný).
Jednou z možností, jak zajistit neukončení programu při odhlášení je použití nohup. Pokud napíšete démona třeba v javě, asi vám ani nic jiného nezbyde. Já vám ale ukáži jak na to v C.
Typický postup při programování démona je:
- Odpojení od terminálu (pomocí fork())
- Nastavení umask(0)
- Otevření souborů (logů atp.)
- Vytvoření nového session ID (pomocí setsid())
- Změna aktuálního adresáře (pomocí chdir())
- Zavření standardních IO
- Zachytávání signálů
- Spuštění práce démona
Krom toho je ještě dobré uložit do nějakého souboru PID démona, aby mohl uživatel snadno zjistit, zda démon běží.
Odpojení od terminálu
Když spustíte program v terminálu, terminál čeká na jeho dokončení a vy, jako uživatelé, komunikujete se spuštěným programem. Terminál sleduje spuštěný proces.
Pokud spustíte nový proces pomocí fork() a ten původní ukončíte, vrátíte se do terminálu a nový proces poběží na pozadí.
Nastavení umask
Nastavení umask na 0 se doporučuje proto, aby démon nebyl ovlivněn nastavením prostředí a pracoval tak vždycky a všude stejně.
Nastavení na 0 znamená, že se nebudou odebírat žádná práva.
#include <sys/stat.h>
mode_t umask(mode_t mask);
Otevření souborů
Předtím, než uzavřete standardní IO (vstup a výstup) je dobré otevřít všechny prostředky, které bude démon potřebovat (obvykle soubory).
Dokud nezavřete stderr, můžete ještě pořád vypsat chybové hlášení v případě, že se něco nepovede.
Soubor s PID démona
Démon by měl uložit do nějakého souboru svůj PID. Použití tohoto souboru uvidíte v části popisující automatické spuštění démona.
Vytvoření nového session ID
Už víte, že každý proces v Linuxu má své ID a také rodičovské ID. Nový proces vytvořený forkem má jako rodiče původní proces. Když rodiče zabijete, bude mít jako rodiče proces s id 1 (init).
Kromě těchto ID má ale každý proces také session ID
. Když se třeba odhlašujete
od terminálu, jádro potřebuje zabít všechny procesy, které jste v tomto terminálu spustili. K zjednodušení
tohoto úkolu združuje kernel všechny procesy pod jedno session ID.
Každý proces dědí session ID od svého rodiče. Pomocí funkce setsid()
můžete vytvořit nové session ID, které bude stejné jako ID procesu, a tím se z původního
session vyloučit. Díky tomu nebude démon zabit, když se odhlásíte.
Proces se zároveň stane tzv. session lídrem. Všechny procesy které spustí (např. pomocí
execl()
), získají stejné session ID.
Změna aktuálního adresáře
Nikdy nevíte, odkud bude démon spuštěn, takže je dobré mu napevno nastavit aktuální adresář pro případ, že byste někdy používali relativní cesty.
Nejlepší je nastavit aktuální adresář na /
. Nebude tak docházet
k žádným problémům při připojování a odpojování disků. (Disk, jehož složku má
nějaký program jako aktuální adresář, obvykle nejde jednoduše odpojit. A pokud
se násilně odpojí, obvykle to znamená pro takový program katastrofu).
Zavření standardních IO
Démon běží na pozadí, takže stdin, stdout ani stderr nepotřebuje, proto je dobré je uzavřít.
Může se ale stát, že démon spustí nějakou funkci nebo program, který očekává, že je
některý z těcho standardních IO otevřen. Proto je dobré znovu otevřít souborové
proudy s čísli deskriptorů standardních IO. Obvykle stačí otevřít /dev/null.
Když se z něho někdo pokusí číst, dostane ihned „konec souboru“. Při
zápisu do /dev/null se zase všechno potichu a bez řečí zapíše a zmizí.
Můžete samozřejmě stdout
a stderr
přesměrovat do nějakého logovacího souboru …
Zachytávání signálů
Démon může komunikovat s okolím pomocí jakékoliv IPC technologie. Určitě by měl ale zachytávat minimálně tyto dva signály:
SIGHUP se obvykle používá pro znovunačtení konfigurace / restart démona.
SIGTERM se používá pro ukončení démona. Démon by tento signál měl zachytit a nějak mírumilovně a rychle se ukončit (uvolnit získanou paměť, uzavřít komunikaci atp.).
Spuštění práce démona
Když už je vše připraveno, může začít démon čekat na událost, kterou obsouží. Může poslouchat na nějaké pipe nebo socketu, používat semafory, či co vás napadne. Já v příkladě spustím nekonečný cyklus, který se vždy na 5 sekund zastaví a pak zapíše větu do logu.
Příklad
V tomto příkladu ukáži všechny výše zmíněné kroky.
Jako první se podívejte na funkce, které bude používat démon pro zápis do logu. Démon do něj bude zapisovat každých 5 vteřin "Pracuji.", pak taky informaci o požadavku na znovunačtení konfigurace (HUP signál) a nakonec informaci o svém ukončení (při ukončení signálem TERM).
Navíc zapíše na začátku nepovinný argument, který budu používat pro odlišení spuštěných instancí démona.
Hlavičkový soubor je jednoduchý:
- /*------------------------------------------------*/
- /* 25daemon/log.h */
- #ifndef _LOG_H
- #define _LOG_H
- /**
- * Otevře soubor
- * @return 0 - soubor se podarilo otevrit
- * 2 - chyba
- */
- #endif
- /*------------------------------------------------*/
Definice funkcí taky nejsou nijak těžké. Všiměte si,
že proměnná logfile je označená jako static,
což znamená, že je viditelná jen v rámci souboru log.c
.
To je dobrý způsob, jak si nezaneřádit zdrojové kódy globálními
proměnnými.
Jméno logovacího souboru bude demon.PID.log, kde PID je PID démona.
- /*------------------------------------------------*/
- /* 25daemon/log.c */
- #include <stdio.h>
- #include <time.h>
- #include <stdarg.h>
- #include <sys/types.h>
- #include <unistd.h>
- #include "log.h"
- {
- }
- }
- {
- time_t sec;
- va_list ap;
- vsnprintf(text, 512, format, ap);
- }
- {
- }
- /*------------------------------------------------*/
Funkce writeLog()
zapisuje s logovacím textem i PID a čas logování.
Využívá k tomu funkce, které už znáte: strftime()
a vsnprintf()
.
Po každém zapsaném řádku také zavolám fflush()
, aby se vyprázdnila vyrovnávací paměť.
Kdyby náhodou démon neočekávaně skončil (byl zabit), tak abych nepřišel o žádné informace.
K zapsání PID do souboru používám funkce z pidfile.h
. Těla funkcí popíšu později,
teď se podívejte jen na hlavičkový soubor.
- /*------------------------------------------------*/
- /* 25daemon/pidfile.h */
- #ifndef _PIDFILE_H
- #define _PIDFILE_H
- #include <stdio.h>
- /**
- * Otevře a zablokuje soubor
- * @return 0 - soubor se podarilo otevrit
- * 1 - bezi uz jiny demon
- * 2 - chyba
- */
- /**
- * Zapíše PID aktuálního procesu a uzavře soubor
- */
- /**
- * Smaže soubor
- */
- #endif
- /*------------------------------------------------*/
Funkci removePidFile()
zavolám ve chvíli, kdy se démon bude ukončovat.
Funkce pro zachytávání signálů jsem vyčlenil do signal.c
.
Hlavičkový soubor k nim vypadá takto:
Funkce zachytávající singál nedělají nic jiného, než že nastaví hodnoty running a sighup. Jak na tuto změnu zareagovat, to už je problém démona. Jak by měl reagovat je asi jasné. Pokud se nastaví running na 0, měl by se ukončit a pokud se nastaví sighup na 1, měl by znovu načíst konfiguraci (zrestartovat se).
A teď přichází na řadu ta nejdůležitější část - démon.
- /*------------------------------------------------*/
- /* 25daemon/demon.c */
- #include <stdlib.h>
- #include <unistd.h>
- #include <fcntl.h>
- #include <sys/stat.h>
- #include "pidfile.h"
- #include "log.h"
- #include "signals.h"
- {
- }
- {
- getpid(), getsid(0), getppid());
- }
- {
- close(STDIN_FILENO);
- close(STDOUT_FILENO);
- close(STDERR_FILENO);
- }
- }
- }
- }
Na začátku si definuji pomocné funkce. Program demon
bude zpracovávat 2 argumenty.
První je název souboru, do kterého se bude ukládat PID. Druhý argument se zapíše do logu.
To můžete použít při automatickém spuštění démona, abyste si označili, odkud byl démon spuštěn.
Ve funkci closeStandardDescriptors()
nejdříve zavírám standardní IO. Pak otvírám /dev/null.
Protože funkce open()
vždy pro deskriptor souboru používá nejnižší dostupné číslo,
bude první otevření mít číslo 1, tedy stejné, jako má stdin, druhé 2, jako má stdout a třetí 3, jako
má stderr. Všiměte si, že u stderr
se očekává otevření pro čtení i zápis.
Ve funkci main()
se pak provádí postupně všechny výše popsané kroky.
- {
- pid_t pid, sid;
- int ret;
- usage();
- }
- pidfile = argv[1];
- ret = openPidFile(pidfile);
- }
- printPidInfo();
- /* Forking and killing father */
- pid = fork();
- }
- }
- printPidInfo();
- umask(0);
- openLog();
- writeLog("%s", argv[2]);
- }
- /* vytvoreni noveho session ID */
- sid = setsid();
- }
- printPidInfo();
- /* zmena pracovniho adresare */
- }
- setSignalHandlers(&running, &sighup);
- closeStandardDescriptors();
- closePidFile();
- /* Demon zacina svou praci */
- sighup = 0;
- writeLog("Načítám znovu konfiguraci.");
- }
- writeLog("Pracuji.");
- ret = sleep(5);
- writeLog("Sleep byl přerušen o %i sec dříve.", ret);
- }
- }
- removePidFile(pidfile);
- writeLog("%s", "Končím v míru.");
- closeLog();
- return EXIT_SUCCESS;
- }
- /*------------------------------------------------*/
Funkce main()
vrací 0 v případě úspěšného spuštění démona,
2 v případě chyby a 1 v případě, že už démon běží (viz návratová
hodnota funkce openPidFile()
). Rozlišení těchto návratových hodnot
se mi bude hodit při automatickém spouštění, viz dále.
Nastasvené obsluhy signálů jenom nastavují
running a sighup. Zatímco signál SIGTERM stačí odchytit
jednou, signál SIGHUP budud chtít zachytávat opakovaně, proto k jeho
zachytávání používám funkci sigaction()
.
- /*------------------------------------------------*/
- /* 25daemon/signals.c */
- #include <stdio.h>
- #include <signal.h>
- #include "signals.h"
- {
- *r = 0;
- }
- {
- *s = 1;
- }
- {
- struct sigaction sa;
- sigset_t set;
- r = running;
- s = sighup;
- signal(SIGTERM, sigterm_handler);
- sigemptyset(&set);
- sa.sa_handler = sighup_handler;
- sa.sa_mask = set;
- sa.sa_flags = SA_RESTART;
- sa.sa_restorer = NULL;
- sigaction(SIGHUP, &sa, NULL);
- }
- /*------------------------------------------------*/
Poslední kus kódu se stará o zápis PID. Všiměte si, že k souboru přistupuju s exclusivním zámkem. To proto, aby se dva současně sputění démoni nepodívali do souboru, že je prázdný, nezapsali své ID (druhý by přepsal ID toho prvního) a nespustili se.
PID zapisuji až v closePidFile()
. Tuto funkci volám, až když jsou nastavené
hanldery na mírumilovné ukončení démona, při kterém soubor s PID zase smažu.
- /*------------------------------------------------*/
- /* 25daemon/pidfile.c */
- #include <errno.h>
- #include <sys/file.h>
- #include <unistd.h>
- #include "pidfile.h"
- {
- pid_t oldpid = 0;
- int ret;
- }
- ret = flock(fileno(pidfile), LOCK_EX);
- }
- }
- }
- }
- {
- }
- {
- }
- /*------------------------------------------------*/
Spuštění programu může vypadat takto:
process id = 7093, session id = 2132, parent id = 2132
process id = 7094, session id = 2132, parent id = 7093
process id = 7094, session id = 7094, parent id = 1
$ kill -HUP 7094
$ kill -TERM 7094
$ cat /tmp/demon.7094.log
[ 7094, 2014-09-15 17:41:36] test
[ 7094, 2014-09-15 17:41:36] Pracuji.
[ 7094, 2014-09-15 17:41:41] Pracuji.
[ 7094, 2014-09-15 17:41:45] Sleep byl přerušen o 1 sec dříve.
[ 7094, 2014-09-15 17:41:45] Načítám znovu konfiguraci.
[ 7094, 2014-09-15 17:41:45] Pracuji.
[ 7094, 2014-09-15 17:41:50] Pracuji.
[ 7094, 2014-09-15 17:41:51] Sleep byl přerušen o 4 sec dříve.
[ 7094, 2014-09-15 17:41:51] Končím v míru.
Všiměte si, že funkce sleep()
je přerušena, pokud program dostane nějaký signál.
Takže nemusíte čekat (až) 5 sekund na to, než se démon ukončí.
Automatické spuštění po startu OS
První proces, který se spustí po spuštění jádra linuxu je proces init
, který má ID 1.
Ten se pak stará o spuštění dalších procesů.
Zbývá už jen otázka, kam co zapsat, aby init spustil vašeho démona (nebo jakýkoliv program, který chcete spustit po statrtu).
Tady ale vyvstává nová otázka, co je vlastně init zač? Bohužel, bylo vytvořeno spoustu programů, které si hrají na init. Takže odpověď na první otázku není jednoduchá a na tu druhou je ještě složitější. Dá se říct, že init je různý nejen systém od systému (Linux vs BSD vs OSX atp), ale i distribuce od distribuce a dokonce verze distribuce od verze distribuce. Nejpravděpodobněji ale asi narazíte na Systemd.
Soubor rc.local
Bývalo zvykem, že jednoduché příkazy stačilo zapsat do souboru /etc/rc.local
.
Třeba v Debianu to funguje dodnes. V OpenSuSE už ne, ale místo toho máte /etc/rc.d/after.local
a /etc/rc.d/boot.local
.
Do všech těchto souborů stačí napsat něco takového, aby se program spustil při startu:
Tento příkaz spustí program /home/petr/bin/deamon
pod uživatelem petr
.
Příkaz je ukončen &, aby se mohl hned spustit další příkaz z rc.local (pokud nějaký existuje).
U démona & možná není úplně nutné, protože se sám rychle odpojí od terminálu, ale je to stále
dobrý zvyk (co kdyby se démon z nějakého důvodu zaseknul, pak by se zaseknul celý start systému …).
Pokud chcete spustit skript jako root, vynechte prostě su - petr -c
a uvozovky.
Všiměte si, že cesta k programu je absolutní. To byste měli používat i v případě programů, které jsou umístěny v systémových adresářích jako je /bin, /usr/bin atp.
Rozdíl mezi after.local a boot.local je ten, kdy se skripty spouští. boot.local se spouští jako jeden z prvních, před init skritpy (o kterých bude řeč dále) zatímco after.local až po init skriptech. Lepší je dávat příkazy do after.local, kdy jsou ostatní služby už nastartované (např. jsou přimountované disky atp). Do boot.local dávejte něco jen tehdy, když k tomu budete mít důvod.
System V init
Klasickým, oblíbeným, nejvíce rozšířeným a snadným init systémem byl System V init
.
A někde pořád ještě je. Bohužel, System V init není zrovna nejrychlejší ve spouštění programů.
Ke spuštění programu používá skritpy napsané v bashi a pouští je paralelně (jeden za druhým).
Takže se snažili vývojáři vytvořit nějakou rychlejší alternativu. Vytvořili jich bohužel hodně,
ale žádná z nich se nijak masivně neujala.
Skripty pro sysvinit se ukládají do adresáře /etc/init.d/
.
V /etc/init.d/skeleton najdete příklad toho, jak má takový skript vypadat. V OpenSuSE tento skript už nenajdete, protože OpenSuSE už System V nepoužívá.
Vytvoření skritpu pro démona vypadá zhruba takto: Zkopíruji skeleton, nastavím mu právo spuštění,
zedituju jeho obsah a pak příkazem insserv jmeno_skritpu
jej přidám mezi
skripty, které se mají spustit.
$ chmod +x /etc/init.d/demon
## ... zedituj demon ...
$ insserv -v demon
Já jsem skeleton ještě trochu osekal a udělal z něj příklad pro náš program deamon.
To, co je mezi BEGIN INIT INFO
a END INIT INFO
není jen obyčejný komentář. Program
insserv
si z toho přečte, kteří démoni mají být spuštěni před naším démonem
(v příkladu je to remote_fs a syslog), v jakých run-levelech se má démon spustit (v příkladu
jsou to 2, 3, 4 a 5) a v jakých se má démon vypnout.
Zbytek skriptu je asi srozumitelný, tedy alespoň pokud umíte trochu programovat v bashi.
### BEGIN INIT INFO
# Provides: demon
# Required-Start: $remote_fs $syslog
# Required-Stop: $remote_fs $syslog
# Default-Start: 2 3 4 5
# Default-Stop: 0 1 6
# Short-Description: Test demona demon
# Description: Libovolny popis ...
### END INIT INFO
# Author: Foo Bar <foobar@baz.org>
# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin
DESC="Ukazka demona"
NAME=demon
DAEMON=/home/petr/bin/$NAME
DAEMON_ARGS="/tmp/init.d.demon.pid /etc/init.d/demon"
PIDFILE=/var/run/$NAME.pid
SCRIPTNAME=/etc/init.d/$NAME
# Exit if the package is not installed
[ -x "$DAEMON" ] || exit 0
# Read configuration variable file if it is present
[ -r /etc/default/$NAME ] && . /etc/default/$NAME
#
# Function that starts the daemon/service
#
do_start()
{
$DAEMON $DAEMON_ARGS
}
#
# Function that stops the daemon/service
#
do_stop()
{
echo killall $NAME
killall $DAEMON
}
#
# Function that sends a SIGHUP to the daemon/service
#
do_reload() {
killall -HUP $DAEMON
}
case "$1" in
start)
do_start
;;
stop)
do_stop
;;
status)
echo "Neni implementovano ... "
;;
reload)
do_reload
;;
restart|force-reload)
do_stop
do_start
;;
*)
echo "Usage: $SCRIPTNAME {start|stop|status|restart|reload|force-reload}" >&2
exit 3
;;
esac
Init pak volá při startu /etc/init.d/deamon start
a při ukončení
zase /etc/init.d/deamon stop
.
Všiměte si, že když posílám signál pomocí killall, neposílám ho jen na demon
,
ale na /home/petr/bin/demon
. Jinak by totiž skript zabil sám sebe (taky
se jmenuje demon).
Při startu skriptu by měl skript vrátit 0 v případě úspěchu, 1 v případě, že démon už běžel a 2 v případě chyby. Víc se k tomuto dočtete ve skutečném /etc/init.d/skeleton (pokud ho tedy v systému máte).
Přidání skriptu mezi spouštěné pak může vypadat takto:
insserv: enable service ../init.d/demon -> /etc/init.d/../rc0.d/K01demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc1.d/K01demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc2.d/S18demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc3.d/S18demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc4.d/S18demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc5.d/S18demon
insserv: enable service ../init.d/demon -> /etc/init.d/../rc6.d/K01demon
insserv: creating .depend.boot
insserv: creating .depend.start
insserv: creating .depend.stop
V zásadě se jen vytvoří symbolické linky do adresářů /tec/init.d/rc*.d/.
Symbolický link začínající S
se spouští při startu, link začínající K
se spouští
při vypínání. Číslo pak určuje pořadí, v jakém se skripty spoutějí. Číslo
v adresáři rc*.d znamená, při jakém runlevelu
se skripty spustí. Z příkladu je jasné, že se bude démon spouštět při runlevelech 2 až 5, při runlevelech
0, 1 a 6 se bude vypínat.
Jenom pro úplnost, odebrání démona vypdá takto:
insserv: remove service /etc/init.d/../rc0.d/K01demon
insserv: remove service /etc/init.d/../rc1.d/K01demon
insserv: remove service /etc/init.d/../rc2.d/S18demon
insserv: remove service /etc/init.d/../rc3.d/S18demon
insserv: remove service /etc/init.d/../rc4.d/S18demon
insserv: remove service /etc/init.d/../rc5.d/S18demon
insserv: remove service /etc/init.d/../rc6.d/K01demon
insserv: creating .depend.boot
insserv: creating .depend.start
insserv: creating .depend.stop
Systemd
Jednou z úspěšných náhrad System V init se zdá být Systemd. Najdete ho třeba v mém oblíbeném OpenSuSE. Zatím se zdá, že ze všech alternativ má největší budoucnost.
Dobrá zpráva je, že Systemd je kompatibilní s System V init. Můžet tak použít
skript napsaný v minulé části a dokonce máte k dispozici i příkaz insserv
,
který se používá stejně, jen připraví skript pro prácí s Systemd.
Systemd, na rozdíl od System V init, si neklade za cíl jen služby (démony) spouštět, vypínat a restartovat. Chce i sledovat jejich stav, zda běží, neběží atp.
K tomu potřebuje znát PID aplikace. A k tomu je potřeba nainstalovat démona podle Systemd způsobu. Než s tím začnete, odinstalujte skript popsaný výše (pokud ho máte instalovaný).
Způsob instalace démona do Systemd je překvapivě jednoduchý. Vytvořte soubor deamon.service
v adresáři /usr/lib/systemd/system/
a zapište do něj následující:
Description=Priklad Demona
Wants=remote-fs.target syslog.service
[Service]
Type=forking
ExecStart=/home/petr/bin/demon /var/run/demon.pid /usr/lib/systemd/system/demon.service
PIDFile=/var/run/demon.pid
[Install]
WantedBy=multi-user.target
Alias=demon.service
Description
je libovolný popis démona (uvidíte ho při dotazech na status služeb app.).
Wants
říká, které služby by měly být spuštěny před spuštěním tohoto démona.
ExecStart
říká, jak se má démon spustit. Systemd obsluhuje různé typy služeb, jako jsou
service (což je třeba náš démon), target (což je třeba připojování disků) atd. Podrobnosti si nastudujte
kdyžtak z dokumentace.
Type=forking
říká, že se jedná o démona, který se forkuje. Přesně tak, jak jsme jej naprogramovali.
Systemd dokáže spustit na pozadí i programy, které jako démoni naprogramovaní nebyly. Vlastně má takové radči,
protože může sám zjistit jejich PID a nepotřebuje k tomu PIDFile
, jako v našem příkladě.
(Systemd může zjistit jen PID jím spuštěného procesu. Náš program po forkování tento proces hned zabije, proto
potřebuje systemd znát PIDFile
.) To je jedna z výhod Systemd, protože psaní démonů tím usnadňuje.
Mimoto Systemd spoutší programy paralelně najednou, a má i pár dalších vychytávek, proč je oblíbenější než
System V init.
WantedBy
říká, jaký runlevel jej vyžaduje. multi-user.target
odpovídá runlevelu 3,
ale vyžaduje jej i runlevel 5.
A teď si můžete hrát s systemctl
. Příkazy enable
/ disable
službu
přidávají / odebírají z automatického startu. Příkazy start
/ stop
službu
ihned zapínají / vypínají. A příkaz status
vám zobrazí status služby (jesti běží, je enabled atp.).
ln -s '/usr/lib/systemd/system/demon.service' '/etc/systemd/system/demon.service'
ln -s '/usr/lib/systemd/system/demon.service' '/etc/systemd/system/multi-user.target.wants/demon.service'
$ systemctl status demon
demon.service - Priklad Demona
Loaded: loaded (/usr/lib/systemd/system/demon.service; enabled)
Active: inactive (dead)
$ systemctl start demon
$ systemctl status demon
demon.service - Priklad Demona
Loaded: loaded (/usr/lib/systemd/system/demon.service; enabled)
Active: active (running) since Po 2014-09-15 23:11:34 CEST; 9s ago
Process: 7294 ExecStart=/home/petr/bin/demon /var/run/demon.pid /usr/lib/systemd/system/demon.service (code=exited, status=0/SUCCESS)
Main PID: 7295 (demon)
CGroup: /system.slice/demon.service
└─7295 /home/petr/bin/demon /var/run/demon.pid /usr/lib/systemd/system/demon.service
zář 15 23:11:34 linux-nrse.site demon[7294]: process id = 7294, session id = 7294, parent id = 1
zář 15 23:11:34 linux-nrse.site systemd[1]: Started Priklad Demona
$ systemctl stop demon
$ systemctl disable demon
rm '/etc/systemd/system/multi-user.target.wants/demon.service'
rm '/etc/systemd/system/demon.service'
A to je k těm malým ďálíkům vše :-). Když budete mít štěstí, bude vaše distribuce podporovat jeden ze 3 probraných způsobů automatického startu. Když ne, budete si muset nastudovat vaší init alternativu sami.