1433d6423SLionel Sambuc /* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */
2*da21d850SDavid van Moolenbroek /*
3*da21d850SDavid van Moolenbroek * As of the introduction of Unix98 PTY support, this test set actually relies
4*da21d850SDavid van Moolenbroek * on the ability to create Unix98 PTYs. The system still supports old-style
5*da21d850SDavid van Moolenbroek * PTYs but there is no way to force openpty(3) to use them. However, part of
6*da21d850SDavid van Moolenbroek * this test set can still be used to test old-style PTYs: first disable Unix98
7*da21d850SDavid van Moolenbroek * PTYs, for example by unmounting PTYFS or temporarily removing /dev/ptmx, and
8*da21d850SDavid van Moolenbroek * then run the a-f subtests from this test set as root.
9*da21d850SDavid van Moolenbroek */
10433d6423SLionel Sambuc #include <stdlib.h>
11433d6423SLionel Sambuc #include <stdio.h>
12433d6423SLionel Sambuc #include <string.h>
13433d6423SLionel Sambuc #include <signal.h>
14433d6423SLionel Sambuc #include <termios.h>
15433d6423SLionel Sambuc #include <sys/wait.h>
16433d6423SLionel Sambuc #include <sys/syslimits.h>
17433d6423SLionel Sambuc #include <paths.h>
18*da21d850SDavid van Moolenbroek #include <dirent.h>
19*da21d850SDavid van Moolenbroek #include <grp.h>
20433d6423SLionel Sambuc #include <fcntl.h>
21433d6423SLionel Sambuc #include <util.h>
22433d6423SLionel Sambuc
23433d6423SLionel Sambuc #define ITERATIONS 10
24433d6423SLionel Sambuc
25*da21d850SDavid van Moolenbroek #define MIN_PTYS 4
26*da21d850SDavid van Moolenbroek
27433d6423SLionel Sambuc #include "common.h"
28433d6423SLionel Sambuc
29433d6423SLionel Sambuc static int sighups; /* number of SIGHUP signals received */
30433d6423SLionel Sambuc
31433d6423SLionel Sambuc /*
32433d6423SLionel Sambuc * Signal handler for SIGHUP and SIGUSR1.
33433d6423SLionel Sambuc */
34673c4e01SDavid van Moolenbroek static void
signal_handler(int sig)35433d6423SLionel Sambuc signal_handler(int sig)
36433d6423SLionel Sambuc {
37433d6423SLionel Sambuc if (sig == SIGHUP)
38433d6423SLionel Sambuc sighups++;
39433d6423SLionel Sambuc }
40433d6423SLionel Sambuc
41433d6423SLionel Sambuc /*
42433d6423SLionel Sambuc * Set the slave side of the pseudo terminal to raw mode. This simplifies
43433d6423SLionel Sambuc * testing communication.
44433d6423SLionel Sambuc */
45433d6423SLionel Sambuc static void
make_raw(int slavefd)46433d6423SLionel Sambuc make_raw(int slavefd)
47433d6423SLionel Sambuc {
48433d6423SLionel Sambuc struct termios tios;
49433d6423SLionel Sambuc
50*da21d850SDavid van Moolenbroek if (tcgetattr(slavefd, &tios) < 0) e(0);
51433d6423SLionel Sambuc
52433d6423SLionel Sambuc cfmakeraw(&tios);
53433d6423SLionel Sambuc
54*da21d850SDavid van Moolenbroek if (tcsetattr(slavefd, TCSANOW, &tios) < 0) e(0);
55433d6423SLionel Sambuc }
56433d6423SLionel Sambuc
57433d6423SLionel Sambuc /*
58433d6423SLionel Sambuc * See if the given pseudo terminal can successfully perform basic
59433d6423SLionel Sambuc * communication between master and slave.
60433d6423SLionel Sambuc */
61433d6423SLionel Sambuc static void
test_comm(int masterfd,int slavefd)62433d6423SLionel Sambuc test_comm(int masterfd, int slavefd)
63433d6423SLionel Sambuc {
64433d6423SLionel Sambuc char c;
65433d6423SLionel Sambuc
66433d6423SLionel Sambuc make_raw(slavefd);
67433d6423SLionel Sambuc
68433d6423SLionel Sambuc c = 'A';
69*da21d850SDavid van Moolenbroek if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
70*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
71*da21d850SDavid van Moolenbroek if (c != 'A') e(0);
72433d6423SLionel Sambuc
73433d6423SLionel Sambuc c = 'B';
74*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
75*da21d850SDavid van Moolenbroek if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
76*da21d850SDavid van Moolenbroek if (c != 'B') e(0);
77433d6423SLionel Sambuc
78433d6423SLionel Sambuc c = 'C';
79*da21d850SDavid van Moolenbroek if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
80*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
81*da21d850SDavid van Moolenbroek if (c != 'C') e(0);
82433d6423SLionel Sambuc
83433d6423SLionel Sambuc c = 'D';
84*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
85*da21d850SDavid van Moolenbroek if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
86*da21d850SDavid van Moolenbroek if (c != 'D') e(0);
87433d6423SLionel Sambuc }
88433d6423SLionel Sambuc
89433d6423SLionel Sambuc /*
90*da21d850SDavid van Moolenbroek * Obtain a pseudo terminal. The master end is opened and its file descriptor
91*da21d850SDavid van Moolenbroek * stored in 'pfd'. The slave path name is stored in 'tname'. For old-style
92*da21d850SDavid van Moolenbroek * PTYs, the function returns 1 and stores the master name in 'pname' if not
93*da21d850SDavid van Moolenbroek * NULL. For Unix98 PTYs, the function returns 0, in which case no master name
94*da21d850SDavid van Moolenbroek * is available. For old-style PTYs, the caller may close and reopen the
95*da21d850SDavid van Moolenbroek * master. In that case, we make the assumption that nobody snatches the pair
96*da21d850SDavid van Moolenbroek * while we are running. For Unix98 PTYs, the master must be kept open.
97433d6423SLionel Sambuc */
98*da21d850SDavid van Moolenbroek static int
get_pty(int * pfd,char pname[PATH_MAX],char tname[PATH_MAX])99*da21d850SDavid van Moolenbroek get_pty(int *pfd, char pname[PATH_MAX], char tname[PATH_MAX])
100433d6423SLionel Sambuc {
101*da21d850SDavid van Moolenbroek char *name;
102433d6423SLionel Sambuc int len, masterfd, slavefd;
103433d6423SLionel Sambuc
104433d6423SLionel Sambuc /*
105*da21d850SDavid van Moolenbroek * First try Unix98 PTY allocation, mainly to avoid opening the slave
106*da21d850SDavid van Moolenbroek * end immediately. If this fails, try openpty(3) as well.
107433d6423SLionel Sambuc */
108*da21d850SDavid van Moolenbroek if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) != -1) {
109*da21d850SDavid van Moolenbroek if (grantpt(masterfd) != -1 && unlockpt(masterfd) != -1 &&
110*da21d850SDavid van Moolenbroek (name = ptsname(masterfd)) != NULL) {
111*da21d850SDavid van Moolenbroek *pfd = masterfd;
112*da21d850SDavid van Moolenbroek strlcpy(tname, name, PATH_MAX);
113433d6423SLionel Sambuc
114*da21d850SDavid van Moolenbroek return 0;
115*da21d850SDavid van Moolenbroek }
116*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
117*da21d850SDavid van Moolenbroek }
118433d6423SLionel Sambuc
119*da21d850SDavid van Moolenbroek if (openpty(&masterfd, &slavefd, tname, NULL, NULL) < 0) e(0);
120433d6423SLionel Sambuc
121433d6423SLionel Sambuc test_comm(masterfd, slavefd);
122433d6423SLionel Sambuc
123*da21d850SDavid van Moolenbroek *pfd = masterfd;
124*da21d850SDavid van Moolenbroek
125*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
126*da21d850SDavid van Moolenbroek
127*da21d850SDavid van Moolenbroek /*
128*da21d850SDavid van Moolenbroek * openpty(3) gives us only the slave name, but we also want the master
129*da21d850SDavid van Moolenbroek * name.
130*da21d850SDavid van Moolenbroek */
131*da21d850SDavid van Moolenbroek len = strlen(_PATH_DEV);
132*da21d850SDavid van Moolenbroek if (strncmp(tname, _PATH_DEV, len)) e(0);
133*da21d850SDavid van Moolenbroek
134*da21d850SDavid van Moolenbroek if (strncmp(&tname[len], "tty", 3))
135*da21d850SDavid van Moolenbroek return 0; /* Unix98 after all? Well okay, whatever.. */
136*da21d850SDavid van Moolenbroek
137*da21d850SDavid van Moolenbroek if (pname != NULL) {
138*da21d850SDavid van Moolenbroek strlcpy(pname, tname, PATH_MAX);
139*da21d850SDavid van Moolenbroek pname[len] = 'p';
140*da21d850SDavid van Moolenbroek }
141*da21d850SDavid van Moolenbroek
142*da21d850SDavid van Moolenbroek return 1;
143433d6423SLionel Sambuc }
144433d6423SLionel Sambuc
145433d6423SLionel Sambuc /*
146433d6423SLionel Sambuc * Test various orders of opening and closing the master and slave sides of a
147433d6423SLionel Sambuc * pseudo terminal, as well as opening/closing one side without ever opening
148*da21d850SDavid van Moolenbroek * the other. This test is meaningful mainly for old-style pseudoterminals.
149433d6423SLionel Sambuc */
150433d6423SLionel Sambuc static void
test77a(void)151433d6423SLionel Sambuc test77a(void)
152433d6423SLionel Sambuc {
153433d6423SLionel Sambuc struct sigaction act, oact;
154433d6423SLionel Sambuc char pname[PATH_MAX], tname[PATH_MAX];
155*da21d850SDavid van Moolenbroek int oldstyle, masterfd, slavefd;
156433d6423SLionel Sambuc
157433d6423SLionel Sambuc subtest = 1;
158433d6423SLionel Sambuc
159433d6423SLionel Sambuc /* We do not want to get SIGHUP signals in this test. */
160433d6423SLionel Sambuc memset(&act, 0, sizeof(act));
161433d6423SLionel Sambuc act.sa_handler = SIG_IGN;
162*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &act, &oact) < 0) e(0);
163433d6423SLionel Sambuc
164*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
165*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
166433d6423SLionel Sambuc
167*da21d850SDavid van Moolenbroek if (oldstyle) {
168*da21d850SDavid van Moolenbroek /* Try closing the master. */
169*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
170433d6423SLionel Sambuc
171*da21d850SDavid van Moolenbroek /* See if we can reopen the master. */
172*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
173*da21d850SDavid van Moolenbroek }
174433d6423SLionel Sambuc
175*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
176433d6423SLionel Sambuc
177433d6423SLionel Sambuc test_comm(masterfd, slavefd);
178433d6423SLionel Sambuc
179433d6423SLionel Sambuc /* In the meantime, test different closing orders. This is order A. */
180*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
181*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
182433d6423SLionel Sambuc
183*da21d850SDavid van Moolenbroek /* Now try opening the pair (or a new pair) again. */
184*da21d850SDavid van Moolenbroek if (!oldstyle)
185*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
186*da21d850SDavid van Moolenbroek else
187*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
188*da21d850SDavid van Moolenbroek
189*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
190433d6423SLionel Sambuc
191433d6423SLionel Sambuc test_comm(masterfd, slavefd);
192433d6423SLionel Sambuc
193*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
194433d6423SLionel Sambuc
195433d6423SLionel Sambuc /*
196433d6423SLionel Sambuc * Try reopening the slave after closing it. It is not very important
197433d6423SLionel Sambuc * that this works, but the TTY driver should currently support it.
198433d6423SLionel Sambuc */
199*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
200433d6423SLionel Sambuc
201433d6423SLionel Sambuc test_comm(masterfd, slavefd);
202433d6423SLionel Sambuc
203433d6423SLionel Sambuc /* This is closing order B. This may or may not cause a SIGHUP. */
204*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
205*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
206433d6423SLionel Sambuc
207433d6423SLionel Sambuc /* Try the normal open procedure. */
208*da21d850SDavid van Moolenbroek if (!oldstyle)
209*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
210*da21d850SDavid van Moolenbroek else
211*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
212*da21d850SDavid van Moolenbroek
213*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
214433d6423SLionel Sambuc
215433d6423SLionel Sambuc test_comm(masterfd, slavefd);
216433d6423SLionel Sambuc
217*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
218*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
219433d6423SLionel Sambuc
220*da21d850SDavid van Moolenbroek /*
221*da21d850SDavid van Moolenbroek * Try reopening and closing the slave, without opening the master.
222*da21d850SDavid van Moolenbroek * This should work on old-style PTYS, but not on Unix98 PTYs.
223*da21d850SDavid van Moolenbroek */
224*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) >= 0) {
225*da21d850SDavid van Moolenbroek if (!oldstyle) e(0);
226433d6423SLionel Sambuc
227*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
228*da21d850SDavid van Moolenbroek } else
229*da21d850SDavid van Moolenbroek if (oldstyle) e(0);
230433d6423SLionel Sambuc
231433d6423SLionel Sambuc /* Again, try the normal open procedure. */
232*da21d850SDavid van Moolenbroek if (!oldstyle)
233*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
234*da21d850SDavid van Moolenbroek else
235*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
236*da21d850SDavid van Moolenbroek
237*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
238433d6423SLionel Sambuc
239433d6423SLionel Sambuc test_comm(masterfd, slavefd);
240433d6423SLionel Sambuc
241*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
242*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
243433d6423SLionel Sambuc
244*da21d850SDavid van Moolenbroek /*
245*da21d850SDavid van Moolenbroek * Finally, try opening the slave first. This does not work with
246*da21d850SDavid van Moolenbroek * Unix98 PTYs.
247*da21d850SDavid van Moolenbroek */
248*da21d850SDavid van Moolenbroek if (oldstyle) {
249*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
250*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
251433d6423SLionel Sambuc
252433d6423SLionel Sambuc test_comm(masterfd, slavefd);
253433d6423SLionel Sambuc
254*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
255*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
256*da21d850SDavid van Moolenbroek }
257433d6423SLionel Sambuc
258*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
259433d6423SLionel Sambuc }
260433d6423SLionel Sambuc
261433d6423SLionel Sambuc /*
262433d6423SLionel Sambuc * Test opening a single side multiple times.
263433d6423SLionel Sambuc */
264433d6423SLionel Sambuc static void
test77b(void)265433d6423SLionel Sambuc test77b(void)
266433d6423SLionel Sambuc {
267433d6423SLionel Sambuc char pname[PATH_MAX], tname[PATH_MAX];
268*da21d850SDavid van Moolenbroek int oldstyle, masterfd, slavefd, extrafd;
269433d6423SLionel Sambuc
270433d6423SLionel Sambuc subtest = 2;
271433d6423SLionel Sambuc
272*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
273*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
274433d6423SLionel Sambuc
275*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
276*da21d850SDavid van Moolenbroek
277*da21d850SDavid van Moolenbroek /*
278*da21d850SDavid van Moolenbroek * It must not be possible to open the master multiple times. Doing so
279*da21d850SDavid van Moolenbroek * is possible only if we have a named master, i.e., an old-style PTY.
280*da21d850SDavid van Moolenbroek */
281*da21d850SDavid van Moolenbroek test_comm(masterfd, slavefd);
282*da21d850SDavid van Moolenbroek
283*da21d850SDavid van Moolenbroek if (oldstyle) {
284*da21d850SDavid van Moolenbroek if ((extrafd = open(pname, O_RDWR | O_NOCTTY)) >= 0) e(0);
285*da21d850SDavid van Moolenbroek if (errno != EIO) e(0);
286*da21d850SDavid van Moolenbroek }
287433d6423SLionel Sambuc
288433d6423SLionel Sambuc test_comm(masterfd, slavefd);
289433d6423SLionel Sambuc
290*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
291*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
292433d6423SLionel Sambuc
293433d6423SLionel Sambuc /* The slave can be opened multiple times, though. */
294*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
295*da21d850SDavid van Moolenbroek
296*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
297433d6423SLionel Sambuc
298433d6423SLionel Sambuc test_comm(masterfd, slavefd);
299433d6423SLionel Sambuc
300*da21d850SDavid van Moolenbroek if ((extrafd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
301433d6423SLionel Sambuc
302433d6423SLionel Sambuc test_comm(masterfd, extrafd);
303433d6423SLionel Sambuc test_comm(masterfd, slavefd);
304433d6423SLionel Sambuc
305*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
306*da21d850SDavid van Moolenbroek if (close(extrafd) < 0) e(0);
307*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
308433d6423SLionel Sambuc }
309433d6423SLionel Sambuc
310433d6423SLionel Sambuc /*
311433d6423SLionel Sambuc * Test communication on half-open pseudo terminals.
312433d6423SLionel Sambuc */
313433d6423SLionel Sambuc static void
test77c(void)314433d6423SLionel Sambuc test77c(void)
315433d6423SLionel Sambuc {
316433d6423SLionel Sambuc struct sigaction act, oact;
317433d6423SLionel Sambuc char pname[PATH_MAX], tname[PATH_MAX];
318*da21d850SDavid van Moolenbroek int oldstyle, masterfd, slavefd;
319433d6423SLionel Sambuc char c;
320433d6423SLionel Sambuc
321433d6423SLionel Sambuc subtest = 3;
322433d6423SLionel Sambuc
323433d6423SLionel Sambuc /* We do not want to get SIGHUP signals in this test. */
324433d6423SLionel Sambuc memset(&act, 0, sizeof(act));
325433d6423SLionel Sambuc act.sa_handler = SIG_IGN;
326*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &act, &oact) < 0) e(0);
327433d6423SLionel Sambuc
328*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
329*da21d850SDavid van Moolenbroek oldstyle = get_pty(&masterfd, pname, tname);
330433d6423SLionel Sambuc
331*da21d850SDavid van Moolenbroek /*
332*da21d850SDavid van Moolenbroek * For old-style pseudo terminals, we have just opened and closed the
333*da21d850SDavid van Moolenbroek * slave end, which alters the behavior we are testing below. Close
334*da21d850SDavid van Moolenbroek * and reopen the master to start fresh.
335*da21d850SDavid van Moolenbroek */
336*da21d850SDavid van Moolenbroek if (oldstyle) {
337*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
338*da21d850SDavid van Moolenbroek
339*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
340*da21d850SDavid van Moolenbroek }
341433d6423SLionel Sambuc
342433d6423SLionel Sambuc /* Writes to the master should be buffered until there is a slave. */
343433d6423SLionel Sambuc c = 'E';
344*da21d850SDavid van Moolenbroek if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
345433d6423SLionel Sambuc
346*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
347433d6423SLionel Sambuc
348433d6423SLionel Sambuc make_raw(slavefd);
349433d6423SLionel Sambuc
350*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
351*da21d850SDavid van Moolenbroek if (c != 'E') e(0);
352433d6423SLionel Sambuc
353433d6423SLionel Sambuc /* Discard the echo on the master. */
354*da21d850SDavid van Moolenbroek if (tcflush(slavefd, TCOFLUSH) != 0) e(0);
355433d6423SLionel Sambuc
356433d6423SLionel Sambuc test_comm(masterfd, slavefd);
357433d6423SLionel Sambuc
358*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
359433d6423SLionel Sambuc
360433d6423SLionel Sambuc /* Writes to the master after the slave has been closed should fail. */
361*da21d850SDavid van Moolenbroek if (write(masterfd, &c, sizeof(c)) >= 0) e(0);
362*da21d850SDavid van Moolenbroek if (errno != EIO) e(0);
363433d6423SLionel Sambuc
364*da21d850SDavid van Moolenbroek if (oldstyle)
365*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
366433d6423SLionel Sambuc
367*da21d850SDavid van Moolenbroek /*
368*da21d850SDavid van Moolenbroek * Writes to the slave should be buffered until there is a master.
369*da21d850SDavid van Moolenbroek * This applies to old-style PTYs only.
370*da21d850SDavid van Moolenbroek */
371*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
372433d6423SLionel Sambuc
373*da21d850SDavid van Moolenbroek if (oldstyle) {
374433d6423SLionel Sambuc make_raw(slavefd);
375433d6423SLionel Sambuc
376433d6423SLionel Sambuc c = 'F';
377*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
378433d6423SLionel Sambuc
379*da21d850SDavid van Moolenbroek if ((masterfd = open(pname, O_RDWR | O_NOCTTY)) < 0) e(0);
380433d6423SLionel Sambuc
381*da21d850SDavid van Moolenbroek if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
382*da21d850SDavid van Moolenbroek if (c != 'F') e(0);
383*da21d850SDavid van Moolenbroek }
384433d6423SLionel Sambuc
385433d6423SLionel Sambuc test_comm(masterfd, slavefd);
386433d6423SLionel Sambuc
387*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
388433d6423SLionel Sambuc
389*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) >= 0) e(0);
390*da21d850SDavid van Moolenbroek if (errno != EIO) e(0);
391433d6423SLionel Sambuc
392673c4e01SDavid van Moolenbroek /* Reads from the slave should return EOF if the master is gone. */
393*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != 0) e(0);
394433d6423SLionel Sambuc
395*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
396673c4e01SDavid van Moolenbroek
397*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
398673c4e01SDavid van Moolenbroek }
399673c4e01SDavid van Moolenbroek
400673c4e01SDavid van Moolenbroek /*
401673c4e01SDavid van Moolenbroek * Wait for a child process to terminate. Return 0 if the child exited without
402673c4e01SDavid van Moolenbroek * errors, -1 otherwise.
403673c4e01SDavid van Moolenbroek */
404673c4e01SDavid van Moolenbroek static int
waitchild(void)405673c4e01SDavid van Moolenbroek waitchild(void)
406673c4e01SDavid van Moolenbroek {
407673c4e01SDavid van Moolenbroek int status;
408673c4e01SDavid van Moolenbroek
409673c4e01SDavid van Moolenbroek if (wait(&status) <= 0) return -1;
410673c4e01SDavid van Moolenbroek if (!WIFEXITED(status)) return -1;
411673c4e01SDavid van Moolenbroek if (WEXITSTATUS(status) != 0) return -1;
412673c4e01SDavid van Moolenbroek
413673c4e01SDavid van Moolenbroek return 0;
414433d6423SLionel Sambuc }
415433d6423SLionel Sambuc
416433d6423SLionel Sambuc /*
417433d6423SLionel Sambuc * Test opening the slave side with and without the O_NOCTTY flag.
418433d6423SLionel Sambuc */
419433d6423SLionel Sambuc static void
test77d(void)420433d6423SLionel Sambuc test77d(void)
421433d6423SLionel Sambuc {
422433d6423SLionel Sambuc char pname[PATH_MAX], tname[PATH_MAX];
423433d6423SLionel Sambuc int masterfd, slavefd;
424433d6423SLionel Sambuc
425433d6423SLionel Sambuc subtest = 4;
426433d6423SLionel Sambuc
427433d6423SLionel Sambuc /* Make ourselves process group leader if we aren't already. */
428433d6423SLionel Sambuc (void)setsid();
429433d6423SLionel Sambuc
430*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
431*da21d850SDavid van Moolenbroek (void)get_pty(&masterfd, NULL, tname);
432433d6423SLionel Sambuc
433433d6423SLionel Sambuc /*
434433d6423SLionel Sambuc * Opening the slave with O_NOCTTY should not change its controlling
435433d6423SLionel Sambuc * terminal.
436433d6423SLionel Sambuc */
437433d6423SLionel Sambuc switch (fork()) {
438433d6423SLionel Sambuc case 0:
439*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
440433d6423SLionel Sambuc
441*da21d850SDavid van Moolenbroek if (setsid() < 0) e(0);
442433d6423SLionel Sambuc
443*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
444*da21d850SDavid van Moolenbroek
445*da21d850SDavid van Moolenbroek if (open("/dev/tty", O_RDWR) >= 0) e(0);
446*da21d850SDavid van Moolenbroek if (errno != ENXIO) e(0);
447433d6423SLionel Sambuc
448673c4e01SDavid van Moolenbroek exit(errct);
449433d6423SLionel Sambuc case -1:
450*da21d850SDavid van Moolenbroek e(0);
451433d6423SLionel Sambuc default:
452433d6423SLionel Sambuc break;
453433d6423SLionel Sambuc }
454433d6423SLionel Sambuc
455*da21d850SDavid van Moolenbroek if (waitchild() < 0) e(0);
456433d6423SLionel Sambuc
457*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
458433d6423SLionel Sambuc
459*da21d850SDavid van Moolenbroek (void)get_pty(&masterfd, pname, tname);
460433d6423SLionel Sambuc
461433d6423SLionel Sambuc /*
462433d6423SLionel Sambuc * Opening the slave without O_NOCTTY should change its controlling
463433d6423SLionel Sambuc * terminal, though.
464433d6423SLionel Sambuc */
465433d6423SLionel Sambuc switch (fork()) {
466433d6423SLionel Sambuc case 0:
467*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
468433d6423SLionel Sambuc
469*da21d850SDavid van Moolenbroek if (setsid() < 0) e(0);
470433d6423SLionel Sambuc
471*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR)) < 0) e(0);
472*da21d850SDavid van Moolenbroek
473*da21d850SDavid van Moolenbroek if (open("/dev/tty", O_RDWR) < 0) e(0);
474433d6423SLionel Sambuc
475673c4e01SDavid van Moolenbroek exit(errct);
476433d6423SLionel Sambuc case -1:
477*da21d850SDavid van Moolenbroek e(0);
478433d6423SLionel Sambuc default:
479433d6423SLionel Sambuc break;
480433d6423SLionel Sambuc }
481433d6423SLionel Sambuc
482*da21d850SDavid van Moolenbroek if (waitchild() < 0) e(0);
483433d6423SLionel Sambuc
484*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
485433d6423SLionel Sambuc }
486433d6423SLionel Sambuc
487433d6423SLionel Sambuc /*
488433d6423SLionel Sambuc * Test receiving of SIGHUP on master hang-up. All of the tests so far have
489433d6423SLionel Sambuc * ignored SIGHUP, and probably would not have received one anyway, since the
490433d6423SLionel Sambuc * process was not its own session leader. Time to test this aspect.
491433d6423SLionel Sambuc */
492433d6423SLionel Sambuc static void
test77e(void)493433d6423SLionel Sambuc test77e(void)
494433d6423SLionel Sambuc {
495433d6423SLionel Sambuc struct sigaction act, hup_oact, usr_oact;
496433d6423SLionel Sambuc sigset_t set, oset;
497*da21d850SDavid van Moolenbroek char tname[PATH_MAX];
498433d6423SLionel Sambuc int masterfd, slavefd;
499433d6423SLionel Sambuc
500433d6423SLionel Sambuc subtest = 5;
501433d6423SLionel Sambuc
502*da21d850SDavid van Moolenbroek memset(&act, 0, sizeof(act));
503*da21d850SDavid van Moolenbroek act.sa_handler = signal_handler;
504*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &act, &hup_oact) < 0) e(0);
505433d6423SLionel Sambuc
506433d6423SLionel Sambuc memset(&act, 0, sizeof(act));
507433d6423SLionel Sambuc act.sa_handler = signal_handler;
508*da21d850SDavid van Moolenbroek if (sigaction(SIGUSR1, &act, &usr_oact) < 0) e(0);
509433d6423SLionel Sambuc
510433d6423SLionel Sambuc sigemptyset(&set);
511433d6423SLionel Sambuc sigaddset(&set, SIGHUP);
512433d6423SLionel Sambuc sigaddset(&set, SIGUSR1);
513*da21d850SDavid van Moolenbroek if (sigprocmask(SIG_BLOCK, &set, &oset) < 0) e(0);
514433d6423SLionel Sambuc
515433d6423SLionel Sambuc sighups = 0;
516433d6423SLionel Sambuc
517433d6423SLionel Sambuc /* Make ourselves process group leader if we aren't already. */
518433d6423SLionel Sambuc (void)setsid();
519433d6423SLionel Sambuc
520*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
521*da21d850SDavid van Moolenbroek (void)get_pty(&masterfd, NULL, tname);
522433d6423SLionel Sambuc
523433d6423SLionel Sambuc switch (fork()) {
524433d6423SLionel Sambuc case 0:
525*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
526433d6423SLionel Sambuc
527433d6423SLionel Sambuc /* Become session leader. */
528*da21d850SDavid van Moolenbroek if (setsid() < 0) e(0);
529433d6423SLionel Sambuc
530*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR)) < 0) e(0);
531433d6423SLionel Sambuc
532433d6423SLionel Sambuc /* Tell the parent we are ready. */
533433d6423SLionel Sambuc kill(getppid(), SIGUSR1);
534433d6423SLionel Sambuc
535433d6423SLionel Sambuc /* We should now get a SIGHUP. */
536433d6423SLionel Sambuc set = oset;
537*da21d850SDavid van Moolenbroek if (sigsuspend(&set) >= 0) e(0);
538433d6423SLionel Sambuc
539*da21d850SDavid van Moolenbroek if (sighups != 1) e(0);
540433d6423SLionel Sambuc
541673c4e01SDavid van Moolenbroek exit(errct);
542433d6423SLionel Sambuc case -1:
543*da21d850SDavid van Moolenbroek e(0);
544433d6423SLionel Sambuc default:
545433d6423SLionel Sambuc break;
546433d6423SLionel Sambuc }
547433d6423SLionel Sambuc
548433d6423SLionel Sambuc /* Wait for SIGUSR1 from the child. */
549433d6423SLionel Sambuc set = oset;
550*da21d850SDavid van Moolenbroek if (sigsuspend(&set) >= 0) e(0);
551433d6423SLionel Sambuc
552433d6423SLionel Sambuc /* Closing the master should now raise a SIGHUP signal in the child. */
553*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
554433d6423SLionel Sambuc
555*da21d850SDavid van Moolenbroek if (waitchild() < 0) e(0);
556433d6423SLionel Sambuc
557*da21d850SDavid van Moolenbroek if (sigprocmask(SIG_SETMASK, &oset, NULL) < 0) e(0);
558433d6423SLionel Sambuc
559*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &hup_oact, NULL) < 0) e(0);
560*da21d850SDavid van Moolenbroek if (sigaction(SIGUSR1, &usr_oact, NULL) < 0) e(0);
561433d6423SLionel Sambuc }
562433d6423SLionel Sambuc
56327d0ecdbSDavid van Moolenbroek /*
56427d0ecdbSDavid van Moolenbroek * Test basic select functionality on /dev/tty. While this test should not be
56527d0ecdbSDavid van Moolenbroek * part of this test set, we already have all the infrastructure we need here.
56627d0ecdbSDavid van Moolenbroek */
56727d0ecdbSDavid van Moolenbroek static void
test77f(void)56827d0ecdbSDavid van Moolenbroek test77f(void)
56927d0ecdbSDavid van Moolenbroek {
57027d0ecdbSDavid van Moolenbroek struct sigaction act, oact;
571*da21d850SDavid van Moolenbroek char c, tname[PATH_MAX];
57227d0ecdbSDavid van Moolenbroek struct timeval tv;
57327d0ecdbSDavid van Moolenbroek fd_set fd_set;
57427d0ecdbSDavid van Moolenbroek int fd, maxfd, masterfd, slavefd;
57527d0ecdbSDavid van Moolenbroek
57627d0ecdbSDavid van Moolenbroek subtest = 6;
57727d0ecdbSDavid van Moolenbroek
57827d0ecdbSDavid van Moolenbroek /* We do not want to get SIGHUP signals in this test. */
57927d0ecdbSDavid van Moolenbroek memset(&act, 0, sizeof(act));
58027d0ecdbSDavid van Moolenbroek act.sa_handler = SIG_IGN;
581*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &act, &oact) < 0) e(0);
58227d0ecdbSDavid van Moolenbroek
583*da21d850SDavid van Moolenbroek /* Obtain a pseudo terminal. */
584*da21d850SDavid van Moolenbroek (void)get_pty(&masterfd, NULL, tname);
58527d0ecdbSDavid van Moolenbroek
58627d0ecdbSDavid van Moolenbroek switch (fork()) {
58727d0ecdbSDavid van Moolenbroek case 0:
588*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
58927d0ecdbSDavid van Moolenbroek
590*da21d850SDavid van Moolenbroek if (setsid() < 0) e(0);
59127d0ecdbSDavid van Moolenbroek
592*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR)) < 0) e(0);
59327d0ecdbSDavid van Moolenbroek
594*da21d850SDavid van Moolenbroek if ((fd = open("/dev/tty", O_RDWR)) < 0) e(0);
59527d0ecdbSDavid van Moolenbroek
59627d0ecdbSDavid van Moolenbroek make_raw(fd);
59727d0ecdbSDavid van Moolenbroek
59827d0ecdbSDavid van Moolenbroek /* Without slave input, /dev/tty is not ready for reading. */
59927d0ecdbSDavid van Moolenbroek FD_ZERO(&fd_set);
60027d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
60127d0ecdbSDavid van Moolenbroek tv.tv_sec = 0;
60227d0ecdbSDavid van Moolenbroek tv.tv_usec = 0;
60327d0ecdbSDavid van Moolenbroek
604*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0);
605*da21d850SDavid van Moolenbroek if (FD_ISSET(fd, &fd_set)) e(0);
60627d0ecdbSDavid van Moolenbroek
60727d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
60827d0ecdbSDavid van Moolenbroek tv.tv_sec = 0;
60927d0ecdbSDavid van Moolenbroek tv.tv_usec = 10000;
61027d0ecdbSDavid van Moolenbroek
611*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0);
612*da21d850SDavid van Moolenbroek if (FD_ISSET(fd, &fd_set)) e(0);
61327d0ecdbSDavid van Moolenbroek
61427d0ecdbSDavid van Moolenbroek /* It will be ready for writing, though. */
61527d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
61627d0ecdbSDavid van Moolenbroek
617*da21d850SDavid van Moolenbroek if (select(fd + 1, NULL, &fd_set, NULL, NULL) != 1) e(0);
618*da21d850SDavid van Moolenbroek if (!FD_ISSET(fd, &fd_set)) e(0);
61927d0ecdbSDavid van Moolenbroek
62027d0ecdbSDavid van Moolenbroek /* Test mixing file descriptors to the same terminal. */
62127d0ecdbSDavid van Moolenbroek FD_ZERO(&fd_set);
62227d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
62327d0ecdbSDavid van Moolenbroek FD_SET(slavefd, &fd_set);
62427d0ecdbSDavid van Moolenbroek tv.tv_sec = 0;
62527d0ecdbSDavid van Moolenbroek tv.tv_usec = 10000;
62627d0ecdbSDavid van Moolenbroek
62727d0ecdbSDavid van Moolenbroek maxfd = fd > slavefd ? fd : slavefd;
628*da21d850SDavid van Moolenbroek if (select(maxfd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0);
629*da21d850SDavid van Moolenbroek if (FD_ISSET(fd, &fd_set)) e(0);
630*da21d850SDavid van Moolenbroek if (FD_ISSET(slavefd, &fd_set)) e(0);
63127d0ecdbSDavid van Moolenbroek
63227d0ecdbSDavid van Moolenbroek /* The delayed echo on the master must wake up our select. */
63327d0ecdbSDavid van Moolenbroek c = 'A';
634*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
63527d0ecdbSDavid van Moolenbroek
63627d0ecdbSDavid van Moolenbroek FD_ZERO(&fd_set);
63727d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
63827d0ecdbSDavid van Moolenbroek
639*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0);
640*da21d850SDavid van Moolenbroek if (!FD_ISSET(fd, &fd_set)) e(0);
64127d0ecdbSDavid van Moolenbroek
64227d0ecdbSDavid van Moolenbroek /* Select must now still flag readiness for reading. */
64327d0ecdbSDavid van Moolenbroek tv.tv_sec = 0;
64427d0ecdbSDavid van Moolenbroek tv.tv_usec = 0;
64527d0ecdbSDavid van Moolenbroek
646*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 1) e(0);
647*da21d850SDavid van Moolenbroek if (!FD_ISSET(fd, &fd_set)) e(0);
64827d0ecdbSDavid van Moolenbroek
64927d0ecdbSDavid van Moolenbroek /* That is, until we read the byte. */
650*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
651*da21d850SDavid van Moolenbroek if (c != 'B') e(0);
65227d0ecdbSDavid van Moolenbroek
653*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, &tv) != 0) e(0);
654*da21d850SDavid van Moolenbroek if (FD_ISSET(fd, &fd_set)) e(0);
65527d0ecdbSDavid van Moolenbroek
65627d0ecdbSDavid van Moolenbroek /* Ask the parent to close the master. */
65727d0ecdbSDavid van Moolenbroek c = 'C';
658*da21d850SDavid van Moolenbroek if (write(slavefd, &c, sizeof(c)) != sizeof(c)) e(0);
65927d0ecdbSDavid van Moolenbroek
66027d0ecdbSDavid van Moolenbroek FD_SET(fd, &fd_set);
66127d0ecdbSDavid van Moolenbroek
66227d0ecdbSDavid van Moolenbroek /* The closure must cause an EOF condition on the slave. */
663*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0);
664*da21d850SDavid van Moolenbroek if (!FD_ISSET(fd, &fd_set)) e(0);
66527d0ecdbSDavid van Moolenbroek
666*da21d850SDavid van Moolenbroek if (select(fd + 1, &fd_set, NULL, NULL, NULL) != 1) e(0);
667*da21d850SDavid van Moolenbroek if (!FD_ISSET(fd, &fd_set)) e(0);
66827d0ecdbSDavid van Moolenbroek
669*da21d850SDavid van Moolenbroek if (read(slavefd, &c, sizeof(c)) != 0) e(0);
67027d0ecdbSDavid van Moolenbroek
67127d0ecdbSDavid van Moolenbroek exit(errct);
67227d0ecdbSDavid van Moolenbroek case -1:
673*da21d850SDavid van Moolenbroek e(0);
67427d0ecdbSDavid van Moolenbroek default:
67527d0ecdbSDavid van Moolenbroek /* Wait for the child to write something to the slave. */
67627d0ecdbSDavid van Moolenbroek FD_ZERO(&fd_set);
67727d0ecdbSDavid van Moolenbroek FD_SET(masterfd, &fd_set);
67827d0ecdbSDavid van Moolenbroek
67927d0ecdbSDavid van Moolenbroek if (select(masterfd + 1, &fd_set, NULL, NULL, NULL) != 1)
680*da21d850SDavid van Moolenbroek e(0);
681*da21d850SDavid van Moolenbroek if (!FD_ISSET(masterfd, &fd_set)) e(0);
68227d0ecdbSDavid van Moolenbroek
683*da21d850SDavid van Moolenbroek if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
684*da21d850SDavid van Moolenbroek if (c != 'A') e(0);
68527d0ecdbSDavid van Moolenbroek
68627d0ecdbSDavid van Moolenbroek /* Write a reply once the child is blocked in its select. */
68727d0ecdbSDavid van Moolenbroek tv.tv_sec = 1;
68827d0ecdbSDavid van Moolenbroek tv.tv_usec = 0;
68927d0ecdbSDavid van Moolenbroek if (select(masterfd + 1, &fd_set, NULL, NULL, &tv) != 0)
690*da21d850SDavid van Moolenbroek e(0);
69127d0ecdbSDavid van Moolenbroek
69227d0ecdbSDavid van Moolenbroek c = 'B';
693*da21d850SDavid van Moolenbroek if (write(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
69427d0ecdbSDavid van Moolenbroek
69527d0ecdbSDavid van Moolenbroek /* Wait for the child to request closing the master. */
696*da21d850SDavid van Moolenbroek if (read(masterfd, &c, sizeof(c)) != sizeof(c)) e(0);
697*da21d850SDavid van Moolenbroek if (c != 'C') e(0);
69827d0ecdbSDavid van Moolenbroek
69927d0ecdbSDavid van Moolenbroek /* Close the master once the child is blocked in its select. */
70027d0ecdbSDavid van Moolenbroek sleep(1);
70127d0ecdbSDavid van Moolenbroek
70227d0ecdbSDavid van Moolenbroek close(masterfd);
70327d0ecdbSDavid van Moolenbroek
70427d0ecdbSDavid van Moolenbroek break;
70527d0ecdbSDavid van Moolenbroek }
70627d0ecdbSDavid van Moolenbroek
707*da21d850SDavid van Moolenbroek if (waitchild() < 0) e(0);
70827d0ecdbSDavid van Moolenbroek
709*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
710*da21d850SDavid van Moolenbroek }
711*da21d850SDavid van Moolenbroek
712*da21d850SDavid van Moolenbroek /*
713*da21d850SDavid van Moolenbroek * See if the directory contents of /dev/pts are as we expect. We have to keep
714*da21d850SDavid van Moolenbroek * in mind that other programs may have pseudo terminals open while we are
715*da21d850SDavid van Moolenbroek * running, although we assume that those programs do not open or close PTYs
716*da21d850SDavid van Moolenbroek * while we are running.
717*da21d850SDavid van Moolenbroek */
718*da21d850SDavid van Moolenbroek static void
test_getdents(int nindex,int array[3],int present[3])719*da21d850SDavid van Moolenbroek test_getdents(int nindex, int array[3], int present[3])
720*da21d850SDavid van Moolenbroek {
721*da21d850SDavid van Moolenbroek struct group *group;
722*da21d850SDavid van Moolenbroek DIR *dirp;
723*da21d850SDavid van Moolenbroek struct dirent *dp;
724*da21d850SDavid van Moolenbroek struct stat buf;
725*da21d850SDavid van Moolenbroek char path[PATH_MAX], *endp;
726*da21d850SDavid van Moolenbroek gid_t tty_gid;
727*da21d850SDavid van Moolenbroek int i, n, seen_dot, seen_dotdot, seen_index[3], *seen;
728*da21d850SDavid van Moolenbroek
729*da21d850SDavid van Moolenbroek seen_dot = seen_dotdot = 0;
730*da21d850SDavid van Moolenbroek for (i = 0; i < nindex; i++)
731*da21d850SDavid van Moolenbroek seen_index[i] = 0;
732*da21d850SDavid van Moolenbroek
733*da21d850SDavid van Moolenbroek if ((group = getgrnam("tty")) == NULL) e(0);
734*da21d850SDavid van Moolenbroek tty_gid = group->gr_gid;
735*da21d850SDavid van Moolenbroek
736*da21d850SDavid van Moolenbroek if ((dirp = opendir(_PATH_DEV_PTS)) == NULL) e(0);
737*da21d850SDavid van Moolenbroek
738*da21d850SDavid van Moolenbroek while ((dp = readdir(dirp)) != NULL) {
739*da21d850SDavid van Moolenbroek snprintf(path, sizeof(path), _PATH_DEV_PTS "%s", dp->d_name);
740*da21d850SDavid van Moolenbroek if (stat(path, &buf) < 0) e(0);
741*da21d850SDavid van Moolenbroek
742*da21d850SDavid van Moolenbroek if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
743*da21d850SDavid van Moolenbroek seen =
744*da21d850SDavid van Moolenbroek (dp->d_name[1] == '.') ? &seen_dot : &seen_dotdot;
745*da21d850SDavid van Moolenbroek if (*seen) e(0);
746*da21d850SDavid van Moolenbroek *seen = 1;
747*da21d850SDavid van Moolenbroek
748*da21d850SDavid van Moolenbroek /* Check basic dirent and stat fields. */
749*da21d850SDavid van Moolenbroek if (dp->d_type != DT_DIR) e(0);
750*da21d850SDavid van Moolenbroek if (dp->d_name[1] == '\0' &&
751*da21d850SDavid van Moolenbroek buf.st_ino != dp->d_fileno) e(0);
752*da21d850SDavid van Moolenbroek if (!S_ISDIR(buf.st_mode)) e(0);
753*da21d850SDavid van Moolenbroek if (buf.st_nlink < 2) e(0);
754*da21d850SDavid van Moolenbroek } else {
755*da21d850SDavid van Moolenbroek /* The file name must be a number. */
756*da21d850SDavid van Moolenbroek errno = 0;
757*da21d850SDavid van Moolenbroek n = strtol(dp->d_name, &endp, 10);
758*da21d850SDavid van Moolenbroek if (errno != 0) e(0);
759*da21d850SDavid van Moolenbroek if (dp->d_name[0] == '\0' || *endp != '\0') e(0);
760*da21d850SDavid van Moolenbroek if (n < 0) e(0);
761*da21d850SDavid van Moolenbroek
762*da21d850SDavid van Moolenbroek /* Check basic dirent and stat fields. */
763*da21d850SDavid van Moolenbroek if (dp->d_type != DT_CHR) e(0);
764*da21d850SDavid van Moolenbroek if (buf.st_ino != dp->d_fileno) e(0);
765*da21d850SDavid van Moolenbroek if (!S_ISCHR(buf.st_mode)) e(0);
766*da21d850SDavid van Moolenbroek if (buf.st_nlink != 1) e(0);
767*da21d850SDavid van Moolenbroek if (buf.st_size != 0) e(0);
768*da21d850SDavid van Moolenbroek if (buf.st_rdev == 0) e(0);
769*da21d850SDavid van Moolenbroek
770*da21d850SDavid van Moolenbroek /* Is this one of the PTYs we created? */
771*da21d850SDavid van Moolenbroek for (i = 0; i < nindex; i++) {
772*da21d850SDavid van Moolenbroek if (array[i] == n) {
773*da21d850SDavid van Moolenbroek if (seen_index[i]) e(0);
774*da21d850SDavid van Moolenbroek seen_index[i] = 1;
775*da21d850SDavid van Moolenbroek
776*da21d850SDavid van Moolenbroek break;
777*da21d850SDavid van Moolenbroek }
778*da21d850SDavid van Moolenbroek }
779*da21d850SDavid van Moolenbroek
780*da21d850SDavid van Moolenbroek /* If so, perform some extra tests. */
781*da21d850SDavid van Moolenbroek if (i < nindex) {
782*da21d850SDavid van Moolenbroek if ((buf.st_mode & ALLPERMS) != 0620) e(0);
783*da21d850SDavid van Moolenbroek if (buf.st_uid != getuid()) e(0);
784*da21d850SDavid van Moolenbroek if (buf.st_gid != tty_gid) e(0);
785*da21d850SDavid van Moolenbroek }
786*da21d850SDavid van Moolenbroek }
787*da21d850SDavid van Moolenbroek }
788*da21d850SDavid van Moolenbroek
789*da21d850SDavid van Moolenbroek if (closedir(dirp) < 0) e(0);
790*da21d850SDavid van Moolenbroek
791*da21d850SDavid van Moolenbroek if (!seen_dot) e(0);
792*da21d850SDavid van Moolenbroek if (!seen_dotdot) e(0);
793*da21d850SDavid van Moolenbroek for (i = 0; i < nindex; i++)
794*da21d850SDavid van Moolenbroek if (seen_index[i] != present[i]) e(0);
795*da21d850SDavid van Moolenbroek }
796*da21d850SDavid van Moolenbroek
797*da21d850SDavid van Moolenbroek /*
798*da21d850SDavid van Moolenbroek * Obtain a Unix98 PTY. Return an open file descriptor for the master side,
799*da21d850SDavid van Moolenbroek * and store the name of the slave side in 'tptr'.
800*da21d850SDavid van Moolenbroek */
801*da21d850SDavid van Moolenbroek static int
get_unix98_pty(char ** tptr)802*da21d850SDavid van Moolenbroek get_unix98_pty(char ** tptr)
803*da21d850SDavid van Moolenbroek {
804*da21d850SDavid van Moolenbroek int masterfd;
805*da21d850SDavid van Moolenbroek
806*da21d850SDavid van Moolenbroek if ((masterfd = posix_openpt(O_RDWR | O_NOCTTY)) < 0) e(0);
807*da21d850SDavid van Moolenbroek
808*da21d850SDavid van Moolenbroek if (grantpt(masterfd) < 0) e(0);
809*da21d850SDavid van Moolenbroek
810*da21d850SDavid van Moolenbroek /* This call is a no-op on MINIX3. */
811*da21d850SDavid van Moolenbroek if (unlockpt(masterfd) < 0) e(0);
812*da21d850SDavid van Moolenbroek
813*da21d850SDavid van Moolenbroek if ((*tptr = ptsname(masterfd)) == NULL) e(0);
814*da21d850SDavid van Moolenbroek
815*da21d850SDavid van Moolenbroek return masterfd;
816*da21d850SDavid van Moolenbroek }
817*da21d850SDavid van Moolenbroek
818*da21d850SDavid van Moolenbroek /*
819*da21d850SDavid van Moolenbroek * Test for Unix98 PTY support and PTYFS.
820*da21d850SDavid van Moolenbroek */
821*da21d850SDavid van Moolenbroek static void
test77g(void)822*da21d850SDavid van Moolenbroek test77g(void)
823*da21d850SDavid van Moolenbroek {
824*da21d850SDavid van Moolenbroek char *tname;
825*da21d850SDavid van Moolenbroek struct stat buf;
826*da21d850SDavid van Moolenbroek size_t len;
827*da21d850SDavid van Moolenbroek int i, masterfd, slavefd, fd[3], array[3], present[3];
828*da21d850SDavid van Moolenbroek
829*da21d850SDavid van Moolenbroek subtest = 7;
830*da21d850SDavid van Moolenbroek
831*da21d850SDavid van Moolenbroek /*
832*da21d850SDavid van Moolenbroek * Test basic operation, and verify that the slave node disappears
833*da21d850SDavid van Moolenbroek * after both sides of the pseudo terminal have been closed. We check
834*da21d850SDavid van Moolenbroek * different combinations of open master and slave ends (with 'i'):
835*da21d850SDavid van Moolenbroek * 0) opening and closing the master only, 1) closing a slave before
836*da21d850SDavid van Moolenbroek * the master, and 2) closing the slave after the master.
837*da21d850SDavid van Moolenbroek */
838*da21d850SDavid van Moolenbroek for (i = 0; i <= 2; i++) {
839*da21d850SDavid van Moolenbroek masterfd = get_unix98_pty(&tname);
840*da21d850SDavid van Moolenbroek
841*da21d850SDavid van Moolenbroek if (access(tname, R_OK | W_OK) < 0) e(0);
842*da21d850SDavid van Moolenbroek
843*da21d850SDavid van Moolenbroek if (i > 0) {
844*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0)
845*da21d850SDavid van Moolenbroek e(0);
846*da21d850SDavid van Moolenbroek
847*da21d850SDavid van Moolenbroek if (access(tname, R_OK | W_OK) < 0) e(0);
848*da21d850SDavid van Moolenbroek
849*da21d850SDavid van Moolenbroek if (i > 1) {
850*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
851*da21d850SDavid van Moolenbroek
852*da21d850SDavid van Moolenbroek masterfd = slavefd; /* ugly but saving code */
853*da21d850SDavid van Moolenbroek } else
854*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
855*da21d850SDavid van Moolenbroek }
856*da21d850SDavid van Moolenbroek
857*da21d850SDavid van Moolenbroek if (access(tname, R_OK | W_OK) < 0) e(0);
858*da21d850SDavid van Moolenbroek
859*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
860*da21d850SDavid van Moolenbroek
861*da21d850SDavid van Moolenbroek if (access(tname, R_OK | W_OK) == 0) e(0);
862*da21d850SDavid van Moolenbroek }
863*da21d850SDavid van Moolenbroek
864*da21d850SDavid van Moolenbroek /*
865*da21d850SDavid van Moolenbroek * Test whether we can open multiple pseudo terminals. We need to be
866*da21d850SDavid van Moolenbroek * able to open three PTYs. Verify that they are properly listed in
867*da21d850SDavid van Moolenbroek * the /dev/pts directory contents, and have proper attributes set.
868*da21d850SDavid van Moolenbroek */
869*da21d850SDavid van Moolenbroek test_getdents(0, NULL, NULL);
870*da21d850SDavid van Moolenbroek
871*da21d850SDavid van Moolenbroek for (i = 0; i < 3; i++) {
872*da21d850SDavid van Moolenbroek fd[i] = get_unix98_pty(&tname);
873*da21d850SDavid van Moolenbroek
874*da21d850SDavid van Moolenbroek /* Figure out the slave index number. */
875*da21d850SDavid van Moolenbroek len = strlen(_PATH_DEV_PTS);
876*da21d850SDavid van Moolenbroek if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0);
877*da21d850SDavid van Moolenbroek array[i] = atoi(&tname[len]);
878*da21d850SDavid van Moolenbroek present[i] = 1;
879*da21d850SDavid van Moolenbroek }
880*da21d850SDavid van Moolenbroek
881*da21d850SDavid van Moolenbroek test_getdents(3, array, present);
882*da21d850SDavid van Moolenbroek
883*da21d850SDavid van Moolenbroek if (close(fd[0]) < 0) e(0);
884*da21d850SDavid van Moolenbroek present[0] = 0;
885*da21d850SDavid van Moolenbroek
886*da21d850SDavid van Moolenbroek test_getdents(3, array, present);
887*da21d850SDavid van Moolenbroek
888*da21d850SDavid van Moolenbroek if (close(fd[2]) < 0) e(0);
889*da21d850SDavid van Moolenbroek present[2] = 0;
890*da21d850SDavid van Moolenbroek
891*da21d850SDavid van Moolenbroek test_getdents(3, array, present);
892*da21d850SDavid van Moolenbroek
893*da21d850SDavid van Moolenbroek if (close(fd[1]) < 0) e(0);
894*da21d850SDavid van Moolenbroek present[1] = 0;
895*da21d850SDavid van Moolenbroek
896*da21d850SDavid van Moolenbroek test_getdents(3, array, present);
897*da21d850SDavid van Moolenbroek
898*da21d850SDavid van Moolenbroek /*
899*da21d850SDavid van Moolenbroek * Test chmod(2) on a slave node, and multiple calls to grantpt(3).
900*da21d850SDavid van Moolenbroek * The first grantpt(3) call should create the slave node (we currently
901*da21d850SDavid van Moolenbroek * can not test this: the slave node may be created earlier as well,
902*da21d850SDavid van Moolenbroek * but we do not know its name), whereas subsequent grantpt(3) calls
903*da21d850SDavid van Moolenbroek * should reset its mode, uid, and gid. Testing the latter two and
904*da21d850SDavid van Moolenbroek * chown(2) on the slave node requires root, so we skip that part.
905*da21d850SDavid van Moolenbroek *
906*da21d850SDavid van Moolenbroek * Finally, NetBSD revokes access to existing slave file descriptors
907*da21d850SDavid van Moolenbroek * upon a call to grantpt(3). This is not a POSIX requirement, but
908*da21d850SDavid van Moolenbroek * NetBSD needs this for security reasons because it already creates
909*da21d850SDavid van Moolenbroek * the slave node when the master is opened (and it does not lock the
910*da21d850SDavid van Moolenbroek * slave until a call to unlockpt(3)). MINIX3 does not implement
911*da21d850SDavid van Moolenbroek * revocation this way, because the slave node is created only upon the
912*da21d850SDavid van Moolenbroek * call to grantpt(3), thus leaving no insecure window for the slave
913*da21d850SDavid van Moolenbroek * side between posix_openpt(3) and grantpt(3). While this behavior
914*da21d850SDavid van Moolenbroek * may be changed later, we test for the lack of revocation here now.
915*da21d850SDavid van Moolenbroek */
916*da21d850SDavid van Moolenbroek masterfd = get_unix98_pty(&tname);
917*da21d850SDavid van Moolenbroek
918*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
919*da21d850SDavid van Moolenbroek
920*da21d850SDavid van Moolenbroek if (stat(tname, &buf) != 0) e(0);
921*da21d850SDavid van Moolenbroek if (buf.st_mode != (S_IFCHR | 0620)) e(0);
922*da21d850SDavid van Moolenbroek
923*da21d850SDavid van Moolenbroek if (chmod(tname, S_IFCHR | 0630) != 0) e(0);
924*da21d850SDavid van Moolenbroek
925*da21d850SDavid van Moolenbroek if (stat(tname, &buf) != 0) e(0);
926*da21d850SDavid van Moolenbroek if (buf.st_mode != (S_IFCHR | 0630)) e(0);
927*da21d850SDavid van Moolenbroek
928*da21d850SDavid van Moolenbroek if (grantpt(masterfd) != 0) e(0);
929*da21d850SDavid van Moolenbroek
930*da21d850SDavid van Moolenbroek if (stat(tname, &buf) != 0) e(0);
931*da21d850SDavid van Moolenbroek if (buf.st_mode != (S_IFCHR | 0620)) e(0);
932*da21d850SDavid van Moolenbroek
933*da21d850SDavid van Moolenbroek test_comm(masterfd, slavefd);
934*da21d850SDavid van Moolenbroek
935*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
936*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
937*da21d850SDavid van Moolenbroek
938*da21d850SDavid van Moolenbroek test_getdents(0, NULL, NULL);
939*da21d850SDavid van Moolenbroek }
940*da21d850SDavid van Moolenbroek
941*da21d850SDavid van Moolenbroek /*
942*da21d850SDavid van Moolenbroek * Check that the given PTY index, which is in use for an old-style PTY, is not
943*da21d850SDavid van Moolenbroek * allocated through Unix98 PTY allocation. This test is not foolproof, but it
944*da21d850SDavid van Moolenbroek * does the job well enough.
945*da21d850SDavid van Moolenbroek */
946*da21d850SDavid van Moolenbroek static void
test_overlap(int m)947*da21d850SDavid van Moolenbroek test_overlap(int m)
948*da21d850SDavid van Moolenbroek {
949*da21d850SDavid van Moolenbroek char *tname;
950*da21d850SDavid van Moolenbroek size_t len;
951*da21d850SDavid van Moolenbroek int i, n, fd[MIN_PTYS];
952*da21d850SDavid van Moolenbroek
953*da21d850SDavid van Moolenbroek for (i = 0; i < MIN_PTYS; i++) {
954*da21d850SDavid van Moolenbroek if ((fd[i] = posix_openpt(O_RDWR | O_NOCTTY)) < 0)
955*da21d850SDavid van Moolenbroek break; /* out of PTYs */
956*da21d850SDavid van Moolenbroek if (grantpt(fd[i]) < 0) e(0);
957*da21d850SDavid van Moolenbroek if (unlockpt(fd[i]) < 0) e(0);
958*da21d850SDavid van Moolenbroek if ((tname = ptsname(fd[i])) == NULL) e(0);
959*da21d850SDavid van Moolenbroek
960*da21d850SDavid van Moolenbroek len = strlen(_PATH_DEV_PTS);
961*da21d850SDavid van Moolenbroek if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0);
962*da21d850SDavid van Moolenbroek n = atoi(&tname[len]);
963*da21d850SDavid van Moolenbroek if (n < 0 || n > 9) e(0);
964*da21d850SDavid van Moolenbroek
965*da21d850SDavid van Moolenbroek if (m == n) e(0);
966*da21d850SDavid van Moolenbroek }
967*da21d850SDavid van Moolenbroek
968*da21d850SDavid van Moolenbroek for (i--; i >= 0; i--)
969*da21d850SDavid van Moolenbroek if (close(fd[i]) < 0) e(0);
970*da21d850SDavid van Moolenbroek }
971*da21d850SDavid van Moolenbroek
972*da21d850SDavid van Moolenbroek /*
973*da21d850SDavid van Moolenbroek * Test for mixing access to old-style and Unix98 PTYs. Since the PTY service
974*da21d850SDavid van Moolenbroek * internally shares the set of pseudo terminals between the two types, it has
975*da21d850SDavid van Moolenbroek * to implement checks to prevent that a PTY opened as one type is also
976*da21d850SDavid van Moolenbroek * accessed through the other type. We test some of those checks here.
977*da21d850SDavid van Moolenbroek */
978*da21d850SDavid van Moolenbroek static void
test77h(void)979*da21d850SDavid van Moolenbroek test77h(void)
980*da21d850SDavid van Moolenbroek {
981*da21d850SDavid van Moolenbroek char *tname, ptest[PATH_MAX], ttest[PATH_MAX];
982*da21d850SDavid van Moolenbroek struct sigaction act, oact;
983*da21d850SDavid van Moolenbroek size_t len;
984*da21d850SDavid van Moolenbroek int i, n, masterfd, slavefd;
985*da21d850SDavid van Moolenbroek
986*da21d850SDavid van Moolenbroek subtest = 8;
987*da21d850SDavid van Moolenbroek
988*da21d850SDavid van Moolenbroek /* We do not want to get SIGHUP signals in this test. */
989*da21d850SDavid van Moolenbroek memset(&act, 0, sizeof(act));
990*da21d850SDavid van Moolenbroek act.sa_handler = SIG_IGN;
991*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &act, &oact) < 0) e(0);
992*da21d850SDavid van Moolenbroek
993*da21d850SDavid van Moolenbroek /*
994*da21d850SDavid van Moolenbroek * Check that Unix98 PTYs cannot be accessed through old-style device
995*da21d850SDavid van Moolenbroek * nodes. We check different combinations of open master and
996*da21d850SDavid van Moolenbroek * slave ends for the Unix98 side (with 'i'): 0) opening and closing
997*da21d850SDavid van Moolenbroek * the master only, 1) closing a slave before the master, and 2)
998*da21d850SDavid van Moolenbroek * closing the slave after the master.
999*da21d850SDavid van Moolenbroek *
1000*da21d850SDavid van Moolenbroek * This test relies on the implementation aspect that /dev/ttypN and
1001*da21d850SDavid van Moolenbroek * /dev/pts/N (with N in the range 0..9) map to the same PTY. It also
1002*da21d850SDavid van Moolenbroek * relies on lack of concurrent PTY allocation outside the test.
1003*da21d850SDavid van Moolenbroek */
1004*da21d850SDavid van Moolenbroek for (i = 0; i <= 2; i++) {
1005*da21d850SDavid van Moolenbroek /* Open a Unix98 PTY and get the slave name. */
1006*da21d850SDavid van Moolenbroek masterfd = get_unix98_pty(&tname);
1007*da21d850SDavid van Moolenbroek
1008*da21d850SDavid van Moolenbroek /* Figure out the slave index number. */
1009*da21d850SDavid van Moolenbroek len = strlen(_PATH_DEV_PTS);
1010*da21d850SDavid van Moolenbroek if (strncmp(tname, _PATH_DEV_PTS, strlen(_PATH_DEV_PTS))) e(0);
1011*da21d850SDavid van Moolenbroek n = atoi(&tname[len]);
1012*da21d850SDavid van Moolenbroek if (n < 0 || n > 9) e(0);
1013*da21d850SDavid van Moolenbroek
1014*da21d850SDavid van Moolenbroek /* Use this index number to create old-style device names. */
1015*da21d850SDavid van Moolenbroek snprintf(ptest, sizeof(ptest), _PATH_DEV "ptyp%u", n);
1016*da21d850SDavid van Moolenbroek snprintf(ttest, sizeof(ttest), _PATH_DEV "ttyp%u", n);
1017*da21d850SDavid van Moolenbroek
1018*da21d850SDavid van Moolenbroek /*
1019*da21d850SDavid van Moolenbroek * Now make sure that opening the old-style master and slave
1020*da21d850SDavid van Moolenbroek * fails as long as either side of the Unix98 PTY is open.
1021*da21d850SDavid van Moolenbroek */
1022*da21d850SDavid van Moolenbroek if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0);
1023*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1024*da21d850SDavid van Moolenbroek if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0);
1025*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1026*da21d850SDavid van Moolenbroek
1027*da21d850SDavid van Moolenbroek if (i > 0) {
1028*da21d850SDavid van Moolenbroek if ((slavefd = open(tname, O_RDWR | O_NOCTTY)) < 0)
1029*da21d850SDavid van Moolenbroek e(0);
1030*da21d850SDavid van Moolenbroek
1031*da21d850SDavid van Moolenbroek if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0);
1032*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1033*da21d850SDavid van Moolenbroek if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0);
1034*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1035*da21d850SDavid van Moolenbroek
1036*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
1037*da21d850SDavid van Moolenbroek
1038*da21d850SDavid van Moolenbroek if (i > 1) {
1039*da21d850SDavid van Moolenbroek if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0);
1040*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1041*da21d850SDavid van Moolenbroek if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0);
1042*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1043*da21d850SDavid van Moolenbroek
1044*da21d850SDavid van Moolenbroek if ((slavefd =
1045*da21d850SDavid van Moolenbroek open(tname, O_RDWR | O_NOCTTY)) < 0) e(0);
1046*da21d850SDavid van Moolenbroek
1047*da21d850SDavid van Moolenbroek if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0);
1048*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1049*da21d850SDavid van Moolenbroek if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0);
1050*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1051*da21d850SDavid van Moolenbroek
1052*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
1053*da21d850SDavid van Moolenbroek
1054*da21d850SDavid van Moolenbroek masterfd = slavefd; /* ugly but saving code */
1055*da21d850SDavid van Moolenbroek }
1056*da21d850SDavid van Moolenbroek
1057*da21d850SDavid van Moolenbroek if (open(ptest, O_RDWR | O_NOCTTY) >= 0) e(0);
1058*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1059*da21d850SDavid van Moolenbroek if (open(ttest, O_RDWR | O_NOCTTY) >= 0) e(0);
1060*da21d850SDavid van Moolenbroek if (errno != EACCES && errno != EIO) e(0);
1061*da21d850SDavid van Moolenbroek }
1062*da21d850SDavid van Moolenbroek
1063*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
1064*da21d850SDavid van Moolenbroek
1065*da21d850SDavid van Moolenbroek /*
1066*da21d850SDavid van Moolenbroek * Once both Unix98 sides are closed, the pseudo terminal can
1067*da21d850SDavid van Moolenbroek * be reused. Thus, opening the old-style master should now
1068*da21d850SDavid van Moolenbroek * succeed. However, it is possible that we do not have
1069*da21d850SDavid van Moolenbroek * permission to open the master at all.
1070*da21d850SDavid van Moolenbroek */
1071*da21d850SDavid van Moolenbroek if ((masterfd = open(ptest, O_RDWR | O_NOCTTY)) < 0 &&
1072*da21d850SDavid van Moolenbroek errno != EACCES) e(0);
1073*da21d850SDavid van Moolenbroek
1074*da21d850SDavid van Moolenbroek if (masterfd >= 0 && close(masterfd) < 0) e(0);
1075*da21d850SDavid van Moolenbroek }
1076*da21d850SDavid van Moolenbroek
1077*da21d850SDavid van Moolenbroek /*
1078*da21d850SDavid van Moolenbroek * The reverse test, which would check that old-style PTYs cannot be
1079*da21d850SDavid van Moolenbroek * accessed through Unix98 device nodes, is impossible to perform
1080*da21d850SDavid van Moolenbroek * properly without root privileges, as we would have to create device
1081*da21d850SDavid van Moolenbroek * nodes manually with mknod(2). All we can do here is ensure that if
1082*da21d850SDavid van Moolenbroek * an old-style PTY is opened, it will not also be allocated as a
1083*da21d850SDavid van Moolenbroek * Unix98 PTY. We do a rather basic check, but only if we can open an
1084*da21d850SDavid van Moolenbroek * old-style master at all. We check two closing orders (with 'i'):
1085*da21d850SDavid van Moolenbroek * 0) the slave first, 1) the master first. Here, we make the hard
1086*da21d850SDavid van Moolenbroek * assumption that the system supports at least four pseudo terminals,
1087*da21d850SDavid van Moolenbroek * of which at least one is currently free.
1088*da21d850SDavid van Moolenbroek */
1089*da21d850SDavid van Moolenbroek for (i = 0; i <= 1; i++) {
1090*da21d850SDavid van Moolenbroek for (n = 0; n < MIN_PTYS; n++) {
1091*da21d850SDavid van Moolenbroek snprintf(ptest, sizeof(ptest), _PATH_DEV "ptyp%u", n);
1092*da21d850SDavid van Moolenbroek
1093*da21d850SDavid van Moolenbroek if ((masterfd = open(ptest, O_RDWR | O_NOCTTY)) >= 0)
1094*da21d850SDavid van Moolenbroek break;
1095*da21d850SDavid van Moolenbroek }
1096*da21d850SDavid van Moolenbroek
1097*da21d850SDavid van Moolenbroek if (n >= MIN_PTYS)
1098*da21d850SDavid van Moolenbroek break;
1099*da21d850SDavid van Moolenbroek
1100*da21d850SDavid van Moolenbroek test_overlap(n);
1101*da21d850SDavid van Moolenbroek
1102*da21d850SDavid van Moolenbroek snprintf(ttest, sizeof(ttest), _PATH_DEV "ttyp%u", n);
1103*da21d850SDavid van Moolenbroek
1104*da21d850SDavid van Moolenbroek /* We can do part of the test only if we can open the slave. */
1105*da21d850SDavid van Moolenbroek if ((slavefd = open(ttest, O_RDWR | O_NOCTTY)) >= 0) {
1106*da21d850SDavid van Moolenbroek test_overlap(n);
1107*da21d850SDavid van Moolenbroek
1108*da21d850SDavid van Moolenbroek if (i > 0) {
1109*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
1110*da21d850SDavid van Moolenbroek
1111*da21d850SDavid van Moolenbroek masterfd = slavefd; /* again, ugly */
1112*da21d850SDavid van Moolenbroek } else
1113*da21d850SDavid van Moolenbroek if (close(slavefd) < 0) e(0);
1114*da21d850SDavid van Moolenbroek
1115*da21d850SDavid van Moolenbroek test_overlap(n);
1116*da21d850SDavid van Moolenbroek }
1117*da21d850SDavid van Moolenbroek
1118*da21d850SDavid van Moolenbroek if (close(masterfd) < 0) e(0);
1119*da21d850SDavid van Moolenbroek }
1120*da21d850SDavid van Moolenbroek
1121*da21d850SDavid van Moolenbroek if (sigaction(SIGHUP, &oact, NULL) < 0) e(0);
112227d0ecdbSDavid van Moolenbroek }
112327d0ecdbSDavid van Moolenbroek
1124433d6423SLionel Sambuc int
main(int argc,char ** argv)1125433d6423SLionel Sambuc main(int argc, char **argv)
1126433d6423SLionel Sambuc {
1127433d6423SLionel Sambuc int i, m;
1128433d6423SLionel Sambuc
1129433d6423SLionel Sambuc start(77);
1130433d6423SLionel Sambuc
1131433d6423SLionel Sambuc if (argc == 2)
1132433d6423SLionel Sambuc m = atoi(argv[1]);
1133433d6423SLionel Sambuc else
1134433d6423SLionel Sambuc m = 0xFF;
1135433d6423SLionel Sambuc
1136433d6423SLionel Sambuc for (i = 0; i < ITERATIONS; i++) {
1137433d6423SLionel Sambuc if (m & 0x01) test77a();
1138433d6423SLionel Sambuc if (m & 0x02) test77b();
1139433d6423SLionel Sambuc if (m & 0x04) test77c();
1140433d6423SLionel Sambuc if (m & 0x08) test77d();
1141433d6423SLionel Sambuc if (m & 0x10) test77e();
114227d0ecdbSDavid van Moolenbroek if (m & 0x20) test77f();
1143*da21d850SDavid van Moolenbroek if (m & 0x40) test77g();
1144*da21d850SDavid van Moolenbroek if (m & 0x80) test77h();
1145433d6423SLionel Sambuc }
1146433d6423SLionel Sambuc
1147433d6423SLionel Sambuc quit();
1148433d6423SLionel Sambuc }
1149