1: /***************************************************************************
2: * This program is Copyright (C) 1986, 1987, 1988 by Jonathan Payne. JOVE *
3: * is 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: #ifdef BSD4_2
9: # include <sys/wait.h>
10: #else
11: # include <wait.h>
12: #endif
13: #include <signal.h>
14: #include <sgtty.h>
15:
16: #define DEAD 1 /* Dead but haven't informed user yet */
17: #define STOPPED 2 /* Job stopped */
18: #define RUNNING 3 /* Just running */
19: #define NEW 4 /* This process is brand new */
20:
21: /* If process is dead, flags says how. */
22: #define EXITED 1
23: #define KILLED 2
24:
25: #define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_toproc == -1)
26: #define makedead(p) (proc_state(p) = DEAD)
27:
28: #define proc_buf(p) (p->p_buffer->b_name)
29: #define proc_cmd(p) (p->p_name)
30: #define proc_state(p) (p->p_state)
31:
32: private Process *procs = 0;
33:
34: int ProcInput,
35: ProcOutput,
36: NumProcs = 0;
37:
38: char *
39: pstate(p)
40: Process *p;
41: {
42: switch (proc_state(p)) {
43: case NEW:
44: return "Pre-birth";
45:
46: case STOPPED:
47: return "Stopped";
48:
49: case RUNNING:
50: return "Running";
51:
52: case DEAD:
53: if (p->p_howdied == EXITED) {
54: if (p->p_reason == 0)
55: return "Done";
56: return sprint("Exit %d", p->p_reason);
57: }
58: return sprint("Killed %d", p->p_reason);
59:
60: default:
61: return "Unknown state";
62: }
63: }
64:
65: static Process *
66: proc_pid(pid)
67: {
68: register Process *p;
69:
70: for (p = procs; p != 0; p = p->p_next)
71: if (p->p_portpid == pid)
72: break;
73:
74: return p;
75: }
76:
77: procs_read()
78: {
79: struct {
80: int pid;
81: int nbytes;
82: } header;
83: int n;
84: long nbytes;
85: static int here = NO;
86:
87: if (here)
88: return;
89: sighold(SIGCHLD); /* block any other children */
90: here = YES;
91: for (;;) {
92: (void) ioctl(ProcInput, FIONREAD, (struct sgttyb *) &nbytes);
93: if (nbytes < sizeof header)
94: break;
95: n = read(ProcInput, (char *) &header, sizeof header);
96: if (n != sizeof header)
97: finish(1);
98: read_proc(header.pid, header.nbytes);
99: }
100: here = NO;
101: sigrelse(SIGCHLD);
102: }
103:
104: read_proc(pid, nbytes)
105: int pid;
106: register int nbytes;
107: {
108: register Process *p;
109: int n;
110: char ibuf[512];
111:
112: if ((p = proc_pid(pid)) == 0) {
113: printf("\riproc: unknown pid (%d)", pid);
114: return;
115: }
116: if (proc_state(p) == NEW) {
117: int rpid;
118: /* pid of real child, not of portsrv */
119:
120: doread(ProcInput, (char *) &rpid, nbytes);
121: nbytes -= sizeof rpid;
122: p->p_pid = rpid;
123: p->p_state = RUNNING;
124: }
125:
126: if (nbytes == EOF) { /* okay to clean up this process */
127: proc_close(p);
128: makedead(p);
129: return;
130: }
131:
132: while (nbytes > 0) {
133: n = min((sizeof ibuf) - 1, nbytes);
134: doread(ProcInput, ibuf, n);
135: ibuf[n] = 0; /* Null terminate for convenience */
136: nbytes -= n;
137: proc_rec(p, ibuf);
138: }
139: }
140:
141: ProcKill()
142: {
143: proc_kill(curbuf->b_process, SIGKILL);
144: }
145:
146: ProcInt()
147: {
148: proc_kill(curbuf->b_process, SIGINT);
149: }
150:
151: ProcQuit()
152: {
153: proc_kill(curbuf->b_process, SIGQUIT);
154: }
155:
156: private
157: proc_close(p)
158: Process *p;
159: {
160: sighold(SIGCHLD);
161:
162: if (p->p_toproc >= 0) {
163: (void) close(p->p_toproc);
164: p->p_toproc = -1; /* writes will fail */
165: NumProcs -= 1;
166: }
167:
168: sigrelse(SIGCHLD);
169: }
170:
171: do_rtp(mp)
172: register Mark *mp;
173: {
174: register Process *p = curbuf->b_process;
175: Line *line1 = curline,
176: *line2 = mp->m_line;
177: int char1 = curchar,
178: char2 = mp->m_char;
179: char *gp;
180:
181: if (isdead(p) || p->p_buffer != curbuf)
182: return;
183:
184: (void) fixorder(&line1, &char1, &line2, &char2);
185: while (line1 != line2->l_next) {
186: gp = ltobuf(line1, genbuf) + char1;
187: if (line1 == line2)
188: gp[char2] = '\0';
189: else
190: strcat(gp, "\n");
191: (void) write(p->p_toproc, gp, strlen(gp));
192: line1 = line1->l_next;
193: char1 = 0;
194: }
195: }
196:
197: /* VARARGS3 */
198:
199: private
200: proc_strt(bufname, clobber, va_alist)
201: char *bufname;
202: va_dcl
203: {
204: Window *owind = curwind;
205: int toproc[2],
206: pid;
207: Process *newp;
208: Buffer *newbuf;
209: char *argv[32],
210: *cp,
211: foo[10],
212: cmdbuf[128];
213: int i;
214: va_list ap;
215:
216: isprocbuf(bufname); /* make sure BUFNAME is either nonexistant
217: or is of type B_PROCESS */
218: dopipe(toproc);
219:
220: sighold(SIGCHLD);
221: #ifdef SIGWINCH
222: sighold(SIGWINCH);
223: #endif
224: switch (pid = fork()) {
225: case -1:
226: pclose(toproc);
227: complain("[Fork failed.]");
228:
229: case 0:
230: sigrelse(SIGCHLD);
231: #ifdef SIGWINCH
232: sigrelse(SIGWINCH);
233: #endif
234: argv[0] = "portsrv";
235: argv[1] = foo;
236: sprintf(foo, "%d", ProcInput);
237: va_start(ap);
238: make_argv(&argv[2], ap);
239: va_end(ap);
240: (void) dup2(toproc[0], 0);
241: (void) dup2(ProcOutput, 1);
242: (void) dup2(ProcOutput, 2);
243: pclose(toproc);
244: execv(Portsrv, argv);
245: printf("execl failed\n");
246: _exit(1);
247: }
248:
249: newp = (Process *) malloc(sizeof *newp);
250: newp->p_next = procs;
251: newp->p_state = NEW;
252: newp->p_cmd = 0;
253:
254: cmdbuf[0] = '\0';
255: va_start(ap);
256: while (cp = va_arg(ap, char *))
257: sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp);
258: va_end(ap);
259: newp->p_name = copystr(cmdbuf);
260: procs = newp;
261: newp->p_portpid = pid;
262: newp->p_pid = -1;
263:
264: newbuf = do_select((Window *) 0, bufname);
265: newbuf->b_type = B_PROCESS;
266: newp->p_buffer = newbuf;
267: newbuf->b_process = newp; /* sorta circular, eh? */
268: pop_wind(bufname, clobber, B_PROCESS);
269: ToLast();
270: if (!bolp())
271: LineInsert(1);
272: /* Pop_wind() after everything is set up; important!
273: Bindings won't work right unless newbuf->b_process is already
274: set up BEFORE NEWBUF is first SetBuf()'d. */
275: newp->p_mark = MakeMark(curline, curchar, M_FLOATER);
276:
277: newp->p_toproc = toproc[1];
278: newp->p_reason = 0;
279: NumProcs += 1;
280: (void) close(toproc[0]);
281: SetWind(owind);
282: sigrelse(SIGCHLD);
283: #ifdef SIGWINCH
284: sigrelse(SIGWINCH);
285: #endif
286: }
287:
288: pinit()
289: {
290: int p[2];
291:
292: (void) signal(SIGCHLD, proc_child);
293: (void) pipe(p);
294: ProcInput = p[0];
295: ProcOutput = p[1];
296: (void) signal(INPUT_SIG, procs_read);
297: sighold(INPUT_SIG); /* Released during terminal read */
298: }
299:
300: doread(fd, buf, n)
301: char *buf;
302: {
303: int nread;
304:
305: if ((nread = read(fd, buf, n)) != n)
306: complain("Cannot read %d (got %d) bytes.", n, nread);
307: }