xref: /csrg-svn/sys/kern/tty_pty.c (revision 17890)
1 /*	tty_pty.c	6.9	85/01/31	*/
2 
3 /*
4  * Pseudo-teletype Driver
5  * (Actually two drivers, requiring two entries in 'cdevsw')
6  */
7 #include "pty.h"
8 
9 #if NPTY > 0
10 #include "param.h"
11 #include "systm.h"
12 #include "ioctl.h"
13 #include "tty.h"
14 #include "dir.h"
15 #include "user.h"
16 #include "conf.h"
17 #include "file.h"
18 #include "proc.h"
19 #include "uio.h"
20 #include "kernel.h"
21 
22 #if NPTY == 1
23 #undef	NPTY
24 #define	NPTY	32		/* crude XXX */
25 #endif
26 
27 #define BUFSIZ 100		/* Chunk size iomoved to/from user */
28 
29 /*
30  * pts == /dev/tty[pP]?
31  * ptc == /dev/ptp[pP]?
32  */
33 struct	tty pt_tty[NPTY];
34 struct	pt_ioctl {
35 	int	pt_flags;
36 	int	pt_gensym;
37 	struct	proc *pt_selr, *pt_selw;
38 	int	pt_send;
39 } pt_ioctl[NPTY];
40 
41 #define	PF_RCOLL	0x01
42 #define	PF_WCOLL	0x02
43 #define	PF_NBIO		0x04
44 #define	PF_PKT		0x08		/* packet mode */
45 #define	PF_STOPPED	0x10		/* user told stopped */
46 #define	PF_REMOTE	0x20		/* remote and flow controlled input */
47 #define	PF_NOSTOP	0x40
48 
49 /*ARGSUSED*/
50 ptsopen(dev, flag)
51 	dev_t dev;
52 {
53 	register struct tty *tp;
54 
55 	if (minor(dev) >= NPTY)
56 		return (ENXIO);
57 	tp = &pt_tty[minor(dev)];
58 	if ((tp->t_state & TS_ISOPEN) == 0) {
59 		ttychars(tp);		/* Set up default chars */
60 		tp->t_ispeed = tp->t_ospeed = EXTB;
61 		tp->t_flags = 0;	/* No features (nor raw mode) */
62 	} else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
63 		return (EBUSY);
64 	if (tp->t_oproc)			/* Ctrlr still around. */
65 		tp->t_state |= TS_CARR_ON;
66 	while ((tp->t_state & TS_CARR_ON) == 0) {
67 		tp->t_state |= TS_WOPEN;
68 		sleep((caddr_t)&tp->t_rawq, TTIPRI);
69 	}
70 	return ((*linesw[tp->t_line].l_open)(dev, tp));
71 }
72 
73 ptsclose(dev)
74 	dev_t dev;
75 {
76 	register struct tty *tp;
77 
78 	tp = &pt_tty[minor(dev)];
79 	(*linesw[tp->t_line].l_close)(tp);
80 	ttyclose(tp);
81 	ptcwakeup(tp);
82 }
83 
84 ptsread(dev, uio)
85 	dev_t dev;
86 	struct uio *uio;
87 {
88 	register struct tty *tp = &pt_tty[minor(dev)];
89 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
90 	int error = 0;
91 
92 again:
93 	if (pti->pt_flags & PF_REMOTE) {
94 		while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
95 #define bit(a) (1<<(a-1))
96 			if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
97 			    (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
98 	/*
99 			    (u.u_procp->p_flag&SDETACH) ||
100 	*/
101 			    u.u_procp->p_flag&SVFORK)
102 				return (EIO);
103 			gsignal(u.u_procp->p_pgrp, SIGTTIN);
104 			sleep((caddr_t)&lbolt, TTIPRI);
105 		}
106 #undef	bit
107 		if (tp->t_rawq.c_cc == 0) {
108 			if (tp->t_state & TS_NBIO)
109 				return (EWOULDBLOCK);
110 			sleep((caddr_t)&tp->t_rawq, TTIPRI);
111 			goto again;
112 		}
113 		while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
114 			if (ureadc(getc(&tp->t_rawq), uio) < 0) {
115 				error = EFAULT;
116 				break;
117 			}
118 		if (tp->t_rawq.c_cc == 1)
119 			(void) getc(&tp->t_rawq);
120 		if (tp->t_rawq.c_cc)
121 			return (error);
122 	} else
123 		if (tp->t_oproc)
124 			error = (*linesw[tp->t_line].l_read)(tp, uio);
125 	wakeup((caddr_t)&tp->t_rawq.c_cf);
126 	if (pti->pt_selw) {
127 		selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
128 		pti->pt_selw = 0;
129 		pti->pt_flags &= ~PF_WCOLL;
130 	}
131 	return (error);
132 }
133 
134 /*
135  * Write to pseudo-tty.
136  * Wakeups of controlling tty will happen
137  * indirectly, when tty driver calls ptsstart.
138  */
139 ptswrite(dev, uio)
140 	dev_t dev;
141 	struct uio *uio;
142 {
143 	register struct tty *tp;
144 
145 	tp = &pt_tty[minor(dev)];
146 	if (tp->t_oproc == 0)
147 		return (EIO);
148 	return ((*linesw[tp->t_line].l_write)(tp, uio));
149 }
150 
151 /*
152  * Start output on pseudo-tty.
153  * Wake up process selecting or sleeping for input from controlling tty.
154  */
155 ptsstart(tp)
156 	struct tty *tp;
157 {
158 	register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
159 
160 	if (tp->t_state & TS_TTSTOP)
161 		return;
162 	if (pti->pt_flags & PF_STOPPED) {
163 		pti->pt_flags &= ~PF_STOPPED;
164 		pti->pt_send = TIOCPKT_START;
165 	}
166 	ptcwakeup(tp);
167 }
168 
169 ptcwakeup(tp)
170 	struct tty *tp;
171 {
172 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
173 
174 	if (pti->pt_selr) {
175 		selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
176 		pti->pt_selr = 0;
177 		pti->pt_flags &= ~PF_RCOLL;
178 	}
179 	wakeup((caddr_t)&tp->t_outq.c_cf);
180 }
181 
182 /*ARGSUSED*/
183 ptcopen(dev, flag)
184 	dev_t dev;
185 	int flag;
186 {
187 	register struct tty *tp;
188 	struct pt_ioctl *pti;
189 
190 	if (minor(dev) >= NPTY)
191 		return (ENXIO);
192 	tp = &pt_tty[minor(dev)];
193 	if (tp->t_oproc)
194 		return (EIO);
195 	tp->t_oproc = ptsstart;
196 	if (tp->t_state & TS_WOPEN)
197 		wakeup((caddr_t)&tp->t_rawq);
198 	tp->t_state |= TS_CARR_ON;
199 	pti = &pt_ioctl[minor(dev)];
200 	pti->pt_flags = 0;
201 	pti->pt_send = 0;
202 	return (0);
203 }
204 
205 ptcclose(dev)
206 	dev_t dev;
207 {
208 	register struct tty *tp;
209 
210 	tp = &pt_tty[minor(dev)];
211 	if (tp->t_state & TS_ISOPEN)
212 		gsignal(tp->t_pgrp, SIGHUP);
213 	tp->t_state &= ~TS_CARR_ON;	/* virtual carrier gone */
214 	ttyflush(tp, FREAD|FWRITE);
215 	tp->t_oproc = 0;		/* mark closed */
216 }
217 
218 ptcread(dev, uio)
219 	dev_t dev;
220 	struct uio *uio;
221 {
222 	register struct tty *tp = &pt_tty[minor(dev)];
223 	struct pt_ioctl *pti;
224 	char buf[BUFSIZ];
225 	int error = 0, cc;
226 
227 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
228 		return (EIO);
229 	pti = &pt_ioctl[minor(dev)];
230 	if (pti->pt_flags & PF_PKT) {
231 		if (pti->pt_send) {
232 			error = ureadc(pti->pt_send, uio);
233 			if (error)
234 				return (error);
235 			pti->pt_send = 0;
236 			return (0);
237 		}
238 		error = ureadc(0, uio);
239 	}
240 	while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
241 		if ((tp->t_state&TS_CARR_ON) == 0)
242 			return (EIO);
243 		if (pti->pt_flags&PF_NBIO)
244 			return (EWOULDBLOCK);
245 		sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
246 	}
247 	while (uio->uio_resid > 0 && error == 0) {
248 		cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
249 		if (cc <= 0)
250 			break;
251 		error = uiomove(buf, cc, UIO_READ, uio);
252 	}
253 	if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
254 		if (tp->t_state&TS_ASLEEP) {
255 			tp->t_state &= ~TS_ASLEEP;
256 			wakeup((caddr_t)&tp->t_outq);
257 		}
258 		if (tp->t_wsel) {
259 			selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
260 			tp->t_wsel = 0;
261 			tp->t_state &= ~TS_WCOLL;
262 		}
263 	}
264 	return (error);
265 }
266 
267 ptsstop(tp, flush)
268 	register struct tty *tp;
269 	int flush;
270 {
271 	struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
272 
273 	/* note: FLUSHREAD and FLUSHWRITE already ok */
274 	if (flush == 0) {
275 		flush = TIOCPKT_STOP;
276 		pti->pt_flags |= PF_STOPPED;
277 	} else {
278 		pti->pt_flags &= ~PF_STOPPED;
279 	}
280 	pti->pt_send |= flush;
281 	ptcwakeup(tp);
282 }
283 
284 ptcselect(dev, rw)
285 	dev_t dev;
286 	int rw;
287 {
288 	register struct tty *tp = &pt_tty[minor(dev)];
289 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
290 	struct proc *p;
291 	int s;
292 
293 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
294 		return (1);
295 	s = spl5();
296 	switch (rw) {
297 
298 	case FREAD:
299 		if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
300 			splx(s);
301 			return (1);
302 		}
303 		if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
304 			pti->pt_flags |= PF_RCOLL;
305 		else
306 			pti->pt_selr = u.u_procp;
307 		break;
308 
309 	case FWRITE:
310 		if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
311 			splx(s);
312 			return (1);
313 		}
314 		if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
315 			pti->pt_flags |= PF_WCOLL;
316 		else
317 			pti->pt_selw = u.u_procp;
318 		break;
319 	}
320 	splx(s);
321 	return (0);
322 }
323 
324 ptcwrite(dev, uio)
325 	dev_t dev;
326 	struct uio *uio;
327 {
328 	register struct tty *tp = &pt_tty[minor(dev)];
329 	register char *cp, *ce;
330 	register int cc;
331 	char locbuf[BUFSIZ];
332 	int cnt = 0;
333 	struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
334 	int error = 0;
335 
336 	if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
337 		return (EIO);
338 	do {
339 		register struct iovec *iov;
340 
341 		if (uio->uio_iovcnt == 0)
342 			break;
343 		iov = uio->uio_iov;
344 		if (iov->iov_len == 0) {
345 			while ((pti->pt_flags&PF_REMOTE) && tp->t_rawq.c_cc != 0)
346 				sleep((caddr_t)&tp->t_rawq.c_cf, TTIPRI);
347 			if (pti->pt_flags&PF_REMOTE) {
348 				(void) putc(0, &tp->t_rawq);
349 				wakeup((caddr_t)&tp->t_rawq);
350 			}
351 			uio->uio_iovcnt--;
352 			uio->uio_iov++;
353 			if (uio->uio_iovcnt < 0)
354 				panic("ptcwrite");
355 			continue;
356 		}
357 		cc = MIN(iov->iov_len, BUFSIZ);
358 		cp = locbuf;
359 		error = uiomove(cp, cc, UIO_WRITE, uio);
360 		if (error)
361 			break;
362 		ce = cp + cc;
363 again:
364 		if (pti->pt_flags & PF_REMOTE) {
365 			if (tp->t_rawq.c_cc) {
366 				if (pti->pt_flags & PF_NBIO) {
367 					iov->iov_base -= ce - cp;
368 					iov->iov_len += ce - cp;
369 					uio->uio_resid += ce - cp;
370 					uio->uio_offset -= ce - cp;
371 					return (EWOULDBLOCK);
372 				}
373 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
374 				goto again;
375 			}
376 			(void) b_to_q(cp, cc, &tp->t_rawq);
377 			(void) putc(0, &tp->t_rawq);
378 			wakeup((caddr_t)&tp->t_rawq);
379 			return (0);
380 		}
381 		while (cp < ce) {
382 			if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
383 			    (tp->t_canq.c_cc > 0)) {
384 				wakeup((caddr_t)&tp->t_rawq);
385 				if (tp->t_state & TS_NBIO) {
386 					iov->iov_base -= ce - cp;
387 					iov->iov_len += ce - cp;
388 					uio->uio_resid += ce - cp;
389 					uio->uio_offset -= ce - cp;
390 					if (cnt == 0)
391 						return (EWOULDBLOCK);
392 					return (0);
393 				}
394 				/* Better than just flushing it! */
395 				/* Wait for something to be read */
396 				sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
397 				goto again;
398 			}
399 			(*linesw[tp->t_line].l_rint)(*cp++, tp);
400 			cnt++;
401 		}
402 	} while (uio->uio_resid);
403 	return (error);
404 }
405 
406 /*ARGSUSED*/
407 ptyioctl(dev, cmd, data, flag)
408 	caddr_t data;
409 	dev_t dev;
410 {
411 	register struct tty *tp = &pt_tty[minor(dev)];
412 	register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
413 	int error;
414 
415 	/* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
416 	if (cdevsw[major(dev)].d_open == ptcopen)
417 		switch (cmd) {
418 
419 		case TIOCPKT:
420 			if (*(int *)data)
421 				pti->pt_flags |= PF_PKT;
422 			else
423 				pti->pt_flags &= ~PF_PKT;
424 			return (0);
425 
426 		case TIOCREMOTE:
427 			if (*(int *)data)
428 				pti->pt_flags |= PF_REMOTE;
429 			else
430 				pti->pt_flags &= ~PF_REMOTE;
431 			ttyflush(tp, FREAD|FWRITE);
432 			return (0);
433 
434 		case FIONBIO:
435 			if (*(int *)data)
436 				pti->pt_flags |= PF_NBIO;
437 			else
438 				pti->pt_flags &= ~PF_NBIO;
439 			return (0);
440 
441 		case TIOCSETP:
442 			while (getc(&tp->t_outq) >= 0)
443 				;
444 			break;
445 		}
446 	error = ttioctl(tp, cmd, data, flag);
447 	if (error < 0)
448 		error = ENOTTY;
449 	{ int stop = ((tp->t_flags & RAW) == 0 &&
450 		      tp->t_stopc == ('s'&037) &&
451 		      tp->t_startc == ('q'&037));
452 	if (pti->pt_flags & PF_NOSTOP) {
453 		if (stop) {
454 			pti->pt_send &= TIOCPKT_NOSTOP;
455 			pti->pt_send |= TIOCPKT_DOSTOP;
456 			pti->pt_flags &= ~PF_NOSTOP;
457 			ptcwakeup(tp);
458 		}
459 	} else {
460 		if (stop == 0) {
461 			pti->pt_send &= ~TIOCPKT_DOSTOP;
462 			pti->pt_send |= TIOCPKT_NOSTOP;
463 			pti->pt_flags |= PF_NOSTOP;
464 			ptcwakeup(tp);
465 		}
466 	}
467 	}
468 	return (error);
469 }
470 #endif
471