1*b48dffc9Sriastradh /* $NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $ */ 2*b48dffc9Sriastradh 3*b48dffc9Sriastradh /*- 4*b48dffc9Sriastradh * Copyright (c) 2024 The NetBSD Foundation, Inc. 5*b48dffc9Sriastradh * All rights reserved. 6*b48dffc9Sriastradh * 7*b48dffc9Sriastradh * Redistribution and use in source and binary forms, with or without 8*b48dffc9Sriastradh * modification, are permitted provided that the following conditions 9*b48dffc9Sriastradh * are met: 10*b48dffc9Sriastradh * 1. Redistributions of source code must retain the above copyright 11*b48dffc9Sriastradh * notice, this list of conditions and the following disclaimer. 12*b48dffc9Sriastradh * 2. Redistributions in binary form must reproduce the above copyright 13*b48dffc9Sriastradh * notice, this list of conditions and the following disclaimer in the 14*b48dffc9Sriastradh * documentation and/or other materials provided with the distribution. 15*b48dffc9Sriastradh * 16*b48dffc9Sriastradh * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 17*b48dffc9Sriastradh * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 18*b48dffc9Sriastradh * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 19*b48dffc9Sriastradh * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 20*b48dffc9Sriastradh * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 21*b48dffc9Sriastradh * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 22*b48dffc9Sriastradh * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 23*b48dffc9Sriastradh * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 24*b48dffc9Sriastradh * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 25*b48dffc9Sriastradh * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 26*b48dffc9Sriastradh * POSSIBILITY OF SUCH DAMAGE. 27*b48dffc9Sriastradh */ 28*b48dffc9Sriastradh 29*b48dffc9Sriastradh #include <sys/cdefs.h> 30*b48dffc9Sriastradh __RCSID("$NetBSD: t_cloexec.c,v 1.1 2024/11/10 15:57:32 riastradh Exp $"); 31*b48dffc9Sriastradh 32*b48dffc9Sriastradh #include <sys/types.h> 33*b48dffc9Sriastradh 34*b48dffc9Sriastradh #include <sys/bitops.h> 35*b48dffc9Sriastradh #include <sys/event.h> 36*b48dffc9Sriastradh #include <sys/ioctl.h> 37*b48dffc9Sriastradh #include <sys/socket.h> 38*b48dffc9Sriastradh #include <sys/un.h> 39*b48dffc9Sriastradh #include <sys/wait.h> 40*b48dffc9Sriastradh 41*b48dffc9Sriastradh #include <atf-c.h> 42*b48dffc9Sriastradh #include <fcntl.h> 43*b48dffc9Sriastradh #include <limits.h> 44*b48dffc9Sriastradh #include <spawn.h> 45*b48dffc9Sriastradh #include <stdio.h> 46*b48dffc9Sriastradh #include <unistd.h> 47*b48dffc9Sriastradh 48*b48dffc9Sriastradh #include "h_macros.h" 49*b48dffc9Sriastradh 50*b48dffc9Sriastradh /* 51*b48dffc9Sriastradh * Test close-on-exec as set in various ways 52*b48dffc9Sriastradh */ 53*b48dffc9Sriastradh 54*b48dffc9Sriastradh static int 55*b48dffc9Sriastradh open_via_accept4(void) 56*b48dffc9Sriastradh { 57*b48dffc9Sriastradh static const union { 58*b48dffc9Sriastradh struct sockaddr sa; 59*b48dffc9Sriastradh struct sockaddr_un sun; 60*b48dffc9Sriastradh } name = { .sun = { 61*b48dffc9Sriastradh .sun_family = AF_LOCAL, 62*b48dffc9Sriastradh .sun_path = "socket", 63*b48dffc9Sriastradh } }; 64*b48dffc9Sriastradh int slisten, saccept, c; 65*b48dffc9Sriastradh 66*b48dffc9Sriastradh /* 67*b48dffc9Sriastradh * Create a listening server socket and bind it to the path. 68*b48dffc9Sriastradh */ 69*b48dffc9Sriastradh RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); 70*b48dffc9Sriastradh RL(bind(slisten, &name.sa, sizeof(name))); 71*b48dffc9Sriastradh RL(listen(slisten, SOMAXCONN)); 72*b48dffc9Sriastradh 73*b48dffc9Sriastradh /* 74*b48dffc9Sriastradh * Create an active client socket and connect it to the path -- 75*b48dffc9Sriastradh * nonblocking, so we don't deadlock here. If connect doesn't 76*b48dffc9Sriastradh * succeed immediately, it had better fail immediately with 77*b48dffc9Sriastradh * EINPROGRESS. 78*b48dffc9Sriastradh */ 79*b48dffc9Sriastradh RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); 80*b48dffc9Sriastradh if (connect(c, &name.sa, sizeof(name)) == -1) { 81*b48dffc9Sriastradh ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", 82*b48dffc9Sriastradh errno, strerror(errno)); 83*b48dffc9Sriastradh } 84*b48dffc9Sriastradh 85*b48dffc9Sriastradh /* 86*b48dffc9Sriastradh * Accept a socket on the server side with SOCK_CLOEXEC. 87*b48dffc9Sriastradh */ 88*b48dffc9Sriastradh RL(saccept = accept4(slisten, /*addr*/NULL, /*addrlen*/NULL, 89*b48dffc9Sriastradh SOCK_CLOEXEC)); 90*b48dffc9Sriastradh return saccept; 91*b48dffc9Sriastradh } 92*b48dffc9Sriastradh 93*b48dffc9Sriastradh static int 94*b48dffc9Sriastradh open_via_clonedev(void) 95*b48dffc9Sriastradh { 96*b48dffc9Sriastradh int fd; 97*b48dffc9Sriastradh 98*b48dffc9Sriastradh RL(fd = open("/dev/drvctl", O_RDONLY|O_CLOEXEC)); 99*b48dffc9Sriastradh 100*b48dffc9Sriastradh return fd; 101*b48dffc9Sriastradh } 102*b48dffc9Sriastradh 103*b48dffc9Sriastradh static int 104*b48dffc9Sriastradh open_via_dup3(void) 105*b48dffc9Sriastradh { 106*b48dffc9Sriastradh int fd3; 107*b48dffc9Sriastradh 108*b48dffc9Sriastradh RL(fd3 = dup3(STDIN_FILENO, 3, O_CLOEXEC)); 109*b48dffc9Sriastradh ATF_REQUIRE_EQ_MSG(fd3, 3, "dup3(STDIN_FILENO, 3, ...)" 110*b48dffc9Sriastradh " failed to return 3: %d", fd3); 111*b48dffc9Sriastradh 112*b48dffc9Sriastradh return fd3; 113*b48dffc9Sriastradh } 114*b48dffc9Sriastradh 115*b48dffc9Sriastradh static int 116*b48dffc9Sriastradh open_via_fcntldupfd(void) 117*b48dffc9Sriastradh { 118*b48dffc9Sriastradh int fd; 119*b48dffc9Sriastradh 120*b48dffc9Sriastradh RL(fd = fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC, 0)); 121*b48dffc9Sriastradh 122*b48dffc9Sriastradh return fd; 123*b48dffc9Sriastradh } 124*b48dffc9Sriastradh 125*b48dffc9Sriastradh static int 126*b48dffc9Sriastradh open_via_kqueue(void) 127*b48dffc9Sriastradh { 128*b48dffc9Sriastradh int fd; 129*b48dffc9Sriastradh 130*b48dffc9Sriastradh RL(fd = kqueue1(O_CLOEXEC)); 131*b48dffc9Sriastradh 132*b48dffc9Sriastradh return fd; 133*b48dffc9Sriastradh } 134*b48dffc9Sriastradh 135*b48dffc9Sriastradh static int 136*b48dffc9Sriastradh open_via_opencloexec(void) 137*b48dffc9Sriastradh { 138*b48dffc9Sriastradh int fd; 139*b48dffc9Sriastradh 140*b48dffc9Sriastradh RL(fd = open("file", O_RDWR|O_CREAT|O_CLOEXEC, 0644)); 141*b48dffc9Sriastradh 142*b48dffc9Sriastradh return fd; 143*b48dffc9Sriastradh } 144*b48dffc9Sriastradh 145*b48dffc9Sriastradh static int 146*b48dffc9Sriastradh open_via_openfcntlcloexec(void) 147*b48dffc9Sriastradh { 148*b48dffc9Sriastradh int fd; 149*b48dffc9Sriastradh 150*b48dffc9Sriastradh RL(fd = open("file", O_RDWR|O_CREAT, 0644)); 151*b48dffc9Sriastradh RL(fcntl(fd, F_SETFD, FD_CLOEXEC)); 152*b48dffc9Sriastradh 153*b48dffc9Sriastradh return fd; 154*b48dffc9Sriastradh } 155*b48dffc9Sriastradh 156*b48dffc9Sriastradh static int 157*b48dffc9Sriastradh open_via_openioctlfioclex(void) 158*b48dffc9Sriastradh { 159*b48dffc9Sriastradh int fd; 160*b48dffc9Sriastradh 161*b48dffc9Sriastradh RL(fd = open("file", O_RDWR|O_CREAT, 0644)); 162*b48dffc9Sriastradh RL(ioctl(fd, FIOCLEX)); 163*b48dffc9Sriastradh 164*b48dffc9Sriastradh return fd; 165*b48dffc9Sriastradh } 166*b48dffc9Sriastradh 167*b48dffc9Sriastradh static int 168*b48dffc9Sriastradh open_via_pipe2rd(void) 169*b48dffc9Sriastradh { 170*b48dffc9Sriastradh int fd[2]; 171*b48dffc9Sriastradh 172*b48dffc9Sriastradh RL(pipe2(fd, O_CLOEXEC)); 173*b48dffc9Sriastradh 174*b48dffc9Sriastradh return fd[0]; 175*b48dffc9Sriastradh } 176*b48dffc9Sriastradh 177*b48dffc9Sriastradh static int 178*b48dffc9Sriastradh open_via_pipe2wr(void) 179*b48dffc9Sriastradh { 180*b48dffc9Sriastradh int fd[2]; 181*b48dffc9Sriastradh 182*b48dffc9Sriastradh RL(pipe2(fd, O_CLOEXEC)); 183*b48dffc9Sriastradh 184*b48dffc9Sriastradh return fd[1]; 185*b48dffc9Sriastradh } 186*b48dffc9Sriastradh 187*b48dffc9Sriastradh static int 188*b48dffc9Sriastradh open_via_paccept(void) 189*b48dffc9Sriastradh { 190*b48dffc9Sriastradh static const union { 191*b48dffc9Sriastradh struct sockaddr sa; 192*b48dffc9Sriastradh struct sockaddr_un sun; 193*b48dffc9Sriastradh } name = { .sun = { 194*b48dffc9Sriastradh .sun_family = AF_LOCAL, 195*b48dffc9Sriastradh .sun_path = "socket", 196*b48dffc9Sriastradh } }; 197*b48dffc9Sriastradh int slisten, saccept, c; 198*b48dffc9Sriastradh 199*b48dffc9Sriastradh /* 200*b48dffc9Sriastradh * Create a listening server socket and bind it to the path. 201*b48dffc9Sriastradh */ 202*b48dffc9Sriastradh RL(slisten = socket(PF_LOCAL, SOCK_STREAM, 0)); 203*b48dffc9Sriastradh RL(bind(slisten, &name.sa, sizeof(name))); 204*b48dffc9Sriastradh RL(listen(slisten, SOMAXCONN)); 205*b48dffc9Sriastradh 206*b48dffc9Sriastradh /* 207*b48dffc9Sriastradh * Create an active client socket and connect it to the path -- 208*b48dffc9Sriastradh * nonblocking, so we don't deadlock here. If connect doesn't 209*b48dffc9Sriastradh * succeed immediately, it had better fail immediately with 210*b48dffc9Sriastradh * EINPROGRESS. 211*b48dffc9Sriastradh */ 212*b48dffc9Sriastradh RL(c = socket(PF_LOCAL, SOCK_STREAM|SOCK_NONBLOCK, 0)); 213*b48dffc9Sriastradh if (connect(c, &name.sa, sizeof(name)) == -1) { 214*b48dffc9Sriastradh ATF_CHECK_EQ_MSG(errno, EINPROGRESS, "connect failed %d: %s", 215*b48dffc9Sriastradh errno, strerror(errno)); 216*b48dffc9Sriastradh } 217*b48dffc9Sriastradh 218*b48dffc9Sriastradh /* 219*b48dffc9Sriastradh * Accept a socket on the server side with SOCK_CLOEXEC. 220*b48dffc9Sriastradh */ 221*b48dffc9Sriastradh RL(saccept = paccept(slisten, /*addr*/NULL, /*addrlen*/NULL, 222*b48dffc9Sriastradh /*sigmask*/NULL, SOCK_CLOEXEC)); 223*b48dffc9Sriastradh return saccept; 224*b48dffc9Sriastradh } 225*b48dffc9Sriastradh 226*b48dffc9Sriastradh static int 227*b48dffc9Sriastradh open_via_socket(void) 228*b48dffc9Sriastradh { 229*b48dffc9Sriastradh int fd; 230*b48dffc9Sriastradh 231*b48dffc9Sriastradh RL(fd = socket(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0)); 232*b48dffc9Sriastradh 233*b48dffc9Sriastradh return fd; 234*b48dffc9Sriastradh } 235*b48dffc9Sriastradh 236*b48dffc9Sriastradh static int 237*b48dffc9Sriastradh open_via_socketpair0(void) 238*b48dffc9Sriastradh { 239*b48dffc9Sriastradh int fd[2]; 240*b48dffc9Sriastradh 241*b48dffc9Sriastradh RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); 242*b48dffc9Sriastradh 243*b48dffc9Sriastradh return fd[0]; 244*b48dffc9Sriastradh } 245*b48dffc9Sriastradh 246*b48dffc9Sriastradh static int 247*b48dffc9Sriastradh open_via_socketpair1(void) 248*b48dffc9Sriastradh { 249*b48dffc9Sriastradh int fd[2]; 250*b48dffc9Sriastradh 251*b48dffc9Sriastradh RL(socketpair(PF_LOCAL, SOCK_STREAM|SOCK_CLOEXEC, 0, fd)); 252*b48dffc9Sriastradh 253*b48dffc9Sriastradh return fd[1]; 254*b48dffc9Sriastradh } 255*b48dffc9Sriastradh 256*b48dffc9Sriastradh /* 257*b48dffc9Sriastradh * XXX Close-on-exec paths still missing: 258*b48dffc9Sriastradh * XXX 259*b48dffc9Sriastradh * XXX compat_linux inotify 260*b48dffc9Sriastradh * XXX compat_linux close_range 261*b48dffc9Sriastradh * XXX drm i915_perf_open_ioctl 262*b48dffc9Sriastradh * XXX drm dma_buf 263*b48dffc9Sriastradh * XXX eventfd(2) 264*b48dffc9Sriastradh * XXX memfd(2) 265*b48dffc9Sriastradh * XXX timerfd(2) 266*b48dffc9Sriastradh * XXX recvmsg/recvmmsg with MSG_CMSG_CLOEXEC 267*b48dffc9Sriastradh */ 268*b48dffc9Sriastradh 269*b48dffc9Sriastradh static void 270*b48dffc9Sriastradh check_cloexec(const struct atf_tc *tc, int fd, 271*b48dffc9Sriastradh pid_t (*execfn)(char *, char *const[])) 272*b48dffc9Sriastradh { 273*b48dffc9Sriastradh char h_cloexec[PATH_MAX]; 274*b48dffc9Sriastradh char fdstr[(ilog2(INT_MAX) + 1)/(ilog2(10) - 1) + 1]; 275*b48dffc9Sriastradh char *const argv[] = {__UNCONST("h_cloexec"), fdstr, NULL}; 276*b48dffc9Sriastradh pid_t child, waitedpid; 277*b48dffc9Sriastradh int status; 278*b48dffc9Sriastradh 279*b48dffc9Sriastradh /* 280*b48dffc9Sriastradh * Format the h_cloexec helper executable path, which lives in 281*b48dffc9Sriastradh * the test's directory (typically /usr/tests/kernel), and the 282*b48dffc9Sriastradh * argument of a file descriptor in decimal. 283*b48dffc9Sriastradh */ 284*b48dffc9Sriastradh snprintf(h_cloexec, sizeof(h_cloexec), "%s/h_cloexec", 285*b48dffc9Sriastradh atf_tc_get_config_var(tc, "srcdir")); 286*b48dffc9Sriastradh snprintf(fdstr, sizeof(fdstr), "%d", fd); 287*b48dffc9Sriastradh 288*b48dffc9Sriastradh /* 289*b48dffc9Sriastradh * Execute h_cloexec as a subprocess. 290*b48dffc9Sriastradh */ 291*b48dffc9Sriastradh child = (*execfn)(h_cloexec, argv); 292*b48dffc9Sriastradh 293*b48dffc9Sriastradh /* 294*b48dffc9Sriastradh * Wait for the child to complete. 295*b48dffc9Sriastradh */ 296*b48dffc9Sriastradh RL(waitedpid = waitpid(child, &status, 0)); 297*b48dffc9Sriastradh ATF_CHECK_EQ_MSG(child, waitedpid, "waited for %jd, got %jd", 298*b48dffc9Sriastradh (intmax_t)child, (intmax_t)waitedpid); 299*b48dffc9Sriastradh 300*b48dffc9Sriastradh /* 301*b48dffc9Sriastradh * Verify the child exited normally. 302*b48dffc9Sriastradh */ 303*b48dffc9Sriastradh if (WIFSIGNALED(status)) { 304*b48dffc9Sriastradh atf_tc_fail("subprocess terminated on signal %d", 305*b48dffc9Sriastradh WTERMSIG(status)); 306*b48dffc9Sriastradh return; 307*b48dffc9Sriastradh } else if (!WIFEXITED(status)) { 308*b48dffc9Sriastradh atf_tc_fail("subprocess failed to exit normally: status=0x%x", 309*b48dffc9Sriastradh status); 310*b48dffc9Sriastradh return; 311*b48dffc9Sriastradh } 312*b48dffc9Sriastradh 313*b48dffc9Sriastradh /* 314*b48dffc9Sriastradh * h_cloexec is supposed to exit status 0 if an operation on 315*b48dffc9Sriastradh * the fd failed with EBADFD, 1 if it unexpectedly succeeded, 316*b48dffc9Sriastradh * 127 if exec returned, or something else if anything else 317*b48dffc9Sriastradh * happened. 318*b48dffc9Sriastradh */ 319*b48dffc9Sriastradh switch (WEXITSTATUS(status)) { 320*b48dffc9Sriastradh case 0: /* success -- closed on exec */ 321*b48dffc9Sriastradh return; 322*b48dffc9Sriastradh case 1: /* fail -- not closed on exec */ 323*b48dffc9Sriastradh atf_tc_fail("fd was not closed on exec"); 324*b48dffc9Sriastradh return; 325*b48dffc9Sriastradh case 127: /* exec failed */ 326*b48dffc9Sriastradh atf_tc_fail("failed to exec h_cloexec"); 327*b48dffc9Sriastradh return; 328*b48dffc9Sriastradh default: /* something else went wong */ 329*b48dffc9Sriastradh atf_tc_fail("h_cloexec failed unexpectedly: %d", 330*b48dffc9Sriastradh WEXITSTATUS(status)); 331*b48dffc9Sriastradh return; 332*b48dffc9Sriastradh } 333*b48dffc9Sriastradh } 334*b48dffc9Sriastradh 335*b48dffc9Sriastradh static pid_t 336*b48dffc9Sriastradh exec_via_forkexecve(char *prog, char *const argv[]) 337*b48dffc9Sriastradh { 338*b48dffc9Sriastradh pid_t pid; 339*b48dffc9Sriastradh 340*b48dffc9Sriastradh RL(pid = fork()); 341*b48dffc9Sriastradh if (pid == 0) { /* child */ 342*b48dffc9Sriastradh if (execve(prog, argv, /*envp*/NULL) == -1) 343*b48dffc9Sriastradh _exit(127); 344*b48dffc9Sriastradh abort(); 345*b48dffc9Sriastradh } 346*b48dffc9Sriastradh 347*b48dffc9Sriastradh /* parent */ 348*b48dffc9Sriastradh return pid; 349*b48dffc9Sriastradh } 350*b48dffc9Sriastradh 351*b48dffc9Sriastradh static pid_t 352*b48dffc9Sriastradh exec_via_vforkexecve(char *prog, char *const argv[]) 353*b48dffc9Sriastradh { 354*b48dffc9Sriastradh pid_t pid; 355*b48dffc9Sriastradh 356*b48dffc9Sriastradh RL(pid = vfork()); 357*b48dffc9Sriastradh if (pid == 0) { /* child */ 358*b48dffc9Sriastradh if (execve(prog, argv, /*envp*/NULL) == -1) 359*b48dffc9Sriastradh _exit(127); 360*b48dffc9Sriastradh abort(); 361*b48dffc9Sriastradh } 362*b48dffc9Sriastradh 363*b48dffc9Sriastradh /* parent */ 364*b48dffc9Sriastradh return pid; 365*b48dffc9Sriastradh } 366*b48dffc9Sriastradh 367*b48dffc9Sriastradh static pid_t 368*b48dffc9Sriastradh exec_via_posixspawn(char *prog, char *const argv[]) 369*b48dffc9Sriastradh { 370*b48dffc9Sriastradh pid_t pid; 371*b48dffc9Sriastradh 372*b48dffc9Sriastradh RZ(posix_spawn(&pid, prog, /*file_actions*/NULL, /*attrp*/NULL, argv, 373*b48dffc9Sriastradh /*envp*/NULL)); 374*b48dffc9Sriastradh 375*b48dffc9Sriastradh return pid; 376*b48dffc9Sriastradh } 377*b48dffc9Sriastradh 378*b48dffc9Sriastradh /* 379*b48dffc9Sriastradh * Full cartesian product is not really important here -- the paths for 380*b48dffc9Sriastradh * open and the paths for exec are independent. So we try 381*b48dffc9Sriastradh * pipe2(O_CLOEXEC) with each exec path, and we try each open path with 382*b48dffc9Sriastradh * posix_spawn. 383*b48dffc9Sriastradh */ 384*b48dffc9Sriastradh 385*b48dffc9Sriastradh #define CLOEXEC_TEST(test, openvia, execvia, descr) \ 386*b48dffc9Sriastradh ATF_TC(test); \ 387*b48dffc9Sriastradh ATF_TC_HEAD(test, tc) \ 388*b48dffc9Sriastradh { \ 389*b48dffc9Sriastradh atf_tc_set_md_var(tc, "descr", descr); \ 390*b48dffc9Sriastradh } \ 391*b48dffc9Sriastradh ATF_TC_BODY(test, tc) \ 392*b48dffc9Sriastradh { \ 393*b48dffc9Sriastradh check_cloexec(tc, openvia(), &execvia); \ 394*b48dffc9Sriastradh } 395*b48dffc9Sriastradh 396*b48dffc9Sriastradh CLOEXEC_TEST(pipe2rd_forkexecve, open_via_pipe2rd, exec_via_forkexecve, 397*b48dffc9Sriastradh "pipe2(O_CLOEXEC) reader is closed in child on fork/exec") 398*b48dffc9Sriastradh CLOEXEC_TEST(pipe2rd_vforkexecve, open_via_pipe2rd, exec_via_vforkexecve, 399*b48dffc9Sriastradh "pipe2(O_CLOEXEC) reader is closed in child on vfork/exec") 400*b48dffc9Sriastradh CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, 401*b48dffc9Sriastradh "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") 402*b48dffc9Sriastradh 403*b48dffc9Sriastradh CLOEXEC_TEST(accept4_posixspawn, open_via_accept4, exec_via_posixspawn, 404*b48dffc9Sriastradh "accept4(SOCK_CLOEXEC) is closed in child on posix_spawn"); 405*b48dffc9Sriastradh CLOEXEC_TEST(clonedev_posixspawn, open_via_clonedev, exec_via_posixspawn, 406*b48dffc9Sriastradh "open(\"/dev/drvctl\") is closed in child on posix_spawn"); 407*b48dffc9Sriastradh CLOEXEC_TEST(dup3_posixspawn, open_via_dup3, exec_via_posixspawn, 408*b48dffc9Sriastradh "dup3(..., O_CLOEXEC) is closed in child on posix_spawn"); 409*b48dffc9Sriastradh CLOEXEC_TEST(fcntldupfd_posixspawn, open_via_fcntldupfd, exec_via_posixspawn, 410*b48dffc9Sriastradh "fcntl(STDIN_FILENO, F_DUPFD_CLOEXEC) is closed in child on posix_spawn"); 411*b48dffc9Sriastradh CLOEXEC_TEST(kqueue_posixspawn, open_via_kqueue, exec_via_posixspawn, 412*b48dffc9Sriastradh "kqueue1(O_CLOEXEC) is closed in child on posix_spawn"); 413*b48dffc9Sriastradh CLOEXEC_TEST(opencloexec_posixspawn, open_via_opencloexec, exec_via_posixspawn, 414*b48dffc9Sriastradh "open(O_CLOEXEC) is closed in child on posix_spawn"); 415*b48dffc9Sriastradh CLOEXEC_TEST(openfcntlcloexec_posixspawn, open_via_openfcntlcloexec, 416*b48dffc9Sriastradh exec_via_posixspawn, 417*b48dffc9Sriastradh "fcntl(open(...), F_SETFD, O_CLOEXEC) is closed in child on posix_spawn"); 418*b48dffc9Sriastradh CLOEXEC_TEST(openioctlfioclex_posixspawn, open_via_openioctlfioclex, 419*b48dffc9Sriastradh exec_via_posixspawn, 420*b48dffc9Sriastradh "ioctl(open(...), FIOCLEX) is closed in child on posix_spawn"); 421*b48dffc9Sriastradh #if 0 /* already done above */ 422*b48dffc9Sriastradh CLOEXEC_TEST(pipe2rd_posixspawn, open_via_pipe2rd, exec_via_posixspawn, 423*b48dffc9Sriastradh "pipe2(O_CLOEXEC) reader is closed in child on posix_spawn") 424*b48dffc9Sriastradh #endif 425*b48dffc9Sriastradh CLOEXEC_TEST(pipe2wr_posixspawn, open_via_pipe2wr, exec_via_posixspawn, 426*b48dffc9Sriastradh "pipe2(O_CLOEXEC) writer is closed in child on posix_spawn") 427*b48dffc9Sriastradh CLOEXEC_TEST(paccept_posixspawn, open_via_paccept, exec_via_posixspawn, 428*b48dffc9Sriastradh "paccept(..., SOCK_CLOEXEC) is closed in child on posix_spawn") 429*b48dffc9Sriastradh CLOEXEC_TEST(socket_posixspawn, open_via_socket, exec_via_posixspawn, 430*b48dffc9Sriastradh "socket(SOCK_CLOEXEC) is closed in child on posix_spawn") 431*b48dffc9Sriastradh CLOEXEC_TEST(socketpair0_posixspawn, open_via_socketpair0, exec_via_posixspawn, 432*b48dffc9Sriastradh "socketpair(SOCK_CLOEXEC) side 0 is closed in child on posix_spawn") 433*b48dffc9Sriastradh CLOEXEC_TEST(socketpair1_posixspawn, open_via_socketpair1, exec_via_posixspawn, 434*b48dffc9Sriastradh "socketpair(SOCK_CLOEXEC) side 1 is closed in child on posix_spawn") 435*b48dffc9Sriastradh 436*b48dffc9Sriastradh ATF_TP_ADD_TCS(tp) 437*b48dffc9Sriastradh { 438*b48dffc9Sriastradh 439*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, accept4_posixspawn); 440*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, clonedev_posixspawn); 441*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, dup3_posixspawn); 442*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, fcntldupfd_posixspawn); 443*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, kqueue_posixspawn); 444*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, opencloexec_posixspawn); 445*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, openfcntlcloexec_posixspawn); 446*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, openioctlfioclex_posixspawn); 447*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, paccept_posixspawn); 448*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, pipe2rd_forkexecve); 449*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, pipe2rd_posixspawn); 450*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, pipe2rd_vforkexecve); 451*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, pipe2wr_posixspawn); 452*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, socket_posixspawn); 453*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, socketpair0_posixspawn); 454*b48dffc9Sriastradh ATF_TP_ADD_TC(tp, socketpair1_posixspawn); 455*b48dffc9Sriastradh 456*b48dffc9Sriastradh return atf_no_error(); 457*b48dffc9Sriastradh } 458