Jspice3
aspice.c
Go to the documentation of this file.
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
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
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
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
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
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");
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
390  wordlist *wl;
391 {
392  fprintf(cp_err, "Asynchronous spice jobs are not available.\n");
393  return;
394 }
395 
396 /* ARGSUSED */
397 void
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
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 
449 void ft_checkkids() {}
450 
451 #endif
452 
static char buf[MAXPROMPT]
Definition: arg.c:18
#define BSIZE_SP
Definition: misc.h:19
#define eq(a, b)
Definition: misc.h:29
bool ft_asyncdb
Definition: options.c:31
void inp_list(FILE *fp, struct line *l1, struct line *l2, int i)
Definition: main.c:260
bool cp_getvar(char *n, int t, char *r)
Definition: help.c:184
void ft_checkkids()
Definition: aspice.c:449
void out_printf()
char * strcpy()
Definition: cddefs.h:119
char * kw_rhost
Definition: options.c:413
Definition: objects.c:1183
int system(char *str)
Definition: libfuncs.c:85
struct line * ci_deck
Definition: ftedefs.h:30
static struct sHtxt * input()
Definition: hypertxt.c:786
struct line * ci_options
Definition: ftedefs.h:32
void plot_add()
FILE * p
Definition: proc2mod.c:48
Definition: ftedata.h:61
struct plot * raw_read()
#define LS_DECK
Definition: fteinp.h:26
Definition: library.c:18
void com_aspice(wordlist *wl)
Definition: aspice.c:389
int bzero(char *ptr, int num)
Definition: string.c:357
#define alloc(type)
Definition: cdmacs.h:21
char * copy()
FILE * cp_err
Definition: help.c:101
char * kw_rprogram
Definition: options.c:414
#define NULL
Definition: spdefs.h:121
struct circ * ft_curckt
Definition: main.c:184
FILE * cp_out
Definition: help.c:101
int unlink(char *fn)
Definition: libfuncs.c:96
void com_rspice(wordlist *wl)
Definition: aspice.c:408
char * smktemp()
bool cp_cwait
Definition: front.c:120
#define VT_STRING
Definition: cpstd.h:63
char * kw_spicepath
Definition: options.c:418
void perror()
Definition: cpstd.h:21
char * Spice_Path
Definition: ivars.c:11
void out_send()
#define SUBMIT
Definition: aspice.c:405
void com_jobs(wordlist *wl)
Definition: aspice.c:398
bool ft_nutmeg
Definition: main.c:161
void bcopy(char *from, char *to, int num)
Definition: string.c:339
char * Spice_Host
#define EXIT_BAD
Definition: misc.h:26
void ft_loadfile()
Definition: cddefs.h:192