1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
|
/* See LICENSE file for copyright and license details. */
#include "common.h"
#ifndef TEST
int
libexec_spawn(pid_t *out, struct libexec_command *cmd,
int (*after_fork)(struct libexec_command *cmd, int new_fd, void *user),
void *user, struct libexec_document **docsp, size_t *ndocsp, int doc_fd_flags)
{
int fds[2], error, new_fd;
size_t i;
ssize_t r;
if (!docsp || !ndocsp || !out || !cmd) {
errno = EINVAL;
return -1;
}
*out = -1;
if (pipe2(fds, O_CLOEXEC))
return -1;
new_fd = fds[1];
for (i = 0; i < cmd->nplumings; i++)
if (cmd->plumings[i].fd >= new_fd)
new_fd = cmd->plumings[i].fd + 1;
if (new_fd != fds[1]) {
new_fd = fcntl(fds[1], F_DUPFD_CLOEXEC, new_fd);
if (new_fd == -1)
goto fail;
fds[1] = new_fd;
}
if (libexec_get_documents(cmd, docsp, ndocsp, doc_fd_flags))
goto fail;
*out = fork();
switch (*out) {
case -1:
goto fail;
case 0:
close(fds[0]);
if (after_fork)
if ((*after_fork)(cmd, fds[1], user))
goto child_fail;
libexec_exec(cmd);
child_fail:
error = errno;
write_again:
r = write(fds[1], &error, sizeof(error));
if (r <= 0) {
if (errno == EINTR)
goto write_again;
abort();
}
_exit(1);
default:
close(fds[1]);
read_again:
r = read(fds[0], &error, sizeof(error));
if (r < 0) {
if (errno == EINTR)
goto read_again;
} else if (r == 0) {
return 0;
} else if ((size_t)r >= sizeof(error)) {
errno = error;
}
return -1;
}
fail:
error = errno;
close(fds[0]);
close(fds[1]);
errno = error;
return -1;
}
#else
LIBEXEC_CONST__ int main(void) {return 0;} /* TODO test */
#endif
|