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