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