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.
15 #ifdef __UCLIBC_HAS_THREADS_NATIVE__
18 #include <bits/libc-lock.h>
19 #include <sysdep-cancel.h>
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
)
29 struct sigaction sa
, save_quit
, save_int
;
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) {
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);
59 __printf("Waiting for child %d\n", pid
);
62 if (__wait4_nocancel(pid
, &wait_val
, 0, 0) == -1)
66 sigaction(SIGQUIT
, &save_quit
, NULL
);
67 sigaction(SIGINT
, &save_int
, NULL
);
68 sigprocmask(SIG_SETMASK
, &save_mask
, NULL
);
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
)
86 INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \
88 #elif defined __sparc__
90 INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL)
93 INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid)
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. */
116 do_system (const char *line
)
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 */
131 if (sigaction (SIGINT
, &sa
, &intr
) < 0)
136 if (sigaction (SIGQUIT
, &sa
, &quit
) < 0)
140 goto out_restore_sigint
;
145 /* We reuse the bitmap in the 'sa' structure. */
146 __sigaddset (&sa
.sa_mask
, SIGCHLD
);
148 if (sigprocmask (SIG_BLOCK
, &sa
.sa_mask
, &omask
) < 0)
155 (void) sigaction (SIGQUIT
, &quit
, (struct sigaction
*) NULL
);
157 (void) sigaction (SIGINT
, &intr
, (struct sigaction
*) NULL
);
169 if (pid
== (pid_t
) 0)
172 const char *new_argv
[4];
173 new_argv
[0] = _PATH_BSHELL
;
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
);
184 /* Exec the shell. */
185 (void) execve (_PATH_BSHELL
, (char *const *) new_argv
, __environ
);
188 else if (pid
< (pid_t
) 0)
189 /* The fork failed. */
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
)
206 && (sigaction (SIGINT
, &intr
, (struct sigaction
*) NULL
)
207 | sigaction (SIGQUIT
, &quit
, (struct sigaction
*) NULL
)) != 0)
208 || sigprocmask (SIG_SETMASK
, &omask
, (sigset_t
*) NULL
) != 0)
219 __libc_system (const char *line
)
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;
227 return do_system (line
);
229 int oldtype
= LIBC_CANCEL_ASYNC ();
231 int result
= do_system (line
);
233 LIBC_CANCEL_RESET (oldtype
);
239 /* The cancellation handler. */
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));
254 (void) sigaction (SIGQUIT
, &quit
, (struct sigaction
*) NULL
);
255 (void) sigaction (SIGINT
, &intr
, (struct sigaction
*) NULL
);
262 weak_alias(__libc_system
,system
)