summaryrefslogtreecommitdiff
path: root/regress/sys/kern/kqueue/kqueue-pty.c
blob: 6b72ed5e288a3f83262e57d23434170e8d7b74be (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*	$OpenBSD: kqueue-pty.c,v 1.8 2016/09/21 15:26:54 bluhm Exp $	*/

/*	Written by Michael Shalayeff, 2003, Public Domain	*/

#include <sys/types.h>
#include <sys/time.h>
#include <sys/event.h>

#include <err.h>
#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <termios.h>
#include <unistd.h>
#include <util.h>

#include "main.h"

static int
pty_check(int kq, struct kevent *ev, int n, int rm, int rs, int wm, int ws)
{
	struct timespec ts;
	int i;

	ts.tv_sec = 0;
	ts.tv_nsec = 0;
	if ((n = kevent(kq, NULL, 0, ev, n, &ts)) < 0)
		err(1, "slave: kevent");

	ASSX(n != 0);

	for (i = 0; i < n; i++, ev++) {
		if (ev->filter == EVFILT_READ) {
			ASSX(ev->ident != -rm);
			ASSX(ev->ident != -rs);
			if (ev->ident == rm)
				rm = 0;
			if (ev->ident == rs)
				rs = 0;
		} else if (ev->filter == EVFILT_WRITE) {
			ASSX(ev->ident != -wm);
			ASSX(ev->ident != -ws);
			if (ev->ident == wm)
				wm = 0;
			if (ev->ident == ws)
				ws = 0;
		} else
			errx(1, "unknown event");
	}
	ASSX(rm <= 0);
	ASSX(rs <= 0);
	ASSX(wm <= 0);
	ASSX(ws <= 0);

	return (0);
}

int
do_pty(void)
{
	struct kevent ev[4];
	struct termios tt;
	int fd, kq, massa, slave;
	char buf[1024];

	ASS((fd = open("/dev/console", O_RDONLY, &tt)) > 0,
	    warn("open /dev/console"));
	ASS(tcgetattr(fd, &tt) == 0,
	    warn("tcgetattr"));
	cfmakeraw(&tt);
	tt.c_lflag &= ~ECHO;
	if (openpty(&massa, &slave, NULL, &tt, NULL) < 0)
		err(1, "openpty");
	if (fcntl(massa, F_SETFL, O_NONBLOCK) < 0)
		err(1, "massa: fcntl");
	if (fcntl(slave, F_SETFL, O_NONBLOCK) < 0)
		err(1, "massa: fcntl");
	if ((kq = kqueue()) == -1)
		err(1, "kqueue");

	/* test the read from the slave works */
	EV_SET(&ev[0], massa, EVFILT_READ,  EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[1], massa, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[2], slave, EVFILT_READ,  EV_ADD|EV_ENABLE, 0, 0, NULL);
	EV_SET(&ev[3], slave, EVFILT_WRITE, EV_ADD|EV_ENABLE, 0, 0, NULL);
	if (kevent(kq, ev, 4, NULL, 0, NULL) < 0)
		err(1, "slave: kevent add");

	memset(buf, 0, sizeof(buf));

	ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);

	if (write(massa, " ", 1) != 1)
		err(1, "massa: write");

	ASSX(pty_check(kq, ev, 4, -massa, slave, massa, slave) == 0);

	read(slave, buf, sizeof(buf));

	ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);

	while (write(massa, buf, sizeof(buf)) > 0)
		continue;

	ASSX(pty_check(kq, ev, 4, -massa, slave, -massa, slave) == 0);

	read(slave, buf, 1);

	ASSX(pty_check(kq, ev, 4, -massa, slave, massa, slave) == 0);

	while (read(slave, buf, sizeof(buf)) > 0)
		continue;

	ASSX(pty_check(kq, ev, 4, -massa, -slave, massa, slave) == 0);

	return (0);
}