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