print errno if init exec fails
[unix-history] / usr / src / sys / kern / tty_pty.c
CommitLineData
da7c5cc6 1/*
0880b18e 2 * Copyright (c) 1982, 1986 Regents of the University of California.
da7c5cc6
KM
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 *
0880b18e 6 * @(#)tty_pty.c 7.1 (Berkeley) %G%
da7c5cc6 7 */
be4367b3 8
45372428
MT
9/*
10 * Pseudo-teletype Driver
11 * (Actually two drivers, requiring two entries in 'cdevsw')
45372428 12 */
647d645f
MT
13#include "pty.h"
14
f12183e4 15#if NPTY > 0
94368568
JB
16#include "param.h"
17#include "systm.h"
18#include "ioctl.h"
19#include "tty.h"
20#include "dir.h"
21#include "user.h"
22#include "conf.h"
23#include "file.h"
24#include "proc.h"
25#include "uio.h"
26#include "kernel.h"
941944c9 27
b3c8737d 28#if NPTY == 1
5bb90914 29#undef NPTY
c91c01fe 30#define NPTY 32 /* crude XXX */
b3c8737d 31#endif
45372428 32
2bb0bef9 33#define BUFSIZ 100 /* Chunk size iomoved to/from user */
e1d74936 34
45372428 35/*
5bb90914
JB
36 * pts == /dev/tty[pqrs]?
37 * ptc == /dev/pty[pqrs]?
45372428 38 */
e1d74936
BJ
39struct tty pt_tty[NPTY];
40struct pt_ioctl {
1a954a11 41 int pt_flags;
1a954a11 42 struct proc *pt_selr, *pt_selw;
5bb90914
JB
43 u_char pt_send;
44 u_char pt_ucntl;
e1d74936 45} pt_ioctl[NPTY];
5bb90914 46int npty = NPTY; /* for pstat -t */
45372428 47
1a954a11
BJ
48#define PF_RCOLL 0x01
49#define PF_WCOLL 0x02
50#define PF_NBIO 0x04
51#define PF_PKT 0x08 /* packet mode */
1e6d24b1 52#define PF_STOPPED 0x10 /* user told stopped */
defdbcd1 53#define PF_REMOTE 0x20 /* remote and flow controlled input */
0a2bd708 54#define PF_NOSTOP 0x40
5bb90914 55#define PF_UCNTL 0x80 /* user control mode */
45372428
MT
56
57/*ARGSUSED*/
58ptsopen(dev, flag)
73c77d38 59 dev_t dev;
e1d74936 60{
45372428 61 register struct tty *tp;
5bb90914 62 int error;
45372428 63
5bb90914
JB
64#ifdef lint
65 npty = npty;
66#endif
f21c8fb8
BJ
67 if (minor(dev) >= NPTY)
68 return (ENXIO);
45372428 69 tp = &pt_tty[minor(dev)];
941944c9 70 if ((tp->t_state & TS_ISOPEN) == 0) {
bdda6b91 71 ttychars(tp); /* Set up default chars */
d2f24af0 72 tp->t_ispeed = tp->t_ospeed = EXTB;
bdda6b91 73 tp->t_flags = 0; /* No features (nor raw mode) */
f21c8fb8
BJ
74 } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0)
75 return (EBUSY);
e1d74936 76 if (tp->t_oproc) /* Ctrlr still around. */
941944c9
BJ
77 tp->t_state |= TS_CARR_ON;
78 while ((tp->t_state & TS_CARR_ON) == 0) {
79 tp->t_state |= TS_WOPEN;
45372428
MT
80 sleep((caddr_t)&tp->t_rawq, TTIPRI);
81 }
5bb90914
JB
82 error = (*linesw[tp->t_line].l_open)(dev, tp);
83 ptcwakeup(tp, FREAD|FWRITE);
84 return (error);
45372428
MT
85}
86
87ptsclose(dev)
73c77d38 88 dev_t dev;
941944c9 89{
45372428
MT
90 register struct tty *tp;
91
92 tp = &pt_tty[minor(dev)];
93 (*linesw[tp->t_line].l_close)(tp);
4b39cb77 94 ttyclose(tp);
5bb90914 95 ptcwakeup(tp, FREAD|FWRITE);
45372428
MT
96}
97
ae9a0a69 98ptsread(dev, uio)
73c77d38 99 dev_t dev;
ae9a0a69 100 struct uio *uio;
e1d74936 101{
defdbcd1
BJ
102 register struct tty *tp = &pt_tty[minor(dev)];
103 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 104 int error = 0;
defdbcd1
BJ
105
106again:
107 if (pti->pt_flags & PF_REMOTE) {
108 while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) {
5bb90914
JB
109 if ((u.u_procp->p_sigignore & sigmask(SIGTTIN)) ||
110 (u.u_procp->p_sigmask & sigmask(SIGTTIN)) ||
defdbcd1 111 u.u_procp->p_flag&SVFORK)
840510a3 112 return (EIO);
defdbcd1
BJ
113 gsignal(u.u_procp->p_pgrp, SIGTTIN);
114 sleep((caddr_t)&lbolt, TTIPRI);
941944c9 115 }
5bb90914 116 if (tp->t_canq.c_cc == 0) {
840510a3
BJ
117 if (tp->t_state & TS_NBIO)
118 return (EWOULDBLOCK);
5bb90914 119 sleep((caddr_t)&tp->t_canq, TTIPRI);
defdbcd1
BJ
120 goto again;
121 }
5bb90914
JB
122 while (tp->t_canq.c_cc > 1 && uio->uio_resid > 0)
123 if (ureadc(getc(&tp->t_canq), uio) < 0) {
840510a3 124 error = EFAULT;
ae9a0a69
BJ
125 break;
126 }
5bb90914
JB
127 if (tp->t_canq.c_cc == 1)
128 (void) getc(&tp->t_canq);
129 if (tp->t_canq.c_cc)
840510a3 130 return (error);
defdbcd1
BJ
131 } else
132 if (tp->t_oproc)
840510a3 133 error = (*linesw[tp->t_line].l_read)(tp, uio);
5bb90914 134 ptcwakeup(tp, FWRITE);
840510a3 135 return (error);
45372428
MT
136}
137
941944c9
BJ
138/*
139 * Write to pseudo-tty.
140 * Wakeups of controlling tty will happen
141 * indirectly, when tty driver calls ptsstart.
142 */
ae9a0a69 143ptswrite(dev, uio)
73c77d38 144 dev_t dev;
ae9a0a69 145 struct uio *uio;
e1d74936 146{
45372428
MT
147 register struct tty *tp;
148
149 tp = &pt_tty[minor(dev)];
840510a3
BJ
150 if (tp->t_oproc == 0)
151 return (EIO);
152 return ((*linesw[tp->t_line].l_write)(tp, uio));
45372428
MT
153}
154
941944c9
BJ
155/*
156 * Start output on pseudo-tty.
157 * Wake up process selecting or sleeping for input from controlling tty.
158 */
45372428 159ptsstart(tp)
e1d74936
BJ
160 struct tty *tp;
161{
1e6d24b1 162 register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
e1d74936 163
941944c9 164 if (tp->t_state & TS_TTSTOP)
45372428 165 return;
1e6d24b1
BJ
166 if (pti->pt_flags & PF_STOPPED) {
167 pti->pt_flags &= ~PF_STOPPED;
168 pti->pt_send = TIOCPKT_START;
169 }
5bb90914 170 ptcwakeup(tp, FREAD);
d427b3b2
BJ
171}
172
5bb90914 173ptcwakeup(tp, flag)
d427b3b2
BJ
174 struct tty *tp;
175{
176 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
177
5bb90914
JB
178 if (flag & FREAD) {
179 if (pti->pt_selr) {
180 selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL);
181 pti->pt_selr = 0;
182 pti->pt_flags &= ~PF_RCOLL;
183 }
184 wakeup((caddr_t)&tp->t_outq.c_cf);
185 }
186 if (flag & FWRITE) {
187 if (pti->pt_selw) {
188 selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL);
189 pti->pt_selw = 0;
190 pti->pt_flags &= ~PF_WCOLL;
191 }
192 wakeup((caddr_t)&tp->t_rawq.c_cf);
e1d74936 193 }
45372428
MT
194}
195
196/*ARGSUSED*/
197ptcopen(dev, flag)
e1d74936
BJ
198 dev_t dev;
199 int flag;
200{
45372428 201 register struct tty *tp;
1a954a11 202 struct pt_ioctl *pti;
45372428 203
f21c8fb8
BJ
204 if (minor(dev) >= NPTY)
205 return (ENXIO);
45372428 206 tp = &pt_tty[minor(dev)];
f21c8fb8
BJ
207 if (tp->t_oproc)
208 return (EIO);
e1d74936 209 tp->t_oproc = ptsstart;
f2f3b49b 210 (void)(*linesw[tp->t_line].l_modem)(tp, 1);
941944c9 211 tp->t_state |= TS_CARR_ON;
1a954a11
BJ
212 pti = &pt_ioctl[minor(dev)];
213 pti->pt_flags = 0;
214 pti->pt_send = 0;
5bb90914 215 pti->pt_ucntl = 0;
f21c8fb8 216 return (0);
45372428
MT
217}
218
219ptcclose(dev)
e1d74936
BJ
220 dev_t dev;
221{
45372428
MT
222 register struct tty *tp;
223
224 tp = &pt_tty[minor(dev)];
f2f3b49b 225 (void)(*linesw[tp->t_line].l_modem)(tp, 0);
e1d74936 226 tp->t_oproc = 0; /* mark closed */
45372428
MT
227}
228
ae9a0a69 229ptcread(dev, uio)
1a954a11 230 dev_t dev;
ae9a0a69 231 struct uio *uio;
e1d74936 232{
840510a3 233 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914 234 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
2bb0bef9
SL
235 char buf[BUFSIZ];
236 int error = 0, cc;
45372428 237
5bb90914
JB
238 /*
239 * We want to block until the slave
240 * is open, and there's something to read;
241 * but if we lost the slave or we're NBIO,
242 * then return the appropriate error instead.
243 */
244 for (;;) {
245 if (tp->t_state&TS_ISOPEN) {
246 if (pti->pt_flags&PF_PKT && pti->pt_send) {
8011f5df 247 error = ureadc((int)pti->pt_send, uio);
5bb90914
JB
248 if (error)
249 return (error);
250 pti->pt_send = 0;
251 return (0);
252 }
253 if (pti->pt_flags&PF_UCNTL && pti->pt_ucntl) {
8011f5df 254 error = ureadc((int)pti->pt_ucntl, uio);
5bb90914
JB
255 if (error)
256 return (error);
257 pti->pt_ucntl = 0;
258 return (0);
259 }
260 if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0)
261 break;
1a954a11 262 }
2bb0bef9
SL
263 if ((tp->t_state&TS_CARR_ON) == 0)
264 return (EIO);
840510a3
BJ
265 if (pti->pt_flags&PF_NBIO)
266 return (EWOULDBLOCK);
45372428 267 sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI);
8b8271ac 268 }
5bb90914
JB
269 if (pti->pt_flags & (PF_PKT|PF_UCNTL))
270 error = ureadc(0, uio);
2bb0bef9
SL
271 while (uio->uio_resid > 0 && error == 0) {
272 cc = q_to_b(&tp->t_outq, buf, MIN(uio->uio_resid, BUFSIZ));
273 if (cc <= 0)
ae9a0a69 274 break;
2bb0bef9
SL
275 error = uiomove(buf, cc, UIO_READ, uio);
276 }
941944c9
BJ
277 if (tp->t_outq.c_cc <= TTLOWAT(tp)) {
278 if (tp->t_state&TS_ASLEEP) {
279 tp->t_state &= ~TS_ASLEEP;
280 wakeup((caddr_t)&tp->t_outq);
281 }
282 if (tp->t_wsel) {
283 selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL);
284 tp->t_wsel = 0;
285 tp->t_state &= ~TS_WCOLL;
286 }
45372428 287 }
840510a3 288 return (error);
45372428
MT
289}
290
1a954a11
BJ
291ptsstop(tp, flush)
292 register struct tty *tp;
293 int flush;
294{
295 struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)];
5bb90914 296 int flag;
1a954a11 297
1e6d24b1
BJ
298 /* note: FLUSHREAD and FLUSHWRITE already ok */
299 if (flush == 0) {
300 flush = TIOCPKT_STOP;
301 pti->pt_flags |= PF_STOPPED;
5bb90914 302 } else
1e6d24b1 303 pti->pt_flags &= ~PF_STOPPED;
0a2bd708 304 pti->pt_send |= flush;
5bb90914
JB
305 /* change of perspective */
306 flag = 0;
307 if (flush & FREAD)
308 flag |= FWRITE;
309 if (flush & FWRITE)
310 flag |= FREAD;
9d2a90b1 311 ptcwakeup(tp, flag);
1a954a11
BJ
312}
313
941944c9 314ptcselect(dev, rw)
e1d74936 315 dev_t dev;
941944c9 316 int rw;
e1d74936
BJ
317{
318 register struct tty *tp = &pt_tty[minor(dev)];
defdbcd1 319 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
e1d74936 320 struct proc *p;
d427b3b2 321 int s;
e1d74936 322
5bb90914 323 if ((tp->t_state&TS_CARR_ON) == 0)
e1d74936 324 return (1);
941944c9
BJ
325 switch (rw) {
326
327 case FREAD:
892f2f35
MK
328 /*
329 * Need to block timeouts (ttrstart).
330 */
331 s = spltty();
7cbd29e4
MK
332 if ((tp->t_state&TS_ISOPEN) &&
333 tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) {
334 splx(s);
335 return (1);
336 }
892f2f35 337 splx(s);
7cbd29e4
MK
338 /* FALLTHROUGH */
339
340 case 0: /* exceptional */
5bb90914
JB
341 if ((tp->t_state&TS_ISOPEN) &&
342 (pti->pt_flags&PF_PKT && pti->pt_send ||
892f2f35 343 pti->pt_flags&PF_UCNTL && pti->pt_ucntl))
941944c9 344 return (1);
1a954a11
BJ
345 if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait)
346 pti->pt_flags |= PF_RCOLL;
941944c9 347 else
1a954a11 348 pti->pt_selr = u.u_procp;
d427b3b2 349 break;
941944c9 350
7cbd29e4 351
941944c9 352 case FWRITE:
892f2f35
MK
353 if (tp->t_state&TS_ISOPEN) {
354 if (pti->pt_flags & PF_REMOTE) {
355 if (tp->t_canq.c_cc == 0)
356 return (1);
357 } else {
358 if (tp->t_rawq.c_cc + tp->t_canq.c_cc < TTYHOG-2)
359 return (1);
360 if (tp->t_canq.c_cc == 0 &&
aec7dd3b 361 (tp->t_flags & (RAW|CBREAK)) == 0)
892f2f35
MK
362 return (1);
363 }
d427b3b2 364 }
1a954a11
BJ
365 if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait)
366 pti->pt_flags |= PF_WCOLL;
941944c9 367 else
1a954a11 368 pti->pt_selw = u.u_procp;
d427b3b2 369 break;
7cbd29e4 370
941944c9 371 }
d427b3b2 372 return (0);
e1d74936
BJ
373}
374
ae9a0a69 375ptcwrite(dev, uio)
941944c9 376 dev_t dev;
5bb90914 377 register struct uio *uio;
e1d74936 378{
840510a3 379 register struct tty *tp = &pt_tty[minor(dev)];
5bb90914
JB
380 register struct iovec *iov;
381 register char *cp;
382 register int cc = 0;
45372428 383 char locbuf[BUFSIZ];
941944c9 384 int cnt = 0;
defdbcd1 385 struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
840510a3 386 int error = 0;
45372428 387
defdbcd1 388again:
5bb90914
JB
389 if ((tp->t_state&TS_ISOPEN) == 0)
390 goto block;
9d2a90b1 391 if (pti->pt_flags & PF_REMOTE) {
5bb90914
JB
392 if (tp->t_canq.c_cc)
393 goto block;
9d2a90b1
JB
394 while (uio->uio_iovcnt > 0 && tp->t_canq.c_cc < TTYHOG - 1) {
395 iov = uio->uio_iov;
396 if (iov->iov_len == 0) {
397 uio->uio_iovcnt--;
398 uio->uio_iov++;
399 continue;
400 }
401 if (cc == 0) {
402 cc = MIN(iov->iov_len, BUFSIZ);
403 cc = MIN(cc, TTYHOG - 1 - tp->t_canq.c_cc);
404 cp = locbuf;
405 error = uiomove(cp, cc, UIO_WRITE, uio);
406 if (error)
407 return (error);
408 /* check again for safety */
409 if ((tp->t_state&TS_ISOPEN) == 0)
410 return (EIO);
411 }
412 if (cc)
413 (void) b_to_q(cp, cc, &tp->t_canq);
414 cc = 0;
defdbcd1 415 }
5bb90914
JB
416 (void) putc(0, &tp->t_canq);
417 ttwakeup(tp);
418 wakeup((caddr_t)&tp->t_canq);
419 return (0);
420 }
421 while (uio->uio_iovcnt > 0) {
422 iov = uio->uio_iov;
423 if (cc == 0) {
424 if (iov->iov_len == 0) {
425 uio->uio_iovcnt--;
426 uio->uio_iov++;
427 continue;
45372428 428 }
5bb90914
JB
429 cc = MIN(iov->iov_len, BUFSIZ);
430 cp = locbuf;
431 error = uiomove(cp, cc, UIO_WRITE, uio);
432 if (error)
433 return (error);
434 /* check again for safety */
435 if ((tp->t_state&TS_ISOPEN) == 0)
436 return (EIO);
437 }
9d2a90b1
JB
438 while (cc > 0) {
439 if ((tp->t_rawq.c_cc + tp->t_canq.c_cc) >= TTYHOG - 2 &&
892f2f35
MK
440 (tp->t_canq.c_cc > 0 ||
441 tp->t_flags & (RAW|CBREAK))) {
9d2a90b1
JB
442 wakeup((caddr_t)&tp->t_rawq);
443 goto block;
444 }
36612a8f 445 (*linesw[tp->t_line].l_rint)(*cp++, tp);
941944c9 446 cnt++;
9d2a90b1 447 cc--;
45372428 448 }
5bb90914
JB
449 cc = 0;
450 }
451 return (0);
452block:
453 /*
9d2a90b1
JB
454 * Come here to wait for slave to open, for space
455 * in outq, or space in rawq.
5bb90914
JB
456 */
457 if ((tp->t_state&TS_CARR_ON) == 0)
458 return (EIO);
459 if (pti->pt_flags & PF_NBIO) {
5bb90914
JB
460 iov->iov_base -= cc;
461 iov->iov_len += cc;
462 uio->uio_resid += cc;
463 uio->uio_offset -= cc;
9d2a90b1
JB
464 if (cnt == 0)
465 return (EWOULDBLOCK);
5bb90914
JB
466 return (0);
467 }
468 sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI);
469 goto again;
45372428
MT
470}
471
45372428 472/*ARGSUSED*/
4b72e2f9
SL
473ptyioctl(dev, cmd, data, flag)
474 caddr_t data;
e1d74936
BJ
475 dev_t dev;
476{
0a2bd708
BJ
477 register struct tty *tp = &pt_tty[minor(dev)];
478 register struct pt_ioctl *pti = &pt_ioctl[minor(dev)];
5bb90914 479 int stop, error;
f2f3b49b 480 extern ttyinput();
45372428 481
f2f3b49b
MK
482 /*
483 * IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG.
484 * ttywflush(tp) will hang if there are characters in the outq.
485 */
4b72e2f9
SL
486 if (cdevsw[major(dev)].d_open == ptcopen)
487 switch (cmd) {
488
489 case TIOCPKT:
5bb90914
JB
490 if (*(int *)data) {
491 if (pti->pt_flags & PF_UCNTL)
492 return (EINVAL);
1a954a11 493 pti->pt_flags |= PF_PKT;
5bb90914 494 } else
1a954a11 495 pti->pt_flags &= ~PF_PKT;
f21c8fb8 496 return (0);
4b72e2f9 497
5bb90914
JB
498 case TIOCUCNTL:
499 if (*(int *)data) {
500 if (pti->pt_flags & PF_PKT)
501 return (EINVAL);
502 pti->pt_flags |= PF_UCNTL;
503 } else
504 pti->pt_flags &= ~PF_UCNTL;
505 return (0);
506
4b72e2f9
SL
507 case TIOCREMOTE:
508 if (*(int *)data)
defdbcd1
BJ
509 pti->pt_flags |= PF_REMOTE;
510 else
511 pti->pt_flags &= ~PF_REMOTE;
88a7a62a 512 ttyflush(tp, FREAD|FWRITE);
f21c8fb8 513 return (0);
4b72e2f9
SL
514
515 case FIONBIO:
516 if (*(int *)data)
1a954a11 517 pti->pt_flags |= PF_NBIO;
8b8271ac 518 else
1a954a11 519 pti->pt_flags &= ~PF_NBIO;
f21c8fb8 520 return (0);
4b72e2f9
SL
521
522 case TIOCSETP:
f2f3b49b
MK
523 case TIOCSETN:
524 case TIOCSETD:
4b72e2f9
SL
525 while (getc(&tp->t_outq) >= 0)
526 ;
527 break;
8b8271ac 528 }
477d62ec 529 error = ttioctl(tp, cmd, data, flag);
f2f3b49b
MK
530 /*
531 * Since we use the tty queues internally,
532 * pty's can't be switched to disciplines which overwrite
533 * the queues. We can't tell anything about the discipline
534 * from here...
535 */
536 if (linesw[tp->t_line].l_rint != ttyinput) {
537 (*linesw[tp->t_line].l_close)(tp);
538 tp->t_line = 0;
539 (void)(*linesw[tp->t_line].l_open)(dev, tp);
540 error = ENOTTY;
541 }
5bb90914
JB
542 if (error < 0) {
543 if (pti->pt_flags & PF_UCNTL &&
97d7430f 544 (cmd & ~0xff) == UIOCCMD(0)) {
5bb90914
JB
545 if (cmd & 0xff) {
546 pti->pt_ucntl = (u_char)cmd;
547 ptcwakeup(tp, FREAD);
548 }
549 return (0);
550 }
f21c8fb8 551 error = ENOTTY;
5bb90914
JB
552 }
553 stop = (tp->t_flags & RAW) == 0 &&
554 tp->t_stopc == CTRL(s) && tp->t_startc == CTRL(q);
0a2bd708
BJ
555 if (pti->pt_flags & PF_NOSTOP) {
556 if (stop) {
b31eb1ff 557 pti->pt_send &= ~TIOCPKT_NOSTOP;
0a2bd708
BJ
558 pti->pt_send |= TIOCPKT_DOSTOP;
559 pti->pt_flags &= ~PF_NOSTOP;
5bb90914 560 ptcwakeup(tp, FREAD);
0a2bd708
BJ
561 }
562 } else {
5bb90914 563 if (!stop) {
0a2bd708
BJ
564 pti->pt_send &= ~TIOCPKT_DOSTOP;
565 pti->pt_send |= TIOCPKT_NOSTOP;
566 pti->pt_flags |= PF_NOSTOP;
5bb90914 567 ptcwakeup(tp, FREAD);
0a2bd708
BJ
568 }
569 }
f21c8fb8 570 return (error);
45372428 571}
4f07e6e5 572#endif