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