reverse sense of pid/pgrp for fcntl, SIOCSPGRP (pgrp is negative)
[unix-history] / usr / src / sys / kern / tty_pty.c
CommitLineData
d19cae27 1/* tty_pty.c 6.11 85/06/07 */
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
5bb90914 23#undef NPTY
c91c01fe 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/*
5bb90914
JB
30 * pts == /dev/tty[pqrs]?
31 * ptc == /dev/pty[pqrs]?
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;
5bb90914
JB
38 u_char pt_send;
39 u_char pt_ucntl;
e1d74936 40} pt_ioctl[NPTY];
5bb90914 41int npty = NPTY; /* for pstat -t */
45372428 42
1a954a11
BJ
43#define PF_RCOLL 0x01
44#define PF_WCOLL 0x02
45#define PF_NBIO 0x04
46#define PF_PKT 0x08 /* packet mode */
1e6d24b1 47#define PF_STOPPED 0x10 /* user told stopped */
defdbcd1 48#define PF_REMOTE 0x20 /* remote and flow controlled input */
0a2bd708 49#define PF_NOSTOP 0x40
5bb90914 50#define PF_UCNTL 0x80 /* user control mode */
45372428
MT
51
52/*ARGSUSED*/
53ptsopen(dev, flag)
73c77d38 54 dev_t dev;
e1d74936 55{
45372428 56 register struct tty *tp;
5bb90914 57 int error;
45372428 58
5bb90914
JB
59#ifdef lint
60 npty = npty;
61#endif
f21c8fb8
BJ
62 if (minor(dev) >= NPTY)
63 return (ENXIO);
45372428 64 tp = &pt_tty[minor(dev)];
941944c9 65 if ((tp->t_state & TS_ISOPEN) == 0) {
bdda6b91 66 ttychars(tp); /* Set up default chars */
d2f24af0 67 tp->t_ispeed = tp->t_ospeed = EXTB;
bdda6b91 68 tp->t_flags = 0; /* No features (nor raw mode) */
f21c8fb8
BJ
69 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
70 return (EBUSY);
e1d74936 71 if (tp->t_oproc) /* Ctrlr still around. */
941944c9
BJ
72 tp->t_state |= TS_CARR_ON;
73 while ((tp->t_state & TS_CARR_ON) == 0) {
74 tp->t_state |= TS_WOPEN;
45372428
MT
75 sleep((caddr_t)&tp->t_rawq, TTIPRI);
76 }
5bb90914
JB
77 error = (*linesw[tp->t_line].l_open)(dev, tp);
78 ptcwakeup(tp, FREAD|FWRITE);
79 return (error);
45372428
MT
80}
81
82ptsclose(dev)
73c77d38 83 dev_t dev;
941944c9 84{
45372428
MT
85 register struct tty *tp;
86
87 tp = &pt_tty[minor(dev)];
88 (*linesw[tp->t_line].l_close)(tp);
4b39cb77 89 ttyclose(tp);
5bb90914 90 ptcwakeup(tp, FREAD|FWRITE);
45372428
MT
91}
92
ae9a0a69 93ptsread(dev, uio)
73c77d38 94 dev_t dev;
ae9a0a69 95 struct uio *uio;
e1d74936 96{
defdbcd1
BJ
97 register struct tty *tp = &pt_tty[minor(dev)];
98 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 99 int error = 0;
defdbcd1
BJ
100
101again:
102 if (pti->pt_flags & PF_REMOTE) {
103 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
5bb90914
JB
104 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
105 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
defdbcd1
BJ
106 /*
107 (u.u_procp->p_flag&SDETACH) ||
108 */
109 u.u_procp->p_flag&SVFORK)
840510a3 110 return (EIO);
defdbcd1
BJ
111 gsignal(u.u_procp->p_pgrp, SIGTTIN);
112 sleep((caddr_t)&lbolt, TTIPRI);
941944c9 113 }
5bb90914 114 if (tp->t_canq.c_cc == 0) {
840510a3
BJ
115 if (tp->t_state & TS_NBIO)
116 return (EWOULDBLOCK);
5bb90914 117 sleep((caddr_t)&tp->t_canq, TTIPRI);
defdbcd1
BJ
118 goto again;
119 }
5bb90914
JB
120 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
121 if (ureadc(getc(&tp->t_canq), uio) < 0) {
840510a3 122 error = EFAULT;
ae9a0a69
BJ
123 break;
124 }
5bb90914
JB
125 if (tp->t_canq.c_cc == 1)
126 (void) getc(&tp->t_canq);
127 if (tp->t_canq.c_cc)
840510a3 128 return (error);
defdbcd1
BJ
129 } else
130 if (tp->t_oproc)
840510a3 131 error = (*linesw[tp->t_line].l_read)(tp, uio);
5bb90914 132 ptcwakeup(tp, FWRITE);
840510a3 133 return (error);
45372428
MT
134}
135
941944c9
BJ
136/*
137 * Write to pseudo-tty.
138 * Wakeups of controlling tty will happen
139 * indirectly, when tty driver calls ptsstart.
140 */
ae9a0a69 141ptswrite(dev, uio)
73c77d38 142 dev_t dev;
ae9a0a69 143 struct uio *uio;
e1d74936 144{
45372428
MT
145 register struct tty *tp;
146
147 tp = &pt_tty[minor(dev)];
840510a3
BJ
148 if (tp->t_oproc == 0)
149 return (EIO);
150 return ((*linesw[tp->t_line].l_write)(tp, uio));
45372428
MT
151}
152
941944c9
BJ
153/*
154 * Start output on pseudo-tty.
155 * Wake up process selecting or sleeping for input from controlling tty.
156 */
45372428 157ptsstart(tp)
e1d74936
BJ
158 struct tty *tp;
159{
1e6d24b1 160 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
e1d74936 161
941944c9 162 if (tp->t_state & TS_TTSTOP)
45372428 163 return;
1e6d24b1
BJ
164 if (pti->pt_flags & PF_STOPPED) {
165 pti->pt_flags &= ~PF_STOPPED;
166 pti->pt_send = TIOCPKT_START;
167 }
5bb90914 168 ptcwakeup(tp, FREAD);
d427b3b2
BJ
169}
170
5bb90914 171ptcwakeup(tp, flag)
d427b3b2
BJ
172 struct tty *tp;
173{
174 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
175
5bb90914
JB
176 if (flag & FREAD) {
177 if (pti->pt_selr) {
178 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
179 pti->pt_selr = 0;
180 pti->pt_flags &= ~PF_RCOLL;
181 }
182 wakeup((caddr_t)&tp->t_outq.c_cf);
183 }
184 if (flag & FWRITE) {
185 if (pti->pt_selw) {
186 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
187 pti->pt_selw = 0;
188 pti->pt_flags &= ~PF_WCOLL;
189 }
190 wakeup((caddr_t)&tp->t_rawq.c_cf);
e1d74936 191 }
45372428
MT
192}
193
194/*ARGSUSED*/
195ptcopen(dev, flag)
e1d74936
BJ
196 dev_t dev;
197 int flag;
198{
45372428 199 register struct tty *tp;
1a954a11 200 struct pt_ioctl *pti;
45372428 201
f21c8fb8
BJ
202 if (minor(dev) >= NPTY)
203 return (ENXIO);
45372428 204 tp = &pt_tty[minor(dev)];
f21c8fb8
BJ
205 if (tp->t_oproc)
206 return (EIO);
e1d74936 207 tp->t_oproc = ptsstart;
941944c9 208 if (tp->t_state & TS_WOPEN)
45372428 209 wakeup((caddr_t)&tp->t_rawq);
941944c9 210 tp->t_state |= TS_CARR_ON;
1a954a11
BJ
211 pti = &pt_ioctl[minor(dev)];
212 pti->pt_flags = 0;
213 pti->pt_send = 0;
5bb90914 214 pti->pt_ucntl = 0;
f21c8fb8 215 return (0);
45372428
MT
216}
217
218ptcclose(dev)
e1d74936
BJ
219 dev_t dev;
220{
45372428
MT
221 register struct tty *tp;
222
223 tp = &pt_tty[minor(dev)];
941944c9 224 if (tp->t_state & TS_ISOPEN)
45372428 225 gsignal(tp->t_pgrp, SIGHUP);
941944c9 226 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */
88a7a62a 227 ttyflush(tp, FREAD|FWRITE);
e1d74936 228 tp->t_oproc = 0; /* mark closed */
45372428
MT
229}
230
ae9a0a69 231ptcread(dev, uio)
1a954a11 232 dev_t dev;
ae9a0a69 233 struct uio *uio;
e1d74936 234{
840510a3 235 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914 236 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2bb0bef9
SL
237 char buf[BUFSIZ];
238 int error = 0, cc;
45372428 239
5bb90914
JB
240 /*
241 * We want to block until the slave
242 * is open, and there's something to read;
243 * but if we lost the slave or we're NBIO,
244 * then return the appropriate error instead.
245 */
246 for (;;) {
247 if (tp->t_state&TS_ISOPEN) {
248 if (pti->pt_flags&PF_PKT && pti->pt_send) {
249 error = ureadc(pti->pt_send, uio);
250 if (error)
251 return (error);
252 pti->pt_send = 0;
253 return (0);
254 }
255 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
256 error = ureadc(pti->pt_ucntl, uio);
257 if (error)
258 return (error);
259 pti->pt_ucntl = 0;
260 return (0);
261 }
262 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
263 break;
1a954a11 264 }
2bb0bef9
SL
265 if ((tp->t_state&TS_CARR_ON) == 0)
266 return (EIO);
840510a3
BJ
267 if (pti->pt_flags&PF_NBIO)
268 return (EWOULDBLOCK);
45372428 269 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
8b8271ac 270 }
5bb90914
JB
271 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
272 error = ureadc(0, uio);
2bb0bef9
SL
273 while (uio->uio_resid > 0 && error == 0) {
274 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
275 if (cc <= 0)
ae9a0a69 276 break;
2bb0bef9
SL
277 error = uiomove(buf, cc, UIO_READ, uio);
278 }
941944c9
BJ
279 if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
280 if (tp->t_state&TS_ASLEEP) {
281 tp->t_state &= ~TS_ASLEEP;
282 wakeup((caddr_t)&tp->t_outq);
283 }
284 if (tp->t_wsel) {
285 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
286 tp->t_wsel = 0;
287 tp->t_state &= ~TS_WCOLL;
288 }
45372428 289 }
840510a3 290 return (error);
45372428
MT
291}
292
1a954a11
BJ
293ptsstop(tp, flush)
294 register struct tty *tp;
295 int flush;
296{
297 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
5bb90914 298 int flag;
1a954a11 299
1e6d24b1
BJ
300 /* note: FLUSHREAD and FLUSHWRITE already ok */
301 if (flush == 0) {
302 flush = TIOCPKT_STOP;
303 pti->pt_flags |= PF_STOPPED;
5bb90914 304 } else
1e6d24b1 305 pti->pt_flags &= ~PF_STOPPED;
0a2bd708 306 pti->pt_send |= flush;
5bb90914
JB
307 /* change of perspective */
308 flag = 0;
309 if (flush & FREAD)
310 flag |= FWRITE;
311 if (flush & FWRITE)
312 flag |= FREAD;
313 ptcwakeup(tp, flush);
1a954a11
BJ
314}
315
941944c9 316ptcselect(dev, rw)
e1d74936 317 dev_t dev;
941944c9 318 int rw;
e1d74936
BJ
319{
320 register struct tty *tp = &pt_tty[minor(dev)];
defdbcd1 321 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e1d74936 322 struct proc *p;
d427b3b2 323 int s;
e1d74936 324
5bb90914 325 if ((tp->t_state&TS_CARR_ON) == 0)
e1d74936 326 return (1);
d427b3b2 327 s = spl5();
941944c9
BJ
328 switch (rw) {
329
330 case FREAD:
5bb90914
JB
331 if ((tp->t_state&TS_ISOPEN) &&
332 (pti->pt_flags&PF_PKT && pti->pt_send ||
333 pti->pt_flags&PF_UCNTL && pti->pt_ucntl ||
334 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)) {
d427b3b2 335 splx(s);
941944c9 336 return (1);
d427b3b2 337 }
1a954a11
BJ
338 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
339 pti->pt_flags |= PF_RCOLL;
941944c9 340 else
1a954a11 341 pti->pt_selr = u.u_procp;
d427b3b2 342 break;
941944c9
BJ
343
344 case FWRITE:
5bb90914 345 if ((tp->t_state&TS_ISOPEN) &&
d19cae27 346 ((pti->pt_flags&PF_REMOTE) == 0 || tp->t_canq.c_cc == 0)) {
d427b3b2 347 splx(s);
941944c9 348 return (1);
d427b3b2 349 }
1a954a11
BJ
350 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
351 pti->pt_flags |= PF_WCOLL;
941944c9 352 else
1a954a11 353 pti->pt_selw = u.u_procp;
d427b3b2 354 break;
941944c9 355 }
d427b3b2
BJ
356 splx(s);
357 return (0);
e1d74936
BJ
358}
359
ae9a0a69 360ptcwrite(dev, uio)
941944c9 361 dev_t dev;
5bb90914 362 register struct uio *uio;
e1d74936 363{
840510a3 364 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914
JB
365 register struct iovec *iov;
366 register char *cp;
367 register int cc = 0;
45372428 368 char locbuf[BUFSIZ];
941944c9 369 int cnt = 0;
defdbcd1 370 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 371 int error = 0;
45372428 372
defdbcd1 373again:
5bb90914
JB
374 if ((tp->t_state&TS_ISOPEN) == 0)
375 goto block;
376 if (cnt == 0 && pti->pt_flags & PF_REMOTE) {
377 if (uio->uio_iovcnt <= 0)
840510a3 378 return (0);
5bb90914
JB
379 if (tp->t_canq.c_cc)
380 goto block;
381 iov = uio->uio_iov;
382 if (cc == 0 && iov->iov_len) {
383 cc = MIN(iov->iov_len, BUFSIZ);
384 cp = locbuf;
385 error = uiomove(cp, cc, UIO_WRITE, uio);
386 if (error)
387 return (error);
388 /* check again for safety */
389 if ((tp->t_state&TS_ISOPEN) == 0)
390 return (EIO);
391 if (tp->t_canq.c_cc)
392 goto block;
defdbcd1 393 }
5bb90914
JB
394 if (cc)
395 (void) b_to_q(cp, cc, &tp->t_canq);
396 (void) putc(0, &tp->t_canq);
397 ttwakeup(tp);
398 wakeup((caddr_t)&tp->t_canq);
399 return (0);
400 }
401 while (uio->uio_iovcnt > 0) {
402 iov = uio->uio_iov;
403 if (cc == 0) {
404 if (iov->iov_len == 0) {
405 uio->uio_iovcnt--;
406 uio->uio_iov++;
407 continue;
45372428 408 }
5bb90914
JB
409 cc = MIN(iov->iov_len, BUFSIZ);
410 cp = locbuf;
411 error = uiomove(cp, cc, UIO_WRITE, uio);
412 if (error)
413 return (error);
414 /* check again for safety */
415 if ((tp->t_state&TS_ISOPEN) == 0)
416 return (EIO);
417 }
418 while (--cc >= 0) {
36612a8f 419 (*linesw[tp->t_line].l_rint)(*cp++, tp);
941944c9 420 cnt++;
45372428 421 }
5bb90914
JB
422 cc = 0;
423 }
424 return (0);
425block:
426 /*
427 * Come here to wait for slave to open or for space
428 * in outq.
429 */
430 if ((tp->t_state&TS_CARR_ON) == 0)
431 return (EIO);
432 if (pti->pt_flags & PF_NBIO) {
433 if (cnt == 0)
434 return (EWOULDBLOCK);
435 iov->iov_base -= cc;
436 iov->iov_len += cc;
437 uio->uio_resid += cc;
438 uio->uio_offset -= cc;
439 return (0);
440 }
441 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
442 goto again;
45372428
MT
443}
444
45372428 445/*ARGSUSED*/
4b72e2f9
SL
446ptyioctl(dev, cmd, data, flag)
447 caddr_t data;
e1d74936
BJ
448 dev_t dev;
449{
0a2bd708
BJ
450 register struct tty *tp = &pt_tty[minor(dev)];
451 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
5bb90914 452 int stop, error;
45372428 453
e1d74936 454 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4b72e2f9
SL
455 if (cdevsw[major(dev)].d_open == ptcopen)
456 switch (cmd) {
457
458 case TIOCPKT:
5bb90914
JB
459 if (*(int *)data) {
460 if (pti->pt_flags & PF_UCNTL)
461 return (EINVAL);
1a954a11 462 pti->pt_flags |= PF_PKT;
5bb90914 463 } else
1a954a11 464 pti->pt_flags &= ~PF_PKT;
f21c8fb8 465 return (0);
4b72e2f9 466
5bb90914
JB
467 case TIOCUCNTL:
468 if (*(int *)data) {
469 if (pti->pt_flags & PF_PKT)
470 return (EINVAL);
471 pti->pt_flags |= PF_UCNTL;
472 } else
473 pti->pt_flags &= ~PF_UCNTL;
474 return (0);
475
4b72e2f9
SL
476 case TIOCREMOTE:
477 if (*(int *)data)
defdbcd1
BJ
478 pti->pt_flags |= PF_REMOTE;
479 else
480 pti->pt_flags &= ~PF_REMOTE;
88a7a62a 481 ttyflush(tp, FREAD|FWRITE);
f21c8fb8 482 return (0);
4b72e2f9
SL
483
484 case FIONBIO:
485 if (*(int *)data)
1a954a11 486 pti->pt_flags |= PF_NBIO;
8b8271ac 487 else
1a954a11 488 pti->pt_flags &= ~PF_NBIO;
f21c8fb8 489 return (0);
4b72e2f9
SL
490
491 case TIOCSETP:
492 while (getc(&tp->t_outq) >= 0)
493 ;
494 break;
8b8271ac 495 }
477d62ec 496 error = ttioctl(tp, cmd, data, flag);
5bb90914
JB
497 if (error < 0) {
498 if (pti->pt_flags & PF_UCNTL &&
499 (cmd & ~0xff) == _IO(u,0)) {
500 if (cmd & 0xff) {
501 pti->pt_ucntl = (u_char)cmd;
502 ptcwakeup(tp, FREAD);
503 }
504 return (0);
505 }
f21c8fb8 506 error = ENOTTY;
5bb90914
JB
507 }
508 stop = (tp->t_flags & RAW) == 0 &&
509 tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
0a2bd708
BJ
510 if (pti->pt_flags & PF_NOSTOP) {
511 if (stop) {
512 pti->pt_send &= TIOCPKT_NOSTOP;
513 pti->pt_send |= TIOCPKT_DOSTOP;
514 pti->pt_flags &= ~PF_NOSTOP;
5bb90914 515 ptcwakeup(tp, FREAD);
0a2bd708
BJ
516 }
517 } else {
5bb90914 518 if (!stop) {
0a2bd708
BJ
519 pti->pt_send &= ~TIOCPKT_DOSTOP;
520 pti->pt_send |= TIOCPKT_NOSTOP;
521 pti->pt_flags |= PF_NOSTOP;
5bb90914 522 ptcwakeup(tp, FREAD);
0a2bd708
BJ
523 }
524 }
f21c8fb8 525 return (error);
45372428 526}
4f07e6e5 527#endif