|
|
1.1 root 1: /*
2: * Copyright (c) 1982, 1986, 1989 The Regents of the University of California.
3: * All rights reserved.
4: *
5: * Redistribution is only permitted until one year after the first shipment
6: * of 4.4BSD by the Regents. Otherwise, redistribution and use in source and
7: * binary forms are permitted provided that: (1) source distributions retain
8: * this entire copyright notice and comment, and (2) distributions including
9: * binaries display the following acknowledgement: This product includes
10: * software developed by the University of California, Berkeley and its
11: * contributors'' in the documentation or other materials provided with the
12: * distribution and in all advertising materials mentioning features or use
13: * of this software. Neither the name of the University nor the names of
14: * its contributors may be used to endorse or promote products derived from
15: * this software without specific prior written permission.
16: * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
17: * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
18: * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19: *
20: * @(#)tty_pty.c 7.15 (Berkeley) 6/28/90
21: */
22:
23: /*
24: * Pseudo-teletype Driver
25: * (Actually two drivers, requiring two entries in 'cdevsw')
26: */
27: #include "pty.h"
28:
29: #if NPTY > 0
30: #include "param.h"
31: #include "systm.h"
32: #include "ioctl.h"
33: #include "tty.h"
34: #include "user.h"
35: #include "conf.h"
36: #include "file.h"
37: #include "proc.h"
38: #include "uio.h"
39: #include "kernel.h"
40: #include "vnode.h"
41:
42: #if NPTY == 1
43: #undef NPTY
44: #define NPTY 32 /* crude XXX */
45: #endif
46:
47: #define BUFSIZ 100 /* Chunk size iomoved to/from user */
48:
49: /*
50: * pts == /dev/tty[pqrs]?
51: * ptc == /dev/pty[pqrs]?
52: */
53: struct tty pt_tty[NPTY];
54: struct pt_ioctl {
55: int pt_flags;
56: struct proc *pt_selr, *pt_selw;
57: u_char pt_send;
58: u_char pt_ucntl;
59: } pt_ioctl[NPTY];
60: int npty = NPTY; /* for pstat -t */
61:
62: int ptydebug = 0;
63:
64: #define PF_RCOLL 0x01
65: #define PF_WCOLL 0x02
66: #define PF_NBIO 0x04
67: #define PF_PKT 0x08 /* packet mode */
68: #define PF_STOPPED 0x10 /* user told stopped */
69: #define PF_REMOTE 0x20 /* remote and flow controlled input */
70: #define PF_NOSTOP 0x40
71: #define PF_UCNTL 0x80 /* user control mode */
72:
73: /*ARGSUSED*/
74: ptsopen(dev, flag)
75: dev_t dev;
76: {
77: register struct tty *tp;
78: int error;
79:
80: #ifdef lint
81: npty = npty;
82: #endif
83: if (minor(dev) >= NPTY)
84: return (ENXIO);
85: tp = &pt_tty[minor(dev)];
86: if ((tp->t_state & TS_ISOPEN) == 0) {
87: tp->t_state |= TS_WOPEN;
88: ttychars(tp); /* Set up default chars */
89: tp->t_iflag = TTYDEF_IFLAG;
90: tp->t_oflag = TTYDEF_OFLAG;
91: tp->t_lflag = TTYDEF_LFLAG;
92: tp->t_cflag = TTYDEF_CFLAG;
93: tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
94: ttsetwater(tp); /* would be done in xxparam() */
95: } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
96: return (EBUSY);
97: if (tp->t_oproc) /* Ctrlr still around. */
98: tp->t_state |= TS_CARR_ON;
99: while ((tp->t_state & TS_CARR_ON) == 0) {
100: tp->t_state |= TS_WOPEN;
101: if (flag&FNDELAY)
102: break;
103: if (error = ttysleep(tp, (caddr_t)&tp->t_rawq, TTIPRI | PCATCH,
104: ttopen, 0))
105: return (error);
106: }
107: error = (*linesw[tp->t_line].l_open)(dev, tp, flag);
108: ptcwakeup(tp, FREAD|FWRITE);
109: return (error);
110: }
111:
112: ptsclose(dev)
113: dev_t dev;
114: {
115: register struct tty *tp;
116:
117: tp = &pt_tty[minor(dev)];
118: (*linesw[tp->t_line].l_close)(tp);
119: ttyclose(tp);
120: ptcwakeup(tp, FREAD|FWRITE);
121: }
122:
123: ptsread(dev, uio, flag)
124: dev_t dev;
125: struct uio *uio;
126: {
127: register struct tty *tp = &pt_tty[minor(dev)];
128: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
129: int error = 0;
130:
131: again:
132: if (pti->pt_flags & PF_REMOTE) {
133: while (isbackground(u.u_procp, tp)) {
134: if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
135: (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
136: u.u_procp->p_pgrp->pg_jobc == 0 ||
137: u.u_procp->p_flag&SVFORK)
138: return (EIO);
139: pgsignal(u.u_procp->p_pgrp, SIGTTIN, 1);
140: if (error = ttysleep(tp, (caddr_t)&lbolt,
141: TTIPRI | PCATCH, ttybg, 0))
142: return (error);
143: }
144: if (tp->t_canq.c_cc == 0) {
145: if (flag & IO_NDELAY)
146: return (EWOULDBLOCK);
147: if (error = ttysleep(tp, (caddr_t)&tp->t_canq,
148: TTIPRI | PCATCH, ttyin, 0))
149: return (error);
150: goto again;
151: }
152: while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
153: if (ureadc(getc(&tp->t_canq), uio) < 0) {
154: error = EFAULT;
155: break;
156: }
157: if (tp->t_canq.c_cc == 1)
158: (void) getc(&tp->t_canq);
159: if (tp->t_canq.c_cc)
160: return (error);
161: } else
162: if (tp->t_oproc)
163: error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
164: ptcwakeup(tp, FWRITE);
165: return (error);
166: }
167:
168: /*
169: * Write to pseudo-tty.
170: * Wakeups of controlling tty will happen
171: * indirectly, when tty driver calls ptsstart.
172: */
173: ptswrite(dev, uio, flag)
174: dev_t dev;
175: struct uio *uio;
176: {
177: register struct tty *tp;
178:
179: tp = &pt_tty[minor(dev)];
180: if (tp->t_oproc == 0)
181: return (EIO);
182: return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
183: }
184:
185: /*
186: * Start output on pseudo-tty.
187: * Wake up process selecting or sleeping for input from controlling tty.
188: */
189: ptsstart(tp)
190: struct tty *tp;
191: {
192: register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
193:
194: if (tp->t_state & TS_TTSTOP)
195: return;
196: if (pti->pt_flags & PF_STOPPED) {
197: pti->pt_flags &= ~PF_STOPPED;
198: pti->pt_send = TIOCPKT_START;
199: }
200: ptcwakeup(tp, FREAD);
201: }
202:
203: ptcwakeup(tp, flag)
204: struct tty *tp;
205: {
206: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
207:
208: if (flag & FREAD) {
209: if (pti->pt_selr) {
210: selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
211: pti->pt_selr = 0;
212: pti->pt_flags &= ~PF_RCOLL;
213: }
214: wakeup((caddr_t)&tp->t_outq.c_cf);
215: }
216: if (flag & FWRITE) {
217: if (pti->pt_selw) {
218: selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
219: pti->pt_selw = 0;
220: pti->pt_flags &= ~PF_WCOLL;
221: }
222: if (ptydebug) printf("WAKEUP c_cf %d\n", u.u_procp->p_pid);
223: wakeup((caddr_t)&tp->t_rawq.c_cf);
224: }
225: }
226:
227: /*ARGSUSED*/
228: ptcopen(dev, flag)
229: dev_t dev;
230: int flag;
231: {
232: register struct tty *tp;
233: struct pt_ioctl *pti;
234:
235: if (minor(dev) >= NPTY)
236: return (ENXIO);
237: tp = &pt_tty[minor(dev)];
238: if (tp->t_oproc)
239: return (EIO);
240: tp->t_oproc = ptsstart;
241: (void)(*linesw[tp->t_line].l_modem)(tp, 1);
242: tp->t_lflag &= ~EXTPROC;
243: pti = &pt_ioctl[minor(dev)];
244: pti->pt_flags = 0;
245: pti->pt_send = 0;
246: pti->pt_ucntl = 0;
247: return (0);
248: }
249:
250: ptcclose(dev)
251: dev_t dev;
252: {
253: register struct tty *tp;
254:
255: tp = &pt_tty[minor(dev)];
256: (void)(*linesw[tp->t_line].l_modem)(tp, 0);
257: tp->t_state &= ~TS_CARR_ON;
258: tp->t_oproc = 0; /* mark closed */
259: tp->t_session = 0;
260: }
261:
262: ptcread(dev, uio, flag)
263: dev_t dev;
264: struct uio *uio;
265: {
266: register struct tty *tp = &pt_tty[minor(dev)];
267: struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
268: char buf[BUFSIZ];
269: int error = 0, cc;
270:
271: /*
272: * We want to block until the slave
273: * is open, and there's something to read;
274: * but if we lost the slave or we're NBIO,
275: * then return the appropriate error instead.
276: */
277: for (;;) {
278: if (tp->t_state&TS_ISOPEN) {
279: if (pti->pt_flags&PF_PKT && pti->pt_send) {
280: error = ureadc((int)pti->pt_send, uio);
281: if (error)
282: return (error);
283: if (pti->pt_send & TIOCPKT_IOCTL) {
284: cc = MIN(uio->uio_resid,
285: sizeof(tp->t_termios));
286: uiomove(&tp->t_termios, cc, uio);
287: }
288: pti->pt_send = 0;
289: return (0);
290: }
291: if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
292: error = ureadc((int)pti->pt_ucntl, uio);
293: if (error)
294: return (error);
295: pti->pt_ucntl = 0;
296: return (0);
297: }
298: if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
299: break;
300: }
301: if ((tp->t_state&TS_CARR_ON) == 0)
302: return (0); /* EOF */
303: if (flag & IO_NDELAY)
304: return (EWOULDBLOCK);
305: if (error = tsleep((caddr_t)&tp->t_outq.c_cf, TTIPRI | PCATCH,
306: ttyin, 0))
307: return (error);
308: }
309: if (pti->pt_flags & (PF_PKT|PF_UCNTL))
310: error = ureadc(0, uio);
311: while (uio->uio_resid > 0 && error == 0) {
312: cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
313: if (cc <= 0)
314: break;
315: error = uiomove(buf, cc, uio);
316: }
317: if (tp->t_outq.c_cc <= tp->t_lowat) {
318: if (tp->t_state&TS_ASLEEP) {
319: tp->t_state &= ~TS_ASLEEP;
320: wakeup((caddr_t)&tp->t_outq);
321: }
322: if (tp->t_wsel) {
323: selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
324: tp->t_wsel = 0;
325: tp->t_state &= ~TS_WCOLL;
326: }
327: }
328: return (error);
329: }
330:
331: ptsstop(tp, flush)
332: register struct tty *tp;
333: int flush;
334: {
335: struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
336: int flag;
337:
338: /* note: FLUSHREAD and FLUSHWRITE already ok */
339: if (flush == 0) {
340: flush = TIOCPKT_STOP;
341: pti->pt_flags |= PF_STOPPED;
342: } else
343: pti->pt_flags &= ~PF_STOPPED;
344: pti->pt_send |= flush;
345: /* change of perspective */
346: flag = 0;
347: if (flush & FREAD)
348: flag |= FWRITE;
349: if (flush & FWRITE)
350: flag |= FREAD;
351: ptcwakeup(tp, flag);
352: }
353:
354: ptcselect(dev, rw)
355: dev_t dev;
356: int rw;
357: {
358: register struct tty *tp = &pt_tty[minor(dev)];
359: struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
360: struct proc *p;
361: int s;
362:
363: if ((tp->t_state&TS_CARR_ON) == 0)
364: return (1);
365: switch (rw) {
366:
367: case FREAD:
368: /*
369: * Need to block timeouts (ttrstart).
370: */
371: s = spltty();
372: if ((tp->t_state&TS_ISOPEN) &&
373: tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
374: splx(s);
375: return (1);
376: }
377: splx(s);
378: /* FALLTHROUGH */
379:
380: case 0: /* exceptional */
381: if ((tp->t_state&TS_ISOPEN) &&
382: (pti->pt_flags&PF_PKT && pti->pt_send ||
383: pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
384: return (1);
385: if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
386: pti->pt_flags |= PF_RCOLL;
387: else
388: pti->pt_selr = u.u_procp;
389: break;
390:
391:
392: case FWRITE:
393: if (tp->t_state&TS_ISOPEN) {
394: if (pti->pt_flags & PF_REMOTE) {
395: if (tp->t_canq.c_cc == 0)
396: return (1);
397: } else {
398: if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
399: return (1);
400: if (tp->t_canq.c_cc == 0 && (tp->t_iflag&ICANON))
401: return (1);
402: }
403: }
404: if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
405: pti->pt_flags |= PF_WCOLL;
406: else
407: pti->pt_selw = u.u_procp;
408: break;
409:
410: }
411: return (0);
412: }
413:
414: ptcwrite(dev, uio, flag)
415: dev_t dev;
416: register struct uio *uio;
417: {
418: register struct tty *tp = &pt_tty[minor(dev)];
419: register struct iovec *iov;
420: register char *cp;
421: register int cc = 0;
422: char locbuf[BUFSIZ];
423: int cnt = 0;
424: struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
425: int error = 0;
426:
427: again:
428: if ((tp->t_state&TS_ISOPEN) == 0)
429: goto block;
430: if (pti->pt_flags & PF_REMOTE) {
431: if (tp->t_canq.c_cc)
432: goto block;
433: while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
434: iov = uio->uio_iov;
435: if (iov->iov_len == 0) {
436: uio->uio_iovcnt--;
437: uio->uio_iov++;
438: continue;
439: }
440: if (cc == 0) {
441: cc = MIN(iov->iov_len, BUFSIZ);
442: cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
443: cp = locbuf;
444: error = uiomove(cp, cc, uio);
445: if (error)
446: return (error);
447: /* check again for safety */
448: if ((tp->t_state&TS_ISOPEN) == 0)
449: return (EIO);
450: }
451: if (cc)
452: (void) b_to_q(cp, cc, &tp->t_canq);
453: cc = 0;
454: }
455: (void) putc(0, &tp->t_canq);
456: ttwakeup(tp);
457: wakeup((caddr_t)&tp->t_canq);
458: return (0);
459: }
460: while (uio->uio_iovcnt > 0) {
461: iov = uio->uio_iov;
462: if (cc == 0) {
463: if (iov->iov_len == 0) {
464: uio->uio_iovcnt--;
465: uio->uio_iov++;
466: continue;
467: }
468: cc = MIN(iov->iov_len, BUFSIZ);
469: cp = locbuf;
470: error = uiomove(cp, cc, uio);
471: if (error)
472: return (error);
473: /* check again for safety */
474: if ((tp->t_state&TS_ISOPEN) == 0)
475: return (EIO);
476: }
477: while (cc > 0) {
478: if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
479: (tp->t_canq.c_cc > 0 || !(tp->t_iflag&ICANON))) {
480: wakeup((caddr_t)&tp->t_rawq);
481: goto block;
482: }
483: (*linesw[tp->t_line].l_rint)(*cp++&0377, tp);
484: cnt++;
485: cc--;
486: }
487: cc = 0;
488: }
489: return (0);
490: block:
491: /*
492: * Come here to wait for slave to open, for space
493: * in outq, or space in rawq.
494: */
495: if ((tp->t_state&TS_CARR_ON) == 0)
496: return (EIO);
497: if ((pti->pt_flags & PF_NBIO) || (flag & IO_NDELAY)) {
498: iov->iov_base -= cc;
499: iov->iov_len += cc;
500: uio->uio_resid += cc;
501: uio->uio_offset -= cc;
502: if (cnt == 0)
503: return (EWOULDBLOCK);
504: return (0);
505: }
506: if (error = tsleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI | PCATCH,
507: ttyout, 0))
508: return (error);
509: goto again;
510: }
511:
512: /*ARGSUSED*/
513: ptyioctl(dev, cmd, data, flag)
514: caddr_t data;
515: dev_t dev;
516: {
517: register struct tty *tp = &pt_tty[minor(dev)];
518: register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
519: register u_char *cc = tp->t_cc;
520: int stop, error;
521: extern ttyinput();
522:
523: /*
524: * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
525: * ttywflush(tp) will hang if there are characters in the outq.
526: */
527: if (cmd == TIOCEXT) {
528: /*
529: * When the EXTPROC bit is being toggled, we need
530: * to send an TIOCPKT_IOCTL if the packet driver
531: * is turned on.
532: */
533: if (*(int *)data) {
534: if (pti->pt_flags & PF_PKT) {
535: pti->pt_send |= TIOCPKT_IOCTL;
536: ptcwakeup(tp);
537: }
538: tp->t_lflag |= EXTPROC;
539: } else {
540: if ((tp->t_state & EXTPROC) &&
541: (pti->pt_flags & PF_PKT)) {
542: pti->pt_send |= TIOCPKT_IOCTL;
543: ptcwakeup(tp);
544: }
545: tp->t_lflag &= ~EXTPROC;
546: }
547: return(0);
548: } else
549: if (cdevsw[major(dev)].d_open == ptcopen)
550: switch (cmd) {
551:
552: case TIOCGPGRP:
553: /*
554: * We aviod calling ttioctl on the controller since,
555: * in that case, tp must be the controlling terminal.
556: */
557: *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
558: return (0);
559:
560: case TIOCPKT:
561: if (*(int *)data) {
562: if (pti->pt_flags & PF_UCNTL)
563: return (EINVAL);
564: pti->pt_flags |= PF_PKT;
565: } else
566: pti->pt_flags &= ~PF_PKT;
567: return (0);
568:
569: case TIOCUCNTL:
570: if (*(int *)data) {
571: if (pti->pt_flags & PF_PKT)
572: return (EINVAL);
573: pti->pt_flags |= PF_UCNTL;
574: } else
575: pti->pt_flags &= ~PF_UCNTL;
576: return (0);
577:
578: case TIOCREMOTE:
579: if (*(int *)data)
580: pti->pt_flags |= PF_REMOTE;
581: else
582: pti->pt_flags &= ~PF_REMOTE;
583: ttyflush(tp, FREAD|FWRITE);
584: return (0);
585:
586: case FIONBIO:
587: if (*(int *)data)
588: pti->pt_flags |= PF_NBIO;
589: else
590: pti->pt_flags &= ~PF_NBIO;
591: return (0);
592:
593: case TIOCSETP:
594: case TIOCSETN:
595: case TIOCSETD:
596: case TIOCSETA:
597: case TIOCSETAW:
598: case TIOCSETAF:
599: case JUNK_TIOCSETAS:
600: case JUNK_TIOCSETAWS:
601: case JUNK_TIOCSETAFS:
602: while (getc(&tp->t_outq) >= 0)
603: ;
604: break;
605:
606: case TIOCSIG:
607: if (*(unsigned int *)data >= NSIG)
608: return(EINVAL);
609: if ((tp->t_lflag&NOFLSH) == 0)
610: ttyflush(tp, FREAD|FWRITE);
611: pgsignal(tp->t_pgrp, *(unsigned int *)data);
612: return(0);
613: }
614: error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag);
615: if (error < 0)
616: error = ttioctl(tp, cmd, data, flag);
617: /*
618: * Since we use the tty queues internally,
619: * pty's can't be switched to disciplines which overwrite
620: * the queues. We can't tell anything about the discipline
621: * from here...
622: */
623: if (linesw[tp->t_line].l_rint != ttyinput) {
624: (*linesw[tp->t_line].l_close)(tp);
625: tp->t_line = 0;
626: (void)(*linesw[tp->t_line].l_open)(dev, tp, flag);
627: error = ENOTTY;
628: }
629: if (error < 0) {
630: if (pti->pt_flags & PF_UCNTL &&
631: (cmd & ~0xff) == UIOCCMD(0)) {
632: if (cmd & 0xff) {
633: pti->pt_ucntl = (u_char)cmd;
634: ptcwakeup(tp, FREAD);
635: }
636: return (0);
637: }
638: error = ENOTTY;
639: }
640: /*
641: * If external processing and packet mode send ioctl packet.
642: */
643: if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
644: switch(cmd) {
645: case TIOCSETA:
646: case TIOCSETAW:
647: case TIOCSETAF:
648: case JUNK_TIOCSETAS:
649: case JUNK_TIOCSETAWS:
650: case JUNK_TIOCSETAFS:
651: case TIOCSETP:
652: case TIOCSETN:
653: #ifdef COMPAT_43
654: case TIOCSETC:
655: case TIOCSLTC:
656: case TIOCLBIS:
657: case TIOCLBIC:
658: case TIOCLSET:
659: #endif
660: pti->pt_send |= TIOCPKT_IOCTL;
661: default:
662: break;
663: }
664: }
665: stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
666: && CCEQ(cc[VSTART], CTRL('q'));
667: if (pti->pt_flags & PF_NOSTOP) {
668: if (stop) {
669: pti->pt_send &= ~TIOCPKT_NOSTOP;
670: pti->pt_send |= TIOCPKT_DOSTOP;
671: pti->pt_flags &= ~PF_NOSTOP;
672: ptcwakeup(tp, FREAD);
673: }
674: } else {
675: if (!stop) {
676: pti->pt_send &= ~TIOCPKT_DOSTOP;
677: pti->pt_send |= TIOCPKT_NOSTOP;
678: pti->pt_flags |= PF_NOSTOP;
679: ptcwakeup(tp, FREAD);
680: }
681: }
682: return (error);
683: }
684: #endif
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.