int execve(const char *fichier, char *const argv[],
char *const envp[]);
#! interpréteur [argument-optionnel]
Pour plus de détails sur ce dernier cas, voir « Scripts d'interprétation » plus loin.
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 du programme, et si le système de fichiers sous-jacent n'est pas monté avec l'option nosuid (l'attribut MS_NOSUID pour mount(2)), et si le processus appelant n'est pas tracé par ptrace(2), 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 permissions 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 version 5, ou /lib/ld-linux.so.2 pour ceux liés avec la glibc 2.
Tous les attributs d'un processus sont conservés pendant un execve(), à l'exception des suivants :
Les attributs de processus de la liste précédente sont tous spécifiés dans POSIX.1-2001. Les attributs de processus, spécifiques à Linux, suivants ne sont pas conservés pendant un execve():
Veuillez noter les points suivants :
#! interpréteur [argument-optionnel]
L'interpréteur doit être indiqué par un nom complet, avec son chemin d'accès, et ne doit pas être lui-même un script. Si l'argument fichier de execve() indique un script, l'interpréteur sera invoqué avec les arguments suivants :
interpréteur [argument-optionnel] fichier arg...
où arg... est la liste de mots pointée par l'argument argv de execve().
Pour une utilisation portable, argument-optionnel doit soit être absent, soit être un mot unique (c'est-à-dire ne pas contenir d'espace) ; voir NOTES plus loin.
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.
Depuis le noyau 2.6.23, la plupart des architectures prennent en charge une limite de taille dérivée de la limite de ressource souple RLIMIT_STACK (voir getrlimit(2)) qui est en vigueur au moment de l'appel à execve(). Pour ces architectures, la taille totale est limitée au quart de la taille de pile autorisée, la limite par chaîne étant de 32 pages (la constante noyau MAX_ARG_STRLEN), et le nombre maximum de chaînes étant de 0x7FFFFFFF. (Cette modification permet aux programmes d'avoir une liste d'arguments et/ou d'environnement plus grande. Imposer une limite d'un quart assure aux programmes de toujours avoir de la place dans la pile.) Les architectures qui n'ont pas d'unité de gestion de mémoire ne sont pas concernées, elles conservent la limite d'avant le noyau 2.6.23.
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 : certaines refuseront l'exécution des fichiers SUID/SGID lorsque cela donnerait à l'appelant des privilèges qu'il n'a pas (et renverront l'erreur EPERM), d'autres ignoreront simplement les bits SUID/SGID mais accepteront d'effectuer l'appel exec().
La première ligne d'un script shell exécutable (#!) a une longueur maximale de 127 caractères.
La sémantique de l'argument argument-optionnel d'un script varie suivant les implémentations. Sous Linux, la chaîne entière qui suit le nom de l'interpréteur est passée à l'interpréteur comme un argument unique et cette chaîne peut contenir des espaces. Toutefois, les comportements diffèrent sur d'autres systèmes. Certains utilisent la première espace pour terminer l'argument argument-optionnel. Sur d'autres systèmes, le script peut avoir plusieurs arguments et les espaces dans argument-optionnel sont utilisées pour délimiter les arguments.
Sous Linux, argv peut être NULL, ce qui a le même effet que de spécifier que cet argument est un pointeur vers des listes contenant un pointeur NULL unique. Ne vous servez pas de cette caractéristique ! Elle n'est ni standard, ni portable : sur la plupart des autres systèmes Unix, elle provoquera une erreur (EFAULT).
/* 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 indiqué comme argument de ligne de commande :
/* execve.c */ #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <assert.h> int main(int argc, char *argv[]) { char *newargv[] = { NULL, "hello", "world", NULL }; char *newenviron[] = { NULL }; assert(argc == 2); /* argv[1] identifie le programme à exécuter */ newargv[0] = argv[1]; execve(argv[1], newargv, newenviron); perror("execve"); /* execve() ne retourne qu'en cas d'erreur */ exit(EXIT_FAILURE); }
Nous pouvons utiliser le second programme pour exécuter le premier de la façon suivante :
$ cc myecho.c -o myecho $ cc execve.c -o execve $ ./exceve ./myecho argv[0]: ./myecho argv[1]: hello argv[2]: world
Nous pouvons également utiliser ces programmes pour montrer l'utilisation d'un script. Pour ce faire, nous créons un script dont l'« interpréteur » est notre programme myecho :
$ cat > script.sh #! ./myecho script-arg ^D $ chmod +x script.sh
Nous pouvons ensuite 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
Ce document est une traduction réalisée par Christophe Blaess <http://www.blaess.fr/christophe/> le 9 octobre 1996 et révisée le 17 juillet 2008.
L'équipe de traduction a fait le maximum pour réaliser une adaptation française de qualité. La version anglaise la plus à jour de ce document est toujours consultable via la commande : « LANG=C man 2 execve ». N'hésitez pas à signaler à l'auteur ou au traducteur, selon le cas, toute erreur dans cette page de manuel.
Dernière mise à jour : 17 juillet 2008