static void h_check(int test) { struct sigaction sa; jmp_buf jb; sigjmp_buf sjb; sigset_t ss; int i, x; myself = pthread_self(); i = getpid(); if (test == TEST_SETJMP || test == TEST_SIGSETJMP_SAVE) expectsignal = 0; else if (test == TEST_U_SETJMP || test == TEST_SIGSETJMP_NOSAVE) expectsignal = 1; else atf_tc_fail("unknown test"); sa.sa_handler = aborthandler; sigemptyset(&sa.sa_mask); sa.sa_flags = 0; REQUIRE_ERRNO(sigaction(SIGABRT, &sa, NULL) != -1); REQUIRE_ERRNO(sigemptyset(&ss) != -1); REQUIRE_ERRNO(sigaddset(&ss, SIGABRT) != -1); REQUIRE_ERRNO(sigprocmask(SIG_BLOCK, &ss, NULL) != -1); ATF_REQUIRE(myself == pthread_self()); if (test == TEST_SETJMP) x = setjmp(jb); else if (test == TEST_U_SETJMP) x = _setjmp(jb); else x = sigsetjmp(sjb, !expectsignal); if (x != 0) { ATF_REQUIRE(myself == pthread_self()); ATF_REQUIRE_MSG(x == i, "setjmp returned wrong value"); kill(i, SIGABRT); ATF_REQUIRE_MSG(!expectsignal, "kill(SIGABRT) failed"); ATF_REQUIRE(myself == pthread_self()); atf_tc_pass(); } ATF_REQUIRE(myself == pthread_self()); REQUIRE_ERRNO(sigprocmask(SIG_UNBLOCK, &ss, NULL) != -1); if (test == TEST_SETJMP) longjmp(jb, i); else if (test == TEST_U_SETJMP) _longjmp(jb, i); else siglongjmp(sjb, i); atf_tc_fail("jmp failed"); }
ATF_TC_BODY(ptmx, tc) { struct stat stm, sts; char *pty; int fdm, fds; struct group *gp; if ((fdm = posix_openpt(O_RDWR|O_NOCTTY)) == -1) { if (errno == ENOENT || errno == ENODEV) atf_tc_skip("/dev/ptmx: %s", strerror(errno)); atf_tc_fail("/dev/ptmx: %s", strerror(errno)); } REQUIRE_ERRNO(fstat(fdm, &stm), -1); #ifdef PTY_DEVNO_CHECK REQUIRE_ERRNO(stat("/dev/ptyp0", &sts), -1); ATF_REQUIRE_EQ_MSG(major(stm.st_rdev), major(sts.st_rdev), "bad master major number"); #endif REQUIRE_ERRNO(grantpt(fdm), -1); REQUIRE_ERRNO(unlockpt(fdm), -1); REQUIRE_ERRNO((pty = ptsname(fdm)), NULL); REQUIRE_ERRNO((fds = open(pty, O_RDWR|O_NOCTTY)), -1); REQUIRE_ERRNO(fstat(fds, &sts), -1); #ifdef PTY_DEVNO_CHECK ATF_REQUIRE_EQ_MSG(minor(stm.st_rdev), minor(sts.st_rdev), "bad slave minor number"); #endif ATF_REQUIRE_EQ_MSG(sts.st_uid, getuid(), "bad slave uid"); ATF_REQUIRE_MSG((gp = getgrnam("tty")) != NULL, "cannot find `tty' group"); ATF_REQUIRE_EQ_MSG(sts.st_gid, gp->gr_gid, "bad slave gid"); }
ATF_TC_BODY(ptm, tc) { struct stat stm, sts; struct ptmget ptm; int fdm; struct group *gp; if ((fdm = open("/dev/ptm", O_RDWR)) == -1) { if (errno == ENOENT || errno == ENODEV) atf_tc_skip("/dev/ptm: %s", strerror(errno)); atf_tc_fail("/dev/ptm: %s", strerror(errno)); } REQUIRE_ERRNO(fstat(fdm, &stm), -1); ATF_REQUIRE_EQ(major(stm.st_rdev), 165); REQUIRE_ERRNO(ioctl(fdm, TIOCPTMGET, &ptm), -1); ATF_REQUIRE_MSG(strncmp(ptm.cn, "/dev/pty", 8) == 0 || strncmp(ptm.cn, "/dev/null", 9) == 0, "bad master name: %s", ptm.cn); ATF_REQUIRE_MSG(strncmp(ptm.sn, "/dev/tty", 8) == 0 || strncmp(ptm.sn, "/dev/pts/", 9) == 0, "bad slave name: %s", ptm.sn); if (strncmp(ptm.cn, "/dev/null", 9) != 0) { REQUIRE_ERRNO(fstat(ptm.cfd, &stm), -1); REQUIRE_ERRNO(stat(ptm.cn, &sts), -1); ATF_REQUIRE_EQ(stm.st_rdev, sts.st_rdev); } REQUIRE_ERRNO(fstat(ptm.sfd, &stm), -1); REQUIRE_ERRNO(stat(ptm.sn, &sts), -1); ATF_REQUIRE_EQ(stm.st_rdev, sts.st_rdev); ATF_REQUIRE_EQ_MSG(sts.st_uid, getuid(), "bad slave uid"); ATF_REQUIRE_MSG((gp = getgrnam("tty")) != NULL, "cannot find `tty' group"); ATF_REQUIRE_EQ_MSG(sts.st_gid, gp->gr_gid, "bad slave grid"); (void)close(ptm.sfd); (void)close(ptm.cfd); (void)close(fdm); }
ATF_TC_BODY(ioctl, tc) { int m, s, rc; char name[128], buf[128]; struct termios term; struct sigaction sa; /* unbuffer stdout */ setbuf(stdout, NULL); /* * Create default termios settings for later use */ memset(&term, 0, sizeof(term)); term.c_iflag = TTYDEF_IFLAG; term.c_oflag = TTYDEF_OFLAG; term.c_cflag = TTYDEF_CFLAG; term.c_lflag = TTYDEF_LFLAG; cfsetspeed(&term, TTYDEF_SPEED); /* get a tty */ REQUIRE_ERRNO(openpty(&m, &s, name, &term, NULL), -1); switch (fork()) { case -1: atf_tc_fail("fork(): %s", strerror(errno)); /* NOTREACHED */ case 0: /* wait for parent to get set up */ (void)sleep(1); (void)printf("child1: exiting\n"); exit(0); /* NOTREACHED */ default: (void)printf("parent: spawned child1\n"); break; } switch (fork()) { case -1: atf_tc_fail("fork(): %s", strerror(errno)); /* NOTREACHED */ case 0: /* wait for parent to get upset */ (void)sleep(2); /* drain the tty q */ if (read(m, buf, sizeof(buf)) == -1) err(1, "read"); (void)printf("child2: exiting\n"); exit(0); /* NOTREACHED */ default: (void)printf("parent: spawned child2\n"); break; } /* set up a restarting signal handler */ (void)sigemptyset(&sa.sa_mask); sa.sa_handler = sigchld; sa.sa_flags = SA_RESTART; REQUIRE_ERRNO(sigaction(SIGCHLD, &sa, NULL), -1); /* put something in the output q */ REQUIRE_ERRNO(write(s, "Hello world\n", 12), -1); /* ask for output to drain but don't drain it */ rc = 0; if (tcsetattr(s, TCSADRAIN, &term) == -1) { (void)printf("parent: tcsetattr: %s\n", strerror(errno)); rc = 1; } /* wait for last child */ sa.sa_handler = SIG_DFL; REQUIRE_ERRNO(sigaction(SIGCHLD, &sa, NULL), -1); (void) wait(NULL); #ifdef __FreeBSD__ (void)close(s); #endif ATF_REQUIRE_EQ(rc, 0); }
/* ARGSUSED */ static void sigchld(int nsig) { REQUIRE_ERRNO(wait(NULL), -1); }