diff options
Diffstat (limited to 'libc/stdlib')
-rw-r--r-- | libc/stdlib/Makefile.in | 7 | ||||
-rw-r--r-- | libc/stdlib/mkdtemp.c | 3 | ||||
-rw-r--r-- | libc/stdlib/mkstemp.c | 3 | ||||
-rw-r--r-- | libc/stdlib/mkstemp64.c | 3 | ||||
-rw-r--r-- | libc/stdlib/mktemp.c | 2 | ||||
-rw-r--r-- | libc/stdlib/system.c | 201 |
6 files changed, 212 insertions, 7 deletions
diff --git a/libc/stdlib/Makefile.in b/libc/stdlib/Makefile.in index 48ee5f227..af8be6451 100644 --- a/libc/stdlib/Makefile.in +++ b/libc/stdlib/Makefile.in @@ -13,7 +13,7 @@ include $(top_srcdir)libc/stdlib/malloc-standard/Makefile.in CSRC := \ abort.c getenv.c mkdtemp.c realpath.c mkstemp.c \ - rand.c random.c random_r.c setenv.c system.c div.c ldiv.c lldiv.c \ + rand.c random.c random_r.c setenv.c div.c ldiv.c lldiv.c \ getpt.c drand48-iter.c jrand48.c \ jrand48_r.c lrand48.c lrand48_r.c mrand48.c mrand48_r.c nrand48.c \ nrand48_r.c rand_r.c srand48.c srand48_r.c seed48.c seed48_r.c \ @@ -40,7 +40,6 @@ ifeq ($(UCLIBC_SUSV3_LEGACY),y) CSRC += mktemp.c endif - # multi source stdlib.c CSRC += abs.c labs.c atoi.c atol.c strtol.c strtoul.c _stdlib_strto_l.c \ qsort.c bsearch.c \ @@ -92,7 +91,9 @@ STDLIB_SRC := $(patsubst %.c,$(STDLIB_DIR)/%.c,$(CSRC)) STDLIB_OBJ := $(patsubst %.c,$(STDLIB_OUT)/%.o,$(CSRC)) libc-y += $(STDLIB_OBJ) -libc-static-y += $(STDLIB_OUT)/atexit.o +libc-static-y += $(STDLIB_OUT)/atexit.o $(STDLIB_OUT)/system.o +libc-shared-y += $(STDLIB_OUT)/system.oS + # this should always be the PIC version, because it could be used in shared libs libc-nonshared-y += $(STDLIB_OUT)/atexit.os diff --git a/libc/stdlib/mkdtemp.c b/libc/stdlib/mkdtemp.c index fa9ae3b05..2bf15ae06 100644 --- a/libc/stdlib/mkdtemp.c +++ b/libc/stdlib/mkdtemp.c @@ -19,6 +19,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" #ifdef __USE_BSD @@ -29,7 +30,7 @@ (This function comes from OpenBSD.) */ char * mkdtemp (char *template) { - if (__gen_tempname (template, __GT_DIR)) + if (__gen_tempname (template, __GT_DIR, S_IRUSR | S_IWUSR | S_IXUSR)) return NULL; else return template; diff --git a/libc/stdlib/mkstemp.c b/libc/stdlib/mkstemp.c index c569ceaf5..ce7d7dba0 100644 --- a/libc/stdlib/mkstemp.c +++ b/libc/stdlib/mkstemp.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@ Then open the file and return a fd. */ int mkstemp (char *template) { - return __gen_tempname (template, __GT_FILE); + return __gen_tempname (template, __GT_FILE, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mkstemp64.c b/libc/stdlib/mkstemp64.c index 02a03f00e..2cdee70a2 100644 --- a/libc/stdlib/mkstemp64.c +++ b/libc/stdlib/mkstemp64.c @@ -18,6 +18,7 @@ #include <stdio.h> #include <stdlib.h> +#include <sys/stat.h> #include "../misc/internals/tempname.h" /* Generate a unique temporary file name from TEMPLATE. @@ -26,5 +27,5 @@ Then open the file and return a fd. */ int mkstemp64 (char *template) { - return __gen_tempname (template, __GT_BIGFILE); + return __gen_tempname (template, __GT_BIGFILE, S_IRUSR | S_IWUSR); } diff --git a/libc/stdlib/mktemp.c b/libc/stdlib/mktemp.c index f3af1c15c..3c922e328 100644 --- a/libc/stdlib/mktemp.c +++ b/libc/stdlib/mktemp.c @@ -25,7 +25,7 @@ * they are replaced with a string that makes the filename unique. */ char *mktemp(char *template) { - if (__gen_tempname (template, __GT_NOCREATE) < 0) + if (__gen_tempname (template, __GT_NOCREATE, 0) < 0) /* We return the null string if we can't find a unique file name. */ template[0] = '\0'; diff --git a/libc/stdlib/system.c b/libc/stdlib/system.c index 99f7970c8..7026a8d20 100644 --- a/libc/stdlib/system.c +++ b/libc/stdlib/system.c @@ -10,8 +10,15 @@ #include <unistd.h> #include <sys/wait.h> #include <stdlib.h> +#ifdef __UCLIBC_HAS_THREADS_NATIVE__ +#include <sched.h> +#include <errno.h> +#include <bits/libc-lock.h> +#include <sysdep-cancel.h> +#endif +#if !defined __UCLIBC_HAS_THREADS_NATIVE__ /* uClinux-2.0 has vfork, but Linux 2.0 doesn't */ #include <sys/syscall.h> #ifndef __NR_vfork @@ -61,4 +68,198 @@ int __libc_system(const char *command) signal(SIGCHLD, save_chld); return wait_val; } +#else +/* We have to and actually can handle cancelable system(). The big + problem: we have to kill the child process if necessary. To do + this a cleanup handler has to be registered and is has to be able + to find the PID of the child. The main problem is to reliable have + the PID when needed. It is not necessary for the parent thread to + return. It might still be in the kernel when the cancellation + request comes. Therefore we have to use the clone() calls ability + to have the kernel write the PID into the user-level variable. */ + +libc_hidden_proto(sigaction) +libc_hidden_proto(waitpid) + +#if defined __ia64__ +# define FORK() \ + INLINE_SYSCALL (clone2, 6, CLONE_PARENT_SETTID | SIGCHLD, NULL, 0, \ + &pid, NULL, NULL) +#elif defined __sparc__ +# define FORK() \ + INLINE_CLONE_SYSCALL (CLONE_PARENT_SETTID | SIGCHLD, 0, &pid, NULL, NULL) +#elif defined __s390__ +# define FORK() \ + INLINE_SYSCALL (clone, 3, 0, CLONE_PARENT_SETTID | SIGCHLD, &pid) +#else +# define FORK() \ + INLINE_SYSCALL (clone, 3, CLONE_PARENT_SETTID | SIGCHLD, 0, &pid) +#endif + +static void cancel_handler (void *arg); + +# define CLEANUP_HANDLER \ + __libc_cleanup_region_start (1, cancel_handler, &pid) + +# define CLEANUP_RESET \ + __libc_cleanup_region_end (0) + +static struct sigaction intr, quit; +static int sa_refcntr; +__libc_lock_define_initialized (static, lock); + +# define DO_LOCK() __libc_lock_lock (lock) +# define DO_UNLOCK() __libc_lock_unlock (lock) +# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; }) +# define ADD_REF() sa_refcntr++ +# define SUB_REF() --sa_refcntr + +/* Execute LINE as a shell command, returning its status. */ +static int +do_system (const char *line) +{ + int status, save; + pid_t pid; + struct sigaction sa; + sigset_t omask; + + sa.sa_handler = SIG_IGN; + sa.sa_flags = 0; + __sigemptyset (&sa.sa_mask); + + DO_LOCK (); + if (ADD_REF () == 0) + { + if (sigaction (SIGINT, &sa, &intr) < 0) + { + SUB_REF (); + goto out; + } + if (sigaction (SIGQUIT, &sa, &quit) < 0) + { + save = errno; + SUB_REF (); + goto out_restore_sigint; + } + } + DO_UNLOCK (); + + /* We reuse the bitmap in the 'sa' structure. */ + __sigaddset (&sa.sa_mask, SIGCHLD); + save = errno; + if (sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0) + { + { + DO_LOCK (); + if (SUB_REF () == 0) + { + save = errno; + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + out_restore_sigint: + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + __set_errno (save); + } + out: + DO_UNLOCK (); + return -1; + } + } + + CLEANUP_HANDLER; + + pid = FORK (); + if (pid == (pid_t) 0) + { + /* Child side. */ + const char *new_argv[4]; + new_argv[0] = "/bin/sh"; + new_argv[1] = "-c"; + new_argv[2] = line; + new_argv[3] = NULL; + + /* Restore the signals. */ + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL); + INIT_LOCK (); + + /* Exec the shell. */ + (void) execve ("/bin/sh", (char *const *) new_argv, __environ); + _exit (127); + } + else if (pid < (pid_t) 0) + /* The fork failed. */ + status = -1; + else + /* Parent side. */ + { + /* Note the system() is a cancellation point. But since we call + waitpid() which itself is a cancellation point we do not + have to do anything here. */ + if (TEMP_FAILURE_RETRY (waitpid (pid, &status, 0)) != pid) + status = -1; + } + + CLEANUP_RESET; + + save = errno; + DO_LOCK (); + if ((SUB_REF () == 0 + && (sigaction (SIGINT, &intr, (struct sigaction *) NULL) + | sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0) + || sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0) + { + status = -1; + } + DO_UNLOCK (); + + return status; +} + + +int +__libc_system (const char *line) +{ + if (line == NULL) + /* Check that we have a command processor available. It might + not be available after a chroot(), for example. */ + return do_system ("exit 0") == 0; + + if (SINGLE_THREAD_P) + return do_system (line); + + int oldtype = LIBC_CANCEL_ASYNC (); + + int result = do_system (line); + + LIBC_CANCEL_RESET (oldtype); + + return result; +} + + +/* The cancellation handler. */ +static void +cancel_handler (void *arg) +{ + pid_t child = *(pid_t *) arg; + + INTERNAL_SYSCALL_DECL (err); + INTERNAL_SYSCALL (kill, err, 2, child, SIGKILL); + + TEMP_FAILURE_RETRY (waitpid (child, NULL, 0)); + + DO_LOCK (); + + if (SUB_REF () == 0) + { + (void) sigaction (SIGQUIT, &quit, (struct sigaction *) NULL); + (void) sigaction (SIGINT, &intr, (struct sigaction *) NULL); + } + + DO_UNLOCK (); +} +#endif +#ifdef IS_IN_libc weak_alias(__libc_system,system) +#endif |