Fix strtod multiple-precision division bug (bug 26137).
[glibc.git] / sysdeps / posix / system.c
bloba03f478fc74672ee05d05405403b4075c498fadf
1 /* Copyright (C) 1991-2020 Free Software Foundation, Inc.
2 This file is part of the GNU C Library.
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.
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.
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 <https://www.gnu.org/licenses/>. */
18 #include <errno.h>
19 #include <signal.h>
20 #include <stdlib.h>
21 #include <unistd.h>
22 #include <sigsetops.h>
23 #include <spawn.h>
24 #include <pthread.h>
25 #include <sys/types.h>
26 #include <sys/wait.h>
27 #include <stdio.h>
29 #include <libc-lock.h>
30 #include <not-errno.h>
31 #include <not-cancel.h>
32 #include <internal-signals.h>
34 #define SHELL_PATH "/bin/sh" /* Path of the shell. */
35 #define SHELL_NAME "sh" /* Name to give it. */
38 /* This system implementation aims to be thread-safe, which requires to
39 restore the signal dispositions for SIGINT and SIGQUIT correctly and to
40 deal with cancellation by terminating the child process.
42 The signal disposition restoration on the single-thread case is
43 straighfoward. For multithreaded case, a reference-counter with a lock
44 is used, so the first thread will set the SIGINT/SIGQUIT dispositions and
45 last thread will restore them.
47 Cancellation handling is done with thread cancellation clean-up handlers
48 on waitpid call. */
50 #ifdef _LIBC_REENTRANT
51 static struct sigaction intr, quit;
52 static int sa_refcntr;
53 __libc_lock_define_initialized (static, lock);
55 # define DO_LOCK() __libc_lock_lock (lock)
56 # define DO_UNLOCK() __libc_lock_unlock (lock)
57 # define INIT_LOCK() ({ __libc_lock_init (lock); sa_refcntr = 0; })
58 # define ADD_REF() sa_refcntr++
59 # define SUB_REF() --sa_refcntr
60 #else
61 # define DO_LOCK()
62 # define DO_UNLOCK()
63 # define INIT_LOCK()
64 # define ADD_REF() 0
65 # define SUB_REF() 0
66 #endif
69 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
70 struct cancel_handler_args
72 struct sigaction *quit;
73 struct sigaction *intr;
74 pid_t pid;
77 static void
78 cancel_handler (void *arg)
80 struct cancel_handler_args *args = (struct cancel_handler_args *) (arg);
82 __kill_noerrno (args->pid, SIGKILL);
84 int state;
85 __libc_ptf_call (__pthread_setcancelstate,
86 (PTHREAD_CANCEL_DISABLE, &state), 0);
87 TEMP_FAILURE_RETRY (__waitpid (args->pid, NULL, 0));
88 __libc_ptf_call (__pthread_setcancelstate, (state, NULL), 0);
90 DO_LOCK ();
91 if (SUB_REF () == 0)
93 __sigaction (SIGQUIT, args->quit, NULL);
94 __sigaction (SIGINT, args->intr, NULL);
96 DO_UNLOCK ();
98 #endif
100 /* Execute LINE as a shell command, returning its status. */
101 static int
102 do_system (const char *line)
104 int status = -1;
105 int ret;
106 pid_t pid;
107 struct sigaction sa;
108 #ifndef _LIBC_REENTRANT
109 struct sigaction intr, quit;
110 #endif
111 sigset_t omask;
112 sigset_t reset;
114 sa.sa_handler = SIG_IGN;
115 sa.sa_flags = 0;
116 __sigemptyset (&sa.sa_mask);
118 DO_LOCK ();
119 if (ADD_REF () == 0)
121 /* sigaction can not fail with SIGINT/SIGQUIT used with SIG_IGN. */
122 __sigaction (SIGINT, &sa, &intr);
123 __sigaction (SIGQUIT, &sa, &quit);
125 DO_UNLOCK ();
127 __sigaddset (&sa.sa_mask, SIGCHLD);
128 /* sigprocmask can not fail with SIG_BLOCK used with valid input
129 arguments. */
130 __sigprocmask (SIG_BLOCK, &sa.sa_mask, &omask);
132 __sigemptyset (&reset);
133 if (intr.sa_handler != SIG_IGN)
134 __sigaddset(&reset, SIGINT);
135 if (quit.sa_handler != SIG_IGN)
136 __sigaddset(&reset, SIGQUIT);
138 posix_spawnattr_t spawn_attr;
139 /* None of the posix_spawnattr_* function returns an error, including
140 posix_spawnattr_setflags for the follow specific usage (using valid
141 flags). */
142 __posix_spawnattr_init (&spawn_attr);
143 __posix_spawnattr_setsigmask (&spawn_attr, &omask);
144 __posix_spawnattr_setsigdefault (&spawn_attr, &reset);
145 __posix_spawnattr_setflags (&spawn_attr,
146 POSIX_SPAWN_SETSIGDEF | POSIX_SPAWN_SETSIGMASK);
148 ret = __posix_spawn (&pid, SHELL_PATH, 0, &spawn_attr,
149 (char *const[]){ (char *) SHELL_NAME,
150 (char *) "-c",
151 (char *) line, NULL },
152 __environ);
153 __posix_spawnattr_destroy (&spawn_attr);
155 if (ret == 0)
157 /* Cancellation results in cleanup handlers running as exceptions in
158 the block where they were installed, so it is safe to reference
159 stack variable allocate in the broader scope. */
160 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
161 struct cancel_handler_args cancel_args =
163 .quit = &quit,
164 .intr = &intr,
165 .pid = pid
167 __libc_cleanup_region_start (1, cancel_handler, &cancel_args);
168 #endif
169 /* Note the system() is a cancellation point. But since we call
170 waitpid() which itself is a cancellation point we do not
171 have to do anything here. */
172 if (TEMP_FAILURE_RETRY (__waitpid (pid, &status, 0)) != pid)
173 status = -1;
174 #if defined(_LIBC_REENTRANT) && defined(SIGCANCEL)
175 __libc_cleanup_region_end (0);
176 #endif
179 DO_LOCK ();
180 if (SUB_REF () == 0)
182 /* sigaction can not fail with SIGINT/SIGQUIT used with old
183 disposition. Same applies for sigprocmask. */
184 __sigaction (SIGINT, &intr, NULL);
185 __sigaction (SIGQUIT, &quit, NULL);
186 __sigprocmask (SIG_SETMASK, &omask, NULL);
188 DO_UNLOCK ();
190 if (ret != 0)
191 __set_errno (ret);
193 return status;
197 __libc_system (const char *line)
199 if (line == NULL)
200 /* Check that we have a command processor available. It might
201 not be available after a chroot(), for example. */
202 return do_system ("exit 0") == 0;
204 return do_system (line);
206 weak_alias (__libc_system, system)