VPN-tjänsten misslyckas vid EXEC: jämför unit, binärfil och sudoers
Ett fel i steget EXEC betyder att systemd inte kunde starta binärfilen. Jämför unitens sökväg, den installerade sökvägen och sudoers-tillståndet innan du ändrar något.
Igår fungerade tunneln, och i morse är uniten död med Failed at step EXEC spawning /usr/local/bin/vpnclient i journalen. Inloggningsuppgifter, rutter och kontot förekommer aldrig i den meningen. systemd löste upp ExecStart till en sökväg, bad kärnan köra den, och kärnan vägrade, oftast för att det inte finns något på den sökvägen eller för att filen inte är körbar. Behandla felet som ett fil- och argv-problem tills det parsade kommandot bevisar motsatsen.
Varför EXEC misslyckas innan autentiseringen börjar
systemd kör inte ExecStart genom ett skal. Det gör en fork, bygger en argumentvektor från raden och anropar execve på det första elementet. Om det anropet misslyckas når tjänsten aldrig VPN-klientens egen kod, så varken profilredigering eller kontroll av inloggningsuppgifter kan hjälpa.
Statuskoden skiljer den här familjen från vanliga krascher. En unit som avslutas med status=203/EXEC har aldrig startat en process; en unit som startar och sedan avslutas med status=1 kan ha misslyckats med autentisering, DNS eller routing. Läs koden före klientloggen, för i det första fallet blir klientloggen tom.
Sökvägen i journalen är den som systemd använde, inte nödvändigtvis den du redigerade. Drop-ins och generatorutdata kan åsidosätta leverantörens fil, och en inaktuell daemon-reload lämnar den gamla raden i minnet. Därför är den första diagnosen att fråga systemd vad den anser vara kommandot, i stället för att öppna filen du minns att du ändrade.
Tre ställen där binärfilens sökväg står skriven
En VPN-klient som installerats från ett distributionspaket, ett leverantörsskript och en tarball från en utgåva kan hamna i tre olika prefix. Uniten, privilegieregeln och installationsprogrammet registrerade var sitt av dessa prefix, och felet uppträder när två av tre inte stämmer.
| Record | Common value | How to read it |
|---|---|---|
| Unit or drop-in | /usr/local/bin/vpnclient | systemctl cat vpnclient.service |
| Installed binary | /usr/bin/vpnclient | command -v vpnclient, then ls -l the result |
| Sudoers grant | /opt/vpnclient/bin/vpnclient | sudo grep -r vpnclient /etc/sudoers.d/ |
En konkret avvikelse ser ut så här: leverantörsskriptet installerar till /usr/local/bin, tarballen packades upp under /opt, och uniten nämner fortfarande den gamla sökvägen /usr/bin från ett tidigare paket. Bara en av dessa filer finns, och det är sällan den i ExecStart.
Avgör vilken sökväg som är kanonisk innan du ändrar någon av filerna. Om distributionspaketet äger binärfilen är paketets sökväg kanonisk och uniten ska följa den. Om leverantörsskriptet äger den gäller samma regel för leverantörens prefix. Att kopiera en binärfil mellan prefix skapar två kopior som glider isär vid nästa uppgradering.
När ett kommando inom citattecken blir ett filnamn
Ett andra felläge gömmer sig bakom samma journallinje. Någon skriver detta i uniten och förväntar sig att klienten ansluter under uppstarten:
ExecStart=/usr/bin/"vpnclient connect office"systemd delar upp värdet i ord, så det första ordet blir /usr/bin/vpnclient connect office, samtidigt som citattecknen tas bort som grupperingssyntax. Sedan letar kärnan efter en fil vars namn innehåller mellanslag, och det finns ingen. Felet är identiskt med en saknad binärfil, trots att binärfilen är installerad.
Den form som stöds är en riktig körbar fil följd av separata argument, till exempel ExecStart=/usr/bin/vpnclient connect office. Om arbetsflödet verkligen behöver en pipeline eller en kedja, lägg den i ett skript och anropa skriptet, eftersom ExecStart inte har &&, inga rör och ingen glob-expansion.
Reparera uniten, inte filsystemet
Den frestande reparationen är en symbolisk länk från den förväntade sökvägen till den riktiga binärfilen. Den fungerar tills paketet uppdateras och länken pekar på en borttagen fil, eller tills en SELinux-etikett inte längre matchar målet. Föredra att redigera uniten via en drop-in, så att leverantörens fil förblir orörd och uppgraderingar förblir förutsägbara.
Privilegieregeln måste matcha samma sökväg och samma underkommandon. En sudoers-post för /usr/local/bin/vpnclient ger inte tillstånd till /usr/bin/vpnclient, och en post som tillåter alla argument låter vilken lokal process som helst konfigurera om eller stoppa tunneln. Ge de två verb som uniten behöver och håll nedmonteringen utanför om stopp av tjänsten redan stänger gränssnittet.
Det är här jämförelsen lönar sig: uniten, paketdatabasen och sudoers bör alla ange en sökväg. När de gör det försvinner EXEC-felet utan omstart och utan en kopia av binärfilen på en tredje plats.
Bevisa det parsade kommandot före omstart
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-pagersystemctl show är det avgörande utdatat eftersom det skriver ut den argv som systemd faktiskt parsade, inklusive eventuell drop-in. systemd-analyze verify fångar en saknad eller icke-körbar sökväg innan du startar om, och statuskommandot efter omstarten säger om processen nu finns.
Om uniten startar och sedan misslyckas har du lämnat EXEC-familjen och gått in i klientens egen felhantering. Leta i journalen efter klientens meddelande, inte efter ännu ett execve-fel. Håll unit-diffen och sudoers-diffen tillsammans i ändringsloggen, så att nästa uppgradering inte tyst återinför den delade sökvägen.