1c5dff60aSchristos /* Utilities to execute a program in a subprocess (possibly linked by pipes
2c5dff60aSchristos    with other subprocesses), and wait for it.  Generic MSDOS specialization.
3*1424dfb3Schristos    Copyright (C) 1996-2020 Free Software Foundation, Inc.
4c5dff60aSchristos 
5c5dff60aSchristos This file is part of the libiberty library.
6c5dff60aSchristos Libiberty is free software; you can redistribute it and/or
7c5dff60aSchristos modify it under the terms of the GNU Library General Public
8c5dff60aSchristos License as published by the Free Software Foundation; either
9c5dff60aSchristos version 2 of the License, or (at your option) any later version.
10c5dff60aSchristos 
11c5dff60aSchristos Libiberty is distributed in the hope that it will be useful,
12c5dff60aSchristos but WITHOUT ANY WARRANTY; without even the implied warranty of
13c5dff60aSchristos MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14c5dff60aSchristos Library General Public License for more details.
15c5dff60aSchristos 
16c5dff60aSchristos You should have received a copy of the GNU Library General Public
17c5dff60aSchristos License along with libiberty; see the file COPYING.LIB.  If not,
18c5dff60aSchristos write to the Free Software Foundation, Inc., 51 Franklin Street - Fifth Floor,
19c5dff60aSchristos Boston, MA 02110-1301, USA.  */
20c5dff60aSchristos 
21c5dff60aSchristos #include "pex-common.h"
22c5dff60aSchristos 
23c5dff60aSchristos #include <stdio.h>
24c5dff60aSchristos #include <errno.h>
25c5dff60aSchristos #ifdef NEED_DECLARATION_ERRNO
26c5dff60aSchristos extern int errno;
27c5dff60aSchristos #endif
28c5dff60aSchristos #ifdef HAVE_STRING_H
29c5dff60aSchristos #include <string.h>
30c5dff60aSchristos #endif
31c5dff60aSchristos #ifdef HAVE_STDLIB_H
32c5dff60aSchristos #include <stdlib.h>
33c5dff60aSchristos #endif
34c5dff60aSchristos 
35c5dff60aSchristos #include "safe-ctype.h"
36c5dff60aSchristos #include <process.h>
37c5dff60aSchristos 
38c5dff60aSchristos /* The structure we keep in obj->sysdep.  */
39c5dff60aSchristos 
40c5dff60aSchristos #define PEX_MSDOS_FILE_COUNT 3
41c5dff60aSchristos 
42c5dff60aSchristos #define PEX_MSDOS_FD_OFFSET 10
43c5dff60aSchristos 
44c5dff60aSchristos struct pex_msdos
45c5dff60aSchristos {
46c5dff60aSchristos   /* An array of file names.  We refer to these using file descriptors
47c5dff60aSchristos      of 10 + array index.  */
48c5dff60aSchristos   const char *files[PEX_MSDOS_FILE_COUNT];
49c5dff60aSchristos   /* Exit statuses of programs which have been run.  */
50c5dff60aSchristos   int *statuses;
51c5dff60aSchristos };
52c5dff60aSchristos 
53c5dff60aSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
54c5dff60aSchristos static int pex_msdos_open (struct pex_obj *, const char *, int);
55c5dff60aSchristos static int pex_msdos_fdindex (struct pex_msdos *, int);
56c5dff60aSchristos static pid_t pex_msdos_exec_child (struct pex_obj *, int, const char *,
57c5dff60aSchristos 				  char * const *, char * const *,
58c5dff60aSchristos 				  int, int, int, int,
59c5dff60aSchristos 				  int, const char **, int *);
60c5dff60aSchristos static int pex_msdos_close (struct pex_obj *, int);
61c5dff60aSchristos static pid_t pex_msdos_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
62c5dff60aSchristos 			   int, const char **, int *);
63c5dff60aSchristos static void pex_msdos_cleanup (struct pex_obj *);
64c5dff60aSchristos 
65c5dff60aSchristos /* The list of functions we pass to the common routines.  */
66c5dff60aSchristos 
67c5dff60aSchristos const struct pex_funcs funcs =
68c5dff60aSchristos {
69c5dff60aSchristos   pex_msdos_open,
70c5dff60aSchristos   pex_msdos_open,
71c5dff60aSchristos   pex_msdos_exec_child,
72c5dff60aSchristos   pex_msdos_close,
73c5dff60aSchristos   pex_msdos_wait,
74c5dff60aSchristos   NULL, /* pipe */
75c5dff60aSchristos   NULL, /* fdopenr */
76c5dff60aSchristos   NULL, /* fdopenw */
77c5dff60aSchristos   pex_msdos_cleanup
78c5dff60aSchristos };
79c5dff60aSchristos 
80c5dff60aSchristos /* Return a newly initialized pex_obj structure.  */
81c5dff60aSchristos 
82c5dff60aSchristos struct pex_obj *
pex_init(int flags,const char * pname,const char * tempbase)83c5dff60aSchristos pex_init (int flags, const char *pname, const char *tempbase)
84c5dff60aSchristos {
85c5dff60aSchristos   struct pex_obj *ret;
86c5dff60aSchristos   int i;
87c5dff60aSchristos 
88c5dff60aSchristos   /* MSDOS does not support pipes.  */
89c5dff60aSchristos   flags &= ~ PEX_USE_PIPES;
90c5dff60aSchristos 
91c5dff60aSchristos   ret = pex_init_common (flags, pname, tempbase, funcs);
92c5dff60aSchristos 
93c5dff60aSchristos   ret->sysdep = XNEW (struct pex_msdos);
94c5dff60aSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
95c5dff60aSchristos     ret->files[i] = NULL;
96c5dff60aSchristos   ret->statuses = NULL;
97c5dff60aSchristos 
98c5dff60aSchristos   return ret;
99c5dff60aSchristos }
100c5dff60aSchristos 
101c5dff60aSchristos /* Open a file.  FIXME: We ignore the binary argument, since we have
102c5dff60aSchristos    no way to handle it.  */
103c5dff60aSchristos 
104c5dff60aSchristos static int
pex_msdos_open(struct pex_obj * obj,const char * name,int binary ATTRIBUTE_UNUSED)105c5dff60aSchristos pex_msdos_open (struct pex_obj *obj, const char *name,
106c5dff60aSchristos 		int binary ATTRIBUTE_UNUSED)
107c5dff60aSchristos {
108c5dff60aSchristos   struct pex_msdos *ms;
109c5dff60aSchristos   int i;
110c5dff60aSchristos 
111c5dff60aSchristos   ms = (struct pex_msdos *) obj->sysdep;
112c5dff60aSchristos 
113c5dff60aSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
114c5dff60aSchristos     {
115c5dff60aSchristos       if (ms->files[i] == NULL)
116c5dff60aSchristos 	{
117c5dff60aSchristos 	  ms->files[i] = xstrdup (name);
118c5dff60aSchristos 	  return i + PEX_MSDOS_FD_OFFSET;
119c5dff60aSchristos 	}
120c5dff60aSchristos     }
121c5dff60aSchristos 
122c5dff60aSchristos   abort ();
123c5dff60aSchristos }
124c5dff60aSchristos 
125c5dff60aSchristos /* Get the index into msdos->files associated with an open file
126c5dff60aSchristos    descriptor.  */
127c5dff60aSchristos 
128c5dff60aSchristos static int
pex_msdos_fdindex(struct pex_msdos * ms,int fd)129c5dff60aSchristos pex_msdos_fdindex (struct pex_msdos *ms, int fd)
130c5dff60aSchristos {
131c5dff60aSchristos   fd -= PEX_MSDOS_FD_OFFSET;
132c5dff60aSchristos   if (fd < 0 || fd >= PEX_MSDOS_FILE_COUNT || ms->files[fd] == NULL)
133c5dff60aSchristos     abort ();
134c5dff60aSchristos   return fd;
135c5dff60aSchristos }
136c5dff60aSchristos 
137c5dff60aSchristos 
138c5dff60aSchristos /* Close a file.  */
139c5dff60aSchristos 
140c5dff60aSchristos static int
pex_msdos_close(struct pex_obj * obj,int fd)141c5dff60aSchristos pex_msdos_close (struct pex_obj *obj, int fd)
142c5dff60aSchristos {
143c5dff60aSchristos   struct pex_msdos *ms;
144c5dff60aSchristos   int fdinex;
145c5dff60aSchristos 
146c5dff60aSchristos   ms = (struct pex_msdos *) obj->sysdep;
147c5dff60aSchristos   fdindex = pe_msdos_fdindex (ms, fd);
148c5dff60aSchristos   free (ms->files[fdindex]);
149c5dff60aSchristos   ms->files[fdindex] = NULL;
150c5dff60aSchristos }
151c5dff60aSchristos 
152c5dff60aSchristos /* Execute a child.  */
153c5dff60aSchristos 
154c5dff60aSchristos 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)155c5dff60aSchristos pex_msdos_exec_child (struct pex_obj *obj, int flags, const char *executable,
156c5dff60aSchristos 		      char * const * argv, char * const * env, int in, int out,
157c5dff60aSchristos 		      int toclose ATTRIBUTE_UNUSED,
158c5dff60aSchristos 		      int errdes ATTRIBUTE_UNUSED, const char **errmsg,
159c5dff60aSchristos 		      int *err)
160c5dff60aSchristos {
161c5dff60aSchristos   struct pex_msdos *ms;
162c5dff60aSchristos   char *temp_base;
163c5dff60aSchristos   int temp_base_allocated;
164c5dff60aSchristos   char *rf;
165c5dff60aSchristos   int inindex;
166c5dff60aSchristos   char *infile;
167c5dff60aSchristos   int outindex;
168c5dff60aSchristos   char *outfile;
169c5dff60aSchristos   char *scmd;
170c5dff60aSchristos   FILE *argfile;
171c5dff60aSchristos   int i;
172c5dff60aSchristos   int status;
173c5dff60aSchristos 
174c5dff60aSchristos   ms = (struct pex_msdos *) obj->sysdep;
175c5dff60aSchristos 
176c5dff60aSchristos   /* FIXME: I don't know how to redirect stderr, so we ignore ERRDES
177c5dff60aSchristos      and PEX_STDERR_TO_STDOUT.  */
178c5dff60aSchristos 
179c5dff60aSchristos   temp_base = obj->temp_base;
180c5dff60aSchristos   if (temp_base != NULL)
181c5dff60aSchristos     temp_base_allocated = 0;
182c5dff60aSchristos   else
183c5dff60aSchristos     {
184c5dff60aSchristos       temp_base = choose_temp_base ();
185c5dff60aSchristos       temp_base_allocated = 1;
186c5dff60aSchristos     }
187c5dff60aSchristos 
188c5dff60aSchristos   rf = concat (temp_base, ".gp", NULL);
189c5dff60aSchristos 
190c5dff60aSchristos   if (temp_base_allocated)
191c5dff60aSchristos     free (temp_base);
192c5dff60aSchristos 
193c5dff60aSchristos   if (in == STDIN_FILE_NO)
194c5dff60aSchristos     {
195c5dff60aSchristos       inindex = -1;
196c5dff60aSchristos       infile = "";
197c5dff60aSchristos     }
198c5dff60aSchristos   else
199c5dff60aSchristos     {
200c5dff60aSchristos       inindex = pex_msdos_fdindex (ms, in);
201c5dff60aSchristos       infile = ms->files[inindex];
202c5dff60aSchristos     }
203c5dff60aSchristos 
204c5dff60aSchristos   if (out == STDOUT_FILE_NO)
205c5dff60aSchristos     {
206c5dff60aSchristos       outindex = -1;
207c5dff60aSchristos       outfile = "";
208c5dff60aSchristos     }
209c5dff60aSchristos   else
210c5dff60aSchristos     {
211c5dff60aSchristos       outindex = pex_msdos_fdindex (ms, out);
212c5dff60aSchristos       outfile = ms->files[outindex];
213c5dff60aSchristos     }
214c5dff60aSchristos 
215c5dff60aSchristos   scmd = XNEWVEC (char, strlen (program)
216c5dff60aSchristos 		  + ((flags & PEXECUTE_SEARCH) != 0 ? 4 : 0)
217c5dff60aSchristos 		  + strlen (rf)
218c5dff60aSchristos 		  + strlen (infile)
219c5dff60aSchristos 		  + strlen (outfile)
220c5dff60aSchristos 		  + 10);
221c5dff60aSchristos   sprintf (scmd, "%s%s @%s%s%s%s%s",
222c5dff60aSchristos 	   program,
223c5dff60aSchristos 	   (flags & PEXECUTE_SEARCH) != 0 ? ".exe" : "",
224c5dff60aSchristos 	   rf,
225c5dff60aSchristos 	   inindex != -1 ? " <" : "",
226c5dff60aSchristos 	   infile,
227c5dff60aSchristos 	   outindex != -1 ? " >" : "",
228c5dff60aSchristos 	   outfile);
229c5dff60aSchristos 
230c5dff60aSchristos   argfile = fopen (rf, "w");
231c5dff60aSchristos   if (argfile == NULL)
232c5dff60aSchristos     {
233c5dff60aSchristos       *err = errno;
234c5dff60aSchristos       free (scmd);
235c5dff60aSchristos       free (rf);
236c5dff60aSchristos       *errmsg = "cannot open temporary command file";
237c5dff60aSchristos       return (pid_t) -1;
238c5dff60aSchristos     }
239c5dff60aSchristos 
240c5dff60aSchristos   for (i = 1; argv[i] != NULL; ++i)
241c5dff60aSchristos     {
242c5dff60aSchristos       char *p;
243c5dff60aSchristos 
244c5dff60aSchristos       for (p = argv[i]; *p != '\0'; ++p)
245c5dff60aSchristos 	{
246c5dff60aSchristos 	  if (*p == '"' || *p == '\'' || *p == '\\' || ISSPACE (*p))
247c5dff60aSchristos 	    putc ('\\', argfile);
248c5dff60aSchristos 	  putc (*p, argfile);
249c5dff60aSchristos 	}
250c5dff60aSchristos       putc ('\n', argfile);
251c5dff60aSchristos     }
252c5dff60aSchristos 
253c5dff60aSchristos   fclose (argfile);
254c5dff60aSchristos 
255c5dff60aSchristos   status = system (scmd);
256c5dff60aSchristos 
257c5dff60aSchristos   if (status == -1)
258c5dff60aSchristos     {
259c5dff60aSchristos       *err = errno;
260c5dff60aSchristos       remove (rf);
261c5dff60aSchristos       free (scmd);
262c5dff60aSchristos       free (rf);
263c5dff60aSchristos       *errmsg = "system";
264c5dff60aSchristos       return (pid_t) -1;
265c5dff60aSchristos     }
266c5dff60aSchristos 
267c5dff60aSchristos   remove (rf);
268c5dff60aSchristos   free (scmd);
269c5dff60aSchristos   free (rf);
270c5dff60aSchristos 
271c5dff60aSchristos   /* Save the exit status for later.  When we are called, obj->count
272c5dff60aSchristos      is the number of children which have executed before this
273c5dff60aSchristos      one.  */
274c5dff60aSchristos   ms->statuses = XRESIZEVEC(int, ms->statuses, obj->count + 1);
275c5dff60aSchristos   ms->statuses[obj->count] = status;
276c5dff60aSchristos 
277c5dff60aSchristos   return (pid_t) obj->count;
278c5dff60aSchristos }
279c5dff60aSchristos 
280c5dff60aSchristos /* Wait for a child process to complete.  Actually the child process
281c5dff60aSchristos    has already completed, and we just need to return the exit
282c5dff60aSchristos    status.  */
283c5dff60aSchristos 
284c5dff60aSchristos 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)285c5dff60aSchristos pex_msdos_wait (struct pex_obj *obj, pid_t pid, int *status,
286c5dff60aSchristos 		struct pex_time *time, int done ATTRIBUTE_UNUSED,
287c5dff60aSchristos 		const char **errmsg ATTRIBUTE_UNUSED,
288c5dff60aSchristos 		int *err ATTRIBUTE_UNUSED)
289c5dff60aSchristos {
290c5dff60aSchristos   struct pex_msdos *ms;
291c5dff60aSchristos 
292c5dff60aSchristos   ms = (struct pex_msdos *) obj->sysdep;
293c5dff60aSchristos 
294c5dff60aSchristos   if (time != NULL)
295c5dff60aSchristos     memset (time, 0, sizeof *time);
296c5dff60aSchristos 
297c5dff60aSchristos   *status = ms->statuses[pid];
298c5dff60aSchristos 
299c5dff60aSchristos   return 0;
300c5dff60aSchristos }
301c5dff60aSchristos 
302c5dff60aSchristos /* Clean up the pex_msdos structure.  */
303c5dff60aSchristos 
304c5dff60aSchristos static void
pex_msdos_cleanup(struct pex_obj * obj)305c5dff60aSchristos pex_msdos_cleanup (struct pex_obj  *obj)
306c5dff60aSchristos {
307c5dff60aSchristos   struct pex_msdos *ms;
308c5dff60aSchristos   int i;
309c5dff60aSchristos 
310c5dff60aSchristos   ms = (struct pex_msdos *) obj->sysdep;
311c5dff60aSchristos   for (i = 0; i < PEX_MSDOS_FILE_COUNT; ++i)
312c5dff60aSchristos     free (msdos->files[i]);
313c5dff60aSchristos   free (msdos->statuses);
314c5dff60aSchristos   free (msdos);
315c5dff60aSchristos   obj->sysdep = NULL;
316c5dff60aSchristos }
317