1*7a7077c0Santon /* $OpenBSD: pty.c,v 1.1 2024/06/03 08:02:22 anton Exp $ */
2*7a7077c0Santon
3*7a7077c0Santon #include <sys/ioctl.h>
4*7a7077c0Santon
5*7a7077c0Santon #include <err.h>
6*7a7077c0Santon #include <fcntl.h>
7*7a7077c0Santon #include <stdlib.h>
8*7a7077c0Santon #include <unistd.h>
9*7a7077c0Santon
10*7a7077c0Santon #include "pty.h"
11*7a7077c0Santon
12*7a7077c0Santon int
pty_open(struct pty * pty)13*7a7077c0Santon pty_open(struct pty *pty)
14*7a7077c0Santon {
15*7a7077c0Santon int master, slave;
16*7a7077c0Santon
17*7a7077c0Santon master = posix_openpt(O_RDWR);
18*7a7077c0Santon if (master == -1) {
19*7a7077c0Santon warn("posix_openpt");
20*7a7077c0Santon return 1;
21*7a7077c0Santon }
22*7a7077c0Santon if (grantpt(master) == -1) {
23*7a7077c0Santon warn("grantpt");
24*7a7077c0Santon return 1;
25*7a7077c0Santon }
26*7a7077c0Santon if (unlockpt(master) == -1) {
27*7a7077c0Santon warn("unlockpt");
28*7a7077c0Santon return 1;
29*7a7077c0Santon }
30*7a7077c0Santon
31*7a7077c0Santon slave = open(ptsname(master), O_RDWR);
32*7a7077c0Santon if (slave == -1) {
33*7a7077c0Santon warn("%s", ptsname(master));
34*7a7077c0Santon return 1;
35*7a7077c0Santon }
36*7a7077c0Santon
37*7a7077c0Santon pty->master = master;
38*7a7077c0Santon pty->slave = slave;
39*7a7077c0Santon return 0;
40*7a7077c0Santon }
41*7a7077c0Santon
42*7a7077c0Santon void
pty_close(struct pty * pty)43*7a7077c0Santon pty_close(struct pty *pty)
44*7a7077c0Santon {
45*7a7077c0Santon close(pty->slave);
46*7a7077c0Santon close(pty->master);
47*7a7077c0Santon }
48*7a7077c0Santon
49*7a7077c0Santon /*
50*7a7077c0Santon * Disconnect the controlling tty, if present.
51*7a7077c0Santon */
52*7a7077c0Santon int
pty_detach(struct pty * pty)53*7a7077c0Santon pty_detach(struct pty *pty)
54*7a7077c0Santon {
55*7a7077c0Santon int fd;
56*7a7077c0Santon
57*7a7077c0Santon fd = open("/dev/tty", O_RDWR | O_NOCTTY);
58*7a7077c0Santon if (fd >= 0) {
59*7a7077c0Santon (void)ioctl(fd, TIOCNOTTY, NULL);
60*7a7077c0Santon close(fd);
61*7a7077c0Santon }
62*7a7077c0Santon return 0;
63*7a7077c0Santon }
64*7a7077c0Santon
65*7a7077c0Santon /*
66*7a7077c0Santon * Connect the slave as the controlling tty.
67*7a7077c0Santon */
68*7a7077c0Santon int
pty_attach(struct pty * pty)69*7a7077c0Santon pty_attach(struct pty *pty)
70*7a7077c0Santon {
71*7a7077c0Santon if (ioctl(pty->slave, TIOCSCTTY, NULL) == -1) {
72*7a7077c0Santon warn("TIOCSCTTY");
73*7a7077c0Santon return 1;
74*7a7077c0Santon }
75*7a7077c0Santon return 0;
76*7a7077c0Santon }
77*7a7077c0Santon
78*7a7077c0Santon int
pty_drain(struct pty * pty)79*7a7077c0Santon pty_drain(struct pty *pty)
80*7a7077c0Santon {
81*7a7077c0Santon for (;;) {
82*7a7077c0Santon char *buf = &pty->buf.storage[pty->buf.len];
83*7a7077c0Santon size_t bufsize = sizeof(pty->buf.storage) - pty->buf.len;
84*7a7077c0Santon ssize_t n;
85*7a7077c0Santon
86*7a7077c0Santon n = read(pty->master, buf, bufsize);
87*7a7077c0Santon if (n == -1) {
88*7a7077c0Santon warn("read");
89*7a7077c0Santon return 1;
90*7a7077c0Santon }
91*7a7077c0Santon if (n == 0)
92*7a7077c0Santon break;
93*7a7077c0Santon
94*7a7077c0Santon /* Ensure space for NUL-terminator. */
95*7a7077c0Santon if ((size_t)n >= bufsize) {
96*7a7077c0Santon warnx("pty buffer too small");
97*7a7077c0Santon return 1;
98*7a7077c0Santon }
99*7a7077c0Santon pty->buf.len += n;
100*7a7077c0Santon }
101*7a7077c0Santon
102*7a7077c0Santon return 0;
103*7a7077c0Santon }
104