don't convert ashl, bicl to extzv if `field' crosses long boundary
[unix-history] / usr / src / sys / kern / tty_pty.c
CommitLineData
28b2d854 1/* tty_pty.c 6.4 84/02/15 */
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"
425a48ad 12#include "../h/ioctl.h"
45372428
MT
13#include "../h/tty.h"
14#include "../h/dir.h"
15#include "../h/user.h"
16#include "../h/conf.h"
bdda6b91 17#include "../h/file.h"
e1d74936 18#include "../h/proc.h"
ae9a0a69 19#include "../h/uio.h"
7ba3a9ca 20#include "../h/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
bdda6b91 27#define BUFSIZ 100 /* Chunk size iomoved 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);
45372428
MT
81}
82
ae9a0a69 83ptsread(dev, uio)
73c77d38 84 dev_t dev;
ae9a0a69 85 struct uio *uio;
e1d74936 86{
defdbcd1
BJ
87 register struct tty *tp = &pt_tty[minor(dev)];
88 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 89 int error = 0;
defdbcd1
BJ
90
91again:
92 if (pti->pt_flags & PF_REMOTE) {
93 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
3622edaa
MK
94#define bit(a) (1<<(a-1))
95 if ((u.u_procp->p_sigignore & bit(SIGTTIN)) ||
96 (u.u_procp->p_sigmask & bit(SIGTTIN)) ||
defdbcd1
BJ
97 /*
98 (u.u_procp->p_flag&SDETACH) ||
99 */
100 u.u_procp->p_flag&SVFORK)
840510a3 101 return (EIO);
defdbcd1
BJ
102 gsignal(u.u_procp->p_pgrp, SIGTTIN);
103 sleep((caddr_t)&lbolt, TTIPRI);
941944c9 104 }
3622edaa 105#undef bit
defdbcd1 106 if (tp->t_rawq.c_cc == 0) {
840510a3
BJ
107 if (tp->t_state & TS_NBIO)
108 return (EWOULDBLOCK);
defdbcd1
BJ
109 sleep((caddr_t)&tp->t_rawq, TTIPRI);
110 goto again;
111 }
ae9a0a69
BJ
112 while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0)
113 if (ureadc(getc(&tp->t_rawq), uio) < 0) {
840510a3 114 error = EFAULT;
ae9a0a69
BJ
115 break;
116 }
defdbcd1
BJ
117 if (tp->t_rawq.c_cc == 1)
118 (void) getc(&tp->t_rawq);
119 if (tp->t_rawq.c_cc)
840510a3 120 return (error);
defdbcd1
BJ
121 } else
122 if (tp->t_oproc)
840510a3 123 error = (*linesw[tp->t_line].l_read)(tp, uio);
defdbcd1
BJ
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;
45372428 129 }
840510a3 130 return (error);
45372428
MT
131}
132
941944c9
BJ
133/*
134 * Write to pseudo-tty.
135 * Wakeups of controlling tty will happen
136 * indirectly, when tty driver calls ptsstart.
137 */
ae9a0a69 138ptswrite(dev, uio)
73c77d38 139 dev_t dev;
ae9a0a69 140 struct uio *uio;
e1d74936 141{
45372428
MT
142 register struct tty *tp;
143
144 tp = &pt_tty[minor(dev)];
840510a3
BJ
145 if (tp->t_oproc == 0)
146 return (EIO);
147 return ((*linesw[tp->t_line].l_write)(tp, uio));
45372428
MT
148}
149
941944c9
BJ
150/*
151 * Start output on pseudo-tty.
152 * Wake up process selecting or sleeping for input from controlling tty.
153 */
45372428 154ptsstart(tp)
e1d74936
BJ
155 struct tty *tp;
156{
1e6d24b1 157 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
e1d74936 158
941944c9 159 if (tp->t_state & TS_TTSTOP)
45372428 160 return;
1e6d24b1
BJ
161 if (pti->pt_flags & PF_STOPPED) {
162 pti->pt_flags &= ~PF_STOPPED;
163 pti->pt_send = TIOCPKT_START;
164 }
d427b3b2
BJ
165 ptcwakeup(tp);
166}
167
168ptcwakeup(tp)
169 struct tty *tp;
170{
171 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
172
1a954a11
BJ
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;
e1d74936 177 }
45372428
MT
178 wakeup((caddr_t)&tp->t_outq.c_cf);
179}
180
181/*ARGSUSED*/
182ptcopen(dev, flag)
e1d74936
BJ
183 dev_t dev;
184 int flag;
185{
45372428 186 register struct tty *tp;
1a954a11 187 struct pt_ioctl *pti;
45372428 188
f21c8fb8
BJ
189 if (minor(dev) >= NPTY)
190 return (ENXIO);
45372428 191 tp = &pt_tty[minor(dev)];
f21c8fb8
BJ
192 if (tp->t_oproc)
193 return (EIO);
e1d74936 194 tp->t_oproc = ptsstart;
941944c9 195 if (tp->t_state & TS_WOPEN)
45372428 196 wakeup((caddr_t)&tp->t_rawq);
941944c9 197 tp->t_state |= TS_CARR_ON;
1a954a11
BJ
198 pti = &pt_ioctl[minor(dev)];
199 pti->pt_flags = 0;
200 pti->pt_send = 0;
f21c8fb8 201 return (0);
45372428
MT
202}
203
204ptcclose(dev)
e1d74936
BJ
205 dev_t dev;
206{
45372428
MT
207 register struct tty *tp;
208
209 tp = &pt_tty[minor(dev)];
941944c9 210 if (tp->t_state & TS_ISOPEN)
45372428 211 gsignal(tp->t_pgrp, SIGHUP);
941944c9 212 tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */
88a7a62a 213 ttyflush(tp, FREAD|FWRITE);
e1d74936 214 tp->t_oproc = 0; /* mark closed */
45372428
MT
215}
216
ae9a0a69 217ptcread(dev, uio)
1a954a11 218 dev_t dev;
ae9a0a69 219 struct uio *uio;
e1d74936 220{
840510a3 221 register struct tty *tp = &pt_tty[minor(dev)];
1a954a11 222 struct pt_ioctl *pti;
840510a3 223 int error = 0;
45372428 224
941944c9 225 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
a8d3bf7f 226 return (EIO);
1a954a11
BJ
227 pti = &pt_ioctl[minor(dev)];
228 if (pti->pt_flags & PF_PKT) {
229 if (pti->pt_send) {
840510a3
BJ
230 error = ureadc(pti->pt_send, uio);
231 if (error)
232 return (error);
1a954a11 233 pti->pt_send = 0;
840510a3 234 return (0);
1a954a11 235 }
840510a3 236 error = ureadc(0, uio);
1a954a11 237 }
8b8271ac 238 while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) {
840510a3
BJ
239 if (pti->pt_flags&PF_NBIO)
240 return (EWOULDBLOCK);
45372428 241 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
8b8271ac 242 }
ae9a0a69
BJ
243 while (tp->t_outq.c_cc && uio->uio_resid > 0)
244 if (ureadc(getc(&tp->t_outq), uio) < 0) {
840510a3 245 error = EFAULT;
ae9a0a69
BJ
246 break;
247 }
941944c9
BJ
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 }
45372428 258 }
840510a3 259 return (error);
45372428
MT
260}
261
1a954a11
BJ
262ptsstop(tp, flush)
263 register struct tty *tp;
264 int flush;
265{
266 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
267
1e6d24b1
BJ
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 }
0a2bd708 275 pti->pt_send |= flush;
d427b3b2 276 ptcwakeup(tp);
1a954a11
BJ
277}
278
941944c9 279ptcselect(dev, rw)
e1d74936 280 dev_t dev;
941944c9 281 int rw;
e1d74936
BJ
282{
283 register struct tty *tp = &pt_tty[minor(dev)];
defdbcd1 284 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e1d74936 285 struct proc *p;
d427b3b2 286 int s;
e1d74936 287
941944c9 288 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
e1d74936 289 return (1);
d427b3b2 290 s = spl5();
941944c9
BJ
291 switch (rw) {
292
293 case FREAD:
d427b3b2
BJ
294 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
295 splx(s);
941944c9 296 return (1);
d427b3b2 297 }
1a954a11
BJ
298 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
299 pti->pt_flags |= PF_RCOLL;
941944c9 300 else
1a954a11 301 pti->pt_selr = u.u_procp;
d427b3b2 302 break;
941944c9
BJ
303
304 case FWRITE:
defdbcd1 305 if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) {
d427b3b2 306 splx(s);
941944c9 307 return (1);
d427b3b2 308 }
1a954a11
BJ
309 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
310 pti->pt_flags |= PF_WCOLL;
941944c9 311 else
1a954a11 312 pti->pt_selw = u.u_procp;
d427b3b2 313 break;
941944c9 314 }
d427b3b2
BJ
315 splx(s);
316 return (0);
e1d74936
BJ
317}
318
ae9a0a69 319ptcwrite(dev, uio)
941944c9 320 dev_t dev;
ae9a0a69 321 struct uio *uio;
e1d74936 322{
840510a3 323 register struct tty *tp = &pt_tty[minor(dev)];
45372428
MT
324 register char *cp, *ce;
325 register int cc;
326 char locbuf[BUFSIZ];
941944c9 327 int cnt = 0;
defdbcd1 328 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 329 int error = 0;
45372428 330
941944c9 331 if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0)
840510a3 332 return (EIO);
defdbcd1 333 do {
ae9a0a69
BJ
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);
45372428 347 cp = locbuf;
840510a3
BJ
348 error = uiomove(cp, cc, UIO_WRITE, uio);
349 if (error)
45372428
MT
350 break;
351 ce = cp + cc;
defdbcd1
BJ
352again:
353 if (pti->pt_flags & PF_REMOTE) {
354 if (tp->t_rawq.c_cc) {
355 if (pti->pt_flags & PF_NBIO) {
ae9a0a69
BJ
356 iov->iov_base -= ce - cp;
357 iov->iov_len += ce - cp;
358 uio->uio_resid += ce - cp;
359 uio->uio_offset -= ce - cp;
840510a3 360 return (EWOULDBLOCK);
defdbcd1
BJ
361 }
362 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
363 goto again;
364 }
668cc26d
SL
365 (void) b_to_q(cp, cc, &tp->t_rawq);
366 (void) putc(0, &tp->t_rawq);
defdbcd1 367 wakeup((caddr_t)&tp->t_rawq);
840510a3 368 return (0);
defdbcd1 369 }
e1d74936 370 while (cp < ce) {
28b2d854
MK
371 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
372 (tp->t_canq.c_cc > 0)) {
45372428 373 wakeup((caddr_t)&tp->t_rawq);
941944c9 374 if (tp->t_state & TS_NBIO) {
ae9a0a69
BJ
375 iov->iov_base -= ce - cp;
376 iov->iov_len += ce - cp;
377 uio->uio_resid += ce - cp;
378 uio->uio_offset -= ce - cp;
941944c9 379 if (cnt == 0)
840510a3
BJ
380 return (EWOULDBLOCK);
381 return (0);
941944c9 382 }
45372428
MT
383 /* Better than just flushing it! */
384 /* Wait for something to be read */
385 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
defdbcd1 386 goto again;
45372428 387 }
36612a8f 388 (*linesw[tp->t_line].l_rint)(*cp++, tp);
941944c9 389 cnt++;
45372428 390 }
ae9a0a69 391 } while (uio->uio_resid);
840510a3 392 return (error);
45372428
MT
393}
394
45372428 395/*ARGSUSED*/
4b72e2f9
SL
396ptyioctl(dev, cmd, data, flag)
397 caddr_t data;
e1d74936
BJ
398 dev_t dev;
399{
0a2bd708
BJ
400 register struct tty *tp = &pt_tty[minor(dev)];
401 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
f21c8fb8 402 int error;
45372428 403
e1d74936 404 /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */
4b72e2f9
SL
405 if (cdevsw[major(dev)].d_open == ptcopen)
406 switch (cmd) {
407
408 case TIOCPKT:
409 if (*(int *)data)
1a954a11
BJ
410 pti->pt_flags |= PF_PKT;
411 else
412 pti->pt_flags &= ~PF_PKT;
f21c8fb8 413 return (0);
4b72e2f9
SL
414
415 case TIOCREMOTE:
416 if (*(int *)data)
defdbcd1
BJ
417 pti->pt_flags |= PF_REMOTE;
418 else
419 pti->pt_flags &= ~PF_REMOTE;
88a7a62a 420 ttyflush(tp, FREAD|FWRITE);
f21c8fb8 421 return (0);
4b72e2f9
SL
422
423 case FIONBIO:
424 if (*(int *)data)
1a954a11 425 pti->pt_flags |= PF_NBIO;
8b8271ac 426 else
1a954a11 427 pti->pt_flags &= ~PF_NBIO;
f21c8fb8 428 return (0);
4b72e2f9
SL
429
430 case TIOCSETP:
431 while (getc(&tp->t_outq) >= 0)
432 ;
433 break;
8b8271ac 434 }
f21c8fb8
BJ
435 error = ttioctl(tp, cmd, data, dev);
436 if (error < 0)
437 error = ENOTTY;
425a48ad
SL
438 { int stop = (tp->t_stopc == ('s'&037) &&
439 tp->t_startc == ('q'&037));
0a2bd708
BJ
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 }
f21c8fb8 456 return (error);
45372428 457}
4f07e6e5 458#endif