ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/netproc.c
Revision: 2.4
Committed: Mon Mar 4 09:22:50 1996 UTC (28 years, 1 month ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.3: +5 -4 lines
Log Message:
changed getcwd() call to getwd()

File Contents

# User Rev Content
1 greg 2.1 /* Copyright (c) 1996 Regents of the University of California */
2    
3     #ifndef lint
4     static char SCCSid[] = "$SunId$ LBL";
5     #endif
6    
7     /*
8     * Parallel network process handling routines
9     */
10    
11     #include <stdio.h>
12     #include <sys/types.h>
13 greg 2.4 #include <sys/param.h>
14 greg 2.1 #include <signal.h>
15     #include <fcntl.h>
16     #include "netproc.h"
17     #include "vfork.h"
18     /* select call compatibility stuff */
19     #ifndef FD_SETSIZE
20     #include <sys/param.h>
21     #define FD_SETSIZE NOFILE /* maximum # select file descriptors */
22     #endif
23     #ifndef FD_SET
24     #ifndef NFDBITS
25     #define NFDBITS (8*sizeof(int)) /* number of bits per fd_mask */
26     #endif
27     #define FD_SET(n, p) ((p)->fds_bits[(n)/NFDBITS] |= (1 << ((n) % NFDBITS)))
28     #define FD_CLR(n, p) ((p)->fds_bits[(n)/NFDBITS] &= ~(1 << ((n) % NFDBITS)))
29     #define FD_ISSET(n, p) ((p)->fds_bits[(n)/NFDBITS] & (1 << ((n) % NFDBITS)))
30     #ifndef BSD
31     #define bzero(d,n) (void)memset(d,0,n)
32     #endif
33     #define FD_ZERO(p) bzero((char *)(p), sizeof(*(p)))
34     #endif
35    
36     PSERVER *pslist = NULL; /* global process server list */
37    
38     static PROC *pindex[FD_SETSIZE]; /* process index table */
39    
40     static char ourhost[64]; /* this host name */
41 greg 2.4 static char ourdir[MAXPATHLEN]; /* our working directory */
42 greg 2.1 static char ouruser[32]; /* our user name */
43     static char *ourshell; /* our user's shell */
44    
45     static fd_set errdesc; /* error file descriptors */
46     static int maxfd; /* maximum assigned descriptor */
47    
48 greg 2.3 extern char *remsh; /* externally defined remote shell program */
49    
50 greg 2.1 extern char *malloc(), *realloc();
51     extern char *getenv();
52    
53    
54     PSERVER *
55     addpserver(host, dir, usr, np) /* add a new process server */
56     char *host, *dir, *usr;
57     int np;
58     {
59     register PSERVER *ps;
60     /* allocate the struct */
61     if (np < 1)
62     return(NULL);
63     ps = (PSERVER *)malloc(sizeof(PSERVER)+(np-1)*sizeof(PROC));
64     if (ps == NULL)
65     return(NULL);
66     if (!ourhost[0]) { /* initialize */
67 greg 2.4 char dirtmp[MAXPATHLEN];
68 greg 2.1 register char *cp;
69     register int len;
70    
71 greg 2.2 strcpy(ourhost, myhostname());
72 greg 2.4 getwd(dirtmp);
73 greg 2.1 if ((cp = getenv("HOME")) != NULL) {
74     if (!strcmp(cp, dirtmp))
75     ourdir[0] = '\0';
76     else if (!strncmp(cp, dirtmp, len=strlen(cp)) &&
77     dirtmp[len] == '/')
78     strcpy(ourdir, dirtmp+len+1);
79     else
80     strcpy(ourdir, dirtmp);
81     } else
82     strcpy(ourdir, dirtmp);
83     if ((cp = getenv("USER")) != NULL)
84     strcpy(ouruser, cp);
85     if ((ourshell = getenv("SHELL")) == NULL)
86     ourshell = "/bin/sh";
87     FD_ZERO(&errdesc);
88     maxfd = -1;
89     }
90     /* assign host, directory, user */
91     if (host == NULL || !strcmp(host, ourhost) ||
92     !strcmp(host, LHOSTNAME))
93     ps->hostname[0] = '\0';
94     else
95     strcpy(ps->hostname, host);
96     if (dir == NULL)
97     strcpy(ps->directory, ourdir);
98     else
99     strcpy(ps->directory, dir);
100     if (usr == NULL || !strcmp(usr, ouruser))
101     ps->username[0] = '\0';
102     else
103     strcpy(ps->username, usr);
104     /* clear process slots */
105     ps->nprocs = np;
106     while (np--) {
107     ps->proc[np].com = NULL;
108     ps->proc[np].pid = -1;
109     ps->proc[np].efd = -1;
110     ps->proc[np].errs = NULL;
111     ps->proc[np].elen = 0;
112     ps->proc[np].cf = NULL;
113     }
114     /* insert in our list */
115     ps->next = pslist;
116     pslist = ps;
117     /* check for signs of life */
118     if (!pserverOK(ps)) {
119     delpserver(ps); /* failure -- abort */
120     return(NULL);
121     }
122     return(ps);
123     }
124    
125    
126     delpserver(ps) /* delete a process server */
127     PSERVER *ps;
128     {
129     PSERVER pstart;
130     register PSERVER *psp;
131     register int i;
132     /* find server in our list */
133     pstart.next = pslist;
134     for (psp = &pstart; ps != psp->next; psp = psp->next)
135     if (psp->next == NULL)
136     return; /* not in our list! */
137     /* kill any running jobs */
138     for (i = 0; i < ps->nprocs; i++)
139     if (ps->proc[i].com != NULL) {
140     kill(SIGTERM, ps->proc[i].pid);
141     wait4job(ps, ps->proc[i].pid);
142     }
143     /* remove server from list */
144     psp->next = ps->next;
145     pslist = pstart.next;
146     free((char *)ps); /* free associated memory */
147     }
148    
149    
150     PSERVER *
151     findjob(pnp) /* find out where process is running */
152     register int *pnp; /* modified */
153     {
154     register PSERVER *ps;
155     register int i;
156    
157     for (ps = pslist; ps != NULL; ps = ps->next)
158     for (i = 0; i < ps->nprocs; i++)
159     if (ps->proc[i].pid == *pnp) {
160     *pnp = i;
161     return(ps);
162     }
163     return(NULL); /* not found */
164     }
165    
166    
167     int
168     startjob(ps, command, compf) /* start a job on a process server */
169     register PSERVER *ps;
170     char *command;
171     int (*compf)();
172     {
173 greg 2.4 char udirt[MAXPATHLEN];
174 greg 2.3 char *av[16];
175 greg 2.1 int pfd[2], pid;
176     register int i;
177    
178     if (ps == NULL) { /* find a server */
179     for (ps = pslist; ps != NULL; ps = ps->next)
180     if ((i = startjob(ps, command, compf)) != -1)
181     return(i); /* got one */
182     return(-1); /* no slots anywhere */
183     }
184     for (i = 0; i < ps->nprocs; i++)
185     if (ps->proc[i].com == NULL)
186     break;
187     if (i >= ps->nprocs)
188     return(-1); /* out of process slots */
189     /* open pipe */
190     if (pipe(pfd) < 0) {
191     perror("cannot open pipe");
192     exit(1);
193     }
194     /* start child process */
195     if ((pid = vfork()) == 0) {
196     close(pfd[0]); /* connect stderr to pipe */
197     if (pfd[1] != 2) {
198     dup2(pfd[1], 2);
199     close(pfd[1]);
200     }
201     if (ps->hostname[0]) { /* rsh command */
202 greg 2.3 av[i=0] = remsh;
203 greg 2.1 av[++i] = ps->hostname;
204 greg 2.3 av[++i] = "-n"; /* no stdin */
205     if (ps->username[0]) { /* different user */
206 greg 2.1 av[++i] = "-l";
207     av[++i] = ps->username;
208 greg 2.3 av[++i] = "cd";
209     udirt[0] = '~';
210     strcpy(udirt+1, ouruser);
211     av[++i] = udirt;
212     av[++i] = ";";
213 greg 2.1 }
214 greg 2.3 if (ps->directory[0]) { /* change directory */
215 greg 2.1 av[++i] = "cd";
216     av[++i] = ps->directory;
217     av[++i] = ";";
218     }
219     av[++i] = command;
220     av[++i] = NULL;
221     } else { /* shell command */
222     av[0] = ourshell;
223     av[1] = "-c";
224     av[2] = command;
225     av[3] = NULL;
226     }
227     execv(av[0], av);
228     _exit(1);
229     }
230     if (pid == -1) {
231     perror("fork failed");
232     exit(1);
233     }
234     ps->proc[i].com = command; /* assign process slot */
235     ps->proc[i].cf = compf;
236     ps->proc[i].pid = pid;
237     close(pfd[1]); /* get piped stderr file descriptor */
238     ps->proc[i].efd = pfd[0];
239     fcntl(pfd[0], F_SETFD, 1); /* set close on exec flag */
240     pindex[pfd[0]] = ps->proc + i; /* assign error fd index */
241     FD_SET(pfd[0], &errdesc); /* add to select call parameter */
242     if (pfd[0] > maxfd)
243     maxfd = pfd[0];
244     return(pid); /* return to parent process */
245     }
246    
247    
248     static int
249     readerrs(fd) /* read error output from fd */
250     int fd;
251     {
252     char errbuf[BUFSIZ];
253     int nr;
254     register PROC *pp;
255     /* look up associated process */
256     if ((pp = pindex[fd]) == NULL)
257     abort(); /* serious consistency error */
258     nr = read(fd, errbuf, BUFSIZ-1);
259     if (nr < 0) {
260     perror("read error");
261     exit(1);
262     }
263     if (nr == 0) /* stream closed (process finished) */
264     return(0);
265     errbuf[nr] = '\0'; /* add to error buffer */
266     if (pp->elen == 0)
267     pp->errs = (char *)malloc(nr+1);
268     else
269     pp->errs = (char *)realloc(pp->errs, pp->elen+nr+1);
270     if (pp->errs == NULL) {
271     perror("malloc failed");
272     exit(1);
273     }
274     strcpy(pp->errs+pp->elen, errbuf);
275     pp->elen += nr;
276     return(nr);
277     }
278    
279    
280     static
281     wait4end() /* read error streams until someone is done */
282     {
283     fd_set readfds, excepfds;
284     register int i;
285     /* find end of descriptor set */
286     for ( ; maxfd >= 0; maxfd--)
287     if (FD_ISSET(maxfd, &errdesc))
288     break;
289     if (maxfd < 0)
290     return; /* nothing to read */
291     readfds = excepfds = errdesc;
292     while (select(maxfd+1, &readfds, NULL, &excepfds, NULL) > 0)
293     for (i = 0; i <= maxfd; i++) /* get pending i/o */
294     if (FD_ISSET(i, &readfds) || FD_ISSET(i, &excepfds))
295     if (readerrs(i) == 0)
296     return; /* finished process */
297     perror("select call failed");
298     exit(1);
299     }
300    
301    
302     static int
303     finishjob(ps, pn, status) /* clean up finished process */
304     PSERVER *ps;
305     int pn;
306     int status;
307     {
308     register PROC *pp;
309    
310     pp = ps->proc + pn;
311     if (pp->cf != NULL) /* client cleanup */
312     status = (*pp->cf)(ps, pn, status);
313     close(pp->efd); /* close error stream */
314     pindex[pp->efd] = NULL;
315     FD_CLR(pp->efd, &errdesc);
316     free((char *)pp->errs);
317     pp->com = NULL; /* clear settings */
318     pp->pid = -1;
319     pp->efd = -1;
320     pp->errs = NULL;
321     pp->elen = 0;
322     pp->cf = NULL;
323     return(status);
324     }
325    
326    
327     int
328     wait4job(ps, pid) /* wait for process to finish */
329     PSERVER *ps;
330     int pid;
331     {
332     int status, psn, psn2;
333     PSERVER *ps2;
334    
335     if (pid == -1) { /* wait for first job */
336     if (ps != NULL) {
337     for (psn = ps->nprocs; psn--; )
338     if (ps->proc[psn].com != NULL)
339     break;
340     if (psn < 0)
341     return(-1); /* no processes this server */
342     }
343     do {
344     wait4end(); /* wait for something to end */
345     if ((psn2 = wait(&status)) == -1)
346     return(-1); /* none left */
347     ps2 = findjob(&psn2);
348     if (ps2 != NULL) /* clean up job if ours */
349     status = finishjob(ps2, psn2, status);
350     } while (ps2 == NULL || (ps != NULL && ps2 != ps));
351     return(status); /* return job status */
352     }
353     psn = pid; /* else find specific job */
354     ps2 = findjob(&psn); /* find process slot */
355     if (ps2 == NULL || (ps != NULL && ps2 != ps))
356     return(-1); /* inconsistent target */
357     ps = ps2;
358     do {
359     wait4end(); /* wait for something to end */
360     if ((psn2 = wait(&status)) == -1)
361     return(-1); /* none left */
362     ps2 = findjob(&psn2);
363     if (ps2 != NULL) /* clean up job if ours */
364     status = finishjob(ps2, psn2, status);
365     } while (ps2 != ps || psn2 != psn);
366     return(status); /* return job status */
367     }