1 /************************************************************************
2 * This program is Copyright (C) 1986-1996 by Jonathan Payne. JOVE is *
3 * provided to you without charge, and with no warranty. You may give *
4 * away copies of JOVE, including sources, provided that this notice is *
5 * included in all the files. *
6 ************************************************************************/
7
8 #include "jove.h"
9
10 #ifdef IPROCS /* the body is the rest of this file */
11
12 #include <signal.h>
13
14 #include "re.h"
15 #include "jctype.h"
16 #include "disp.h"
17 #include "fp.h"
18 #include "sysprocs.h"
19 #include "iproc.h"
20 #include "ask.h"
21 #include "extend.h"
22 #include "fmt.h"
23 #include "insert.h"
24 #include "marks.h"
25 #include "move.h"
26 #include "proc.h"
27 #include "wind.h"
28
29 #ifdef USE_KILLPG
30 # ifndef FULL_UNISTD
31 extern int UNMACRO(killpg) proto((int /*pgrp*/, int /*sig*/));
32 # endif
33 #else /* !USE_KILLPG */
34 #define killpg(pid, sig) kill(-(pid), (sig))
35 #endif /* USE_KILLPG */
36
37 #include <errno.h>
38
39 struct process {
40 Process p_next;
41 #ifdef PIPEPROCS
42 int p_toproc; /* write end of pipe to process */
43 pid_t p_portpid, /* pid of direct child (the portsrv) */
44 p_pid; /* pid of real child i.e. not portsrv */
45 bool p_portlive; /* is portsrv still live? */
46 #else
47 int p_fd; /* file descriptor of pty? opened r/w */
48 # define p_portpid p_pid /* pid of direct child (the shell) */
49 pid_t p_pid; /* pid of child (the shell) */
50 #endif
51 Buffer *p_buffer; /* add output to end of this buffer */
52 char *p_name; /* ... */
53 int p_io_state; /* state of communication with child and descendents */
54 # define IO_NEW 0 /* brand new, process has not yet sent output */
55 # define IO_RUNNING 1 /* just running */
56 # define IO_EOFED 2 /* we have sent EOF, or have received it */
57 int p_child_state; /* state of child process, as disclosed by SIGCHLD/wait */
58 # define C_LIVE 0 /* no news is good news */
59 # define C_STOPPED 1
60 # define C_EXITED 2
61 # define C_KILLED 3
62 int p_reason; /* If killed, p_reason is the signal;
63 if exited, it is the the exit code */
64 Mark *p_mark; /* where output left us */
65 bool p_dbx_mode; /* whether to parse output for file/lineno
66 pairs */
67 };
68
69 private void
70 jputenv proto((char *)),
71 proc_rec proto((Process, char *, size_t)),
72 proc_close proto ((Process)),
73 SendData proto((bool)),
74 obituary proto((register Process child, wait_status_t w));
75
76 private bool
77 proc_kill proto((Process, int));
78
79 #define child_dead(p) ((p)->p_child_state >= C_EXITED)
80 #define io_eofed(p) ((p)->p_io_state == IO_EOFED)
81
82 private bool
dead(p)83 dead(p)
84 Process p;
85 {
86 return p == NULL || (io_eofed(p) && child_dead(p));
87 }
88
89
90 #define proc_cmd(p) ((p)->p_name)
91
92 private Process procs = NULL;
93
94 private Process
proc_pid(pid)95 proc_pid(pid)
96 pid_t pid;
97 {
98 register Process p;
99
100 for (p = procs; ; p = p->p_next)
101 if (p == NULL || p->p_portpid == pid)
102 return p;
103 }
104
105 private char *
proc_bufname(p)106 proc_bufname(p)
107 Process p;
108 {
109 Buffer *b = p->p_buffer;
110
111 return (b != NULL) ? b->b_name : "<Deleted>";
112 }
113
114 void
ProcKill()115 ProcKill()
116 {
117 (void) proc_kill(
118 buf_exists(ask_buf(curbuf, ALLOW_OLD | ALLOW_INDEX))->b_process,
119 SIGKILL);
120 }
121
122 private void
make_argv(argv,ap)123 make_argv(argv, ap)
124 register char *argv[];
125 va_list ap;
126 {
127 register int i = 0;
128
129 argv[i++] = va_arg(ap, char *);
130 argv[i++] = basename(argv[0]);
131 do ; while ((argv[i++] = va_arg(ap, char *)) != NULL);
132 }
133
134 /* There are two very different implementation techniques: pipes and ptys.
135 * The following two chunks of code implement the same operations using
136 * the two techniques: the first uses pipes and the second uses ptys.
137 */
138
139 #ifdef PIPEPROCS
140
141 #include <sgtty.h>
142
143 char Portsrv[FILESIZE]; /* path to portsrv program (in LibDir) */
144
145 int NumProcs = 0;
146
147 File *ProcInput;
148 private int ProcOutput = -1;
149
150 pid_t kbd_pid = -1;
151
152 void
read_pipe_proc(pid,nbytes)153 read_pipe_proc(pid, nbytes)
154 pid_t pid;
155 register int nbytes;
156 {
157 register Process p = proc_pid(pid);
158
159 if (p == NULL) {
160 writef("\riproc: unknown pid (%d)", (int)pid);
161 } else if (p->p_io_state == IO_NEW) {
162 /* first message: pid of real child, not of portsrv */
163 pid_t rpid;
164
165 (void) f_readn(ProcInput, (char *) &rpid, sizeof(pid_t));
166 p->p_pid = rpid;
167 p->p_io_state = IO_RUNNING;
168 UpdModLine = YES;
169 } else if (nbytes == -1) {
170 /* okay to clean up this process */
171 wait_status_t status;
172
173 (void) f_readn(ProcInput, (char *) &status, sizeof(status));
174 /* Reap portsrv process, if it still remains.
175 * Note that any status for this process is uninteresting:
176 * the interesting status came (just now) by pipe.
177 */
178 while (p->p_portlive) {
179 wait_status_t w;
180 pid_t rpid = wait(&w);
181
182 if (rpid == -1) {
183 if (errno == ECHILD) {
184 /* oops: no children, not even portsrv */
185 p->p_portlive = NO;
186 }
187 } else {
188 kill_off(rpid, w);
189 }
190 }
191 proc_close(p);
192 obituary(p, status);
193 } else {
194 /* regular data */
195 while (nbytes > 0) {
196 char ibuf[512+1]; /* NOTE: room for added NUL */
197 size_t n = f_readn(ProcInput, ibuf,
198 (size_t)min((int)(sizeof ibuf) - 1, nbytes));
199
200 nbytes -= n;
201 proc_rec(p, ibuf, n);
202 }
203 }
204 }
205
206 void
ProcInt()207 ProcInt()
208 {
209 (void) proc_kill(curbuf->b_process, SIGINT);
210 }
211
212 void
ProcQuit()213 ProcQuit()
214 {
215 (void) proc_kill(curbuf->b_process, SIGQUIT);
216 }
217
218 private void
proc_close(p)219 proc_close(p)
220 Process p;
221 {
222 if (p->p_toproc >= 0) {
223 (void) close(p->p_toproc);
224 p->p_toproc = -1; /* writes will fail */
225 NumProcs -= 1;
226 p->p_io_state = IO_EOFED; /* process output EOF is tied to reaping */
227 UpdModLine = YES;
228 }
229 }
230
231 private void
proc_write(p,buf,nbytes)232 proc_write(p, buf, nbytes)
233 Process p;
234 char *buf;
235 size_t nbytes;
236 {
237 if (p->p_toproc >= 0) {
238 while (nbytes != 0) {
239 SSIZE_T wr = write(p->p_toproc, (UnivConstPtr)buf, nbytes);
240
241 if (wr >= 0) {
242 nbytes -= wr;
243 buf += wr;
244 } else if (errno != EINTR) {
245 complain("[error writing to iproc: %d %s]", errno, strerror(errno));
246 }
247 }
248 }
249 }
250
251
252 # ifdef STDARGS
253 private void
proc_strt(char * bufname,bool clobber,char * procname,...)254 proc_strt(char *bufname, bool clobber, char *procname, ...)
255 # else
256 private /*VARARGS3*/ void
257 proc_strt(bufname, clobber, procname, va_alist)
258 char *bufname;
259 bool clobber;
260 char *procname;
261 va_dcl
262 # endif
263 {
264 Window *owind = curwind;
265 int toproc[2];
266 pid_t pid;
267 Process newp;
268 Buffer *newbuf;
269 char *argv[32];
270 va_list ap;
271
272 untieDeadProcess(buf_exists(bufname));
273 isprocbuf(bufname); /* make sure BUFNAME is either nonexistant
274 or is of type B_PROCESS */
275 if (access(Portsrv, X_OK) < 0) {
276 complain("[Couldn't access %s: %s]", Portsrv, strerror(errno));
277 /* NOTREACHED */
278 }
279
280 dopipe(toproc);
281
282 if (NumProcs++ == 0)
283 kbd_strt(); /* may create kbd process: must be done before fork */
284 switch (pid = fork()) {
285 case -1:
286 pipeclose(toproc);
287 if (--NumProcs == 0)
288 kbd_stop();
289 complain("[Fork failed: %s]", strerror(errno));
290 /* NOTREACHED */
291
292 case 0:
293 argv[0] = "portsrv";
294 va_init(ap, procname);
295 make_argv(&argv[1], ap);
296 va_end(ap);
297 (void) dup2(toproc[0], 0);
298 (void) dup2(ProcOutput, 1);
299 (void) dup2(ProcOutput, 2);
300 pipeclose(toproc);
301 jcloseall();
302 jputenv("EMACS=t");
303 jputenv("TERM=emacs");
304 /* ??? the following line is not useful for terminfo systems */
305 jputenv(sprint("TERMCAP=emacs:co#%d:tc=unknown:", CO-1));
306 execv(Portsrv, argv);
307 raw_complain("execl failed: %s", strerror(errno));
308 _exit(1);
309 }
310
311 newp = (Process) emalloc(sizeof *newp);
312 newp->p_next = procs;
313 newp->p_io_state = IO_NEW;
314 newp->p_child_state = C_LIVE;
315 newp->p_name = copystr(procname);
316 procs = newp;
317 newp->p_portpid = pid;
318 newp->p_pid = -1;
319 newp->p_portlive = YES;
320
321 newbuf = do_select((Window *)NULL, bufname);
322 newbuf->b_type = B_PROCESS;
323 newp->p_buffer = newbuf;
324 newbuf->b_process = newp; /* sorta circular, eh? */
325 pop_wind(bufname, clobber, B_PROCESS);
326 ToLast();
327 if (!bolp())
328 LineInsert(1);
329 /* Pop_wind() after everything is set up; important!
330 Bindings won't work right unless newbuf->b_process is already
331 set up BEFORE NEWBUF is first SetBuf()'d. */
332 newp->p_mark = MakeMark(curline, curchar);
333 newp->p_dbx_mode = NO;
334
335 newp->p_toproc = toproc[1];
336 (void) close(toproc[0]);
337 SetWind(owind);
338 }
339
340 void
closeiprocs()341 closeiprocs()
342 {
343 Process p;
344
345 if (ProcOutput != -1)
346 close(ProcOutput);
347 for (p=procs; p!=NULL; p=p->p_next)
348 if (p->p_toproc >= 0)
349 close(p->p_toproc);
350 }
351
352 private void
kbd_init()353 kbd_init()
354 {
355 /* Initiate the keyboard process.
356 * We only get here after a portsrv process has been started
357 * so we know that the portsrv program must exist -- no need to test.
358 */
359 int p[2];
360
361 (void) pipe(p);
362 ProcInput = fd_open("process-input", F_READ|F_LOCKED, p[0],
363 (char *)NULL, 512);
364 ProcOutput = p[1];
365 switch (kbd_pid = fork()) {
366 case -1:
367 complain("Cannot fork kbd process! %s\n", strerror(errno));
368 /* NOTREACHED */
369
370 case 0:
371 (void) setsighandler(SIGINT, SIG_IGN);
372 (void) setsighandler(SIGALRM, SIG_IGN);
373 close(1);
374 dup(ProcOutput);
375 jcloseall();
376 execl(Portsrv, "kbd", (char *)NULL);
377 raw_complain("kbd exec failed: %s", strerror(errno));
378 exit(-1);
379 }
380 }
381
382 /* kbd_stop() returns true if it changes the state of (i.e. stops)
383 the keyboard process. This is so kbd stopping and starting in
384 pairs works - see finish() in jove.c. */
385
386 private bool kbd_state = NO;
387
388 void
kbd_strt()389 kbd_strt()
390 {
391 if (!kbd_state) {
392 if (kbd_pid == -1)
393 kbd_init();
394 else
395 kill(kbd_pid, KBDSIG);
396 kbd_state = YES;
397 }
398 }
399
400 bool
kbd_stop()401 kbd_stop()
402 {
403 if (kbd_state) {
404 kbd_state = NO;
405 kill(kbd_pid, KBDSIG);
406 return YES;
407 }
408 return NO;
409 }
410
411 void
kbd_kill()412 kbd_kill()
413 {
414 if (kbd_pid != -1) {
415 kill(kbd_pid, SIGKILL);
416 kbd_pid = -1;
417 }
418 }
419
420 #else /* !PIPEPROCS */
421
422 #include <sys/time.h>
423 #include <fcntl.h>
424 #include "select.h"
425
426 #include "ttystate.h"
427
428 # ifdef SVR4_PTYS
429 # include <stdlib.h> /* for grantpt and unlockpt, at least in Solaris 2.3 */
430 # include <sys/stropts.h>
431 extern char *ptsname proto((int /*filedes*/)); /* get name of slave */
432 # endif
433
434 # ifdef IRIX_PTYS
435 # include <sys/types.h>
436 # include <sys/stat.h>
437 # endif
438
439 void
read_pty_proc(fd)440 read_pty_proc(fd)
441 register int fd;
442 {
443 register Process p;
444 int n;
445 char ibuf[1024+1]; /* NOTE: room for added NUL */
446
447 for (p = procs; ; p = p->p_next) {
448 if (p == NULL) {
449 writef("\riproc: unknown fd %d", fd);
450 return;
451 }
452 if (p->p_fd == fd)
453 break;
454 }
455
456 n = read(fd, (UnivPtr) ibuf, sizeof(ibuf) - 1);
457 if (n <= 0) {
458 if (n < 0) {
459 switch (errno) {
460 case EIO:
461 case EWOULDBLOCK:
462 #if EWOULDBLOCK != EAGAIN
463 case EAGAIN:
464 #endif
465 /* ??? On some systems, pty reads fail initially, for
466 * reasons that are not clear to me (DHR). This code
467 * forgives these specific kinds of failure until the
468 * process leaves the NEW state. We hope that this
469 * does not cause a long busy wait.
470 */
471 if (p->p_io_state == IO_NEW)
472 return;
473
474 /* We get here if the i-proc closes stdout
475 * before exiting (eg. Bourne Shell),
476 * so we treat it as a simple EOF.
477 */
478 break;
479 default:
480 /* true I/O error */
481 swritef(ibuf, sizeof(ibuf),
482 "\n[pty read error: %s]\n", strerror(errno));
483 proc_rec(p, ibuf, strlen(ibuf));
484 /* now treat as EOF... */
485 }
486 } /* else, EOF received */
487 proc_close(p);
488 } else {
489 if (p->p_io_state == IO_NEW) {
490 p->p_io_state = IO_RUNNING;
491 UpdModLine = YES;
492 }
493 proc_rec(p, ibuf, (size_t)n);
494 }
495 }
496
497 void
ProcCont()498 ProcCont()
499 {
500 Process p = curbuf->b_process;
501
502 if (proc_kill(p, SIGCONT) && p->p_child_state == C_STOPPED) {
503 p->p_child_state = C_LIVE;
504 UpdModLine = YES;
505 }
506 }
507
508 /* Sending non-character info through "keyboard"
509 *
510 * There are two kinds of "out of band" signals we wish to send
511 * through the pty: signals (such as SIGINT) and EOF. On top
512 * of that, there is a kind of out of band signal we wish not to
513 * send: ERASE and KILL. Unfortunately, there are a number of ways
514 * in which our environment may vary. Two ioctls are useful:
515 * TIOCREMOTE and TIOCSIGNAL/TIOCSIG.
516 *
517 *
518 * TIOCREMOTE:
519 *
520 * Some systems support the TIOCREMOTE ioctl. With this ioctl,
521 * the "input editing" is suppressed on the characters sent
522 * to the slave. Input editing involves interpreting ERASE,
523 * KILL, INTERRUPT, QUIT, EOF, etc. characters. It is best
524 * to run this way since JOVE already does input editing.
525 *
526 * The scant documentation on TIOCREMOTE in Solaris2.3 suggests
527 * that the third argument to the TIOCREMOTE ioctl ought to be
528 * an integer (but a pointer to the integer works). The SunOS4
529 * ldterm(4m) manpage says that the third argument is to be a
530 * pointer to an integer. At the moment, we only use the pointer
531 * form.
532 *
533 * Although IRIX defines TIOCREMOTE, it does not seem to work.
534 * This may well be true of other systems, so as a safety,
535 * we support "NO_TIOCREMOTE" as a feature deselect macro
536 * for systems that define TIOCREMOTE but are broken.
537 *
538 * Under BSDI's BSD/386 v1.[01], the TIOCREMOTE ioctls appear to fail
539 * for send_xc (without an error indication), but work otherwise. This
540 * only affects dstop-process, so it is probably best not to define
541 * NO_TIOCREMOTE. Even if we do define NO_TIOCREMOTE, the dstop-process
542 * may require the user to do a process-newline (apparently, if the tty
543 * input is being canonicalized). How odd.
544 *
545 *
546 * TIOCSIGNAL/TIOCSIG:
547 *
548 * Some systems support the TIOCSIGNAL ioctl. With this ioctl,
549 * a signal can be sent through the pty. Recent (4.3 or later?)
550 * BSD systems seem to provide a TIOCSIG ioctl which is similar.
551 *
552 * The TIOCSIGNAL ioctl is not well documented and seems to be
553 * broken on at least IRIX 5.3. Again, we provide "NO_TIOCSIGNAL"
554 * to prevent using it on systems that define it but are broken.
555 *
556 * Another mystery: systems vary on how the signal number should be
557 * passed in the TIOCSIGNAL ioctl. SunOS4 requires that the third
558 * argument be a pointer to an integer, the signal number. Vanilla
559 * SVR4 requires that the third argument be a an integer, the signal
560 * number. Solaris2.3 accepts either. The SunOS 5.3 STREAMS
561 * Programmer's Guide says that the third argument is an int. We have
562 * not figured out, for an arbitrary system with TIOCSIGNAL, how to
563 * tell which form the third argument should take. For now, it is
564 * conditionalized on SVR4_PTYS.
565 *
566 * If TIOCSIGNAL/TIOCSIG isn't supplied (perhaps from termios.h), we
567 * cannot send signals to the child when TIOCREMOTE is on, so we just
568 * turn it off for a moment. This is pretty dubious because the user
569 * might have done an stty to change or disable the characters.
570 *
571 * We don't know how to implement dstop using TIOCSIGNAL/TIOCSIG, so
572 * we use the dubious trick.
573 */
574
575 # if !defined(NO_TIOCREMOTE) && !defined(TIOCREMOTE)
576 # define NO_TIOCREMOTE 1
577 # endif
578
579 # if !defined(NO_TIOCSIGNAL) && !defined(TIOCSIGNAL) && !defined(TIOCSIG)
580 # define NO_TIOCSIGNAL 1
581 # endif
582
583 # ifdef NO_TIOCSIGNAL
584
585 # define kbd_sig(sig, tch, sch) send_oxc(tch, sch)
586
587 # else /* !NO_TIOCSIGNAL */
588
589 # define kbd_sig(sig, tch, sch) send_sig(sig)
590
591 private void
send_sig(sig)592 send_sig(sig)
593 int sig;
594 {
595 Process p;
596
597 if ((p = curbuf->b_process) == NULL || p->p_fd < 0)
598 complain("[No process]");
599 ToLast();
600 # ifdef TIOCSIG
601 if (ioctl(p->p_fd, TIOCSIG, sig) < 0)
602 complain("TIOCSIG failed: %d %s", errno, strerror(errno));
603 # else /* !TIOCSIG */
604 # ifdef SVR4_PTYS
605 if (ioctl(p->p_fd, TIOCSIGNAL, sig) < 0)
606 complain("TIOCSIGNAL failed: %d %s", errno, strerror(errno));
607 # else /* !SVR4_PTYS */
608 if (ioctl(p->p_fd, TIOCSIGNAL, (void *) &sig) < 0)
609 complain("TIOCSIGNAL failed: %d %s", errno, strerror(errno));
610 # endif /* !SVR4_PTYS */
611 # endif /* !TIOCSIG */
612 }
613
614 # endif /* !NO_TIOCSIGNAL */
615
616 # if defined(NO_TIOCREMOTE) || defined(NO_TIOCSIGNAL) || (!defined(TERMIO) && !defined(TERMIOS)) || defined(VDSUSP)
617
618 # if defined(TERMIO) || defined(TERMIOS)
619 # define send_oxc(tch, sch) send_xc(sg[NO].c_cc[tch])
620 # else
621 # define send_oxc(tch, sfld) send_xc(tc[NO].sfld)
622 # endif
623
624 private void
send_xc(c)625 send_xc(c)
626 char c;
627 {
628 Process p;
629
630 if ((p = curbuf->b_process) == NULL || p->p_fd < 0)
631 complain("[No process]");
632 ToLast();
633 {
634 char buf[1+1]; /* NOTE: room for added NUL */
635
636 buf[0] = c;
637 proc_rec(p, buf, (size_t)1);
638
639 {
640 # ifndef NO_TIOCREMOTE
641 int
642 off = 0,
643 on = 1;
644
645 while (ioctl(p->p_fd, TIOCREMOTE, (UnivPtr) &off) < 0)
646 if (errno != EINTR)
647 complain("TIOCREMOTE OFF failed: %d %s", errno, strerror(errno));
648 # endif /* !NO_TIOCREMOTE */
649 for (;;) {
650 switch (write(p->p_fd, (UnivPtr) &c, sizeof(c))) {
651 case -1: /* error: consider ERRNO */
652 if (errno == EINTR)
653 continue; /* interrupted: try again */
654 complain("pty write of control failed: %d %s", errno, strerror(errno));
655 /* NOTREACHED */
656 case 0: /* nothing happened: try again */
657 continue;
658 case 1: /* done */
659 break;
660 }
661 break;
662 }
663 # ifndef NO_TIOCREMOTE
664 while (ioctl(p->p_fd, TIOCREMOTE, (UnivPtr) &on) < 0)
665 if (errno != EINTR)
666 complain("TIOCREMOTE ON failed: %d %s", errno, strerror(errno));
667 # endif /* !NO_TIOCREMOTE */
668 }
669 }
670 }
671
672 # endif /* defined(NO_TIOCREMOTE) || defined(NO_TIOCSIGNAL) */
673
674 void
ProcEof()675 ProcEof()
676 {
677 # ifdef NO_TIOCREMOTE
678 /* we have to write a char */
679 send_oxc(VEOF, t_eofc);
680 # else /* !NO_TIOCREMOTE */
681 /* write a zero-length record to signify EOF */
682 static char mess[] = "<EOF> "; /* NOTE: NUL will be overwritten */
683 Process p;
684
685 if ((p = curbuf->b_process) == NULL || p->p_fd < 0)
686 complain("[No process]");
687 ToLast();
688 proc_rec(p, mess, sizeof(mess)-1);
689 while (write(p->p_fd, (UnivPtr) mess, (size_t)0) < 0)
690 if (errno != EINTR)
691 complain("[error writing EOF to iproc: %d %s]", errno, strerror(errno));
692 # endif /* !NO_TIOCREMOTE */
693 }
694
695 void
ProcInt()696 ProcInt()
697 {
698 kbd_sig(SIGINT, VINTR, t_intrc);
699 }
700
701 void
ProcQuit()702 ProcQuit()
703 {
704 kbd_sig(SIGQUIT, VQUIT, t_quitc);
705 }
706
707 void
ProcStop()708 ProcStop()
709 {
710 # if (!defined(TERMIO) && !defined(TERMIOS)) || defined(VSUSP)
711 kbd_sig(SIGTSTP, VSUSP, t_suspc);
712 # else
713 complain("[stop-process not supported]");
714 # endif
715 }
716
717 void
ProcDStop()718 ProcDStop()
719 {
720 /* we don't know how to send a dstop via TIOCSIGNAL/TIOCSIG */
721 # if (!defined(TERMIO) && !defined(TERMIOS)) || defined(VDSUSP)
722 send_oxc(VDSUSP, t_dsuspc);
723 # else
724 complain("[dstop-process not supported]");
725 # endif
726 }
727
728 private void
proc_close(p)729 proc_close(p)
730 Process p;
731 {
732 if (p->p_fd >= 0) {
733 (void) close(p->p_fd);
734 FD_CLR(p->p_fd, &global_fd);
735 p->p_fd = -1;
736 p->p_io_state = IO_EOFED; /* I/O is finished */
737 UpdModLine = YES;
738 }
739 }
740
741 private void
proc_write(p,buf,nbytes)742 proc_write(p, buf, nbytes)
743 Process p;
744 char *buf;
745 size_t nbytes;
746 {
747 if (p->p_fd >= 0) {
748 fd_set mask;
749
750 FD_ZERO(&mask);
751 FD_SET(p->p_fd, &mask);
752 while (write(p->p_fd, (UnivPtr) buf, nbytes) < 0)
753 (void) select(p->p_fd + 1, (fd_set *)NULL, &mask, (fd_set *)NULL,
754 (struct timeval *)NULL);
755 }
756 }
757
758 # ifdef STDARGS
759 private void
proc_strt(char * bufname,bool clobber,char * procname,...)760 proc_strt(char *bufname, bool clobber, char *procname, ...)
761 # else
762 private /*VARARGS2*/ void
763 proc_strt(bufname, clobber, procname, va_alist)
764 char *bufname;
765 bool clobber;
766 char *procname;
767 va_dcl
768 # endif
769 {
770 va_list ap;
771 char *argv[32];
772 Window *owind = curwind;
773 pid_t pid;
774 Process newp;
775 Buffer *newbuf;
776 int i,
777 ptyfd = -1;
778
779 # if !defined(TERMIO) && !defined(TERMIOS)
780 # ifdef TIOCSETD
781 int ldisc; /* tty line discipline */
782 # endif
783 # ifdef TIOCLSET
784 int lmode; /* tty local flags */
785 # endif
786 # endif
787 register char *s,
788 *t;
789 char ttybuf[32];
790 # ifdef TERMIO
791 struct termio sgt;
792 # endif
793 # ifdef TERMIOS
794 struct termios sgt;
795 # endif
796 # ifdef SGTTY
797 struct sgttyb sgt;
798 # endif
799
800 # ifdef TIOCGWINSZ
801 struct winsize win;
802 # else
803 # ifdef BTL_BLIT
804 # include <sys/jioctl.h>
805 struct jwinsize jwin;
806 # endif
807 # endif
808
809 untieDeadProcess(buf_exists(bufname));
810 isprocbuf(bufname); /* make sure BUFNAME is either nonexistant
811 or is of type B_PROCESS */
812 va_init(ap, procname);
813 make_argv(argv, ap);
814 va_end(ap);
815 if (access(argv[0], X_OK) != 0) {
816 complain("[Couldn't access %s: %s]", argv[0], strerror(errno));
817 /* NOTREACHED */
818 }
819
820 # ifdef IRIX_PTYS
821 /*
822 * _getpty may fork off a child to execute mkpts to make a slave pty
823 * in /dev (if we need more) and set the correct ownership and
824 * modes on the slave pty. Since _getpty uses waitpid this works
825 * fine with regard to our other children, but we do have to be
826 * prepared to catch a SIGCHLD for an unknown child and ignore it ...
827 */
828 s = _getpty(&ptyfd, O_RDWR|O_NDELAY, 0600, 0);
829 if (s == NULL) {
830 message("[No ptys!]");
831 goto fail;
832 }
833 (void)strcpy(ttybuf, s);
834 # endif /* IRIX_PTYS */
835 # ifdef SVR4_PTYS
836 if ((ptyfd = open("/dev/ptmx", O_RDWR)) < 0) {
837 message("[No ptys!]");
838 goto fail;
839 }
840 # ifndef GRANTPT_BUG
841 /* grantpt() seems to be implemented using a fork/exec.
842 * This is done to allow grantpt do do priviledged things
843 * via a setuid program. One consequence is that JOVE's
844 * SIGCLD/SIGCHLD handler must not do a wait that would
845 * reap the grantpt process. So much for library routines
846 * being black boxes. Worse, this restriction is not documented.
847 */
848 if (grantpt(ptyfd) < 0) {
849 message("[grantpt failed]");
850 goto fail;
851 }
852 if (unlockpt(ptyfd) < 0) {
853 message("[unlockpt failed]");
854 goto fail;
855 }
856 # endif /* !GRANTPT_BUG */
857 if ((s = ptsname(ptyfd)) == NULL) {
858 message("[ptsname failed]");
859 goto fail;
860 }
861 strcpy(ttybuf, s);
862 (void) ioctl(ptyfd, TIOCFLUSH, (UnivPtr) NULL); /* ??? why? */
863 # endif /* SVR4_PTYS */
864 # ifdef BSD_PTYS
865 for (s = "pqrs"; ptyfd<0; s++) {
866 if (*s == '\0') {
867 message("[Out of ptys!]");
868 goto fail;
869 }
870 for (t = "0123456789abcdef"; *t; t++) {
871 swritef(ttybuf, sizeof(ttybuf), "/dev/pty%c%c", *s, *t);
872 if ((ptyfd = open(ttybuf, 2)) >= 0) {
873 ttybuf[5] = 't'; /* pty => tty */
874 # ifdef NEVER
875 /* Make sure both ends are available.
876 * ??? This code seems to confuse BSDI's BSD/386 v1.[01]
877 * so we have eliminated it. We leave this scar
878 * in case the checking was in fact useful on other
879 * systems. Part of this checking will still be
880 * done by the "access" below, but with no recovery.
881 */
882 if ((i = open(ttybuf, 2)) < 0) {
883 (void) close(ptyfd);
884 ptyfd = -1;
885 } else {
886 (void) close(i);
887 break;
888 }
889 # else
890 break;
891 # endif
892 }
893 }
894 }
895 # endif /* BSD_PTYS */
896 /* Check that we can write to the pty, else things will fail in the
897 * child, where they're harder to detect. This will not work with
898 * GRANTPT_BUG because the grantpt and unlockpt have not been done yet.
899 */
900 # ifndef GRANTPT_BUG
901 if (access(ttybuf, W_OK) != 0) {
902 int ugh = errno;
903
904 message("[Couldn't access ");
905 message(ttybuf);
906 message(": ");
907 message(strerror(ugh));
908 message("]");
909 goto fail;
910 }
911 # endif /* !GRANTPT_BUG */
912
913 # if !defined(TERMIO) && !defined(TERMIOS)
914 # ifdef TIOCGETD
915 (void) ioctl(0, TIOCGETD, (UnivPtr) &ldisc);
916 # endif
917 # ifdef TIOCLGET
918 (void) ioctl(0, TIOCLGET, (UnivPtr) &lmode);
919 # endif
920 # endif /* !defined(TERMIO) && !defined(TERMIOS) */
921
922 # ifdef TIOCGWINSZ
923 (void) ioctl(0, TIOCGWINSZ, (UnivPtr) &win);
924 # else
925 # ifdef BTL_BLIT
926 (void) ioctl(0, JWINSIZE, (UnivPtr) &jwin);
927 # endif /* BTL_BLIT */
928 # endif
929
930 switch (pid = fork()) {
931 case -1:
932 /* fork failed */
933
934 {
935 int ugh = errno; /* hold across library calls */
936
937 message("[Fork failed! ");
938 message(strerror(ugh));
939 message("]");
940 goto fail;
941 }
942
943 case 0:
944 /* child process */
945
946 # ifdef GRANTPT_BUG
947 /* grantpt() seems to be implemented using a fork/exec.
948 * This is done to allow grantpt do do priviledged things
949 * via a setuid program. One consequence is that JOVE's
950 * SIGCLD/SIGCHLD handler must not do a wait that would
951 * reap the grantpt process. So much for library routines
952 * being black boxes. Worse, this restriction is not documented.
953 *
954 * Worse still, at least Solaris 2.0 and SVR4.0 appear to have
955 * a bug: the wait is not restarted once interrupted. If the wait
956 * is interrupted, (1) the grantpt will return a failure status
957 * and (2) the process will not be reaped -- it will remain a
958 * zombie until JOVE exits or happens to reap it accidentally.
959 * Any interrupt could cause the premature end of the wait,
960 * but SIGCHLD (actually, SIGCLD) is the most probable.
961 *
962 * To dodge these bullets, we moved the grantpt into the child
963 * where we can turn off signal handling. Too bad this prevents
964 * us giving good diagnostics for grantpt and unlockpt.
965 * I hope I've found all the signals caught everywhere else.
966 */
967 (void) setsighandler(SIGCHLD, SIG_DFL);
968 (void) setsighandler(SIGWINCH, SIG_DFL);
969 (void) setsighandler(SIGALRM, SIG_DFL);
970 (void) setsighandler(SIGINT, SIG_DFL);
971 /* (void) setsighandler(SIGQUIT, SIG_DFL); */ /* dead anyway */
972 /* (void) setsighandler(SIGHUP, SIG_DFL); */ /* dead anyway */
973 /* (void) setsighandler(SIGTERM, SIG_DFL); */ /* no longer used */
974 /* (void) setsighandler(SIGBUS, SIG_DFL); */ /* dead anyway */
975 /* (void) setsighandler(SIGSEGV, SIG_DFL); */ /* dead anyway */
976 /* (void) setsighandler(SIGPIPE, SIG_DFL); */ /* dead anyway */
977
978 if (grantpt(ptyfd) < 0) {
979 _exit(errno + 1);
980 }
981
982 if (unlockpt(ptyfd) < 0) {
983 _exit(errno + 1);
984 }
985 # endif /* GRANTPT_BUG */
986 jcloseall();
987 (void) close(0);
988 (void) close(1);
989 (void) close(2);
990
991 # ifdef TERMIOS
992 setsid();
993 # else /* !TERMIOS */
994 # ifdef TIOCNOTTY
995 /* get rid of controlling tty */
996 if ((i = open("/dev/tty", 2)) >= 0) {
997 (void) ioctl(i, TIOCNOTTY, (UnivPtr)NULL);
998 (void) close(i);
999 }
1000 # endif /* TIOCNOTTY */
1001 # endif /* !TERMIOS */
1002 if (open(ttybuf, 2) != 0)
1003 _exit(errno+1);
1004 (void) dup2(0, 1);
1005 (void) dup2(0, 2);
1006
1007 # ifdef SVR4_PTYS
1008 (void) ioctl(0, I_PUSH, (UnivPtr) "ptem");
1009 (void) ioctl(0, I_PUSH, (UnivPtr) "ldterm");
1010 (void) ioctl(0, I_PUSH, (UnivPtr) "ttcompat");
1011 # endif
1012
1013 # ifdef TIOCSCTTY
1014 /* This is needed by OSF. It may be needed by BSDPOSIX systems.
1015 * It should not hurt any system that define TIOCSCTTY.
1016 */
1017 (void) ioctl(0, TIOCSCTTY); /* make this controling tty */
1018 # endif
1019
1020 # ifndef NO_TIOCREMOTE
1021 /* The TIOCREMOTE ioctl prevents the pty code from doing
1022 * input editing on characters from the master. In particular
1023 * we don't want ERASE, KILL, INTERRUPT, QUIT, etc. characters
1024 * interpreted.
1025 * On SVR4, this must be done *after* the slave side is set up.
1026 * The easiest way to ensure this is to put it here, in the child
1027 * after the slave is opened and has the STREAMS modules pushed,
1028 * and before the master is closed.
1029 */
1030 {
1031 int on = 1;
1032
1033 if (ioctl(ptyfd, TIOCREMOTE, (UnivPtr) &on) < 0)
1034 _exit(errno+1); /* no good way to signal user */
1035 }
1036 # endif
1037 close(ptyfd);
1038
1039 # if !defined(TERMIO) && !defined(TERMIOS)
1040 # ifdef TIOCSETD
1041 (void) ioctl(0, TIOCSETD, (UnivPtr) &ldisc);
1042 # endif
1043 # ifdef TIOCLSET
1044 (void) ioctl(0, TIOCLSET, (UnivPtr) &lmode);
1045 # endif
1046 # ifdef TIOCSETC
1047 (void) ioctl(0, TIOCSETC, (UnivPtr) &tc[NO]);
1048 # endif
1049 # ifdef USE_TIOCSLTC
1050 (void) ioctl(0, TIOCSLTC, (UnivPtr) &ls[NO]);
1051 # endif
1052 # endif /* !defined(TERMIO) && !defined(TERMIOS) */
1053
1054 # ifdef TIOCGWINSZ
1055 win.ws_row = curwind->w_height;
1056 (void) ioctl(0, TIOCSWINSZ, (UnivPtr) &win);
1057 # else /* !TIOCGWINSZ */
1058 # ifdef BTL_BLIT
1059 jwin.bytesy = curwind->w_height;
1060 (void) ioctl(0, JSWINSIZE, (UnivPtr) &jwin);
1061 # endif
1062 # endif /* !TIOCGWINSZ */
1063
1064 # if defined(TERMIO) || defined(TERMIOS)
1065 sgt = sg[NO];
1066 sgt.c_iflag &= ~(IGNBRK | BRKINT | ISTRIP | INLCR | IGNCR | ICRNL
1067 # ifdef IXANY /* not in QNX */
1068 | IXANY
1069 # endif
1070 | IXON | IXOFF);
1071 sgt.c_lflag &= ~(ECHO);
1072 sgt.c_oflag &= ~(ONLCR | TABDLY);
1073 # ifdef TERMIO
1074 do ; while (ioctl(0, TCSETAW, (UnivPtr) &sgt) < 0 && errno == EINTR);
1075 # endif
1076 # ifdef TERMIOS
1077 do ; while (tcsetattr(0, TCSADRAIN, &sgt) < 0 && errno == EINTR);
1078 # endif
1079 # else /* !(defined(TERMIO) || defined(TERMIOS)) */
1080 sgt = sg[NO];
1081 sgt.sg_flags &= ~(ECHO | CRMOD | ANYP | ALLDELAY | RAW | LCASE | CBREAK | TANDEM);
1082 (void) stty(0, &sgt);
1083 # endif /* !(defined(TERMIO) || defined(TERMIOS)) */
1084
1085 NEWPG();
1086 # ifdef POSIX_PROCS
1087 tcsetpgrp(0, getpid());
1088 # else /* !POSIX_PROCS */
1089 i = getpid();
1090 (void) ioctl(0, TIOCSPGRP, (UnivPtr) &i);
1091 # endif /* POSIX_PROCS */
1092
1093 jputenv("EMACS=t");
1094 jputenv("TERM=emacs");
1095 /* ??? the following line is not useful for terminfo systems */
1096 jputenv(sprint("TERMCAP=emacs:co#%d:tc=unknown:", CO-1));
1097 execvp(argv[0], &argv[1]);
1098 raw_complain("execvp failed! %s", strerror(errno));
1099 _exit(errno + 1);
1100 }
1101
1102 newp = (Process) emalloc(sizeof *newp);
1103
1104 # ifdef O_NDELAY
1105 fcntl(ptyfd, F_SETFL, O_NDELAY);
1106 # endif
1107 # ifdef O_NONBLOCK
1108 fcntl(ptyfd, F_SETFL, O_NONBLOCK);
1109 # endif
1110 newp->p_fd = ptyfd;
1111 newp->p_pid = pid;
1112
1113 newbuf = do_select((Window *)NULL, bufname);
1114 newbuf->b_type = B_PROCESS;
1115 newp->p_buffer = newbuf;
1116 newbuf->b_process = newp; /* sorta circular, eh? */
1117 pop_wind(bufname, clobber, B_PROCESS);
1118 /* Pop_wind() after everything is set up; important!
1119 Bindings won't work right unless newbuf->b_process is already
1120 set up BEFORE NEWBUF is first SetBuf()'d. */
1121 ToLast();
1122 if (!bolp())
1123 LineInsert(1);
1124
1125 newp->p_name = copystr(procname);
1126 newp->p_io_state = IO_NEW;
1127 newp->p_child_state = C_LIVE;
1128 newp->p_mark = MakeMark(curline, curchar);
1129 newp->p_dbx_mode = NO;
1130
1131 newp->p_next = procs;
1132 procs = newp;
1133 FD_SET(newp->p_fd, &global_fd);
1134 if (global_maxfd <= newp->p_fd)
1135 global_maxfd = newp->p_fd + 1;
1136 SetWind(owind);
1137 return;
1138
1139 fail:
1140 if (ptyfd >= 0)
1141 close(ptyfd);
1142 }
1143
1144 /* NOTE 1: SIGCHLD is an asynchronous signal. To safely handle it,
1145 * the sigchld_handler simply sets a flag requesting later processing.
1146 * reap_procs is called synchronously to do the actual work.
1147 *
1148 * NOTE 2: SIGCHLD is "level triggered" on some systems (HPUX, IRIX, ...).
1149 * If the signal signal handler is re-established before the child is reaped,
1150 * another signal will be generated immediately. For this reason, we
1151 * defer the re-establishment until reap_procs is done.
1152 */
1153
1154 volatile bool procs_to_reap = NO;
1155
1156 /*ARGSUSED*/
1157 SIGRESTYPE
sigchld_handler(junk)1158 sigchld_handler(junk)
1159 int junk; /* needed for signal handler; not used */
1160 {
1161 procs_to_reap = YES;
1162 return SIGRESVALUE;
1163 }
1164
1165 void
reap_procs()1166 reap_procs()
1167 {
1168 wait_status_t w;
1169 register pid_t pid;
1170
1171 for (;;) {
1172 pid = wait_opt(&w, (WNOHANG | WUNTRACED));
1173 if (pid <= 0) {
1174 if (procs_to_reap) {
1175 resetsighandler(SIGCHLD, sigchld_handler);
1176 procs_to_reap = NO;
1177 /* go around once more to avoid window of vulnerability */
1178 } else {
1179 break;
1180 }
1181 } else {
1182 kill_off(pid, w);
1183 }
1184 }
1185 }
1186
1187 void
closeiprocs()1188 closeiprocs()
1189 {
1190 Process p;
1191
1192 for (p=procs; p!=NULL; p=p->p_next)
1193 if (p->p_fd >= 0)
1194 close(p->p_fd);
1195 }
1196
1197 #endif /* !PIPEPROCS */
1198
1199 extern char **environ;
1200
1201 private void
jputenv(def)1202 jputenv(def)
1203 char *def; /* Note: caller must ensure string persists */
1204 {
1205 char **p, *eq;
1206 static int headroom = -1; /* trick: -1 is flag for first time */
1207
1208 if ((eq = strchr(def, '=')) == NULL)
1209 return;
1210
1211 for (p = environ; ; p++) {
1212 if (*p == NULL) {
1213 if (headroom <= 0) {
1214 # define JENV_INCR 5
1215 size_t sz = ((p-environ) + 1) * sizeof(char *);
1216 char **ne = (char **)malloc(sz + JENV_INCR*sizeof(char *));
1217
1218 if (ne == NULL)
1219 break;
1220 byte_copy(environ, ne, sz);
1221 p = ne + (p-environ);
1222 if (headroom == 0)
1223 free((UnivPtr)environ);
1224 headroom = JENV_INCR;
1225 environ = ne;
1226 # undef JENV_INCR
1227 }
1228 headroom -= 1;
1229 *p++ = def;
1230 *p = NULL;
1231 break;
1232 }
1233 if (strncmp(*p, def, (size_t) (eq - def + 1)) == 0) {
1234 *p = def;
1235 break;
1236 }
1237 }
1238 }
1239
1240 char proc_prompt[128] = "% "; /* VAR: process prompt */
1241
1242 const char *
dbxness(p)1243 dbxness(p)
1244 Process p;
1245 {
1246 return (p == NULL || !p->p_dbx_mode)? NullStr : "DBX ";
1247 }
1248
1249 const char *
pstate(p)1250 pstate(p)
1251 Process p;
1252 {
1253 static const char *const ios_name[] = { "New", "Running", "EOFed" };
1254
1255 if (p == NULL)
1256 return "No process";
1257
1258 /* Try *not* to report the whole cross-product of child and IO states. */
1259 switch (p->p_child_state) {
1260 case C_LIVE:
1261 return ios_name[p->p_io_state];
1262 case C_STOPPED:
1263 return io_eofed(p)? "Stopped; EOFed" : "Stopped";
1264 case C_EXITED:
1265 if (io_eofed(p) && p->p_reason == 0)
1266 return "Done";
1267 /* FALLTHROUGH */
1268 default:
1269 return sprint("%s %d%s",
1270 (p->p_child_state == C_EXITED? "Exited" : "Killed"),
1271 p->p_reason,
1272 (io_eofed(p)? "" : "; not EOFed"));
1273 }
1274 }
1275
1276 bool
KillProcs()1277 KillProcs()
1278 {
1279 register Process p;
1280 bool asked = NO;
1281
1282 for (p = procs; p != NULL; p = p->p_next) {
1283 if (!dead(p)) {
1284 if (!asked) {
1285 if (!yes_or_no_p("Some interactive processes are still running; leave anyway? "))
1286 return NO; /* processes not killed */
1287 asked = YES;
1288 }
1289 if (!child_dead(p))
1290 (void) proc_kill(p, SIGKILL);
1291 proc_close(p);
1292 }
1293 }
1294 return YES; /* processes killed */
1295 }
1296
1297 /* VAR: dbx-mode parse string */
1298 char dbx_parse_fmt[128] = "line \\([0-9]*\\) in \\{file\\|\\} *\"\\([^\"]*\\)\"";
1299
1300 void
DBXpoutput()1301 DBXpoutput()
1302 {
1303 if (curbuf->b_process == NULL)
1304 complain("[Must be in a process buffer to enable dbx mode]");
1305 curbuf->b_process->p_dbx_mode = !curbuf->b_process->p_dbx_mode;
1306 UpdModLine = YES;
1307 }
1308
1309 private void
watch_input(m)1310 watch_input(m)
1311 Mark *m;
1312 {
1313 Bufpos save;
1314 char fname[FILESIZE],
1315 lineno[FILESIZE];
1316 int lnum;
1317 Window *savew = curwind;
1318 Buffer *buf;
1319
1320 DOTsave(&save);
1321 ToMark(m);
1322 if (dosearch(dbx_parse_fmt, FORWARD, YES) != NULL) {
1323 get_FL_info(fname, lineno);
1324 buf = do_find((Window *)NULL, fname, YES, YES);
1325 pop_wind(buf->b_name, NO, -1);
1326 lnum = atoi(lineno);
1327 SetLine(next_line(buf->b_first, lnum - 1));
1328 SetWind(savew);
1329 }
1330 SetDot(&save);
1331 }
1332
1333 /* Process receive: receives the characters in buf, and appends them to
1334 the buffer associated with p. */
1335
1336 private void
proc_rec(p,buf,len)1337 proc_rec(p, buf, len)
1338 register Process p;
1339 char *buf;
1340 size_t len;
1341 {
1342 Buffer *saveb = curbuf;
1343 register Window *w;
1344 register Mark *savepoint;
1345 bool sameplace,
1346 do_disp;
1347
1348 if (curwind->w_bufp == p->p_buffer)
1349 w = curwind;
1350 else
1351 w = windbp(p->p_buffer); /* Is this window visible? */
1352 do_disp = w != NULL && in_window(w, p->p_mark->m_line) != -1;
1353 SetBuf(p->p_buffer);
1354 savepoint = MakeMark(curline, curchar);
1355 ToMark(p->p_mark); /* where output last stopped */
1356 sameplace = savepoint->m_line == curline && savepoint->m_char == curchar;
1357
1358 /* insert contents of buffer, carefully translating NUL to ^@ */
1359 buf[len] = '\0'; /* NUL-terminate buffer */
1360 while (len != 0) {
1361 if (*buf == '\0') {
1362 ins_str_wrap("^@", YES, WrapProcessLines ? CO-1 : LBSIZE-1);
1363 buf++;
1364 len--;
1365 } else {
1366 size_t sublen = strlen(buf);
1367
1368 ins_str_wrap(buf, YES, WrapProcessLines ? CO-1 : LBSIZE-1);
1369 buf += sublen;
1370 len -= sublen;
1371 }
1372 }
1373
1374 if (do_disp && p->p_dbx_mode)
1375 watch_input(p->p_mark);
1376 MarkSet(p->p_mark, curline, curchar);
1377 if (!sameplace)
1378 ToMark(savepoint); /* back to where we were */
1379 DelMark(savepoint);
1380 /* redisplay now, instead of right after the ins_str, so that
1381 we don't get a bouncing effect if point is not the same as
1382 the process output position */
1383 if (do_disp) {
1384 w->w_line = curline;
1385 w->w_char = curchar;
1386 redisplay();
1387 }
1388 SetBuf(saveb);
1389 }
1390
1391 private bool
proc_kill(p,sig)1392 proc_kill(p, sig)
1393 register Process p;
1394 int sig;
1395 {
1396 if (p == NULL)
1397 complain("[no process]");
1398 if (!child_dead(p)) {
1399 if (killpg(p->p_pid, sig) != -1)
1400 return YES;
1401 s_mess("Cannot kill %s!", proc_bufname(p));
1402 }
1403 return NO;
1404 }
1405
1406 /* Free process CHILD. Do all the necessary cleaning up (closing fd's,
1407 etc.). */
1408
1409 private void
free_proc(child)1410 free_proc(child)
1411 Process child;
1412 {
1413 register Process
1414 p,
1415 prev = NULL;
1416
1417 if (!dead(child))
1418 return;
1419 untieDeadProcess(child->p_buffer);
1420
1421 for (p = procs; p != child; prev = p, p = p->p_next)
1422 ;
1423
1424 if (prev == NULL)
1425 procs = child->p_next;
1426 else
1427 prev->p_next = child->p_next;
1428 proc_close(child); /* if not already closed */
1429
1430 free((UnivPtr) child->p_name);
1431 free((UnivPtr) child);
1432 }
1433
1434 void
untieDeadProcess(b)1435 untieDeadProcess(b)
1436 register Buffer *b;
1437 {
1438 if (b != NULL) {
1439 register Process p = b->b_process;
1440
1441 if (p != NULL) {
1442 Buffer *old = curbuf;
1443
1444 if (!dead(p))
1445 complain("Process %s, attached to %b, is %s.",
1446 proc_cmd(p), b, pstate(p));
1447 SetBuf(p->p_buffer);
1448 DelMark(p->p_mark);
1449 SetBuf(old);
1450 p->p_buffer = NULL;
1451 b->b_process = NULL;
1452 }
1453 }
1454 }
1455
1456 void
ProcList()1457 ProcList()
1458 {
1459 register Process
1460 p,
1461 next;
1462 char *fmt = "%-15s %-15s %-8s %s",
1463 pidstr[16];
1464
1465 if (procs == NULL) {
1466 message("[No subprocesses]");
1467 return;
1468 }
1469 TOstart("Process list");
1470
1471 Typeout(fmt, "Buffer", "Status", "Pid ", "Command");
1472 Typeout(fmt, "------", "------", "--- ", "-------");
1473 for (p = procs; p != NULL; p = next) {
1474 next = p->p_next;
1475 swritef(pidstr, sizeof(pidstr), "%d", (int) p->p_pid);
1476 Typeout(fmt, proc_bufname(p), pstate(p), pidstr, p->p_name);
1477 if (dead(p)) {
1478 free_proc(p);
1479 UpdModLine = YES;
1480 }
1481 }
1482 TOstop();
1483 }
1484
1485 private void
do_rtp(mp)1486 do_rtp(mp)
1487 register Mark *mp;
1488 {
1489 register Process p = curbuf->b_process;
1490 LinePtr line1 = curline,
1491 line2 = mp->m_line;
1492 int char1 = curchar,
1493 char2 = mp->m_char;
1494 char *gp;
1495 size_t nbytes;
1496
1497 if (dead(p) || p->p_buffer != curbuf)
1498 return;
1499
1500 (void) fixorder(&line1, &char1, &line2, &char2);
1501 while (line1 != line2->l_next) {
1502 gp = ltobuf(line1, genbuf) + char1;
1503 if (line1 == line2) {
1504 nbytes = char2 - char1;
1505 } else {
1506 genbuf[Jr_Len] = EOL; /* replace NUL with EOL */
1507 nbytes = Jr_Len - char1 + 1; /* and include it */
1508 }
1509 if (nbytes != 0)
1510 proc_write(p, gp, nbytes);
1511 line1 = line1->l_next;
1512 char1 = 0;
1513 }
1514 }
1515
1516 void
ProcNewline()1517 ProcNewline()
1518 {
1519 #ifdef ABBREV
1520 MaybeAbbrevExpand();
1521 #endif
1522 SendData(YES);
1523 }
1524
1525 void
ProcSendData()1526 ProcSendData()
1527 {
1528 #ifdef ABBREV
1529 MaybeAbbrevExpand();
1530 #endif
1531 SendData(NO);
1532 }
1533
1534 private void
SendData(newlinep)1535 SendData(newlinep)
1536 bool newlinep;
1537 {
1538 register Process p = curbuf->b_process;
1539 register char *lp,
1540 *gp; /* JF fix for better prompt handling */
1541
1542 if (dead(p))
1543 return;
1544 /* If the process mark was involved in a big deletion, because
1545 the user hit ^W or something, then let's do some magic with
1546 the process mark. Problem is that if the user yanks back the
1547 text he deleted, the mark stays at the beginning of the region,
1548 and so the next time SendData() is called the entire region
1549 will be sent. That's not good. So, to deal with that we reset
1550 the mark to the last line, after skipping over the prompt, etc. */
1551 if (p->p_mark->m_big_delete) {
1552 Bufpos bp;
1553
1554 p->p_mark->m_big_delete = NO;
1555
1556 DOTsave(&bp);
1557 ToLast();
1558 Bol();
1559 /* While we're looking at a prompt, and while we're
1560 moving forward. This is for people who accidently
1561 set their process-prompt to ">*" which will always
1562 match! */
1563 while (LookingAt(proc_prompt, linebuf, curchar)
1564 && (REeom > curchar))
1565 curchar = REeom;
1566 MarkSet(p->p_mark, curline, curchar);
1567 SetDot(&bp);
1568 }
1569
1570 if (lastp(curline)) {
1571 Eol();
1572 if (newlinep)
1573 LineInsert(1);
1574 do_rtp(p->p_mark);
1575 MarkSet(p->p_mark, curline, curchar);
1576 } else {
1577 /* Either we're looking at a prompt, or we're not, in
1578 which case we want to strip off the beginning of the
1579 line anything that looks like what the prompt at the
1580 end of the file is. In other words, if "(dbx) stop in
1581 ProcessNewline" is the line we're on, and the last
1582 line in the buffer is "(dbx) ", then we strip off the
1583 leading "(dbx) " from this line, because we know it's
1584 part of the prompt. But this only happens if "(dbx) "
1585 isn't one of the process prompts ... follow what I'm
1586 saying? */
1587 Bol();
1588 if (LookingAt(proc_prompt, linebuf, curchar)) {
1589 do {
1590 curchar = REeom;
1591 } while (LookingAt(proc_prompt, linebuf, curchar)
1592 && (REeom > curchar));
1593 strcpy(genbuf, linebuf + curchar);
1594 Eof();
1595 ins_str(genbuf);
1596 } else {
1597 strcpy(genbuf, linebuf + curchar);
1598 Eof();
1599 gp = genbuf;
1600 lp = linebuf;
1601 while (*lp == *gp && *lp != '\0') {
1602 lp += 1;
1603 gp += 1;
1604 }
1605 ins_str(gp);
1606 }
1607 }
1608 }
1609
1610 void
ShellProc()1611 ShellProc()
1612 {
1613 char shbuf[20];
1614 register Buffer *b;
1615
1616 swritef(shbuf, sizeof(shbuf), "*shell-%d*", arg_value());
1617 b = buf_exists(shbuf);
1618 if (b == NULL || dead(b->b_process))
1619 proc_strt(shbuf, NO, "i-shell", Shell, "-is", pr_name(curbuf->b_fname, NO),
1620 (char *)NULL);
1621 pop_wind(shbuf, NO, -1);
1622 }
1623
1624 void
Iprocess()1625 Iprocess()
1626 {
1627 char scratch[64],
1628 *bnm;
1629 int cnt = 1;
1630 Buffer *bp;
1631 char *fn = pr_name(curbuf->b_fname, NO);
1632
1633 null_ncpy(ShcomBuf, ask(ShcomBuf, ProcFmt), (sizeof ShcomBuf) - 1);
1634 bnm = MakeName(ShcomBuf);
1635 null_ncpy(scratch, bnm, (sizeof scratch) - 1);
1636 while ((bp = buf_exists(scratch)) != NULL && !dead(bp->b_process))
1637 swritef(scratch, sizeof(scratch), "%s.%d", bnm, cnt++);
1638 proc_strt(scratch, YES, ShcomBuf, Shell, ShFlags, ShcomBuf, fn, fn, (char *)NULL);
1639 }
1640
1641 pid_t DeadPid; /* info about ChildPid, if reaped by kill_off */
1642 wait_status_t DeadStatus;
1643
1644 #ifdef USE_PROTOTYPES
1645 void
kill_off(pid_t pid,wait_status_t w)1646 kill_off(pid_t pid, wait_status_t w)
1647 #else
1648 void
1649 kill_off(pid, w)
1650 register pid_t pid;
1651 wait_status_t w;
1652 #endif
1653 {
1654 register Process child;
1655
1656 if (pid == ChildPid) {
1657 /* we are reaping the non-iproc process: record info */
1658 DeadPid = pid;
1659 DeadStatus = w;
1660 return;
1661 }
1662
1663 if ((child = proc_pid(pid)) == NULL)
1664 return;
1665
1666 UpdModLine = YES; /* we're changing state ... */
1667 if (WIFSTOPPED(w))
1668 child->p_child_state = C_STOPPED;
1669 else {
1670 #ifdef PIPEPROCS
1671 /* the true process status comes by pipe, not from wait().
1672 * However, we must note the death of portsrv processes.
1673 */
1674 child->p_portlive = NO;
1675 #else /* !PIPEPROCS */
1676 /* record the details of the death of the process.
1677 * Kludge: see if we can get any queued EOF from pty first.
1678 * We wish to do this to make our message less confusing.
1679 */
1680 while (!io_eofed(child)) {
1681 int nfds;
1682 fd_set reads;
1683 struct timeval notime;
1684
1685 FD_ZERO(&reads);
1686 FD_SET(child->p_fd, &reads);
1687 notime.tv_sec = 0;
1688 notime.tv_usec = 0;
1689 nfds = select(global_maxfd, &reads,
1690 (fd_set *)NULL, (fd_set *)NULL, ¬ime);
1691 if (nfds == 1)
1692 read_pty_proc(child->p_fd);
1693 else if (nfds >= 0 || errno != EINTR) {
1694 # ifdef NO_EOF_FROM_PTY
1695 /* Certain systems never indicate EOF from a slave.
1696 * On those systems, we force a close when the direct
1697 * child terminates.
1698 */
1699 proc_close(child);
1700 # endif
1701 break;
1702 }
1703 }
1704 obituary(child, w);
1705 #endif /* !PIPEPROCS */
1706 }
1707 }
1708
1709 #ifdef USE_PROTOTYPES
1710 private void
obituary(register Process child,wait_status_t w)1711 obituary(register Process child, wait_status_t w)
1712 #else
1713 private void
1714 obituary(child, w)
1715 register Process child;
1716 wait_status_t w;
1717 #endif
1718 {
1719 UpdModLine = YES; /* we're changing state ... */
1720 if (WIFEXITED(w)) {
1721 child->p_child_state = C_EXITED;
1722 child->p_reason = WEXITSTATUS(w);
1723 } else if (WIFSIGNALED(w)) {
1724 child->p_child_state = C_KILLED;
1725 child->p_reason = WTERMSIG(w);
1726 } else {
1727 /* presume it died peacefully! */
1728 child->p_child_state = C_EXITED;
1729 child->p_reason = 0;
1730 }
1731
1732 {
1733 Buffer *save = curbuf;
1734 Bufpos bp;
1735 char mesg[128];
1736
1737 /* insert status message now */
1738 swritef(mesg, sizeof(mesg), "[Process %s: %s]\n",
1739 proc_cmd(child), pstate(child));
1740 SetBuf(child->p_buffer);
1741 DOTsave(&bp);
1742 ToLast();
1743 ins_str(mesg);
1744 SetDot(&bp);
1745 SetBuf(save);
1746 redisplay();
1747 }
1748 }
1749
1750 #endif /* IPROCS */
1751