procopen.c 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. /*
  2. * server.c Set up and handle communications with a server process.
  3. *
  4. * Server Handling copyright 1992-1999, 2004 The Free Software Foundation
  5. *
  6. * Server Handling is free software.
  7. * You may redistribute it and/or modify it under the terms of the
  8. * GNU General Public License, as published by the Free Software
  9. * Foundation; either version 2, or (at your option) any later version.
  10. *
  11. * Server Handling is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with Server Handling. See the file "COPYING". If not,
  18. * write to: The Free Software Foundation, Inc.,
  19. * 51 Franklin Street, Fifth Floor,
  20. * Boston, MA 02110-1301, USA.
  21. *
  22. * As a special exception, The Free Software Foundation gives
  23. * permission for additional uses of the text contained in his release
  24. * of ServerHandler.
  25. *
  26. * The exception is that, if you link the ServerHandler library with other
  27. * files to produce an executable, this does not by itself cause the
  28. * resulting executable to be covered by the GNU General Public License.
  29. * Your use of that executable is in no way restricted on account of
  30. * linking the ServerHandler library code into it.
  31. *
  32. * This exception does not however invalidate any other reasons why
  33. * the executable file might be covered by the GNU General Public License.
  34. *
  35. * This exception applies only to the code released by The Free
  36. * Software Foundation under the name ServerHandler. If you copy code
  37. * from other sources under the General Public License into a copy of
  38. * ServerHandler, as the General Public License permits, the exception
  39. * does not apply to the code that you add in this way. To avoid
  40. * misleading anyone as to the status of such modified files, you must
  41. * delete this exception notice from them.
  42. *
  43. * If you write modifications of your own for ServerHandler, it is your
  44. * choice whether to permit this exception to apply to your modifications.
  45. * If you do not wish that, delete this exception notice.
  46. */
  47. #include "fixlib.h"
  48. #include "server.h"
  49. STATIC const char* def_args[] =
  50. { (char *) NULL, (char *) NULL };
  51. /*
  52. * chain_open
  53. *
  54. * Given an FD for an inferior process to use as stdin,
  55. * start that process and return a NEW FD that that process
  56. * will use for its stdout. Requires the argument vector
  57. * for the new process and, optionally, a pointer to a place
  58. * to store the child's process id.
  59. */
  60. int
  61. chain_open (int stdin_fd, tCC** pp_args, pid_t* p_child)
  62. {
  63. t_fd_pair stdout_pair;
  64. pid_t ch_id;
  65. tCC *pz_cmd;
  66. stdout_pair.read_fd = stdout_pair.write_fd = -1;
  67. /*
  68. * Create a pipe it will be the child process' stdout,
  69. * and the parent will read from it.
  70. */
  71. if (pipe ((int *) &stdout_pair) < 0)
  72. {
  73. if (p_child != (pid_t *) NULL)
  74. *p_child = NOPROCESS;
  75. return -1;
  76. }
  77. /*
  78. * If we did not get an arg list, use the default
  79. */
  80. if (pp_args == (tCC **) NULL)
  81. pp_args = def_args;
  82. /*
  83. * If the arg list does not have a program,
  84. * assume the "SHELL" from the environment, or, failing
  85. * that, then sh. Set argv[0] to whatever we decided on.
  86. */
  87. if (pz_cmd = *pp_args,
  88. (pz_cmd == (char *) NULL) || (*pz_cmd == '\0'))
  89. {
  90. pz_cmd = getenv ("SHELL");
  91. if (pz_cmd == (char *) NULL)
  92. pz_cmd = "sh";
  93. }
  94. #ifdef DEBUG_PRINT
  95. printf ("START: %s\n", pz_cmd);
  96. {
  97. int idx = 0;
  98. while (pp_args[++idx] != (char *) NULL)
  99. printf (" ARG %2d: %s\n", idx, pp_args[idx]);
  100. }
  101. #endif
  102. /*
  103. * Call fork() and see which process we become
  104. */
  105. ch_id = fork ();
  106. switch (ch_id)
  107. {
  108. case NOPROCESS: /* parent - error in call */
  109. close (stdout_pair.read_fd);
  110. close (stdout_pair.write_fd);
  111. if (p_child != (pid_t *) NULL)
  112. *p_child = NOPROCESS;
  113. return -1;
  114. default: /* parent - return opposite FD's */
  115. if (p_child != (pid_t *) NULL)
  116. *p_child = ch_id;
  117. #ifdef DEBUG_PRINT
  118. printf ("for pid %d: stdin from %d, stdout to %d\n"
  119. "for parent: read from %d\n",
  120. ch_id, stdin_fd, stdout_pair.write_fd, stdout_pair.read_fd);
  121. #endif
  122. close (stdin_fd);
  123. close (stdout_pair.write_fd);
  124. return stdout_pair.read_fd;
  125. case NULLPROCESS: /* child - continue processing */
  126. break;
  127. }
  128. /*
  129. * Close the pipe end handed back to the parent process
  130. */
  131. close (stdout_pair.read_fd);
  132. /*
  133. * Close our current stdin and stdout
  134. */
  135. close (STDIN_FILENO);
  136. close (STDOUT_FILENO);
  137. /*
  138. * Make the fd passed in the stdin, and the write end of
  139. * the new pipe become the stdout.
  140. */
  141. dup2 (stdout_pair.write_fd, STDOUT_FILENO);
  142. dup2 (stdin_fd, STDIN_FILENO);
  143. if (*pp_args == (char *) NULL)
  144. *pp_args = pz_cmd;
  145. execvp (pz_cmd, (char**)pp_args);
  146. fprintf (stderr, "Error %d: Could not execvp( '%s', ... ): %s\n",
  147. errno, pz_cmd, xstrerror (errno));
  148. exit (EXIT_PANIC);
  149. }
  150. /*
  151. * proc2_open
  152. *
  153. * Given a pointer to an argument vector, start a process and
  154. * place its stdin and stdout file descriptors into an fd pair
  155. * structure. The "write_fd" connects to the inferior process
  156. * stdin, and the "read_fd" connects to its stdout. The calling
  157. * process should write to "write_fd" and read from "read_fd".
  158. * The return value is the process id of the created process.
  159. */
  160. pid_t
  161. proc2_open (t_fd_pair* p_pair, tCC** pp_args)
  162. {
  163. pid_t ch_id;
  164. /* Create a bi-directional pipe. Writes on 0 arrive on 1 and vice
  165. versa, so the parent and child processes will read and write to
  166. opposite FD's. */
  167. if (pipe ((int *) p_pair) < 0)
  168. return NOPROCESS;
  169. p_pair->read_fd = chain_open (p_pair->read_fd, pp_args, &ch_id);
  170. if (ch_id == NOPROCESS)
  171. close (p_pair->write_fd);
  172. return ch_id;
  173. }
  174. /*
  175. * proc2_fopen
  176. *
  177. * Identical to "proc2_open()", except that the "fd"'s are
  178. * "fdopen(3)"-ed into file pointers instead.
  179. */
  180. pid_t
  181. proc2_fopen (t_pf_pair* pf_pair, tCC** pp_args)
  182. {
  183. t_fd_pair fd_pair;
  184. pid_t ch_id = proc2_open (&fd_pair, pp_args);
  185. if (ch_id == NOPROCESS)
  186. return ch_id;
  187. pf_pair->pf_read = fdopen (fd_pair.read_fd, "r");
  188. pf_pair->pf_write = fdopen (fd_pair.write_fd, "w");
  189. return ch_id;
  190. }