1 1.1 mrg 2 1.1 mrg /* 3 1.1 mrg * server.c Set up and handle communications with a server process. 4 1.1 mrg * 5 1.1 mrg * Server Handling copyright 1992-1999, 2001 The Free Software Foundation 6 1.1 mrg * 7 1.1 mrg * Server Handling is free software. 8 1.1 mrg * You may redistribute it and/or modify it under the terms of the 9 1.1 mrg * GNU General Public License, as published by the Free Software 10 1.1 mrg * Foundation; either version 2, or (at your option) any later version. 11 1.1 mrg * 12 1.1 mrg * Server Handling is distributed in the hope that it will be useful, 13 1.1 mrg * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 1.1 mrg * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 1.1 mrg * GNU General Public License for more details. 16 1.1 mrg * 17 1.1 mrg * You should have received a copy of the GNU General Public License 18 1.1 mrg * along with Server Handling. See the file "COPYING". If not, 19 1.1 mrg * write to: The Free Software Foundation, Inc., 20 1.1 mrg * 51 Franklin Street, Fifth Floor, 21 1.1 mrg * Boston, MA 02110-1301, USA. 22 1.1 mrg * 23 1.1 mrg * As a special exception, The Free Software Foundation gives 24 1.1 mrg * permission for additional uses of the text contained in his release 25 1.1 mrg * of ServerHandler. 26 1.1 mrg * 27 1.1 mrg * The exception is that, if you link the ServerHandler library with other 28 1.1 mrg * files to produce an executable, this does not by itself cause the 29 1.1 mrg * resulting executable to be covered by the GNU General Public License. 30 1.1 mrg * Your use of that executable is in no way restricted on account of 31 1.1 mrg * linking the ServerHandler library code into it. 32 1.1 mrg * 33 1.1 mrg * This exception does not however invalidate any other reasons why 34 1.1 mrg * the executable file might be covered by the GNU General Public License. 35 1.1 mrg * 36 1.1 mrg * This exception applies only to the code released by The Free 37 1.1 mrg * Software Foundation under the name ServerHandler. If you copy code 38 1.1 mrg * from other sources under the General Public License into a copy of 39 1.1 mrg * ServerHandler, as the General Public License permits, the exception 40 1.1 mrg * does not apply to the code that you add in this way. To avoid 41 1.1 mrg * misleading anyone as to the status of such modified files, you must 42 1.1 mrg * delete this exception notice from them. 43 1.1 mrg * 44 1.1 mrg * If you write modifications of your own for ServerHandler, it is your 45 1.1 mrg * choice whether to permit this exception to apply to your modifications. 46 1.1 mrg * If you do not wish that, delete this exception notice. 47 1.1 mrg */ 48 1.1 mrg 49 1.1 mrg #include "fixlib.h" 50 1.1 mrg #include "server.h" 51 1.1 mrg 52 1.1 mrg STATIC volatile enum t_bool read_pipe_timeout; 53 1.1 mrg STATIC pid_t server_master_pid = NOPROCESS; 54 1.1 mrg 55 1.1 mrg tSCC* def_args[] = 56 1.1 mrg { (char *) NULL, (char *) NULL }; 57 1.1 mrg STATIC t_pf_pair server_pair = 58 1.1 mrg { (FILE *) NULL, (FILE *) NULL }; 59 1.1 mrg STATIC pid_t server_id = NULLPROCESS; 60 1.1 mrg /* 61 1.1 mrg * Arbitrary text that should not be found in the shell output. 62 1.1 mrg * It must be a single line and appear verbatim at the start of 63 1.1 mrg * the terminating output line. 64 1.1 mrg */ 65 1.1 mrg tSCC z_done[] = "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd"; 66 1.1 mrg tSCC* p_cur_dir = (char *) NULL; 67 1.1 mrg 68 1.1 mrg /* 69 1.1 mrg * load_data 70 1.1 mrg * 71 1.1 mrg * Read data from a file pointer (a pipe to a process in this context) 72 1.1 mrg * until we either get EOF or we get a marker line back. 73 1.1 mrg * The read data are stored in a malloc-ed string that is truncated 74 1.1 mrg * to size at the end. Input is assumed to be an ASCII string. 75 1.1 mrg */ 76 1.1 mrg static char * 77 1.1 mrg load_data (FILE* fp) 78 1.1 mrg { 79 1.1 mrg char *pz_text; 80 1.1 mrg size_t text_size; 81 1.1 mrg char *pz_scan; 82 1.1 mrg char z_line[1024]; 83 1.1 mrg t_bool got_done = BOOL_FALSE; 84 1.1 mrg 85 1.1 mrg text_size = sizeof (z_line) * 2; 86 1.1 mrg pz_scan = pz_text = XNEWVEC (char, text_size); 87 1.1 mrg 88 1.1 mrg for (;;) 89 1.1 mrg { 90 1.1 mrg size_t used_ct; 91 1.1 mrg 92 1.1 mrg alarm (10); 93 1.1 mrg read_pipe_timeout = BOOL_FALSE; 94 1.1 mrg if (fgets (z_line, sizeof (z_line), fp) == (char *) NULL) 95 1.1 mrg break; 96 1.1 mrg 97 1.1 mrg if (strncmp (z_line, z_done, sizeof (z_done) - 1) == 0) 98 1.1 mrg { 99 1.1 mrg got_done = BOOL_TRUE; 100 1.1 mrg break; 101 1.1 mrg } 102 1.1 mrg 103 1.1 mrg strcpy (pz_scan, z_line); 104 1.1 mrg pz_scan += strlen (z_line); 105 1.1 mrg used_ct = (size_t) (pz_scan - pz_text); 106 1.1 mrg 107 1.1 mrg if (text_size - used_ct < sizeof (z_line)) 108 1.1 mrg { 109 1.1 mrg size_t off = (size_t) (pz_scan - pz_text); 110 1.1 mrg 111 1.1 mrg text_size += 4096; 112 1.1 mrg pz_text = XRESIZEVEC (char, pz_text, text_size); 113 1.1 mrg pz_scan = pz_text + off; 114 1.1 mrg } 115 1.1 mrg } 116 1.1 mrg 117 1.1 mrg alarm (0); 118 1.1 mrg if (read_pipe_timeout || ! got_done) 119 1.1 mrg { 120 1.1 mrg free ((void *) pz_text); 121 1.1 mrg return (char *) NULL; 122 1.1 mrg } 123 1.1 mrg 124 1.1 mrg while ((pz_scan > pz_text) && ISSPACE (pz_scan[-1])) 125 1.1 mrg pz_scan--; 126 1.1 mrg *pz_scan = NUL; 127 1.1 mrg return XRESIZEVEC (char, pz_text, strlen (pz_text) + 1); 128 1.1 mrg } 129 1.1 mrg 130 1.1 mrg 131 1.1 mrg /* 132 1.1 mrg * close_server 133 1.1 mrg * 134 1.1 mrg * Make certain the server process is dead, close the 135 1.1 mrg * pipes to it and from it, finally NULL out the file pointers 136 1.1 mrg */ 137 1.1 mrg void 138 1.1 mrg close_server (void) 139 1.1 mrg { 140 1.1 mrg if ( (server_id != NULLPROCESS) 141 1.1 mrg && (server_master_pid == getpid ())) 142 1.1 mrg { 143 1.1 mrg kill ((pid_t) server_id, SIGKILL); 144 1.1 mrg server_id = NULLPROCESS; 145 1.1 mrg server_master_pid = NOPROCESS; 146 1.1 mrg fclose (server_pair.pf_read); 147 1.1 mrg fclose (server_pair.pf_write); 148 1.1 mrg server_pair.pf_read = server_pair.pf_write = (FILE *) NULL; 149 1.1 mrg } 150 1.1 mrg } 151 1.1 mrg 152 1.1 mrg /* 153 1.1 mrg * sig_handler really only handles the timeout and pipe signals. 154 1.1 mrg * This ensures that we do not wait forever on a request 155 1.1 mrg * to our server, and also that if the server dies, we do not 156 1.1 mrg * die from a sigpipe problem. 157 1.1 mrg */ 158 1.1 mrg static void 159 1.1 mrg sig_handler (int signo ATTRIBUTE_UNUSED) 160 1.1 mrg { 161 1.1 mrg #ifdef DEBUG 162 1.1 mrg /* FIXME: this is illegal to do in a signal handler. */ 163 1.1 mrg fprintf (stderr, 164 1.1 mrg "fixincl ERROR: sig_handler: killed pid %ld due to %s\n", 165 1.1 mrg (long) server_id, signo == SIGPIPE ? "SIGPIPE" : "SIGALRM"); 166 1.1 mrg #endif 167 1.1 mrg close_server (); 168 1.1 mrg read_pipe_timeout = BOOL_TRUE; 169 1.1 mrg } 170 1.1 mrg 171 1.1 mrg 172 1.1 mrg /* 173 1.1 mrg * server_setup Establish the signal handler for PIPE and ALARM. 174 1.1 mrg * Also establishes the current directory to give to the 175 1.1 mrg * server process at the start of every server command. 176 1.1 mrg */ 177 1.1 mrg static void 178 1.1 mrg server_setup (void) 179 1.1 mrg { 180 1.1 mrg static int atexit_done = 0; 181 1.1 mrg char buff [MAXPATHLEN + 1]; 182 1.1 mrg 183 1.1 mrg if (atexit_done++ == 0) 184 1.1 mrg atexit (close_server); 185 1.1 mrg else 186 1.1 mrg fputs ("NOTE: server restarted\n", stderr); 187 1.1 mrg 188 1.1 mrg server_master_pid = getpid (); 189 1.1 mrg 190 1.1 mrg signal (SIGPIPE, sig_handler); 191 1.1 mrg signal (SIGALRM, sig_handler); 192 1.1 mrg 193 1.1 mrg fputs ("trap : 1\n", server_pair.pf_write); 194 1.1 mrg fflush (server_pair.pf_write); 195 1.5 mrg if (getcwd (buff, MAXPATHLEN + 1) == NULL) 196 1.5 mrg buff[0] = 0; 197 1.1 mrg p_cur_dir = xstrdup (buff); 198 1.1 mrg } 199 1.1 mrg 200 1.1 mrg /* 201 1.1 mrg * find_shell 202 1.1 mrg * 203 1.1 mrg * Locate a shell suitable for use. For various reasons 204 1.1 mrg * (like the use of "trap" in server_setup(), it must be a 205 1.1 mrg * Bourne-like shell. 206 1.1 mrg * 207 1.1 mrg * Most of the time, /bin/sh is preferred, but sometimes 208 1.1 mrg * it's quite broken (like on Ultrix). autoconf lets you 209 1.1 mrg * override with $CONFIG_SHELL, so we do the same. 210 1.1 mrg */ 211 1.1 mrg 212 1.1 mrg static const char * 213 1.1 mrg find_shell (void) 214 1.1 mrg { 215 1.1 mrg char * shell = getenv ("CONFIG_SHELL"); 216 1.1 mrg if (shell) 217 1.1 mrg return shell; 218 1.1 mrg 219 1.1 mrg return "/bin/sh"; 220 1.1 mrg } 221 1.1 mrg 222 1.1 mrg 223 1.1 mrg /* 224 1.1 mrg * run_shell 225 1.1 mrg * 226 1.1 mrg * Run a shell command on the server. The command string 227 1.1 mrg * passed in is wrapped inside the sequence: 228 1.1 mrg * 229 1.1 mrg * cd <original directory> 230 1.1 mrg * <command string> 231 1.1 mrg * echo 232 1.1 mrg * echo <end-of-command-marker> 233 1.1 mrg * 234 1.1 mrg * This ensures that all commands start at a known place in 235 1.1 mrg * the directory structure, that any incomplete output lines 236 1.1 mrg * are completed and that our special marker sequence appears on 237 1.1 mrg * a line by itself. We have chosen a marker that is 238 1.1 mrg * excessively unlikely to be reproduced in normal output: 239 1.1 mrg * 240 1.1 mrg * "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd" 241 1.1 mrg */ 242 1.1 mrg char * 243 1.1 mrg run_shell (const char* pz_cmd) 244 1.1 mrg { 245 1.1 mrg tSCC zNoServer[] = "Server not running, cannot run:\n%s\n\n"; 246 1.1 mrg t_bool retry = BOOL_TRUE; 247 1.1 mrg 248 1.1 mrg do_retry: 249 1.1 mrg /* IF the shell server process is not running yet, 250 1.1 mrg THEN try to start it. */ 251 1.1 mrg if (server_id == NULLPROCESS) 252 1.1 mrg { 253 1.1 mrg def_args[0] = find_shell (); 254 1.1 mrg 255 1.1 mrg server_id = proc2_fopen (&server_pair, def_args); 256 1.1 mrg if (server_id > 0) 257 1.1 mrg server_setup (); 258 1.1 mrg } 259 1.1 mrg 260 1.1 mrg /* IF it is still not running, THEN return the nil string. */ 261 1.1 mrg if (server_id <= 0) 262 1.1 mrg { 263 1.1 mrg fprintf (stderr, zNoServer, pz_cmd); 264 1.1 mrg return XCNEW (char); 265 1.1 mrg } 266 1.1 mrg 267 1.1 mrg /* Make sure the process will pay attention to us, send the 268 1.1 mrg supplied command, and then have it output a special marker that 269 1.1 mrg we can find. */ 270 1.1 mrg fprintf (server_pair.pf_write, "cd \"%s\"\n%s\n\necho\necho %s\n", 271 1.1 mrg p_cur_dir, pz_cmd, z_done); 272 1.1 mrg fflush (server_pair.pf_write); 273 1.1 mrg 274 1.1 mrg /* IF the server died and we received a SIGPIPE, 275 1.1 mrg THEN return an empty string. */ 276 1.1 mrg if (server_id == NULLPROCESS) 277 1.1 mrg { 278 1.1 mrg fprintf (stderr, zNoServer, pz_cmd); 279 1.1 mrg return XCNEW (char); 280 1.1 mrg } 281 1.1 mrg 282 1.1 mrg /* Now try to read back all the data. If we fail due to either a 283 1.1 mrg sigpipe or sigalrm (timeout), we will return the nil string. */ 284 1.1 mrg { 285 1.1 mrg char *pz = load_data (server_pair.pf_read); 286 1.1 mrg 287 1.1 mrg if (pz == (char *) NULL) 288 1.1 mrg { 289 1.1 mrg close_server (); 290 1.1 mrg 291 1.1 mrg if (retry) 292 1.1 mrg { 293 1.1 mrg retry = BOOL_FALSE; 294 1.1 mrg goto do_retry; 295 1.1 mrg } 296 1.1 mrg 297 1.1 mrg fprintf (stderr, "CLOSING SHELL SERVER - command failure:\n\t%s\n", 298 1.1 mrg pz_cmd); 299 1.1 mrg pz = XCNEW (char); 300 1.1 mrg } 301 1.1 mrg #ifdef DEBUG 302 1.1 mrg fprintf( stderr, "run_shell command success: %s\n", pz ); 303 1.1 mrg #endif 304 1.1 mrg return pz; 305 1.1 mrg } 306 1.1 mrg } 307