2 * Copyright 2017, Jérôme Duval, jerome.Duval@gmail.com
3 * Distributed under the terms of the MIT license.
16 #include <signal_defs.h>
27 enum action_type type
;
41 struct _posix_spawnattr
{
48 struct _posix_spawn_file_actions
{
51 _file_action
*actions
;
56 posix_spawn_file_actions_extend(struct _posix_spawn_file_actions
*actions
)
58 int newsize
= actions
->size
+ 4;
59 void *newactions
= realloc(actions
->actions
,
60 newsize
* sizeof(struct _file_action
));
61 if (newactions
== NULL
)
63 actions
->actions
= (struct _file_action
*)newactions
;
64 actions
->size
= newsize
;
70 posix_spawn_file_actions_init(posix_spawn_file_actions_t
*_file_actions
)
72 posix_spawn_file_actions_t actions
= (posix_spawn_file_actions_t
)malloc(
73 sizeof(struct _posix_spawn_file_actions
));
78 memset(actions
, 0, sizeof(*actions
));
79 *_file_actions
= actions
;
86 posix_spawn_file_actions_destroy(posix_spawn_file_actions_t
*_actions
)
88 struct _posix_spawn_file_actions
* actions
= _actions
!= NULL
? *_actions
: NULL
;
100 posix_spawn_file_actions_addopen(posix_spawn_file_actions_t
*_actions
,
101 int fildes
, const char *path
, int oflag
, mode_t mode
)
103 struct _posix_spawn_file_actions
* actions
= _actions
!= NULL
? *_actions
: NULL
;
108 if (fildes
< 0 || fildes
>= sysconf(_SC_OPEN_MAX
))
111 char* npath
= strdup(path
);
114 if (actions
->count
== actions
->size
115 && posix_spawn_file_actions_extend(actions
) != 0) {
120 struct _file_action
*action
= &actions
->actions
[actions
->count
];
121 action
->type
= file_action_open
;
123 action
->action
.open_action
.path
= npath
;
124 action
->action
.open_action
.oflag
= oflag
;
125 action
->action
.open_action
.mode
= mode
;
132 posix_spawn_file_actions_addclose(posix_spawn_file_actions_t
*_actions
,
135 struct _posix_spawn_file_actions
* actions
= _actions
!= NULL
? *_actions
: NULL
;
140 if (fildes
< 0 || fildes
>= sysconf(_SC_OPEN_MAX
))
143 if (actions
->count
== actions
->size
144 && posix_spawn_file_actions_extend(actions
) != 0) {
148 struct _file_action
*action
= &actions
->actions
[actions
->count
];
149 action
->type
= file_action_close
;
157 posix_spawn_file_actions_adddup2(posix_spawn_file_actions_t
*_actions
,
158 int fildes
, int newfildes
)
160 struct _posix_spawn_file_actions
* actions
= _actions
!= NULL
? *_actions
: NULL
;
165 if (fildes
< 0 || fildes
>= sysconf(_SC_OPEN_MAX
))
168 if (actions
->count
== actions
->size
169 && posix_spawn_file_actions_extend(actions
) != 0) {
173 struct _file_action
*action
= &actions
->actions
[actions
->count
];
174 action
->type
= file_action_dup2
;
175 action
->fd
= newfildes
;
176 action
->action
.dup2_action
.srcfd
= fildes
;
183 posix_spawnattr_init(posix_spawnattr_t
*_attr
)
185 posix_spawnattr_t attr
= (posix_spawnattr_t
)malloc(
186 sizeof(struct _posix_spawnattr
));
191 memset(attr
, 0, sizeof(*attr
));
199 posix_spawnattr_destroy(posix_spawnattr_t
*_attr
)
201 struct _posix_spawnattr
* attr
= _attr
!= NULL
? *_attr
: NULL
;
213 posix_spawnattr_getflags(const posix_spawnattr_t
*_attr
, short *flags
)
215 struct _posix_spawnattr
*attr
;
217 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| flags
== NULL
)
220 *flags
= attr
->flags
;
227 posix_spawnattr_setflags(posix_spawnattr_t
*_attr
, short flags
)
229 struct _posix_spawnattr
*attr
;
231 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
)
234 if ((flags
& ~(POSIX_SPAWN_RESETIDS
| POSIX_SPAWN_SETPGROUP
235 | POSIX_SPAWN_SETSIGDEF
| POSIX_SPAWN_SETSIGMASK
)) != 0) {
246 posix_spawnattr_getpgroup(const posix_spawnattr_t
*_attr
, pid_t
*pgroup
)
248 struct _posix_spawnattr
*attr
;
250 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| pgroup
== NULL
)
253 *pgroup
= attr
->pgroup
;
260 posix_spawnattr_setpgroup(posix_spawnattr_t
*_attr
, pid_t pgroup
)
262 struct _posix_spawnattr
*attr
;
264 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
)
267 attr
->pgroup
= pgroup
;
274 posix_spawnattr_getsigdefault(const posix_spawnattr_t
*_attr
, sigset_t
*sigdefault
)
276 struct _posix_spawnattr
*attr
;
278 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| sigdefault
== NULL
)
281 memcpy(sigdefault
, &attr
->sigdefault
, sizeof(sigset_t
));
288 posix_spawnattr_setsigdefault(posix_spawnattr_t
*_attr
,
289 const sigset_t
*sigdefault
)
291 struct _posix_spawnattr
*attr
;
293 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| sigdefault
== NULL
)
296 memcpy(&attr
->sigdefault
, sigdefault
, sizeof(sigset_t
));
303 posix_spawnattr_getsigmask(const posix_spawnattr_t
*_attr
, sigset_t
*sigmask
)
305 struct _posix_spawnattr
*attr
;
307 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| sigmask
== NULL
)
310 memcpy(sigmask
, &attr
->sigmask
, sizeof(sigset_t
));
317 posix_spawnattr_setsigmask(posix_spawnattr_t
*_attr
, const sigset_t
*sigmask
)
319 struct _posix_spawnattr
*attr
;
321 if (_attr
== NULL
|| (attr
= *_attr
) == NULL
|| sigmask
== NULL
)
324 memcpy(&attr
->sigmask
, sigmask
, sizeof(sigset_t
));
331 process_spawnattr(const posix_spawnattr_t
*_attr
)
336 struct _posix_spawnattr
*attr
= *_attr
;
340 if ((attr
->flags
& POSIX_SPAWN_SETSIGMASK
) != 0)
341 sigprocmask(SIG_SETMASK
, &attr
->sigmask
, NULL
);
343 if ((attr
->flags
& POSIX_SPAWN_SETSIGDEF
) != 0) {
344 struct sigaction action
;
345 action
.sa_handler
= SIG_DFL
;
347 action
.sa_userdata
= NULL
;
348 sigemptyset(&action
.sa_mask
);
349 for (int i
= 1; i
<= MAX_SIGNAL_NUMBER
; i
++) {
350 if (sigismember(&attr
->sigdefault
, i
) == 1
351 && sigaction(i
, &action
, NULL
) != 0) {
357 if ((attr
->flags
& POSIX_SPAWN_RESETIDS
) != 0) {
358 if (setegid(getgid()) != 0)
360 if (seteuid(getuid()) != 0)
364 if ((attr
->flags
& POSIX_SPAWN_SETPGROUP
) != 0) {
365 if (setpgid(0, attr
->pgroup
) != 0)
374 process_file_actions(const posix_spawn_file_actions_t
*_actions
, int *errfd
)
376 if (_actions
== NULL
)
379 struct _posix_spawn_file_actions
* actions
= *_actions
;
383 for (int i
= 0; i
< actions
->count
; i
++) {
384 struct _file_action
*action
= &actions
->actions
[i
];
386 if (action
->fd
== *errfd
) {
387 int newfd
= dup(action
->fd
);
391 fcntl(newfd
, F_SETFD
, FD_CLOEXEC
);
395 if (action
->type
== file_action_close
) {
396 if (close(action
->fd
) != 0)
398 } else if (action
->type
== file_action_open
) {
399 int fd
= open(action
->action
.open_action
.path
,
400 action
->action
.open_action
.oflag
,
401 action
->action
.open_action
.mode
);
404 if (fd
!= action
->fd
) {
405 if (dup2(action
->fd
, fd
) != 0)
410 } else if (action
->type
== file_action_dup2
) {
411 if (dup2(action
->action
.dup2_action
.srcfd
, action
->fd
) != 0)
421 do_posix_spawn(pid_t
*_pid
, const char *path
,
422 const posix_spawn_file_actions_t
*actions
,
423 const posix_spawnattr_t
*attrp
, char *const argv
[], char *const envp
[],
432 if (fcntl(fds
[0], F_SETFD
, FD_CLOEXEC
) != 0
433 || fcntl(fds
[1], F_SETFD
, FD_CLOEXEC
) != 0) {
445 read(fds
[0], &err
, sizeof(err
));
447 waitpid(pid
, NULL
, WNOHANG
);
455 err
= process_spawnattr(attrp
);
457 err
= process_file_actions(actions
, &fds
[1]);
462 execvpe(path
, argv
, envp
!= NULL
? envp
: environ
);
464 execve(path
, argv
, envp
!= NULL
? envp
: environ
);
469 write(fds
[1], &err
, sizeof(err
));
482 posix_spawn(pid_t
*pid
, const char *path
,
483 const posix_spawn_file_actions_t
*file_actions
,
484 const posix_spawnattr_t
*attrp
, char *const argv
[], char *const envp
[])
486 return do_posix_spawn(pid
, path
, file_actions
, attrp
, argv
, envp
, false);
491 posix_spawnp(pid_t
*pid
, const char *file
,
492 const posix_spawn_file_actions_t
*file_actions
,
493 const posix_spawnattr_t
*attrp
, char *const argv
[],
496 return do_posix_spawn(pid
, file
, file_actions
, attrp
, argv
, envp
, true);