1440a403fSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes
2440a403fSchristos    with other subprocesses), and wait for it.  Generic MSDOS specialization.
3*b88e3e88Schristos    Copyright (C) 1996-2020 Free Software Foundation, Inc.
4440a403fSchristos 
5440a403fSchristos This file is part of the libiberty library.
6440a403fSchristos Libiberty is free software; you can redistribute it and/or
7440a403fSchristos modify it under the terms of the GNU Library General Public
8440a403fSchristos License as published by the Free Software Foundation; either
9440a403fSchristos version 2 of the License, or (at your option) any later version.
10440a403fSchristos 
11440a403fSchristos Libiberty is distributed in the hope that it will be useful,
12440a403fSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13440a403fSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14440a403fSchristos Library General Public License for more details.
15440a403fSchristos 
16440a403fSchristos You should have received a copy of the GNU Library General Public
17440a403fSchristos License along with libiberty; see the file COPYING.LIB.  If not,
18440a403fSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19440a403fSchristos Boston, MA 02110-1301, USA.  */
20440a403fSchristos 
21440a403fSchristos #include "pex-common.h"
22440a403fSchristos 
23440a403fSchristos #include <stdio.h>
24440a403fSchristos #include <errno.h>
25440a403fSchristos #ifdef NEED_DECLARATION_ERRNO
26440a403fSchristos extern int errno;
27440a403fSchristos #endif
28440a403fSchristos #ifdef HAVE_STRING_H
29440a403fSchristos #include <string.h>
30440a403fSchristos #endif
31440a403fSchristos #ifdef HAVE_STDLIB_H
32440a403fSchristos #include <stdlib.h>
33440a403fSchristos #endif
34440a403fSchristos 
35440a403fSchristos #include "safe-ctype.h"
36440a403fSchristos #include <process.h>
37440a403fSchristos 
38440a403fSchristos /* The structure we keep in obj->sysdep.  */
39440a403fSchristos 
40440a403fSchristos #define PEX_MSDOS_FILE_COUNT 3
41440a403fSchristos 
42440a403fSchristos #define PEX_MSDOS_FD_OFFSET 10
43440a403fSchristos 
44440a403fSchristos struct pex_msdos
45440a403fSchristos {
46440a403fSchristos   /* An array of file names.  We refer to these using file descriptors
47440a403fSchristos      of 10 + array index.  */
48440a403fSchristos   const char *files[PEX_MSDOS_FILE_COUNT];
49440a403fSchristos   /* Exit statuses of programs which have been run.  */
50440a403fSchristos   int *statuses;
51440a403fSchristos };
52440a403fSchristos 
53440a403fSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
54440a403fSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
55440a403fSchristos static int pex_msdos_fdindex (struct pex_msdos *, int);
56440a403fSchristos static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *,
57440a403fSchristos 				  char * const *, char * const *,
58440a403fSchristos 				  int, int, int, int,
59440a403fSchristos 				  int, const char **, int *);
60440a403fSchristos static int pex_msdos_close (struct pex_obj *, int);
61440a403fSchristos static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
62440a403fSchristos 			   int, const char **, int *);
63440a403fSchristos static void pex_msdos_cleanup (struct pex_obj *);
64440a403fSchristos 
65440a403fSchristos /* The list of functions we pass to the common routines.  */
66440a403fSchristos 
67440a403fSchristos const struct pex_funcs funcs =
68440a403fSchristos {
69440a403fSchristos   pex_msdos_open,
70440a403fSchristos   pex_msdos_open,
71440a403fSchristos   pex_msdos_exec_child,
72440a403fSchristos   pex_msdos_close,
73440a403fSchristos   pex_msdos_wait,
74440a403fSchristos   NULL, /* pipe */
75440a403fSchristos   NULL, /* fdopenr */
76440a403fSchristos   NULL, /* fdopenw */
77440a403fSchristos   pex_msdos_cleanup
78440a403fSchristos };
79440a403fSchristos 
80440a403fSchristos /* Return a newly initialized pex_obj structure.  */
81440a403fSchristos 
82440a403fSchristos struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)83440a403fSchristos pex_init (int flags, const char *pname, const char *tempbase)
84440a403fSchristos {
85440a403fSchristos   struct pex_obj *ret;
86440a403fSchristos   int i;
87440a403fSchristos 
88440a403fSchristos   /* MSDOS does not support pipes.  */
89440a403fSchristos   flags &= ~ PEX_USE_PIPES;
90440a403fSchristos 
91440a403fSchristos   ret = pex_init_common (flags, pname, tempbase, funcs);
92440a403fSchristos 
93440a403fSchristos   ret->sysdep = XNEW (struct pex_msdos);
94440a403fSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
95440a403fSchristos     ret->files[i] = NULL;
96440a403fSchristos   ret->statuses = NULL;
97440a403fSchristos 
98440a403fSchristos   return ret;
99440a403fSchristos }
100440a403fSchristos 
101440a403fSchristos /* Open a file.  FIXME: We ignore the binary argument, since we have
102440a403fSchristos    no way to handle it.  */
103440a403fSchristos 
104440a403fSchristos static int
pex_msdos_open(struct pex_obj * obj,const char * name,int binary ATTRIBUTE_UNUSED)105440a403fSchristos pex_msdos_open (struct pex_obj *obj, const char *name,
106440a403fSchristos 		int binary ATTRIBUTE_UNUSED)
107440a403fSchristos {
108440a403fSchristos   struct pex_msdos *ms;
109440a403fSchristos   int i;
110440a403fSchristos 
111440a403fSchristos   ms = (struct pex_msdos *) obj->sysdep;
112440a403fSchristos 
113440a403fSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
114440a403fSchristos     {
115440a403fSchristos       if (ms->files[i] == NULL)
116440a403fSchristos 	{
117440a403fSchristos 	  ms->files[i] = xstrdup (name);
118440a403fSchristos 	  return i + PEX_MSDOS_FD_OFFSET;
119440a403fSchristos 	}
120440a403fSchristos     }
121440a403fSchristos 
122440a403fSchristos   abort ();
123440a403fSchristos }
124440a403fSchristos 
125440a403fSchristos /* Get the index into msdos->files associated with an open file
126440a403fSchristos    descriptor.  */
127440a403fSchristos 
128440a403fSchristos static int
pex_msdos_fdindex(struct pex_msdos * ms,int fd)129440a403fSchristos pex_msdos_fdindex (struct pex_msdos *ms, int fd)
130440a403fSchristos {
131440a403fSchristos   fd -= PEX_MSDOS_FD_OFFSET;
132440a403fSchristos   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
133440a403fSchristos     abort ();
134440a403fSchristos   return fd;
135440a403fSchristos }
136440a403fSchristos 
137440a403fSchristos 
138440a403fSchristos /* Close a file.  */
139440a403fSchristos 
140440a403fSchristos static int
pex_msdos_close(struct pex_obj * obj,int fd)141440a403fSchristos pex_msdos_close (struct pex_obj *obj, int fd)
142440a403fSchristos {
143440a403fSchristos   struct pex_msdos *ms;
144440a403fSchristos   int fdinex;
145440a403fSchristos 
146440a403fSchristos   ms = (struct pex_msdos *) obj->sysdep;
147440a403fSchristos   fdindex = pe_msdos_fdindex (ms, fd);
148440a403fSchristos   free (ms->files[fdindex]);
149440a403fSchristos   ms->files[fdindex] = NULL;
150440a403fSchristos }
151440a403fSchristos 
152440a403fSchristos /* Execute a child.  */
153440a403fSchristos 
154440a403fSchristos static pid_t
pex_msdos_exec_child(struct pex_obj * obj,int flags,const char * executable,char * const * argv,char * const * env,int in,int out,int toclose ATTRIBUTE_UNUSED,int errdes ATTRIBUTE_UNUSED,const char ** errmsg,int * err)155440a403fSchristos pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
156440a403fSchristos 		      char * const * argv, char * const * env, int in, int out,
157440a403fSchristos 		      int toclose ATTRIBUTE_UNUSED,
158440a403fSchristos 		      int errdes ATTRIBUTE_UNUSED, const char **errmsg,
159440a403fSchristos 		      int *err)
160440a403fSchristos {
161440a403fSchristos   struct pex_msdos *ms;
162440a403fSchristos   char *temp_base;
163440a403fSchristos   int temp_base_allocated;
164440a403fSchristos   char *rf;
165440a403fSchristos   int inindex;
166440a403fSchristos   char *infile;
167440a403fSchristos   int outindex;
168440a403fSchristos   char *outfile;
169440a403fSchristos   char *scmd;
170440a403fSchristos   FILE *argfile;
171440a403fSchristos   int i;
172440a403fSchristos   int status;
173440a403fSchristos 
174440a403fSchristos   ms = (struct pex_msdos *) obj->sysdep;
175440a403fSchristos 
176440a403fSchristos   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
177440a403fSchristos      and PEX_STDERR_TO_STDOUT.  */
178440a403fSchristos 
179440a403fSchristos   temp_base = obj->temp_base;
180440a403fSchristos   if (temp_base != NULL)
181440a403fSchristos     temp_base_allocated = 0;
182440a403fSchristos   else
183440a403fSchristos     {
184440a403fSchristos       temp_base = choose_temp_base ();
185440a403fSchristos       temp_base_allocated = 1;
186440a403fSchristos     }
187440a403fSchristos 
188440a403fSchristos   rf = concat (temp_base, ".gp", NULL);
189440a403fSchristos 
190440a403fSchristos   if (temp_base_allocated)
191440a403fSchristos     free (temp_base);
192440a403fSchristos 
193440a403fSchristos   if (in == STDIN_FILE_NO)
194440a403fSchristos     {
195440a403fSchristos       inindex = -1;
196440a403fSchristos       infile = "";
197440a403fSchristos     }
198440a403fSchristos   else
199440a403fSchristos     {
200440a403fSchristos       inindex = pex_msdos_fdindex (ms, in);
201440a403fSchristos       infile = ms->files[inindex];
202440a403fSchristos     }
203440a403fSchristos 
204440a403fSchristos   if (out == STDOUT_FILE_NO)
205440a403fSchristos     {
206440a403fSchristos       outindex = -1;
207440a403fSchristos       outfile = "";
208440a403fSchristos     }
209440a403fSchristos   else
210440a403fSchristos     {
211440a403fSchristos       outindex = pex_msdos_fdindex (ms, out);
212440a403fSchristos       outfile = ms->files[outindex];
213440a403fSchristos     }
214440a403fSchristos 
215440a403fSchristos   scmd = XNEWVEC (char, strlen (program)
216440a403fSchristos 		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
217440a403fSchristos 		  + strlen (rf)
218440a403fSchristos 		  + strlen (infile)
219440a403fSchristos 		  + strlen (outfile)
220440a403fSchristos 		  + 10);
221440a403fSchristos   sprintf (scmd, "%s%s @%s%s%s%s%s",
222440a403fSchristos 	   program,
223440a403fSchristos 	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
224440a403fSchristos 	   rf,
225440a403fSchristos 	   inindex != -1 ? " <" : "",
226440a403fSchristos 	   infile,
227440a403fSchristos 	   outindex != -1 ? " >" : "",
228440a403fSchristos 	   outfile);
229440a403fSchristos 
230440a403fSchristos   argfile = fopen (rf, "w");
231440a403fSchristos   if (argfile == NULL)
232440a403fSchristos     {
233440a403fSchristos       *err = errno;
234440a403fSchristos       free (scmd);
235440a403fSchristos       free (rf);
236440a403fSchristos       *errmsg = "cannot open temporary command file";
237440a403fSchristos       return (pid_t) -1;
238440a403fSchristos     }
239440a403fSchristos 
240440a403fSchristos   for (i = 1; argv[i] != NULL; ++i)
241440a403fSchristos     {
242440a403fSchristos       char *p;
243440a403fSchristos 
244440a403fSchristos       for (p = argv[i]; *p != '\0'; ++p)
245440a403fSchristos 	{
246440a403fSchristos 	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
247440a403fSchristos 	    putc ('\\', argfile);
248440a403fSchristos 	  putc (*p, argfile);
249440a403fSchristos 	}
250440a403fSchristos       putc ('\n', argfile);
251440a403fSchristos     }
252440a403fSchristos 
253440a403fSchristos   fclose (argfile);
254440a403fSchristos 
255440a403fSchristos   status = system (scmd);
256440a403fSchristos 
257440a403fSchristos   if (status == -1)
258440a403fSchristos     {
259440a403fSchristos       *err = errno;
260440a403fSchristos       remove (rf);
261440a403fSchristos       free (scmd);
262440a403fSchristos       free (rf);
263440a403fSchristos       *errmsg = "system";
264440a403fSchristos       return (pid_t) -1;
265440a403fSchristos     }
266440a403fSchristos 
267440a403fSchristos   remove (rf);
268440a403fSchristos   free (scmd);
269440a403fSchristos   free (rf);
270440a403fSchristos 
271440a403fSchristos   /* Save the exit status for later.  When we are called, obj->count
272440a403fSchristos      is the number of children which have executed before this
273440a403fSchristos      one.  */
274440a403fSchristos   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
275440a403fSchristos   ms->statuses[obj->count] = status;
276440a403fSchristos 
277440a403fSchristos   return (pid_t) obj->count;
278440a403fSchristos }
279440a403fSchristos 
280440a403fSchristos /* Wait for a child process to complete.  Actually the child process
281440a403fSchristos    has already completed, and we just need to return the exit
282440a403fSchristos    status.  */
283440a403fSchristos 
284440a403fSchristos static pid_t
pex_msdos_wait(struct pex_obj * obj,pid_t pid,int * status,struct pex_time * time,int done ATTRIBUTE_UNUSED,const char ** errmsg ATTRIBUTE_UNUSED,int * err ATTRIBUTE_UNUSED)285440a403fSchristos pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status,
286440a403fSchristos 		struct pex_time *time, int done ATTRIBUTE_UNUSED,
287440a403fSchristos 		const char **errmsg ATTRIBUTE_UNUSED,
288440a403fSchristos 		int *err ATTRIBUTE_UNUSED)
289440a403fSchristos {
290440a403fSchristos   struct pex_msdos *ms;
291440a403fSchristos 
292440a403fSchristos   ms = (struct pex_msdos *) obj->sysdep;
293440a403fSchristos 
294440a403fSchristos   if (time != NULL)
295440a403fSchristos     memset (time, 0, sizeof *time);
296440a403fSchristos 
297440a403fSchristos   *status = ms->statuses[pid];
298440a403fSchristos 
299440a403fSchristos   return 0;
300440a403fSchristos }
301440a403fSchristos 
302440a403fSchristos /* Clean up the pex_msdos structure.  */
303440a403fSchristos 
304440a403fSchristos static void
pex_msdos_cleanup(struct pex_obj * obj)305440a403fSchristos pex_msdos_cleanup (struct pex_obj  *obj)
306440a403fSchristos {
307440a403fSchristos   struct pex_msdos *ms;
308440a403fSchristos   int i;
309440a403fSchristos 
310440a403fSchristos   ms = (struct pex_msdos *) obj->sysdep;
311440a403fSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
312440a403fSchristos     free (msdos->files[i]);
313440a403fSchristos   free (msdos->statuses);
314440a403fSchristos   free (msdos);
315440a403fSchristos   obj->sysdep = NULL;
316440a403fSchristos }
317