pex-djgpp.c 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. /* Utilities to execute a program in a subprocess (possibly linked by pipes
  2. with other subprocesses), and wait for it. DJGPP 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_STDLIB_H
  24. #include <stdlib.h>
  25. #endif
  26. #include <string.h>
  27. #include <fcntl.h>
  28. #include <unistd.h>
  29. #include <sys/stat.h>
  30. #include <process.h>
  31. /* Use ECHILD if available, otherwise use EINVAL. */
  32. #ifdef ECHILD
  33. #define PWAIT_ERROR ECHILD
  34. #else
  35. #define PWAIT_ERROR EINVAL
  36. #endif
  37. static int pex_djgpp_open_read (struct pex_obj *, const char *, int);
  38. static int pex_djgpp_open_write (struct pex_obj *, const char *, int, int);
  39. static pid_t pex_djgpp_exec_child (struct pex_obj *, int, const char *,
  40. char * const *, char * const *,
  41. int, int, int, int,
  42. const char **, int *);
  43. static int pex_djgpp_close (struct pex_obj *, int);
  44. static pid_t pex_djgpp_wait (struct pex_obj *, pid_t, int *, struct pex_time *,
  45. int, const char **, int *);
  46. /* The list of functions we pass to the common routines. */
  47. const struct pex_funcs funcs =
  48. {
  49. pex_djgpp_open_read,
  50. pex_djgpp_open_write,
  51. pex_djgpp_exec_child,
  52. pex_djgpp_close,
  53. pex_djgpp_wait,
  54. NULL, /* pipe */
  55. NULL, /* fdopenr */
  56. NULL, /* fdopenw */
  57. NULL /* cleanup */
  58. };
  59. /* Return a newly initialized pex_obj structure. */
  60. struct pex_obj *
  61. pex_init (int flags, const char *pname, const char *tempbase)
  62. {
  63. /* DJGPP does not support pipes. */
  64. flags &= ~ PEX_USE_PIPES;
  65. return pex_init_common (flags, pname, tempbase, &funcs);
  66. }
  67. /* Open a file for reading. */
  68. static int
  69. pex_djgpp_open_read (struct pex_obj *obj ATTRIBUTE_UNUSED,
  70. const char *name, int binary)
  71. {
  72. return open (name, O_RDONLY | (binary ? O_BINARY : O_TEXT));
  73. }
  74. /* Open a file for writing. */
  75. static int
  76. pex_djgpp_open_write (struct pex_obj *obj ATTRIBUTE_UNUSED,
  77. const char *name, int binary, int append)
  78. {
  79. /* Note that we can't use O_EXCL here because gcc may have already
  80. created the temporary file via make_temp_file. */
  81. if (append)
  82. return -1;
  83. return open (name,
  84. (O_WRONLY | O_CREAT | O_TRUNC
  85. | (binary ? O_BINARY : O_TEXT)),
  86. S_IRUSR | S_IWUSR);
  87. }
  88. /* Close a file. */
  89. static int
  90. pex_djgpp_close (struct pex_obj *obj ATTRIBUTE_UNUSED, int fd)
  91. {
  92. return close (fd);
  93. }
  94. /* Execute a child. */
  95. static pid_t
  96. pex_djgpp_exec_child (struct pex_obj *obj, int flags, const char *executable,
  97. char * const * argv, char * const * env,
  98. int in, int out, int errdes,
  99. int toclose ATTRIBUTE_UNUSED, const char **errmsg,
  100. int *err)
  101. {
  102. int org_in, org_out, org_errdes;
  103. int status;
  104. int *statuses;
  105. org_in = -1;
  106. org_out = -1;
  107. org_errdes = -1;
  108. if (in != STDIN_FILE_NO)
  109. {
  110. org_in = dup (STDIN_FILE_NO);
  111. if (org_in < 0)
  112. {
  113. *err = errno;
  114. *errmsg = "dup";
  115. return (pid_t) -1;
  116. }
  117. if (dup2 (in, STDIN_FILE_NO) < 0)
  118. {
  119. *err = errno;
  120. *errmsg = "dup2";
  121. return (pid_t) -1;
  122. }
  123. if (close (in) < 0)
  124. {
  125. *err = errno;
  126. *errmsg = "close";
  127. return (pid_t) -1;
  128. }
  129. }
  130. if (out != STDOUT_FILE_NO)
  131. {
  132. org_out = dup (STDOUT_FILE_NO);
  133. if (org_out < 0)
  134. {
  135. *err = errno;
  136. *errmsg = "dup";
  137. return (pid_t) -1;
  138. }
  139. if (dup2 (out, STDOUT_FILE_NO) < 0)
  140. {
  141. *err = errno;
  142. *errmsg = "dup2";
  143. return (pid_t) -1;
  144. }
  145. if (close (out) < 0)
  146. {
  147. *err = errno;
  148. *errmsg = "close";
  149. return (pid_t) -1;
  150. }
  151. }
  152. if (errdes != STDERR_FILE_NO
  153. || (flags & PEX_STDERR_TO_STDOUT) != 0)
  154. {
  155. org_errdes = dup (STDERR_FILE_NO);
  156. if (org_errdes < 0)
  157. {
  158. *err = errno;
  159. *errmsg = "dup";
  160. return (pid_t) -1;
  161. }
  162. if (dup2 ((flags & PEX_STDERR_TO_STDOUT) != 0 ? STDOUT_FILE_NO : errdes,
  163. STDERR_FILE_NO) < 0)
  164. {
  165. *err = errno;
  166. *errmsg = "dup2";
  167. return (pid_t) -1;
  168. }
  169. if (errdes != STDERR_FILE_NO)
  170. {
  171. if (close (errdes) < 0)
  172. {
  173. *err = errno;
  174. *errmsg = "close";
  175. return (pid_t) -1;
  176. }
  177. }
  178. }
  179. if (env)
  180. status = (((flags & PEX_SEARCH) != 0 ? spawnvpe : spawnve)
  181. (P_WAIT, executable, argv, env));
  182. else
  183. status = (((flags & PEX_SEARCH) != 0 ? spawnvp : spawnv)
  184. (P_WAIT, executable, argv));
  185. if (status == -1)
  186. {
  187. *err = errno;
  188. *errmsg = ((flags & PEX_SEARCH) != 0) ? "spawnvp" : "spawnv";
  189. }
  190. if (in != STDIN_FILE_NO)
  191. {
  192. if (dup2 (org_in, STDIN_FILE_NO) < 0)
  193. {
  194. *err = errno;
  195. *errmsg = "dup2";
  196. return (pid_t) -1;
  197. }
  198. if (close (org_in) < 0)
  199. {
  200. *err = errno;
  201. *errmsg = "close";
  202. return (pid_t) -1;
  203. }
  204. }
  205. if (out != STDOUT_FILE_NO)
  206. {
  207. if (dup2 (org_out, STDOUT_FILE_NO) < 0)
  208. {
  209. *err = errno;
  210. *errmsg = "dup2";
  211. return (pid_t) -1;
  212. }
  213. if (close (org_out) < 0)
  214. {
  215. *err = errno;
  216. *errmsg = "close";
  217. return (pid_t) -1;
  218. }
  219. }
  220. if (errdes != STDERR_FILE_NO
  221. || (flags & PEX_STDERR_TO_STDOUT) != 0)
  222. {
  223. if (dup2 (org_errdes, STDERR_FILE_NO) < 0)
  224. {
  225. *err = errno;
  226. *errmsg = "dup2";
  227. return (pid_t) -1;
  228. }
  229. if (close (org_errdes) < 0)
  230. {
  231. *err = errno;
  232. *errmsg = "close";
  233. return (pid_t) -1;
  234. }
  235. }
  236. /* Save the exit status for later. When we are called, obj->count
  237. is the number of children which have executed before this
  238. one. */
  239. statuses = (int *) obj->sysdep;
  240. statuses = XRESIZEVEC (int, statuses, obj->count + 1);
  241. statuses[obj->count] = status;
  242. obj->sysdep = (void *) statuses;
  243. return (pid_t) obj->count;
  244. }
  245. /* Wait for a child process to complete. Actually the child process
  246. has already completed, and we just need to return the exit
  247. status. */
  248. static pid_t
  249. pex_djgpp_wait (struct pex_obj *obj, pid_t pid, int *status,
  250. struct pex_time *time, int done ATTRIBUTE_UNUSED,
  251. const char **errmsg ATTRIBUTE_UNUSED,
  252. int *err ATTRIBUTE_UNUSED)
  253. {
  254. int *statuses;
  255. if (time != NULL)
  256. memset (time, 0, sizeof *time);
  257. statuses = (int *) obj->sysdep;
  258. *status = statuses[pid];
  259. return 0;
  260. }