xref: /minix/minix/drivers/tty/pty/pty.c (revision fb9c64b2)
1 /*	pty.c - pseudo terminal driver			Author: Kees J. Bot
2  *								30 Dec 1995
3  * PTYs can be seen as a bidirectional pipe with TTY
4  * input and output processing.  For example a simple rlogin session:
5  *
6  *	keyboard -> rlogin -> in.rld -> /dev/ptypX -> /dev/ttypX -> shell
7  *	shell -> /dev/ttypX -> /dev/ptypX -> in.rld -> rlogin -> screen
8  *
9  * This file takes care of copying data between the tty/pty device pairs and
10  * the open/read/write/close calls on the pty devices.  The TTY task takes
11  * care of the input and output processing (interrupt, backspace, raw I/O,
12  * etc.) using the pty_slave_read() and pty_slave_write() functions as the
13  * "keyboard" and "screen" functions of the ttypX devices.
14  * Be careful when reading this code, the terms "reading" and "writing" are
15  * used both for the tty (slave) and the pty (master) end of the pseudo tty.
16  * Writes to one end are to be read at the other end and vice-versa.
17  *
18  * In addition to the above, PTY service now also supports Unix98 pseudo-
19  * terminal pairs, thereby allowing non-root users to allocate pseudoterminals.
20  * It requires the presence for PTYFS for this, and supports only old-style
21  * ptys when PTYFS is not running. For Unix98 ptys, the general idea is that a
22  * userland program opens a pty master by opening /dev/ptmx through the use of
23  * posxix_openpt(3). A slave node is allocated on PTYFS when the program calls
24  * grantpt(3) on the master. The program can then obtain the path name for the
25  * slave end through ptsname(3), and open the slave end using this path.
26  *
27  * Implementation-wise, the Unix98 and non-Unix98 pseudoterminals share the
28  * same pool of data structures, but use different ranges of minor numbers.
29  * Access to the two types may not be mixed, and thus, some parts of the code
30  * have checks to make sure a traditional slave is not opened for a master
31  * allocated through /dev/ptmx, etcetera.
32  */
33 
34 #include <minix/drivers.h>
35 #include <paths.h>
36 #include <termios.h>
37 #include <assert.h>
38 #include <sys/termios.h>
39 #include <signal.h>
40 #include "tty.h"
41 #include "ptyfs.h"
42 
43 /* Device node attributes used for Unix98 slave nodes. */
44 #define UNIX98_MODE		(S_IFCHR | 0620)	/* crw--w---- */
45 
46 #define UNIX98_MASTER(index)	(UNIX98_MINOR + (index) * 2)
47 #define UNIX98_SLAVE(index)	(UNIX98_MINOR + (index) * 2 + 1)
48 
49 /* PTY bookkeeping structure, one per pty/tty pair. */
50 typedef struct pty {
51   tty_t		*tty;		/* associated TTY structure */
52   char		state;		/* flags: busy, closed, ... */
53 
54   /* Read call on master (/dev/ptypX). */
55   endpoint_t	rdcaller;	/* process making the call, or NONE if none */
56   cdev_id_t	rdid;		/* ID of suspended read request */
57   cp_grant_id_t	rdgrant;	/* grant for reader's address space */
58   size_t	rdleft;		/* # bytes yet to be read */
59   size_t	rdcum;		/* # bytes written so far */
60 
61   /* Write call to master (/dev/ptypX). */
62   endpoint_t	wrcaller;	/* process making the call, or NONE if none*/
63   cdev_id_t	wrid;		/* ID of suspended write request */
64   cp_grant_id_t	wrgrant;	/* grant for writer's address space */
65   size_t	wrleft;		/* # bytes yet to be written */
66   size_t	wrcum;		/* # bytes written so far */
67 
68   /* Output buffer. */
69   int		ocount;		/* # characters in the buffer */
70   char		*ohead, *otail;	/* head and tail of the circular buffer */
71   char		obuf[TTY_OUT_BYTES];
72 				/* buffer for bytes going to the pty reader */
73 
74   /* select() data. */
75   unsigned int	select_ops;	/* Which operations do we want to know about? */
76   endpoint_t	select_proc;	/* Who wants to know about it? */
77   devminor_t	select_minor;	/* Which minor was being selected on? */
78 } pty_t;
79 
80 #define TTY_ACTIVE	0x01	/* tty is open/active */
81 #define PTY_ACTIVE	0x02	/* pty is open/active */
82 #define TTY_CLOSED	0x04	/* tty side has closed down */
83 #define PTY_CLOSED	0x08	/* pty side has closed down */
84 #define PTY_UNIX98	0x10	/* pty pair is Unix98 */
85 #define PTY_PKTMODE	0x20	/* pty side is in packet mode (TIOCPKT) */
86 
87 static pty_t pty_table[NR_PTYS];	/* PTY bookkeeping */
88 
89 static void pty_start(pty_t *pp);
90 static void pty_finish(pty_t *pp);
91 
92 static int pty_master_open(devminor_t minor, int access,
93 	endpoint_t user_endpt);
94 static int pty_master_close(devminor_t minor);
95 static ssize_t pty_master_read(devminor_t minor, u64_t position,
96 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
97 	cdev_id_t id);
98 static ssize_t pty_master_write(devminor_t minor, u64_t position,
99 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
100 	cdev_id_t id);
101 static int pty_master_ioctl(devminor_t minor, unsigned long request,
102 	endpoint_t endpt, cp_grant_id_t grant, int flags,
103 	endpoint_t user_endpt, cdev_id_t id);
104 static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id);
105 static int pty_master_select(devminor_t minor, unsigned int ops,
106 	endpoint_t endpt);
107 
108 static struct chardriver pty_master_tab = {
109   .cdr_open	= pty_master_open,
110   .cdr_close	= pty_master_close,
111   .cdr_read	= pty_master_read,
112   .cdr_write	= pty_master_write,
113   .cdr_ioctl	= pty_master_ioctl,
114   .cdr_cancel	= pty_master_cancel,
115   .cdr_select	= pty_master_select
116 };
117 
118 /*===========================================================================*
119  *				get_free_pty				     *
120  *===========================================================================*/
121 static tty_t *get_free_pty(void)
122 {
123 /* Return a pointer to a free tty structure, or NULL if no tty is free. */
124   tty_t *tp;
125   pty_t *pp;
126 
127   for (tp = &tty_table[0]; tp < &tty_table[NR_PTYS]; tp++) {
128 	pp = tp->tty_priv;
129 
130 	if (!(pp->state & (PTY_ACTIVE | TTY_ACTIVE)))
131 		return tp;
132   }
133 
134   return NULL;
135 }
136 
137 /*===========================================================================*
138  *				pty_master_open				     *
139  *===========================================================================*/
140 static int pty_master_open(devminor_t minor, int UNUSED(access),
141 	endpoint_t UNUSED(user_endpt))
142 {
143   tty_t *tp;
144   pty_t *pp;
145   int r;
146 
147   if (minor == PTMX_MINOR) {
148 	/* /dev/ptmx acts as a cloning device. We return a free PTY master and
149 	 * mark it as a UNIX98 type.
150 	 */
151 	if ((tp = get_free_pty()) == NULL)
152 		return EAGAIN; /* POSIX says this is the right error code */
153 
154 	/* The following call has two purposes. First, we check right here
155 	 * whether PTYFS is running at all; if not, the PTMX device cannot be
156 	 * opened at all and userland can fall back to other allocation
157 	 * methods right away. Second, in the exceptional case that the PTY
158 	 * service is restarted while PTYFS keeps running, PTYFS may expose
159 	 * stale slave nodes, which are a security hole if not removed as soon
160 	 * as a new PTY pair is allocated.
161 	 */
162 	if (ptyfs_clear(tp->tty_index) != OK)
163 		return EAGAIN;
164 
165 	pp = tp->tty_priv;
166 	pp->state |= PTY_UNIX98;
167 
168 	minor = UNIX98_MASTER(tp->tty_index);
169 
170 	r = CDEV_CLONED | minor;
171   } else {
172 	/* There is no way to open Unix98 masters directly, except by messing
173 	 * with mknod. We disallow such tricks altogether, and thus, the rest
174 	 * of the code deals with opening a non-Unix98 master only.
175 	 */
176 	if (minor < PTYPX_MINOR || minor >= PTYPX_MINOR + NR_PTYS)
177 		return EIO;
178 
179 	if ((tp = line2tty(minor)) == NULL)
180 		return ENXIO;
181 	pp = tp->tty_priv;
182 
183 	/* For non-Unix98 PTYs, we allow the slave to be opened before the
184 	 * master, but the master may be opened only once. This is how userland
185 	 * is able to find a free non-Unix98 PTY pair.
186 	 */
187 	if (pp->state & PTY_ACTIVE)
188 		return EIO;
189 	assert(!(pp->state & PTY_UNIX98));
190 
191 	r = OK;
192   }
193 
194   pp->state |= PTY_ACTIVE;
195 
196   pp->rdcum = 0;
197   pp->wrcum = 0;
198 
199   return r;
200 }
201 
202 /*===========================================================================*
203  *				pty_reset				     *
204  *===========================================================================*/
205 static void pty_reset(tty_t *tp)
206 {
207 /* Both sides of a PTY pair have been closed. Clean up its state. */
208   pty_t *pp;
209 
210   pp = tp->tty_priv;
211 
212   /* For Unix98 pairs, clean up the Unix98 slave node. It may never have been
213    * allocated, but we don't care. Ignore failures altogether.
214    */
215   if (pp->state & PTY_UNIX98)
216 	(void)ptyfs_clear(tp->tty_index);
217 
218   pp->state = 0;
219 }
220 
221 /*===========================================================================*
222  *				pty_master_close			     *
223  *===========================================================================*/
224 static int pty_master_close(devminor_t minor)
225 {
226   tty_t *tp;
227   pty_t *pp;
228 
229   if ((tp = line2tty(minor)) == NULL)
230 	return ENXIO;
231   pp = tp->tty_priv;
232 
233   if ((pp->state & (TTY_ACTIVE | TTY_CLOSED)) != TTY_ACTIVE) {
234 	pty_reset(tp);
235   } else {
236 	pp->state |= PTY_CLOSED;
237 	tp->tty_termios.c_ospeed = B0; /* cause EOF on slave side */
238 	sigchar(tp, SIGHUP, 1);
239   }
240 
241   return OK;
242 }
243 
244 /*===========================================================================*
245  *				pty_master_read				     *
246  *===========================================================================*/
247 static ssize_t pty_master_read(devminor_t minor, u64_t UNUSED(position),
248 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
249 	cdev_id_t id)
250 {
251   tty_t *tp;
252   pty_t *pp;
253   ssize_t r;
254 
255   if ((tp = line2tty(minor)) == NULL)
256 	return ENXIO;
257   pp = tp->tty_priv;
258 
259   /* Check, store information on the reader, do I/O. */
260   if (pp->state & TTY_CLOSED)
261 	return 0; /* EOF */
262 
263   if (pp->rdcaller != NONE || pp->rdleft != 0 || pp->rdcum != 0)
264 	return EIO;
265 
266   if (size <= 0)
267 	return EINVAL;
268 
269   pp->rdcaller = endpt;
270   pp->rdid = id;
271   pp->rdgrant = grant;
272   pp->rdleft = size;
273   pty_start(pp);
274 
275   handle_events(tp);
276 
277   if (pp->rdleft == 0) {
278 	pp->rdcaller = NONE;
279 	return EDONTREPLY;		/* already done */
280   }
281 
282   if (flags & CDEV_NONBLOCK) {
283 	r = pp->rdcum > 0 ? pp->rdcum : EAGAIN;
284 	pp->rdleft = pp->rdcum = 0;
285 	pp->rdcaller = NONE;
286 	return r;
287   }
288 
289   return EDONTREPLY;			/* do suspend */
290 }
291 
292 /*===========================================================================*
293  *				pty_master_write			     *
294  *===========================================================================*/
295 static ssize_t pty_master_write(devminor_t minor, u64_t UNUSED(position),
296 	endpoint_t endpt, cp_grant_id_t grant, size_t size, int flags,
297 	cdev_id_t id)
298 {
299   tty_t *tp;
300   pty_t *pp;
301   ssize_t r;
302 
303   if ((tp = line2tty(minor)) == NULL)
304 	return ENXIO;
305   pp = tp->tty_priv;
306 
307   /* Check, store information on the writer, do I/O. */
308   if (pp->state & TTY_CLOSED)
309 	return EIO;
310 
311   if (pp->wrcaller != NONE || pp->wrleft != 0 || pp->wrcum != 0)
312 	return EIO;
313 
314   if (size <= 0)
315 	return EINVAL;
316 
317   pp->wrcaller = endpt;
318   pp->wrid = id;
319   pp->wrgrant = grant;
320   pp->wrleft = size;
321 
322   handle_events(tp);
323 
324   if (pp->wrleft == 0) {
325 	pp->wrcaller = NONE;
326 	return EDONTREPLY;		/* already done */
327   }
328 
329   if (flags & CDEV_NONBLOCK) {
330 	r = pp->wrcum > 0 ? pp->wrcum : EAGAIN;
331 	pp->wrleft = pp->wrcum = 0;
332 	pp->wrcaller = NONE;
333 	return r;
334   }
335 
336   return EDONTREPLY;			/* do suspend */
337 }
338 
339 /*===========================================================================*
340  *				pty_master_ioctl			     *
341  *===========================================================================*/
342 static int pty_master_ioctl(devminor_t minor, unsigned long request,
343 	endpoint_t endpt, cp_grant_id_t grant, int flags,
344 	endpoint_t user_endpt, cdev_id_t id)
345 {
346   tty_t *tp;
347   pty_t *pp;
348   uid_t uid;
349   struct ptmget pm;
350   size_t len;
351   int r, val;
352 
353   if ((tp = line2tty(minor)) == NULL)
354 	return ENXIO;
355   pp = tp->tty_priv;
356 
357   /* Some IOCTLs are for the master side only. */
358   switch (request) {
359   case TIOCGRANTPT:	/* grantpt(3) */
360 	if (!(pp->state & PTY_UNIX98))
361 		break;
362 
363 	if ((int)(uid = getnuid(user_endpt)) == -1)
364 		return EACCES;
365 	if (tty_gid == -1) {
366 		printf("PTY: no tty group ID given at startup\n");
367 		return EACCES;
368 	}
369 
370 	/* Create or update the slave node. */
371 	if (ptyfs_set(tp->tty_index, UNIX98_MODE, uid, tty_gid,
372 	    makedev(PTY_MAJOR, UNIX98_SLAVE(tp->tty_index))) != OK)
373 		return EACCES;
374 
375 	return OK;
376 
377   case TIOCPTSNAME:	/* ptsname(3) */
378 	if (!(pp->state & PTY_UNIX98))
379 		break;
380 
381 	/* Since pm.sn is 16 bytes, we can have up to a million slaves. */
382 	memset(&pm, 0, sizeof(pm));
383 
384 	strlcpy(pm.sn, _PATH_DEV_PTS, sizeof(pm.sn));
385 	len = strlen(pm.sn);
386 
387 	if (ptyfs_name(tp->tty_index, &pm.sn[len], sizeof(pm.sn) - len) != OK)
388 		return EINVAL;
389 
390 	return sys_safecopyto(endpt, grant, 0, (vir_bytes)&pm, sizeof(pm));
391 
392   case TIOCPKT:
393 	r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes)&val, sizeof(val));
394 	if (r != OK)
395 		return r;
396 
397 	if (val)
398 		pp->state |= PTY_PKTMODE;
399 	else
400 		pp->state &= ~PTY_PKTMODE;
401 
402 	return OK;
403   }
404 
405   /* TODO: historically, all IOCTLs on the master are processed as if issued on
406    * the slave end. Make sure that this can not cause problems, in particular
407    * with blocking IOCTLs.
408    */
409   return tty_ioctl(minor, request, endpt, grant, flags, user_endpt, id);
410 }
411 
412 /*===========================================================================*
413  *				pty_master_cancel			     *
414  *===========================================================================*/
415 static int pty_master_cancel(devminor_t minor, endpoint_t endpt, cdev_id_t id)
416 {
417   tty_t *tp;
418   pty_t *pp;
419   int r;
420 
421   if ((tp = line2tty(minor)) == NULL)
422 	return ENXIO;
423   pp = tp->tty_priv;
424 
425   if (pp->rdcaller == endpt && pp->rdid == id) {
426 	/* Cancel a read from a PTY. */
427 	r = pp->rdcum > 0 ? pp->rdcum : EINTR;
428 	pp->rdleft = pp->rdcum = 0;
429 	pp->rdcaller = NONE;
430 	return r;
431   }
432 
433   if (pp->wrcaller == endpt && pp->wrid == id) {
434 	/* Cancel a write to a PTY. */
435 	r = pp->wrcum > 0 ? pp->wrcum : EINTR;
436 	pp->wrleft = pp->wrcum = 0;
437 	pp->wrcaller = NONE;
438 	return r;
439   }
440 
441   /* Request not found. */
442   return EDONTREPLY;
443 }
444 
445 /*===========================================================================*
446  *				select_try_pty				     *
447  *===========================================================================*/
448 static int select_try_pty(tty_t *tp, int ops)
449 {
450   pty_t *pp = tp->tty_priv;
451   int r = 0;
452 
453   if (ops & CDEV_OP_WR)  {
454 	/* Write won't block on error. */
455 	if (pp->state & TTY_CLOSED) r |= CDEV_OP_WR;
456 	else if (pp->wrleft != 0 || pp->wrcum != 0) r |= CDEV_OP_WR;
457 	else if (tp->tty_incount < buflen(tp->tty_inbuf)) r |= CDEV_OP_WR;
458   }
459 
460   if (ops & CDEV_OP_RD) {
461 	/* Read won't block on error. */
462 	if (pp->state & TTY_CLOSED) r |= CDEV_OP_RD;
463 	else if (pp->rdleft != 0 || pp->rdcum != 0) r |= CDEV_OP_RD;
464 	else if (pp->ocount > 0) r |= CDEV_OP_RD;	/* Actual data. */
465   }
466 
467   return r;
468 }
469 
470 /*===========================================================================*
471  *				select_retry_pty			     *
472  *===========================================================================*/
473 void select_retry_pty(tty_t *tp)
474 {
475   pty_t *pp = tp->tty_priv;
476   int r;
477 
478   /* See if the pty side of a pty is ready to return a select. */
479   if (pp->select_ops && (r = select_try_pty(tp, pp->select_ops))) {
480 	chardriver_reply_select(pp->select_proc, pp->select_minor, r);
481 	pp->select_ops &= ~r;
482   }
483 }
484 
485 /*===========================================================================*
486  *				pty_master_select			     *
487  *===========================================================================*/
488 static int pty_master_select(devminor_t minor, unsigned int ops,
489 	endpoint_t endpt)
490 {
491   tty_t *tp;
492   pty_t *pp;
493   int ready_ops, watch;
494 
495   if ((tp = line2tty(minor)) == NULL)
496 	return ENXIO;
497   pp = tp->tty_priv;
498 
499   watch = (ops & CDEV_NOTIFY);
500   ops &= (CDEV_OP_RD | CDEV_OP_WR | CDEV_OP_ERR);
501 
502   ready_ops = select_try_pty(tp, ops);
503 
504   ops &= ~ready_ops;
505   if (ops && watch) {
506 	pp->select_ops |= ops;
507 	pp->select_proc = endpt;
508 	pp->select_minor = minor;
509   }
510 
511   return ready_ops;
512 }
513 
514 /*===========================================================================*
515  *				do_pty					     *
516  *===========================================================================*/
517 void do_pty(message *m_ptr, int ipc_status)
518 {
519 /* Process a request for a PTY master (/dev/ptypX) device. */
520 
521   chardriver_process(&pty_master_tab, m_ptr, ipc_status);
522 }
523 
524 /*===========================================================================*
525  *				pty_slave_write				     *
526  *===========================================================================*/
527 static int pty_slave_write(tty_t *tp, int try)
528 {
529 /* (*dev_write)() routine for PTYs.  Transfer bytes from the writer on
530  * /dev/ttypX to the output buffer.
531  */
532   pty_t *pp = tp->tty_priv;
533   int count, ocount, s;
534 
535   /* PTY closed down? */
536   if (pp->state & PTY_CLOSED) {
537   	if (try) return 1;
538 	if (tp->tty_outleft > 0) {
539 		chardriver_reply_task(tp->tty_outcaller, tp->tty_outid, EIO);
540 		tp->tty_outleft = tp->tty_outcum = 0;
541 		tp->tty_outcaller = NONE;
542 	}
543 	return 0;
544   }
545 
546   /* While there is something to do. */
547   for (;;) {
548 	ocount = buflen(pp->obuf) - pp->ocount;
549 	if (try) return (ocount > 0);
550 	count = bufend(pp->obuf) - pp->ohead;
551 	if (count > ocount) count = ocount;
552 	if (count > tp->tty_outleft) count = tp->tty_outleft;
553 	if (count == 0 || tp->tty_inhibited)
554 		break;
555 
556 	/* Copy from user space to the PTY output buffer. */
557 	if (tp->tty_outcaller == KERNEL) {
558 		/* We're trying to print on kernel's behalf */
559 		memcpy(pp->ohead, (void *) tp->tty_outgrant + tp->tty_outcum,
560 			count);
561 	} else {
562 		if ((s = sys_safecopyfrom(tp->tty_outcaller, tp->tty_outgrant,
563 				tp->tty_outcum, (vir_bytes) pp->ohead,
564 				count)) != OK) {
565 			break;
566 		}
567 	}
568 
569 	/* Perform output processing on the output buffer. */
570 	out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
571 	if (count == 0) break;
572 
573 	/* Assume echoing messed up by output. */
574 	tp->tty_reprint = TRUE;
575 
576 	/* Bookkeeping. */
577 	pp->ocount += ocount;
578 	if ((pp->ohead += ocount) >= bufend(pp->obuf))
579 		pp->ohead -= buflen(pp->obuf);
580 	pty_start(pp);
581 
582 	tp->tty_outcum += count;
583 	if ((tp->tty_outleft -= count) == 0) {
584 		/* Output is finished, reply to the writer. */
585 		chardriver_reply_task(tp->tty_outcaller, tp->tty_outid,
586 			tp->tty_outcum);
587 		tp->tty_outcum = 0;
588 		tp->tty_outcaller = NONE;
589 	}
590   }
591   pty_finish(pp);
592   return 1;
593 }
594 
595 /*===========================================================================*
596  *				pty_slave_echo				     *
597  *===========================================================================*/
598 static void pty_slave_echo(tty_t *tp, int c)
599 {
600 /* Echo one character.  (Like pty_write, but only one character, optionally.) */
601 
602   pty_t *pp = tp->tty_priv;
603   int count, ocount;
604 
605   ocount = buflen(pp->obuf) - pp->ocount;
606   if (ocount == 0) return;		/* output buffer full */
607   count = 1;
608   *pp->ohead = c;			/* add one character */
609 
610   out_process(tp, pp->obuf, pp->ohead, bufend(pp->obuf), &count, &ocount);
611   if (count == 0) return;
612 
613   pp->ocount += ocount;
614   if ((pp->ohead += ocount) >= bufend(pp->obuf)) pp->ohead -= buflen(pp->obuf);
615   pty_start(pp);
616 }
617 
618 /*===========================================================================*
619  *				pty_start				     *
620  *===========================================================================*/
621 static void pty_start(pty_t *pp)
622 {
623 /* Transfer bytes written to the output buffer to the PTY reader. */
624   int count;
625   char c;
626 
627   /* While there are things to do. */
628   for (;;) {
629 	count = bufend(pp->obuf) - pp->otail;
630 	if (count > pp->ocount) count = pp->ocount;
631 	if (count == 0 || pp->rdleft == 0) break;
632 
633 	/* If there is output at all, and packet mode is enabled, then prepend
634 	 * the output with a zero byte. This is absolutely minimal "support"
635 	 * for the TIOCPKT receipt mode to get telnetd(8) going. Implementing
636 	 * full support for all the TIOCPKT bits will require more work.
637 	 */
638 	if (pp->rdcum == 0 && (pp->state & PTY_PKTMODE)) {
639 		c = 0;
640 		if (sys_safecopyto(pp->rdcaller, pp->rdgrant, 0, (vir_bytes)&c,
641 		    sizeof(c)) != OK)
642 			break;
643 
644 		pp->rdcum++;
645 		pp->rdleft--;
646 	}
647 
648 	if (count > pp->rdleft) count = pp->rdleft;
649 	if (count == 0) break;
650 
651 	/* Copy from the output buffer to the readers address space. */
652 	if (sys_safecopyto(pp->rdcaller, pp->rdgrant, pp->rdcum,
653 	    (vir_bytes)pp->otail, count) != OK)
654 		break;
655 
656 	/* Bookkeeping. */
657 	pp->ocount -= count;
658 	if ((pp->otail += count) == bufend(pp->obuf)) pp->otail = pp->obuf;
659 	pp->rdcum += count;
660 	pp->rdleft -= count;
661   }
662 }
663 
664 /*===========================================================================*
665  *				pty_finish				     *
666  *===========================================================================*/
667 static void pty_finish(pty_t *pp)
668 {
669 /* Finish the read request of a PTY reader if there is at least one byte
670  * transferred.
671  */
672 
673   if (pp->rdcum > 0) {
674 	chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum);
675 	pp->rdleft = pp->rdcum = 0;
676 	pp->rdcaller = NONE;
677   }
678 }
679 
680 /*===========================================================================*
681  *				pty_slave_read				     *
682  *===========================================================================*/
683 static int pty_slave_read(tty_t *tp, int try)
684 {
685 /* Offer bytes from the PTY writer for input on the TTY.  (Do it one byte at
686  * a time, 99% of the writes will be for one byte, so no sense in being smart.)
687  */
688   pty_t *pp = tp->tty_priv;
689   char c;
690 
691   if (pp->state & PTY_CLOSED) {
692 	if (try) return 1;
693 	if (tp->tty_inleft > 0) {
694 		chardriver_reply_task(tp->tty_incaller, tp->tty_inid,
695 			tp->tty_incum);
696 		tp->tty_inleft = tp->tty_incum = 0;
697 		tp->tty_incaller = NONE;
698 	}
699 	return 1;
700   }
701 
702   if (try) {
703   	if (pp->wrleft > 0)
704   		return 1;
705   	return 0;
706   }
707 
708   while (pp->wrleft > 0) {
709   	int s;
710 
711 	/* Transfer one character to 'c'. */
712 	if ((s = sys_safecopyfrom(pp->wrcaller, pp->wrgrant, pp->wrcum,
713 		(vir_bytes) &c, 1)) != OK) {
714 		printf("pty: safecopy failed (error %d)\n", s);
715 		break;
716 	}
717 
718 	/* Input processing. */
719 	if (in_process(tp, &c, 1) == 0) break;
720 
721 	/* PTY writer bookkeeping. */
722 	pp->wrcum++;
723 	if (--pp->wrleft == 0) {
724 		chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
725 		pp->wrcum = 0;
726 		pp->wrcaller = NONE;
727 	}
728   }
729 
730   return 0;
731 }
732 
733 /*===========================================================================*
734  *				pty_slave_mayopen			     *
735  *===========================================================================*/
736 static int pty_slave_mayopen(tty_t *tp, devminor_t line)
737 {
738 /* Check if the user is not mixing Unix98 and non-Unix98 terminal ends. */
739   pty_t *pp;
740   int unix98_line, unix98_pty;
741 
742   pp = tp->tty_priv;
743 
744   /* A non-Unix98 slave may be opened even if the corresponding master is not
745    * opened yet, but PTY_UNIX98 is always clear for free ptys.  A Unix98 slave
746    * may not be opened before its master, but this should not occur anyway.
747    */
748   unix98_line = (line >= UNIX98_MINOR && line < UNIX98_MINOR + NR_PTYS * 2);
749   unix98_pty = !!(pp->state & PTY_UNIX98);
750 
751   return (unix98_line == unix98_pty);
752 }
753 
754 /*===========================================================================*
755  *				pty_slave_open				     *
756  *===========================================================================*/
757 static int pty_slave_open(tty_t *tp, int UNUSED(try))
758 {
759 /* The tty side has been opened. */
760   pty_t *pp = tp->tty_priv;
761 
762   /* TTY_ACTIVE may already be set, which would indicate that the slave is
763    * reopened after being fully closed while the master is still open. In that
764    * case TTY_CLOSED will also be set, so clear that one.
765    */
766   pp->state |= TTY_ACTIVE;
767   pp->state &= ~TTY_CLOSED;
768 
769   return 0;
770 }
771 
772 /*===========================================================================*
773  *				pty_slave_close				     *
774  *===========================================================================*/
775 static int pty_slave_close(tty_t *tp, int UNUSED(try))
776 {
777 /* The tty side has closed, so shut down the pty side. */
778   pty_t *pp = tp->tty_priv;
779 
780   if (!(pp->state & PTY_ACTIVE)) return 0;
781 
782   if (pp->rdleft > 0) {
783 	chardriver_reply_task(pp->rdcaller, pp->rdid, pp->rdcum);
784 	pp->rdleft = pp->rdcum = 0;
785 	pp->rdcaller = NONE;
786   }
787 
788   if (pp->wrleft > 0) {
789 	chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum);
790 	pp->wrleft = pp->wrcum = 0;
791 	pp->wrcaller = NONE;
792   }
793 
794   if (pp->state & PTY_CLOSED) pty_reset(tp);
795   else pp->state |= TTY_CLOSED;
796 
797   return 0;
798 }
799 
800 /*===========================================================================*
801  *				pty_slave_icancel			     *
802  *===========================================================================*/
803 static int pty_slave_icancel(tty_t *tp, int UNUSED(try))
804 {
805 /* Discard waiting input. */
806   pty_t *pp = tp->tty_priv;
807 
808   if (pp->wrleft > 0) {
809 	chardriver_reply_task(pp->wrcaller, pp->wrid, pp->wrcum + pp->wrleft);
810 	pp->wrcum = pp->wrleft = 0;
811 	pp->wrcaller = NONE;
812   }
813 
814   return 0;
815 }
816 
817 /*===========================================================================*
818  *				pty_slave_ocancel			     *
819  *===========================================================================*/
820 static int pty_slave_ocancel(tty_t *tp, int UNUSED(try))
821 {
822 /* Drain the output buffer. */
823   pty_t *pp = tp->tty_priv;
824 
825   pp->ocount = 0;
826   pp->otail = pp->ohead;
827 
828   return 0;
829 }
830 
831 /*===========================================================================*
832  *				pty_init				     *
833  *===========================================================================*/
834 void pty_init(tty_t *tp)
835 {
836   pty_t *pp;
837   int line;
838 
839   /* Associate PTY and TTY structures. */
840   line = tp - tty_table;
841   pp = tp->tty_priv = &pty_table[line];
842   pp->tty = tp;
843   pp->select_ops = 0;
844   pp->rdcaller = NONE;
845   pp->wrcaller = NONE;
846 
847   /* Set up output queue. */
848   pp->ohead = pp->otail = pp->obuf;
849 
850   /* Fill in TTY function hooks. */
851   tp->tty_devread = pty_slave_read;
852   tp->tty_devwrite = pty_slave_write;
853   tp->tty_echo = pty_slave_echo;
854   tp->tty_icancel = pty_slave_icancel;
855   tp->tty_ocancel = pty_slave_ocancel;
856   tp->tty_mayopen = pty_slave_mayopen;
857   tp->tty_open = pty_slave_open;
858   tp->tty_close = pty_slave_close;
859   tp->tty_select_ops = 0;
860 }
861