Google Chrome 136 byl prohlášen za stabilní. Nejnovější stabilní verze 136.0.7103.59 přináší řadu novinek z hlediska uživatelů i vývojářů. Podrobný přehled v poznámkách k vydání. Opraveno bylo 8 bezpečnostních chyb. Vylepšeny byly také nástroje pro vývojáře.
Homebrew (Wikipedie), správce balíčků pro macOS a od verze 2.0.0 také pro Linux, byl vydán ve verzi 4.5.0. Na stránce Homebrew Formulae lze procházet seznamem balíčků. K dispozici jsou také různé statistiky.
Byl vydán Mozilla Firefox 138.0. Přehled novinek v poznámkách k vydání a poznámkách k vydání pro vývojáře. Řešeny jsou rovněž bezpečnostní chyby. Nový Firefox 138 je již k dispozici také na Flathubu a Snapcraftu.
Šestnáctý ročník ne-konference jOpenSpace se koná 3. – 5. října 2025 v Hotelu Antoň v Telči. Pro účast je potřeba vyplnit registrační formulář. Ne-konference neznamená, že se organizátorům nechce připravovat program, ale naopak dává prostor všem pozvaným, aby si program sami složili z toho nejzajímavějšího, čím se v poslední době zabývají nebo co je oslovilo. Obsah, který vytvářejí všichni účastníci, se skládá z desetiminutových
… více »Richard Stallman přednáší ve středu 7. května od 16:30 na Technické univerzitě v Liberci o vlivu technologií na svobodu. Přednáška je určená jak odborné tak laické veřejnosti.
Jean-Baptiste Mardelle se v příspěvku na blogu rozepsal o novinkám v nejnovější verzi 25.04.0 editoru videa Kdenlive (Wikipedie). Ke stažení také na Flathubu.
TmuxAI (GitHub) je AI asistent pro práci v terminálu. Vyžaduje účet na OpenRouter.
Byla vydána nová verze R14.1.4 desktopového prostředí Trinity Desktop Environment (TDE, fork KDE 3.5, Wikipedie). Přehled novinek i s náhledy v poznámkách k vydání. Podrobný přehled v Changelogu.
Bylo vydáno OpenBSD 7.7. Opět bez písničky.
V tradiční unixové terminologii se objevuje slovo démon (respektive daemon, ale to je v češtině zlá, nepěkná věc). Démoni mají zvláštní postavení. Chovají se jinak než ostatní aplikace a ve většině případů jsou tím, co spouští příslušný init skript. V Unixu je každý program připojen k (pseudo)terminálu, pomocí něhož komunikuje s okolím. Na terminál se zapisuje, přijímají se z něj data a po jeho uzavření je daný program ukončen. Znamená to tedy, že spouštět klasické programy init skriptem není možné, protože ten pouze vydá povel ke spuštění a potom se ukončí, kdežto démon pokračuje na pozadí.
Existuje sice možnost spustit program s nohup
a na pozadí, takže nedojde k jeho
ukončení, ale jak uvidíme dále, není to úplně korektní postup. Přesto se v praxi
vyskytuje. Například pro servery napsané v Javě je to jediná rozumná možnost.
Slovo démon je neodbytně spjato s magií a unixoví démoni musí ve skutečnosti udělat řadu v pravdě „magických“ kroků k tomu, aby se z běžného programu mohl stát démon.
getrlimit(RLIMIT_NOFILE)
a volat
close(2)
na každý z nich a na konci vynulovat errno
, protože chyba zavírání
neexistujícího popisovače nás nezajímá. V Linuxu můžeme vzít v potaz
/proc/self/fd
a zavírat pouze ty skutečně otevřené.SIGKILL
a SIGSTOP
na SIG_DFL
.
Opět můžeme iterovat přes všechny signály až po NSIG
(nebo _NSIG
, pokud
hodláme na glibc pracovat i real-time signály – v tom případě musíme ignorovat
první dva rt signály).sigprocmask
, aby nás v
démonizaci nerušily zbloudilé signály.fork(2)
pro vytvoření procesu na pozadí.setsid()
.fork(2)
a ukončit prvního potomka. Ukončením zajistíme,
že rodičem bude PID 1.umask(2)
na 0./
, aby démon nebránil případnému odpojení
oddílů./dev/null
, protože démoni
komunikují přes sockety a informace zapisují přes syslog. Tímto se vyhneme
selháním v operacích printf
, které nikdo obvykle nečeká./var/run/démon.pid
. Tato
operace obvykle zahrnuje ještě zjištění, zda už náhodou neběží další instance,
takže to celé musí probíhat atomicky. exit()
– ten musí přijít až v okamžiku, kdy se
ukončí inicializace původního procesu a měl by návratovým kódem naznačit,
kterak skončil démonizovaný proces.A to je, mimo „drobností“ jako odmaskovat signály, nastavit reakce na HUP, otevření socketu, načtení konfigurace a podobných záležitostí, vše.
A jelikož je ladění takovýchto démonů z příkazové řádky dosti nepohodlné, obvyklým postupem je mít možnost přepínat se mezi režimem démona a klasickým programem běžícím na popředí, který se od terminálu neodpojuje.
Tento postup není ve skutečnosti nijak magický. V zásadě jde o směs funkčních a
bezpečnostních opatření. Kostrou démona je posloupnost fork(2)
, setsid()2
a
fork(2)
. Což je kód sloužící k tomu, aby se program vyvázal z případné uživatelské
relace (session
), pokud je v ní spuštěn a aby neměl přiřazeny žádné prostředky,
které by potom nebylo možné uvolnit. Případně aby jejich uvolnění nemělo vliv na
náš kód.
Důvodem existence fork-setsid-fork
je způsob organizace procesů v unixovém shellu.
Každý trochu pokročilejší uživatel ví o PID – unikátním identifikátoru procesu. Ti
ještě pokročilejší vědí, že unixové procesy mohou patřit do skupin procesů
(process groups
), které mají svoje číslo PGID
a rovněž do relací – sessions
-
které mají opět své identifikační číslo a navíc kontrolní terminál.
Že tomu tak skutečně je, se můžeme snadno přesvědčit příkazem ps
ps -eo pid,ppid,pgid,sess,comm,tty
Po jeho spuštění se objeví hromada čísel následovaná názvem spustitelného
procesu. A taky vidíme, že spousta procesů má stejné čísla skupin procesů nebo
relací. Tento způsob organizace vznikl a je používán především v interaktivním
shellu. Omezme výpis pouze na aktuální relaci (vynecháním argumentu -e
).
$ ps -o pid,ppid,pgid,sess,tty,comm --sort pid PID PPID PGID SESS TT COMMAND 12375 12368 12375 12375 pts/0 bash 12510 12375 12510 12375 pts/0 ps
Spustíme pár příkazů
$ sleep 200 & [1] 12549 $ sleep 200 & [2] 12571 $ bash $ ps -o pid,ppid,pgid,sess,tty,comm --sort pid | cat PID PPID PGID SESS TT COMMAND 12375 12368 12375 12375 pts/0 bash 12549 12375 12549 12375 pts/0 sleep 12571 12375 12571 12375 pts/0 sleep 12664 12375 12664 12375 pts/0 bash 12693 12664 12693 12375 pts/0 ps 12694 12664 12693 12375 pts/0 cat
Jak vidíme, tak všechny spuštěné programy mají stejné číslo uživatelské relace
(což je logické, protože to právě vynechání argumentu -e
dělá). Číslo skupiny
procesů je u všech stejné, s výjimkou posledních ps
a cat
. A rodičovské
čísla ukazují, kdo spustil co – příkaz pstree
je používá pro kreslení grafu
procesů.
Spusťme teď váš oblíbený emulátor terminálu a v něm znovu ps
$ ps -o pid,ppid,pgid,sess,tty,comm --sort pid | cat PID PPID PGID SESS TT COMMAND 13808 13807 13808 13808 pts/3 bash 13860 13808 13860 13808 pts/3 ps 13861 13808 13860 13808 pts/3 cat
Vidíte, že příkaz vypisuje nejen jiné číslo relace, ale i odlišný terminál.
Z výše uvedených příkazů lze odvodit následující pravidla:
Začněme druhým odstavcem. Unixový shell používá skupiny procesů pro práci s
úlohami, které spouští. Každý spuštěný příkaz vytvoří novou skupinu procesů,
pokud je spuštěn pouze jeden, pak je hodnota PPID
rovna hodnotě PID
.
Pouze jedna skupina procesů může běžet v popředí, zbytek musí běžet na pozadí. A
nakonec to hlavní – existuje systémové volání – zašli signál všem procesům z
dané skupiny. Takže, pokud napíšeme kill %2
, shell to převede na volání
killpg(SIGTERM,skupina-odpovídající-%2)
.
Existují systémová volání setpgid(2)
a setssid(2)
, kterými proces může změnit
svoji skupinu a relaci. Pro démonizaci nás zajímá to druhé – setsid(2)
, které
vytvoří novou relaci pro proces, který ji zavolá. Tato funkce má jedno zásadní
omezení, nesmí být zavolána z takzvaného process group leader – čili hlavního
procesu skupiny. Je tomu tak proto, že nelze určit, který ze zbývajících procesů má
být ve skupině novým hlavním procesem.
A převod všech procesů skupiny pod novou relaci není možný, protože jak čísla skupin, tak čísla relací musí být unikátní a odvozují se od PID příslušného vůdcovského procesu.
Řešením je tak první fork(2)
, kdy s určitostí víme, že náš potomek není hlavním
procesem skupiny, tudíž může bezpečně zavolat setsid(2)
. Navíc, ukončením
původního procesu si uvolníme prompt shellu.
Otázkou je, proč potřebujeme volat ještě druhý fork(2)
? Tím se dostáváme k
relacím. Co nebylo přímo uvedeno, i když je to vidět z výpisů příkazu ps
je
to, že procesy jedné relace sdílejí stejný terminál (v našem případě
pseudoterminál). Ten se nazývá kontrolní terminál a je základním komunikačním
prostředkem mezi uživatelem a procesy. Voláním setsid(2)
se vyvážeme z
aktuálního terminálu. Ovšem stejně jako existuje process group leader, tak
existuje i session leader. Ten má obvykle připojený terminál, ale v
případě fork-setsid
proces žádný terminál nemá, ale jako vůdce může
otevřít nový.
Otázkou tedy je, jak zajistit, aby náš proces nemohl dostat nový terminál?
O_NOCTTY
– nepraktické už kvůli knihovnámioctl()
fork()
, kde je jasné, že potomek není session
leader a tudíž už nemůže v žádném případě získat kontrolní terminálPrávě forkovací magie dělá problémy nejen autorům těchto démonů, tak i z mnoha důvodů autorům (dobrých ™) init systémů. Jak Lennart ve svém původním článku napsal, důležitou částí takového init systému je i sledování stavu spuštěných procesů, což není u tradičního démona spuštěného init skriptem nijak přímočaré a spolehlivé.
Tak třeba klasický démon provede několik forků, takže je bez PID souboru prakticky nemožné rozumně zjistit číslo hlavního procesu. A to potřebujeme pro komunikaci s démonem.
Ale double fork způsobuje z hlediska sledování i jiné problémy. Klasicky,
pokud totiž rodič zavolá fork()
, dostane SIGCHLD
v případě, že běh potomka
skončil. Tímto způsobem může jednoduše reagovat na neočekávané ukončení
potomků. Ovšem pokud takto spouštíme démona, tak SIGCHLD
nic o ukončení
hlavního procesu nevypovídá – ten důležitý proces běží s jinou identitou a jiným
rodičem dále.
Vyvázáním se z konzole ztrácí proces místo, kam může posílat zprávy o svém
stavu. Naivním řešením je, aby si každý proces otevřel logovací soubor a
ten spravoval. Z mnoha důvodů to není nejlepší řešení, takže většina slušných
démonů zapisuje do systémového logu reprezentovaného /dev/log
a démonem
syslog
. Ten obvykle zapisuje všechny zprávy předané voláním syslog(2)
do /var/log/messages
, ale některé z implementací démona syslog podporují
nejrůznější nastavení, typu zprávy tohoto démona zapisuj sem, tento typ zpráv
sem a zbytek posílej po síti do vzdáleného logu a podobně.
Lennart, mimochodem autor multiplatformní knihovny libdaemon
usnadňující
psaní démonů, vydal vlastní sadu doporučení, jak psát démony v novém stylu.
SIGTERM
, démon se čistě a bezpečně ukončí.SIGHUP
, démon znovu načte svoji konfiguraci, pokud to
dává smysl, jinak tento signál ignoruje..service
, .socket
, nebo .path
jednotku..socket
jednotku pro start na požádání.sd_notify
, nebo podobného volání.syslog()
, které zprávy posílá logovacímu démonu,
nový typ může jednoduše zapisovat zprávy do stderr
a nechat init systém je
forwardovat do systémového logu. Priority jsou kódovány na začátku řetězcem
„<číslo>“
, kde číslo odpovídá prioritám použitým v démonu syslog. Tato
technika umožní systemd přesměrovat celý systémový log do kmsg
, což může být
výhodné pro embeded systémy.Tyto požadavky, až na první dva týkající se reakce na signály, se od tradičního doporučení liší a nový typ démona se nijak neliší od standardního programu. Základním rozdílem je totiž skutečnost, že systemd (to jest proces s PID 1) spouští procesy přímo, tudíž ty mají správného rodiče, nepotřebují se vyvazovat ze skupin a podobně.
A jelikož systemd umí přesměrovat standardní výstup do systémového logu, mohou
být všechny zprávy logovány právě na standardní výstup, takže odpadá nutnost
používat speciální příkaz pro psaní zpráv. Na všechny ostatní kroky, které
démoni mohou implementovat, jako omezení práv, nastavení limitů a podobně je
rovněž možné a vhodné se spolehnout na systemd a jeho funkci exec_spawn
.
Dnešní díl se zabýval obecnou problematikou démonů. Ukázal kroky nutné k tomu,
aby se z klasického procesu stal démon běžící na pozadí a také ukázal, jak
systemd mění náhled na démony, které jsou v jeho podání podobné běžným
programům. Mimochodem podobné požadavky vydal Apple ve spojitosti s launchd
.
V příštím díle se podíváme na zoubek .service
jednotkám, což je přímá náhrada za
init skripty a ukážeme si, jak triviální je se systemd napsat démona v shellu.
Nástroje: Tisk bez diskuse
Tiskni
Sdílej:
Takže, pokud napíšeme kill %2, shell to převede na volání killpg(SIGKILL,skupina-odpovídající-%2).nebude to SIGTERM?
SIGTERM
, nechápu, jak jsem to mohl tolikrát přehlédnout.
fork()
je zajímavý, něco takového jsem sice už viděl, ale nikdy v běžných démonech (tj. v takových, kteří nespouštějí žádné externí programy, které by mohly způsobit uzmutí nového terminálu). Osobně jsem pár démonů napsal a žádný nedělá dvojtý fork()
, dokonce ani v běžných návodech na unixové démony se tato operace nevyskytuje (viz. např. Unix Daemon Server Programming) a ani v démonech, které jsem si kdysi prohlížel jako vzory.
Jediné místo, kdy jsem na to narazil před tím, bylo v UNIX Programming FAQ, v části 1.7 How do I get my program to act like a daemon?, ale tam se vyskytují i speciality jako doporučení nepoužít po prvním fork()
u volání exit()
, ale _exit()
(při kterém se nespouští registrované uživatelské "úklidové" rutiny), nebo rozdíly mezi fork()
a vfork()
(v Linuxu je to putna). A ano, démoní jsou klasická unixová magie