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