1/* Copyright (C) 1991-2018 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
3
4 The GNU C Library is free software; you can redistribute it and/or
5 modify it under the terms of the GNU Lesser General Public
6 License as published by the Free Software Foundation; either
7 version 2.1 of the License, or (at your option) any later version.
8
9 The GNU C Library is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 Lesser General Public License for more details.
13
14 You should have received a copy of the GNU Lesser General Public
15 License along with the GNU C Library; if not, see
16 <http://www.gnu.org/licenses/>. */
17
18#include <errno.h>
19#include <signal.h>
20#include <stddef.h>
21#include <stdlib.h>
22#include <unistd.h>
23#include <sys/types.h>
24#include <sys/wait.h>
25#include <libc-lock.h>
26#include <sysdep-cancel.h>
27#include <sigsetops.h>
28
29
30#define SHELL_PATH "/bin/sh" /* Path of the shell. */
31#define SHELL_NAME "sh" /* Name to give it. */
32
33
34#ifdef _LIBC_REENTRANT
35static struct sigaction intr, quit;
36static int sa_refcntr;
37__libc_lock_define_initialized (static, lock);
38
39# define DO_LOCK() __libc_lock_lock (lock)
40# define DO_UNLOCK() __libc_lock_unlock (lock)
41# define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
42# define ADD_REF() sa_refcntr++
43# define SUB_REF() --sa_refcntr
44#else
45# define DO_LOCK()
46# define DO_UNLOCK()
47# define INIT_LOCK()
48# define ADD_REF() 0
49# define SUB_REF() 0
50#endif
51
52
53/* Execute LINE as a shell command, returning its status. */
54static int
55do_system (const char *line)
56{
57 int status, save;
58 pid_t pid;
59 struct sigaction sa;
60#ifndef _LIBC_REENTRANT
61 struct sigaction intr, quit;
62#endif
63 sigset_t omask;
64
65 sa.sa_handler = SIG_IGN;
66 sa.sa_flags = 0;
67 __sigemptyset (&sa.sa_mask);
68
69 DO_LOCK ();
70 if (ADD_REF () == 0)
71 {
72 if (__sigaction (SIGINT, &sa, &intr) < 0)
73 {
74 (void) SUB_REF ();
75 goto out;
76 }
77 if (__sigaction (SIGQUIT, &sa, &quit) < 0)
78 {
79 save = errno;
80 (void) SUB_REF ();
81 goto out_restore_sigint;
82 }
83 }
84 DO_UNLOCK ();
85
86 /* We reuse the bitmap in the 'sa' structure. */
87 __sigaddset (&sa.sa_mask, SIGCHLD);
88 save = errno;
89 if (__sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask) < 0)
90 {
91#ifndef _LIBC
92 if (errno == ENOSYS)
93 __set_errno (save);
94 else
95#endif
96 {
97 DO_LOCK ();
98 if (SUB_REF () == 0)
99 {
100 save = errno;
101 (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
102 out_restore_sigint:
103 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
104 __set_errno (save);
105 }
106 out:
107 DO_UNLOCK ();
108 return -1;
109 }
110 }
111
112#ifdef CLEANUP_HANDLER
113 CLEANUP_HANDLER;
114#endif
115
116#ifdef FORK
117 pid = FORK ();
118#else
119 pid = __fork ();
120#endif
121 if (pid == (pid_t) 0)
122 {
123 /* Child side. */
124 const char *new_argv[4];
125 new_argv[0] = SHELL_NAME;
126 new_argv[1] = "-c";
127 new_argv[2] = line;
128 new_argv[3] = NULL;
129
130 /* Restore the signals. */
131 (void) __sigaction (SIGINT, &intr, (struct sigaction *) NULL);
132 (void) __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL);
133 (void) __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL);
134 INIT_LOCK ();
135
136 /* Exec the shell. */
137 (void) __execve (SHELL_PATH, (char *const *) new_argv, __environ);
138 _exit (127);
139 }
140 else if (pid < (pid_t) 0)
141 /* The fork failed. */
142 status = -1;
143 else
144 /* Parent side. */
145 {
146 /* Note the system() is a cancellation point. But since we call
147 waitpid() which itself is a cancellation point we do not
148 have to do anything here. */
149 if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
150 status = -1;
151 }
152
153#ifdef CLEANUP_HANDLER
154 CLEANUP_RESET;
155#endif
156
157 save = errno;
158 DO_LOCK ();
159 if ((SUB_REF () == 0
160 && (__sigaction (SIGINT, &intr, (struct sigaction *) NULL)
161 | __sigaction (SIGQUIT, &quit, (struct sigaction *) NULL)) != 0)
162 || __sigprocmask (SIG_SETMASK, &omask, (sigset_t *) NULL) != 0)
163 {
164#ifndef _LIBC
165 /* glibc cannot be used on systems without waitpid. */
166 if (errno == ENOSYS)
167 __set_errno (save);
168 else
169#endif
170 status = -1;
171 }
172 DO_UNLOCK ();
173
174 return status;
175}
176
177int
178__libc_system (const char *line)
179{
180 if (line == NULL)
181 /* Check that we have a command processor available. It might
182 not be available after a chroot(), for example. */
183 return do_system ("exit 0") == 0;
184
185 return do_system (line);
186}
187weak_alias (__libc_system, system)
188