aboutsummaryrefslogtreecommitdiff
path: root/sysdeps
diff options
context:
space:
mode:
Diffstat (limited to 'sysdeps')
-rw-r--r--sysdeps/posix/system.c72
1 files changed, 57 insertions, 15 deletions
diff --git a/sysdeps/posix/system.c b/sysdeps/posix/system.c
index 6df7984889..0881a3a431 100644
--- a/sysdeps/posix/system.c
+++ b/sysdeps/posix/system.c
@@ -16,13 +16,14 @@
Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
02111-1307 USA. */
+#include <errno.h>
+#include <signal.h>
#include <stddef.h>
#include <stdlib.h>
#include <unistd.h>
-#include <sys/wait.h>
-#include <signal.h>
#include <sys/types.h>
-#include <errno.h>
+#include <sys/wait.h>
+#include <bits/libc-lock.h>
#ifndef HAVE_GNU_LD
@@ -32,13 +33,36 @@
#define SHELL_PATH "/bin/sh" /* Path of the shell. */
#define SHELL_NAME "sh" /* Name to give it. */
+
+#ifdef _LIBC_REENTRANT
+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
+#else
+# define DO_LOCK()
+# define DO_UNLOCK()
+# define INIT_LOCK()
+# define ADD_REF() (void) 0
+# define SUB_REF() 0
+#endif
+
+
/* 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, intr, quit;
+ struct sigaction sa;
+#ifndef _LIBC_REENTRANT
+ struct sigaction intr, quit;
+#endif
#ifndef WAITPID_CANNOT_BLOCK_SIGCHLD
sigset_t block, omask;
#endif
@@ -47,13 +71,22 @@ do_system (const char *line)
sa.sa_flags = 0;
__sigemptyset (&sa.sa_mask);
- if (__sigaction (SIGINT, &sa, &intr) < 0)
- return -1;
- if (__sigaction (SIGQUIT, &sa, &quit) < 0)
+ DO_LOCK ();
+ if (ADD_REF () == 0)
{
- save = errno;
- goto out_restore_sigint;
+ if (__sigaction (SIGINT, &sa, &intr) < 0)
+ {
+ SUB_REF ();
+ DO_UNLOCK ();
+ return -1;
+ }
+ if (__sigaction (SIGQUIT, &sa, &quit) < 0)
+ {
+ save = errno;
+ goto out_restore_sigint;
+ }
}
+ DO_UNLOCK ();
__sigemptyset (&block);
__sigaddset (&block, SIGCHLD);
@@ -65,9 +98,14 @@ do_system (const char *line)
else
{
save = errno;
- (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
+ DO_LOCK ();
+ if (SUB_REF () == 0)
+ {
+ (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
out_restore_sigint:
- (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+ (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
+ }
+ DO_UNLOCK ();
__set_errno (save);
return -1;
}
@@ -87,6 +125,7 @@ do_system (const char *line)
(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 (SHELL_PATH, (char *const *) new_argv, __environ);
@@ -119,9 +158,11 @@ do_system (const char *line)
}
save = errno;
- if ((__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
- | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)
- | __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL)) != 0)
+ 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)
{
#ifndef _LIBC
/* glibc cannot be used on systems without waitpid. */
@@ -129,8 +170,9 @@ do_system (const char *line)
__set_errno (save);
else
#endif
- return -1;
+ status = -1;
}
+ DO_UNLOCK ();
return status;
}