pex-msdos.c 7.2 KB

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