1 /* $OpenBSD: kqueue-pty.c,v 1.10 2019/03/04 19:35:28 anton Exp $ */
2
3 /* Written by Michael Shalayeff, 2003, Public Domain */
4
5 #include <sys/types.h>
6 #include <sys/time.h>
7 #include <sys/event.h>
8
9 #include <err.h>
10 #include <fcntl.h>
11 #include <stdio.h>
12 #include <string.h>
13 #include <termios.h>
14 #include <unistd.h>
15 #include <util.h>
16
17 #include "main.h"
18
19 static int
pty_check(int kq,struct kevent * ev,int n,int rm,int rs,int wm,int ws)20 pty_check(int kq, struct kevent *ev, int n, int rm, int rs, int wm, int ws)
21 {
22 struct timespec ts;
23 int i;
24
25 ts.tv_sec = 0;
26 ts.tv_nsec = 0;
27 if ((n = kevent(kq, NULL, 0, ev, n, &ts)) < 0)
28 err(1, "slave: kevent");
29
30 ASSX(n != 0);
31
32 for (i = 0; i < n; i++, ev++) {
33 if (ev->filter == EVFILT_READ) {
34 ASSX(ev->ident != -rm);
35 ASSX(ev->ident != -rs);
36 if (ev->ident == rm)
37 rm = 0;
38 if (ev->ident == rs)
39 rs = 0;
40 } else if (ev->filter == EVFILT_WRITE) {
41 ASSX(ev->ident != -wm);
42 ASSX(ev->ident != -ws);
43 if (ev->ident == wm)
44 wm = 0;
45 if (ev->ident == ws)
46 ws = 0;
47 } else
48 errx(1, "unknown event");
49 }
50 ASSX(rm <= 0);
51 ASSX(rs <= 0);
52 ASSX(wm <= 0);
53 ASSX(ws <= 0);
54
55 return (0);
56 }
57
58 static int
pty_rdrw(void)59 pty_rdrw(void)
60 {
61 struct kevent ev[4];
62 struct termios tt;
63 int fd, kq, massa, slave;
64 char buf[1024];
65
66 ASS((fd = open("/dev/console", O_RDONLY, &tt)) > 0,
67 warn("open /dev/console"));
68 ASS(tcgetattr(fd, &tt) == 0,
69 warn("tcgetattr"));
70 cfmakeraw(&tt);
71 tt.c_lflag &= ~ECHO;
72 if (openpty(&massa, &slave, NULL, &tt, NULL) < 0)
73 err(1, "openpty");
74 if (fcntl(massa, F_SETFL, O_NONBLOCK) < 0)
75 err(1, "massa: fcntl");
76 if (fcntl(slave, F_SETFL, O_NONBLOCK) < 0)
77 err(1, "massa: fcntl");
78 if ((kq = kqueue()) == -1)
79 err(1, "kqueue");
80
81 /* test the read from the slave works */
82 EV_SET(&ev[0], massa, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, NULL);
83 EV_SET(&ev[1], massa, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
84 EV_SET(&ev[2], slave, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, NULL);
85 EV_SET(&ev[3], slave, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
86 if (kevent(kq, ev, 4, NULL, 0, NULL) < 0)
87 err(1, "slave: kevent add");
88
89 memset(buf, 0, sizeof(buf));
90
91 ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);
92
93 if (write(massa, " ", 1) != 1)
94 err(1, "massa: write");
95
96 ASSX(pty_check(kq, ev, 4, -massa, slave, massa, slave) == 0);
97
98 read(slave, buf, sizeof(buf));
99
100 ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);
101
102 while (write(massa, buf, sizeof(buf)) > 0)
103 continue;
104
105 ASSX(pty_check(kq, ev, 4, -massa, slave, -massa, slave) == 0);
106
107 read(slave, buf, 1);
108
109 ASSX(pty_check(kq, ev, 4, -massa, slave, massa, slave) == 0);
110
111 while (read(slave, buf, sizeof(buf)) > 0)
112 continue;
113
114 ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);
115
116 return (0);
117 }
118
119 static int
pty_close(void)120 pty_close(void)
121 {
122 struct kevent ev[1];
123 struct timespec ts;
124 int kq, massa, n, slave;
125
126 if (openpty(&massa, &slave, NULL, NULL, NULL) == -1)
127 err(1, "openpty");
128
129 kq = kqueue();
130 if (kq == -1)
131 err(1, "kqueue");
132
133 EV_SET(&ev[0], massa, EVFILT_READ, EV_ADD|EV_ENABLE, 0, 0, NULL);
134 if (kevent(kq, ev, 1, NULL, 0, NULL) == -1)
135 err(1, "kevent: add");
136
137 close(slave);
138
139 ts.tv_sec = 5;
140 ts.tv_nsec = 0;
141 n = kevent(kq, NULL, 0, ev, 1, &ts);
142 ASSX(n == 1);
143 ASSX(ev[0].filter == EVFILT_READ);
144 ASSX(ev[0].flags & EV_EOF);
145
146 return 0;
147 }
148
149 int
do_pty(int n)150 do_pty(int n)
151 {
152 switch (n) {
153 case 1:
154 return pty_rdrw();
155 case 2:
156 return pty_close();
157 default:
158 errx(1, "unknown pty test number %d", n);
159 }
160 }
161