Eilen tunneli toimi, ja tänä aamuna unit on kuollut, journalissa on Failed at step EXEC spawning /usr/local/bin/vpnclient. Tunnistetiedot, reitit ja tili eivät koskaan esiinny tuossa lauseessa. systemd ratkaisi ExecStartin poluksi, pyysi ydintä suorittamaan sen, ja ydin kieltäytyi, useimmiten siksi, ettei polulla ole mitään tai tiedosto ei ole suoritettava. Käsittele vikaa tiedosto- ja argv-ongelmana, kunnes jäsennetty komento todistaa muuta.

Miksi EXEC epäonnistuu ennen todennuksen alkua

systemd ei suorita ExecStartia kuoren kautta. Se haarautuu, rakentaa rivistä argumenttivektorin ja kutsuu execveä ensimmäiselle elementille. Jos se kutsu epäonnistuu, palvelu ei koskaan saavuta VPN-asiakkaan omaa koodia, joten profiilin muokkaus tai tunnistetietojen tarkistus ei auta.

Tilakoodi erottaa tämän perheen tavallisista kaatumisista. Unit, joka poistuu tilalla status=203/EXEC, ei koskaan käynnistänyt prosessia; unit, joka käynnistyy ja poistuu sitten tilalla status=1 on ehkä epäonnistunut todennuksessa, DNS:ssä tai reitityksessä. Lue koodi ennen asiakkaan lokia, sillä ensimmäisessä tapauksessa asiakkaan loki on tyhjä.

Journalin polku on se, jota systemd käytti, ei välttämättä se, jota muokkasit. Drop-in-tiedostot ja generaattorin tuloste voivat ohittaa toimittajan tiedoston, ja vanhentunut daemon-reload jättää vanhan rivin muistiin. Siksi ensimmäinen diagnoosi on kysyä systemdiltä, mitä se pitää komentona, sen sijaan että avaisit tiedoston, jonka muistat muuttaneesi.

Kolme paikkaa, joihin binaarin polku on kirjattu

Jakelupaketista, toimittajan skriptistä ja julkaisun tarballista asennettu VPN-asiakas voi päätyä kolmeen eri etuliitteeseen. Unit, oikeussääntö ja asentaja kirjasivat kukin yhden näistä etuliitteistä, ja vika näkyy, kun kaksi kolmesta ei täsmää.

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/

Konkreettinen ristiriita näyttää tältä: toimittajan skripti asentaa hakemistoon /usr/local/bin, tarball purettiin /opt alle ja unit mainitsee yhä vanhan /usr/bin-polun aiemmasta paketista. Vain yksi näistä tiedostoista on olemassa, ja harvoin se on ExecStartissa oleva.

Päätä, mikä polku on kanoninen, ennen kuin muutat kumpaakaan tiedostoa. Jos jakelupaketti omistaa binaarin, paketin polku on kanoninen ja unitin on seurattava sitä. Jos toimittajan skripti omistaa sen, sama sääntö koskee toimittajan etuliitettä. Binaarin kopioiminen etuliitteiden välillä luo kaksi kopiota, jotka erkanevat seuraavassa päivityksessä.

Kun lainausmerkeissä oleva komento muuttuu tiedostonimeksi

Toinen vikatila piiloutuu saman journal-rivin taakse. Joku kirjoittaa tämän unittiin ja odottaa asiakkaan yhdistävän käynnistyksen aikana:

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

systemd jakaa arvon sanoihin, joten ensimmäisestä sanasta tulee /usr/bin/vpnclient connect office, kun lainausmerkit poistetaan ryhmittelysyntaksina. Sitten ydin etsii tiedostoa, jonka nimessä on välilyöntejä, eikä sellaista ole. Virhe on sama kuin puuttuvassa binaarissa, vaikka binaari on asennettu.

Tuettu muoto on todellinen suoritettava tiedosto, jota seuraavat erilliset argumentit, esimerkiksi ExecStart=/usr/bin/vpnclient connect office. Jos työnkulku todella tarvitsee putken tai ketjun, laita se skriptiin ja kutsu skriptiä, koska ExecStartissa ei ole &&, ei putkia eikä glob-laajennusta.

Korjaa unit, älä tiedostojärjestelmää

Houkkueleva korjaus on symbolinen linkki odotetusta polusta todelliseen binaariin. Se toimii, kunnes paketti päivittyy ja linkki osoittaa poistettuun tiedostoon, tai kunnes SELinux-leima ei enää vastaa kohdetta. Muokkaa unitia mieluummin drop-inin kautta, jotta toimittajan tiedosto pysyy koskemattomana ja päivitykset pysyvät ennustettavina.

Oikeussäännön on vastattava samaa polkua ja samoja alikomentoja. Sudoers-merkintä polulle /usr/local/bin/vpnclient ei valtuuta polkua /usr/bin/vpnclient, ja merkintä, joka sallii minkä tahansa argumentin, antaa minkä tahansa paikallisen prosessin määrittää tunnelin uudelleen tai pysäyttää sen. Anna ne kaksi verbiä, jotka unit tarvitsee, ja pidä purkaminen sen ulkopuolella, jos palvelun pysäyttäminen sulkee rajapinnan jo valmiiksi.

Tässä vertailu kannattaa: unitin, pakettitietokannan ja sudoersin pitäisi kaikkien nimetä yksi polku. Kun ne tekevät niin, EXEC-virhe katoaa ilman uudelleenkäynnistystä ja ilman binaarin kopiota kolmanteen paikkaan.

Todista jäsennetty komento ennen uudelleenkäynnistystä

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 on ratkaiseva tuloste, koska se tulostaa sen argvin, jonka systemd todella jäsensi, mukaan lukien mahdollinen drop-in. systemd-analyze verify nappaa puuttuvan tai ei-suoritettavan polun ennen uudelleenkäynnistystä, ja uudelleenkäynnistyksen jälkeinen tilakomento kertoo, onko prosessi nyt olemassa.

Jos unit käynnistyy ja epäonnistuu sitten, olet poistunut EXEC-perheestä ja siirtynyt asiakkaan omaan virheenkäsittelyyn. Etsi journalista asiakkaan viesti, älä uutta execve-epäonnistumista. Pidä unitin diff ja sudoersin diff yhdessä muutosmerkinnässä, jottei seuraava päivitys hiljaa palauta jaettua polkua.

Aiheeseen liittyvät artikkelit