syscall messaging 3: Expand the 'header' that goes in front of the syscall
[dragonfly.git] / sys / kern / tty_pty.c
1 /*
2  * Copyright (c) 1982, 1986, 1989, 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  * 3. All advertising materials mentioning features or use of this software
14  *    must display the following acknowledgement:
15  *      This product includes software developed by the University of
16  *      California, Berkeley and its contributors.
17  * 4. Neither the name of the University nor the names of its contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  *      @(#)tty_pty.c   8.4 (Berkeley) 2/20/95
34  * $FreeBSD: src/sys/kern/tty_pty.c,v 1.74.2.4 2002/02/20 19:58:13 dillon Exp $
35  * $DragonFly: src/sys/kern/tty_pty.c,v 1.8 2003/07/26 19:42:11 rob Exp $
36  */
37
38 /*
39  * Pseudo-teletype Driver
40  * (Actually two drivers, requiring two entries in 'cdevsw')
41  */
42 #include "pty.h"                /* XXX */
43 #include "opt_compat.h"
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
47 #include <sys/ioctl_compat.h>
48 #endif
49 #include <sys/proc.h>
50 #include <sys/tty.h>
51 #include <sys/conf.h>
52 #include <sys/fcntl.h>
53 #include <sys/poll.h>
54 #include <sys/kernel.h>
55 #include <sys/vnode.h>
56 #include <sys/signalvar.h>
57 #include <sys/malloc.h>
58 #include <sys/device.h>
59
60 MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
61
62 static void ptsstart __P((struct tty *tp));
63 static void ptsstop __P((struct tty *tp, int rw));
64 static void ptcwakeup __P((struct tty *tp, int flag));
65 static void ptyinit __P((int n));
66
67 static  d_open_t        ptsopen;
68 static  d_close_t       ptsclose;
69 static  d_read_t        ptsread;
70 static  d_write_t       ptswrite;
71 static  d_ioctl_t       ptyioctl;
72 static  d_open_t        ptcopen;
73 static  d_close_t       ptcclose;
74 static  d_read_t        ptcread;
75 static  d_write_t       ptcwrite;
76 static  d_poll_t        ptcpoll;
77
78 #define CDEV_MAJOR_S    5
79 static struct cdevsw pts_cdevsw = {
80         /* name */      "pts",
81         /* maj */       CDEV_MAJOR_S,
82         /* flags */     D_TTY | D_KQFILTER,
83         /* port */      NULL,
84         /* autoq */     0,
85
86         /* open */      ptsopen,
87         /* close */     ptsclose,
88         /* read */      ptsread,
89         /* write */     ptswrite,
90         /* ioctl */     ptyioctl,
91         /* poll */      ttypoll,
92         /* mmap */      nommap,
93         /* strategy */  nostrategy,
94         /* dump */      nodump,
95         /* psize */     nopsize,
96         /* kqfilter */  ttykqfilter
97 };
98
99 #define CDEV_MAJOR_C    6
100 static struct cdevsw ptc_cdevsw = {
101         /* name */      "ptc",
102         /* maj */       CDEV_MAJOR_C,
103         /* flags */     D_TTY | D_KQFILTER | D_MASTER,
104         /* port */      NULL,
105         /* autoq */     0,
106
107         /* open */      ptcopen,
108         /* close */     ptcclose,
109         /* read */      ptcread,
110         /* write */     ptcwrite,
111         /* ioctl */     ptyioctl,
112         /* poll */      ptcpoll,
113         /* mmap */      nommap,
114         /* strategy */  nostrategy,
115         /* dump */      nodump,
116         /* psize */     nopsize,
117         /* kqfilter */  ttykqfilter
118 };
119
120 #define BUFSIZ 100              /* Chunk size iomoved to/from user */
121
122 struct  pt_ioctl {
123         int     pt_flags;
124         struct  selinfo pt_selr, pt_selw;
125         u_char  pt_send;
126         u_char  pt_ucntl;
127         struct tty pt_tty;
128         dev_t   devs, devc;
129         struct  prison *pt_prison;
130 };
131
132 #define PF_PKT          0x08            /* packet mode */
133 #define PF_STOPPED      0x10            /* user told stopped */
134 #define PF_REMOTE       0x20            /* remote and flow controlled input */
135 #define PF_NOSTOP       0x40
136 #define PF_UCNTL        0x80            /* user control mode */
137
138 /*
139  * This function creates and initializes a pts/ptc pair
140  *
141  * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
142  * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
143  *
144  * XXX: define and add mapping of upper minor bits to allow more 
145  *      than 256 ptys.
146  */
147 static void
148 ptyinit(n)
149         int n;
150 {
151         dev_t devs, devc;
152         char *names = "pqrsPQRS";
153         struct pt_ioctl *pt;
154
155         /* For now we only map the lower 8 bits of the minor */
156         if (n & ~0xff)
157                 return;
158
159         pt = malloc(sizeof(*pt), M_PTY, M_WAITOK);
160         bzero(pt, sizeof(*pt));
161         pt->devs = devs = make_dev(&pts_cdevsw, n,
162             0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
163         pt->devc = devc = make_dev(&ptc_cdevsw, n,
164             0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
165
166         devs->si_drv1 = devc->si_drv1 = pt;
167         devs->si_tty = devc->si_tty = &pt->pt_tty;
168         pt->pt_tty.t_dev = devs;
169         ttyregister(&pt->pt_tty);
170 }
171
172 /*ARGSUSED*/
173 static  int
174 ptsopen(dev_t dev, int flag, int devtype, struct thread *td)
175 {
176         struct tty *tp;
177         int error;
178         int minr;
179         dev_t nextdev;
180         struct pt_ioctl *pti;
181         struct proc *p;
182
183         p = td->td_proc;
184         KKASSERT(p != NULL);
185
186         /*
187          * XXX: Gross hack for DEVFS:
188          * XXX: DEVFS is no more, should this be removed?
189          * If we openned this device, ensure we have the
190          * next one too, so people can open it.
191          */
192         minr = lminor(dev);
193         if (minr < 255) {
194                 nextdev = makedev(major(dev), minr + 1);
195                 if (!nextdev->si_drv1) {
196                         ptyinit(minr + 1);
197                 }
198         }
199         if (!dev->si_drv1)
200                 ptyinit(minor(dev));
201         if (!dev->si_drv1)
202                 return(ENXIO);  
203         pti = dev->si_drv1;
204         tp = dev->si_tty;
205         if ((tp->t_state & TS_ISOPEN) == 0) {
206                 ttychars(tp);           /* Set up default chars */
207                 tp->t_iflag = TTYDEF_IFLAG;
208                 tp->t_oflag = TTYDEF_OFLAG;
209                 tp->t_lflag = TTYDEF_LFLAG;
210                 tp->t_cflag = TTYDEF_CFLAG;
211                 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
212         } else if (tp->t_state & TS_XCLUDE && suser(td)) {
213                 return (EBUSY);
214         } else if (pti->pt_prison != p->p_ucred->cr_prison) {
215                 return (EBUSY);
216         }
217         if (tp->t_oproc)                        /* Ctrlr still around. */
218                 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
219         while ((tp->t_state & TS_CARR_ON) == 0) {
220                 if (flag&FNONBLOCK)
221                         break;
222                 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0);
223                 if (error)
224                         return (error);
225         }
226         error = (*linesw[tp->t_line].l_open)(dev, tp);
227         if (error == 0)
228                 ptcwakeup(tp, FREAD|FWRITE);
229         return (error);
230 }
231
232 static  int
233 ptsclose(dev, flag, mode, td)
234         dev_t dev;
235         int flag, mode;
236         struct thread *td;
237 {
238         struct tty *tp;
239         int err;
240
241         tp = dev->si_tty;
242         err = (*linesw[tp->t_line].l_close)(tp, flag);
243         ptsstop(tp, FREAD|FWRITE);
244         (void) ttyclose(tp);
245         return (err);
246 }
247
248 static  int
249 ptsread(dev, uio, flag)
250         dev_t dev;
251         struct uio *uio;
252         int flag;
253 {
254         struct proc *p = curproc;
255         struct tty *tp = dev->si_tty;
256         struct pt_ioctl *pti = dev->si_drv1;
257         int error = 0;
258
259 again:
260         if (pti->pt_flags & PF_REMOTE) {
261                 while (isbackground(p, tp)) {
262                         if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
263                             SIGISMEMBER(p->p_sigmask, SIGTTIN) ||
264                             p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT)
265                                 return (EIO);
266                         pgsignal(p->p_pgrp, SIGTTIN, 1);
267                         error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0);
268                         if (error)
269                                 return (error);
270                 }
271                 if (tp->t_canq.c_cc == 0) {
272                         if (flag & IO_NDELAY)
273                                 return (EWOULDBLOCK);
274                         error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH,
275                                          "ptsin", 0);
276                         if (error)
277                                 return (error);
278                         goto again;
279                 }
280                 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
281                         if (ureadc(getc(&tp->t_canq), uio) < 0) {
282                                 error = EFAULT;
283                                 break;
284                         }
285                 if (tp->t_canq.c_cc == 1)
286                         (void) getc(&tp->t_canq);
287                 if (tp->t_canq.c_cc)
288                         return (error);
289         } else
290                 if (tp->t_oproc)
291                         error = (*linesw[tp->t_line].l_read)(tp, uio, flag);
292         ptcwakeup(tp, FWRITE);
293         return (error);
294 }
295
296 /*
297  * Write to pseudo-tty.
298  * Wakeups of controlling tty will happen
299  * indirectly, when tty driver calls ptsstart.
300  */
301 static  int
302 ptswrite(dev, uio, flag)
303         dev_t dev;
304         struct uio *uio;
305         int flag;
306 {
307         struct tty *tp;
308
309         tp = dev->si_tty;
310         if (tp->t_oproc == 0)
311                 return (EIO);
312         return ((*linesw[tp->t_line].l_write)(tp, uio, flag));
313 }
314
315 /*
316  * Start output on pseudo-tty.
317  * Wake up process selecting or sleeping for input from controlling tty.
318  */
319 static void
320 ptsstart(tp)
321         struct tty *tp;
322 {
323         struct pt_ioctl *pti = tp->t_dev->si_drv1;
324
325         if (tp->t_state & TS_TTSTOP)
326                 return;
327         if (pti->pt_flags & PF_STOPPED) {
328                 pti->pt_flags &= ~PF_STOPPED;
329                 pti->pt_send = TIOCPKT_START;
330         }
331         ptcwakeup(tp, FREAD);
332 }
333
334 static void
335 ptcwakeup(tp, flag)
336         struct tty *tp;
337         int flag;
338 {
339         struct pt_ioctl *pti = tp->t_dev->si_drv1;
340
341         if (flag & FREAD) {
342                 selwakeup(&pti->pt_selr);
343                 wakeup(TSA_PTC_READ(tp));
344         }
345         if (flag & FWRITE) {
346                 selwakeup(&pti->pt_selw);
347                 wakeup(TSA_PTC_WRITE(tp));
348         }
349 }
350
351 static  int
352 ptcopen(dev, flag, devtype, td)
353         dev_t dev;
354         int flag, devtype;
355         struct thread *td;
356 {
357         struct tty *tp;
358         struct pt_ioctl *pti;
359
360         if (!dev->si_drv1)
361                 ptyinit(minor(dev));
362         if (!dev->si_drv1)
363                 return(ENXIO);  
364         tp = dev->si_tty;
365         if (tp->t_oproc)
366                 return (EIO);
367         KKASSERT(td->td_proc != NULL);
368         tp->t_oproc = ptsstart;
369         tp->t_stop = ptsstop;
370         (void)(*linesw[tp->t_line].l_modem)(tp, 1);
371         tp->t_lflag &= ~EXTPROC;
372         pti = dev->si_drv1;
373         pti->pt_prison = td->td_proc->p_ucred->cr_prison;
374         pti->pt_flags = 0;
375         pti->pt_send = 0;
376         pti->pt_ucntl = 0;
377         return (0);
378 }
379
380 static  int
381 ptcclose(dev, flags, fmt, td)
382         dev_t dev;
383         int flags;
384         int fmt;
385         struct thread *td;
386 {
387         struct tty *tp;
388
389         tp = dev->si_tty;
390         (void)(*linesw[tp->t_line].l_modem)(tp, 0);
391
392         /*
393          * XXX MDMBUF makes no sense for ptys but would inhibit the above
394          * l_modem().  CLOCAL makes sense but isn't supported.   Special
395          * l_modem()s that ignore carrier drop make no sense for ptys but
396          * may be in use because other parts of the line discipline make
397          * sense for ptys.  Recover by doing everything that a normal
398          * ttymodem() would have done except for sending a SIGHUP.
399          */
400         if (tp->t_state & TS_ISOPEN) {
401                 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
402                 tp->t_state |= TS_ZOMBIE;
403                 ttyflush(tp, FREAD | FWRITE);
404         }
405
406         tp->t_oproc = 0;                /* mark closed */
407         return (0);
408 }
409
410 static  int
411 ptcread(dev, uio, flag)
412         dev_t dev;
413         struct uio *uio;
414         int flag;
415 {
416         struct tty *tp = dev->si_tty;
417         struct pt_ioctl *pti = dev->si_drv1;
418         char buf[BUFSIZ];
419         int error = 0, cc;
420
421         /*
422          * We want to block until the slave
423          * is open, and there's something to read;
424          * but if we lost the slave or we're NBIO,
425          * then return the appropriate error instead.
426          */
427         for (;;) {
428                 if (tp->t_state&TS_ISOPEN) {
429                         if (pti->pt_flags&PF_PKT && pti->pt_send) {
430                                 error = ureadc((int)pti->pt_send, uio);
431                                 if (error)
432                                         return (error);
433                                 if (pti->pt_send & TIOCPKT_IOCTL) {
434                                         cc = min(uio->uio_resid,
435                                                 sizeof(tp->t_termios));
436                                         uiomove((caddr_t)&tp->t_termios, cc,
437                                                 uio);
438                                 }
439                                 pti->pt_send = 0;
440                                 return (0);
441                         }
442                         if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
443                                 error = ureadc((int)pti->pt_ucntl, uio);
444                                 if (error)
445                                         return (error);
446                                 pti->pt_ucntl = 0;
447                                 return (0);
448                         }
449                         if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
450                                 break;
451                 }
452                 if ((tp->t_state & TS_CONNECTED) == 0)
453                         return (0);     /* EOF */
454                 if (flag & IO_NDELAY)
455                         return (EWOULDBLOCK);
456                 error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0);
457                 if (error)
458                         return (error);
459         }
460         if (pti->pt_flags & (PF_PKT|PF_UCNTL))
461                 error = ureadc(0, uio);
462         while (uio->uio_resid > 0 && error == 0) {
463                 cc = q_to_b(&tp->t_outq, buf, min(uio->uio_resid, BUFSIZ));
464                 if (cc <= 0)
465                         break;
466                 error = uiomove(buf, cc, uio);
467         }
468         ttwwakeup(tp);
469         return (error);
470 }
471
472 static  void
473 ptsstop(tp, flush)
474         struct tty *tp;
475         int flush;
476 {
477         struct pt_ioctl *pti = tp->t_dev->si_drv1;
478         int flag;
479
480         /* note: FLUSHREAD and FLUSHWRITE already ok */
481         if (flush == 0) {
482                 flush = TIOCPKT_STOP;
483                 pti->pt_flags |= PF_STOPPED;
484         } else
485                 pti->pt_flags &= ~PF_STOPPED;
486         pti->pt_send |= flush;
487         /* change of perspective */
488         flag = 0;
489         if (flush & FREAD)
490                 flag |= FWRITE;
491         if (flush & FWRITE)
492                 flag |= FREAD;
493         ptcwakeup(tp, flag);
494 }
495
496 static  int
497 ptcpoll(dev, events, td)
498         dev_t dev;
499         int events;
500         struct thread *td;
501 {
502         struct tty *tp = dev->si_tty;
503         struct pt_ioctl *pti = dev->si_drv1;
504         int revents = 0;
505         int s;
506
507         if ((tp->t_state & TS_CONNECTED) == 0)
508                 return (seltrue(dev, events, td) | POLLHUP);
509
510         /*
511          * Need to block timeouts (ttrstart).
512          */
513         s = spltty();
514
515         if (events & (POLLIN | POLLRDNORM))
516                 if ((tp->t_state & TS_ISOPEN) &&
517                     ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
518                      ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
519                      ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
520                         revents |= events & (POLLIN | POLLRDNORM);
521
522         if (events & (POLLOUT | POLLWRNORM))
523                 if (tp->t_state & TS_ISOPEN &&
524                     ((pti->pt_flags & PF_REMOTE) ?
525                      (tp->t_canq.c_cc == 0) : 
526                      ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
527                       (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
528                         revents |= events & (POLLOUT | POLLWRNORM);
529
530         if (events & POLLHUP)
531                 if ((tp->t_state & TS_CARR_ON) == 0)
532                         revents |= POLLHUP;
533
534         if (revents == 0) {
535                 if (events & (POLLIN | POLLRDNORM))
536                         selrecord(td, &pti->pt_selr);
537
538                 if (events & (POLLOUT | POLLWRNORM)) 
539                         selrecord(td, &pti->pt_selw);
540         }
541         splx(s);
542
543         return (revents);
544 }
545
546 static  int
547 ptcwrite(dev, uio, flag)
548         dev_t dev;
549         struct uio *uio;
550         int flag;
551 {
552         struct tty *tp = dev->si_tty;
553         u_char *cp = 0;
554         int cc = 0;
555         u_char locbuf[BUFSIZ];
556         int cnt = 0;
557         struct pt_ioctl *pti = dev->si_drv1;
558         int error = 0;
559
560 again:
561         if ((tp->t_state&TS_ISOPEN) == 0)
562                 goto block;
563         if (pti->pt_flags & PF_REMOTE) {
564                 if (tp->t_canq.c_cc)
565                         goto block;
566                 while ((uio->uio_resid > 0 || cc > 0) &&
567                        tp->t_canq.c_cc < TTYHOG - 1) {
568                         if (cc == 0) {
569                                 cc = min(uio->uio_resid, BUFSIZ);
570                                 cc = min(cc, TTYHOG - 1 - tp->t_canq.c_cc);
571                                 cp = locbuf;
572                                 error = uiomove((caddr_t)cp, cc, uio);
573                                 if (error)
574                                         return (error);
575                                 /* check again for safety */
576                                 if ((tp->t_state & TS_ISOPEN) == 0) {
577                                         /* adjust as usual */
578                                         uio->uio_resid += cc;
579                                         return (EIO);
580                                 }
581                         }
582                         if (cc > 0) {
583                                 cc = b_to_q((char *)cp, cc, &tp->t_canq);
584                                 /*
585                                  * XXX we don't guarantee that the canq size
586                                  * is >= TTYHOG, so the above b_to_q() may
587                                  * leave some bytes uncopied.  However, space
588                                  * is guaranteed for the null terminator if
589                                  * we don't fail here since (TTYHOG - 1) is
590                                  * not a multiple of CBSIZE.
591                                  */
592                                 if (cc > 0)
593                                         break;
594                         }
595                 }
596                 /* adjust for data copied in but not written */
597                 uio->uio_resid += cc;
598                 (void) putc(0, &tp->t_canq);
599                 ttwakeup(tp);
600                 wakeup(TSA_PTS_READ(tp));
601                 return (0);
602         }
603         while (uio->uio_resid > 0 || cc > 0) {
604                 if (cc == 0) {
605                         cc = min(uio->uio_resid, BUFSIZ);
606                         cp = locbuf;
607                         error = uiomove((caddr_t)cp, cc, uio);
608                         if (error)
609                                 return (error);
610                         /* check again for safety */
611                         if ((tp->t_state & TS_ISOPEN) == 0) {
612                                 /* adjust for data copied in but not written */
613                                 uio->uio_resid += cc;
614                                 return (EIO);
615                         }
616                 }
617                 while (cc > 0) {
618                         if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
619                            (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
620                                 wakeup(TSA_HUP_OR_INPUT(tp));
621                                 goto block;
622                         }
623                         (*linesw[tp->t_line].l_rint)(*cp++, tp);
624                         cnt++;
625                         cc--;
626                 }
627                 cc = 0;
628         }
629         return (0);
630 block:
631         /*
632          * Come here to wait for slave to open, for space
633          * in outq, or space in rawq, or an empty canq.
634          */
635         if ((tp->t_state & TS_CONNECTED) == 0) {
636                 /* adjust for data copied in but not written */
637                 uio->uio_resid += cc;
638                 return (EIO);
639         }
640         if (flag & IO_NDELAY) {
641                 /* adjust for data copied in but not written */
642                 uio->uio_resid += cc;
643                 if (cnt == 0)
644                         return (EWOULDBLOCK);
645                 return (0);
646         }
647         error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0);
648         if (error) {
649                 /* adjust for data copied in but not written */
650                 uio->uio_resid += cc;
651                 return (error);
652         }
653         goto again;
654 }
655
656 /*ARGSUSED*/
657 static  int
658 ptyioctl(dev, cmd, data, flag, td)
659         dev_t dev;
660         u_long cmd;
661         caddr_t data;
662         int flag;
663         struct thread *td;
664 {
665         struct tty *tp = dev->si_tty;
666         struct pt_ioctl *pti = dev->si_drv1;
667         u_char *cc = tp->t_cc;
668         int stop, error;
669
670         if (dev_dflags(dev) & D_MASTER) {
671                 switch (cmd) {
672
673                 case TIOCGPGRP:
674                         /*
675                          * We avoid calling ttioctl on the controller since,
676                          * in that case, tp must be the controlling terminal.
677                          */
678                         *(int *)data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
679                         return (0);
680
681                 case TIOCPKT:
682                         if (*(int *)data) {
683                                 if (pti->pt_flags & PF_UCNTL)
684                                         return (EINVAL);
685                                 pti->pt_flags |= PF_PKT;
686                         } else
687                                 pti->pt_flags &= ~PF_PKT;
688                         return (0);
689
690                 case TIOCUCNTL:
691                         if (*(int *)data) {
692                                 if (pti->pt_flags & PF_PKT)
693                                         return (EINVAL);
694                                 pti->pt_flags |= PF_UCNTL;
695                         } else
696                                 pti->pt_flags &= ~PF_UCNTL;
697                         return (0);
698
699                 case TIOCREMOTE:
700                         if (*(int *)data)
701                                 pti->pt_flags |= PF_REMOTE;
702                         else
703                                 pti->pt_flags &= ~PF_REMOTE;
704                         ttyflush(tp, FREAD|FWRITE);
705                         return (0);
706                 }
707
708                 /*
709                  * The rest of the ioctls shouldn't be called until 
710                  * the slave is open.
711                  */
712                 if ((tp->t_state & TS_ISOPEN) == 0)
713                         return (EAGAIN);
714
715                 switch (cmd) {
716 #ifdef COMPAT_43
717                 case TIOCSETP:
718                 case TIOCSETN:
719 #endif
720                 case TIOCSETD:
721                 case TIOCSETA:
722                 case TIOCSETAW:
723                 case TIOCSETAF:
724                         /*
725                          * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
726                          * ttywflush(tp) will hang if there are characters in
727                          * the outq.
728                          */
729                         ndflush(&tp->t_outq, tp->t_outq.c_cc);
730                         break;
731
732                 case TIOCSIG:
733                         if (*(unsigned int *)data >= NSIG ||
734                             *(unsigned int *)data == 0)
735                                 return(EINVAL);
736                         if ((tp->t_lflag&NOFLSH) == 0)
737                                 ttyflush(tp, FREAD|FWRITE);
738                         pgsignal(tp->t_pgrp, *(unsigned int *)data, 1);
739                         if ((*(unsigned int *)data == SIGINFO) &&
740                             ((tp->t_lflag&NOKERNINFO) == 0))
741                                 ttyinfo(tp);
742                         return(0);
743                 }
744         }
745         if (cmd == TIOCEXT) {
746                 /*
747                  * When the EXTPROC bit is being toggled, we need
748                  * to send an TIOCPKT_IOCTL if the packet driver
749                  * is turned on.
750                  */
751                 if (*(int *)data) {
752                         if (pti->pt_flags & PF_PKT) {
753                                 pti->pt_send |= TIOCPKT_IOCTL;
754                                 ptcwakeup(tp, FREAD);
755                         }
756                         tp->t_lflag |= EXTPROC;
757                 } else {
758                         if ((tp->t_lflag & EXTPROC) &&
759                             (pti->pt_flags & PF_PKT)) {
760                                 pti->pt_send |= TIOCPKT_IOCTL;
761                                 ptcwakeup(tp, FREAD);
762                         }
763                         tp->t_lflag &= ~EXTPROC;
764                 }
765                 return(0);
766         }
767         error = (*linesw[tp->t_line].l_ioctl)(tp, cmd, data, flag, td);
768         if (error == ENOIOCTL)
769                  error = ttioctl(tp, cmd, data, flag);
770         if (error == ENOIOCTL) {
771                 if (pti->pt_flags & PF_UCNTL &&
772                     (cmd & ~0xff) == UIOCCMD(0)) {
773                         if (cmd & 0xff) {
774                                 pti->pt_ucntl = (u_char)cmd;
775                                 ptcwakeup(tp, FREAD);
776                         }
777                         return (0);
778                 }
779                 error = ENOTTY;
780         }
781         /*
782          * If external processing and packet mode send ioctl packet.
783          */
784         if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
785                 switch(cmd) {
786                 case TIOCSETA:
787                 case TIOCSETAW:
788                 case TIOCSETAF:
789 #ifdef COMPAT_43
790                 case TIOCSETP:
791                 case TIOCSETN:
792 #endif
793 #if defined(COMPAT_43) || defined(COMPAT_SUNOS)
794                 case TIOCSETC:
795                 case TIOCSLTC:
796                 case TIOCLBIS:
797                 case TIOCLBIC:
798                 case TIOCLSET:
799 #endif
800                         pti->pt_send |= TIOCPKT_IOCTL;
801                         ptcwakeup(tp, FREAD);
802                 default:
803                         break;
804                 }
805         }
806         stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
807                 && CCEQ(cc[VSTART], CTRL('q'));
808         if (pti->pt_flags & PF_NOSTOP) {
809                 if (stop) {
810                         pti->pt_send &= ~TIOCPKT_NOSTOP;
811                         pti->pt_send |= TIOCPKT_DOSTOP;
812                         pti->pt_flags &= ~PF_NOSTOP;
813                         ptcwakeup(tp, FREAD);
814                 }
815         } else {
816                 if (!stop) {
817                         pti->pt_send &= ~TIOCPKT_DOSTOP;
818                         pti->pt_send |= TIOCPKT_NOSTOP;
819                         pti->pt_flags |= PF_NOSTOP;
820                         ptcwakeup(tp, FREAD);
821                 }
822         }
823         return (error);
824 }
825
826
827 static void ptc_drvinit __P((void *unused));
828
829 static void
830 ptc_drvinit(unused)
831         void *unused;
832 {
833         cdevsw_add(&pts_cdevsw);
834         cdevsw_add(&ptc_cdevsw);
835         /* XXX: Gross hack for DEVFS */
836         /* XXX: DEVFS is no more, should this be removed? */
837         ptyinit(0);
838 }
839
840 SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)