diff options
author | ngie <ngie@FreeBSD.org> | 2015-12-31 21:51:38 +0000 |
---|---|---|
committer | ngie <ngie@FreeBSD.org> | 2015-12-31 21:51:38 +0000 |
commit | 1ce5880b96d860b35dd841ffb1fec742c1c019d6 (patch) | |
tree | 3aa79d15890879ed3ccdbf3d6eeb38835112bc3c /tests | |
parent | 15afae85deb48e3e52ed3d9df3b576cb58793c31 (diff) | |
parent | b8cae6c53bb98cfc07d21feaa7d74ffcf5e09bb2 (diff) | |
download | FreeBSD-src-1ce5880b96d860b35dd841ffb1fec742c1c019d6.zip FreeBSD-src-1ce5880b96d860b35dd841ffb1fec742c1c019d6.tar.gz |
MFhead @ r293006
Diffstat (limited to 'tests')
-rw-r--r-- | tests/sys/kern/Makefile | 1 | ||||
-rw-r--r-- | tests/sys/kern/ptrace_test.c | 193 | ||||
-rw-r--r-- | tests/sys/kern/unix_passfd_test.c | 396 |
3 files changed, 583 insertions, 7 deletions
diff --git a/tests/sys/kern/Makefile b/tests/sys/kern/Makefile index a38b1f2..c9a7cfd 100644 --- a/tests/sys/kern/Makefile +++ b/tests/sys/kern/Makefile @@ -8,6 +8,7 @@ ATF_TESTS_C+= kern_copyin ATF_TESTS_C+= kern_descrip_test ATF_TESTS_C+= ptrace_test ATF_TESTS_C+= unix_seqpacket_test +ATF_TESTS_C+= unix_passfd_test TEST_METADATA.unix_seqpacket_test+= timeout="15" LIBADD.ptrace_test+= pthread diff --git a/tests/sys/kern/ptrace_test.c b/tests/sys/kern/ptrace_test.c index f611221..177f412 100644 --- a/tests/sys/kern/ptrace_test.c +++ b/tests/sys/kern/ptrace_test.c @@ -1094,6 +1094,16 @@ simple_thread(void *arg __unused) pthread_exit(NULL); } +static __dead2 void +simple_thread_main(void) +{ + pthread_t thread; + + CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread, NULL) == 0); + CHILD_REQUIRE(pthread_join(thread, NULL) == 0); + exit(1); +} + /* * Verify that pl_syscall_code in struct ptrace_lwpinfo for a new * thread reports the correct value. @@ -1108,14 +1118,8 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc) ATF_REQUIRE((fpid = fork()) != -1); if (fpid == 0) { - pthread_t thread; - trace_me(); - - CHILD_REQUIRE(pthread_create(&thread, NULL, simple_thread, - NULL) == 0); - CHILD_REQUIRE(pthread_join(thread, NULL) == 0); - exit(1); + simple_thread_main(); } /* The first wait() should report the stop from SIGSTOP. */ @@ -1178,6 +1182,179 @@ ATF_TC_BODY(ptrace__new_child_pl_syscall_code_thread, tc) ATF_REQUIRE(errno == ECHILD); } +/* + * Verify that the expected LWP events are reported for a child thread. + */ +ATF_TC_WITHOUT_HEAD(ptrace__lwp_events); +ATF_TC_BODY(ptrace__lwp_events, tc) +{ + struct ptrace_lwpinfo pl; + pid_t fpid, wpid; + lwpid_t lwps[2]; + int status; + + ATF_REQUIRE((fpid = fork()) != -1); + if (fpid == 0) { + trace_me(); + simple_thread_main(); + } + + /* The first wait() should report the stop from SIGSTOP. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, + sizeof(pl)) != -1); + lwps[0] = pl.pl_lwpid; + + ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); + + /* Continue the child ignoring the SIGSTOP. */ + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The first event should be for the child thread's birth. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); + ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == + (PL_FLAG_BORN | PL_FLAG_SCX)); + ATF_REQUIRE(pl.pl_lwpid != lwps[0]); + lwps[1] = pl.pl_lwpid; + + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The next event should be for the child thread's death. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); + ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) == + (PL_FLAG_EXITED | PL_FLAG_SCE)); + ATF_REQUIRE(pl.pl_lwpid == lwps[1]); + + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The last event should be for the child process's exit. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE(WEXITSTATUS(status) == 1); + + wpid = wait(&status); + ATF_REQUIRE(wpid == -1); + ATF_REQUIRE(errno == ECHILD); +} + +static void * +exec_thread(void *arg __unused) +{ + + execl("/usr/bin/true", "true", NULL); + exit(127); +} + +static __dead2 void +exec_thread_main(void) +{ + pthread_t thread; + + CHILD_REQUIRE(pthread_create(&thread, NULL, exec_thread, NULL) == 0); + for (;;) + sleep(60); + exit(1); +} + +/* + * Verify that the expected LWP events are reported for a multithreaded + * process that calls execve(2). + */ +ATF_TC_WITHOUT_HEAD(ptrace__lwp_events_exec); +ATF_TC_BODY(ptrace__lwp_events_exec, tc) +{ + struct ptrace_lwpinfo pl; + pid_t fpid, wpid; + lwpid_t lwps[2]; + int status; + + ATF_REQUIRE((fpid = fork()) != -1); + if (fpid == 0) { + trace_me(); + exec_thread_main(); + } + + /* The first wait() should report the stop from SIGSTOP. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGSTOP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, + sizeof(pl)) != -1); + lwps[0] = pl.pl_lwpid; + + ATF_REQUIRE(ptrace(PT_LWP_EVENTS, wpid, NULL, 1) == 0); + + /* Continue the child ignoring the SIGSTOP. */ + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The first event should be for the child thread's birth. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); + ATF_REQUIRE((pl.pl_flags & (PL_FLAG_BORN | PL_FLAG_SCX)) == + (PL_FLAG_BORN | PL_FLAG_SCX)); + ATF_REQUIRE(pl.pl_lwpid != lwps[0]); + lwps[1] = pl.pl_lwpid; + + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* + * The next event should be for the main thread's death due to + * single threading from execve(). + */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(wpid == fpid); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); + ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXITED | PL_FLAG_SCE)) == + (PL_FLAG_EXITED)); + ATF_REQUIRE(pl.pl_lwpid == lwps[0]); + + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The next event should be for the child process's exec. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(WIFSTOPPED(status)); + ATF_REQUIRE(WSTOPSIG(status) == SIGTRAP); + + ATF_REQUIRE(ptrace(PT_LWPINFO, wpid, (caddr_t)&pl, sizeof(pl)) != -1); + ATF_REQUIRE((pl.pl_flags & (PL_FLAG_EXEC | PL_FLAG_SCX)) == + (PL_FLAG_EXEC | PL_FLAG_SCX)); + ATF_REQUIRE(pl.pl_lwpid == lwps[1]); + + ATF_REQUIRE(ptrace(PT_CONTINUE, fpid, (caddr_t)1, 0) == 0); + + /* The last event should be for the child process's exit. */ + wpid = waitpid(fpid, &status, 0); + ATF_REQUIRE(WIFEXITED(status)); + ATF_REQUIRE(WEXITSTATUS(status) == 0); + + wpid = wait(&status); + ATF_REQUIRE(wpid == -1); + ATF_REQUIRE(errno == ECHILD); +} + ATF_TP_ADD_TCS(tp) { @@ -1197,6 +1374,8 @@ ATF_TP_ADD_TCS(tp) ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_fork); ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_vfork); ATF_TP_ADD_TC(tp, ptrace__new_child_pl_syscall_code_thread); + ATF_TP_ADD_TC(tp, ptrace__lwp_events); + ATF_TP_ADD_TC(tp, ptrace__lwp_events_exec); return (atf_no_error()); } diff --git a/tests/sys/kern/unix_passfd_test.c b/tests/sys/kern/unix_passfd_test.c new file mode 100644 index 0000000..12568389 --- /dev/null +++ b/tests/sys/kern/unix_passfd_test.c @@ -0,0 +1,396 @@ +/*- + * Copyright (c) 2005 Robert N. M. Watson + * Copyright (c) 2015 Mark Johnston + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/un.h> + +#include <errno.h> +#include <fcntl.h> +#include <limits.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <atf-c.h> + +/* + * UNIX domain sockets allow file descriptors to be passed via "ancillary + * data", or control messages. This regression test is intended to exercise + * this facility, both performing some basic tests that it operates, and also + * causing some kernel edge cases to execute, such as garbage collection when + * there are cyclic file descriptor references. Right now we test only with + * stream sockets, but ideally we'd also test with datagram sockets. + */ + +static void +domainsocketpair(int *fdp) +{ + + ATF_REQUIRE_MSG(socketpair(PF_UNIX, SOCK_STREAM, 0, fdp) != -1, + "socketpair(PF_UNIX, SOCK_STREAM) failed: %s", strerror(errno)); +} + +static void +closesocketpair(int *fdp) +{ + + close(fdp[0]); + close(fdp[1]); +} + +static void +devnull(int *fdp) +{ + int fd; + + fd = open("/dev/null", O_RDONLY); + ATF_REQUIRE_MSG(fd != -1, "open failed: %s", strerror(errno)); + *fdp = fd; +} + +static void +tempfile(int *fdp) +{ + char path[PATH_MAX]; + int fd; + + snprintf(path, PATH_MAX, "%s/unix_passfd.XXXXXXXXXXXXXXX", + getenv("TMPDIR") == NULL ? "/tmp" : getenv("TMPDIR")); + fd = mkstemp(path); + ATF_REQUIRE_MSG(fd != -1, "mkstemp(%s) failed", path); + (void)unlink(path); + *fdp = fd; +} + +static void +dofstat(int fd, struct stat *sb) +{ + + ATF_REQUIRE_MSG(fstat(fd, sb) == 0, + "fstat failed: %s", strerror(errno)); +} + +static void +samefile(struct stat *sb1, struct stat *sb2) +{ + + ATF_REQUIRE_MSG(sb1->st_dev == sb2->st_dev, "different device"); + ATF_REQUIRE_MSG(sb1->st_ino == sb2->st_ino, "different inode"); +} + +static void +sendfd_payload(int sockfd, int send_fd, void *payload, size_t paylen) +{ + struct iovec iovec; + char message[CMSG_SPACE(sizeof(int))]; + struct cmsghdr *cmsghdr; + struct msghdr msghdr; + ssize_t len; + + bzero(&msghdr, sizeof(msghdr)); + bzero(&message, sizeof(message)); + + msghdr.msg_control = message; + msghdr.msg_controllen = sizeof(message); + + iovec.iov_base = payload; + iovec.iov_len = paylen; + + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + + cmsghdr = (struct cmsghdr *)(void*)message; + cmsghdr->cmsg_len = CMSG_LEN(sizeof(int)); + cmsghdr->cmsg_level = SOL_SOCKET; + cmsghdr->cmsg_type = SCM_RIGHTS; + memcpy(CMSG_DATA(cmsghdr), &send_fd, sizeof(int)); + + len = sendmsg(sockfd, &msghdr, 0); + ATF_REQUIRE_MSG(len != -1, "sendmsg failed: %s", strerror(errno)); + ATF_REQUIRE_MSG((size_t)len == paylen, + "sendmsg: %zd messages sent; expected: %zu; %s", len, paylen, + strerror(errno)); +} + +static void +sendfd(int sockfd, int send_fd) +{ + char ch = 0; + + return (sendfd_payload(sockfd, send_fd, &ch, sizeof(ch))); +} + +static void +recvfd_payload(int sockfd, int *recv_fd, void *buf, size_t buflen) +{ + struct cmsghdr *cmsghdr; + char message[CMSG_SPACE(SOCKCREDSIZE(CMGROUP_MAX)) + sizeof(int)]; + struct msghdr msghdr; + struct iovec iovec; + ssize_t len; + + bzero(&msghdr, sizeof(msghdr)); + + msghdr.msg_control = message; + msghdr.msg_controllen = sizeof(message); + + iovec.iov_base = buf; + iovec.iov_len = buflen; + + msghdr.msg_iov = &iovec; + msghdr.msg_iovlen = 1; + + len = recvmsg(sockfd, &msghdr, 0); + ATF_REQUIRE_MSG(len != -1, "recvmsg failed: %s", strerror(errno)); + ATF_REQUIRE_MSG((size_t)len == buflen, + "recvmsg: %zd bytes received; expected %zd", len, buflen); + + cmsghdr = CMSG_FIRSTHDR(&msghdr); + ATF_REQUIRE_MSG(cmsghdr != NULL, + "recvmsg: did not receive control message"); + *recv_fd = -1; + for (; cmsghdr != NULL; cmsghdr = CMSG_NXTHDR(&msghdr, cmsghdr)) { + if (cmsghdr->cmsg_level == SOL_SOCKET && + cmsghdr->cmsg_type == SCM_RIGHTS && + cmsghdr->cmsg_len == CMSG_LEN(sizeof(int))) { + memcpy(recv_fd, CMSG_DATA(cmsghdr), sizeof(int)); + ATF_REQUIRE(*recv_fd != -1); + } + } + ATF_REQUIRE_MSG(*recv_fd != -1, + "recvmsg: did not receive single-fd message"); +} + +static void +recvfd(int sockfd, int *recv_fd) +{ + char ch = 0; + + return (recvfd_payload(sockfd, recv_fd, &ch, sizeof(ch))); +} + +/* + * Put a temporary file into a UNIX domain socket, then take it out and make + * sure it's the same file. First time around, don't close the reference + * after sending. + */ +ATF_TC_WITHOUT_HEAD(simple_send_fd); +ATF_TC_BODY(simple_send_fd, tc) +{ + struct stat getfd_stat, putfd_stat; + int fd[2], getfd, putfd; + + domainsocketpair(fd); + tempfile(&putfd); + dofstat(putfd, &putfd_stat); + sendfd(fd[0], putfd); + recvfd(fd[1], &getfd); + dofstat(getfd, &getfd_stat); + samefile(&putfd_stat, &getfd_stat); + close(putfd); + close(getfd); + closesocketpair(fd); +} + +/* + * Same as simple_send_fd, only close the file reference after sending, so that + * the only reference is the descriptor in the UNIX domain socket buffer. + */ +ATF_TC_WITHOUT_HEAD(send_and_close); +ATF_TC_BODY(send_and_close, tc) +{ + struct stat getfd_stat, putfd_stat; + int fd[2], getfd, putfd; + + domainsocketpair(fd); + tempfile(&putfd); + dofstat(putfd, &putfd_stat); + sendfd(fd[0], putfd); + close(putfd); + recvfd(fd[1], &getfd); + dofstat(getfd, &getfd_stat); + samefile(&putfd_stat, &getfd_stat); + close(getfd); + closesocketpair(fd); +} + +/* + * Put a temporary file into a UNIX domain socket, then close both endpoints + * causing garbage collection to kick off. + */ +ATF_TC_WITHOUT_HEAD(send_and_cancel); +ATF_TC_BODY(send_and_cancel, tc) +{ + int fd[2], putfd; + + domainsocketpair(fd); + tempfile(&putfd); + sendfd(fd[0], putfd); + close(putfd); + closesocketpair(fd); +} + +/* + * Send two files. Then receive them. Make sure they are returned in the + * right order, and both get there. + */ +ATF_TC_WITHOUT_HEAD(two_files); +ATF_TC_BODY(two_files, tc) +{ + struct stat getfd_1_stat, getfd_2_stat, putfd_1_stat, putfd_2_stat; + int fd[2], getfd_1, getfd_2, putfd_1, putfd_2; + + domainsocketpair(fd); + tempfile(&putfd_1); + tempfile(&putfd_2); + dofstat(putfd_1, &putfd_1_stat); + dofstat(putfd_2, &putfd_2_stat); + sendfd(fd[0], putfd_1); + sendfd(fd[0], putfd_2); + close(putfd_1); + close(putfd_2); + recvfd(fd[1], &getfd_1); + recvfd(fd[1], &getfd_2); + dofstat(getfd_1, &getfd_1_stat); + dofstat(getfd_2, &getfd_2_stat); + samefile(&putfd_1_stat, &getfd_1_stat); + samefile(&putfd_2_stat, &getfd_2_stat); + close(getfd_1); + close(getfd_2); + closesocketpair(fd); +} + +/* + * Big bundling test. Send an endpoint of the UNIX domain socket over itself, + * closing the door behind it. + */ +ATF_TC_WITHOUT_HEAD(bundle); +ATF_TC_BODY(bundle, tc) +{ + int fd[2], getfd; + + domainsocketpair(fd); + + sendfd(fd[0], fd[0]); + close(fd[0]); + recvfd(fd[1], &getfd); + close(getfd); + close(fd[1]); +} + +/* + * Big bundling test part two: Send an endpoint of the UNIX domain socket over + * itself, close the door behind it, and never remove it from the other end. + */ +ATF_TC_WITHOUT_HEAD(bundle_cancel); +ATF_TC_BODY(bundle_cancel, tc) +{ + int fd[2]; + + domainsocketpair(fd); + sendfd(fd[0], fd[0]); + sendfd(fd[1], fd[0]); + closesocketpair(fd); +} + +/* + * Test for PR 151758: Send an character device over the UNIX domain socket + * and then close both sockets to orphan the device. + */ +ATF_TC_WITHOUT_HEAD(devfs_orphan); +ATF_TC_BODY(devfs_orphan, tc) +{ + int fd[2], putfd; + + domainsocketpair(fd); + devnull(&putfd); + sendfd(fd[0], putfd); + close(putfd); + closesocketpair(fd); +} + +#define LOCAL_SENDSPACE_SYSCTL "net.local.stream.sendspace" + +/* + * Test for PR 181741. Receiver sets LOCAL_CREDS, and kernel prepends a + * control message to the data. Sender sends large payload. + * Payload + SCM_RIGHTS + LOCAL_CREDS hit socket buffer limit, and receiver + * receives truncated data. + */ +ATF_TC_WITHOUT_HEAD(rights_creds_payload); +ATF_TC_BODY(rights_creds_payload, tc) +{ + const int on = 1; + u_long sendspace; + size_t len; + void *buf; + int fd[2], getfd, putfd, rc; + + atf_tc_expect_fail("PR 181741: Packet loss when 'control' messages " + "are present with large data"); + + len = sizeof(sendspace); + rc = sysctlbyname(LOCAL_SENDSPACE_SYSCTL, &sendspace, + &len, NULL, 0); + ATF_REQUIRE_MSG(rc != -1, + "sysctl %s failed: %s", LOCAL_SENDSPACE_SYSCTL, strerror(errno)); + + buf = calloc(1, sendspace); + ATF_REQUIRE(buf != NULL); + + domainsocketpair(fd); + rc = setsockopt(fd[1], 0, LOCAL_CREDS, &on, sizeof(on)); + ATF_REQUIRE_MSG(rc != -1, "setsockopt(LOCAL_CREDS) failed: %s", + strerror(errno)); + tempfile(&putfd); + sendfd_payload(fd[0], putfd, buf, sendspace); + recvfd_payload(fd[1], &getfd, buf, sendspace); + close(putfd); + close(getfd); + closesocketpair(fd); +} + +ATF_TP_ADD_TCS(tp) +{ + + ATF_TP_ADD_TC(tp, simple_send_fd); + ATF_TP_ADD_TC(tp, send_and_close); + ATF_TP_ADD_TC(tp, send_and_cancel); + ATF_TP_ADD_TC(tp, two_files); + ATF_TP_ADD_TC(tp, bundle); + ATF_TP_ADD_TC(tp, bundle_cancel); + ATF_TP_ADD_TC(tp, devfs_orphan); + ATF_TP_ADD_TC(tp, rights_creds_payload); + + return (atf_no_error()); +} |