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
90
91
92
93
94
95
96
97
98
99
100
|
/* Execute LINE as a shell command, returning its status. */
static int
do_system (const char *line)
{
int status = -1;
int ret;
pid_t pid;
struct sigaction sa;
#ifndef _LIBC_REENTRANT
struct sigaction intr, quit;
#endif
sigset_t omask;
sigset_t reset;
sa.sa_handler = SIG_IGN;
sa.sa_flags = 0;
__sigemptyset (&sa.sa_mask);
DO_LOCK ();
if (ADD_REF () == 0)
{
/* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */
__sigaction (SIGINT, &sa, &intr);
__sigaction (SIGQUIT, &sa, &quit);
}
DO_UNLOCK ();
__sigaddset (&sa.sa_mask, SIGCHLD);
/* sigprocmask can not fail with SIG_BLOCK used with valid input
arguments. */
__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask);
__sigemptyset (&reset);
if (intr.sa_handler != SIG_IGN)
__sigaddset(&reset, SIGINT);
if (quit.sa_handler != SIG_IGN)
__sigaddset(&reset, SIGQUIT);
posix_spawnattr_t spawn_attr;
/* None of the posix_spawnattr_* function returns an error, including
posix_spawnattr_setflags for the follow specific usage (using valid
flags). */
__posix_spawnattr_init (&spawn_attr);
__posix_spawnattr_setsigmask (&spawn_attr, &omask);
__posix_spawnattr_setsigdefault (&spawn_attr, &reset);
__posix_spawnattr_setflags (&spawn_attr,
POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr,
(char *const[]){ (char *) SHELL_NAME,
(char *) "-c",
(char *) "--",
(char *) line, NULL },
__environ);
__posix_spawnattr_destroy (&spawn_attr);
if (ret == 0)
{
/* Cancellation results in cleanup handlers running as exceptions in
the block where they were installed, so it is safe to reference
stack variable allocate in the broader scope. */
#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
struct cancel_handler_args cancel_args =
{
.quit = &quit,
.intr = &intr,
.pid = pid
};
__libc_cleanup_region_start (1, cancel_handler, &cancel_args);
#endif
/* Note the system() is a cancellation point. But since we call
waitpid() which itself is a cancellation point we do not
have to do anything here. */
if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
status = -1;
#if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
__libc_cleanup_region_end (0);
#endif
}
else
/* POSIX states that failure to execute the shell should return
as if the shell had terminated using _exit(127). */
status = W_EXITCODE (127, 0);
/* sigaction can not fail with SIGINT/SIGQUIT used with old
disposition. Same applies for sigprocmask. */
DO_LOCK ();
if (SUB_REF () == 0)
{
__sigaction (SIGINT, &intr, NULL);
__sigaction (SIGQUIT, &quit, NULL);
}
DO_UNLOCK ();
__sigprocmask (SIG_SETMASK, &omask, NULL);
if (ret != 0)
__set_errno (ret);
return status;
}
|