BSD 4_3_Tahoe development
[unix-history] / usr / src / new / jove / iproc-ptys.c
CommitLineData
6ca833f5
C
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#include <errno.h>
16
17#define DEAD 1 /* dead but haven't informed user yet */
18#define STOPPED 2 /* job stopped */
19#define RUNNING 3 /* just running */
20#define NEW 4 /* brand new, never been ... received no input */
21
22/* If process is dead, flags says how. */
23#define EXITED 1
24#define KILLED 2
25
26#define isdead(p) (p == 0 || proc_state(p) == DEAD || p->p_fd == -1)
27#define makedead(p) (proc_state(p) = DEAD)
28
29#define proc_buf(p) (p->p_buffer->b_name)
30#define proc_cmd(p) (p->p_name)
31#define proc_state(p) (p->p_state)
32
33private Process *procs = 0;
34
35long global_fd = 1;
36int NumProcs = 0;
37
38#ifdef BRLUNIX
39 extern struct sg_brl sg1;
40#else
41 extern struct sgttyb sg1;
42#endif
43
44extern struct tchars tc1;
45
46#ifdef TIOCSLTC
47 extern struct ltchars ls1;
48#endif
49
50char *
51pstate(p)
52Process *p;
53{
54 switch (proc_state(p)) {
55 case STOPPED:
56 return "Stopped";
57
58 case RUNNING:
59 return "Running";
60
61 case DEAD:
62 if (p->p_howdied == EXITED) {
63 if (p->p_reason == 0)
64 return "Done";
65 return sprint("Exit %d", p->p_reason);
66 }
67 return sprint("Killed %d", p->p_reason);
68
69 case NEW:
70 return "New";
71
72 default:
73 return "Unknown state";
74 }
75}
76
77static Process *
78proc_pid(pid)
79{
80 register Process *p;
81
82 for (p = procs; p != 0; p = p->p_next)
83 if (p->p_pid == pid)
84 break;
85
86 return p;
87}
88
89read_proc(fd)
90register int fd;
91{
92 register Process *p;
93 unsigned int n;
94 char ibuf[1024];
95
96 for (p = procs; p != 0; p = p->p_next)
97 if (p->p_fd == fd)
98 break;
99
100 if (p == 0) {
101 printf("\riproc: unknown fd %d", fd);
102 return;
103 }
104
105 n = read(fd, ibuf, sizeof(ibuf) - 1);
106 if (n == -1 && errno == EIO) {
107 if (proc_state(p) == NEW)
108 return;
109 proc_close(p);
110 makedead(p);
111 return;
112 } else {
113 if (proc_state(p) != RUNNING) {
114 proc_state(p) = RUNNING;
115 UpdModLine = YES;
116 }
117 }
118 if (n <= 0) {
119 if (n == 0)
120 strcpy(ibuf, "[Process EOF]");
121 else
122 sprintf(ibuf, "\n[pty read error: %d]\n", errno);
123 } else
124 ibuf[n] = '\0';
125 proc_rec(p, ibuf);
126}
127
128ProcKill()
129{
130 register Buffer *b;
131 Process *buf_to_proc();
132 char *bname;
133
134 bname = ask_buf(curbuf);
135
136 if ((b = buf_exists(bname)) == 0)
137 complain("[No such buffer]");
138 if (b->b_process == 0)
139 complain("%s not tied to a process.", bname);
140 proc_kill(b->b_process, SIGKILL);
141}
142
143ProcCont()
144{
145 Process *p;
146
147 if ((p = curbuf->b_process) == 0)
148 complain("[No process]");
149 if (p->p_state != DEAD) {
150 proc_kill(p, SIGCONT);
151 p->p_state = RUNNING;
152 }
153}
154
155ProcEof()
156{
157 send_p(tc1.t_eofc);
158}
159
160ProcInt()
161{
162 send_p(tc1.t_intrc);
163}
164
165ProcQuit()
166{
167 send_p(tc1.t_quitc);
168}
169
170ProcStop()
171{
172 send_p(ls1.t_suspc);
173}
174
175ProcDStop()
176{
177 send_p(ls1.t_dsuspc);
178}
179
180send_p(c)
181char c;
182{
183 Process *p;
184 char buf[2];
185
186 if ((p = curbuf->b_process) == 0)
187 complain("[No process]");
188 ToLast();
189 buf[0] = c;
190 buf[1] = '\0';
191 proc_rec(p, buf);
192 (void) write(p->p_fd, &c, 1);
193}
194
195private
196proc_close(p)
197Process *p;
198{
199 sighold(SIGCHLD); /* be mutually exclusive */
200
201 if (p->p_fd >= 0) {
202 (void) close(p->p_fd);
203 global_fd &= ~(1L << p->p_fd);
204 NumProcs -= 1;
205 p->p_fd = -1;
206 }
207
208 sigrelse(SIGCHLD);
209}
210
211do_rtp(mp)
212register Mark *mp;
213{
214 register Process *p = curbuf->b_process;
215 Line *line1 = curline,
216 *line2 = mp->m_line;
217 int char1 = curchar,
218 char2 = mp->m_char;
219 char *gp;
220 int nbytes;
221
222 if (isdead(p) || p->p_buffer != curbuf)
223 return;
224
225 (void) fixorder(&line1, &char1, &line2, &char2);
226 while (line1 != line2->l_next) {
227 gp = ltobuf(line1, genbuf) + char1;
228 if (line1 == line2)
229 gp[char2] = '\0';
230 else
231 strcat(gp, "\n");
232 if (nbytes = strlen(gp))
233 (void) write(p->p_fd, gp, nbytes);
234 line1 = line1->l_next;
235 char1 = 0;
236 }
237}
238
239/* VARARGS2 */
240
241private
242proc_strt(bufname, clobber, va_alist)
243char *bufname;
244va_dcl
245{
246 va_list ap;
247 char *argv[32],
248 *cp;
249 Window *owind = curwind;
250 int pid;
251 Process *newp;
252 Buffer *newbuf;
253 int i,
254 ptyfd,
255 ttyfd,
256 ldisc,
257 lmode;
258 register char *s,
259 *t;
260 extern int errno;
261 static char ttybuf[11],
262 ptybuf[11];
263 char cmdbuf[128];
264#ifdef BRLUNIX
265 struct sg_brl sg;
266#else
267 struct sgttyb sg;
268#endif
269
270#ifdef TIOCGWINSZ
271 struct winsize win;
272#else
273# ifdef BTL_BLIT
274# include <sys/jioctl.h>
275 struct jwinsize jwin;
276# endif
277#endif
278
279 isprocbuf(bufname); /* make sure BUFNAME is either nonexistant
280 or is of type B_PROCESS */
281 for (s = "pqrs"; *s; s++) {
282 for (t = "0123456789abcdef"; *t; t++) {
283 sprintf(ptybuf, "/dev/pty%c%c", *s, *t);
284 if ((ptyfd = open(ptybuf, 2)) >= 0) {
285 strcpy(ttybuf, ptybuf);
286 ttybuf[5] = 't';
287 /* make sure both ends are available */
288 if ((i = open(ttybuf, 2)) < 0)
289 continue;
290 (void) close(i);
291 goto out;
292 }
293 }
294 }
295
296out: if (s == 0 && t == 0)
297 complain("[Out of ptys!]");
298
299#ifdef TIOCGETD
300 (void) ioctl(0, TIOCGETD, (struct sgttyb *) &ldisc);
301#endif
302#ifdef TIOCLGET
303 (void) ioctl(0, TIOCLGET, (struct sgttyb *) &lmode);
304#endif
305#ifdef TIOCGWINSZ
306 (void) ioctl(0, TIOCGWINSZ, (struct sgttyb *) &win);
307#else
308# ifdef BTL_BLIT
309 (void) ioctl(0, JWINSIZE, (struct sgttyb *) &jwin);
310# endif /* BTL_BLIT */
311#endif
312
313 sighold(SIGCHLD);
314#ifdef SIGWINCH
315 sighold(SIGWINCH);
316#endif
317 switch (pid = fork()) {
318 case -1:
319 (void) close(ptyfd);
320 message("[Fork failed!]");
321 goto fail;
322
323 case 0:
324 sigrelse(SIGCHLD);
325#ifdef SIGWINCH
326 sigrelse(SIGWINCH);
327#endif
328 for (i = 0; i < 32; i++)
329 (void) close(i);
330
331#ifdef TIOCNOTTY
332 if ((i = open("/dev/tty", 2)) >= 0) {
333 (void) ioctl(i, TIOCNOTTY, (struct sgttyb *) 0);
334 (void) close(i);
335 }
336#endif
337 if ((ttyfd = open(ttybuf, 2)) < 0)
338 exit(-1);
339 (void) dup2(ttyfd, 1);
340 (void) dup2(ttyfd, 2);
341
342#ifdef TIOCSETD
343 (void) ioctl(0, TIOCSETD, (struct sgttyb *) &ldisc);
344#endif
345#ifdef TIOCLSET
346 (void) ioctl(0, TIOCLSET, (struct sgttyb *) &lmode);
347#endif
348#ifdef TIOCSETC
349 (void) ioctl(0, TIOCSETC, (struct sgttyb *) &tc1);
350#endif
351#ifdef TIOCSLTC
352 (void) ioctl(0, TIOCSLTC, (struct sgttyb *) &ls1);
353#endif
354
355#ifdef TIOCGWINSZ
356# ifdef SIGWINCH
357 (void) signal(SIGWINCH, SIG_IGN);
358# endif
359 win.ws_row = curwind->w_height;
360 (void) ioctl(0, TIOCSWINSZ, (struct sgttyb *) &win);
361#else
362# ifdef BTL_BLIT
363 jwin.bytesy = curwind->w_height;
364 (void) ioctl(0, JSWINSIZE, (struct sgttyb *) &jwin);
365# endif
366#endif
367
368 sg = sg1;
369 sg.sg_flags &= ~(ECHO | CRMOD);
370 (void) stty(0, &sg);
371
372 i = getpid();
373 (void) ioctl(0, TIOCSPGRP, (struct sgttyb *) &i);
374 (void) setpgrp(0, i);
375 va_start(ap);
376 make_argv(argv, ap);
377 va_end(ap);
378 execv(argv[0], &argv[1]);
379 (void) write(1, "execve failed!\n", 15);
380 _exit(errno + 1);
381 }
382
383 newp = (Process *) emalloc(sizeof *newp);
384
385 newp->p_fd = ptyfd;
386 newp->p_pid = pid;
387
388 newbuf = do_select((Window *) 0, bufname);
389 newbuf->b_type = B_PROCESS;
390 newp->p_buffer = newbuf;
391 newbuf->b_process = newp; /* sorta circular, eh? */
392 pop_wind(bufname, clobber, B_PROCESS);
393 /* Pop_wind() after everything is set up; important!
394 Bindings won't work right unless newbuf->b_process is already
395 set up BEFORE NEWBUF is first SetBuf()'d. */
396 ToLast();
397 if (!bolp())
398 LineInsert(1);
399
400 cmdbuf[0] = '\0';
401 va_start(ap);
402 while (cp = va_arg(ap, char *))
403 sprintf(&cmdbuf[strlen(cmdbuf)], "%s ", cp++);
404 va_end(ap);
405
406 newp->p_name = copystr(cmdbuf);
407 newp->p_state = NEW;
408 newp->p_reason = 0;
409 newp->p_mark = MakeMark(curline, curchar, M_FLOATER);
410
411 newp->p_next = procs;
412 procs = newp;
413 NumProcs += 1;
414 global_fd |= 1L << newp->p_fd;
415 SetWind(owind);
416
417fail: sigrelse(SIGCHLD);
418#ifdef SIGWINCH
419 sigrelse(SIGWINCH);
420#endif
421}
422
423pinit()
424{
425 (void) signal(SIGCHLD, proc_child);
426}
427