El servei de VPN falla a EXEC: compara la unit, el binari i sudoers
Fallar al pas EXEC vol dir que systemd no ha pogut iniciar el binari. Compara la ruta de la unit, la ruta instal·lada i el permís de sudoers abans de modificar res.
Ahir el túnel funcionava, i aquest matí la unit és morta amb Failed at step EXEC spawning /usr/local/bin/vpnclient al journal. Les credencials, les rutes i el compte no entren mai en aquesta frase. systemd va resoldre ExecStart a una ruta, va demanar al nucli que l’executés, i el nucli s’hi va negar, sovint perquè no hi ha res en aquesta ruta o perquè el fitxer no és executable. Tracta la fallada com un problema de fitxer i argv fins que l’ordre analitzada demostri el contrari.
Per què EXEC falla abans que comenci l’autenticació
systemd no executa ExecStart a través d’un shell. Fa un fork, construeix un vector d’arguments a partir de la línia i crida execve sobre el primer element. Si aquesta crida falla, el servei no arriba mai al codi propi del client de VPN, així que cap edició de perfil ni cap comprovació de credencials no hi pot ajudar.
El codi d’estat separa aquesta família de les caigudes ordinàries. Una unit que surt amb status=203/EXEC no ha iniciat mai cap procés; una unit que s’inicia i després surt amb status=1 pot haver fallat a l’autenticació, al DNS o a l’encaminament. Llegeix el codi abans del registre del client, perquè en el primer cas el registre del client estarà buit.
La ruta del journal és la que va fer servir systemd, no necessàriament la que has editat. Els fitxers drop-in i la sortida del generador poden substituir el fitxer del proveïdor, i un daemon-reload obsolet deixa la línia antiga a la memòria. Per això el primer diagnòstic és preguntar a systemd quina ordre creu que és, en lloc d’obrir el fitxer que recordes haver canviat.
Tres llocs on s’escriu la ruta del binari
Un client de VPN instal·lat des d’un paquet de distribució, un script del proveïdor i un tarball d’alliberament poden acabar en tres prefixos diferents. La unit, la regla de privilegis i l’instal·lador van registrar cadascun un d’aquests prefixos, i la fallada apareix quan dos dels tres no coincideixen.
| 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/ |
Una discrepància concreta es veu així: el script del proveïdor instal·la a /usr/local/bin, el tarball es va descomprimir sota /opt, i la unit encara anomena l’antiga ruta /usr/bin d’un paquet anterior. Només existeix un d’aquests fitxers, i poques vegades és el que hi ha a ExecStart.
Decideix quina ruta és canònica abans de canviar cap dels fitxers. Si el paquet de distribució és el propietari del binari, la ruta del paquet és la canònica i la unit l’ha de seguir. Si el propietari és el script del proveïdor, la mateixa regla s’aplica al prefix del proveïdor. Copiar un binari entre prefixos crea dues còpies que divergeixen en la propera actualització.
Quan una ordre entre cometes es converteix en un nom de fitxer
Un segon mode de fallada s’amaga darrere la mateixa línia del journal. Algú escriu això a la unit i espera que el client es connecti durant l’arrencada:
ExecStart=/usr/bin/"vpnclient connect office"systemd divideix el valor en paraules, així que la primera paraula es converteix en /usr/bin/vpnclient connect office amb les cometes eliminades com a sintaxi d’agrupació. Després el nucli busca un fitxer el nom del qual contingui espais, i no n’existeix cap. L’error és idèntic al d’un binari absent, tot i que el binari estigui instal·lat.
La forma admesa és un executable real seguit d’arguments separats, per exemple ExecStart=/usr/bin/vpnclient connect office. Si el flux de treball necessita de debò una canonada o una cadena, posa’l en un script i crida el script, perquè ExecStart no té &&, ni canonades, ni expansió de glob.
Arregla la unit, no el sistema de fitxers
La reparació temptadora és un enllaç simbòlic des de la ruta esperada fins al binari real. Funciona fins que el paquet s’actualitza i l’enllaç apunta a un fitxer eliminat, o fins que una etiqueta d’SELinux deixa de coincidir amb l’objectiu. És preferible editar la unit mitjançant un drop-in, perquè el fitxer del proveïdor quedi intacte i les actualitzacions segueixin sent previsibles.
La regla de privilegis ha de coincidir amb la mateixa ruta i les mateixes subordres. Una entrada de sudoers per a /usr/local/bin/vpnclient no autoritza /usr/bin/vpnclient, i una entrada que permet qualsevol argument deixa que qualsevol procés local reconfigure o aturi el túnel. Concedeix els dos verbs que necessita la unit i mantén el desmuntatge fora d’ella si aturar el servei ja tanca la interfície.
Aquí és on la comparació val la pena: la unit, la base de dades de paquets i sudoers haurien de nomenar una sola ruta. Quan ho fan, l’error EXEC desapareix sense reiniciar i sense una còpia del binari en un tercer lloc.
Demostra l’ordre analitzada abans de reiniciar
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 és la sortida decisiva perquè imprimeix l’argv que systemd ha analitzat realment, incloent-hi qualsevol drop-in. systemd-analyze verify detecta una ruta absent o no executable abans que reiniciïs, i l’ordre d’estat després del reinici et diu si el procés existeix ara.
Si la unit s’inicia i després falla, has deixat la família EXEC i has entrat en el maneig d’errors propi del client. Comprova el journal buscant el missatge del client, no una altra fallada d’execve. Guarda el diff de la unit i el diff de sudoers junts al registre de canvis, perquè la propera actualització no reintrodueixi silenciosament la ruta dividida.