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 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 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 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 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