GCC with OpenMP stream-computing extension and BatchQueue algorithm
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
8.5 KiB

  1. /*
  2. * server.c Set up and handle communications with a server process.
  3. *
  4. * Server Handling copyright 1992-1999, 2001 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 volatile enum t_bool read_pipe_timeout;
  50. STATIC pid_t server_master_pid = NOPROCESS;
  51. tSCC* def_args[] =
  52. { (char *) NULL, (char *) NULL };
  53. STATIC t_pf_pair server_pair =
  54. { (FILE *) NULL, (FILE *) NULL };
  55. STATIC pid_t server_id = NULLPROCESS;
  56. /*
  57. * Arbitrary text that should not be found in the shell output.
  58. * It must be a single line and appear verbatim at the start of
  59. * the terminating output line.
  60. */
  61. tSCC z_done[] = "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd";
  62. tSCC* p_cur_dir = (char *) NULL;
  63. /*
  64. * load_data
  65. *
  66. * Read data from a file pointer (a pipe to a process in this context)
  67. * until we either get EOF or we get a marker line back.
  68. * The read data are stored in a malloc-ed string that is truncated
  69. * to size at the end. Input is assumed to be an ASCII string.
  70. */
  71. static char *
  72. load_data (FILE* fp)
  73. {
  74. char *pz_text;
  75. size_t text_size;
  76. char *pz_scan;
  77. char z_line[1024];
  78. t_bool got_done = BOOL_FALSE;
  79. text_size = sizeof (z_line) * 2;
  80. pz_scan = pz_text = XNEWVEC (char, text_size);
  81. for (;;)
  82. {
  83. size_t used_ct;
  84. alarm (10);
  85. read_pipe_timeout = BOOL_FALSE;
  86. if (fgets (z_line, sizeof (z_line), fp) == (char *) NULL)
  87. break;
  88. if (strncmp (z_line, z_done, sizeof (z_done) - 1) == 0)
  89. {
  90. got_done = BOOL_TRUE;
  91. break;
  92. }
  93. strcpy (pz_scan, z_line);
  94. pz_scan += strlen (z_line);
  95. used_ct = (size_t) (pz_scan - pz_text);
  96. if (text_size - used_ct < sizeof (z_line))
  97. {
  98. size_t off = (size_t) (pz_scan - pz_text);
  99. text_size += 4096;
  100. pz_text = XRESIZEVEC (char, pz_text, text_size);
  101. pz_scan = pz_text + off;
  102. }
  103. }
  104. alarm (0);
  105. if (read_pipe_timeout || ! got_done)
  106. {
  107. free ((void *) pz_text);
  108. return (char *) NULL;
  109. }
  110. while ((pz_scan > pz_text) && ISSPACE (pz_scan[-1]))
  111. pz_scan--;
  112. *pz_scan = NUL;
  113. return XRESIZEVEC (char, pz_text, strlen (pz_text) + 1);
  114. }
  115. /*
  116. * close_server
  117. *
  118. * Make certain the server process is dead, close the
  119. * pipes to it and from it, finally NULL out the file pointers
  120. */
  121. void
  122. close_server (void)
  123. {
  124. if ( (server_id != NULLPROCESS)
  125. && (server_master_pid == getpid ()))
  126. {
  127. kill ((pid_t) server_id, SIGKILL);
  128. server_id = NULLPROCESS;
  129. server_master_pid = NOPROCESS;
  130. fclose (server_pair.pf_read);
  131. fclose (server_pair.pf_write);
  132. server_pair.pf_read = server_pair.pf_write = (FILE *) NULL;
  133. }
  134. }
  135. /*
  136. * sig_handler really only handles the timeout and pipe signals.
  137. * This ensures that we do not wait forever on a request
  138. * to our server, and also that if the server dies, we do not
  139. * die from a sigpipe problem.
  140. */
  141. static void
  142. sig_handler (int signo ATTRIBUTE_UNUSED)
  143. {
  144. #ifdef DEBUG
  145. /* FIXME: this is illegal to do in a signal handler. */
  146. fprintf (stderr,
  147. "fixincl ERROR: sig_handler: killed pid %ld due to %s\n",
  148. (long) server_id, signo == SIGPIPE ? "SIGPIPE" : "SIGALRM");
  149. #endif
  150. close_server ();
  151. read_pipe_timeout = BOOL_TRUE;
  152. }
  153. /*
  154. * server_setup Establish the signal handler for PIPE and ALARM.
  155. * Also establishes the current directory to give to the
  156. * server process at the start of every server command.
  157. */
  158. static void
  159. server_setup (void)
  160. {
  161. static int atexit_done = 0;
  162. char buff [MAXPATHLEN + 1];
  163. if (atexit_done++ == 0)
  164. atexit (close_server);
  165. else
  166. fputs ("NOTE: server restarted\n", stderr);
  167. server_master_pid = getpid ();
  168. signal (SIGPIPE, sig_handler);
  169. signal (SIGALRM, sig_handler);
  170. fputs ("trap : 1\n", server_pair.pf_write);
  171. fflush (server_pair.pf_write);
  172. getcwd (buff, MAXPATHLEN + 1);
  173. p_cur_dir = xstrdup (buff);
  174. }
  175. /*
  176. * find_shell
  177. *
  178. * Locate a shell suitable for use. For various reasons
  179. * (like the use of "trap" in server_setup(), it must be a
  180. * Bourne-like shell.
  181. *
  182. * Most of the time, /bin/sh is preferred, but sometimes
  183. * it's quite broken (like on Ultrix). autoconf lets you
  184. * override with $CONFIG_SHELL, so we do the same.
  185. */
  186. static const char *
  187. find_shell (void)
  188. {
  189. char * shell = getenv ("CONFIG_SHELL");
  190. if (shell)
  191. return shell;
  192. return "/bin/sh";
  193. }
  194. /*
  195. * run_shell
  196. *
  197. * Run a shell command on the server. The command string
  198. * passed in is wrapped inside the sequence:
  199. *
  200. * cd <original directory>
  201. * <command string>
  202. * echo
  203. * echo <end-of-command-marker>
  204. *
  205. * This ensures that all commands start at a known place in
  206. * the directory structure, that any incomplete output lines
  207. * are completed and that our special marker sequence appears on
  208. * a line by itself. We have chosen a marker that is
  209. * excessively unlikely to be reproduced in normal output:
  210. *
  211. * "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd"
  212. */
  213. char *
  214. run_shell (const char* pz_cmd)
  215. {
  216. tSCC zNoServer[] = "Server not running, cannot run:\n%s\n\n";
  217. t_bool retry = BOOL_TRUE;
  218. do_retry:
  219. /* IF the shell server process is not running yet,
  220. THEN try to start it. */
  221. if (server_id == NULLPROCESS)
  222. {
  223. def_args[0] = find_shell ();
  224. server_id = proc2_fopen (&server_pair, def_args);
  225. if (server_id > 0)
  226. server_setup ();
  227. }
  228. /* IF it is still not running, THEN return the nil string. */
  229. if (server_id <= 0)
  230. {
  231. fprintf (stderr, zNoServer, pz_cmd);
  232. return XCNEW (char);
  233. }
  234. /* Make sure the process will pay attention to us, send the
  235. supplied command, and then have it output a special marker that
  236. we can find. */
  237. fprintf (server_pair.pf_write, "cd \"%s\"\n%s\n\necho\necho %s\n",
  238. p_cur_dir, pz_cmd, z_done);
  239. fflush (server_pair.pf_write);
  240. /* IF the server died and we received a SIGPIPE,
  241. THEN return an empty string. */
  242. if (server_id == NULLPROCESS)
  243. {
  244. fprintf (stderr, zNoServer, pz_cmd);
  245. return XCNEW (char);
  246. }
  247. /* Now try to read back all the data. If we fail due to either a
  248. sigpipe or sigalrm (timeout), we will return the nil string. */
  249. {
  250. char *pz = load_data (server_pair.pf_read);
  251. if (pz == (char *) NULL)
  252. {
  253. close_server ();
  254. if (retry)
  255. {
  256. retry = BOOL_FALSE;
  257. goto do_retry;
  258. }
  259. fprintf (stderr, "CLOSING SHELL SERVER - command failure:\n\t%s\n",
  260. pz_cmd);
  261. pz = XCNEW (char);
  262. }
  263. #ifdef DEBUG
  264. fprintf( stderr, "run_shell command success: %s\n", pz );
  265. #endif
  266. return pz;
  267. }
  268. }