ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/netproc.c
Revision: 2.5
Committed: Mon Jun 24 10:06:40 1996 UTC (27 years, 9 months ago) by greg
Content type: text/plain
Branch: MAIN
Changes since 2.4: +4 -4 lines
Log Message:
added conditional use of getwd()

File Contents

# Content
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 #include <signal.h>
14 #include <fcntl.h>
15 #include "netproc.h"
16 #include "paths.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 static char ourdir[MAXPATH]; /* our working directory */
42 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 extern char *remsh; /* externally defined remote shell program */
49
50 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 char dirtmp[MAXPATH];
68 register char *cp;
69 register int len;
70
71 strcpy(ourhost, myhostname());
72 getwd(dirtmp);
73 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 char udirt[MAXPATH];
174 char *av[16];
175 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 av[i=0] = remsh;
203 av[++i] = ps->hostname;
204 av[++i] = "-n"; /* no stdin */
205 if (ps->username[0]) { /* different user */
206 av[++i] = "-l";
207 av[++i] = ps->username;
208 av[++i] = "cd";
209 udirt[0] = '~';
210 strcpy(udirt+1, ouruser);
211 av[++i] = udirt;
212 av[++i] = ";";
213 }
214 if (ps->directory[0]) { /* change directory */
215 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 }