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 | 
