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