]> gcc.gnu.org Git - gcc.git/blame - gcc/fixinc/server.c
Daily bump.
[gcc.git] / gcc / fixinc / server.c
CommitLineData
0083c904
BK
1
2/*
3 * $Id: server.c,v 1.2 1998/12/16 21:19:16 law Exp $
4 *
5 * Server Handling copyright 1992-1998 Bruce Korb
6 *
7 * Server Handling is free software.
8 * You may redistribute it and/or modify it under the terms of the
9 * GNU General Public License, as published by the Free Software
10 * Foundation; either version 2, or (at your option) any later version.
11 *
12 * Server Handling is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with Server Handling. See the file "COPYING". If not,
19 * write to: The Free Software Foundation, Inc.,
20 * 59 Temple Place - Suite 330,
21 * Boston, MA 02111-1307, USA.
22 *
23 * As a special exception, Bruce Korb gives permission for additional
24 * uses of the text contained in his release 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 Bruce Korb under
36 * the name ServerHandler. If you copy code from other sources under the
37 * General Public License into a copy of ServerHandler, as the General Public
38 * License permits, the exception does not apply to the code that you add
39 * in this way. To avoid misleading anyone as to the status of such
40 * modified files, you must delete this exception notice from them.
41 *
42 * If you write modifications of your own for ServerHandler, it is your
43 * choice whether to permit this exception to apply to your modifications.
44 * If you do not wish that, delete this exception notice.
45 */
46
47#include <fcntl.h>
48#include <errno.h>
49#include <signal.h>
50#include <stdlib.h>
51#include <string.h>
52#include <ctype.h>
53#include <sys/param.h>
54
55#include "server.h"
56
57#ifdef DEBUG
58#define STATIC
59#else
60#define STATIC static
61#endif
62#ifndef tSCC
63#define tSCC static const char
64#endif
65#ifndef NUL
66#define NUL '\0'
67#endif
68
69STATIC bool readPipeTimeout;
70
71STATIC tpChar defArgs[] =
72{(char *) NULL, "-p", (char *) NULL};
73STATIC tpfPair serverPair =
74{(FILE *) NULL, (FILE *) NULL};
75STATIC pid_t serverId = NULLPROCESS;
76/*
77 * Arbitrary text that should not be found in the shell output.
78 * It must be a single line and appear verbatim at the start of
79 * the terminating output line.
80 */
81tSCC zDone[] = "ShElL-OuTpUt-HaS-bEeN-cOmPlEtEd";
82STATIC tpChar pCurDir = (char *) NULL;
83
84/*
85 * chainOpen
86 *
87 * Given an FD for an inferior process to use as stdin,
88 * start that process and return a NEW FD that that process
89 * will use for its stdout. Requires the argument vector
90 * for the new process and, optionally, a pointer to a place
91 * to store the child's process id.
92 */
93int
94chainOpen (stdinFd, ppArgs, pChild)
95 int stdinFd;
96 tpChar *ppArgs;
97 pid_t *pChild;
98{
99 tFdPair stdoutPair =
100 {-1, -1};
101 pid_t chId;
102 char *pzCmd;
103
104 /*
105 * Create a pipe it will be the child process' stdout,
106 * and the parent will read from it.
107 */
108 if ((pipe ((int *) &stdoutPair) < 0))
109 {
110 if (pChild != (pid_t *) NULL)
111 *pChild = NOPROCESS;
112 return -1;
113 }
114
115 /*
116 * If we did not get an arg list, use the default
117 */
118 if (ppArgs == (tpChar *) NULL)
119 ppArgs = defArgs;
120
121 /*
122 * If the arg list does not have a program,
123 * assume the "SHELL" from the environment, or, failing
124 * that, then sh. Set argv[0] to whatever we decided on.
125 */
126 if (pzCmd = *ppArgs,
127 (pzCmd == (char *) NULL) || (*pzCmd == '\0'))
128 {
129
130 pzCmd = getenv ("SHELL");
131 if (pzCmd == (char *) NULL)
132 pzCmd = "sh";
133 }
134#ifdef DEBUG_PRINT
135 printf ("START: %s\n", pzCmd);
136 {
137 int idx = 0;
138 while (ppArgs[++idx] != (char *) NULL)
139 printf (" ARG %2d: %s\n", idx, ppArgs[idx]);
140 }
141#endif
142 /*
143 * Call fork() and see which process we become
144 */
145 chId = fork ();
146 switch (chId)
147 {
148 case NOPROCESS: /* parent - error in call */
149 close (stdoutPair.readFd);
150 close (stdoutPair.writeFd);
151 if (pChild != (pid_t *) NULL)
152 *pChild = NOPROCESS;
153 return -1;
154
155 default: /* parent - return opposite FD's */
156 if (pChild != (pid_t *) NULL)
157 *pChild = chId;
158#ifdef DEBUG_PRINT
159 printf ("for pid %d: stdin from %d, stdout to %d\n"
160 "for parent: read from %d\n",
161 chId, stdinFd, stdoutPair.writeFd, stdoutPair.readFd);
162#endif
163 close (stdinFd);
164 close (stdoutPair.writeFd);
165 return stdoutPair.readFd;
166
167 case NULLPROCESS: /* child - continue processing */
168 break;
169 }
170
171 /*
172 * Close the pipe end handed back to the parent process
173 */
174 close (stdoutPair.readFd);
175
176 /*
177 * Close our current stdin and stdout
178 */
179 close (STDIN_FILENO);
180 close (STDOUT_FILENO);
181
182 /*
183 * Make the fd passed in the stdin, and the write end of
184 * the new pipe become the stdout.
185 */
186 fcntl (stdoutPair.writeFd, F_DUPFD, STDOUT_FILENO);
187 fcntl (stdinFd, F_DUPFD, STDIN_FILENO);
188
189 if (*ppArgs == (char *) NULL)
190 *ppArgs = pzCmd;
191
192 execvp (pzCmd, ppArgs);
193 fprintf (stderr, "Error %d: Could not execvp( '%s', ... ): %s\n",
194 errno, pzCmd, strerror (errno));
195 exit (EXIT_PANIC);
196}
197
198
199/*
200 * p2open
201 *
202 * Given a pointer to an argument vector, start a process and
203 * place its stdin and stdout file descriptors into an fd pair
204 * structure. The "writeFd" connects to the inferior process
205 * stdin, and the "readFd" connects to its stdout. The calling
206 * process should write to "writeFd" and read from "readFd".
207 * The return value is the process id of the created process.
208 */
209pid_t
210p2open (pPair, ppArgs)
211 tFdPair *pPair;
212 tpChar *ppArgs;
213{
214 pid_t chId;
215
216 /*
217 * Create a bi-directional pipe. Writes on 0 arrive on 1
218 * and vice versa, so the parent and child processes will
219 * read and write to opposite FD's.
220 */
221 if (pipe ((int *) pPair) < 0)
222 return NOPROCESS;
223
224 pPair->readFd = chainOpen (pPair->readFd, ppArgs, &chId);
225 if (chId == NOPROCESS)
226 close (pPair->writeFd);
227
228 return chId;
229}
230
231
232/*
233 * p2fopen
234 *
235 * Identical to "p2open()", except that the "fd"'s are "fdopen(3)"-ed
236 * into file pointers instead.
237 */
238pid_t
239p2fopen (pfPair, ppArgs)
240 tpfPair *pfPair;
241 tpChar *ppArgs;
242{
243 tFdPair fdPair;
244 pid_t chId = p2open (&fdPair, ppArgs);
245
246 if (chId == NOPROCESS)
247 return chId;
248
249 pfPair->pfRead = fdopen (fdPair.readFd, "r");
250 pfPair->pfWrite = fdopen (fdPair.writeFd, "w");
251 return chId;
252}
253
254
255/*
256 * loadData
257 *
258 * Read data from a file pointer (a pipe to a process in this context)
259 * until we either get EOF or we get a marker line back.
260 * The read data are stored in a malloc-ed string that is truncated
261 * to size at the end. Input is assumed to be an ASCII string.
262 */
263STATIC char *
264loadData (fp)
265 FILE *fp;
266{
267 char *pzText;
268 size_t textSize;
269 char *pzScan;
270 char zLine[1024];
271
272 textSize = sizeof (zLine) * 2;
273 pzScan = \
274 pzText = malloc (textSize);
275
276 if (pzText == (char *) NULL)
277 return pzText;
278
279 for (;;)
280 {
281 size_t usedCt;
282
283 alarm (10);
284 readPipeTimeout = BOOL_FALSE;
285 if (fgets (zLine, sizeof (zLine), fp) == (char *) NULL)
286 break;
287
288 if (strncmp (zLine, zDone, sizeof (zDone) - 1) == 0)
289 break;
290
291 strcpy (pzScan, zLine);
292 pzScan += strlen (zLine);
293 usedCt = (size_t) (pzScan - pzText);
294
295 if (textSize - usedCt < sizeof (zLine))
296 {
297
298 size_t off = (size_t) (pzScan - pzText);
299 void *p;
300 textSize += 4096;
301 p = realloc ((void *) pzText, textSize);
302 if (p == (void *) NULL)
303 {
304 fprintf (stderr, "Failed to get 0x%08X bytes\n", textSize);
305 free ((void *) pzText);
306 return (char *) NULL;
307 }
308
309 pzText = (char *) p;
310 pzScan = pzText + off;
311 }
312 }
313
314 alarm (0);
315 if (readPipeTimeout)
316 {
317 free ((void *) pzText);
318 return (char *) NULL;
319 }
320
321 while ((pzScan > pzText) && isspace (pzScan[-1]))
322 pzScan--;
323 *pzScan = NUL;
324 return realloc ((void *) pzText, strlen (pzText) + 1);
325}
326
327
328/*
329 * SHELL SERVER PROCESS CODE
330 */
331
332#ifdef DONT_HAVE_SIGSEND
333typedef enum
334{
335 P_ALL, P_PID, P_GID, P_UID, P_PGID, P_SID, P_CID
336}
337idtype_t;
338typedef long id_t;
339
340STATIC int
341sigsend (idtype, id, sig)
342 idtype_t idtype;
343 id_t id;
344 int sig;
345{
346 switch (idtype)
347 {
348 case P_PID:
349 kill ((pid_t) id, sig);
350 break;
351
352 case P_ALL:
353 case P_GID:
354 case P_UID:
355 case P_PGID:
356 case P_SID:
357 case P_CID:
358 errno = EINVAL;
359 return -1;
360 /*NOTREACHED */
361 }
362
363 return 0;
364}
365#endif /* HAVE_SIGSEND */
366
367
368STATIC void
369closeServer ()
370{
371 kill( (pid_t) serverId, SIGKILL);
372 serverId = NULLPROCESS;
373 fclose (serverPair.pfRead);
374 fclose (serverPair.pfWrite);
375 serverPair.pfRead = serverPair.pfWrite = (FILE *) NULL;
376}
377
378
379struct sigaction savePipeAction;
380struct sigaction saveAlrmAction;
381struct sigaction currentAction;
382
383STATIC void
384sigHandler (signo)
385 int signo;
386{
387 closeServer ();
388 readPipeTimeout = BOOL_TRUE;
389}
390
391
392STATIC void
393serverSetup ()
394{
395#ifndef SA_SIGINFO
396# define SA_SIGINFO 0
397#else
398 currentAction.sa_sigaction =
399#endif
400 currentAction.sa_handler = sigHandler;
401 currentAction.sa_flags = SA_SIGINFO;
402 sigemptyset( &currentAction.sa_mask );
403
404 sigaction( SIGPIPE, &currentAction, &savePipeAction );
405 sigaction( SIGALRM, &currentAction, &saveAlrmAction );
406 atexit( &closeServer );
407
408 fputs ("trap : INT\n", serverPair.pfWrite);
409 fflush (serverPair.pfWrite);
410 pCurDir = getcwd ((char *) NULL, MAXPATHLEN + 1);
411}
412
413
414char *
415runShell (pzCmd)
416 const char *pzCmd;
417{
418 tSCC zNil[] = "";
419
420 /*
421 * IF the shell server process is not running yet,
422 * THEN try to start it.
423 */
424 if (serverId == NULLPROCESS)
425 {
426 serverId = p2fopen (&serverPair, defArgs);
427 if (serverId > 0)
428 serverSetup ();
429 }
430
431 /*
432 * IF it is still not running,
433 * THEN return the nil string.
434 */
435 if (serverId <= 0)
436 return (char *) zNil;
437
438 /*
439 * Make sure the process will pay attention to us,
440 * send the supplied command, and then
441 * have it output a special marker that we can find.
442 */
443 fprintf (serverPair.pfWrite, "\\cd %s\n%s\n\necho\necho %s\n",
444 pCurDir, pzCmd, zDone);
445 fflush (serverPair.pfWrite);
446 if (serverId == NULLPROCESS)
447 return (char *) NULL;
448
449 /*
450 * Now try to read back all the data. If we fail due to either
451 * a sigpipe or sigalrm (timeout), we will return the nil string.
452 */
453 {
454 char *pz = loadData (serverPair.pfRead);
455 if (pz == (char *) NULL)
456 {
457 fprintf (stderr, "CLOSING SHELL SERVER - command failure:\n\t%s\n",
458 pzCmd);
459 closeServer ();
460 pz = (char *) zNil;
461 }
462 return pz;
463 }
464}
This page took 0.150128 seconds and 5 git commands to generate.