Včera tunel fungoval a dnes ráno je unit mŕtvy s Failed at step EXEC spawning /usr/local/bin/vpnclient v journal. Prihlasovacie údaje, trasy ani účet sa v tej vete nikdy neobjavia. systemd preložil ExecStart na cestu, požiadal jadro o jej spustenie a jadro odmietlo — najčastejšie preto, že na tej ceste nič nie je alebo súbor nie je spustiteľný. Berte závadu ako problém súboru a argv, kým analyzovaný príkaz nepreukáže opak.

Prečo EXEC zlyhá skôr, než sa začne autentizácia

systemd nespúšťa ExecStart cez shell. Vytvorí fork, z riadku zostaví vektor argumentov a zavolá execve na prvý prvok. Ak toto volanie zlyhá, služba sa nikdy nedostane k vlastnému kódu klienta VPN, takže žiadne úpravy profilu ani kontrola prihlasovacích údajov nepomôžu.

Stavový kód oddeľuje túto rodinu od bežných pádov. Unit, ktorý skončí so status=203/EXEC, nikdy nespustil proces; unit, ktorý sa spustí a potom skončí so status=1 mohol zlyhať pri autentizácii, DNS alebo smerovaní. Prečítajte kód skôr než log klienta, pretože v prvom prípade bude log klienta prázdny.

Cesta v journal je tá, ktorú použil systemd, nie nutne tá, ktorú ste upravili. Súbory drop-in a výstup generátora môžu prepísať súbor dodávateľa a zastaraný daemon-reload necháva starý riadok v pamäti. Preto je prvou diagnostikou opýtať sa systemd, čo považuje za príkaz, namiesto otvárania súboru, o ktorom si pamätáte, že ste ho menili.

Tri miesta, kde je zapísaná cesta k binárke

Klient VPN nainštalovaný z distribučného balíčka, skriptu dodávateľa a tarballu vydania môže skončiť v troch rôznych prefixoch. Unit, pravidlo oprávnení a inštalátor každý zaznamenal jeden z týchto prefixov a závada sa objaví, keď sa dva z troch nezhodujú.

RecordCommon valueHow to read it
Unit or drop-in/usr/local/bin/vpnclientsystemctl cat vpnclient.service
Installed binary/usr/bin/vpnclientcommand -v vpnclient, then ls -l the result
Sudoers grant/opt/vpnclient/bin/vpnclientsudo grep -r vpnclient /etc/sudoers.d/

Konkrétna nezhoda vyzerá takto: skript dodávateľa inštaluje do /usr/local/bin, tarball bol rozbalený pod /opt a unit stále uvádza starú cestu /usr/bin z predchádzajúceho balíčka. Existuje len jeden z týchto súborov a málokedy je to ten v ExecStart.

Pred zmenou ktoréhokoľvek súboru rozhodnite, ktorá cesta je kanonická. Ak binárku vlastní distribučný balíček, kanonická je cesta balíčka a unit ju má nasledovať. Ak ju vlastní skript dodávateľa, platí to isté pravidlo pre prefix dodávateľa. Kopírovanie binárky medzi prefixmi vytvára dve kópie, ktoré sa pri ďalšej aktualizácii rozídu.

Keď sa z citovaného príkazu stane názov súboru

Druhý režim zlyhania sa skrýva za tým istým riadkom v journal. Niekto zapíše do unitu toto a očakáva, že sa klient pri štarte pripojí:

ExecStart=/usr/bin/"vpnclient connect office"

systemd rozdelí hodnotu na slová, takže prvé slovo sa stane /usr/bin/vpnclient connect office a úvodzovky sa odstránia ako syntax zoskupenia. Jadro potom hľadá súbor, ktorého názov obsahuje medzery, a taký neexistuje. Chyba je rovnaká ako pri chýbajúcej binárke, hoci binárka je nainštalovaná.

Podporovanou formou je skutočný spustiteľný súbor nasledovaný samostatnými argumentmi, napríklad ExecStart=/usr/bin/vpnclient connect office. Ak pracovný postup naozaj potrebuje rúru alebo reťaz, dajte ho do skriptu a zavolajte skript, pretože ExecStart nemá &&, nemá rúry ani glob expanziu.

Opravte unit, nie súborový systém

Lákavá oprava je symbolický odkaz z očakávanej cesty na skutočnú binárku. Funguje, kým sa balíček neaktualizuje a odkaz nezačne ukazovať na odstránený súbor, alebo kým sa štítok SELinux prestane zhodovať s cieľom. Radšej upravte unit pomocou drop-in, aby súbor dodávateľa zostal nedotknutý a aktualizácie zostali predvídateľné.

Pravidlo oprávnení musí zodpovedať tej istej ceste a tým istým podpríkazom. Záznam v sudoers pre /usr/local/bin/vpnclient neoprávňuje /usr/bin/vpnclient a záznam, ktorý povoľuje akýkoľvek argument, umožní ľubovoľnému lokálnemu procesu prekonfigurovať alebo zastaviť tunel. Dajte unitu obe potrebné slovesá a ponechajte demontáž mimo neho, ak zastavenie služby už zatvára rozhranie.

Tu sa porovnanie vyplatí: unit, databáza balíčkov aj sudoers by mali uviesť jednu cestu. Keď sa tak stane, chyba EXEC zmizne bez reštartu a bez kópie binárky na treťom mieste.

Dokážte analyzovaný príkaz pred reštartom

sudo systemctl daemon-reload
sudo systemctl cat vpnclient.service
systemctl show -p ExecStart vpnclient.service
systemd-analyze verify /etc/systemd/system/vpnclient.service
sudo systemctl restart vpnclient.service
systemctl status vpnclient.service --no-pager

systemctl show je rozhodujúci výstup, pretože vypisuje argv, ktoré systemd skutočne analyzoval, vrátane každého drop-in. systemd-analyze verify zachytí chýbajúcu alebo nespustiteľnú cestu ešte pred reštartom a stavový príkaz po reštarte povie, či proces teraz existuje.

Ak sa unit spustí a potom zlyhá, opustili ste rodinu EXEC a vstúpili do vlastného spracovania chýb klienta. Hľadajte v journal správu klienta, nie ďalšie zlyhanie execve. Držte diff unitu a diff sudoers spolu v zázname zmien, aby budúca aktualizácia potichu nevrátila rozdelenú cestu.

Súvisiace články