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__
27 /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */
28 #include <sys/syscall.h>
33 int __libc_system(const char *command)
36 __sighandler_t save_quit, save_int, save_chld;
41 save_quit = signal(SIGQUIT, SIG_IGN);
42 save_int = signal(SIGINT, SIG_IGN);
43 save_chld = signal(SIGCHLD, SIG_DFL);
45 if ((pid = vfork()) < 0) {
46 signal(SIGQUIT, save_quit);
47 signal(SIGINT, save_int);
48 signal(SIGCHLD, save_chld);
52 signal(SIGQUIT, SIG_DFL);
53 signal(SIGINT, SIG_DFL);
54 signal(SIGCHLD, SIG_DFL);
56 execl("/bin/sh", "sh", "-c", command, (char *) 0);
59 /* Signals are not absolutly guarenteed with vfork */
60 signal(SIGQUIT, SIG_IGN);
61 signal(SIGINT, SIG_IGN);
64 __printf("Waiting for child %d\n", pid);
67 if (wait4(pid, &wait_val, 0, 0) == -1)
70 signal(SIGQUIT, save_quit);
71 signal(SIGINT, save_int);
72 signal(SIGCHLD, save_chld);
76 /* We have to and actually can handle cancelable system(). The big
77 problem: we have to kill the child process if necessary. To do
78 this a cleanup handler has to be registered and is has to be able
79 to find the PID of the child. The main problem is to reliable have
80 the PID when needed. It is not necessary for the parent thread to
81 return. It might still be in the kernel when the cancellation
82 request comes. Therefore we have to use the clone() calls ability
83 to have the kernel write the PID into the user-level variable. */
85 libc_hidden_proto(sigaction)
86 libc_hidden_proto(waitpid)
90 INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
92 #elif defined __sparc__
94 INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
95 #elif defined __s390__
97 INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid)
100 INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
103 static void cancel_handler (void *arg);
105 # define CLEANUP_HANDLER \
106 __libc_cleanup_region_start (1, cancel_handler, &pid)
108 # define CLEANUP_RESET \
109 __libc_cleanup_region_end (0)
111 static struct sigaction intr, quit;
112 static int sa_refcntr;
113 __libc_lock_define_initialized (static, lock);
115 # define DO_LOCK() __libc_lock_lock (lock)
116 # define DO_UNLOCK() __libc_lock_unlock (lock)
117 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
118 # define ADD_REF() sa_refcntr++
119 # define SUB_REF() --sa_refcntr
121 /* Execute LINE as a shell command, returning its status. */
123 do_system (const char *line)
130 memset(&sa, 0, sizeof(sa));
131 sa.sa_handler = SIG_IGN;
132 /*sa.sa_flags = 0; - done by memset */
133 /*__sigemptyset (&sa.sa_mask); - done by memset */
138 if (sigaction (SIGINT, &sa, &intr) < 0)
143 if (sigaction (SIGQUIT, &sa, &quit) < 0)
147 goto out_restore_sigint;
152 /* We reuse the bitmap in the 'sa' structure. */
153 __sigaddset (&sa.sa_mask, SIGCHLD);
155 if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
162 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
164 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
176 if (pid == (pid_t) 0)
179 const char *new_argv[4];
180 new_argv[0] = "/bin/sh";
185 /* Restore the signals. */
186 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
187 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
188 (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
191 /* Exec the shell. */
192 (void) execve ("/bin/sh", (char *const *) new_argv, __environ);
195 else if (pid < (pid_t) 0)
196 /* The fork failed. */
201 /* Note the system() is a cancellation point. But since we call
202 waitpid() which itself is a cancellation point we do not
203 have to do anything here. */
204 if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
213 && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
214 | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
215 || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
226 __libc_system (const char *line)
229 /* Check that we have a command processor available. It might
230 not be available after a chroot(), for example. */
231 return do_system ("exit 0") == 0;
234 return do_system (line);
236 int oldtype = LIBC_CANCEL_ASYNC ();
238 int result = do_system (line);
240 LIBC_CANCEL_RESET (oldtype);
246 /* The cancellation handler. */
248 cancel_handler (void *arg)
250 pid_t child = *(pid_t *) arg;
252 INTERNAL_SYSCALL_DECL (err);
253 INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
255 TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
261 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
262 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
269 weak_alias(__libc_system,system)