bump version to 1.0.28
[uclibc-ng.git] / libc / stdlib / system.c
blob771c30e3fc35849a7c24203ae09d2553a2bb8f8d
1 /*
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.
5 */
7 #include <stdio.h>
8 #include <string.h>
9 #include <stddef.h>
10 #include <signal.h>
11 #include <unistd.h>
12 #include <sys/wait.h>
13 #include <stdlib.h>
14 #include <paths.h>
15 #ifdef __UCLIBC_HAS_THREADS_NATIVE__
16 #include <sched.h>
17 #include <errno.h>
18 #include <bits/libc-lock.h>
19 #include <sysdep-cancel.h>
20 #endif
22 extern __typeof(system) __libc_system;
23 #if !defined __UCLIBC_HAS_THREADS_NATIVE__
24 #include <sys/syscall.h>
26 int __libc_system(const char *command)
28 int wait_val, pid;
29 struct sigaction sa, save_quit, save_int;
30 sigset_t save_mask;
32 if (command == 0)
33 return 1;
35 memset(&sa, 0, sizeof(sa));
36 sa.sa_handler = SIG_IGN;
37 /* __sigemptyset(&sa.sa_mask); - done by memset() */
38 /* sa.sa_flags = 0; - done by memset() */
40 sigaction(SIGQUIT, &sa, &save_quit);
41 sigaction(SIGINT, &sa, &save_int);
42 __sigaddset(&sa.sa_mask, SIGCHLD);
43 sigprocmask(SIG_BLOCK, &sa.sa_mask, &save_mask);
45 if ((pid = vfork()) < 0) {
46 wait_val = -1;
47 goto out;
49 if (pid == 0) {
50 sigaction(SIGQUIT, &save_quit, NULL);
51 sigaction(SIGINT, &save_int, NULL);
52 sigprocmask(SIG_SETMASK, &save_mask, NULL);
54 execl(_PATH_BSHELL, "sh", "-c", command, (char *) 0);
55 _exit(127);
58 #if 0
59 __printf("Waiting for child %d\n", pid);
60 #endif
62 if (__wait4_nocancel(pid, &wait_val, 0, 0) == -1)
63 wait_val = -1;
65 out:
66 sigaction(SIGQUIT, &save_quit, NULL);
67 sigaction(SIGINT, &save_int, NULL);
68 sigprocmask(SIG_SETMASK, &save_mask, NULL);
69 return wait_val;
71 #else
72 /* We have to and actually can handle cancelable system(). The big
73 problem: we have to kill the child process if necessary. To do
74 this a cleanup handler has to be registered and is has to be able
75 to find the PID of the child. The main problem is to reliable have
76 the PID when needed. It is not necessary for the parent thread to
77 return. It might still be in the kernel when the cancellation
78 request comes. Therefore we have to use the clone() calls ability
79 to have the kernel write the PID into the user-level variable. */
81 libc_hidden_proto(sigaction)
82 libc_hidden_proto(waitpid)
84 #if defined __ia64__
85 # define FORK() \
86 INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
87 &pid, NULL, NULL)
88 #elif defined __sparc__
89 # define FORK() \
90 INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
91 #else
92 # define FORK() \
93 INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
94 #endif
96 static void cancel_handler (void *arg);
98 # define CLEANUP_HANDLER \
99 __libc_cleanup_region_start (1, cancel_handler, &pid)
101 # define CLEANUP_RESET \
102 __libc_cleanup_region_end (0)
104 static struct sigaction intr, quit;
105 static int sa_refcntr;
106 __libc_lock_define_initialized (static, lock);
108 # define DO_LOCK() __libc_lock_lock (lock)
109 # define DO_UNLOCK() __libc_lock_unlock (lock)
110 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
111 # define ADD_REF() sa_refcntr++
112 # define SUB_REF() --sa_refcntr
114 /* Execute LINE as a shell command, returning its status. */
115 static int
116 do_system (const char *line)
118 int status, save;
119 pid_t pid;
120 struct sigaction sa;
121 sigset_t omask;
123 memset(&sa, 0, sizeof(sa));
124 sa.sa_handler = SIG_IGN;
125 /*sa.sa_flags = 0; - done by memset */
126 /*__sigemptyset (&sa.sa_mask); - done by memset */
128 DO_LOCK ();
129 if (ADD_REF () == 0)
131 if (sigaction (SIGINT, &sa, &intr) < 0)
133 SUB_REF ();
134 goto out;
136 if (sigaction (SIGQUIT, &sa, &quit) < 0)
138 save = errno;
139 SUB_REF ();
140 goto out_restore_sigint;
143 DO_UNLOCK ();
145 /* We reuse the bitmap in the 'sa' structure. */
146 __sigaddset (&sa.sa_mask, SIGCHLD);
147 save = errno;
148 if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
151 DO_LOCK ();
152 if (SUB_REF () == 0)
154 save = errno;
155 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
156 out_restore_sigint:
157 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
158 __set_errno (save);
160 out:
161 DO_UNLOCK ();
162 return -1;
166 CLEANUP_HANDLER;
168 pid = FORK ();
169 if (pid == (pid_t) 0)
171 /* Child side. */
172 const char *new_argv[4];
173 new_argv[0] = _PATH_BSHELL;
174 new_argv[1] = "-c";
175 new_argv[2] = line;
176 new_argv[3] = NULL;
178 /* Restore the signals. */
179 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
180 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
181 (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
182 INIT_LOCK ();
184 /* Exec the shell. */
185 (void) execve (_PATH_BSHELL, (char *const *) new_argv, __environ);
186 _exit (127);
188 else if (pid < (pid_t) 0)
189 /* The fork failed. */
190 status = -1;
191 else
192 /* Parent side. */
194 /* Note the system() is a cancellation point. But since we call
195 waitpid() which itself is a cancellation point we do not
196 have to do anything here. */
197 if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid)
198 status = -1;
201 CLEANUP_RESET;
203 save = errno;
204 DO_LOCK ();
205 if ((SUB_REF () == 0
206 && (sigaction (SIGINT, &intr, (struct sigaction *) NULL)
207 | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
208 || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
210 status = -1;
212 DO_UNLOCK ();
214 return status;
219 __libc_system (const char *line)
221 if (line == NULL)
222 /* Check that we have a command processor available. It might
223 not be available after a chroot(), for example. */
224 return do_system ("exit 0") == 0;
226 if (SINGLE_THREAD_P)
227 return do_system (line);
229 int oldtype = LIBC_CANCEL_ASYNC ();
231 int result = do_system (line);
233 LIBC_CANCEL_RESET (oldtype);
235 return result;
239 /* The cancellation handler. */
240 static void
241 cancel_handler (void *arg)
243 pid_t child = *(pid_t *) arg;
245 INTERNAL_SYSCALL_DECL (err);
246 INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL);
248 TEMP_FAILURE_RETRY (waitpid (child, NULL, 0));
250 DO_LOCK ();
252 if (SUB_REF () == 0)
254 (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
255 (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL);
258 DO_UNLOCK ();
260 #endif
261 #ifdef IS_IN_libc
262 weak_alias(__libc_system,system)
263 #endif