#include <spawn.h> int posix_spawn(pid_t *restrict pid, const char *restrict path, const posix_spawn_file_actions_t *restrict file_actions, const posix_spawnattr_t *restrict attrp, char *const argv[restrict], char *const envp[restrict]); int posix_spawnp(pid_t *restrict pid, const char *restrict file, const posix_spawn_file_actions_t *restrict file_actions, const posix_spawnattr_t *restrict attrp, char *const argv[restrict], char *const envp[restrict]);
Les fonctions posix_spawn() et posix_spawnp() fournissent les fonctionnalités de fork(2) et exec(3) combinées, complétées par des étapes facultatives de nettoyage dans l'enfant avant l'appel à exec(3). Ces fonctions n'ont pas vocation à remplacer les appels systèmes fork(2) et execve(2). En fait, elles ne fournissent qu'un sous-ensemble des fonctionnalités qui peuvent être réalisées par ces appels systèmes.
La seule différence entre posix_spawn() et posix_spawnp() est la manière avec laquelle elles spécifient le fichier devant être exécuté par le processus enfant. Avec posix_spawn(), le fichier exécutable est indiqué par un chemin (absolu ou relatif). Avec posix_spawnp(), le fichier exécutable n'est indiqué que par un nom de fichier et le système le cherche dans la liste des répertoires indiqués dans PATH (de la même façon que execvp(3)). Le reste de cette page est écrit du point de vue de posix_spawn() et il est à garder en mémoire que posix_spawnp() ne diffère que par le point qui vient d'être décrit.
Les arguments restants de ces fonctions sont comme suit :
Ci-dessous, les fonctions sont décrites selon une méthode en trois étapes : fork(), pré-exec() (exécuté dans l'enfant) et exec() (exécuté dans l'enfant).
L'identifiant du nouveau processus enfant est placé dans *pid. La fonction posix_spawn() rend alors la main au processus appelant.
Ensuite, le parent peut utiliser l'un des appels système décrits dans wait(2) pour vérifier l’état du processus enfant. Si l'enfant échoue dans n'importe laquelle des étapes de nettoyage décrites ci-dessous ou n'arrive pas à exécuter le fichier indiqué, il retourne avec un état 127.
Avant la glibc 2.24, le processus enfant est créé avec vfork(2) au lieu de fork(2) lorsqu'une des conditions suivantes est remplie :
En d'autres termes, vfork(2) est utilisée si l'appelant le demande ou si aucun nettoyage n'est attendu dans l'enfant avant qu'il n'exec(3)ute le fichier demandé.
Tous les attributs de processus de l'enfant, autres que ceux affectés par les attributs indiqués dans l'objet vers lequel attrp pointe et par les actions sur fichier indiquées dans l'objet vers lequel file_actions pointe, seront affectés comme si l'enfant avait été créé par fork(2) et que le programme avait été exécuté par execve(2).
Les actions d'attributs de processus sont définies par l'objet d'attributs vers lequel attrp pointe. L'attribut spawn-flags (indiqué par un appel à posix_spawnattr_setflags(3)) contrôle les actions globales effectuées, et les autres attributs de l'objet déterminent les valeurs utilisées durant ces actions.
Les effets des drapeaux qui peuvent être indiqués dans spawn-flags sont les suivants :
Si les drapeaux POSIX_SPAWN_SETSCHEDPARAM et POSIX_SPAWN_SETSCHEDPOLICY ne sont pas spécifiés, l'enfant hérite du parent les attributs correspondants de l'ordonnanceur.
Si attrp est NULL, alors les comportements par défaut décrits plus haut pour chaque drapeau s'appliquent.
The file_actions argument specifies a sequence of file operations that are performed in the child process after the general processing described above, and before it performs the exec(3). If file_actions is NULL, then no special action is taken, and standard exec(3) semantics apply---file descriptors open before the exec remain open in the new process, except those for which the FD_CLOEXEC flag has been set. File locks remain in place.
Si file_actions n'est pas NULL, il contient un ensemble ordonné de demandes pour exécuter open(2), close(2) et dup2() sur des fichiers . Ces requêtes sont ajoutées à file_actions par posix_spawn_file_actions_addopen(3), posix_spawn_file_actions_addclose(3) et posix_spawn_file_actions_adddup2(3). Les opérations demandées sont effectuées dans l'ordre dans lequel elles ont été ajoutées à file_actions.
Si une des actions de nettoyage échoue (à cause de mauvaises valeurs ou pour toute autre raison pour laquelle la gestion de signaux, l'ordonnancement de processus, les fonctions d'identifiant de groupe de processus ou d'opérations de descripteur de fichier peuvent échouer), le processus enfant termine avec un code de retour de 127.
Le processus enfant récupère son environnement depuis l'argument envp, analysé comme si execve(2) avait été appelé avec. Les arguments du processus créé viennent de l'argument argv, analysé comme pour execve(2).
Même lorsque ces fonctions renvoient un état de réussite, le processus enfant peut encore échouer pour une pléthore de raisons liées au pré-exec(). De plus, exec(3) peut échouer. Dans tous ces cas, le processus enfant termine avec 127 comme code de retour.
De plus, ces fonction échouent si :
Selon POSIX, il n'est pas déterminé si les gestionnaires de dédoublement établis avec pthread_atfork(3) sont appelés lorsque posix_spawn() est appelée. Depuis la version 2.24 de la glibc, les gestionnaires de dédoublement ne sont jamais exécutés. Sur des implémentations plus anciennes, les gestionnaires de dédoublement ne sont appelés que si l'enfant est créé avec fork(2).
Il n'existe pas de fonction « posix_fspawn » (c'est-à-dire une fonction qui serait à posix_spawn() ce que fexecve(3) est à execve(2)). Cependant, cette fonctionnalité peut être obtenue en spécifiant l'argument path comme l'un des fichiers dans le répertoire /proc/self/fd de l'appelant.
Dans la première invocation, la commande date(1) est exécutée dans l'enfant et l'appel à posix_spawn() n'utilise pas d'objets d'actions sur fichier ou d'attributs.
$ ./a.out date PID de l'enfant : 7634 Tue Feb 1 19:47:50 CEST 2011 État de l'enfant : terminé, statut=0
Dans la deuxième invocation, l'option en ligne de commande -c est utilisée pour créer un objet d'actions sur fichier qui ferme la sortie standard dans l'enfant. Par la suite, date(1) échoue lors d'une tentative d'écriture et termine avec un état 1.
$ ./a.out -c date PID de l'enfant : 7636 date : erreur d'écriture : Mauvais descripteur de fichier État de l'enfant : terminé, état=1
Dans l'invocation suivante, l'option en ligne de commande -s est utilisée pour créer un objet d'attributs qui indique que tous les signaux (blocables) doivent être bloqués dans l'enfant. Par la suite, une tentative de tuer l'enfant par le signal par défaut envoyé par kill(1) (c'est-à-dire SIGTERM) échoue car ce signal est bloqué. Par conséquent, il est nécessaire d'utiliser SIGKILL pour tuer l'enfant (car SIGKILL ne peut être bloqué).
$ ./a.out -s sleep 60 & [1] 7637 $ PID de l'enfant : 7638
$ kill 7638 $ kill -KILL 7638 $ État de l'enfant : tué par le signal 9 [1]+ Fait ./a.out -s sleep 60
Lorsque l'enfant tente d'exécuter une commande qui n'existe pas, l'appel à exec(3) échoue et l'enfant termine avec un état 127.
$ ./a.out xxxxx PID de l'enfant : 10190 Statut de l'enfant : terminé, état=127
#define errExit(msg) do { perror(msg); \
exit(EXIT_FAILURE); } while (0)
#define errExitEN(en, msg) \
do { errno = en; perror(msg); \
exit(EXIT_FAILURE); } while (0)
char **environ;
int
main(int argc, char *argv[])
{
pid_t child_pid;
int s, opt, status;
sigset_t mask;
posix_spawnattr_t attr;
posix_spawnattr_t *attrp;
posix_spawn_file_actions_t file_actions;
posix_spawn_file_actions_t *file_actionsp;
/* Lire les options de la ligne de commande pouvant être utilisées pour indiquer
un objet d'attributs et un objet d'actions sur fichier pour l'enfant. */
attrp = NULL;
file_actionsp = NULL;
while ((opt = getopt(argc, argv, "sc")) != -1) {
switch (opt) {
case 'c': /* -c: close standard output in child */
/* Créer un objet d'actions de fichier et lui ajouter
une action "fermer". */
s = posix_spawn_file_actions_init(&file_actions);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_init");
s = posix_spawn_file_actions_addclose(&file_actions,
STDOUT_FILENO);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_addclose");
file_actionsp = &file_actions;
break;
case 's': /* -s: block all signals in child */
/* Créer un objet d'attributs et lui ajouter
une action "établir un masque de signaux". */
s = posix_spawnattr_init(&attr);
if (s != 0)
errExitEN(s, "posix_spawnattr_init");
s = posix_spawnattr_setflags(&attr, POSIX_SPAWN_SETSIGMASK);
if (s != 0)
errExitEN(s, "posix_spawnattr_setflags");
sigfillset(&mask);
s = posix_spawnattr_setsigmask(&attr, &mask);
if (s != 0)
errExitEN(s, "posix_spawnattr_setsigmask");
attrp = &attr;
break;
}
}
/* Spawn the child. The name of the program to execute and the
command-line arguments are taken from the command-line arguments
of this program. The environment of the program execed in the
child is made the same as the parent's environment. */
s = posix_spawnp(&child_pid, argv[optind], file_actionsp, attrp,
&argv[optind], environ);
if (s != 0)
errExitEN(s, "posix_spawn");
/* Détruire tout objet créé précédemment. */
if (attrp != NULL) {
s = posix_spawnattr_destroy(attrp);
if (s != 0)
errExitEN(s, "posix_spawnattr_destroy");
}
if (file_actionsp != NULL) {
s = posix_spawn_file_actions_destroy(file_actionsp);
if (s != 0)
errExitEN(s, "posix_spawn_file_actions_destroy");
}
printf("PID de l'enfant : %jd\n", (intmax_t) child_pid);
/* Observer l’état de l'enfant jusqu'à son arrêt. */
do {
s = waitpid(child_pid, &status, WUNTRACED | WCONTINUED);
if (s == -1)
errExit("waitpid");
printf("Statut de l'enfant : ");
if (WIFEXITED(status)) {
printf("terminé, état=%d\n", WEXITSTATUS(status));
} else if (WIFSIGNALED(status)) {
printf("tué par le signal %d\n", WTERMSIG(status));
} else if (WIFSTOPPED(status)) {
printf("arrêté par le signal %d\n", WSTOPSIG(status));
} else if (WIFCONTINUED(status)) {
printf("reprise\n");
}
} while (!WIFEXITED(status) && !WIFSIGNALED(status));
Cette traduction est une documentation libre ; veuillez vous reporter à la GNU General Public License version 3 concernant les conditions de copie et de distribution. Il n'y a aucune RESPONSABILITÉ LÉGALE.
Si vous découvrez un bogue dans la traduction de cette page de manuel, veuillez envoyer un message à