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