Onte o túnel funcionaba, e esta mañá a unit está morta con Failed at step EXEC spawning /usr/local/bin/vpnclient no journal. As credenciais, as rutas e a conta nunca entran nesa frase. systemd resolveu ExecStart nunha ruta, pediu ao núcleo que a executase, e o núcleo negouse, case sempre porque non existe nada nesa ruta ou porque o ficheiro non é executable. Trata o fallo como un problema de ficheiro e argv ata que o comando analizado demostre o contrario.

Por que EXEC falla antes de que comece a autenticación

systemd non executa ExecStart a través dun shell. Fai un fork, constrúe un vector de argumentos a partir da liña e chama a execve sobre o primeiro elemento. Se esa chamada falla, o servizo nunca chega ao código propio do cliente de VPN, así que ningunha edición de perfil nin comprobación de credenciais pode axudar.

O código de estado separa esta familia das caídas ordinarias. Unha unit que sae con status=203/EXEC nunca iniciou un proceso; unha unit que arranca e logo sae con status=1 pode ter fallado na autenticación, no DNS ou no encamiñamento. Le o código antes do rexistro do cliente, porque no primeiro caso o rexistro do cliente estará baleiro.

A ruta do journal é a que usou systemd, non necesariamente a que editaches. Os ficheiros drop-in e a saída do xerador poden substituír o ficheiro do provedor, e un daemon-reload obsoleto deixa a liña antiga na memoria. Por iso o primeiro diagnóstico é preguntar a systemd que cre que é o comando, en lugar de abrir o ficheiro que recordas ter cambiado.

Tres lugares onde se escribe a ruta do binario

Un cliente de VPN instalado desde un paquete de distribución, un script do provedor e un tarball de versión poden acabar en tres prefixos distintos. A unit, a regra de privilexios e o instalador rexistraron cada un un deses prefixos, e o fallo aparece cando dous dos tres non coinciden.

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/

Unha discrepancia concreta vese así: o script do provedor instala en /usr/local/bin, o tarball descomprimiuse baixo /opt, e a unit segue nomeando a ruta antiga /usr/bin dun paquete anterior. Só existe un deses ficheiros, e rara vez é o que está en ExecStart.

Decide que ruta é canónica antes de cambiar calquera dos ficheiros. Se o paquete de distribución é dono do binario, a ruta do paquete é a canónica e a unit debe seguila. Se o é o script do provedor, a mesma regra aplícase ao prefixo do provedor. Copiar un binario entre prefixos crea dúas copias que se separan na próxima actualización.

Cando un comando entre comiñas se converte nun nome de ficheiro

Un segundo modo de fallo escóndese tras a mesma liña do journal. Alguén escribe isto na unit e espera que o cliente se conecte durante o arranque:

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

systemd divide o valor en palabras, así que a primeira palabra convértese en /usr/bin/vpnclient connect office ao eliminar as comiñas como sintaxe de agrupación. Despois o núcleo busca un ficheiro cuxo nome conteña espazos, e non existe. O erro é idéntico ao dun binario ausente aínda que o binario estea instalado.

A forma admitida é un executable real seguido de argumentos separados, por exemplo ExecStart=/usr/bin/vpnclient connect office. Se o fluxo de traballo precisa de verdade unha tubería ou unha cadea, pono nun script e chama o script, porque ExecStart non ten &&, nin tuberías, nin expansión de glob.

Arranxa a unit, non o sistema de ficheiros

A reparación tentadora é unha ligazón simbólica desde a ruta esperada ata o binario real. Funciona ata que o paquete se actualiza e a ligazón apunta a un ficheiro eliminado, ou ata que unha etiqueta de SELinux deixa de coincidir co obxectivo. É preferible editar a unit mediante un drop-in, para que o ficheiro do provedor quede intacto e as actualizacións sigan sendo previsibles.

A regra de privilexios debe coincidir coa mesma ruta e os mesmos subcomandos. Unha entrada de sudoers para /usr/local/bin/vpnclient non autoriza /usr/bin/vpnclient, e unha entrada que permite calquera argumento deixa que calquera proceso local reconfigure ou deteña o túnel. Concede os dous verbos que necesita a unit e mantén a desmontaxe fóra dela se deter o servizo xa pecha a interface.

Aquí é onde a comparación paga a pena: a unit, a base de datos de paquetes e sudoers deberían nomear unha soa ruta. Cando o fan, o erro EXEC desaparece sen reiniciar e sen unha copia do binario nun terceiro lugar.

Demostra o comando analizado antes 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-pager

systemctl show é a saída decisiva porque imprime o argv que systemd analizou realmente, incluído calquera drop-in. systemd-analyze verify detecta unha ruta ausente ou non executable antes de que reinicies, e o comando de estado tras o reinicio diche se o proceso existe agora.

Se a unit arranca e logo falla, deixaches a familia EXEC e entriches no manexo de erros propio do cliente. Busca no journal a mensaxe do cliente, non outro fallo de execve. Garda o diff da unit e o diff de sudoers xuntos no rexistro de cambios, para que a próxima actualización non reintroduza silenciosamente a ruta dividida.

Artigos relacionados