Commit | Line | Data |
---|---|---|
a8d3bf7f | 1 | /* tty_pty.c 4.28 82/10/17 */ |
be4367b3 | 2 | |
45372428 MT |
3 | /* |
4 | * Pseudo-teletype Driver | |
5 | * (Actually two drivers, requiring two entries in 'cdevsw') | |
45372428 | 6 | */ |
647d645f MT |
7 | #include "pty.h" |
8 | ||
f12183e4 | 9 | #if NPTY > 0 |
45372428 MT |
10 | #include "../h/param.h" |
11 | #include "../h/systm.h" | |
12 | #include "../h/tty.h" | |
13 | #include "../h/dir.h" | |
14 | #include "../h/user.h" | |
15 | #include "../h/conf.h" | |
bdda6b91 | 16 | #include "../h/file.h" |
e1d74936 | 17 | #include "../h/proc.h" |
ae9a0a69 | 18 | #include "../h/uio.h" |
7ba3a9ca | 19 | #include "../h/kernel.h" |
941944c9 | 20 | |
b3c8737d | 21 | #if NPTY == 1 |
c91c01fe BJ |
22 | #undef NPTY |
23 | #define NPTY 32 /* crude XXX */ | |
b3c8737d | 24 | #endif |
45372428 | 25 | |
bdda6b91 | 26 | #define BUFSIZ 100 /* Chunk size iomoved from user */ |
e1d74936 | 27 | |
45372428 | 28 | /* |
e1d74936 BJ |
29 | * pts == /dev/tty[pP]? |
30 | * ptc == /dev/ptp[pP]? | |
45372428 | 31 | */ |
e1d74936 BJ |
32 | struct tty pt_tty[NPTY]; |
33 | struct pt_ioctl { | |
1a954a11 BJ |
34 | int pt_flags; |
35 | int pt_gensym; | |
36 | struct proc *pt_selr, *pt_selw; | |
37 | int pt_send; | |
e1d74936 | 38 | } pt_ioctl[NPTY]; |
45372428 | 39 | |
1a954a11 BJ |
40 | #define PF_RCOLL 0x01 |
41 | #define PF_WCOLL 0x02 | |
42 | #define PF_NBIO 0x04 | |
43 | #define PF_PKT 0x08 /* packet mode */ | |
1e6d24b1 | 44 | #define PF_STOPPED 0x10 /* user told stopped */ |
defdbcd1 | 45 | #define PF_REMOTE 0x20 /* remote and flow controlled input */ |
0a2bd708 | 46 | #define PF_NOSTOP 0x40 |
45372428 MT |
47 | |
48 | /*ARGSUSED*/ | |
49 | ptsopen(dev, flag) | |
73c77d38 | 50 | dev_t dev; |
e1d74936 | 51 | { |
45372428 MT |
52 | register struct tty *tp; |
53 | ||
f21c8fb8 BJ |
54 | if (minor(dev) >= NPTY) |
55 | return (ENXIO); | |
45372428 | 56 | tp = &pt_tty[minor(dev)]; |
941944c9 | 57 | if ((tp->t_state & TS_ISOPEN) == 0) { |
bdda6b91 BJ |
58 | ttychars(tp); /* Set up default chars */ |
59 | tp->t_flags = 0; /* No features (nor raw mode) */ | |
f21c8fb8 BJ |
60 | } else if (tp->t_state&TS_XCLUDE && u.u_uid != 0) |
61 | return (EBUSY); | |
e1d74936 | 62 | if (tp->t_oproc) /* Ctrlr still around. */ |
941944c9 BJ |
63 | tp->t_state |= TS_CARR_ON; |
64 | while ((tp->t_state & TS_CARR_ON) == 0) { | |
65 | tp->t_state |= TS_WOPEN; | |
45372428 MT |
66 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
67 | } | |
f21c8fb8 | 68 | return ((*linesw[tp->t_line].l_open)(dev, tp)); |
45372428 MT |
69 | } |
70 | ||
71 | ptsclose(dev) | |
73c77d38 | 72 | dev_t dev; |
941944c9 | 73 | { |
45372428 MT |
74 | register struct tty *tp; |
75 | ||
76 | tp = &pt_tty[minor(dev)]; | |
77 | (*linesw[tp->t_line].l_close)(tp); | |
4b39cb77 | 78 | ttyclose(tp); |
45372428 MT |
79 | } |
80 | ||
ae9a0a69 | 81 | ptsread(dev, uio) |
73c77d38 | 82 | dev_t dev; |
ae9a0a69 | 83 | struct uio *uio; |
e1d74936 | 84 | { |
defdbcd1 BJ |
85 | register struct tty *tp = &pt_tty[minor(dev)]; |
86 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
840510a3 | 87 | int error = 0; |
defdbcd1 BJ |
88 | |
89 | again: | |
90 | if (pti->pt_flags & PF_REMOTE) { | |
91 | while (tp == u.u_ttyp && u.u_procp->p_pgrp != tp->t_pgrp) { | |
92 | if (u.u_signal[SIGTTIN] == SIG_IGN || | |
93 | u.u_signal[SIGTTIN] == SIG_HOLD || | |
94 | /* | |
95 | (u.u_procp->p_flag&SDETACH) || | |
96 | */ | |
97 | u.u_procp->p_flag&SVFORK) | |
840510a3 | 98 | return (EIO); |
defdbcd1 BJ |
99 | gsignal(u.u_procp->p_pgrp, SIGTTIN); |
100 | sleep((caddr_t)&lbolt, TTIPRI); | |
941944c9 | 101 | } |
defdbcd1 | 102 | if (tp->t_rawq.c_cc == 0) { |
840510a3 BJ |
103 | if (tp->t_state & TS_NBIO) |
104 | return (EWOULDBLOCK); | |
defdbcd1 BJ |
105 | sleep((caddr_t)&tp->t_rawq, TTIPRI); |
106 | goto again; | |
107 | } | |
ae9a0a69 BJ |
108 | while (tp->t_rawq.c_cc > 1 && uio->uio_resid > 0) |
109 | if (ureadc(getc(&tp->t_rawq), uio) < 0) { | |
840510a3 | 110 | error = EFAULT; |
ae9a0a69 BJ |
111 | break; |
112 | } | |
defdbcd1 BJ |
113 | if (tp->t_rawq.c_cc == 1) |
114 | (void) getc(&tp->t_rawq); | |
115 | if (tp->t_rawq.c_cc) | |
840510a3 | 116 | return (error); |
defdbcd1 BJ |
117 | } else |
118 | if (tp->t_oproc) | |
840510a3 | 119 | error = (*linesw[tp->t_line].l_read)(tp, uio); |
defdbcd1 BJ |
120 | wakeup((caddr_t)&tp->t_rawq.c_cf); |
121 | if (pti->pt_selw) { | |
122 | selwakeup(pti->pt_selw, pti->pt_flags & PF_WCOLL); | |
123 | pti->pt_selw = 0; | |
124 | pti->pt_flags &= ~PF_WCOLL; | |
45372428 | 125 | } |
840510a3 | 126 | return (error); |
45372428 MT |
127 | } |
128 | ||
941944c9 BJ |
129 | /* |
130 | * Write to pseudo-tty. | |
131 | * Wakeups of controlling tty will happen | |
132 | * indirectly, when tty driver calls ptsstart. | |
133 | */ | |
ae9a0a69 | 134 | ptswrite(dev, uio) |
73c77d38 | 135 | dev_t dev; |
ae9a0a69 | 136 | struct uio *uio; |
e1d74936 | 137 | { |
45372428 MT |
138 | register struct tty *tp; |
139 | ||
140 | tp = &pt_tty[minor(dev)]; | |
840510a3 BJ |
141 | if (tp->t_oproc == 0) |
142 | return (EIO); | |
143 | return ((*linesw[tp->t_line].l_write)(tp, uio)); | |
45372428 MT |
144 | } |
145 | ||
941944c9 BJ |
146 | /* |
147 | * Start output on pseudo-tty. | |
148 | * Wake up process selecting or sleeping for input from controlling tty. | |
149 | */ | |
45372428 | 150 | ptsstart(tp) |
e1d74936 BJ |
151 | struct tty *tp; |
152 | { | |
1e6d24b1 | 153 | register struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; |
e1d74936 | 154 | |
941944c9 | 155 | if (tp->t_state & TS_TTSTOP) |
45372428 | 156 | return; |
1e6d24b1 BJ |
157 | if (pti->pt_flags & PF_STOPPED) { |
158 | pti->pt_flags &= ~PF_STOPPED; | |
159 | pti->pt_send = TIOCPKT_START; | |
160 | } | |
d427b3b2 BJ |
161 | ptcwakeup(tp); |
162 | } | |
163 | ||
164 | ptcwakeup(tp) | |
165 | struct tty *tp; | |
166 | { | |
167 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
168 | ||
1a954a11 BJ |
169 | if (pti->pt_selr) { |
170 | selwakeup(pti->pt_selr, pti->pt_flags & PF_RCOLL); | |
171 | pti->pt_selr = 0; | |
172 | pti->pt_flags &= ~PF_RCOLL; | |
e1d74936 | 173 | } |
45372428 MT |
174 | wakeup((caddr_t)&tp->t_outq.c_cf); |
175 | } | |
176 | ||
177 | /*ARGSUSED*/ | |
178 | ptcopen(dev, flag) | |
e1d74936 BJ |
179 | dev_t dev; |
180 | int flag; | |
181 | { | |
45372428 | 182 | register struct tty *tp; |
1a954a11 | 183 | struct pt_ioctl *pti; |
45372428 | 184 | |
f21c8fb8 BJ |
185 | if (minor(dev) >= NPTY) |
186 | return (ENXIO); | |
45372428 | 187 | tp = &pt_tty[minor(dev)]; |
f21c8fb8 BJ |
188 | if (tp->t_oproc) |
189 | return (EIO); | |
e1d74936 | 190 | tp->t_oproc = ptsstart; |
941944c9 | 191 | if (tp->t_state & TS_WOPEN) |
45372428 | 192 | wakeup((caddr_t)&tp->t_rawq); |
941944c9 | 193 | tp->t_state |= TS_CARR_ON; |
1a954a11 BJ |
194 | pti = &pt_ioctl[minor(dev)]; |
195 | pti->pt_flags = 0; | |
196 | pti->pt_send = 0; | |
f21c8fb8 | 197 | return (0); |
45372428 MT |
198 | } |
199 | ||
200 | ptcclose(dev) | |
e1d74936 BJ |
201 | dev_t dev; |
202 | { | |
45372428 MT |
203 | register struct tty *tp; |
204 | ||
205 | tp = &pt_tty[minor(dev)]; | |
941944c9 | 206 | if (tp->t_state & TS_ISOPEN) |
45372428 | 207 | gsignal(tp->t_pgrp, SIGHUP); |
941944c9 | 208 | tp->t_state &= ~TS_CARR_ON; /* virtual carrier gone */ |
e1d74936 BJ |
209 | flushtty(tp, FREAD|FWRITE); |
210 | tp->t_oproc = 0; /* mark closed */ | |
45372428 MT |
211 | } |
212 | ||
ae9a0a69 | 213 | ptcread(dev, uio) |
1a954a11 | 214 | dev_t dev; |
ae9a0a69 | 215 | struct uio *uio; |
e1d74936 | 216 | { |
840510a3 | 217 | register struct tty *tp = &pt_tty[minor(dev)]; |
1a954a11 | 218 | struct pt_ioctl *pti; |
840510a3 | 219 | int error = 0; |
45372428 | 220 | |
941944c9 | 221 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
a8d3bf7f | 222 | return (EIO); |
1a954a11 BJ |
223 | pti = &pt_ioctl[minor(dev)]; |
224 | if (pti->pt_flags & PF_PKT) { | |
225 | if (pti->pt_send) { | |
840510a3 BJ |
226 | error = ureadc(pti->pt_send, uio); |
227 | if (error) | |
228 | return (error); | |
1a954a11 | 229 | pti->pt_send = 0; |
840510a3 | 230 | return (0); |
1a954a11 | 231 | } |
840510a3 | 232 | error = ureadc(0, uio); |
1a954a11 | 233 | } |
8b8271ac | 234 | while (tp->t_outq.c_cc == 0 || (tp->t_state&TS_TTSTOP)) { |
840510a3 BJ |
235 | if (pti->pt_flags&PF_NBIO) |
236 | return (EWOULDBLOCK); | |
45372428 | 237 | sleep((caddr_t)&tp->t_outq.c_cf, TTIPRI); |
8b8271ac | 238 | } |
ae9a0a69 BJ |
239 | while (tp->t_outq.c_cc && uio->uio_resid > 0) |
240 | if (ureadc(getc(&tp->t_outq), uio) < 0) { | |
840510a3 | 241 | error = EFAULT; |
ae9a0a69 BJ |
242 | break; |
243 | } | |
941944c9 BJ |
244 | if (tp->t_outq.c_cc <= TTLOWAT(tp)) { |
245 | if (tp->t_state&TS_ASLEEP) { | |
246 | tp->t_state &= ~TS_ASLEEP; | |
247 | wakeup((caddr_t)&tp->t_outq); | |
248 | } | |
249 | if (tp->t_wsel) { | |
250 | selwakeup(tp->t_wsel, tp->t_state & TS_WCOLL); | |
251 | tp->t_wsel = 0; | |
252 | tp->t_state &= ~TS_WCOLL; | |
253 | } | |
45372428 | 254 | } |
840510a3 | 255 | return (error); |
45372428 MT |
256 | } |
257 | ||
1a954a11 BJ |
258 | ptsstop(tp, flush) |
259 | register struct tty *tp; | |
260 | int flush; | |
261 | { | |
262 | struct pt_ioctl *pti = &pt_ioctl[minor(tp->t_dev)]; | |
263 | ||
1e6d24b1 BJ |
264 | /* note: FLUSHREAD and FLUSHWRITE already ok */ |
265 | if (flush == 0) { | |
266 | flush = TIOCPKT_STOP; | |
267 | pti->pt_flags |= PF_STOPPED; | |
268 | } else { | |
269 | pti->pt_flags &= ~PF_STOPPED; | |
270 | } | |
0a2bd708 | 271 | pti->pt_send |= flush; |
d427b3b2 | 272 | ptcwakeup(tp); |
1a954a11 BJ |
273 | } |
274 | ||
941944c9 | 275 | ptcselect(dev, rw) |
e1d74936 | 276 | dev_t dev; |
941944c9 | 277 | int rw; |
e1d74936 BJ |
278 | { |
279 | register struct tty *tp = &pt_tty[minor(dev)]; | |
defdbcd1 | 280 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
e1d74936 | 281 | struct proc *p; |
d427b3b2 | 282 | int s; |
e1d74936 | 283 | |
941944c9 | 284 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
e1d74936 | 285 | return (1); |
d427b3b2 | 286 | s = spl5(); |
941944c9 BJ |
287 | switch (rw) { |
288 | ||
289 | case FREAD: | |
d427b3b2 BJ |
290 | if (tp->t_outq.c_cc && (tp->t_state&TS_TTSTOP) == 0) { |
291 | splx(s); | |
941944c9 | 292 | return (1); |
d427b3b2 | 293 | } |
1a954a11 BJ |
294 | if ((p = pti->pt_selr) && p->p_wchan == (caddr_t)&selwait) |
295 | pti->pt_flags |= PF_RCOLL; | |
941944c9 | 296 | else |
1a954a11 | 297 | pti->pt_selr = u.u_procp; |
d427b3b2 | 298 | break; |
941944c9 BJ |
299 | |
300 | case FWRITE: | |
defdbcd1 | 301 | if ((pti->pt_flags & PF_REMOTE) == 0 || tp->t_rawq.c_cc == 0) { |
d427b3b2 | 302 | splx(s); |
941944c9 | 303 | return (1); |
d427b3b2 | 304 | } |
1a954a11 BJ |
305 | if ((p = pti->pt_selw) && p->p_wchan == (caddr_t)&selwait) |
306 | pti->pt_flags |= PF_WCOLL; | |
941944c9 | 307 | else |
1a954a11 | 308 | pti->pt_selw = u.u_procp; |
d427b3b2 | 309 | break; |
941944c9 | 310 | } |
d427b3b2 BJ |
311 | splx(s); |
312 | return (0); | |
e1d74936 BJ |
313 | } |
314 | ||
ae9a0a69 | 315 | ptcwrite(dev, uio) |
941944c9 | 316 | dev_t dev; |
ae9a0a69 | 317 | struct uio *uio; |
e1d74936 | 318 | { |
840510a3 | 319 | register struct tty *tp = &pt_tty[minor(dev)]; |
45372428 MT |
320 | register char *cp, *ce; |
321 | register int cc; | |
322 | char locbuf[BUFSIZ]; | |
941944c9 | 323 | int cnt = 0; |
defdbcd1 | 324 | struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; |
840510a3 | 325 | int error = 0; |
45372428 | 326 | |
941944c9 | 327 | if ((tp->t_state&(TS_CARR_ON|TS_ISOPEN)) == 0) |
840510a3 | 328 | return (EIO); |
defdbcd1 | 329 | do { |
ae9a0a69 BJ |
330 | register struct iovec *iov; |
331 | ||
332 | if (uio->uio_iovcnt == 0) | |
333 | break; | |
334 | iov = uio->uio_iov; | |
335 | if (iov->iov_len == 0) { | |
336 | uio->uio_iovcnt--; | |
337 | uio->uio_iov++; | |
338 | if (uio->uio_iovcnt < 0) | |
339 | panic("ptcwrite"); | |
340 | continue; | |
341 | } | |
342 | cc = MIN(iov->iov_len, BUFSIZ); | |
45372428 | 343 | cp = locbuf; |
840510a3 BJ |
344 | error = uiomove(cp, cc, UIO_WRITE, uio); |
345 | if (error) | |
45372428 MT |
346 | break; |
347 | ce = cp + cc; | |
defdbcd1 BJ |
348 | again: |
349 | if (pti->pt_flags & PF_REMOTE) { | |
350 | if (tp->t_rawq.c_cc) { | |
351 | if (pti->pt_flags & PF_NBIO) { | |
ae9a0a69 BJ |
352 | iov->iov_base -= ce - cp; |
353 | iov->iov_len += ce - cp; | |
354 | uio->uio_resid += ce - cp; | |
355 | uio->uio_offset -= ce - cp; | |
840510a3 | 356 | return (EWOULDBLOCK); |
defdbcd1 BJ |
357 | } |
358 | sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); | |
359 | goto again; | |
360 | } | |
668cc26d SL |
361 | (void) b_to_q(cp, cc, &tp->t_rawq); |
362 | (void) putc(0, &tp->t_rawq); | |
defdbcd1 | 363 | wakeup((caddr_t)&tp->t_rawq); |
840510a3 | 364 | return (0); |
defdbcd1 | 365 | } |
e1d74936 BJ |
366 | while (cp < ce) { |
367 | while (tp->t_delct && tp->t_rawq.c_cc >= TTYHOG - 2) { | |
45372428 | 368 | wakeup((caddr_t)&tp->t_rawq); |
941944c9 | 369 | if (tp->t_state & TS_NBIO) { |
ae9a0a69 BJ |
370 | iov->iov_base -= ce - cp; |
371 | iov->iov_len += ce - cp; | |
372 | uio->uio_resid += ce - cp; | |
373 | uio->uio_offset -= ce - cp; | |
941944c9 | 374 | if (cnt == 0) |
840510a3 BJ |
375 | return (EWOULDBLOCK); |
376 | return (0); | |
941944c9 | 377 | } |
45372428 MT |
378 | /* Better than just flushing it! */ |
379 | /* Wait for something to be read */ | |
380 | sleep((caddr_t)&tp->t_rawq.c_cf, TTOPRI); | |
defdbcd1 | 381 | goto again; |
45372428 | 382 | } |
36612a8f | 383 | (*linesw[tp->t_line].l_rint)(*cp++, tp); |
941944c9 | 384 | cnt++; |
45372428 | 385 | } |
ae9a0a69 | 386 | } while (uio->uio_resid); |
840510a3 | 387 | return (error); |
45372428 MT |
388 | } |
389 | ||
45372428 | 390 | /*ARGSUSED*/ |
4b72e2f9 SL |
391 | ptyioctl(dev, cmd, data, flag) |
392 | caddr_t data; | |
e1d74936 BJ |
393 | dev_t dev; |
394 | { | |
0a2bd708 BJ |
395 | register struct tty *tp = &pt_tty[minor(dev)]; |
396 | register struct pt_ioctl *pti = &pt_ioctl[minor(dev)]; | |
f21c8fb8 | 397 | int error; |
45372428 | 398 | |
e1d74936 | 399 | /* IF CONTROLLER STTY THEN MUST FLUSH TO PREVENT A HANG ??? */ |
4b72e2f9 SL |
400 | if (cdevsw[major(dev)].d_open == ptcopen) |
401 | switch (cmd) { | |
402 | ||
403 | case TIOCPKT: | |
404 | if (*(int *)data) | |
1a954a11 BJ |
405 | pti->pt_flags |= PF_PKT; |
406 | else | |
407 | pti->pt_flags &= ~PF_PKT; | |
f21c8fb8 | 408 | return (0); |
4b72e2f9 SL |
409 | |
410 | case TIOCREMOTE: | |
411 | if (*(int *)data) | |
defdbcd1 BJ |
412 | pti->pt_flags |= PF_REMOTE; |
413 | else | |
414 | pti->pt_flags &= ~PF_REMOTE; | |
415 | flushtty(tp, FREAD|FWRITE); | |
f21c8fb8 | 416 | return (0); |
4b72e2f9 SL |
417 | |
418 | case FIONBIO: | |
419 | if (*(int *)data) | |
1a954a11 | 420 | pti->pt_flags |= PF_NBIO; |
8b8271ac | 421 | else |
1a954a11 | 422 | pti->pt_flags &= ~PF_NBIO; |
f21c8fb8 | 423 | return (0); |
4b72e2f9 SL |
424 | |
425 | case TIOCSETP: | |
426 | while (getc(&tp->t_outq) >= 0) | |
427 | ; | |
428 | break; | |
8b8271ac | 429 | } |
f21c8fb8 BJ |
430 | error = ttioctl(tp, cmd, data, dev); |
431 | if (error < 0) | |
432 | error = ENOTTY; | |
0a2bd708 BJ |
433 | { int stop = (tp->t_un.t_chr.t_stopc == ('s'&037) && |
434 | tp->t_un.t_chr.t_startc == ('q'&037)); | |
435 | if (pti->pt_flags & PF_NOSTOP) { | |
436 | if (stop) { | |
437 | pti->pt_send &= TIOCPKT_NOSTOP; | |
438 | pti->pt_send |= TIOCPKT_DOSTOP; | |
439 | pti->pt_flags &= ~PF_NOSTOP; | |
440 | ptcwakeup(tp); | |
441 | } | |
442 | } else { | |
443 | if (stop == 0) { | |
444 | pti->pt_send &= ~TIOCPKT_DOSTOP; | |
445 | pti->pt_send |= TIOCPKT_NOSTOP; | |
446 | pti->pt_flags |= PF_NOSTOP; | |
447 | ptcwakeup(tp); | |
448 | } | |
449 | } | |
450 | } | |
f21c8fb8 | 451 | return (error); |
45372428 | 452 | } |
4f07e6e5 | 453 | #endif |