ViewVC Help
View File | Revision Log | Show Annotations | Download File | Root Listing
root/radiance/ray/src/util/netproc.c
Revision: 2.11
Committed: Mon Jun 30 14:59:13 2003 UTC (20 years, 9 months ago) by schorsch
Content type: text/plain
Branch: MAIN
Changes since 2.10: +7 -5 lines
Log Message:
Replaced most outdated BSD function calls with their posix equivalents, and cleaned up a few other platform dependencies.

File Contents

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