1 /* Tests for opening/closing pseudo terminals - by D.C. van Moolenbroek */
3 * As of the introduction of Unix98 PTY support, this test set actually relies
4 * on the ability to create Unix98 PTYs. The system still supports old-style
5 * PTYs but there is no way to force openpty(3) to use them. However, part of
6 * this test set can still be used to test old-style PTYs: first disable Unix98
7 * PTYs, for example by unmounting PTYFS or temporarily removing /dev/ptmx, and
8 * then run the a-f subtests from this test set as root.
16 #include <sys/syslimits.h>
29 static int sighups
; /* number of SIGHUP signals received */
32 * Signal handler for SIGHUP and SIGUSR1.
35 signal_handler(int sig
)
42 * Set the slave side of the pseudo terminal to raw mode. This simplifies
43 * testing communication.
50 if (tcgetattr(slavefd
, &tios
) < 0) e(0);
54 if (tcsetattr(slavefd
, TCSANOW
, &tios
) < 0) e(0);
58 * See if the given pseudo terminal can successfully perform basic
59 * communication between master and slave.
62 test_comm(int masterfd
, int slavefd
)
69 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
70 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
74 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
75 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
79 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
80 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
84 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
85 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
90 * Obtain a pseudo terminal. The master end is opened and its file descriptor
91 * stored in 'pfd'. The slave path name is stored in 'tname'. For old-style
92 * PTYs, the function returns 1 and stores the master name in 'pname' if not
93 * NULL. For Unix98 PTYs, the function returns 0, in which case no master name
94 * is available. For old-style PTYs, the caller may close and reopen the
95 * master. In that case, we make the assumption that nobody snatches the pair
96 * while we are running. For Unix98 PTYs, the master must be kept open.
99 get_pty(int *pfd
, char pname
[PATH_MAX
], char tname
[PATH_MAX
])
102 int len
, masterfd
, slavefd
;
105 * First try Unix98 PTY allocation, mainly to avoid opening the slave
106 * end immediately. If this fails, try openpty(3) as well.
108 if ((masterfd
= posix_openpt(O_RDWR
| O_NOCTTY
)) != -1) {
109 if (grantpt(masterfd
) != -1 && unlockpt(masterfd
) != -1 &&
110 (name
= ptsname(masterfd
)) != NULL
) {
112 strlcpy(tname
, name
, PATH_MAX
);
116 if (close(masterfd
) < 0) e(0);
119 if (openpty(&masterfd
, &slavefd
, tname
, NULL
, NULL
) < 0) e(0);
121 test_comm(masterfd
, slavefd
);
125 if (close(slavefd
) < 0) e(0);
128 * openpty(3) gives us only the slave name, but we also want the master
131 len
= strlen(_PATH_DEV
);
132 if (strncmp(tname
, _PATH_DEV
, len
)) e(0);
134 if (strncmp(&tname
[len
], "tty", 3))
135 return 0; /* Unix98 after all? Well okay, whatever.. */
138 strlcpy(pname
, tname
, PATH_MAX
);
146 * Test various orders of opening and closing the master and slave sides of a
147 * pseudo terminal, as well as opening/closing one side without ever opening
148 * the other. This test is meaningful mainly for old-style pseudoterminals.
153 struct sigaction act
, oact
;
154 char pname
[PATH_MAX
], tname
[PATH_MAX
];
155 int oldstyle
, masterfd
, slavefd
;
159 /* We do not want to get SIGHUP signals in this test. */
160 memset(&act
, 0, sizeof(act
));
161 act
.sa_handler
= SIG_IGN
;
162 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(0);
164 /* Obtain a pseudo terminal. */
165 oldstyle
= get_pty(&masterfd
, pname
, tname
);
168 /* Try closing the master. */
169 if (close(masterfd
) < 0) e(0);
171 /* See if we can reopen the master. */
172 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
175 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
177 test_comm(masterfd
, slavefd
);
179 /* In the meantime, test different closing orders. This is order A. */
180 if (close(slavefd
) < 0) e(0);
181 if (close(masterfd
) < 0) e(0);
183 /* Now try opening the pair (or a new pair) again. */
185 oldstyle
= get_pty(&masterfd
, pname
, tname
);
187 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
189 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
191 test_comm(masterfd
, slavefd
);
193 if (close(slavefd
) < 0) e(0);
196 * Try reopening the slave after closing it. It is not very important
197 * that this works, but the TTY driver should currently support it.
199 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
201 test_comm(masterfd
, slavefd
);
203 /* This is closing order B. This may or may not cause a SIGHUP. */
204 if (close(masterfd
) < 0) e(0);
205 if (close(slavefd
) < 0) e(0);
207 /* Try the normal open procedure. */
209 oldstyle
= get_pty(&masterfd
, pname
, tname
);
211 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
213 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
215 test_comm(masterfd
, slavefd
);
217 if (close(slavefd
) < 0) e(0);
218 if (close(masterfd
) < 0) e(0);
221 * Try reopening and closing the slave, without opening the master.
222 * This should work on old-style PTYS, but not on Unix98 PTYs.
224 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) >= 0) {
227 if (close(slavefd
) < 0) e(0);
231 /* Again, try the normal open procedure. */
233 oldstyle
= get_pty(&masterfd
, pname
, tname
);
235 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
237 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
239 test_comm(masterfd
, slavefd
);
241 if (close(slavefd
) < 0) e(0);
242 if (close(masterfd
) < 0) e(0);
245 * Finally, try opening the slave first. This does not work with
249 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
250 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
252 test_comm(masterfd
, slavefd
);
254 if (close(slavefd
) < 0) e(0);
255 if (close(masterfd
) < 0) e(0);
258 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(0);
262 * Test opening a single side multiple times.
267 char pname
[PATH_MAX
], tname
[PATH_MAX
];
268 int oldstyle
, masterfd
, slavefd
, extrafd
;
272 /* Obtain a pseudo terminal. */
273 oldstyle
= get_pty(&masterfd
, pname
, tname
);
275 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
278 * It must not be possible to open the master multiple times. Doing so
279 * is possible only if we have a named master, i.e., an old-style PTY.
281 test_comm(masterfd
, slavefd
);
284 if ((extrafd
= open(pname
, O_RDWR
| O_NOCTTY
)) >= 0) e(0);
285 if (errno
!= EIO
) e(0);
288 test_comm(masterfd
, slavefd
);
290 if (close(slavefd
) < 0) e(0);
291 if (close(masterfd
) < 0) e(0);
293 /* The slave can be opened multiple times, though. */
294 oldstyle
= get_pty(&masterfd
, pname
, tname
);
296 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
298 test_comm(masterfd
, slavefd
);
300 if ((extrafd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
302 test_comm(masterfd
, extrafd
);
303 test_comm(masterfd
, slavefd
);
305 if (close(slavefd
) < 0) e(0);
306 if (close(extrafd
) < 0) e(0);
307 if (close(masterfd
) < 0) e(0);
311 * Test communication on half-open pseudo terminals.
316 struct sigaction act
, oact
;
317 char pname
[PATH_MAX
], tname
[PATH_MAX
];
318 int oldstyle
, masterfd
, slavefd
;
323 /* We do not want to get SIGHUP signals in this test. */
324 memset(&act
, 0, sizeof(act
));
325 act
.sa_handler
= SIG_IGN
;
326 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(0);
328 /* Obtain a pseudo terminal. */
329 oldstyle
= get_pty(&masterfd
, pname
, tname
);
332 * For old-style pseudo terminals, we have just opened and closed the
333 * slave end, which alters the behavior we are testing below. Close
334 * and reopen the master to start fresh.
337 if (close(masterfd
) < 0) e(0);
339 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
342 /* Writes to the master should be buffered until there is a slave. */
344 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
346 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
350 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
353 /* Discard the echo on the master. */
354 if (tcflush(slavefd
, TCOFLUSH
) != 0) e(0);
356 test_comm(masterfd
, slavefd
);
358 if (close(slavefd
) < 0) e(0);
360 /* Writes to the master after the slave has been closed should fail. */
361 if (write(masterfd
, &c
, sizeof(c
)) >= 0) e(0);
362 if (errno
!= EIO
) e(0);
365 if (close(masterfd
) < 0) e(0);
368 * Writes to the slave should be buffered until there is a master.
369 * This applies to old-style PTYs only.
371 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
377 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
379 if ((masterfd
= open(pname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
381 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
385 test_comm(masterfd
, slavefd
);
387 if (close(masterfd
) < 0) e(0);
389 if (write(slavefd
, &c
, sizeof(c
)) >= 0) e(0);
390 if (errno
!= EIO
) e(0);
392 /* Reads from the slave should return EOF if the master is gone. */
393 if (read(slavefd
, &c
, sizeof(c
)) != 0) e(0);
395 if (close(slavefd
) < 0) e(0);
397 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(0);
401 * Wait for a child process to terminate. Return 0 if the child exited without
402 * errors, -1 otherwise.
409 if (wait(&status
) <= 0) return -1;
410 if (!WIFEXITED(status
)) return -1;
411 if (WEXITSTATUS(status
) != 0) return -1;
417 * Test opening the slave side with and without the O_NOCTTY flag.
422 char pname
[PATH_MAX
], tname
[PATH_MAX
];
423 int masterfd
, slavefd
;
427 /* Make ourselves process group leader if we aren't already. */
430 /* Obtain a pseudo terminal. */
431 (void)get_pty(&masterfd
, NULL
, tname
);
434 * Opening the slave with O_NOCTTY should not change its controlling
439 if (close(masterfd
) < 0) e(0);
441 if (setsid() < 0) e(0);
443 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
445 if (open("/dev/tty", O_RDWR
) >= 0) e(0);
446 if (errno
!= ENXIO
) e(0);
455 if (waitchild() < 0) e(0);
457 if (close(masterfd
) < 0) e(0);
459 (void)get_pty(&masterfd
, pname
, tname
);
462 * Opening the slave without O_NOCTTY should change its controlling
467 if (close(masterfd
) < 0) e(0);
469 if (setsid() < 0) e(0);
471 if ((slavefd
= open(tname
, O_RDWR
)) < 0) e(0);
473 if (open("/dev/tty", O_RDWR
) < 0) e(0);
482 if (waitchild() < 0) e(0);
484 if (close(masterfd
) < 0) e(0);
488 * Test receiving of SIGHUP on master hang-up. All of the tests so far have
489 * ignored SIGHUP, and probably would not have received one anyway, since the
490 * process was not its own session leader. Time to test this aspect.
495 struct sigaction act
, hup_oact
, usr_oact
;
497 char tname
[PATH_MAX
];
498 int masterfd
, slavefd
;
502 memset(&act
, 0, sizeof(act
));
503 act
.sa_handler
= signal_handler
;
504 if (sigaction(SIGHUP
, &act
, &hup_oact
) < 0) e(0);
506 memset(&act
, 0, sizeof(act
));
507 act
.sa_handler
= signal_handler
;
508 if (sigaction(SIGUSR1
, &act
, &usr_oact
) < 0) e(0);
511 sigaddset(&set
, SIGHUP
);
512 sigaddset(&set
, SIGUSR1
);
513 if (sigprocmask(SIG_BLOCK
, &set
, &oset
) < 0) e(0);
517 /* Make ourselves process group leader if we aren't already. */
520 /* Obtain a pseudo terminal. */
521 (void)get_pty(&masterfd
, NULL
, tname
);
525 if (close(masterfd
) < 0) e(0);
527 /* Become session leader. */
528 if (setsid() < 0) e(0);
530 if ((slavefd
= open(tname
, O_RDWR
)) < 0) e(0);
532 /* Tell the parent we are ready. */
533 kill(getppid(), SIGUSR1
);
535 /* We should now get a SIGHUP. */
537 if (sigsuspend(&set
) >= 0) e(0);
539 if (sighups
!= 1) e(0);
548 /* Wait for SIGUSR1 from the child. */
550 if (sigsuspend(&set
) >= 0) e(0);
552 /* Closing the master should now raise a SIGHUP signal in the child. */
553 if (close(masterfd
) < 0) e(0);
555 if (waitchild() < 0) e(0);
557 if (sigprocmask(SIG_SETMASK
, &oset
, NULL
) < 0) e(0);
559 if (sigaction(SIGHUP
, &hup_oact
, NULL
) < 0) e(0);
560 if (sigaction(SIGUSR1
, &usr_oact
, NULL
) < 0) e(0);
564 * Test basic select functionality on /dev/tty. While this test should not be
565 * part of this test set, we already have all the infrastructure we need here.
570 struct sigaction act
, oact
;
571 char c
, tname
[PATH_MAX
];
574 int fd
, maxfd
, masterfd
, slavefd
;
578 /* We do not want to get SIGHUP signals in this test. */
579 memset(&act
, 0, sizeof(act
));
580 act
.sa_handler
= SIG_IGN
;
581 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(0);
583 /* Obtain a pseudo terminal. */
584 (void)get_pty(&masterfd
, NULL
, tname
);
588 if (close(masterfd
) < 0) e(0);
590 if (setsid() < 0) e(0);
592 if ((slavefd
= open(tname
, O_RDWR
)) < 0) e(0);
594 if ((fd
= open("/dev/tty", O_RDWR
)) < 0) e(0);
598 /* Without slave input, /dev/tty is not ready for reading. */
604 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 0) e(0);
605 if (FD_ISSET(fd
, &fd_set
)) e(0);
611 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 0) e(0);
612 if (FD_ISSET(fd
, &fd_set
)) e(0);
614 /* It will be ready for writing, though. */
617 if (select(fd
+ 1, NULL
, &fd_set
, NULL
, NULL
) != 1) e(0);
618 if (!FD_ISSET(fd
, &fd_set
)) e(0);
620 /* Test mixing file descriptors to the same terminal. */
623 FD_SET(slavefd
, &fd_set
);
627 maxfd
= fd
> slavefd
? fd
: slavefd
;
628 if (select(maxfd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 0) e(0);
629 if (FD_ISSET(fd
, &fd_set
)) e(0);
630 if (FD_ISSET(slavefd
, &fd_set
)) e(0);
632 /* The delayed echo on the master must wake up our select. */
634 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
639 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, NULL
) != 1) e(0);
640 if (!FD_ISSET(fd
, &fd_set
)) e(0);
642 /* Select must now still flag readiness for reading. */
646 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 1) e(0);
647 if (!FD_ISSET(fd
, &fd_set
)) e(0);
649 /* That is, until we read the byte. */
650 if (read(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
653 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 0) e(0);
654 if (FD_ISSET(fd
, &fd_set
)) e(0);
656 /* Ask the parent to close the master. */
658 if (write(slavefd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
662 /* The closure must cause an EOF condition on the slave. */
663 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, NULL
) != 1) e(0);
664 if (!FD_ISSET(fd
, &fd_set
)) e(0);
666 if (select(fd
+ 1, &fd_set
, NULL
, NULL
, NULL
) != 1) e(0);
667 if (!FD_ISSET(fd
, &fd_set
)) e(0);
669 if (read(slavefd
, &c
, sizeof(c
)) != 0) e(0);
675 /* Wait for the child to write something to the slave. */
677 FD_SET(masterfd
, &fd_set
);
679 if (select(masterfd
+ 1, &fd_set
, NULL
, NULL
, NULL
) != 1)
681 if (!FD_ISSET(masterfd
, &fd_set
)) e(0);
683 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
686 /* Write a reply once the child is blocked in its select. */
689 if (select(masterfd
+ 1, &fd_set
, NULL
, NULL
, &tv
) != 0)
693 if (write(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
695 /* Wait for the child to request closing the master. */
696 if (read(masterfd
, &c
, sizeof(c
)) != sizeof(c
)) e(0);
699 /* Close the master once the child is blocked in its select. */
707 if (waitchild() < 0) e(0);
709 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(0);
713 * See if the directory contents of /dev/pts are as we expect. We have to keep
714 * in mind that other programs may have pseudo terminals open while we are
715 * running, although we assume that those programs do not open or close PTYs
716 * while we are running.
719 test_getdents(int nindex
, int array
[3], int present
[3])
725 char path
[PATH_MAX
], *endp
;
727 int i
, n
, seen_dot
, seen_dotdot
, seen_index
[3], *seen
;
729 seen_dot
= seen_dotdot
= 0;
730 for (i
= 0; i
< nindex
; i
++)
733 if ((group
= getgrnam("tty")) == NULL
) e(0);
734 tty_gid
= group
->gr_gid
;
736 if ((dirp
= opendir(_PATH_DEV_PTS
)) == NULL
) e(0);
738 while ((dp
= readdir(dirp
)) != NULL
) {
739 snprintf(path
, sizeof(path
), _PATH_DEV_PTS
"%s", dp
->d_name
);
740 if (stat(path
, &buf
) < 0) e(0);
742 if (!strcmp(dp
->d_name
, ".") || !strcmp(dp
->d_name
, "..")) {
744 (dp
->d_name
[1] == '.') ? &seen_dot
: &seen_dotdot
;
748 /* Check basic dirent and stat fields. */
749 if (dp
->d_type
!= DT_DIR
) e(0);
750 if (dp
->d_name
[1] == '\0' &&
751 buf
.st_ino
!= dp
->d_fileno
) e(0);
752 if (!S_ISDIR(buf
.st_mode
)) e(0);
753 if (buf
.st_nlink
< 2) e(0);
755 /* The file name must be a number. */
757 n
= strtol(dp
->d_name
, &endp
, 10);
758 if (errno
!= 0) e(0);
759 if (dp
->d_name
[0] == '\0' || *endp
!= '\0') e(0);
762 /* Check basic dirent and stat fields. */
763 if (dp
->d_type
!= DT_CHR
) e(0);
764 if (buf
.st_ino
!= dp
->d_fileno
) e(0);
765 if (!S_ISCHR(buf
.st_mode
)) e(0);
766 if (buf
.st_nlink
!= 1) e(0);
767 if (buf
.st_size
!= 0) e(0);
768 if (buf
.st_rdev
== 0) e(0);
770 /* Is this one of the PTYs we created? */
771 for (i
= 0; i
< nindex
; i
++) {
773 if (seen_index
[i
]) e(0);
780 /* If so, perform some extra tests. */
782 if ((buf
.st_mode
& ALLPERMS
) != 0620) e(0);
783 if (buf
.st_uid
!= getuid()) e(0);
784 if (buf
.st_gid
!= tty_gid
) e(0);
789 if (closedir(dirp
) < 0) e(0);
792 if (!seen_dotdot
) e(0);
793 for (i
= 0; i
< nindex
; i
++)
794 if (seen_index
[i
] != present
[i
]) e(0);
798 * Obtain a Unix98 PTY. Return an open file descriptor for the master side,
799 * and store the name of the slave side in 'tptr'.
802 get_unix98_pty(char ** tptr
)
806 if ((masterfd
= posix_openpt(O_RDWR
| O_NOCTTY
)) < 0) e(0);
808 if (grantpt(masterfd
) < 0) e(0);
810 /* This call is a no-op on MINIX3. */
811 if (unlockpt(masterfd
) < 0) e(0);
813 if ((*tptr
= ptsname(masterfd
)) == NULL
) e(0);
819 * Test for Unix98 PTY support and PTYFS.
827 int i
, masterfd
, slavefd
, fd
[3], array
[3], present
[3];
832 * Test basic operation, and verify that the slave node disappears
833 * after both sides of the pseudo terminal have been closed. We check
834 * different combinations of open master and slave ends (with 'i'):
835 * 0) opening and closing the master only, 1) closing a slave before
836 * the master, and 2) closing the slave after the master.
838 for (i
= 0; i
<= 2; i
++) {
839 masterfd
= get_unix98_pty(&tname
);
841 if (access(tname
, R_OK
| W_OK
) < 0) e(0);
844 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0)
847 if (access(tname
, R_OK
| W_OK
) < 0) e(0);
850 if (close(masterfd
) < 0) e(0);
852 masterfd
= slavefd
; /* ugly but saving code */
854 if (close(slavefd
) < 0) e(0);
857 if (access(tname
, R_OK
| W_OK
) < 0) e(0);
859 if (close(masterfd
) < 0) e(0);
861 if (access(tname
, R_OK
| W_OK
) == 0) e(0);
865 * Test whether we can open multiple pseudo terminals. We need to be
866 * able to open three PTYs. Verify that they are properly listed in
867 * the /dev/pts directory contents, and have proper attributes set.
869 test_getdents(0, NULL
, NULL
);
871 for (i
= 0; i
< 3; i
++) {
872 fd
[i
] = get_unix98_pty(&tname
);
874 /* Figure out the slave index number. */
875 len
= strlen(_PATH_DEV_PTS
);
876 if (strncmp(tname
, _PATH_DEV_PTS
, strlen(_PATH_DEV_PTS
))) e(0);
877 array
[i
] = atoi(&tname
[len
]);
881 test_getdents(3, array
, present
);
883 if (close(fd
[0]) < 0) e(0);
886 test_getdents(3, array
, present
);
888 if (close(fd
[2]) < 0) e(0);
891 test_getdents(3, array
, present
);
893 if (close(fd
[1]) < 0) e(0);
896 test_getdents(3, array
, present
);
899 * Test chmod(2) on a slave node, and multiple calls to grantpt(3).
900 * The first grantpt(3) call should create the slave node (we currently
901 * can not test this: the slave node may be created earlier as well,
902 * but we do not know its name), whereas subsequent grantpt(3) calls
903 * should reset its mode, uid, and gid. Testing the latter two and
904 * chown(2) on the slave node requires root, so we skip that part.
906 * Finally, NetBSD revokes access to existing slave file descriptors
907 * upon a call to grantpt(3). This is not a POSIX requirement, but
908 * NetBSD needs this for security reasons because it already creates
909 * the slave node when the master is opened (and it does not lock the
910 * slave until a call to unlockpt(3)). MINIX3 does not implement
911 * revocation this way, because the slave node is created only upon the
912 * call to grantpt(3), thus leaving no insecure window for the slave
913 * side between posix_openpt(3) and grantpt(3). While this behavior
914 * may be changed later, we test for the lack of revocation here now.
916 masterfd
= get_unix98_pty(&tname
);
918 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
920 if (stat(tname
, &buf
) != 0) e(0);
921 if (buf
.st_mode
!= (S_IFCHR
| 0620)) e(0);
923 if (chmod(tname
, S_IFCHR
| 0630) != 0) e(0);
925 if (stat(tname
, &buf
) != 0) e(0);
926 if (buf
.st_mode
!= (S_IFCHR
| 0630)) e(0);
928 if (grantpt(masterfd
) != 0) e(0);
930 if (stat(tname
, &buf
) != 0) e(0);
931 if (buf
.st_mode
!= (S_IFCHR
| 0620)) e(0);
933 test_comm(masterfd
, slavefd
);
935 if (close(slavefd
) < 0) e(0);
936 if (close(masterfd
) < 0) e(0);
938 test_getdents(0, NULL
, NULL
);
942 * Check that the given PTY index, which is in use for an old-style PTY, is not
943 * allocated through Unix98 PTY allocation. This test is not foolproof, but it
944 * does the job well enough.
951 int i
, n
, fd
[MIN_PTYS
];
953 for (i
= 0; i
< MIN_PTYS
; i
++) {
954 if ((fd
[i
] = posix_openpt(O_RDWR
| O_NOCTTY
)) < 0)
955 break; /* out of PTYs */
956 if (grantpt(fd
[i
]) < 0) e(0);
957 if (unlockpt(fd
[i
]) < 0) e(0);
958 if ((tname
= ptsname(fd
[i
])) == NULL
) e(0);
960 len
= strlen(_PATH_DEV_PTS
);
961 if (strncmp(tname
, _PATH_DEV_PTS
, strlen(_PATH_DEV_PTS
))) e(0);
962 n
= atoi(&tname
[len
]);
963 if (n
< 0 || n
> 9) e(0);
968 for (i
--; i
>= 0; i
--)
969 if (close(fd
[i
]) < 0) e(0);
973 * Test for mixing access to old-style and Unix98 PTYs. Since the PTY service
974 * internally shares the set of pseudo terminals between the two types, it has
975 * to implement checks to prevent that a PTY opened as one type is also
976 * accessed through the other type. We test some of those checks here.
981 char *tname
, ptest
[PATH_MAX
], ttest
[PATH_MAX
];
982 struct sigaction act
, oact
;
984 int i
, n
, masterfd
, slavefd
;
988 /* We do not want to get SIGHUP signals in this test. */
989 memset(&act
, 0, sizeof(act
));
990 act
.sa_handler
= SIG_IGN
;
991 if (sigaction(SIGHUP
, &act
, &oact
) < 0) e(0);
994 * Check that Unix98 PTYs cannot be accessed through old-style device
995 * nodes. We check different combinations of open master and
996 * slave ends for the Unix98 side (with 'i'): 0) opening and closing
997 * the master only, 1) closing a slave before the master, and 2)
998 * closing the slave after the master.
1000 * This test relies on the implementation aspect that /dev/ttypN and
1001 * /dev/pts/N (with N in the range 0..9) map to the same PTY. It also
1002 * relies on lack of concurrent PTY allocation outside the test.
1004 for (i
= 0; i
<= 2; i
++) {
1005 /* Open a Unix98 PTY and get the slave name. */
1006 masterfd
= get_unix98_pty(&tname
);
1008 /* Figure out the slave index number. */
1009 len
= strlen(_PATH_DEV_PTS
);
1010 if (strncmp(tname
, _PATH_DEV_PTS
, strlen(_PATH_DEV_PTS
))) e(0);
1011 n
= atoi(&tname
[len
]);
1012 if (n
< 0 || n
> 9) e(0);
1014 /* Use this index number to create old-style device names. */
1015 snprintf(ptest
, sizeof(ptest
), _PATH_DEV
"ptyp%u", n
);
1016 snprintf(ttest
, sizeof(ttest
), _PATH_DEV
"ttyp%u", n
);
1019 * Now make sure that opening the old-style master and slave
1020 * fails as long as either side of the Unix98 PTY is open.
1022 if (open(ptest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1023 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1024 if (open(ttest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1025 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1028 if ((slavefd
= open(tname
, O_RDWR
| O_NOCTTY
)) < 0)
1031 if (open(ptest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1032 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1033 if (open(ttest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1034 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1036 if (close(slavefd
) < 0) e(0);
1039 if (open(ptest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1040 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1041 if (open(ttest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1042 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1045 open(tname
, O_RDWR
| O_NOCTTY
)) < 0) e(0);
1047 if (open(ptest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1048 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1049 if (open(ttest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1050 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1052 if (close(masterfd
) < 0) e(0);
1054 masterfd
= slavefd
; /* ugly but saving code */
1057 if (open(ptest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1058 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1059 if (open(ttest
, O_RDWR
| O_NOCTTY
) >= 0) e(0);
1060 if (errno
!= EACCES
&& errno
!= EIO
) e(0);
1063 if (close(masterfd
) < 0) e(0);
1066 * Once both Unix98 sides are closed, the pseudo terminal can
1067 * be reused. Thus, opening the old-style master should now
1068 * succeed. However, it is possible that we do not have
1069 * permission to open the master at all.
1071 if ((masterfd
= open(ptest
, O_RDWR
| O_NOCTTY
)) < 0 &&
1072 errno
!= EACCES
) e(0);
1074 if (masterfd
>= 0 && close(masterfd
) < 0) e(0);
1078 * The reverse test, which would check that old-style PTYs cannot be
1079 * accessed through Unix98 device nodes, is impossible to perform
1080 * properly without root privileges, as we would have to create device
1081 * nodes manually with mknod(2). All we can do here is ensure that if
1082 * an old-style PTY is opened, it will not also be allocated as a
1083 * Unix98 PTY. We do a rather basic check, but only if we can open an
1084 * old-style master at all. We check two closing orders (with 'i'):
1085 * 0) the slave first, 1) the master first. Here, we make the hard
1086 * assumption that the system supports at least four pseudo terminals,
1087 * of which at least one is currently free.
1089 for (i
= 0; i
<= 1; i
++) {
1090 for (n
= 0; n
< MIN_PTYS
; n
++) {
1091 snprintf(ptest
, sizeof(ptest
), _PATH_DEV
"ptyp%u", n
);
1093 if ((masterfd
= open(ptest
, O_RDWR
| O_NOCTTY
)) >= 0)
1102 snprintf(ttest
, sizeof(ttest
), _PATH_DEV
"ttyp%u", n
);
1104 /* We can do part of the test only if we can open the slave. */
1105 if ((slavefd
= open(ttest
, O_RDWR
| O_NOCTTY
)) >= 0) {
1109 if (close(masterfd
) < 0) e(0);
1111 masterfd
= slavefd
; /* again, ugly */
1113 if (close(slavefd
) < 0) e(0);
1118 if (close(masterfd
) < 0) e(0);
1121 if (sigaction(SIGHUP
, &oact
, NULL
) < 0) e(0);
1125 main(int argc
, char **argv
)
1136 for (i
= 0; i
< ITERATIONS
; i
++) {
1137 if (m
& 0x01) test77a();
1138 if (m
& 0x02) test77b();
1139 if (m
& 0x04) test77c();
1140 if (m
& 0x08) test77d();
1141 if (m
& 0x10) test77e();
1142 if (m
& 0x20) test77f();
1143 if (m
& 0x40) test77g();
1144 if (m
& 0x80) test77h();