198b9484cSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes 298b9484cSchristos with other subprocesses), and wait for it. Generic MSDOS specialization. 3*5173eb0aSchristos Copyright (C) 1996-2024 Free Software Foundation, Inc. 498b9484cSchristos 598b9484cSchristos This file is part of the libiberty library. 698b9484cSchristos Libiberty is free software; you can redistribute it and/or 798b9484cSchristos modify it under the terms of the GNU Library General Public 898b9484cSchristos License as published by the Free Software Foundation; either 998b9484cSchristos version 2 of the License, or (at your option) any later version. 1098b9484cSchristos 1198b9484cSchristos Libiberty is distributed in the hope that it will be useful, 1298b9484cSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of 1398b9484cSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 1498b9484cSchristos Library General Public License for more details. 1598b9484cSchristos 1698b9484cSchristos You should have received a copy of the GNU Library General Public 1798b9484cSchristos License along with libiberty; see the file COPYING.LIB. If not, 1898b9484cSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor, 1998b9484cSchristos Boston, MA 02110-1301, USA. */ 2098b9484cSchristos 2198b9484cSchristos #include "pex-common.h" 2298b9484cSchristos 2398b9484cSchristos #include <stdio.h> 2498b9484cSchristos #include <errno.h> 2598b9484cSchristos #ifdef NEED_DECLARATION_ERRNO 2698b9484cSchristos extern int errno; 2798b9484cSchristos #endif 2898b9484cSchristos #ifdef HAVE_STRING_H 2998b9484cSchristos #include <string.h> 3098b9484cSchristos #endif 3198b9484cSchristos #ifdef HAVE_STDLIB_H 3298b9484cSchristos #include <stdlib.h> 3398b9484cSchristos #endif 3498b9484cSchristos 3598b9484cSchristos #include "safe-ctype.h" 3698b9484cSchristos #include <process.h> 3798b9484cSchristos 3898b9484cSchristos /* The structure we keep in obj->sysdep. */ 3998b9484cSchristos 4098b9484cSchristos #define PEX_MSDOS_FILE_COUNT 3 4198b9484cSchristos 4298b9484cSchristos #define PEX_MSDOS_FD_OFFSET 10 4398b9484cSchristos 4498b9484cSchristos struct pex_msdos 4598b9484cSchristos { 4698b9484cSchristos /* An array of file names. We refer to these using file descriptors 4798b9484cSchristos of 10 + array index. */ 4898b9484cSchristos const char *files[PEX_MSDOS_FILE_COUNT]; 4998b9484cSchristos /* Exit statuses of programs which have been run. */ 5098b9484cSchristos int *statuses; 5198b9484cSchristos }; 5298b9484cSchristos 5398b9484cSchristos static int pex_msdos_open (struct pex_obj *, const char *, int); 5498b9484cSchristos static int pex_msdos_open (struct pex_obj *, const char *, int); 5598b9484cSchristos static int pex_msdos_fdindex (struct pex_msdos *, int); 5698b9484cSchristos static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *, 5798b9484cSchristos char * const *, char * const *, 5898b9484cSchristos int, int, int, int, 5998b9484cSchristos int, const char **, int *); 6098b9484cSchristos static int pex_msdos_close (struct pex_obj *, int); 6198b9484cSchristos static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *, 6298b9484cSchristos int, const char **, int *); 6398b9484cSchristos static void pex_msdos_cleanup (struct pex_obj *); 6498b9484cSchristos 6598b9484cSchristos /* The list of functions we pass to the common routines. */ 6698b9484cSchristos 6798b9484cSchristos const struct pex_funcs funcs = 6898b9484cSchristos { 6998b9484cSchristos pex_msdos_open, 7098b9484cSchristos pex_msdos_open, 7198b9484cSchristos pex_msdos_exec_child, 7298b9484cSchristos pex_msdos_close, 7398b9484cSchristos pex_msdos_wait, 7498b9484cSchristos NULL, /* pipe */ 7598b9484cSchristos NULL, /* fdopenr */ 7698b9484cSchristos NULL, /* fdopenw */ 7798b9484cSchristos pex_msdos_cleanup 7898b9484cSchristos }; 7998b9484cSchristos 8098b9484cSchristos /* Return a newly initialized pex_obj structure. */ 8198b9484cSchristos 8298b9484cSchristos struct pex_obj * 8398b9484cSchristos pex_init (int flags, const char *pname, const char *tempbase) 8498b9484cSchristos { 8598b9484cSchristos struct pex_obj *ret; 8698b9484cSchristos int i; 8798b9484cSchristos 8898b9484cSchristos /* MSDOS does not support pipes. */ 8998b9484cSchristos flags &= ~ PEX_USE_PIPES; 9098b9484cSchristos 9198b9484cSchristos ret = pex_init_common (flags, pname, tempbase, funcs); 9298b9484cSchristos 9398b9484cSchristos ret->sysdep = XNEW (struct pex_msdos); 9498b9484cSchristos for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 9598b9484cSchristos ret->files[i] = NULL; 9698b9484cSchristos ret->statuses = NULL; 9798b9484cSchristos 9898b9484cSchristos return ret; 9998b9484cSchristos } 10098b9484cSchristos 10198b9484cSchristos /* Open a file. FIXME: We ignore the binary argument, since we have 10298b9484cSchristos no way to handle it. */ 10398b9484cSchristos 10498b9484cSchristos static int 10598b9484cSchristos pex_msdos_open (struct pex_obj *obj, const char *name, 10698b9484cSchristos int binary ATTRIBUTE_UNUSED) 10798b9484cSchristos { 10898b9484cSchristos struct pex_msdos *ms; 10998b9484cSchristos int i; 11098b9484cSchristos 11198b9484cSchristos ms = (struct pex_msdos *) obj->sysdep; 11298b9484cSchristos 11398b9484cSchristos for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 11498b9484cSchristos { 11598b9484cSchristos if (ms->files[i] == NULL) 11698b9484cSchristos { 11798b9484cSchristos ms->files[i] = xstrdup (name); 11898b9484cSchristos return i + PEX_MSDOS_FD_OFFSET; 11998b9484cSchristos } 12098b9484cSchristos } 12198b9484cSchristos 12298b9484cSchristos abort (); 12398b9484cSchristos } 12498b9484cSchristos 12598b9484cSchristos /* Get the index into msdos->files associated with an open file 12698b9484cSchristos descriptor. */ 12798b9484cSchristos 12898b9484cSchristos static int 12998b9484cSchristos pex_msdos_fdindex (struct pex_msdos *ms, int fd) 13098b9484cSchristos { 13198b9484cSchristos fd -= PEX_MSDOS_FD_OFFSET; 13298b9484cSchristos if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL) 13398b9484cSchristos abort (); 13498b9484cSchristos return fd; 13598b9484cSchristos } 13698b9484cSchristos 13798b9484cSchristos 13898b9484cSchristos /* Close a file. */ 13998b9484cSchristos 14098b9484cSchristos static int 14198b9484cSchristos pex_msdos_close (struct pex_obj *obj, int fd) 14298b9484cSchristos { 14398b9484cSchristos struct pex_msdos *ms; 14498b9484cSchristos int fdinex; 14598b9484cSchristos 14698b9484cSchristos ms = (struct pex_msdos *) obj->sysdep; 14798b9484cSchristos fdindex = pe_msdos_fdindex (ms, fd); 14898b9484cSchristos free (ms->files[fdindex]); 14998b9484cSchristos ms->files[fdindex] = NULL; 15098b9484cSchristos } 15198b9484cSchristos 15298b9484cSchristos /* Execute a child. */ 15398b9484cSchristos 15498b9484cSchristos static pid_t 15598b9484cSchristos pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable, 15698b9484cSchristos char * const * argv, char * const * env, int in, int out, 15798b9484cSchristos int toclose ATTRIBUTE_UNUSED, 15898b9484cSchristos int errdes ATTRIBUTE_UNUSED, const char **errmsg, 15998b9484cSchristos int *err) 16098b9484cSchristos { 16198b9484cSchristos struct pex_msdos *ms; 16298b9484cSchristos char *temp_base; 16398b9484cSchristos int temp_base_allocated; 16498b9484cSchristos char *rf; 16598b9484cSchristos int inindex; 16698b9484cSchristos char *infile; 16798b9484cSchristos int outindex; 16898b9484cSchristos char *outfile; 16998b9484cSchristos char *scmd; 17098b9484cSchristos FILE *argfile; 17198b9484cSchristos int i; 17298b9484cSchristos int status; 17398b9484cSchristos 17498b9484cSchristos ms = (struct pex_msdos *) obj->sysdep; 17598b9484cSchristos 17698b9484cSchristos /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES 17798b9484cSchristos and PEX_STDERR_TO_STDOUT. */ 17898b9484cSchristos 17998b9484cSchristos temp_base = obj->temp_base; 18098b9484cSchristos if (temp_base != NULL) 18198b9484cSchristos temp_base_allocated = 0; 18298b9484cSchristos else 18398b9484cSchristos { 18498b9484cSchristos temp_base = choose_temp_base (); 18598b9484cSchristos temp_base_allocated = 1; 18698b9484cSchristos } 18798b9484cSchristos 18898b9484cSchristos rf = concat (temp_base, ".gp", NULL); 18998b9484cSchristos 19098b9484cSchristos if (temp_base_allocated) 19198b9484cSchristos free (temp_base); 19298b9484cSchristos 19398b9484cSchristos if (in == STDIN_FILE_NO) 19498b9484cSchristos { 19598b9484cSchristos inindex = -1; 19698b9484cSchristos infile = ""; 19798b9484cSchristos } 19898b9484cSchristos else 19998b9484cSchristos { 20098b9484cSchristos inindex = pex_msdos_fdindex (ms, in); 20198b9484cSchristos infile = ms->files[inindex]; 20298b9484cSchristos } 20398b9484cSchristos 20498b9484cSchristos if (out == STDOUT_FILE_NO) 20598b9484cSchristos { 20698b9484cSchristos outindex = -1; 20798b9484cSchristos outfile = ""; 20898b9484cSchristos } 20998b9484cSchristos else 21098b9484cSchristos { 21198b9484cSchristos outindex = pex_msdos_fdindex (ms, out); 21298b9484cSchristos outfile = ms->files[outindex]; 21398b9484cSchristos } 21498b9484cSchristos 21598b9484cSchristos scmd = XNEWVEC (char, strlen (program) 21698b9484cSchristos + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0) 21798b9484cSchristos + strlen (rf) 21898b9484cSchristos + strlen (infile) 21998b9484cSchristos + strlen (outfile) 22098b9484cSchristos + 10); 22198b9484cSchristos sprintf (scmd, "%s%s @%s%s%s%s%s", 22298b9484cSchristos program, 22398b9484cSchristos (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "", 22498b9484cSchristos rf, 22598b9484cSchristos inindex != -1 ? " <" : "", 22698b9484cSchristos infile, 22798b9484cSchristos outindex != -1 ? " >" : "", 22898b9484cSchristos outfile); 22998b9484cSchristos 23098b9484cSchristos argfile = fopen (rf, "w"); 23198b9484cSchristos if (argfile == NULL) 23298b9484cSchristos { 23398b9484cSchristos *err = errno; 23498b9484cSchristos free (scmd); 23598b9484cSchristos free (rf); 23698b9484cSchristos *errmsg = "cannot open temporary command file"; 23798b9484cSchristos return (pid_t) -1; 23898b9484cSchristos } 23998b9484cSchristos 24098b9484cSchristos for (i = 1; argv[i] != NULL; ++i) 24198b9484cSchristos { 24298b9484cSchristos char *p; 24398b9484cSchristos 24498b9484cSchristos for (p = argv[i]; *p != '\0'; ++p) 24598b9484cSchristos { 24698b9484cSchristos if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p)) 24798b9484cSchristos putc ('\\', argfile); 24898b9484cSchristos putc (*p, argfile); 24998b9484cSchristos } 25098b9484cSchristos putc ('\n', argfile); 25198b9484cSchristos } 25298b9484cSchristos 25398b9484cSchristos fclose (argfile); 25498b9484cSchristos 25598b9484cSchristos status = system (scmd); 25698b9484cSchristos 25798b9484cSchristos if (status == -1) 25898b9484cSchristos { 25998b9484cSchristos *err = errno; 26098b9484cSchristos remove (rf); 26198b9484cSchristos free (scmd); 26298b9484cSchristos free (rf); 26398b9484cSchristos *errmsg = "system"; 26498b9484cSchristos return (pid_t) -1; 26598b9484cSchristos } 26698b9484cSchristos 26798b9484cSchristos remove (rf); 26898b9484cSchristos free (scmd); 26998b9484cSchristos free (rf); 27098b9484cSchristos 27198b9484cSchristos /* Save the exit status for later. When we are called, obj->count 27298b9484cSchristos is the number of children which have executed before this 27398b9484cSchristos one. */ 27498b9484cSchristos ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1); 27598b9484cSchristos ms->statuses[obj->count] = status; 27698b9484cSchristos 27798b9484cSchristos return (pid_t) obj->count; 27898b9484cSchristos } 27998b9484cSchristos 28098b9484cSchristos /* Wait for a child process to complete. Actually the child process 28198b9484cSchristos has already completed, and we just need to return the exit 28298b9484cSchristos status. */ 28398b9484cSchristos 28498b9484cSchristos static pid_t 28598b9484cSchristos pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status, 28698b9484cSchristos struct pex_time *time, int done ATTRIBUTE_UNUSED, 28798b9484cSchristos const char **errmsg ATTRIBUTE_UNUSED, 28898b9484cSchristos int *err ATTRIBUTE_UNUSED) 28998b9484cSchristos { 29098b9484cSchristos struct pex_msdos *ms; 29198b9484cSchristos 29298b9484cSchristos ms = (struct pex_msdos *) obj->sysdep; 29398b9484cSchristos 29498b9484cSchristos if (time != NULL) 29598b9484cSchristos memset (time, 0, sizeof *time); 29698b9484cSchristos 29798b9484cSchristos *status = ms->statuses[pid]; 29898b9484cSchristos 29998b9484cSchristos return 0; 30098b9484cSchristos } 30198b9484cSchristos 30298b9484cSchristos /* Clean up the pex_msdos structure. */ 30398b9484cSchristos 30498b9484cSchristos static void 30598b9484cSchristos pex_msdos_cleanup (struct pex_obj *obj) 30698b9484cSchristos { 30798b9484cSchristos struct pex_msdos *ms; 30898b9484cSchristos int i; 30998b9484cSchristos 31098b9484cSchristos ms = (struct pex_msdos *) obj->sysdep; 31198b9484cSchristos for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i) 31298b9484cSchristos free (msdos->files[i]); 31398b9484cSchristos free (msdos->statuses); 31498b9484cSchristos free (msdos); 31598b9484cSchristos obj->sysdep = NULL; 31698b9484cSchristos } 317