summaryrefslogtreecommitdiff
path: root/libc/stdlib
diff options
context:
space:
mode:
Diffstat (limited to 'libc/stdlib')
-rw-r--r--libc/stdlib/Makefile.in7
-rw-r--r--libc/stdlib/mkdtemp.c3
-rw-r--r--libc/stdlib/mkstemp.c3
-rw-r--r--libc/stdlib/mkstemp64.c3
-rw-r--r--libc/stdlib/mktemp.c2
-rw-r--r--libc/stdlib/system.c201
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