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