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;
22 #if !defined __UCLIBC_HAS_THREADS_NATIVE__
23 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
24 #include <sys/syscall.h>
29 int __libc_system(const char *command)
32 struct sigaction sa, save_quit, save_int;
38 memset(&sa, 0, sizeof(sa));
39 sa.sa_handler = SIG_IGN;
40 /* __sigemptyset(&sa.sa_mask); - done by memset() */
41 /* sa.sa_flags = 0; - done by memset() */
43 sigaction(SIGQUIT, &sa, &save_quit);
44 sigaction(SIGINT, &sa, &save_int);
45 __sigaddset(&sa.sa_mask, SIGCHLD);
46 sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask);
48 if ((pid = vfork()) < 0) {
53 sigaction(SIGQUIT, &save_quit, NULL);
54 sigaction(SIGINT, &save_int, NULL);
55 sigprocmask(SIG_SETMASK, &save_mask, NULL);
57 execl("/bin/sh", "sh", "-c", command, (char *) 0);
62 __printf("Waiting for child %d\n", pid);
65 if (__wait4_nocancel(pid, &wait_val, 0, 0) == -1)
69 sigaction(SIGQUIT, &save_quit, NULL);
70 sigaction(SIGINT, &save_int, NULL);
71 sigprocmask(SIG_SETMASK, &save_mask, NULL);
75 /* We have to and actually can handle cancelable system(). The big
76 problem: we have to kill the child process if necessary. To do
77 this a cleanup handler has to be registered and is has to be able
78 to find the PID of the child. The main problem is to reliable have
79 the PID when needed. It is not necessary for the parent thread to
80 return. It might still be in the kernel when the cancellation
81 request comes. Therefore we have to use the clone() calls ability
82 to have the kernel write the PID into the user-level variable. */
84 libc_hidden_proto(sigaction)
85 libc_hidden_proto(waitpid)
89 INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
91 #elif defined __sparc__
93 INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
94 #elif defined __s390__
96 INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
99 INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
102 static void cancel_handler (void *arg);
104 # define CLEANUP_HANDLER \
105 __libc_cleanup_region_start (1, cancel_handler, &pid)
107 # define CLEANUP_RESET \
108 __libc_cleanup_region_end (0)
110 static struct sigaction intr, quit;
111 static int sa_refcntr;
112 __libc_lock_define_initialized (static, lock);
114 # define DO_LOCK() __libc_lock_lock (lock)
115 # define DO_UNLOCK() __libc_lock_unlock (lock)
116 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
117 # define ADD_REF() sa_refcntr++
118 # define SUB_REF() --sa_refcntr
120 /* Execute LINE as a shell command, returning its status. */
122 do_system (const char *line)
129 memset(&sa, 0, sizeof(sa));
130 sa.sa_handler = SIG_IGN;
131 /*sa.sa_flags = 0; - done by memset */
132 /*__sigemptyset (&sa.sa_mask); - done by memset */
137 if (sigaction (SIGINT, &sa, &intr) < 0)
142 if (sigaction (SIGQUIT, &sa, &quit) < 0)
146 goto out_restore_sigint;
151 /* We reuse the bitmap in the 'sa' structure. */
152 __sigaddset (&sa.sa_mask, SIGCHLD);
154 if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
161 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
163 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
175 if (pid == (pid_t) 0)
178 const char *new_argv[4];
179 new_argv[0] = "/bin/sh";
184 /* Restore the signals. */
185 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
186 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
187 (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
190 /* Exec the shell. */
191 (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
194 else if (pid < (pid_t) 0)
195 /* The fork failed. */
200 /* Note the system() is a cancellation point. But since we call
201 waitpid() which itself is a cancellation point we do not
202 have to do anything here. */
203 if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
212 && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
213 | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
214 || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
225 __libc_system (const char *line)
228 /* Check that we have a command processor available. It might
229 not be available after a chroot(), for example. */
230 return do_system ("exit 0") == 0;
233 return do_system (line);
235 int oldtype = LIBC_CANCEL_ASYNC ();
237 int result = do_system (line);
239 LIBC_CANCEL_RESET (oldtype);
245 /* The cancellation handler. */
247 cancel_handler (void *arg)
249 pid_t child = *(pid_t *) arg;
251 INTERNAL_SYSCALL_DECL (err);
252 INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
254 TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
260 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
261 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
268 weak_alias(__libc_system,system)