1169695Skan/* Utilities to execute a program in a subprocess (possibly linked by pipes 2169695Skan with other subprocesses), and wait for it. Generic MSDOS specialization. 3169695Skan Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2003, 2005 4169695Skan Free Software Foundation, Inc. 5169695Skan 6169695SkanThis file is part of the libiberty library. 7169695SkanLibiberty is free software; you can redistribute it and/or 8169695Skanmodify it under the terms of the GNU Library General Public 9169695SkanLicense as published by the Free Software Foundation; either 10169695Skanversion 2 of the License, or (at your option) any later version. 11169695Skan 12169695SkanLibiberty is distributed in the hope that it will be useful, 13169695Skanbut WITHOUT ANY WARRANTY; without even the implied warranty of 14169695SkanMERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15169695SkanLibrary General Public License for more details. 16169695Skan 17169695SkanYou should have received a copy of the GNU Library General Public 18169695SkanLicense along with libiberty; see the file COPYING.LIB. If not, 19169695Skanwrite to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 20169695SkanBoston, MA 02110-1301, USA. */ 21169695Skan 22169695Skan#include "pex-common.h" 23169695Skan 24169695Skan#include <stdio.h> 25169695Skan#include <errno.h> 26169695Skan#ifdef NEED_DECLARATION_ERRNO 27169695Skanextern int errno; 28169695Skan#endif 29169695Skan#ifdef HAVE_STRING_H 30169695Skan#include <string.h> 31169695Skan#endif 32169695Skan#ifdef HAVE_STDLIB_H 33169695Skan#include <stdlib.h> 34169695Skan#endif 35169695Skan 36169695Skan#include "safe-ctype.h" 37169695Skan#include <process.h> 38169695Skan 39169695Skan/* The structure we keep in obj->sysdep. */ 40169695Skan 41169695Skan#define PEX_MSDOS_FILE_COUNT 3 42169695Skan 43169695Skan#define PEX_MSDOS_FD_OFFSET 10 44169695Skan 45169695Skanstruct pex_msdos 46169695Skan{ 47169695Skan /* An array of file names. We refer to these using file descriptors 48169695Skan of 10 + array index. */ 49169695Skan const char *files[PEX_MSDOS_FILE_COUNT]; 50169695Skan /* Exit statuses of programs which have been run. */ 51169695Skan int *statuses; 52169695Skan}; 53169695Skan 54169695Skanstatic int pex_msdos_open (struct pex_obj *, const char *, int); 55169695Skanstatic int pex_msdos_open (struct pex_obj *, const char *, int); 56169695Skanstatic int pex_msdos_fdindex (struct pex_msdos *, int); 57169695Skanstatic long pex_msdos_exec_child (struct pex_obj *, int, const char *, 58169695Skan char * const *, char * const *, 59169695Skan int, int, int, int, 60169695Skan int, const char **, int *); 61169695Skanstatic int pex_msdos_close (struct pex_obj *, int); 62169695Skanstatic int pex_msdos_wait (struct pex_obj *, long, int *, struct pex_time *, 63169695Skan int, const char **, int *); 64169695Skanstatic void pex_msdos_cleanup (struct pex_obj *); 65169695Skan 66169695Skan/* The list of functions we pass to the common routines. */ 67169695Skan 68169695Skanconst struct pex_funcs funcs = 69169695Skan{ 70169695Skan pex_msdos_open, 71169695Skan pex_msdos_open, 72169695Skan pex_msdos_exec_child, 73169695Skan pex_msdos_close, 74169695Skan pex_msdos_wait, 75169695Skan NULL, /* pipe */ 76169695Skan NULL, /* fdopenr */ 77169695Skan NULL, /* fdopenw */ 78169695Skan pex_msdos_cleanup 79169695Skan}; 80169695Skan 81169695Skan/* Return a newly initialized pex_obj structure. */ 82169695Skan 83169695Skanstruct pex_obj * 84169695Skanpex_init (int flags, const char *pname, const char *tempbase) 85169695Skan{ 86169695Skan struct pex_obj *ret; 87169695Skan int i; 88169695Skan 89169695Skan /* MSDOS does not support pipes. */ 90169695Skan flags &= ~ PEX_USE_PIPES; 91169695Skan 92169695Skan ret = pex_init_common (flags, pname, tempbase, funcs); 93169695Skan 94169695Skan ret->sysdep = XNEW (struct pex_msdos); 95169695Skan for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 96169695Skan ret->files[i] = NULL; 97169695Skan ret->statuses = NULL; 98169695Skan 99169695Skan return ret; 100169695Skan} 101169695Skan 102169695Skan/* Open a file. FIXME: We ignore the binary argument, since we have 103169695Skan no way to handle it. */ 104169695Skan 105169695Skanstatic int 106169695Skanpex_msdos_open (struct pex_obj *obj, const char *name, 107169695Skan int binary ATTRIBUTE_UNUSED) 108169695Skan{ 109169695Skan struct pex_msdos *ms; 110169695Skan int i; 111169695Skan 112169695Skan ms = (struct pex_msdos *) obj->sysdep; 113169695Skan 114169695Skan for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 115169695Skan { 116169695Skan if (ms->files[i] == NULL) 117169695Skan { 118169695Skan ms->files[i] = xstrdup (name); 119169695Skan return i + PEX_MSDOS_FD_OFFSET; 120169695Skan } 121169695Skan } 122169695Skan 123169695Skan abort (); 124169695Skan} 125169695Skan 126169695Skan/* Get the index into msdos->files associated with an open file 127169695Skan descriptor. */ 128169695Skan 129169695Skanstatic int 130169695Skanpex_msdos_fdindex (struct pex_msdos *ms, int fd) 131169695Skan{ 132169695Skan fd -= PEX_MSDOS_FD_OFFSET; 133169695Skan if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL) 134169695Skan abort (); 135169695Skan return fd; 136169695Skan} 137169695Skan 138169695Skan 139169695Skan/* Close a file. */ 140169695Skan 141169695Skanstatic int 142169695Skanpex_msdos_close (struct pex_obj *obj, int fd) 143169695Skan{ 144169695Skan struct pex_msdos *ms; 145169695Skan int fdinex; 146169695Skan 147169695Skan ms = (struct pex_msdos *) obj->sysdep; 148169695Skan fdindex = pe_msdos_fdindex (ms, fd); 149169695Skan free (ms->files[fdindex]); 150169695Skan ms->files[fdindex] = NULL; 151169695Skan} 152169695Skan 153169695Skan/* Execute a child. */ 154169695Skan 155169695Skanstatic long 156169695Skanpex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable, 157169695Skan char * const * argv, char * const * env, int in, int out, 158169695Skan int toclose ATTRIBUTE_UNUSED, 159169695Skan int errdes ATTRIBUTE_UNUSED, const char **errmsg, 160169695Skan int *err) 161169695Skan{ 162169695Skan struct pex_msdos *ms; 163169695Skan char *temp_base; 164169695Skan int temp_base_allocated; 165169695Skan char *rf; 166169695Skan int inindex; 167169695Skan char *infile; 168169695Skan int outindex; 169169695Skan char *outfile; 170169695Skan char *scmd; 171169695Skan FILE *argfile; 172169695Skan int i; 173169695Skan int status; 174169695Skan 175169695Skan ms = (struct pex_msdos *) obj->sysdep; 176169695Skan 177169695Skan /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES 178169695Skan and PEX_STDERR_TO_STDOUT. */ 179169695Skan 180169695Skan temp_base = obj->temp_base; 181169695Skan if (temp_base != NULL) 182169695Skan temp_base_allocated = 0; 183169695Skan else 184169695Skan { 185169695Skan temp_base = choose_temp_base (); 186169695Skan temp_base_allocated = 1; 187169695Skan } 188169695Skan 189169695Skan rf = concat (temp_base, ".gp", NULL); 190169695Skan 191169695Skan if (temp_base_allocated) 192169695Skan free (temp_base); 193169695Skan 194169695Skan if (in == STDIN_FILE_NO) 195169695Skan { 196169695Skan inindex = -1; 197169695Skan infile = ""; 198169695Skan } 199169695Skan else 200169695Skan { 201169695Skan inindex = pex_msdos_fdindex (ms, in); 202169695Skan infile = ms->files[inindex]; 203169695Skan } 204169695Skan 205169695Skan if (out == STDOUT_FILE_NO) 206169695Skan { 207169695Skan outindex = -1; 208169695Skan outfile = ""; 209169695Skan } 210169695Skan else 211169695Skan { 212169695Skan outindex = pex_msdos_fdindex (ms, out); 213169695Skan outfile = ms->files[outindex]; 214169695Skan } 215169695Skan 216169695Skan scmd = XNEWVEC (char, strlen (program) 217169695Skan + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0) 218169695Skan + strlen (rf) 219169695Skan + strlen (infile) 220169695Skan + strlen (outfile) 221169695Skan + 10); 222169695Skan sprintf (scmd, "%s%s @%s%s%s%s%s", 223169695Skan program, 224169695Skan (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "", 225169695Skan rf, 226169695Skan inindex != -1 ? " <" : "", 227169695Skan infile, 228169695Skan outindex != -1 ? " >" : "", 229169695Skan outfile); 230169695Skan 231169695Skan argfile = fopen (rf, "w"); 232169695Skan if (argfile == NULL) 233169695Skan { 234169695Skan *err = errno; 235169695Skan free (scmd); 236169695Skan free (rf); 237169695Skan *errmsg = "cannot open temporary command file"; 238169695Skan return -1; 239169695Skan } 240169695Skan 241169695Skan for (i = 1; argv[i] != NULL; ++i) 242169695Skan { 243169695Skan char *p; 244169695Skan 245169695Skan for (p = argv[i]; *p != '\0'; ++p) 246169695Skan { 247169695Skan if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p)) 248169695Skan putc ('\\', argfile); 249169695Skan putc (*p, argfile); 250169695Skan } 251169695Skan putc ('\n', argfile); 252169695Skan } 253169695Skan 254169695Skan fclose (argfile); 255169695Skan 256169695Skan status = system (scmd); 257169695Skan 258169695Skan if (status == -1) 259169695Skan { 260169695Skan *err = errno; 261169695Skan remove (rf); 262169695Skan free (scmd); 263169695Skan free (rf); 264169695Skan *errmsg = "system"; 265169695Skan return -1; 266169695Skan } 267169695Skan 268169695Skan remove (rf); 269169695Skan free (scmd); 270169695Skan free (rf); 271169695Skan 272169695Skan /* Save the exit status for later. When we are called, obj->count 273169695Skan is the number of children which have executed before this 274169695Skan one. */ 275169695Skan ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1); 276169695Skan ms->statuses[obj->count] = status; 277169695Skan 278169695Skan return obj->count; 279169695Skan} 280169695Skan 281169695Skan/* Wait for a child process to complete. Actually the child process 282169695Skan has already completed, and we just need to return the exit 283169695Skan status. */ 284169695Skan 285169695Skanstatic int 286169695Skanpex_msdos_wait (struct pex_obj *obj, long pid, int *status, 287169695Skan struct pex_time *time, int done ATTRIBUTE_UNUSED, 288169695Skan const char **errmsg ATTRIBUTE_UNUSED, 289169695Skan int *err ATTRIBUTE_UNUSED) 290169695Skan{ 291169695Skan struct pex_msdos *ms; 292169695Skan 293169695Skan ms = (struct pex_msdos *) obj->sysdep; 294169695Skan 295169695Skan if (time != NULL) 296169695Skan memset (time, 0, sizeof *time); 297169695Skan 298169695Skan *status = ms->statuses[pid]; 299169695Skan 300169695Skan return 0; 301169695Skan} 302169695Skan 303169695Skan/* Clean up the pex_msdos structure. */ 304169695Skan 305169695Skanstatic void 306169695Skanpex_msdos_cleanup (struct pex_obj *obj) 307169695Skan{ 308169695Skan struct pex_msdos *ms; 309169695Skan int i; 310169695Skan 311169695Skan ms = (struct pex_msdos *) obj->sysdep; 312169695Skan for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 313169695Skan if (msdos->files[i] != NULL) 314169695Skan free (msdos->files[i]); 315169695Skan if (msdos->statuses != NULL) 316169695Skan free (msdos->statuses); 317169695Skan free (msdos); 318169695Skan obj->sysdep = NULL; 319169695Skan} 320