AMD64 - Refactor uio_resid and size_t assumptions.
[dragonfly.git] / sys / kern / tty_pty.c
CommitLineData
984263bc
MD
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 $
8683f632 35 * $DragonFly: src/sys/kern/tty_pty.c,v 1.21 2008/08/13 10:29:38 swildner Exp $
984263bc
MD
36 */
37
38/*
39 * Pseudo-teletype Driver
fef8985e 40 * (Actually two drivers, requiring two dev_ops structures)
984263bc 41 */
1f2de5d4 42#include "use_pty.h" /* XXX */
984263bc 43#include "opt_compat.h"
1f2de5d4 44
984263bc
MD
45#include <sys/param.h>
46#include <sys/systm.h>
47#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
48#include <sys/ioctl_compat.h>
49#endif
50#include <sys/proc.h>
895c1f85 51#include <sys/priv.h>
984263bc
MD
52#include <sys/tty.h>
53#include <sys/conf.h>
54#include <sys/fcntl.h>
55#include <sys/poll.h>
56#include <sys/kernel.h>
57#include <sys/vnode.h>
58#include <sys/signalvar.h>
59#include <sys/malloc.h>
335dda38 60#include <sys/device.h>
e43a034f 61#include <sys/thread2.h>
2c1e28dd 62#include <sys/devfs.h>
cd29885a
MD
63
64DEVFS_DECLARE_CLONE_BITMAP(pty);
65DEVFS_DECLARE_CLONE_BITMAP(pts);
984263bc
MD
66
67MALLOC_DEFINE(M_PTY, "ptys", "pty data structures");
68
402ed7e1
RG
69static void ptsstart (struct tty *tp);
70static void ptsstop (struct tty *tp, int rw);
71static void ptcwakeup (struct tty *tp, int flag);
72static void ptyinit (int n);
984263bc
MD
73
74static d_open_t ptsopen;
75static d_close_t ptsclose;
76static d_read_t ptsread;
77static d_write_t ptswrite;
78static d_ioctl_t ptyioctl;
79static d_open_t ptcopen;
80static d_close_t ptcclose;
81static d_read_t ptcread;
82static d_write_t ptcwrite;
83static d_poll_t ptcpoll;
5d40c1cd 84#if 0
cd29885a 85static d_clone_t ptyclone;
5d40c1cd 86#endif
984263bc
MD
87
88#define CDEV_MAJOR_S 5
fef8985e
MD
89static struct dev_ops pts_ops = {
90 { "pts", CDEV_MAJOR_S, D_TTY | D_KQFILTER },
91 .d_open = ptsopen,
92 .d_close = ptsclose,
93 .d_read = ptsread,
94 .d_write = ptswrite,
95 .d_ioctl = ptyioctl,
96 .d_poll = ttypoll,
a32446b7
MD
97 .d_kqfilter = ttykqfilter,
98 .d_revoke = ttyrevoke
984263bc
MD
99};
100
101#define CDEV_MAJOR_C 6
fef8985e
MD
102static struct dev_ops ptc_ops = {
103 { "ptc", CDEV_MAJOR_C, D_TTY | D_KQFILTER | D_MASTER },
104 .d_open = ptcopen,
105 .d_close = ptcclose,
106 .d_read = ptcread,
107 .d_write = ptcwrite,
108 .d_ioctl = ptyioctl,
109 .d_poll = ptcpoll,
a32446b7
MD
110 .d_kqfilter = ttykqfilter,
111 .d_revoke = ttyrevoke
984263bc
MD
112};
113
114#define BUFSIZ 100 /* Chunk size iomoved to/from user */
115
116struct pt_ioctl {
117 int pt_flags;
118 struct selinfo pt_selr, pt_selw;
119 u_char pt_send;
120 u_char pt_ucntl;
121 struct tty pt_tty;
b13267a5 122 cdev_t devs, devc;
984263bc 123 struct prison *pt_prison;
cd29885a 124 short ref_count;
984263bc
MD
125};
126
127#define PF_PKT 0x08 /* packet mode */
128#define PF_STOPPED 0x10 /* user told stopped */
129#define PF_REMOTE 0x20 /* remote and flow controlled input */
130#define PF_NOSTOP 0x40
131#define PF_UCNTL 0x80 /* user control mode */
132
133/*
134 * This function creates and initializes a pts/ptc pair
135 *
136 * pts == /dev/tty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
137 * ptc == /dev/pty[pqrsPQRS][0123456789abcdefghijklmnopqrstuv]
138 *
139 * XXX: define and add mapping of upper minor bits to allow more
140 * than 256 ptys.
141 */
142static void
c972a82f 143ptyinit(int n)
984263bc 144{
b13267a5 145 cdev_t devs, devc;
984263bc
MD
146 char *names = "pqrsPQRS";
147 struct pt_ioctl *pt;
148
149 /* For now we only map the lower 8 bits of the minor */
150 if (n & ~0xff)
151 return;
152
e7b4468c 153 pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
fef8985e 154 pt->devs = devs = make_dev(&pts_ops, n,
984263bc 155 0, 0, 0666, "tty%c%r", names[n / 32], n % 32);
fef8985e 156 pt->devc = devc = make_dev(&ptc_ops, n,
984263bc
MD
157 0, 0, 0666, "pty%c%r", names[n / 32], n % 32);
158
159 devs->si_drv1 = devc->si_drv1 = pt;
160 devs->si_tty = devc->si_tty = &pt->pt_tty;
4062d050
MD
161 devs->si_flags |= SI_OVERRIDE; /* uid, gid, perms from dev */
162 devc->si_flags |= SI_OVERRIDE; /* uid, gid, perms from dev */
984263bc
MD
163 pt->pt_tty.t_dev = devs;
164 ttyregister(&pt->pt_tty);
165}
166
5d40c1cd 167#if 0
cd29885a
MD
168static int
169ptyclone(struct dev_clone_args *ap)
170{
171 int unit;
172 struct pt_ioctl *pt;
173
174 unit = devfs_clone_bitmap_get(&DEVFS_CLONE_BITMAP(pty), 256);
175
176 if (unit < 0)
177 return 1;
178
179 pt = kmalloc(sizeof(*pt), M_PTY, M_WAITOK | M_ZERO);
180 pt->ref_count++;
181 pt->devc = ap->a_dev = make_only_dev(&ptc_ops, unit, ap->a_cred->cr_ruid, 0, 0600, "ptm/%d", unit);
182 pt->devs = make_dev(&pts_ops, unit, ap->a_cred->cr_ruid, 0, 0600, "pts/%d", unit);
183
184 //reference_dev(pt->devc);
185 //reference_dev(pt->devs);
186
187 pt->devs->si_drv1 = pt->devc->si_drv1 = pt;
188 pt->devs->si_tty = pt->devc->si_tty = &pt->pt_tty;
189 pt->pt_tty.t_dev = pt->devs;
190 ttyregister(&pt->pt_tty);
191
192 return 0;
193}
5d40c1cd 194#endif
cd29885a 195
984263bc
MD
196/*ARGSUSED*/
197static int
fef8985e 198ptsopen(struct dev_open_args *ap)
984263bc 199{
b13267a5 200 cdev_t dev = ap->a_head.a_dev;
1fd87d54 201 struct tty *tp;
984263bc 202 int error;
984263bc
MD
203 struct pt_ioctl *pti;
204
984263bc
MD
205 if (!dev->si_drv1)
206 ptyinit(minor(dev));
207 if (!dev->si_drv1)
cd29885a 208 return(ENXIO);
984263bc
MD
209 pti = dev->si_drv1;
210 tp = dev->si_tty;
211 if ((tp->t_state & TS_ISOPEN) == 0) {
212 ttychars(tp); /* Set up default chars */
213 tp->t_iflag = TTYDEF_IFLAG;
214 tp->t_oflag = TTYDEF_OFLAG;
215 tp->t_lflag = TTYDEF_LFLAG;
216 tp->t_cflag = TTYDEF_CFLAG;
217 tp->t_ispeed = tp->t_ospeed = TTYDEF_SPEED;
895c1f85 218 } else if ((tp->t_state & TS_XCLUDE) && priv_check_cred(ap->a_cred, PRIV_ROOT, 0)) {
984263bc 219 return (EBUSY);
fef8985e 220 } else if (pti->pt_prison != ap->a_cred->cr_prison) {
984263bc
MD
221 return (EBUSY);
222 }
223 if (tp->t_oproc) /* Ctrlr still around. */
224 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
225 while ((tp->t_state & TS_CARR_ON) == 0) {
fef8985e 226 if (ap->a_oflags & FNONBLOCK)
984263bc 227 break;
377d4740 228 error = ttysleep(tp, TSA_CARR_ON(tp), PCATCH, "ptsopn", 0);
984263bc
MD
229 if (error)
230 return (error);
231 }
232 error = (*linesw[tp->t_line].l_open)(dev, tp);
233 if (error == 0)
234 ptcwakeup(tp, FREAD|FWRITE);
cd29885a
MD
235
236#if 0
237 /* unix98 pty stuff */
238 if ((!error) && (!memcmp(dev->si_name, "pts/", 4))) {
239 ((struct pt_ioctl *)dev->si_drv1)->ref_count++;
240 //reference_dev(dev);
241 //reference_dev(((struct pt_ioctl *)dev->si_drv1)->devc);
242 //devfs_clone_bitmap_set(&DEVFS_CLONE_BITMAP(pts), dev->si_uminor-300);
243 }
244#endif
245
984263bc
MD
246 return (error);
247}
248
249static int
fef8985e 250ptsclose(struct dev_close_args *ap)
984263bc 251{
b13267a5 252 cdev_t dev = ap->a_head.a_dev;
1fd87d54 253 struct tty *tp;
984263bc 254 int err;
cd29885a
MD
255#if 0
256 /* unix98 pty stuff */
257 if (!memcmp(dev->si_name, "pts/", 4)) {
258 if (--((struct pt_ioctl *)dev->si_drv1)->ref_count == 0) {
259 kfree(dev->si_drv1, M_PTY);
260 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(pty), dev->si_uminor);
261 destroy_dev(dev);
262 }
263 }
264#endif
984263bc 265 tp = dev->si_tty;
fef8985e 266 err = (*linesw[tp->t_line].l_close)(tp, ap->a_fflag);
984263bc
MD
267 ptsstop(tp, FREAD|FWRITE);
268 (void) ttyclose(tp);
269 return (err);
270}
271
272static int
fef8985e 273ptsread(struct dev_read_args *ap)
984263bc 274{
b13267a5 275 cdev_t dev = ap->a_head.a_dev;
984263bc 276 struct proc *p = curproc;
1fd87d54
RG
277 struct tty *tp = dev->si_tty;
278 struct pt_ioctl *pti = dev->si_drv1;
08f2f1bb
SS
279 struct lwp *lp;
280
984263bc
MD
281 int error = 0;
282
08f2f1bb
SS
283 lp = curthread->td_lwp;
284
984263bc
MD
285again:
286 if (pti->pt_flags & PF_REMOTE) {
287 while (isbackground(p, tp)) {
288 if (SIGISMEMBER(p->p_sigignore, SIGTTIN) ||
08f2f1bb 289 SIGISMEMBER(lp->lwp_sigmask, SIGTTIN) ||
984263bc
MD
290 p->p_pgrp->pg_jobc == 0 || p->p_flag & P_PPWAIT)
291 return (EIO);
292 pgsignal(p->p_pgrp, SIGTTIN, 1);
377d4740 293 error = ttysleep(tp, &lbolt, PCATCH, "ptsbg", 0);
984263bc
MD
294 if (error)
295 return (error);
296 }
297 if (tp->t_canq.c_cc == 0) {
fef8985e 298 if (ap->a_ioflag & IO_NDELAY)
984263bc 299 return (EWOULDBLOCK);
377d4740 300 error = ttysleep(tp, TSA_PTS_READ(tp), PCATCH,
984263bc
MD
301 "ptsin", 0);
302 if (error)
303 return (error);
304 goto again;
305 }
fef8985e 306 while (tp->t_canq.c_cc > 1 && ap->a_uio->uio_resid > 0)
0ced1954 307 if (ureadc(clist_getc(&tp->t_canq), ap->a_uio) < 0) {
984263bc
MD
308 error = EFAULT;
309 break;
310 }
311 if (tp->t_canq.c_cc == 1)
0ced1954 312 clist_getc(&tp->t_canq);
984263bc
MD
313 if (tp->t_canq.c_cc)
314 return (error);
315 } else
316 if (tp->t_oproc)
fef8985e 317 error = (*linesw[tp->t_line].l_read)(tp, ap->a_uio, ap->a_ioflag);
984263bc
MD
318 ptcwakeup(tp, FWRITE);
319 return (error);
320}
321
322/*
323 * Write to pseudo-tty.
324 * Wakeups of controlling tty will happen
325 * indirectly, when tty driver calls ptsstart.
326 */
327static int
fef8985e 328ptswrite(struct dev_write_args *ap)
984263bc 329{
b13267a5 330 cdev_t dev = ap->a_head.a_dev;
1fd87d54 331 struct tty *tp;
984263bc
MD
332
333 tp = dev->si_tty;
334 if (tp->t_oproc == 0)
335 return (EIO);
fef8985e 336 return ((*linesw[tp->t_line].l_write)(tp, ap->a_uio, ap->a_ioflag));
984263bc
MD
337}
338
339/*
340 * Start output on pseudo-tty.
341 * Wake up process selecting or sleeping for input from controlling tty.
342 */
343static void
c972a82f 344ptsstart(struct tty *tp)
984263bc 345{
1fd87d54 346 struct pt_ioctl *pti = tp->t_dev->si_drv1;
984263bc
MD
347
348 if (tp->t_state & TS_TTSTOP)
349 return;
350 if (pti->pt_flags & PF_STOPPED) {
351 pti->pt_flags &= ~PF_STOPPED;
352 pti->pt_send = TIOCPKT_START;
353 }
354 ptcwakeup(tp, FREAD);
355}
356
357static void
c972a82f 358ptcwakeup(struct tty *tp, int flag)
984263bc
MD
359{
360 struct pt_ioctl *pti = tp->t_dev->si_drv1;
361
362 if (flag & FREAD) {
363 selwakeup(&pti->pt_selr);
364 wakeup(TSA_PTC_READ(tp));
365 }
366 if (flag & FWRITE) {
367 selwakeup(&pti->pt_selw);
368 wakeup(TSA_PTC_WRITE(tp));
369 }
370}
371
372static int
fef8985e 373ptcopen(struct dev_open_args *ap)
984263bc 374{
b13267a5 375 cdev_t dev = ap->a_head.a_dev;
1fd87d54 376 struct tty *tp;
984263bc
MD
377 struct pt_ioctl *pti;
378
379 if (!dev->si_drv1)
380 ptyinit(minor(dev));
381 if (!dev->si_drv1)
382 return(ENXIO);
4062d050
MD
383 pti = dev->si_drv1;
384 if (pti->pt_prison && pti->pt_prison != ap->a_cred->cr_prison)
385 return(EBUSY);
984263bc
MD
386 tp = dev->si_tty;
387 if (tp->t_oproc)
388 return (EIO);
389 tp->t_oproc = ptsstart;
390 tp->t_stop = ptsstop;
391 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
392 tp->t_lflag &= ~EXTPROC;
fef8985e 393 pti->pt_prison = ap->a_cred->cr_prison;
984263bc
MD
394 pti->pt_flags = 0;
395 pti->pt_send = 0;
396 pti->pt_ucntl = 0;
4062d050 397
cd65363e 398 pti->devs->si_uid = ap->a_cred->cr_uid;
4062d050
MD
399 pti->devs->si_gid = 0;
400 pti->devs->si_perms = 0600;
401 pti->devc->si_uid = ap->a_cred->cr_uid;
402 pti->devc->si_gid = 0;
403 pti->devc->si_perms = 0600;
404
984263bc
MD
405 return (0);
406}
407
408static int
fef8985e 409ptcclose(struct dev_close_args *ap)
984263bc 410{
b13267a5 411 cdev_t dev = ap->a_head.a_dev;
1fd87d54 412 struct tty *tp;
4062d050 413 struct pt_ioctl *pti;
984263bc
MD
414
415 tp = dev->si_tty;
416 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
417
418 /*
419 * XXX MDMBUF makes no sense for ptys but would inhibit the above
420 * l_modem(). CLOCAL makes sense but isn't supported. Special
421 * l_modem()s that ignore carrier drop make no sense for ptys but
422 * may be in use because other parts of the line discipline make
423 * sense for ptys. Recover by doing everything that a normal
424 * ttymodem() would have done except for sending a SIGHUP.
425 */
426 if (tp->t_state & TS_ISOPEN) {
427 tp->t_state &= ~(TS_CARR_ON | TS_CONNECTED);
428 tp->t_state |= TS_ZOMBIE;
429 ttyflush(tp, FREAD | FWRITE);
430 }
984263bc 431 tp->t_oproc = 0; /* mark closed */
4062d050
MD
432
433 pti = dev->si_drv1;
434 pti->pt_prison = NULL;
435 pti->devs->si_uid = 0;
436 pti->devs->si_gid = 0;
437 pti->devs->si_perms = 0666;
438 pti->devc->si_uid = 0;
439 pti->devc->si_gid = 0;
440 pti->devc->si_perms = 0666;
441
cd29885a
MD
442#if 0
443 if (!memcmp(dev->si_name, "ptm/", 4)) {
444 ((struct pt_ioctl *)dev->si_drv1)->devc = NULL;
445 if (--((struct pt_ioctl *)dev->si_drv1)->ref_count == 0) {
446 kfree(dev->si_drv1, M_PTY);
447 devfs_clone_bitmap_put(&DEVFS_CLONE_BITMAP(pty), dev->si_uminor);
448 }
449 //release_dev(dev);
450 //release_dev(((struct pt_ioctl *)dev->si_drv1)->devs);
451 }
452#endif
984263bc
MD
453 return (0);
454}
455
456static int
fef8985e 457ptcread(struct dev_read_args *ap)
984263bc 458{
b13267a5 459 cdev_t dev = ap->a_head.a_dev;
1fd87d54 460 struct tty *tp = dev->si_tty;
984263bc
MD
461 struct pt_ioctl *pti = dev->si_drv1;
462 char buf[BUFSIZ];
463 int error = 0, cc;
464
465 /*
466 * We want to block until the slave
467 * is open, and there's something to read;
468 * but if we lost the slave or we're NBIO,
469 * then return the appropriate error instead.
470 */
471 for (;;) {
472 if (tp->t_state&TS_ISOPEN) {
473 if (pti->pt_flags&PF_PKT && pti->pt_send) {
fef8985e 474 error = ureadc((int)pti->pt_send, ap->a_uio);
984263bc
MD
475 if (error)
476 return (error);
477 if (pti->pt_send & TIOCPKT_IOCTL) {
e54488bb
MD
478 cc = (int)szmin(ap->a_uio->uio_resid,
479 sizeof(tp->t_termios));
984263bc 480 uiomove((caddr_t)&tp->t_termios, cc,
fef8985e 481 ap->a_uio);
984263bc
MD
482 }
483 pti->pt_send = 0;
484 return (0);
485 }
486 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
fef8985e 487 error = ureadc((int)pti->pt_ucntl, ap->a_uio);
984263bc
MD
488 if (error)
489 return (error);
490 pti->pt_ucntl = 0;
491 return (0);
492 }
493 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
494 break;
495 }
496 if ((tp->t_state & TS_CONNECTED) == 0)
497 return (0); /* EOF */
fef8985e 498 if (ap->a_ioflag & IO_NDELAY)
984263bc 499 return (EWOULDBLOCK);
377d4740 500 error = tsleep(TSA_PTC_READ(tp), PCATCH, "ptcin", 0);
984263bc
MD
501 if (error)
502 return (error);
503 }
504 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
fef8985e
MD
505 error = ureadc(0, ap->a_uio);
506 while (ap->a_uio->uio_resid > 0 && error == 0) {
e54488bb
MD
507 cc = q_to_b(&tp->t_outq, buf,
508 (int)szmin(ap->a_uio->uio_resid, BUFSIZ));
984263bc
MD
509 if (cc <= 0)
510 break;
e54488bb 511 error = uiomove(buf, (size_t)cc, ap->a_uio);
984263bc
MD
512 }
513 ttwwakeup(tp);
514 return (error);
515}
516
517static void
c972a82f 518ptsstop(struct tty *tp, int flush)
984263bc
MD
519{
520 struct pt_ioctl *pti = tp->t_dev->si_drv1;
521 int flag;
522
523 /* note: FLUSHREAD and FLUSHWRITE already ok */
524 if (flush == 0) {
525 flush = TIOCPKT_STOP;
526 pti->pt_flags |= PF_STOPPED;
527 } else
528 pti->pt_flags &= ~PF_STOPPED;
529 pti->pt_send |= flush;
530 /* change of perspective */
531 flag = 0;
532 if (flush & FREAD)
533 flag |= FWRITE;
534 if (flush & FWRITE)
535 flag |= FREAD;
536 ptcwakeup(tp, flag);
537}
538
539static int
fef8985e 540ptcpoll(struct dev_poll_args *ap)
984263bc 541{
b13267a5 542 cdev_t dev = ap->a_head.a_dev;
1fd87d54 543 struct tty *tp = dev->si_tty;
984263bc
MD
544 struct pt_ioctl *pti = dev->si_drv1;
545 int revents = 0;
984263bc 546
fef8985e
MD
547 if ((tp->t_state & TS_CONNECTED) == 0) {
548 ap->a_events = seltrue(dev, ap->a_events) | POLLHUP;
549 return(0);
550 }
984263bc
MD
551
552 /*
553 * Need to block timeouts (ttrstart).
554 */
e43a034f 555 crit_enter();
984263bc 556
fef8985e 557 if (ap->a_events & (POLLIN | POLLRDNORM))
984263bc
MD
558 if ((tp->t_state & TS_ISOPEN) &&
559 ((tp->t_outq.c_cc && (tp->t_state & TS_TTSTOP) == 0) ||
560 ((pti->pt_flags & PF_PKT) && pti->pt_send) ||
561 ((pti->pt_flags & PF_UCNTL) && pti->pt_ucntl)))
fef8985e 562 revents |= ap->a_events & (POLLIN | POLLRDNORM);
984263bc 563
fef8985e 564 if (ap->a_events & (POLLOUT | POLLWRNORM))
984263bc
MD
565 if (tp->t_state & TS_ISOPEN &&
566 ((pti->pt_flags & PF_REMOTE) ?
567 (tp->t_canq.c_cc == 0) :
568 ((tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG - 2) ||
569 (tp->t_canq.c_cc == 0 && (tp->t_lflag & ICANON)))))
fef8985e 570 revents |= ap->a_events & (POLLOUT | POLLWRNORM);
984263bc 571
fef8985e 572 if (ap->a_events & POLLHUP)
984263bc
MD
573 if ((tp->t_state & TS_CARR_ON) == 0)
574 revents |= POLLHUP;
575
576 if (revents == 0) {
fef8985e
MD
577 if (ap->a_events & (POLLIN | POLLRDNORM))
578 selrecord(curthread, &pti->pt_selr);
984263bc 579
fef8985e
MD
580 if (ap->a_events & (POLLOUT | POLLWRNORM))
581 selrecord(curthread, &pti->pt_selw);
984263bc 582 }
e43a034f 583 crit_exit();
984263bc 584
fef8985e
MD
585 ap->a_events = revents;
586 return (0);
984263bc
MD
587}
588
589static int
fef8985e 590ptcwrite(struct dev_write_args *ap)
984263bc 591{
b13267a5 592 cdev_t dev = ap->a_head.a_dev;
1fd87d54
RG
593 struct tty *tp = dev->si_tty;
594 u_char *cp = 0;
595 int cc = 0;
984263bc
MD
596 u_char locbuf[BUFSIZ];
597 int cnt = 0;
598 struct pt_ioctl *pti = dev->si_drv1;
599 int error = 0;
600
601again:
602 if ((tp->t_state&TS_ISOPEN) == 0)
603 goto block;
604 if (pti->pt_flags & PF_REMOTE) {
605 if (tp->t_canq.c_cc)
606 goto block;
fef8985e 607 while ((ap->a_uio->uio_resid > 0 || cc > 0) &&
984263bc
MD
608 tp->t_canq.c_cc < TTYHOG - 1) {
609 if (cc == 0) {
e54488bb
MD
610 cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ);
611 cc = imin(cc, TTYHOG - 1 - tp->t_canq.c_cc);
984263bc 612 cp = locbuf;
e54488bb 613 error = uiomove(cp, (size_t)cc, ap->a_uio);
984263bc
MD
614 if (error)
615 return (error);
616 /* check again for safety */
617 if ((tp->t_state & TS_ISOPEN) == 0) {
618 /* adjust as usual */
fef8985e 619 ap->a_uio->uio_resid += cc;
984263bc
MD
620 return (EIO);
621 }
622 }
623 if (cc > 0) {
624 cc = b_to_q((char *)cp, cc, &tp->t_canq);
625 /*
626 * XXX we don't guarantee that the canq size
627 * is >= TTYHOG, so the above b_to_q() may
628 * leave some bytes uncopied. However, space
629 * is guaranteed for the null terminator if
630 * we don't fail here since (TTYHOG - 1) is
631 * not a multiple of CBSIZE.
632 */
633 if (cc > 0)
634 break;
635 }
636 }
637 /* adjust for data copied in but not written */
fef8985e 638 ap->a_uio->uio_resid += cc;
0ced1954 639 clist_putc(0, &tp->t_canq);
984263bc
MD
640 ttwakeup(tp);
641 wakeup(TSA_PTS_READ(tp));
642 return (0);
643 }
fef8985e 644 while (ap->a_uio->uio_resid > 0 || cc > 0) {
984263bc 645 if (cc == 0) {
e54488bb 646 cc = (int)szmin(ap->a_uio->uio_resid, BUFSIZ);
984263bc 647 cp = locbuf;
e54488bb 648 error = uiomove(cp, (size_t)cc, ap->a_uio);
984263bc
MD
649 if (error)
650 return (error);
651 /* check again for safety */
652 if ((tp->t_state & TS_ISOPEN) == 0) {
653 /* adjust for data copied in but not written */
fef8985e 654 ap->a_uio->uio_resid += cc;
984263bc
MD
655 return (EIO);
656 }
657 }
658 while (cc > 0) {
659 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
660 (tp->t_canq.c_cc > 0 || !(tp->t_lflag&ICANON))) {
661 wakeup(TSA_HUP_OR_INPUT(tp));
662 goto block;
663 }
664 (*linesw[tp->t_line].l_rint)(*cp++, tp);
665 cnt++;
666 cc--;
667 }
668 cc = 0;
669 }
670 return (0);
671block:
672 /*
673 * Come here to wait for slave to open, for space
674 * in outq, or space in rawq, or an empty canq.
675 */
676 if ((tp->t_state & TS_CONNECTED) == 0) {
677 /* adjust for data copied in but not written */
fef8985e 678 ap->a_uio->uio_resid += cc;
984263bc
MD
679 return (EIO);
680 }
fef8985e 681 if (ap->a_ioflag & IO_NDELAY) {
984263bc 682 /* adjust for data copied in but not written */
fef8985e 683 ap->a_uio->uio_resid += cc;
984263bc
MD
684 if (cnt == 0)
685 return (EWOULDBLOCK);
686 return (0);
687 }
377d4740 688 error = tsleep(TSA_PTC_WRITE(tp), PCATCH, "ptcout", 0);
984263bc
MD
689 if (error) {
690 /* adjust for data copied in but not written */
fef8985e 691 ap->a_uio->uio_resid += cc;
984263bc
MD
692 return (error);
693 }
694 goto again;
695}
696
697/*ARGSUSED*/
698static int
fef8985e 699ptyioctl(struct dev_ioctl_args *ap)
984263bc 700{
b13267a5 701 cdev_t dev = ap->a_head.a_dev;
1fd87d54
RG
702 struct tty *tp = dev->si_tty;
703 struct pt_ioctl *pti = dev->si_drv1;
704 u_char *cc = tp->t_cc;
984263bc
MD
705 int stop, error;
706
335dda38 707 if (dev_dflags(dev) & D_MASTER) {
fef8985e 708 switch (ap->a_cmd) {
984263bc
MD
709
710 case TIOCGPGRP:
711 /*
712 * We avoid calling ttioctl on the controller since,
713 * in that case, tp must be the controlling terminal.
714 */
fef8985e 715 *(int *)ap->a_data = tp->t_pgrp ? tp->t_pgrp->pg_id : 0;
984263bc
MD
716 return (0);
717
718 case TIOCPKT:
fef8985e 719 if (*(int *)ap->a_data) {
984263bc
MD
720 if (pti->pt_flags & PF_UCNTL)
721 return (EINVAL);
722 pti->pt_flags |= PF_PKT;
723 } else
724 pti->pt_flags &= ~PF_PKT;
725 return (0);
726
727 case TIOCUCNTL:
fef8985e 728 if (*(int *)ap->a_data) {
984263bc
MD
729 if (pti->pt_flags & PF_PKT)
730 return (EINVAL);
731 pti->pt_flags |= PF_UCNTL;
732 } else
733 pti->pt_flags &= ~PF_UCNTL;
734 return (0);
735
736 case TIOCREMOTE:
fef8985e 737 if (*(int *)ap->a_data)
984263bc
MD
738 pti->pt_flags |= PF_REMOTE;
739 else
740 pti->pt_flags &= ~PF_REMOTE;
741 ttyflush(tp, FREAD|FWRITE);
742 return (0);
743 }
744
745 /*
746 * The rest of the ioctls shouldn't be called until
747 * the slave is open.
748 */
749 if ((tp->t_state & TS_ISOPEN) == 0)
750 return (EAGAIN);
751
fef8985e 752 switch (ap->a_cmd) {
984263bc
MD
753#ifdef COMPAT_43
754 case TIOCSETP:
755 case TIOCSETN:
756#endif
757 case TIOCSETD:
758 case TIOCSETA:
759 case TIOCSETAW:
760 case TIOCSETAF:
761 /*
762 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
763 * ttywflush(tp) will hang if there are characters in
764 * the outq.
765 */
766 ndflush(&tp->t_outq, tp->t_outq.c_cc);
767 break;
768
769 case TIOCSIG:
fef8985e
MD
770 if (*(unsigned int *)ap->a_data >= NSIG ||
771 *(unsigned int *)ap->a_data == 0)
984263bc
MD
772 return(EINVAL);
773 if ((tp->t_lflag&NOFLSH) == 0)
774 ttyflush(tp, FREAD|FWRITE);
fef8985e
MD
775 pgsignal(tp->t_pgrp, *(unsigned int *)ap->a_data, 1);
776 if ((*(unsigned int *)ap->a_data == SIGINFO) &&
984263bc
MD
777 ((tp->t_lflag&NOKERNINFO) == 0))
778 ttyinfo(tp);
779 return(0);
780 }
781 }
fef8985e 782 if (ap->a_cmd == TIOCEXT) {
984263bc
MD
783 /*
784 * When the EXTPROC bit is being toggled, we need
785 * to send an TIOCPKT_IOCTL if the packet driver
786 * is turned on.
787 */
fef8985e 788 if (*(int *)ap->a_data) {
984263bc
MD
789 if (pti->pt_flags & PF_PKT) {
790 pti->pt_send |= TIOCPKT_IOCTL;
791 ptcwakeup(tp, FREAD);
792 }
793 tp->t_lflag |= EXTPROC;
794 } else {
795 if ((tp->t_lflag & EXTPROC) &&
796 (pti->pt_flags & PF_PKT)) {
797 pti->pt_send |= TIOCPKT_IOCTL;
798 ptcwakeup(tp, FREAD);
799 }
800 tp->t_lflag &= ~EXTPROC;
801 }
802 return(0);
803 }
fef8985e
MD
804 error = (*linesw[tp->t_line].l_ioctl)(tp, ap->a_cmd, ap->a_data,
805 ap->a_fflag, ap->a_cred);
984263bc 806 if (error == ENOIOCTL)
fef8985e 807 error = ttioctl(tp, ap->a_cmd, ap->a_data, ap->a_fflag);
984263bc
MD
808 if (error == ENOIOCTL) {
809 if (pti->pt_flags & PF_UCNTL &&
fef8985e
MD
810 (ap->a_cmd & ~0xff) == UIOCCMD(0)) {
811 if (ap->a_cmd & 0xff) {
812 pti->pt_ucntl = (u_char)ap->a_cmd;
984263bc
MD
813 ptcwakeup(tp, FREAD);
814 }
815 return (0);
816 }
817 error = ENOTTY;
818 }
819 /*
820 * If external processing and packet mode send ioctl packet.
821 */
822 if ((tp->t_lflag&EXTPROC) && (pti->pt_flags & PF_PKT)) {
fef8985e 823 switch(ap->a_cmd) {
984263bc
MD
824 case TIOCSETA:
825 case TIOCSETAW:
826 case TIOCSETAF:
827#ifdef COMPAT_43
828 case TIOCSETP:
829 case TIOCSETN:
830#endif
831#if defined(COMPAT_43) || defined(COMPAT_SUNOS)
832 case TIOCSETC:
833 case TIOCSLTC:
834 case TIOCLBIS:
835 case TIOCLBIC:
836 case TIOCLSET:
837#endif
838 pti->pt_send |= TIOCPKT_IOCTL;
839 ptcwakeup(tp, FREAD);
840 default:
841 break;
842 }
843 }
844 stop = (tp->t_iflag & IXON) && CCEQ(cc[VSTOP], CTRL('s'))
845 && CCEQ(cc[VSTART], CTRL('q'));
846 if (pti->pt_flags & PF_NOSTOP) {
847 if (stop) {
848 pti->pt_send &= ~TIOCPKT_NOSTOP;
849 pti->pt_send |= TIOCPKT_DOSTOP;
850 pti->pt_flags &= ~PF_NOSTOP;
851 ptcwakeup(tp, FREAD);
852 }
853 } else {
854 if (!stop) {
855 pti->pt_send &= ~TIOCPKT_DOSTOP;
856 pti->pt_send |= TIOCPKT_NOSTOP;
857 pti->pt_flags |= PF_NOSTOP;
858 ptcwakeup(tp, FREAD);
859 }
860 }
861 return (error);
862}
863
864
402ed7e1 865static void ptc_drvinit (void *unused);
984263bc
MD
866
867static void
c972a82f 868ptc_drvinit(void *unused)
984263bc 869{
cd29885a 870 int i;
cd29885a
MD
871
872 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(pty));
873 devfs_clone_bitmap_init(&DEVFS_CLONE_BITMAP(pts));
874
875#if 0
876 /* Unix98 pty stuff, leave out for now */
877 make_dev(&ptc_ops, 0, 0, 0, 0666, "ptmx");
878 devfs_clone_handler_add("ptmx", ptyclone);
879#endif
880 for (i = 0; i < 256; i++) {
881 ptyinit(i);
882 }
984263bc
MD
883}
884
885SYSINIT(ptcdev,SI_SUB_DRIVERS,SI_ORDER_MIDDLE+CDEV_MAJOR_C,ptc_drvinit,NULL)