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