1 /* Copyright (C) 1991-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
22 #include <sigsetops.h>
25 #include <sys/types.h>
29 #include <libc-lock.h>
30 #include <not-errno.h>
31 #include <not-cancel.h>
32 #include <internal-signals.h>
34 #define SHELL_PATH "/bin/sh" /* Path of the shell. */
35 #define SHELL_NAME "sh" /* Name to give it. */
38 /* This system implementation aims to be thread-safe, which requires to
39 restore the signal dispositions for SIGINT and SIGQUIT correctly and to
40 deal with cancellation by terminating the child process.
42 The signal disposition restoration on the single-thread case is
43 straighfoward. For multithreaded case, a reference-counter with a lock
44 is used, so the first thread will set the SIGINT/SIGQUIT dispositions and
45 last thread will restore them.
47 Cancellation handling is done with thread cancellation clean-up handlers
50 #ifdef _LIBC_REENTRANT
51 static struct sigaction intr
, quit
;
52 static int sa_refcntr
;
53 __libc_lock_define_initialized (static, lock
);
55 # define DO_LOCK() __libc_lock_lock (lock)
56 # define DO_UNLOCK() __libc_lock_unlock (lock)
57 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
58 # define ADD_REF() sa_refcntr++
59 # define SUB_REF() --sa_refcntr
69 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
70 struct cancel_handler_args
72 struct sigaction
*quit
;
73 struct sigaction
*intr
;
78 cancel_handler (void *arg
)
80 struct cancel_handler_args
*args
= (struct cancel_handler_args
*) (arg
);
82 __kill_noerrno (args
->pid
, SIGKILL
);
84 TEMP_FAILURE_RETRY (__waitpid_nocancel (args
->pid
, NULL
, 0));
89 __sigaction (SIGQUIT
, args
->quit
, NULL
);
90 __sigaction (SIGINT
, args
->intr
, NULL
);
96 /* Execute LINE as a shell command, returning its status. */
98 do_system (const char *line
)
103 #ifndef _LIBC_REENTRANT
104 struct sigaction intr
, quit
;
109 sa
.sa_handler
= SIG_IGN
;
111 __sigemptyset (&sa
.sa_mask
);
116 /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */
117 __sigaction (SIGINT
, &sa
, &intr
);
118 __sigaction (SIGQUIT
, &sa
, &quit
);
122 __sigaddset (&sa
.sa_mask
, SIGCHLD
);
123 /* sigprocmask can not fail with SIG_BLOCK used with valid input
125 __sigprocmask (SIG_BLOCK
, &sa
.sa_mask
, &omask
);
127 __sigemptyset (&reset
);
128 if (intr
.sa_handler
!= SIG_IGN
)
129 __sigaddset(&reset
, SIGINT
);
130 if (quit
.sa_handler
!= SIG_IGN
)
131 __sigaddset(&reset
, SIGQUIT
);
133 posix_spawnattr_t spawn_attr
;
134 /* None of the posix_spawnattr_* function returns an error, including
135 posix_spawnattr_setflags for the follow specific usage (using valid
137 __posix_spawnattr_init (&spawn_attr
);
138 __posix_spawnattr_setsigmask (&spawn_attr
, &omask
);
139 __posix_spawnattr_setsigdefault (&spawn_attr
, &reset
);
140 __posix_spawnattr_setflags (&spawn_attr
,
141 POSIX_SPAWN_SETSIGDEF
| POSIX_SPAWN_SETSIGMASK
);
143 status
= __posix_spawn (&pid
, SHELL_PATH
, 0, &spawn_attr
,
144 (char *const[]){ (char*) SHELL_NAME
,
146 (char *) line
, NULL
},
148 __posix_spawnattr_destroy (&spawn_attr
);
152 /* Cancellation results in cleanup handlers running as exceptions in
153 the block where they were installed, so it is safe to reference
154 stack variable allocate in the broader scope. */
155 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
156 struct cancel_handler_args cancel_args
=
162 __libc_cleanup_region_start (1, cancel_handler
, &cancel_args
);
164 /* Note the system() is a cancellation point. But since we call
165 waitpid() which itself is a cancellation point we do not
166 have to do anything here. */
167 if (TEMP_FAILURE_RETRY (__waitpid (pid
, &status
, 0)) != pid
)
169 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
170 __libc_cleanup_region_end (0);
177 /* sigaction can not fail with SIGINT/SIGQUIT used with old
178 disposition. Same applies for sigprocmask. */
179 __sigaction (SIGINT
, &intr
, NULL
);
180 __sigaction (SIGQUIT
, &quit
, NULL
);
181 __sigprocmask (SIG_SETMASK
, &omask
, NULL
);
189 __libc_system (const char *line
)
192 /* Check that we have a command processor available. It might
193 not be available after a chroot(), for example. */
194 return do_system ("exit 0") == 0;
196 return do_system (line
);
198 weak_alias (__libc_system
, system
)