2 * Copyright (C) 2000-2006 Erik Andersen <andersen@uclibc.org>
4 * Licensed under the LGPL v2.1, see the file COPYING.LIB in this tarball.
14 #ifdef __UCLIBC_HAS_THREADS_NATIVE__
17 #include <bits/libc-lock.h>
18 #include <sysdep-cancel.h>
21 extern __typeof(system) __libc_system;
23 /* TODO: the cancellable version breaks on sparc currently,
24 * need to figure out why still
26 #if !defined __UCLIBC_HAS_THREADS_NATIVE__ || defined __sparc__
28 int __libc_system(const char *command)
31 struct sigaction sa, save_quit, save_int;
37 memset(&sa, 0, sizeof(sa));
38 sa.sa_handler = SIG_IGN;
39 /* __sigemptyset(&sa.sa_mask); - done by memset() */
40 /* sa.sa_flags = 0; - done by memset() */
42 sigaction(SIGQUIT, &sa, &save_quit);
43 sigaction(SIGINT, &sa, &save_int);
44 __sigaddset(&sa.sa_mask, SIGCHLD);
45 sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask);
47 if ((pid = vfork()) < 0) {
52 sigaction(SIGQUIT, &save_quit, NULL);
53 sigaction(SIGINT, &save_int, NULL);
54 sigprocmask(SIG_SETMASK, &save_mask, NULL);
56 execl("/bin/sh", "sh", "-c", command, (char *) 0);
61 __printf("Waiting for child %d\n", pid);
64 if (__wait4_nocancel(pid, &wait_val, 0, 0) == -1)
68 sigaction(SIGQUIT, &save_quit, NULL);
69 sigaction(SIGINT, &save_int, NULL);
70 sigprocmask(SIG_SETMASK, &save_mask, NULL);
74 /* We have to and actually can handle cancelable system(). The big
75 problem: we have to kill the child process if necessary. To do
76 this a cleanup handler has to be registered and is has to be able
77 to find the PID of the child. The main problem is to reliable have
78 the PID when needed. It is not necessary for the parent thread to
79 return. It might still be in the kernel when the cancellation
80 request comes. Therefore we have to use the clone() calls ability
81 to have the kernel write the PID into the user-level variable. */
83 libc_hidden_proto(sigaction)
84 libc_hidden_proto(waitpid)
88 INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
90 #elif defined __sparc__
92 INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
93 #elif defined __s390__
95 INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
98 INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
101 static void cancel_handler (void *arg);
103 # define CLEANUP_HANDLER \
104 __libc_cleanup_region_start (1, cancel_handler, &pid)
106 # define CLEANUP_RESET \
107 __libc_cleanup_region_end (0)
109 static struct sigaction intr, quit;
110 static int sa_refcntr;
111 __libc_lock_define_initialized (static, lock);
113 # define DO_LOCK() __libc_lock_lock (lock)
114 # define DO_UNLOCK() __libc_lock_unlock (lock)
115 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
116 # define ADD_REF() sa_refcntr++
117 # define SUB_REF() --sa_refcntr
119 /* Execute LINE as a shell command, returning its status. */
121 do_system (const char *line)
128 memset(&sa, 0, sizeof(sa));
129 sa.sa_handler = SIG_IGN;
130 /*sa.sa_flags = 0; - done by memset */
131 /*__sigemptyset (&sa.sa_mask); - done by memset */
136 if (sigaction (SIGINT, &sa, &intr) < 0)
141 if (sigaction (SIGQUIT, &sa, &quit) < 0)
145 goto out_restore_sigint;
150 /* We reuse the bitmap in the 'sa' structure. */
151 __sigaddset (&sa.sa_mask, SIGCHLD);
153 if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
160 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
162 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
174 if (pid == (pid_t) 0)
177 const char *new_argv[4];
178 new_argv[0] = "/bin/sh";
183 /* Restore the signals. */
184 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
185 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
186 (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
189 /* Exec the shell. */
190 (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
193 else if (pid < (pid_t) 0)
194 /* The fork failed. */
199 /* Note the system() is a cancellation point. But since we call
200 waitpid() which itself is a cancellation point we do not
201 have to do anything here. */
202 if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
211 && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
212 | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
213 || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
224 __libc_system (const char *line)
227 /* Check that we have a command processor available. It might
228 not be available after a chroot(), for example. */
229 return do_system ("exit 0") == 0;
232 return do_system (line);
234 int oldtype = LIBC_CANCEL_ASYNC ();
236 int result = do_system (line);
238 LIBC_CANCEL_RESET (oldtype);
244 /* The cancellation handler. */
246 cancel_handler (void *arg)
248 pid_t child = *(pid_t *) arg;
250 INTERNAL_SYSCALL_DECL (err);
251 INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
253 TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
259 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
260 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
267 weak_alias(__libc_system,system)