CyberSDF

Reprenez la main sur votre numérique

systemctl status=203/EXEC : execve a échoué et le programme n’a jamais démarré

un poste de travail sobre vu de trois quarts, ecran eteint, clavier mecanique, carnet ouvert

Le journal a écrit Main process exited, code=exited, status=203/EXEC et le service est passé en failed sans qu’une seule ligne de votre programme s’exécute. Le code 203 est interne à systemd : la page de manuel systemd.exec(5) livrée par Debian 13 le nomme EXIT_EXEC et le rattache à l’appel système execve(2). Quatre causes couvrent la quasi-totalité des cas, et la première ligne du journal les sépare déjà : cible introuvable, bit d’exécution manquant, format de fichier refusé, interpréteur absent.

Sommaire
  1. code=exited, status=203/EXEC vient de systemd et place la panne dans execve
  2. Trois causes produisent 203/EXEC : cible absente, bit x perdu, format refusé
  3. Reprendre la main : nommer le chemin, tester l’accès, corriger, relancer
  4. Le piège : No such file or directory désigne parfois la ligne #! et non le fichier
  5. Failed to locate en 252, Unable to locate en 257 : la formulation dépend de la version
  6. Le bit x, le shebang et le noexec couvrent la plupart des 203/EXEC : six questions pour trancher
  7. Sources et versions de référence

code=exited, status=203/EXEC vient de systemd et place la panne dans execve

Le statut 203/EXEC est fabriqué par systemd, pas par votre programme : l’appel système execve(2) a échoué et le noyau n’a jamais transféré la main au binaire. La page de manuel systemd.exec(5) livrée par Debian 13 nomme ce code EXIT_EXEC et le résume par cette phrase : « The actual process execution failed (specifically, the execve(2) system call). Most likely this is caused by a missing or non-accessible executable file. » La fonction unit_log_process_exit() écrit le nombre puis son nom, 203 puis EXEC, d’après le code de la balise v252 du dépôt systemd. Un programme qui plante en interne renvoie son propre code de sortie, sans nom symbolique accolé, et systemd écrit alors status=1 ou status=2. Voir 203/EXEC circonscrit donc la panne à la phase de lancement, avant la première instruction exécutée, ce que la suite du journal confirme en nommant le fichier refusé.

sep 19 10:12:33 poste systemd[1]: sauvegarde.service: Failed to locate executable /usr/local/bin/sauvegarde.sh: No such file or directory
sep 19 10:12:33 poste systemd[1]: sauvegarde.service: Failed at step EXEC spawning /usr/local/bin/sauvegarde.sh: No such file or directory
sep 19 10:12:33 poste systemd[1]: sauvegarde.service: Main process exited, code=exited, status=203/EXEC
sep 19 10:12:33 poste systemd[1]: sauvegarde.service: Failed with result 'exit-code'.

Cause de ces quatre lignes : le chemin écrit dans ExecStart ne mène à aucun fichier. Le remède tient en deux gestes, vérifier le chemin avec ls -l, puis réécrire la ligne ExecStart. Sur systemd 257, la même panne s’écrit Unable to locate executable '/usr/local/bin/sauvegarde.sh': No such file or directory, la deuxième ligne ne bougeant pas d’une version à l’autre.

Trois causes produisent 203/EXEC : cible absente, bit x perdu, format refusé

execve(2) ne renvoie qu’une poignée d’erreurs, et chacune se traduit par une phrase différente dans le journal. Un chemin qui ne mène à rien produit ENOENT, que le noyau nomme No such file or directory ; un fichier privé du bit d’exécution produit EACCES, traduit Permission denied ; un fichier qui n’est ni un binaire ELF reconnu ni un script à ligne #! produit ENOEXEC, soit Exec format error. Selon la page execve(2) du projet man-pages Linux, ces erreurs couvrent aussi l’option de montage noexec et le cas d’un interpréteur absent, script ou chargeur ELF, qui trompe tout le monde parce que le fichier visé, lui, existe. Sur systemd 252, la fonction check_x_access() de path-util.c tranche avant même l’appel au noyau : elle ouvre le chemin, vérifie qu’il s’agit d’un fichier ordinaire, puis teste le droit d’exécution, et son verdict alimente la première ligne du journal.

Codes rendus par execve(2) et lignes correspondantes du journal, relevés dans le code de systemd 252 et les manuels du noyau.
Cause constatée Errno exécve Ligne du journal sur systemd 252 Correction
Chemin absent ENOENT Failed to locate executable /usr/local/bin/sauvegarde.sh: No such file or directory corriger ExecStart, puis systemctl daemon-reload
Bit x manquant EACCES Failed to locate executable /usr/local/bin/sauvegarde.sh: Permission denied chmod 755 /usr/local/bin/sauvegarde.sh
Chemin qui désigne un répertoire EISDIR Failed to locate executable /usr/local/bin/sauvegarde.sh: Is a directory corriger le chemin dans l’unité
Partition montée noexec EACCES Failed to execute /usr/local/bin/sauvegarde.sh: Permission denied déplacer le fichier ou remonter la partition avec exec
Ligne #! terminée par un retour chariot ENOENT Failed to execute /usr/local/bin/sauvegarde.sh: No such file or directory sed -i 's/\r$//' /usr/local/bin/sauvegarde.sh
Script sans ligne #! ENOEXEC Failed to execute /usr/local/bin/sauvegarde.sh: Exec format error ajouter #!/bin/bash en première ligne
Chargeur ELF absent ENOENT Failed to execute /usr/local/bin/binaire: No such file or directory fournir libc6:i386 ou recompiler pour la bonne architecture

Le contrôle de systemd précède l’appel au noyau, et il ne voit pas tout : l’option noexec d’une partition n’est testée qu’au moment d’exécuter, dans may_open() du fichier fs/namei.c du noyau Linux. D’où la ligne Failed to execute pour ce cas, là où un bit x manquant produit Failed to locate.

Reprendre la main : nommer le chemin, tester l’accès, corriger, relancer

Le diagnostic se mène dans l’ordre, sans rien modifier avant la dernière étape : la ligne du journal nomme le message, l’unité donne le chemin exact, le disque dit si le fichier est exécutable, le noyau dit s’il accepte le format, et la table de montage dit si la partition autorise l’exécution. Chaque étape se termine par la sortie attendue, qui sert de critère d’arrêt. Les exemples utilisent sauvegarde.service et /usr/local/bin/sauvegarde.sh ; remplacez ces deux noms par ceux de votre unité, que systemctl cat affiche avec ses éventuels drop-ins. Tant qu’une sortie ne correspond pas à ce qui est annoncé, la cause n’est pas encore trouvée, et mieux vaut continuer la liste que corriger au hasard.

  1. Lire l’état du service et la dernière erreur.

    systemctl status sauvegarde.service --no-pager

    Ce que vous devez voir : une ligne Active: failed (Result: exit-code), une ligne Process: 4821 ExecStart=/usr/local/bin/sauvegarde.sh (code=exited, status=203/EXEC), puis les dernières lignes du journal.

  2. Extraire le chemin exact lu par systemd.

    systemctl cat sauvegarde.service

    Ce que vous devez voir : la ligne ExecStart=/usr/local/bin/sauvegarde.sh, avec un chemin complet.

  3. Vérifier l’existence du fichier et son bit d’exécution.

    ls -l /usr/local/bin/sauvegarde.sh
    test -x /usr/local/bin/sauvegarde.sh && echo "bit x present"

    Ce que vous devez voir : un mode qui commence par -rwx et le texte bit x present. Un mode -rw-r--r-- annonce Permission denied.

  4. Lire le type réel du fichier et les octets de la première ligne.

    file /usr/local/bin/sauvegarde.sh
    head -1 /usr/local/bin/sauvegarde.sh | od -c | head -3

    Ce que vous devez voir : POSIX shell script, ASCII text executable, sans la mention with CRLF line terminators, et un \n en fin de ligne, jamais \r \n.

  5. Vérifier la monture et les réglages qui masquent un chemin.

    findmnt -no SOURCE,OPTIONS -T /usr/local/bin/sauvegarde.sh
    grep -E "ProtectHome|RootDirectory" /etc/systemd/system/sauvegarde.service

    Ce que vous devez voir : des options de montage sans noexec, et aucune ligne ProtectHome=yes quand le binaire vit sous /home.

  6. Corriger, recharger si l’unité a changé, relancer.

    sudo chmod 755 /usr/local/bin/sauvegarde.sh
    sudo systemctl daemon-reload
    sudo systemctl restart sauvegarde.service
    systemctl status sauvegarde.service --no-pager

    Ce que vous devez voir : Active: active (running) et, dans le journal, Started sauvegarde.service à la place de Failed with result 'exit-code'.

Le piège : No such file or directory désigne parfois la ligne #! et non le fichier

Un fichier présent, lisible et marqué exécutable peut tout de même provoquer No such file or directory, parce que le noyau ne cherche pas que le fichier : il cherche aussi l’interpréteur que la ligne #! désigne. D’après fs/binfmt_script.c dans le noyau Linux, cette ligne est lue jusqu’au premier passage à la ligne, seuls les espaces et les tabulations de fin sont retirés, et le nom restant est pris au mot dans un tampon de 256 octets. Un \r laissé par un éditeur venu de Windows reste donc collé au nom : le noyau demande /bin/bash suivi d’un retour chariot, ne trouve rien, et rend ENOENT. Un second cas donne le même message sans ligne #! : un binaire ELF dont le chargeur dynamique manque, par exemple un exécutable 32 bits sur un système 64 bits dépourvu de libc6:i386, car execve(2) rend ENOENT dès qu’un interpréteur ELF manque.

file /usr/local/bin/sauvegarde.sh
head -1 /usr/local/bin/sauvegarde.sh | od -c | head -3
sed -i 's/\r$//' /usr/local/bin/sauvegarde.sh

La première commande nomme le type réel, la deuxième montre les octets de la ligne #!, la troisième retire les retours chariot. Un interpréteur /bin/bash existe sous Debian et Ubuntu, où /bin mène à /usr/bin, comme le détaillent les chemins de /bin et de bash.

Failed to locate en 252, Unable to locate en 257 : la formulation dépend de la version

La phrase à chercher dans le journal a changé deux fois entre systemd 245 et systemd 257, et une recherche sur un texte exact ne trouve donc pas les réponses écrites pour une autre version. De systemd 237 à 245, la première ligne était Failed to execute command, sans le chemin, et le nom du fichier n’apparaissait que sur la ligne Failed at step EXEC spawning, d’après les balises v237 et v245 du dépôt systemd. À partir de systemd 247, cette première ligne devient Failed to locate executable /chemin, réservée aux cas où la cible n’est pas trouvable ou pas exécutable. La balise v256 remplace la phrase par Unable to locate executable ‘/chemin’, entre apostrophes, et Debian 13 livre en 257.13-1~deb13u1 cette dernière formulation, publiée le 9 août 2025.

Formulation de la première ligne du journal quand le chemin d’ExecStart ne mène à rien, par version embarquée.
Version de systemd Distribution qui l’embarque Première ligne du journal
252.39-1~deb12u2 Debian 12 bookworm Failed to locate executable /usr/local/bin/sauvegarde.sh: No such file or directory
255.4 Ubuntu 24.04 LTS même première ligne que systemd 252
257.13-1~deb13u1 Debian 13 trixie Unable to locate executable '/usr/local/bin/sauvegarde.sh': No such file or directory

Deux limites valent d’être connues. La page systemd.exec(5) résume encore 203 par missing or non-accessible executable file, sans reprendre la séparation entre Failed to locate et Failed to execute que le code applique depuis systemd 252.

La lecture des unités et des journaux pour un autre service suit la même marche, décrite dans systemctl service code exited status 203, et le reste du diagnostic tient dans la rubrique Linux.

Le bit x, le shebang et le noexec couvrent la plupart des 203/EXEC : six questions pour trancher

Le fichier existe, porte le bit x, et le journal dit quand même No such file or directory ?

La ligne #! désigne alors un interpréteur que le noyau ne trouve pas : un \r collé au nom transforme /bin/bash en /bin/bash\r, qui n’existe pas. La commande file affiche « with CRLF line terminators », head -1 | od -c montre le \r, et sed -i 's/\r$//' le retire. Même message pour un binaire 32 bits privé de son chargeur.

Faut-il écrire /usr/bin/bash ou seulement bash dans ExecStart ?

Selon systemd.service(5), les deux passent : un chemin absolu, ou un simple nom sans barre oblique, résolu dans un chemin de recherche figé à la compilation, qui contient /usr/local/bin, /usr/bin et leurs équivalents sbin. La commande systemd-path search-binaries-default affiche ce chemin réel. Hors de ces répertoires, seul un chemin absolu évite le 203/EXEC.

Comment réparer un 203/EXEC quand le bit x manque ?

chmod 755 /usr/local/bin/sauvegarde.sh puis systemctl restart sauvegarde.service suffisent, aucun rechargement de l’unité n’étant nécessaire si le fichier .service n’a pas bougé. Le journal doit passer de Failed with result 'exit-code' à Started sauvegarde.service. Si l’unité tourne sous un autre compte avec User=, contrôler le chemin complet avec namei -l.

Faut-il un daemon-reload après la correction ?

Uniquement si le fichier .service a été modifié : selon systemd.unit(5), systemctl daemon-reload remplace la configuration d’une unité déjà chargée. Un chmod, une correction de shebang ou un fichier remplacé ne touchent pas l’unité, donc systemctl restart suffit. Après une correction d’ExecStart, l’ordre est daemon-reload puis restart, et systemctl reset-failed sauvegarde.service remet à zéro le compteur de démarrages.

Combien de tentatives systemd fait-il avant d’abandonner ?

Cinq en dix secondes par défaut, d’après systemd-system.conf(5) qui fixe DefaultStartLimitBurst à 5 et DefaultStartLimitIntervalSec à dix secondes. Au-delà, le journal écrit Start request repeated too quickly. et l’unité reste en failed sans nouvel essai. Relever StartLimitBurst ne répare pas un 203/EXEC : le binaire reste introuvable.

Un script sans ligne #! peut-il démarrer sous systemd ?

Non. Le noyau rend ENOEXEC pour un fichier qui n’est ni un format binaire reconnu ni un script à ligne #!, et systemd n’a pas de repli vers un shell : le journal écrit Failed to execute /usr/local/bin/sauvegarde.sh: Exec format error, suivi de 203/EXEC. Ajouter #!/bin/bash en première ligne règle le cas, sinon ExecStart=/bin/bash /usr/local/bin/sauvegarde.sh.

Sources et versions de référence