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