server.c 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306
  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. if (getcwd (buff, MAXPATHLEN + 1) == NULL)
  173. buff[0] = 0;
  174. p_cur_dir = xstrdup (buff);
  175. }
  176. /*
  177. * find_shell
  178. *
  179. * Locate a shell suitable for use. For various reasons
  180. * (like the use of "trap" in server_setup(), it must be a
  181. * Bourne-like shell.
  182. *
  183. * Most of the time, /bin/sh is preferred, but sometimes
  184. * it's quite broken (like on Ultrix). autoconf lets you
  185. * override with $CONFIG_SHELL, so we do the same.
  186. */
  187. static const char *
  188. find_shell (void)
  189. {
  190. char * shell = getenv ("CONFIG_SHELL");
  191. if (shell)
  192. return shell;
  193. return "/bin/sh";
  194. }
  195. /*
  196. * run_shell
  197. *
  198. * Run a shell command on the server. The command string
  199. * passed in is wrapped inside the sequence:
  200. *
  201. * cd <original directory>
  202. * <command string>
  203. * echo
  204. * echo <end-of-command-marker>
  205. *
  206. * This ensures that all commands start at a known place in
  207. * the directory structure, that any incomplete output lines
  208. * are completed and that our special marker sequence appears on
  209. * a line by itself. We have chosen a marker that is
  210. * excessively unlikely to be reproduced in normal output:
  211. *
  212. * "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd"
  213. */
  214. char *
  215. run_shell (const char* pz_cmd)
  216. {
  217. tSCC zNoServer[] = "Server not running, cannot run:\n%s\n\n";
  218. t_bool retry = BOOL_TRUE;
  219. do_retry:
  220. /* IF the shell server process is not running yet,
  221. THEN try to start it. */
  222. if (server_id == NULLPROCESS)
  223. {
  224. def_args[0] = find_shell ();
  225. server_id = proc2_fopen (&server_pair, def_args);
  226. if (server_id > 0)
  227. server_setup ();
  228. }
  229. /* IF it is still not running, THEN return the nil string. */
  230. if (server_id <= 0)
  231. {
  232. fprintf (stderr, zNoServer, pz_cmd);
  233. return XCNEW (char);
  234. }
  235. /* Make sure the process will pay attention to us, send the
  236. supplied command, and then have it output a special marker that
  237. we can find. */
  238. fprintf (server_pair.pf_write, "cd \"%s\"\n%s\n\necho\necho %s\n",
  239. p_cur_dir, pz_cmd, z_done);
  240. fflush (server_pair.pf_write);
  241. /* IF the server died and we received a SIGPIPE,
  242. THEN return an empty string. */
  243. if (server_id == NULLPROCESS)
  244. {
  245. fprintf (stderr, zNoServer, pz_cmd);
  246. return XCNEW (char);
  247. }
  248. /* Now try to read back all the data. If we fail due to either a
  249. sigpipe or sigalrm (timeout), we will return the nil string. */
  250. {
  251. char *pz = load_data (server_pair.pf_read);
  252. if (pz == (char *) NULL)
  253. {
  254. close_server ();
  255. if (retry)
  256. {
  257. retry = BOOL_FALSE;
  258. goto do_retry;
  259. }
  260. fprintf (stderr, "CLOSING SHELL SERVER - command failure:\n\t%s\n",
  261. pz_cmd);
  262. pz = XCNEW (char);
  263. }
  264. #ifdef DEBUG
  265. fprintf( stderr, "run_shell command success: %s\n", pz );
  266. #endif
  267. return pz;
  268. }
  269. }