1: /*************************************************************************
2: * This program is copyright (C) 1985, 1986 by Jonathan Payne. It is *
3: * provided to you without charge for use only on a licensed Unix *
4: * system. You may copy JOVE provided that this notice is included with *
5: * the copy. You may not sell copies of this program or versions *
6: * modified for use on microcomputer systems, unless the copies are *
7: * included with a Unix system distribution and the source is provided. *
8: *************************************************************************/
9:
10: #ifdef BSD4_2
11: # include <sys/wait.h>
12: #else
13: # include <wait.h>
14: #endif
15: #include <signal.h>
16: #include <sgtty.h>
17:
18: typedef struct process Process;
19:
20: #define DEAD 1 /* Dead but haven't informed user yet */
21: #define STOPPED 2 /* Job stopped */
22: #define RUNNING 3 /* Just running */
23: #define NEW 4 /* This process is brand new */
24:
25: /* If process is dead, flags says how. */
26: #define EXITED 1
27: #define KILLED 2
28:
29: #define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_toproc == -1)
30:
31: #define proc_buf(p) (p->p_buffer->b_name)
32: #define proc_cmd(p) (p->p_name)
33: #define proc_state(p) (p->p_state)
34:
35: struct process {
36: Process *p_next;
37: int p_toproc, /* read p_fromproc and write p_toproc */
38: p_portpid, /* Pid of child (the portsrv) */
39: p_pid; /* Pid of real child i.e. not portsrv */
40: Buffer *p_buffer; /* Add output to end of this buffer */
41: char *p_name; /* ... */
42: char p_state, /* State */
43: p_howdied, /* Killed? or Exited? */
44: p_reason, /* If signaled, p_reason is the signal; else
45: it is the the exit code */
46: p_eof; /* Received EOF, so can be free'd up */
47: Mark *p_mark; /* Where output left us. */
48: data_obj
49: *p_cmd; /* Command to call when process dies */
50: } *procs = 0,
51: *cur_proc = 0;
52:
53: char proc_prompt[80] = "% ";
54:
55: int ProcInput,
56: ProcOutput,
57: NumProcs = 0;
58:
59: static char *
60: pstate(p)
61: Process *p;
62: {
63: switch (proc_state(p)) {
64: case NEW:
65: return "Pre-birth";
66:
67: case STOPPED:
68: return "Stopped";
69:
70: case RUNNING:
71: return "Running";
72:
73: case DEAD:
74: if (p->p_howdied == EXITED) {
75: if (p->p_reason == 0)
76: return "Done";
77: return sprint("[Exit %d]", p->p_reason);
78: }
79: return sprint("[Killed %d]", p->p_reason);
80:
81: default:
82: return "Unknown state.";
83: }
84: }
85:
86: static Process *
87: proc_pid(pid)
88: {
89: register Process *p;
90:
91: for (p = procs; p != 0; p = p->p_next)
92: if (p->p_portpid == pid)
93: break;
94:
95: return p;
96: }
97:
98: procs_read()
99: {
100: struct {
101: int pid;
102: int nbytes;
103: } header;
104: int n;
105: long nbytes;
106: static int here = 0;
107:
108: if (here)
109: return;
110: sighold(SIGCHLD); /* Block any other children. */
111: here++;
112: for (;;) {
113: (void) ioctl(ProcInput, FIONREAD, (struct sgttyb *) &nbytes);
114: if (nbytes < sizeof header)
115: break;
116: n = read(ProcInput, (char *) &header, sizeof header);
117: if (n != sizeof header)
118: finish(1);
119: read_proc(header.pid, header.nbytes);
120: }
121: redisplay();
122: here = 0;
123: sigrelse(SIGCHLD);
124: }
125:
126: read_proc(pid, nbytes)
127: int pid;
128: register int nbytes;
129: {
130: register Process *p;
131: int n;
132: char ibuf[512];
133:
134: if ((p = proc_pid(pid)) == 0) {
135: printf("\riproc: unknown pid (%d)", pid);
136: return;
137: }
138: if (proc_state(p) == NEW) {
139: int rpid;
140: /* Pid of real child, not of portsrv. */
141:
142: doread(ProcInput, (char *) &rpid, nbytes);
143: nbytes -= sizeof rpid;
144: p->p_pid = rpid;
145: p->p_state = RUNNING;
146: }
147:
148: if (nbytes == EOF) { /* Okay to clean up this process */
149: p->p_eof = 1;
150: NumProcs--; /* As far as getch() in main is concerned */
151: return;
152: }
153:
154: while (nbytes > 0) {
155: n = min((sizeof ibuf) - 1, nbytes);
156: doread(ProcInput, ibuf, n);
157: ibuf[n] = 0; /* Null terminate for convenience */
158: nbytes -= n;
159: proc_rec(p, ibuf);
160: }
161: }
162:
163: ProcKill()
164: {
165: proc_kill(cur_proc, SIGKILL);
166: }
167:
168: ProcInt()
169: {
170: proc_kill(cur_proc, SIGINT);
171: }
172:
173: ProcQuit()
174: {
175: proc_kill(cur_proc, SIGQUIT);
176: }
177:
178: static
179: proc_close(p)
180: Process *p;
181: {
182: (void) close(p->p_toproc);
183: p->p_toproc = -1; /* Writes will fail. */
184: }
185:
186: do_rtp(mp)
187: register Mark *mp;
188: {
189: register Process *p = cur_proc;
190: Line *line1 = curline,
191: *line2 = mp->m_line;
192: int char1 = curchar,
193: char2 = mp->m_char;
194: char *gp;
195:
196: if (isdead(p) || p->p_buffer != curbuf)
197: return;
198:
199: (void) fixorder(&line1, &char1, &line2, &char2);
200: while (line1 != line2->l_next) {
201: gp = ltobuf(line1, genbuf) + char1;
202: if (line1 == line2)
203: gp[char2] = '\0';
204: else
205: strcat(gp, "\n");
206: (void) write(p->p_toproc, gp, strlen(gp));
207: line1 = line1->l_next;
208: char1 = 0;
209: }
210: }
211:
212: /* VARARGS2 */
213:
214: static
215: proc_strt(bufname, procname, cmd)
216: char *bufname,
217: *procname,
218: *cmd;
219: {
220: Window *owind = curwind;
221: int toproc[2],
222: pid;
223: Process *newp;
224: Buffer *bp;
225: char *args[25],
226: **cp,
227: foo[10],
228: cmdbuf[128];
229: int i;
230:
231: bp = buf_exists(bufname);
232: if (bp != 0 && IsModified(bp) && bp->b_type != B_IPROCESS && bp->b_type != B_PROCESS)
233: complain("Command would over-write buffer %s.", procname, bufname);
234: pop_wind(bufname, 1, B_IPROCESS);
235:
236: dopipe(toproc);
237:
238: switch (pid = fork()) {
239: case -1:
240: pclose(toproc);
241: complain("[Fork failed.]");
242:
243: case 0:
244: args[0] = "portsrv";
245: args[1] = foo;
246: sprintf(foo, "%d", ProcInput);
247: for (i = 0, cp = &cmd; cp[i] != 0; i++)
248: args[2 + i] = cp[i];
249: args[2 + i] = 0;
250: (void) dup2(toproc[0], 0);
251: (void) dup2(ProcOutput, 1);
252: (void) dup2(ProcOutput, 2);
253: pclose(toproc);
254: execv(PORTSRV, args);
255: printf("Execl failed.\n");
256: _exit(1);
257: }
258:
259: sighold(SIGCHLD);
260: cur_proc = newp = (Process *) malloc(sizeof *newp);
261: newp->p_next = procs;
262: newp->p_state = NEW;
263: newp->p_mark = MakeMark(curline, curchar, FLOATER);
264: newp->p_cmd = 0;
265:
266: cp = &cmd + 1;
267: cmdbuf[0] = '\0';
268: while (*cp != 0)
269: sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", *cp++);
270: newp->p_name = copystr(cmdbuf);
271: procs = newp;
272: newp->p_portpid = pid;
273: newp->p_pid = -1;
274: newp->p_buffer = curbuf;
275: newp->p_toproc = toproc[1];
276: newp->p_reason = 0;
277: newp->p_eof = 0;
278: NumProcs++;
279: (void) close(toproc[0]);
280: sigrelse(SIGCHLD);
281: SetWind(owind);
282: }
283:
284: pinit()
285: {
286: int p[2];
287:
288: (void) signal(SIGCHLD, proc_child);
289: (void) pipe(p);
290: ProcInput = p[0];
291: ProcOutput = p[1];
292: (void) signal(INPUT_SIG, procs_read);
293: sighold(INPUT_SIG); /* Released during terminal read */
294: }
295:
296: doread(fd, buf, n)
297: char *buf;
298: {
299: int nread;
300:
301: if ((nread = read(fd, buf, n)) != n)
302: complain("Cannot read %d (got %d) bytes.", n, nread);
303: }