1/* Utilities to execute a program in a subprocess (possibly linked by pipes 2 with other subprocesses), and wait for it. DJGPP specialization. 3 Copyright (C) 1996-2020 Free Software Foundation, Inc. 4 5This file is part of the libiberty library. 6Libiberty is free software; you can redistribute it and/or 7modify it under the terms of the GNU Library General Public 8License as published by the Free Software Foundation; either 9version 2 of the License, or (at your option) any later version. 10 11Libiberty is distributed in the hope that it will be useful, 12but WITHOUT ANY WARRANTY; without even the implied warranty of 13MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14Library General Public License for more details. 15 16You should have received a copy of the GNU Library General Public 17License along with libiberty; see the file COPYING.LIB. If not, 18write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 19Boston, MA 02110-1301, USA. */ 20 21#include "pex-common.h" 22 23#include <stdio.h> 24#include <errno.h> 25#ifdef NEED_DECLARATION_ERRNO 26extern int errno; 27#endif 28#ifdef HAVE_STDLIB_H 29#include <stdlib.h> 30#endif 31#include <string.h> 32#include <fcntl.h> 33#include <unistd.h> 34#include <sys/stat.h> 35#include <process.h> 36 37/* Use ECHILD if available, otherwise use EINVAL. */ 38#ifdef ECHILD 39#define PWAIT_ERROR ECHILD 40#else 41#define PWAIT_ERROR EINVAL 42#endif 43 44static int pex_djgpp_open_read (struct pex_obj *, const char *, int); 45static int pex_djgpp_open_write (struct pex_obj *, const char *, int, int); 46static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *, 47 char * const *, char * const *, 48 int, int, int, int, 49 const char **, int *); 50static int pex_djgpp_close (struct pex_obj *, int); 51static pid_t pex_djgpp_wait (struct pex_obj *, pid_t, int *, struct pex_time *, 52 int, const char **, int *); 53 54/* The list of functions we pass to the common routines. */ 55 56const struct pex_funcs funcs = 57{ 58 pex_djgpp_open_read, 59 pex_djgpp_open_write, 60 pex_djgpp_exec_child, 61 pex_djgpp_close, 62 pex_djgpp_wait, 63 NULL, /* pipe */ 64 NULL, /* fdopenr */ 65 NULL, /* fdopenw */ 66 NULL /* cleanup */ 67}; 68 69/* Return a newly initialized pex_obj structure. */ 70 71struct pex_obj * 72pex_init (int flags, const char *pname, const char *tempbase) 73{ 74 /* DJGPP does not support pipes. */ 75 flags &= ~ PEX_USE_PIPES; 76 return pex_init_common (flags, pname, tempbase, &funcs); 77} 78 79/* Open a file for reading. */ 80 81static int 82pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED, 83 const char *name, int binary) 84{ 85 return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT)); 86} 87 88/* Open a file for writing. */ 89 90static int 91pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED, 92 const char *name, int binary, int append) 93{ 94 /* Note that we can't use O_EXCL here because gcc may have already 95 created the temporary file via make_temp_file. */ 96 if (append) 97 return -1; 98 return open (name, 99 (O_WRONLY | O_CREAT | O_TRUNC 100 | (binary ? O_BINARY : O_TEXT)), 101 S_IRUSR | S_IWUSR); 102} 103 104/* Close a file. */ 105 106static int 107pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd) 108{ 109 return close (fd); 110} 111 112/* Execute a child. */ 113 114static pid_t 115pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable, 116 char * const * argv, char * const * env, 117 int in, int out, int errdes, 118 int toclose ATTRIBUTE_UNUSED, const char **errmsg, 119 int *err) 120{ 121 int org_in, org_out, org_errdes; 122 int status; 123 int *statuses; 124 125 org_in = -1; 126 org_out = -1; 127 org_errdes = -1; 128 129 if (in != STDIN_FILE_NO) 130 { 131 org_in = dup (STDIN_FILE_NO); 132 if (org_in < 0) 133 { 134 *err = errno; 135 *errmsg = "dup"; 136 return (pid_t) -1; 137 } 138 if (dup2 (in, STDIN_FILE_NO) < 0) 139 { 140 *err = errno; 141 *errmsg = "dup2"; 142 return (pid_t) -1; 143 } 144 if (close (in) < 0) 145 { 146 *err = errno; 147 *errmsg = "close"; 148 return (pid_t) -1; 149 } 150 } 151 152 if (out != STDOUT_FILE_NO) 153 { 154 org_out = dup (STDOUT_FILE_NO); 155 if (org_out < 0) 156 { 157 *err = errno; 158 *errmsg = "dup"; 159 return (pid_t) -1; 160 } 161 if (dup2 (out, STDOUT_FILE_NO) < 0) 162 { 163 *err = errno; 164 *errmsg = "dup2"; 165 return (pid_t) -1; 166 } 167 if (close (out) < 0) 168 { 169 *err = errno; 170 *errmsg = "close"; 171 return (pid_t) -1; 172 } 173 } 174 175 if (errdes != STDERR_FILE_NO 176 || (flags & PEX_STDERR_TO_STDOUT) != 0) 177 { 178 org_errdes = dup (STDERR_FILE_NO); 179 if (org_errdes < 0) 180 { 181 *err = errno; 182 *errmsg = "dup"; 183 return (pid_t) -1; 184 } 185 if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes, 186 STDERR_FILE_NO) < 0) 187 { 188 *err = errno; 189 *errmsg = "dup2"; 190 return (pid_t) -1; 191 } 192 if (errdes != STDERR_FILE_NO) 193 { 194 if (close (errdes) < 0) 195 { 196 *err = errno; 197 *errmsg = "close"; 198 return (pid_t) -1; 199 } 200 } 201 } 202 203 if (env) 204 status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve) 205 (P_WAIT, executable, argv, env)); 206 else 207 status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv) 208 (P_WAIT, executable, argv)); 209 210 if (status == -1) 211 { 212 *err = errno; 213 *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv"; 214 } 215 216 if (in != STDIN_FILE_NO) 217 { 218 if (dup2 (org_in, STDIN_FILE_NO) < 0) 219 { 220 *err = errno; 221 *errmsg = "dup2"; 222 return (pid_t) -1; 223 } 224 if (close (org_in) < 0) 225 { 226 *err = errno; 227 *errmsg = "close"; 228 return (pid_t) -1; 229 } 230 } 231 232 if (out != STDOUT_FILE_NO) 233 { 234 if (dup2 (org_out, STDOUT_FILE_NO) < 0) 235 { 236 *err = errno; 237 *errmsg = "dup2"; 238 return (pid_t) -1; 239 } 240 if (close (org_out) < 0) 241 { 242 *err = errno; 243 *errmsg = "close"; 244 return (pid_t) -1; 245 } 246 } 247 248 if (errdes != STDERR_FILE_NO 249 || (flags & PEX_STDERR_TO_STDOUT) != 0) 250 { 251 if (dup2 (org_errdes, STDERR_FILE_NO) < 0) 252 { 253 *err = errno; 254 *errmsg = "dup2"; 255 return (pid_t) -1; 256 } 257 if (close (org_errdes) < 0) 258 { 259 *err = errno; 260 *errmsg = "close"; 261 return (pid_t) -1; 262 } 263 } 264 265 /* Save the exit status for later. When we are called, obj->count 266 is the number of children which have executed before this 267 one. */ 268 statuses = (int *) obj->sysdep; 269 statuses = XRESIZEVEC (int, statuses, obj->count + 1); 270 statuses[obj->count] = status; 271 obj->sysdep = (void *) statuses; 272 273 return (pid_t) obj->count; 274} 275 276/* Wait for a child process to complete. Actually the child process 277 has already completed, and we just need to return the exit 278 status. */ 279 280static pid_t 281pex_djgpp_wait (struct pex_obj *obj, pid_t pid, int *status, 282 struct pex_time *time, int done ATTRIBUTE_UNUSED, 283 const char **errmsg ATTRIBUTE_UNUSED, 284 int *err ATTRIBUTE_UNUSED) 285{ 286 int *statuses; 287 288 if (time != NULL) 289 memset (time, 0, sizeof *time); 290 291 statuses = (int *) obj->sysdep; 292 *status = statuses[pid]; 293 294 return 0; 295} 296