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