1/* Copyright (C) 1993-2022 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 <https://www.gnu.org/licenses/>.
17
18 As a special exception, if you link the code in this file with
19 files compiled with a GNU compiler to produce an executable,
20 that does not cause the resulting executable to be covered by
21 the GNU Lesser General Public License. This exception does not
22 however invalidate any other reasons why the executable file
23 might be covered by the GNU Lesser General Public License.
24 This exception applies to code released by its copyright holders
25 in files containing the exception. */
26
27#include "libioP.h"
28#include <fcntl.h>
29#include <signal.h>
30#include <unistd.h>
31#include <stdlib.h>
32#include <shlib-compat.h>
33#include <not-cancel.h>
34#include <sys/types.h>
35#include <sys/wait.h>
36#include <spawn.h>
37#include <paths.h>
38
39struct _IO_proc_file
40{
41 struct _IO_FILE_plus file;
42 /* Following fields must match those in class procbuf (procbuf.h) */
43 pid_t pid;
44 struct _IO_proc_file *next;
45};
46typedef struct _IO_proc_file _IO_proc_file;
47
48static const struct _IO_jump_t _IO_proc_jumps;
49
50static struct _IO_proc_file *proc_file_chain;
51
52#ifdef _IO_MTSAFE_IO
53static _IO_lock_t proc_file_chain_lock = _IO_lock_initializer;
54
55static void
56unlock (void *not_used)
57{
58 _IO_lock_unlock (proc_file_chain_lock);
59}
60#endif
61
62/* POSIX states popen shall ensure that any streams from previous popen()
63 calls that remain open in the parent process should be closed in the new
64 child process.
65 To avoid a race-condition between checking which file descriptors need to
66 be close (by transversing the proc_file_chain list) and the insertion of a
67 new one after a successful posix_spawn this function should be called
68 with proc_file_chain_lock acquired. */
69static bool
70spawn_process (posix_spawn_file_actions_t *fa, FILE *fp, const char *command,
71 int do_cloexec, int pipe_fds[2], int parent_end, int child_end,
72 int child_pipe_fd)
73{
74
75 for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next)
76 {
77 int fd = _IO_fileno ((FILE *) p);
78
79 /* If any stream from previous popen() calls has fileno
80 child_pipe_fd, it has been already closed by the adddup2 action
81 above. */
82 if (fd != child_pipe_fd
83 && __posix_spawn_file_actions_addclose (fa, fd) != 0)
84 return false;
85 }
86
87 if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, fa, 0,
88 (char *const[]){ (char*) "sh", (char*) "-c",
89 (char *) command, NULL }, __environ) != 0)
90 return false;
91
92 __close_nocancel (pipe_fds[child_end]);
93
94 if (!do_cloexec)
95 /* Undo the effects of the pipe2 call which set the
96 close-on-exec flag. */
97 __fcntl (pipe_fds[parent_end], F_SETFD, 0);
98
99 _IO_fileno (fp) = pipe_fds[parent_end];
100
101 ((_IO_proc_file *) fp)->next = proc_file_chain;
102 proc_file_chain = (_IO_proc_file *) fp;
103
104 return true;
105}
106
107FILE *
108_IO_new_proc_open (FILE *fp, const char *command, const char *mode)
109{
110 int read_or_write;
111 /* These are indexes for pipe_fds. */
112 int parent_end, child_end;
113 int pipe_fds[2];
114 int child_pipe_fd;
115 bool spawn_ok;
116
117 int do_read = 0;
118 int do_write = 0;
119 int do_cloexec = 0;
120 while (*mode != '\0')
121 switch (*mode++)
122 {
123 case 'r':
124 do_read = 1;
125 break;
126 case 'w':
127 do_write = 1;
128 break;
129 case 'e':
130 do_cloexec = 1;
131 break;
132 default:
133 errout:
134 __set_errno (EINVAL);
135 return NULL;
136 }
137
138 if ((do_read ^ do_write) == 0)
139 goto errout;
140
141 if (_IO_file_is_open (fp))
142 return NULL;
143
144 /* Atomically set the O_CLOEXEC flag for the pipe end used by the
145 child process (to avoid leaking the file descriptor in case of a
146 concurrent fork). This is later reverted in the child process.
147 When popen returns, the parent pipe end can be O_CLOEXEC or not,
148 depending on the 'e' open mode, but there is only one flag which
149 controls both descriptors. The parent end is adjusted below,
150 after creating the child process. (In the child process, the
151 parent end should be closed on execve, so O_CLOEXEC remains set
152 there.) */
153 if (__pipe2 (pipedes: pipe_fds, O_CLOEXEC) < 0)
154 return NULL;
155
156 if (do_read)
157 {
158 parent_end = 0;
159 child_end = 1;
160 read_or_write = _IO_NO_WRITES;
161 child_pipe_fd = 1;
162 }
163 else
164 {
165 parent_end = 1;
166 child_end = 0;
167 read_or_write = _IO_NO_READS;
168 child_pipe_fd = 0;
169 }
170
171 posix_spawn_file_actions_t fa;
172 /* posix_spawn_file_actions_init does not fail. */
173 __posix_spawn_file_actions_init (&fa);
174
175 /* The descriptor is already the one the child will use. In this case
176 it must be moved to another one otherwise, there is no safe way to
177 remove the close-on-exec flag in the child without creating a FD leak
178 race in the parent. */
179 if (pipe_fds[child_end] == child_pipe_fd)
180 {
181 int tmp = __fcntl (child_pipe_fd, F_DUPFD_CLOEXEC, 0);
182 if (tmp < 0)
183 goto spawn_failure;
184 __close_nocancel (pipe_fds[child_end]);
185 pipe_fds[child_end] = tmp;
186 }
187
188 if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[child_end],
189 child_pipe_fd) != 0)
190 goto spawn_failure;
191
192#ifdef _IO_MTSAFE_IO
193 _IO_cleanup_region_start_noarg (unlock);
194 _IO_lock_lock (proc_file_chain_lock);
195#endif
196 spawn_ok = spawn_process (fa: &fa, fp, command, do_cloexec, pipe_fds,
197 parent_end, child_end, child_pipe_fd);
198#ifdef _IO_MTSAFE_IO
199 _IO_lock_unlock (proc_file_chain_lock);
200 _IO_cleanup_region_end (0);
201#endif
202
203 __posix_spawn_file_actions_destroy (&fa);
204
205 if (!spawn_ok)
206 {
207 spawn_failure:
208 __close_nocancel (pipe_fds[child_end]);
209 __close_nocancel (pipe_fds[parent_end]);
210 __set_errno (ENOMEM);
211 return NULL;
212 }
213
214 _IO_mask_flags (fp, read_or_write, _IO_NO_READS|_IO_NO_WRITES);
215 return fp;
216}
217
218FILE *
219_IO_new_popen (const char *command, const char *mode)
220{
221 struct locked_FILE
222 {
223 struct _IO_proc_file fpx;
224#ifdef _IO_MTSAFE_IO
225 _IO_lock_t lock;
226#endif
227 } *new_f;
228 FILE *fp;
229
230 new_f = (struct locked_FILE *) malloc (size: sizeof (struct locked_FILE));
231 if (new_f == NULL)
232 return NULL;
233#ifdef _IO_MTSAFE_IO
234 new_f->fpx.file.file._lock = &new_f->lock;
235#endif
236 fp = &new_f->fpx.file.file;
237 _IO_init_internal (fp, 0);
238 _IO_JUMPS (&new_f->fpx.file) = &_IO_proc_jumps;
239 _IO_new_file_init_internal (&new_f->fpx.file);
240 if (_IO_new_proc_open (fp, command, mode) != NULL)
241 return (FILE *) &new_f->fpx.file;
242 _IO_un_link (&new_f->fpx.file);
243 free (ptr: new_f);
244 return NULL;
245}
246
247int
248_IO_new_proc_close (FILE *fp)
249{
250 /* This is not name-space clean. FIXME! */
251 int wstatus;
252 _IO_proc_file **ptr = &proc_file_chain;
253 pid_t wait_pid;
254 int status = -1;
255
256 /* Unlink from proc_file_chain. */
257#ifdef _IO_MTSAFE_IO
258 _IO_cleanup_region_start_noarg (unlock);
259 _IO_lock_lock (proc_file_chain_lock);
260#endif
261 for ( ; *ptr != NULL; ptr = &(*ptr)->next)
262 {
263 if (*ptr == (_IO_proc_file *) fp)
264 {
265 *ptr = (*ptr)->next;
266 status = 0;
267 break;
268 }
269 }
270#ifdef _IO_MTSAFE_IO
271 _IO_lock_unlock (proc_file_chain_lock);
272 _IO_cleanup_region_end (0);
273#endif
274
275 if (status < 0 || __close_nocancel (_IO_fileno(fp)) < 0)
276 return -1;
277 /* POSIX.2 Rationale: "Some historical implementations either block
278 or ignore the signals SIGINT, SIGQUIT, and SIGHUP while waiting
279 for the child process to terminate. Since this behavior is not
280 described in POSIX.2, such implementations are not conforming." */
281 do
282 {
283 int state;
284 __pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &state);
285 wait_pid = __waitpid (((_IO_proc_file *) fp)->pid, &wstatus, 0);
286 __pthread_setcancelstate (state, NULL);
287 }
288 while (wait_pid == -1 && errno == EINTR);
289 if (wait_pid == -1)
290 return -1;
291 return wstatus;
292}
293
294static const struct _IO_jump_t _IO_proc_jumps libio_vtable = {
295 JUMP_INIT_DUMMY,
296 JUMP_INIT(finish, _IO_new_file_finish),
297 JUMP_INIT(overflow, _IO_new_file_overflow),
298 JUMP_INIT(underflow, _IO_new_file_underflow),
299 JUMP_INIT(uflow, _IO_default_uflow),
300 JUMP_INIT(pbackfail, _IO_default_pbackfail),
301 JUMP_INIT(xsputn, _IO_new_file_xsputn),
302 JUMP_INIT(xsgetn, _IO_default_xsgetn),
303 JUMP_INIT(seekoff, _IO_new_file_seekoff),
304 JUMP_INIT(seekpos, _IO_default_seekpos),
305 JUMP_INIT(setbuf, _IO_new_file_setbuf),
306 JUMP_INIT(sync, _IO_new_file_sync),
307 JUMP_INIT(doallocate, _IO_file_doallocate),
308 JUMP_INIT(read, _IO_file_read),
309 JUMP_INIT(write, _IO_new_file_write),
310 JUMP_INIT(seek, _IO_file_seek),
311 JUMP_INIT(close, _IO_new_proc_close),
312 JUMP_INIT(stat, _IO_file_stat),
313 JUMP_INIT(showmanyc, _IO_default_showmanyc),
314 JUMP_INIT(imbue, _IO_default_imbue)
315};
316
317strong_alias (_IO_new_popen, __new_popen)
318versioned_symbol (libc, _IO_new_popen, _IO_popen, GLIBC_2_1);
319versioned_symbol (libc, __new_popen, popen, GLIBC_2_1);
320versioned_symbol (libc, _IO_new_proc_open, _IO_proc_open, GLIBC_2_1);
321versioned_symbol (libc, _IO_new_proc_close, _IO_proc_close, GLIBC_2_1);
322

source code of glibc/libio/iopopen.c