1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California.  All rights reserved.
4 Authors: 1987 Wayne A. Christopher
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Stuff for asynchronous spice runs, and also rspice.
10  */
11 
12 #include "spice.h"
13 #include "ftedefs.h"
14 #include "fteinp.h"
15 
16 #ifdef HAVE_SOCKET
17 
18 #include <sys/types.h>
19 #include <sys/socket.h>
20 #include <sys/ioctl.h>
21 #include <sys/wait.h>
22 #include <netinet/in.h>
23 #include <netdb.h>
24 
25 #ifdef HAVE_GETPWUID
26 #include <pwd.h>
27 #endif
28 
29 #ifdef HAVE_SIGNAL
30 #include <signal.h>
31 #endif
32 
33 static RETSIGTYPE sigchild();
34 
35 struct proc {
36     int pr_pid;     /* The pid of the spice job. */
37     char *pr_rawfile;   /* The temporary raw file. */
38     char *pr_name;      /* The name of the spice run. */
39     char *pr_inpfile;   /* The name of the input file. */
40     char *pr_outfile;   /* The name of the (tmp) output file. */
41     bool pr_saveout;    /* Don't unlink the output file */
42     struct proc *pr_next;   /* Link. */
43 } ;
44 
45 static struct proc *running = NULL;
46 static int numchanged = 0;  /* How many children have changed in state. */
47 
48 void
com_aspice(wl)49 com_aspice(wl)
50 
51 wordlist *wl;
52 {
53     char *deck, *output = NULL, spicepath[BSIZE_SP], s[BSIZE_SP];
54     char *raw, *t;
55     FILE *inp;
56     struct proc *p;
57     int pid;
58     bool saveout = false;
59     extern char *kw_spicepath;
60 
61     if (!Spice_Path) {
62         fprintf(cp_err,
63             "No spice-3 binary is available for the aspice command.\n");
64         return;
65     }
66 
67     deck = wl->wl_word;
68     if (!cp_getvar(kw_spicepath, VT_STRING, spicepath))
69         (void) strcpy(spicepath, Spice_Path);
70 
71     if (wl->wl_next) {
72         output = wl->wl_next->wl_word;
73         saveout = true;
74     }
75     else {
76         output = smktemp("spout");
77     }
78 
79     if ((inp = fopen(deck, "r")) == NULL) {
80         perror(deck);
81         return;
82     }
83     if (!fgets(s, BSIZE_SP, inp)) {
84         fprintf(cp_err, "Error: bad deck %s\n", deck);
85         (void) fclose(inp);
86         return;
87     }
88     for (t = s; *t && (*t != '\n'); t++)
89         ;
90     *t = '\0';
91     out_printf("Starting spice run for:\n%s\n", s);
92     (void) fclose(inp);
93     raw = smktemp("raw");
94     (void) fclose(fopen(raw, "w")); /* So there isn't a race condition. */
95     pid = fork();
96     if (pid == 0) {
97         if (!(freopen(deck, "r", stdin))) {
98             perror(deck);
99             exit (EXIT_BAD);
100         }
101         if (!(freopen(output, "w", stdout))) {
102             perror(output);
103             exit (EXIT_BAD);
104         }
105         (void) dup2(fileno(stdout), fileno(stderr));
106 
107         (void) execl(spicepath, spicepath, "-r", raw, 0);
108 
109         /* Screwed up. */
110         perror(spicepath);
111         exit(EXIT_BAD);
112     }
113 
114     /* Add this one to the job list. */
115     p = alloc(struct proc);
116     p->pr_pid = pid;
117     p->pr_name = copy(s);
118     p->pr_rawfile = copy(raw);
119     p->pr_inpfile = copy(deck);
120     p->pr_outfile = copy(output);
121     p->pr_saveout = saveout;
122     if (running)
123         p->pr_next = running;
124     running = p;
125 #ifdef SIGCHLD
126     (void) signal(SIGCHLD, sigchild);
127 #else
128 #ifdef SIGCLD
129     (void) signal(SIGCLD, sigchild);
130 #endif
131 #endif
132     return;
133 }
134 
135 /* ARGSUSED */
136 void
com_jobs(wl)137 com_jobs(wl)
138 
139 wordlist *wl;
140 {
141     struct proc *p;
142 
143     for (p = running; p; p = p->pr_next)
144         out_printf("%d\t%.70s\n", p->pr_pid, p->pr_name);
145     return;
146 }
147 
148 
149 static RETSIGTYPE
sigchild()150 sigchild()
151 {
152     numchanged++;
153     if (ft_asyncdb)
154         fprintf(cp_err, "%d jobs done now\n", numchanged);
155     if (cp_cwait) {
156         ft_checkkids();
157     }
158     return;
159 }
160 
161 /* This gets called every once in a while, and checks to see if any
162  * jobs have finished. If they have it gets the data.  The problem is
163  * that wait(0) is probably more portable, but it can't tell
164  * whether the exit was normal or not.
165  */
166 
167 void
ft_checkkids()168 ft_checkkids()
169 {
170     struct proc *p, *lp;
171     char buf[BSIZE_SP];
172     FILE *fp;
173     int pid;
174     static bool here = false;   /* Don't want to be re-entrant. */
175 
176     if (!numchanged || here)
177         return;
178 
179     here = true;
180 
181     while (numchanged > 0) {
182         pid = wait(NULL);
183         if (pid == -1) {
184             fprintf(cp_err,
185 "ft_checkkids: Internal Error: should be %d jobs done but there aren't any.\n",
186                 numchanged);
187             numchanged = 0;
188             running = NULL;
189             here = false;
190             return;
191         }
192         for (p = running; p; p = p->pr_next) {
193             if (p->pr_pid == pid)
194                 break;
195             lp = p;
196         }
197         if (p == NULL) {
198             fprintf(cp_err,
199             "ft_checkkids: Internal Error: Process %d not a job!\n",
200                     pid);
201             here = false;
202             return;
203         }
204         if (p == running)
205             running = p->pr_next;
206         else
207             lp->pr_next = p->pr_next;
208         out_printf("Job finished: %.60s\n", p->pr_name);
209         numchanged--;
210         ft_loadfile(p->pr_rawfile);
211         (void) unlink(p->pr_rawfile);
212         if (!(fp = fopen(p->pr_outfile, "r"))) {
213             perror(p->pr_outfile);
214             here = false;
215             return;
216         }
217         while (fgets(buf, BSIZE_SP, fp))
218             out_send(buf);
219         (void) fclose(fp);
220         if (!p->pr_saveout)
221             (void) unlink(p->pr_outfile);
222         out_send("\n-----\n");
223     }
224     out_send("\n");
225 #ifdef TIOCSTI
226     (void) ioctl(0, TIOCSTI, "\022");   /* Reprint the line. */
227 #endif
228     here = false;
229     return;
230 }
231 
232 /* Run a spice job remotely. See the description of the spice daemon for
233  * the protocol. This is 4.2 specific.
234  */
235 
236 void
com_rspice(wl)237 com_rspice(wl)
238 
239 wordlist *wl;
240 {
241     char rhost[64], *user, host[64], program[128], buf[BSIZE_SP];
242     char *outfile;
243     struct servent *sp;
244     struct protoent *pp;
245     struct hostent *hp;
246     struct sockaddr_in server;
247     FILE *inp, *serv, *out;
248     struct passwd *pw;
249     struct plot *pl;
250     int s, i;
251     extern char *kw_rhost, *kw_rprogram;
252 
253     /* Figure out where the spicedaemon is and connect to it. */
254     if (!cp_getvar(kw_rhost, VT_STRING, rhost))
255         (void) strcpy(rhost, Spice_Host);
256     if (!cp_getvar(kw_rprogram, VT_STRING, program))
257         *program = '\0';
258     if (*rhost == '\0') {
259         fprintf(cp_err,
260         "Error: there is no remote spice host for this site.\n");
261     }
262     pw = getpwuid(getuid());
263     if (pw == NULL) {
264         fprintf(cp_err, "Who the heck are you, anyway??\n");
265         return;
266     }
267     user = pw->pw_name;
268     if (gethostname(host, 64) > 0) {
269         perror("gethostname");
270         return;
271     }
272 
273     sp = getservbyname("spice", "tcp");
274     if (sp == NULL) {
275         fprintf(cp_err, "Error: spice/tcp: unknown service\n");
276         return;
277     }
278     pp = getprotobyname("tcp");
279     if (pp == NULL) {
280         fprintf(cp_err, "Error: tcp: unknown protocol\n");
281         return;
282     }
283     hp = gethostbyname(rhost);
284     if (hp == NULL) {
285         fprintf(cp_err, "Error: unknown host %s\n", rhost);
286         return;
287     }
288     bzero((char *) &server, sizeof (struct sockaddr_in));
289     bcopy(hp->h_addr, (char *) &server.sin_addr, hp->h_length);
290     server.sin_family = hp->h_addrtype;
291     server.sin_port = sp->s_port;
292 
293     /* Create the socket. */
294     s = socket(AF_INET, SOCK_STREAM, pp->p_proto);
295     if (s < 0) {
296         perror("socket");
297         return;
298     }
299 
300     if (connect(s, (struct sockaddr *) &server,
301             sizeof (struct sockaddr)) < 0) {
302         perror("connect");
303         return;
304     }
305 
306     /* Now we are ready to do the stuff. */
307     if (*program)
308         (void) sprintf(buf, "%s %s %s", user, host, program);
309     else
310         (void) sprintf(buf, "%s %s", user, host);
311     (void) write(s, buf, strlen(buf) + 1);      /* Get the trailing \0. */
312     if (read(s, buf, BSIZE_SP) <= 0) {
313         fprintf(cp_err, "Connection (void) closed\n");
314         (void) close(s);
315         return;
316     }
317 
318     if (eq(buf, "toomany")) {
319         fprintf(cp_err,
320     "\nSorry, %s is too loaded now -- please try another machine\n",
321             rhost);
322         fprintf(cp_err,
323     "\tthat has a spice server running, or try again later.\n");
324         (void) close(s);
325         return;
326     } else if (!eq(buf, "ok")) {
327         fprintf(cp_err, "Error: remote spiced says %s\n", buf);
328         (void) close(s);
329         return;
330     }
331 
332     /* Send the circuit over. */
333     if (wl) {
334         while (wl) {
335             if (!(inp = fopen(wl->wl_word, "r"))) {
336                 perror(wl->wl_word);
337                 wl = wl->wl_next;
338                 continue;   /* Should be careful */
339             }
340             while ((i = fread(buf, 1, BSIZE_SP, inp)) > 0)
341                 (void) write(s, buf, i);
342             wl = wl->wl_next;
343         }
344         (void) write(s, "@\n", 3);
345     }
346     else {
347         if (ft_nutmeg || !ft_curckt) {
348             fprintf(cp_err, "Error: no circuits loaded\n");
349             (void) close(s);
350             return;
351         }
352 
353         /* We have to make a FILE struct for the socket. */
354         inp = fdopen(s, "w");
355         inp_list(inp, ft_curckt->ci_deck, ft_curckt->ci_options,
356                 LS_DECK);
357         fputs("@\n", inp);
358         (void) fflush(inp);
359     }
360 
361     /* Now wait for things to come through */
362     serv = fdopen(s, "r");
363     while (fgets(buf, BSIZE_SP, serv) != NULL) {
364         if (*buf == '@')
365             break;
366         fputs(buf, cp_out);
367     }
368     outfile = smktemp("rsp");
369     if (!(out = fopen(outfile, "w"))) {
370         perror(outfile);
371         (void) fclose(serv);
372         return;
373     }
374     while (i = fread(buf, 1, BSIZE_SP, serv))
375         (void) fwrite(buf, 1, i, out);
376     (void) fclose(out);
377     (void) fclose(serv);
378     pl = raw_read(outfile);
379     if (pl)
380         plot_add(pl);
381     (void) unlink(outfile);
382     return;
383 }
384 
385 #else /* if ! HAVE_SOCKET */
386 
387 /* ARGSUSED */
388 void
com_aspice(wl)389 com_aspice(wl)
390     wordlist *wl;
391 {
392     fprintf(cp_err, "Asynchronous spice jobs are not available.\n");
393     return;
394 }
395 
396 /* ARGSUSED */
397 void
com_jobs(wl)398 com_jobs(wl)
399     wordlist *wl;
400 {
401     fprintf(cp_err, "Asynchronous spice jobs are not available.\n");
402     return;
403 }
404 
405 #define SUBMIT "/bin/csh /usr/bin/rspice"
406 
407 void
com_rspice(wl)408 com_rspice(wl)
409 
410 wordlist *wl;
411 {
412     char *output, *raw;
413     char *input, buf[BSIZE_SP];
414     FILE *fp;
415 
416     if (wl && !wl->wl_next) {
417         input = wl->wl_word;
418     }
419     else {
420         fprintf(cp_err, "Error: you must supply the input deck name.\n");
421         return;
422     }
423     output = smktemp("out");
424     raw = smktemp("raw");
425 
426     out_printf("Running job, please wait. ");
427     (void) fflush(cp_out);
428     (void) sprintf(buf, "%s %s %s %s", SUBMIT, input, output, raw);
429     if (system(buf) != 0)
430         return;
431 
432     out_printf("done.\n\n");
433 
434     if (!(fp = fopen(output, "r"))) {
435         perror(output);
436         return;
437     }
438     while (fgets(buf, BSIZE_SP, fp))
439         out_send(buf);
440     (void) fclose(fp);
441     (void) unlink(output);
442 
443     ft_loadfile(raw);
444     (void) unlink(raw);
445     return;
446 }
447 
448 
ft_checkkids()449 void ft_checkkids() {}
450 
451 #endif
452 
453