NOM
execve - Exécuter un programme
SYNOPSIS
#include <unistd.h>
int execve(const char *filename, char *const argv[],
char *const envp[]);
execve() exécute le programme correspondant au fichier filename.
Celui‐ci doit être un exécutable binaire ou bien un script commençant
par une ligne du type :
#! interprteur [argument-optionnel]
Pour des détails sur ce dernier cas, voir « Scripts » ci‐dessous.
argv est un tableau de chaînes d’arguments passées au nouveau
programme. envp est un tableau de chaînes, ayant par convention la
forme clé=valeur, qui sont passées au nouveau programme comme
environnement. argv ainsi que envp doivent se terminer par un pointeur
NULL. Les arguments et l’environnement sont accessibles par le nouveau
programme dans sa fonction principale, lorsqu’elle est définie comme :
int main(int argc, char *argv[], char *envp[])
En cas de réussite, execve() ne revient pas à l’appelant, et les
segments de texte, de données (« data » et « bss »), ainsi que la pile
du processus appelant sont remplacés par ceux du programme chargé.
Si l’on effectuait un ptrace(2) sur le programme appelant, un signal
SIGTRAP est envoyé après la réussite de execve().
Si le bit Set-UID est positionné sur le fichier filename, si le système
de fichiers sous‐jacent n’est pas monté nosuid (l’attribut MS_NOSUID de
mount(2)), et si le programme n’est pas tracé, l’UID effectif du
processus appelant est modifié pour prendre celui du propriétaire du
fichier. De même, lorsque le bit Set‐GID est positionné, le GID
effectif est modifié pour correspondre à celui du groupe du fichier.
L’UID effectif du processus est copié dans le Set-UID sauvé ; de la
même manière, le GID effectif est copié dans le Set-GID sauvé. Ces
copies ont lieu après toute modification d’ID effectif à cause des bits
de permission Set-UID et Set-GID.
Si l’exécutable est un fichier binaire a.out lié dynamiquement, et
contenant des appels aux bibliothèques partagées, le linker dynamique
de Linux ld.so(8) est appelé avant l’exécution, afin de charger les
bibliothèques partagées nécessaires en mémoire et d’effectuer l’édition
des liens de l’exécutable.
Si l’exécutable est au format ELF lié dynamiquement, l’interpréteur
indiqué dans le segment PT_INTERP sera invoqué pour charger les
bibliothèques partagées. Cet interpréteur est généralement
/lib/ld-linux.so.1 pour les fichiers binaires liés avec la libc Linux
5, ou /lib/ld-linux.so.2 pour ceux liés avec la glibc 2.
Tous les attributs du processus sont préservés lors d’un execve(), à
l’exception des suivants :
* Les signaux pour lesquels le processus avait placé un
gestionnaire sont maintenant ignorés.
* L’éventuelle pile spécifique pour les gestionnaire de signaux
n’est pas conservée (sigaltstack(2)).
* Les projections en mémoire ne sont pas conservées (mmap(2)).
* Les segments de mémoire partagée System V sont détachés
(shmat(2)).
* Les objets de mémoire partagée POSIX sont supprimés
(shm_open(3)).
* Les descripteurs de files de messages POSIX ouverts sont fermés
(mq_overview(7)).
* Les sémaphores nommés POSIX ouverts sont fermés
(sem_overview(7)).
* Les temporisations POSIX ne sont pas conservées
(timer_create(2)).
* Les flux de répertoires ouverts sont fermés (opendir(3)).
* Les verrouillages de mémoire ne sont pas préservés (mlock(2),
mlockall(2)).
* Les gestionnaires de terminaison ne sont pas préservés
(atexit(3), on_exit(3)).
* L’environnement de travail en virgule flottante est remis à zéro
(voir fenv(3)).
Les attributs de processus listés ci‐dessus sont spécifiés dans
POSIX.1-2001. Les attributs de processus spécifiques à Linux suivants
sont également réinitialisés lors d’un execve() :
* L’attribut PR_SET_DUMPABLE de prctl(2) est activé, sauf si un
programme setuid ou setgid est exécuté, auquel cas il est désactivé.
* L’attribut PR_SET_KEEPCAPS de prctl(2) est effacé.
* Le nom du processus, positionné par prctl(2) PR_SET_NAME (et affiché
avec ps -o comm), est réinitialisé avec le nom du nouvel exécutable.
* Le signal de terminaison est réinitialisé à SIGCHLD (voir clone(2)).
Notez également les points suivants :
* Tous les threads autre que l’appelant sont détruits lors d’un
execve(). Les mutex, les variables de condition, et les autres
objets de pthreads sont détruits.
* L’équivalent de setlocale(LC_ALL, "C") est exécuté au démarrage du
programme.
* POSIX.1-2001 indique que les actions pour les signaux ignorés ou
placés à la valeur par défaut ne sont pas modifiées. Une exception
est néanmoins spécifiée dans POSIX.1-2001 : si SIGCHLD est ignoré,
l’implémentation peut laisser l’action inchangée ou la replacer à la
valeur par défaut ; Linux ne modifie pas l’action.
* Toutes les opérations d’E/S asynchrones en cours sont annulées
(aio_read(3), aio_write(3)).
* Pour le traitement des capacités lors d’un execve(), voir
capabilities(7).
* Par défaut, les descripteurs de fichier restent ouverts au travers
d’un execve(). Les descripteurs marqués close‐on‐exec sont fermés ;
voir la description de FD_CLOEXEC dans fcntl(2). (Si un descripteur
de fichier est fermé, cela cause la libération de tous les verrous
d’enregistrement obtenus sur le fichier correspondant par ce
processus. Voir fcntl(2) pour les détails.) POSIX.1-2001 indique que
si les descripteurs de fichiers 0, 1 et 2 devaient être fermés après
un execve() réussi, et le processus devient privilégié en raison
d’un bit set-user-ID ou set-group-ID sur le fichier exécuté, le
système peut ouvrir un fichier non spécifié pour chacun de ces
descripteurs. En général, un programme portable, privilégié ou pas,
peut considérer que ces trois descripteurs resteront fermés après un
execve().
Scripts
Un script est un fichier dont le bit d’exécution est activé et dont la
première ligne est de la forme :
#! interprteur [argument-optionnel]
L’interprteur doit être un nom de fichier valide pour un exécutable
qui n’est pas un script lui‐même. Si l’argument filename de execve()
indique un script, l’interprteur sera appelé avec les arguments
suivants :
interprteur [argument-optionnel] filename arg...
où arg... est la liste de mots pointée par l’argument argv de execve().
Pour être portable, argument-optionnel doit soit être absent, soit être
un seul mot (c’est‐à‐dire ne pas contenir d’espace) ; voir les NOTES
ci‐dessous.
Limites sur la taille des paramètres et environnement
La plupart des implémentations Unix imposent des limites sur la taille
totale des chaînes des paramètres des lignes de commande (argv) et de
l’environnement (envp) qui peuvent être passées à un nouveau programme.
POSIX.1 permet à une implémentation d’annoncer cette limite en
utilisant la constante ARG_MAX (soit définie dans <limits.h>, soit
disponible à l’exécution en utilisant l’appel sysconf(_SC_ARG_MAX)).
Sur les noyaux Linux antérieurs à 2.6.23, la mémoire utilisée pour
stocker les chaînes d’environnement et d’arguments était limitée à 32
pages (défini par la constante noyau MAX_ARG_PAGES). Sur les
architectures dont la taille de page est 4 Ko, cela donne un maximum de
128 Ko.
Sur les noyaux 2.6.23 et ultérieurs, la plupart des architectures ont
une limite de taille dérivée de la limite de ressources souple
RLIMIT_STACK (voir getrlimit(2)) qui est en vigueur au moment de
l’appel à execve() (ce n’est pas le cas pour les architectures sans
unité de gestion mémoire : elles conservent la limite des noyaux
antérieurs à 2.6.23). Ce changement permet aux programmes d’avoir une
liste de paramètre ou un environnement beaucoup plus grand. Pour ces
architectures, la taille totale est limitées à 1/4 de la taille de pile
permise (imposer une limite de 1/4 permet d’assurer que le nouveau
programme garde de l’espace pour la pile). Depuis Linux 2.6.25, le
noyau place une limite inférieure de 32 pages à cette limite de taille,
de telle sorte que même si RLIMIT_STACK est très faible, il est
garantit aux applications qu’elles auront au moins autant de place pour
les paramètres et leur environnement que ce qui était fournit par Linux
2.6.23 et les précédents (cette garantie n’était pas présente dans les
noyaux 2.6.23 et 2.6.24). De plus, la limite par chaîne est de 32 pages
(la constante noyau MAX_ARG_STRLEN), et le nombre maximum de chaînes
est de 0x7FFFFFFF.
VALEUR RENVOYÉE
En cas de réussite, execve() ne revient pas, en cas d’échec il renvoie
-1 et errno contient le code d’erreur.
ERREURS
E2BIG Le nombre total d’octets dans l’environnement (envp) et la liste
d’arguments (argv) est trop grand.
EACCES La permission de parcours est refusée pour un des composants du
chemin filename ou du nom d’un interpréteur de script. (Voir
aussi path_resolution(7).)
EACCES Le fichier ou l’interpréteur de script n’est pas un fichier
régulier.
EACCES L’autorisation d’exécution est refusée pour le fichier, ou un
interpréteur de script, ou un interpréteur ELF.
EACCES Le système de fichiers est monté avec l’option noexec.
EFAULT L’argument filename pointe en dehors de l’espace d’adressage
accessible.
EINVAL Un exécutable ELF a plusieurs segments PT_INTERP (indique
plusieurs interpréteurs).
EIO Une erreur d’entrée-sortie s’est produite.
EISDIR L’interpréteur ELF cité est un répertoire.
ELIBBAD
L’interpréteur ELF mentionné n’est pas dans un format connu.
ELOOP Le chemin d’accès au fichier filename, ou à un interpréteur de
script, ou à un interpréteur ELF, contient une référence
circulaire (à travers un lien symbolique)
EMFILE Le nombre maximal de fichiers ouverts par processus est atteint.
ENAMETOOLONG
La chaîne de caractères filename est trop longue.
ENFILE La limite du nombre total de fichiers ouverts sur le système a
été atteinte.
ENOENT Le fichier filename ou un script ou un interpréteur ELF n’existe
pas, ou une bibliothèque partagée nécessaire pour le fichier ou
l’interpréteur n’est pas disponible.
ENOEXEC
Le fichier exécutable n’est pas dans le bon format, ou est
destiné à une autre architecture.
ENOMEM Pas assez de mémoire pour le noyau.
ENOTDIR
Un élément du chemin d’accès au fichier filename, à un script ou
à un interpréteur ELF, n’est pas un répertoire.
EPERM Le système de fichiers est monté avec l’attribut nosuid et le
fichier a un bit Set-UID ou Set-GID positionné.
EPERM Le processus est suivi avec ptrace(2), l’utilisateur n’est pas
le superutilisateur, et le fichier a un bit Set-UID ou Set-GID
positionné.
ETXTBSY
Un exécutable a été ouvert en écriture par un ou plusieurs
processus.
CONFORMITÉ
SVr4, BSD 4.3, POSIX.1-2001. POSIX.1-2001 ne documente pas le
comportement avec « #! » mais est néanmoins compatible.
NOTES
Les processus Set-UID et Set-GID ne peuvent pas être suivis par
ptrace(2).
Linux ignore les bits Set-UID et Set-GID sur les scripts.
Le résultat d’un montage de système de fichiers avec l’attribut nosuid
peut varier suivant les versions du noyau Linux : certaines refuseront
l’exécution des fichiers Set-UID et Set-GID lorsque cela donnerait à
l’appelant des privilèges qu’il n’a pas (et renverront l’erreur EPERM),
d’autres ignoreront simplement les bits Set-UID et Set-GID mais
accepteront d’effectuer l’appel exec().
La première ligne d’un shell script exécutable (#!) a une longueur
maximale de 127 caractères.
La sémantique de l’argument-optionnel d’un script diffère selon les
implémentations. Sous Linux, la chaîne qui suit le nom de
l’interprteur est passée à l’interpréteur comme un seul mot, et cette
chaîne peut contenir des espaces. Cependant, le comportement est
différent sur d’autres systèmes. Certains utilisent la première espace
comme fin de l’argument-optionnel. Sur certains systèmes, un script
peut avoir plusieurs arguments, délimités par des espaces dans
argument-optionnel.
Sous Linux, argv peut être NULL, ce qui a le même effet que de
spécifier que cet argument est un pointeur vers une liste contenant un
pointeur NULL unique. Ne vous servez pas de cette caractéristique !
Elle n’est ni standard ni portable : sur la plupart des systèmes Unix,
faire cela causera une erreur.
POSIX.1-2001 indique que les valeurs renvoyées par sysconf(3) ne
doivent pas changer pendant la vie d’un processus. Cependant, depuis
Linux 2.6.23, si la limite de ressources RLIMIT_STACK change, alors la
valeur renvoyée par _SC_ARG_MAX changera également, pour refléter le
fait que la limite de l’espace qui reçoit les paramètres de la ligne de
commande et les variables d’environnement a changé.
Historique
Avec Unix V6, la liste des arguments d’un appel exec() se terminait par
0, alors que la liste des arguments de main se terminait par -1. Aussi,
cette liste d’arguments n’était pas utilisable directement dans un
appel exec() supplémentaire. Depuis Unix V7, les deux terminateurs sont
NULL.
EXEMPLE
Le programme suivant est conçu pour être exécuté par le second
programme ci‐dessous. Il se contente d’afficher sa ligne de commande,
un argument par ligne.
/* myecho.c */
#include <stdio.h>
#include <stdlib.h>
int
main(int argc, char *argv[])
{
int j;
for (j = 0; j < argc; j++)
printf("argv[%d]: %s\n", j, argv[j]);
exit(EXIT_SUCCESS);
}
Ce programme peut être utilisé pour exécuter le programme donné comme
argument de ligne de commande :
/* execve.c */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int
main(int argc, char *argv[])
{
char *newargv[] = { NULL, "hello", "world", NULL };
char *newenviron[] = { NULL };
if (argc != 2) {
fprintf(stderr, "Usage: %s <file-to-exec>\n", argv[0]);
exit(EXIT_FAILURE);
}
newargv[0] = argv[1];
execve(argv[1], newargv, newenviron);
perror("execve"); /* execve() ne retourne qu’en cas d’erreur */
exit(EXIT_FAILURE);
}
On peut utiliser le second programme pour exécuter le premier de la
façon suivante :
$ cc myecho.c -o myecho
$ cc execve.c -o execve
$ ./execve ./myecho
argv[0]: ./myecho
argv[1]: hello
argv[2]: world
On peut aussi utiliser ces programmes pour montrer l’utilisation d’un
interpréteur de scripts. Pour ce faire, on crée un script dont
l’«interpréteur » est notre programme myecho :
$ cat > script.sh
#! ./myecho script-arg
^D
$ chmod +x script.sh
On peut alors utiliser notre programme pour exécuter le script :
$ ./execve ./script.sh
argv[0]: ./myecho
argv[1]: script-arg
argv[2]: ./script.sh
argv[3]: hello
argv[4]: world
VOIR AUSSI
chmod(2), fork(2), ptrace(2), execl(3), fexecve(3), getopt(3),
credentials(7), environ(7), path_resolution(7), ld.so(8)
COLOPHON
Cette page fait partie de la publication 3.23 du projet man-pages
Linux. Une description du projet et des instructions pour signaler des
anomalies peuvent être trouvées à l’adresse
http://www.kernel.org/doc/man-pages/.
TRADUCTION
Cette page de manuel a été traduite et mise à jour par Christophe
Blaess <http://www.blaess.fr/christophe/> entre 1996 et 2003, puis par
Alain Portal <aportal AT univ-montp2 DOT fr> jusqu’en 2006, et mise à
disposition sur http://manpagesfr.free.fr/.
Les mises à jour et corrections de la version présente dans Debian sont
directement gérées par Julien Cristau <jcristau@debian.org> et l’équipe
francophone de traduction de Debian.
Veuillez signaler toute erreur de traduction en écrivant à
<debian-l10n-french@lists.debian.org> ou par un rapport de bogue sur le
paquet manpages-fr.
Vous pouvez toujours avoir accès à la version anglaise de ce document
en utilisant la commande « man -L C <section> <page_de_man> ».