1 /* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */
2 /* This test needs to be run as root; otherwise, openpty() won't work. */
9 #include <sys/syslimits.h>
18 static int sighups
; /* number of SIGHUP signals received */
21 * Signal handler for SIGHUP and SIGUSR1.
24 signal_handler(int sig
)
31 * Set the slave side of the pseudo terminal to raw mode. This simplifies
32 * testing communication.
39 if (tcgetattr(slavefd
, &tios
) < 0) e(100);
43 if (tcsetattr(slavefd
, TCSANOW
, &tios
) < 0) e(101);
47 * See if the given pseudo terminal can successfully perform basic
48 * communication between master and slave.
51 test_comm(int masterfd
, int slavefd
)
58 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(200);
59 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(201);
63 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(203);
64 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(204);
68 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(206);
69 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(207);
73 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(209);
74 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(210);
79 * Get device node names for the master and slave end of a free pseudo
80 * terminal. We don't want to replicate the entire openpty(3) logic here, so
81 * start by letting openpty(3) do the work for us. We make the assumption that
82 * nobody snatches the pair while we are running.
85 get_names(char pname
[PATH_MAX
], char tname
[PATH_MAX
])
87 int len
, masterfd
, slavefd
;
89 if (openpty(&masterfd
, &slavefd
, tname
, NULL
, NULL
) < 0) e(300);
92 * openpty(3) gives us only the slave name, but we also need the master
95 strlcpy(pname
, tname
, PATH_MAX
);
96 len
= strlen(_PATH_DEV
);
98 if (strncmp(pname
, _PATH_DEV
, len
)) e(301);
100 /* If this fails, this test needs to be updated. */
101 if (pname
[len
] != 't') e(302);
105 test_comm(masterfd
, slavefd
);
107 if (close(masterfd
) < 0) e(303);
108 if (close(slavefd
) < 0) e(304);
112 * Test various orders of opening and closing the master and slave sides of a
113 * pseudo terminal, as well as opening/closing one side without ever opening
119 struct sigaction act
, oact
;
120 char pname
[PATH_MAX
], tname
[PATH_MAX
];
121 int masterfd
, slavefd
;
125 /* We do not want to get SIGHUP signals in this test. */
126 memset(&act
, 0, sizeof(act
));
127 act
.sa_handler
= SIG_IGN
;
128 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(1);
130 /* Get master and slave device names for a free pseudo terminal. */
131 get_names(pname
, tname
);
133 /* Try opening and then closing the master. */
134 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(2);
136 if (close(masterfd
) < 0) e(3);
138 /* Now see if we can reopen the master as well as the slave. */
139 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(4);
140 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(5);
142 test_comm(masterfd
, slavefd
);
144 /* In the meantime, test different closing orders. This is order A. */
145 if (close(slavefd
) < 0) e(6);
146 if (close(masterfd
) < 0) e(7);
148 /* Now try opening the pair again. */
149 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(8);
150 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(9);
152 test_comm(masterfd
, slavefd
);
154 if (close(slavefd
) < 0) e(10);
157 * Try reopening the slave after closing it. It is not very important
158 * that this works, but the TTY driver should currently support it.
160 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(11);
162 test_comm(masterfd
, slavefd
);
164 /* This is closing order B. This may or may not cause a SIGHUP. */
165 if (close(masterfd
) < 0) e(12);
166 if (close(slavefd
) < 0) e(13);
168 /* Try the normal open procedure. */
169 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(14);
170 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(15);
172 test_comm(masterfd
, slavefd
);
174 if (close(slavefd
) < 0) e(16);
175 if (close(masterfd
) < 0) e(17);
177 /* Try reopening and closing the slave, without opening the master. */
178 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(18);
180 if (close(slavefd
) < 0) e(19);
182 /* Again, try the normal open procedure. */
183 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(20);
184 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(21);
186 test_comm(masterfd
, slavefd
);
188 if (close(slavefd
) < 0) e(22);
189 if (close(masterfd
) < 0) e(23);
191 /* Finally, try opening the slave first. */
192 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(24);
193 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(25);
195 test_comm(masterfd
, slavefd
);
197 if (close(slavefd
) < 0) e(26);
198 if (close(masterfd
) < 0) e(27);
200 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(28);
204 * Test opening a single side multiple times.
209 char pname
[PATH_MAX
], tname
[PATH_MAX
];
210 int masterfd
, slavefd
, extrafd
;
214 /* Get master and slave device names for a free pseudo terminal. */
215 get_names(pname
, tname
);
217 /* It must not be possible to open the master multiple times. */
218 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(1);
219 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(2);
221 test_comm(masterfd
, slavefd
);
223 if ((extrafd
= open(pname
, O_RDWR
| O_NOCTTY
)) >= 0) e(3);
224 if (errno
!= EIO
) e(4);
226 test_comm(masterfd
, slavefd
);
228 if (close(slavefd
) < 0) e(5);
229 if (close(masterfd
) < 0) e(6);
231 /* The slave can be opened multiple times, though. */
232 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(7);
233 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(8);
235 test_comm(masterfd
, slavefd
);
237 if ((extrafd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(9);
239 test_comm(masterfd
, extrafd
);
240 test_comm(masterfd
, slavefd
);
242 if (close(slavefd
) < 0) e(10);
243 if (close(extrafd
) < 0) e(11);
244 if (close(masterfd
) < 0) e(12);
248 * Test communication on half-open pseudo terminals.
253 struct sigaction act
, oact
;
254 char pname
[PATH_MAX
], tname
[PATH_MAX
];
255 int masterfd
, slavefd
;
260 /* We do not want to get SIGHUP signals in this test. */
261 memset(&act
, 0, sizeof(act
));
262 act
.sa_handler
= SIG_IGN
;
263 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(1);
265 /* Get master and slave device names for a free pseudo terminal. */
266 get_names(pname
, tname
);
268 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(2);
270 /* Writes to the master should be buffered until there is a slave. */
272 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(3);
274 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(4);
278 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(5);
281 /* Discard the echo on the master. */
282 if (tcflush(slavefd
, TCOFLUSH
) != 0) e(7);
284 test_comm(masterfd
, slavefd
);
286 if (close(slavefd
) < 0) e(8);
288 /* Writes to the master after the slave has been closed should fail. */
289 if (write(masterfd
, &c
, sizeof(c
)) >= 0) e(9);
290 if (errno
!= EIO
) e(10);
292 if (close(masterfd
) < 0) e(11);
294 /* Writes to the slave should be buffered until there is a master. */
295 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(12);
300 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(13);
302 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(14);
304 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(15);
307 test_comm(masterfd
, slavefd
);
309 if (close(masterfd
) < 0) e(17);
311 if (write(slavefd
, &c
, sizeof(c
)) >= 0) e(18);
312 if (errno
!= EIO
) e(19);
314 if (close(slavefd
) < 0) e(20);
316 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(21);
320 * Test opening the slave side with and without the O_NOCTTY flag.
325 char pname
[PATH_MAX
], tname
[PATH_MAX
];
326 int masterfd
, slavefd
;
330 /* Get master and slave device names for a free pseudo terminal. */
331 get_names(pname
, tname
);
333 /* Make ourselves process group leader if we aren't already. */
336 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(1);
339 * Opening the slave with O_NOCTTY should not change its controlling
344 if (setsid() < 0) e(2);
346 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(3);
348 if (open("/dev/tty", O_RDWR
) >= 0) e(4);
349 if (errno
!= ENXIO
) e(5);
358 if (wait(NULL
) <= 0) e(7);
360 if (close(masterfd
) < 0) e(8);
362 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(9);
365 * Opening the slave without O_NOCTTY should change its controlling
370 if (setsid() < 0) e(10);
372 if ((slavefd
= open(tname
, O_RDWR
)) < 0) e(11);
374 if (open("/dev/tty", O_RDWR
) < 0) e(12);
383 if (wait(NULL
) <= 0) e(14);
385 if (close(masterfd
) < 0) e(15);
389 * Test receiving of SIGHUP on master hang-up. All of the tests so far have
390 * ignored SIGHUP, and probably would not have received one anyway, since the
391 * process was not its own session leader. Time to test this aspect.
396 struct sigaction act
, hup_oact
, usr_oact
;
398 char pname
[PATH_MAX
], tname
[PATH_MAX
];
399 int masterfd
, slavefd
;
403 /* Get master and slave device names for a free pseudo terminal. */
404 get_names(pname
, tname
);
406 memset(&act
, 0, sizeof(act
));
407 act
.sa_handler
= signal_handler
;
408 if (sigaction(SIGHUP
, &act
, &hup_oact
) < 0) e(1);
410 memset(&act
, 0, sizeof(act
));
411 act
.sa_handler
= signal_handler
;
412 if (sigaction(SIGUSR1
, &act
, &usr_oact
) < 0) e(2);
415 sigaddset(&set
, SIGHUP
);
416 sigaddset(&set
, SIGUSR1
);
417 if (sigprocmask(SIG_BLOCK
, &set
, &oset
) < 0) e(3);
421 /* Make ourselves process group leader if we aren't already. */
424 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(4);
428 if (close(masterfd
) < 0) e(5);
430 /* Become session leader. */
431 if (setsid() < 0) e(6);
433 if ((slavefd
= open(tname
, O_RDWR
)) < 0) e(7);
435 /* Tell the parent we are ready. */
436 kill(getppid(), SIGUSR1
);
438 /* We should now get a SIGHUP. */
440 if (sigsuspend(&set
) >= 0) e(8);
442 if (sighups
!= 1) e(9);
451 /* Wait for SIGUSR1 from the child. */
453 if (sigsuspend(&set
) >= 0) e(11);
455 /* Closing the master should now raise a SIGHUP signal in the child. */
456 if (close(masterfd
) < 0) e(12);
458 if (wait(NULL
) <= 0) e(13);
460 if (sigprocmask(SIG_SETMASK
, &oset
, NULL
) < 0) e(14);
462 if (sigaction(SIGHUP
, &hup_oact
, NULL
) < 0) e(15);
463 if (sigaction(SIGUSR1
, &usr_oact
, NULL
) < 0) e(16);
467 main(int argc
, char **argv
)
478 for (i
= 0; i
< ITERATIONS
; i
++) {
479 if (m
& 0x01) test77a();
480 if (m
& 0x02) test77b();
481 if (m
& 0x04) test77c();
482 if (m
& 0x08) test77d();
483 if (m
& 0x10) test77e();