1*5400c854SAndy Fiddaman /* 2*5400c854SAndy Fiddaman * This file and its contents are supplied under the terms of the 3*5400c854SAndy Fiddaman * Common Development and Distribution License ("CDDL"), version 1.0. 4*5400c854SAndy Fiddaman * You may only use this file in accordance with the terms of version 5*5400c854SAndy Fiddaman * 1.0 of the CDDL. 6*5400c854SAndy Fiddaman * 7*5400c854SAndy Fiddaman * A full copy of the text of the CDDL should have accompanied this 8*5400c854SAndy Fiddaman * source. A copy of the CDDL is also available via the Internet at 9*5400c854SAndy Fiddaman * http://www.illumos.org/license/CDDL. 10*5400c854SAndy Fiddaman */ 11*5400c854SAndy Fiddaman 12*5400c854SAndy Fiddaman /* 13*5400c854SAndy Fiddaman * Copyright 2026 Oxide Computer Company 14*5400c854SAndy Fiddaman */ 15*5400c854SAndy Fiddaman 16*5400c854SAndy Fiddaman /* 17*5400c854SAndy Fiddaman * Tests for close_range(2): range semantics, CLOEXEC/CLOFORK marking, 18*5400c854SAndy Fiddaman * argument validation and the cancellation of outstanding asynchronous 19*5400c854SAndy Fiddaman * I/O against descriptors that are closed. We also exercise 20*5400c854SAndy Fiddaman * closefrom(3C), which is implemented on top of close_range(). 21*5400c854SAndy Fiddaman */ 22*5400c854SAndy Fiddaman 23*5400c854SAndy Fiddaman #include <aio.h> 24*5400c854SAndy Fiddaman #include <err.h> 25*5400c854SAndy Fiddaman #include <errno.h> 26*5400c854SAndy Fiddaman #include <fcntl.h> 27*5400c854SAndy Fiddaman #include <limits.h> 28*5400c854SAndy Fiddaman #include <stdbool.h> 29*5400c854SAndy Fiddaman #include <stdio.h> 30*5400c854SAndy Fiddaman #include <stdlib.h> 31*5400c854SAndy Fiddaman #include <string.h> 32*5400c854SAndy Fiddaman #include <time.h> 33*5400c854SAndy Fiddaman #include <unistd.h> 34*5400c854SAndy Fiddaman #include <sys/time.h> 35*5400c854SAndy Fiddaman 36*5400c854SAndy Fiddaman static uint_t failures = 0; 37*5400c854SAndy Fiddaman 38*5400c854SAndy Fiddaman #define TFAIL(name, fmt, ...) do { \ 39*5400c854SAndy Fiddaman (void) fprintf(stderr, "TEST FAILED: %s: " fmt "\n", \ 40*5400c854SAndy Fiddaman (name), ##__VA_ARGS__); \ 41*5400c854SAndy Fiddaman failures++; \ 42*5400c854SAndy Fiddaman } while (0) 43*5400c854SAndy Fiddaman 44*5400c854SAndy Fiddaman #define TPASS(name) (void) printf("TEST PASSED: %s\n", (name)) 45*5400c854SAndy Fiddaman 46*5400c854SAndy Fiddaman /* 47*5400c854SAndy Fiddaman * The test descriptors are pinned at known numbers, comfortably above 48*5400c854SAndy Fiddaman * anything the process opens for itself. 49*5400c854SAndy Fiddaman */ 50*5400c854SAndy Fiddaman #define FD_BASE 50 51*5400c854SAndy Fiddaman #define FD_LIMIT 70 52*5400c854SAndy Fiddaman 53*5400c854SAndy Fiddaman static void 54*5400c854SAndy Fiddaman open_fds(void) 55*5400c854SAndy Fiddaman { 56*5400c854SAndy Fiddaman int fd; 57*5400c854SAndy Fiddaman 58*5400c854SAndy Fiddaman if ((fd = open("/dev/null", O_RDONLY)) == -1) 59*5400c854SAndy Fiddaman err(EXIT_FAILURE, "could not open /dev/null"); 60*5400c854SAndy Fiddaman 61*5400c854SAndy Fiddaman for (int i = FD_BASE; i < FD_LIMIT; i++) { 62*5400c854SAndy Fiddaman if (dup2(fd, i) != i) 63*5400c854SAndy Fiddaman err(EXIT_FAILURE, "could not dup to fd %d", i); 64*5400c854SAndy Fiddaman } 65*5400c854SAndy Fiddaman 66*5400c854SAndy Fiddaman (void) close(fd); 67*5400c854SAndy Fiddaman } 68*5400c854SAndy Fiddaman 69*5400c854SAndy Fiddaman /* 70*5400c854SAndy Fiddaman * Verify that fd is open and carries precisely the descriptor flags in 71*5400c854SAndy Fiddaman * 'want', or, if want is -1, that fd is closed. 72*5400c854SAndy Fiddaman */ 73*5400c854SAndy Fiddaman static bool 74*5400c854SAndy Fiddaman check_fd(const char *name, int fd, int want) 75*5400c854SAndy Fiddaman { 76*5400c854SAndy Fiddaman int fl = fcntl(fd, F_GETFD); 77*5400c854SAndy Fiddaman 78*5400c854SAndy Fiddaman if (want == -1) { 79*5400c854SAndy Fiddaman if (fl != -1) { 80*5400c854SAndy Fiddaman TFAIL(name, "fd %d unexpectedly open (flags %#x)", 81*5400c854SAndy Fiddaman fd, fl); 82*5400c854SAndy Fiddaman return (false); 83*5400c854SAndy Fiddaman } 84*5400c854SAndy Fiddaman if (errno != EBADF) { 85*5400c854SAndy Fiddaman TFAIL(name, "fd %d: got errno %s, wanted EBADF", 86*5400c854SAndy Fiddaman fd, strerrorname_np(errno)); 87*5400c854SAndy Fiddaman return (false); 88*5400c854SAndy Fiddaman } 89*5400c854SAndy Fiddaman return (true); 90*5400c854SAndy Fiddaman } 91*5400c854SAndy Fiddaman 92*5400c854SAndy Fiddaman if (fl == -1) { 93*5400c854SAndy Fiddaman TFAIL(name, "fd %d unexpectedly closed", fd); 94*5400c854SAndy Fiddaman return (false); 95*5400c854SAndy Fiddaman } 96*5400c854SAndy Fiddaman if ((fl & (FD_CLOEXEC | FD_CLOFORK)) != want) { 97*5400c854SAndy Fiddaman TFAIL(name, "fd %d flags %#x, expected %#x", fd, fl, want); 98*5400c854SAndy Fiddaman return (false); 99*5400c854SAndy Fiddaman } 100*5400c854SAndy Fiddaman return (true); 101*5400c854SAndy Fiddaman } 102*5400c854SAndy Fiddaman 103*5400c854SAndy Fiddaman static bool 104*5400c854SAndy Fiddaman check_range(const char *name, int low, int high, int want) 105*5400c854SAndy Fiddaman { 106*5400c854SAndy Fiddaman bool pass = true; 107*5400c854SAndy Fiddaman 108*5400c854SAndy Fiddaman for (int fd = low; fd <= high; fd++) { 109*5400c854SAndy Fiddaman if (!check_fd(name, fd, want)) 110*5400c854SAndy Fiddaman pass = false; 111*5400c854SAndy Fiddaman } 112*5400c854SAndy Fiddaman return (pass); 113*5400c854SAndy Fiddaman } 114*5400c854SAndy Fiddaman 115*5400c854SAndy Fiddaman static void 116*5400c854SAndy Fiddaman expect_einval(const char *name, uint_t low, uint_t high, int flags) 117*5400c854SAndy Fiddaman { 118*5400c854SAndy Fiddaman int ret = close_range(low, high, flags); 119*5400c854SAndy Fiddaman 120*5400c854SAndy Fiddaman if (ret != -1) { 121*5400c854SAndy Fiddaman TFAIL(name, "close_range returned %d, expected failure", ret); 122*5400c854SAndy Fiddaman return; 123*5400c854SAndy Fiddaman } 124*5400c854SAndy Fiddaman if (errno != EINVAL) { 125*5400c854SAndy Fiddaman TFAIL(name, "got errno %s, wanted EINVAL", 126*5400c854SAndy Fiddaman strerrorname_np(errno)); 127*5400c854SAndy Fiddaman return; 128*5400c854SAndy Fiddaman } 129*5400c854SAndy Fiddaman TPASS(name); 130*5400c854SAndy Fiddaman } 131*5400c854SAndy Fiddaman 132*5400c854SAndy Fiddaman /* 133*5400c854SAndy Fiddaman * Render an aio_error() result, or the -1 used here to indicate a 134*5400c854SAndy Fiddaman * timeout, for a failure message. 135*5400c854SAndy Fiddaman */ 136*5400c854SAndy Fiddaman static const char * 137*5400c854SAndy Fiddaman errname(int e) 138*5400c854SAndy Fiddaman { 139*5400c854SAndy Fiddaman const char *n; 140*5400c854SAndy Fiddaman 141*5400c854SAndy Fiddaman if (e == -1) 142*5400c854SAndy Fiddaman return ("EINPROGRESS (timed out)"); 143*5400c854SAndy Fiddaman if (e == 0) 144*5400c854SAndy Fiddaman return ("success"); 145*5400c854SAndy Fiddaman if ((n = strerrorname_np(e)) == NULL) 146*5400c854SAndy Fiddaman return ("unknown error"); 147*5400c854SAndy Fiddaman return (n); 148*5400c854SAndy Fiddaman } 149*5400c854SAndy Fiddaman 150*5400c854SAndy Fiddaman /* 151*5400c854SAndy Fiddaman * Create a pipe with the read end at the requested descriptor, returning 152*5400c854SAndy Fiddaman * the write end. 153*5400c854SAndy Fiddaman */ 154*5400c854SAndy Fiddaman static int 155*5400c854SAndy Fiddaman pipe_at(int rfd) 156*5400c854SAndy Fiddaman { 157*5400c854SAndy Fiddaman int p[2]; 158*5400c854SAndy Fiddaman 159*5400c854SAndy Fiddaman if (pipe(p) == -1) 160*5400c854SAndy Fiddaman err(EXIT_FAILURE, "pipe"); 161*5400c854SAndy Fiddaman if (dup2(p[0], rfd) != rfd) 162*5400c854SAndy Fiddaman err(EXIT_FAILURE, "could not dup pipe to fd %d", rfd); 163*5400c854SAndy Fiddaman (void) close(p[0]); 164*5400c854SAndy Fiddaman return (p[1]); 165*5400c854SAndy Fiddaman } 166*5400c854SAndy Fiddaman 167*5400c854SAndy Fiddaman /* 168*5400c854SAndy Fiddaman * Start an asynchronous read against fd. The pipes used here are kept 169*5400c854SAndy Fiddaman * empty, so the request stays outstanding until data arrives or it is 170*5400c854SAndy Fiddaman * cancelled. 171*5400c854SAndy Fiddaman */ 172*5400c854SAndy Fiddaman static void 173*5400c854SAndy Fiddaman start_aio(struct aiocb *cb, int fd, char *buf, size_t bufsz) 174*5400c854SAndy Fiddaman { 175*5400c854SAndy Fiddaman (void) memset(cb, 0, sizeof (*cb)); 176*5400c854SAndy Fiddaman cb->aio_fildes = fd; 177*5400c854SAndy Fiddaman cb->aio_buf = buf; 178*5400c854SAndy Fiddaman cb->aio_nbytes = bufsz; 179*5400c854SAndy Fiddaman if (aio_read(cb) != 0) 180*5400c854SAndy Fiddaman err(EXIT_FAILURE, "aio_read(fd %d)", fd); 181*5400c854SAndy Fiddaman } 182*5400c854SAndy Fiddaman 183*5400c854SAndy Fiddaman /* 184*5400c854SAndy Fiddaman * Wait for an asynchronous request to leave the in-progress state and 185*5400c854SAndy Fiddaman * return its final aio_error() value, or -1 if it is still in progress 186*5400c854SAndy Fiddaman * after five seconds. 187*5400c854SAndy Fiddaman */ 188*5400c854SAndy Fiddaman static int 189*5400c854SAndy Fiddaman await_aio(const struct aiocb *cb) 190*5400c854SAndy Fiddaman { 191*5400c854SAndy Fiddaman const struct timespec ts = { .tv_sec = 0, .tv_nsec = MSEC2NSEC(1) }; 192*5400c854SAndy Fiddaman 193*5400c854SAndy Fiddaman for (int i = 0; i < 5000; i++) { 194*5400c854SAndy Fiddaman int e = aio_error(cb); 195*5400c854SAndy Fiddaman 196*5400c854SAndy Fiddaman if (e != EINPROGRESS) 197*5400c854SAndy Fiddaman return (e); 198*5400c854SAndy Fiddaman (void) nanosleep(&ts, NULL); 199*5400c854SAndy Fiddaman } 200*5400c854SAndy Fiddaman return (-1); 201*5400c854SAndy Fiddaman } 202*5400c854SAndy Fiddaman 203*5400c854SAndy Fiddaman /* 204*5400c854SAndy Fiddaman * Closing a range must cancel outstanding user-level aio requests 205*5400c854SAndy Fiddaman * against the descriptors within it, and only those. A range that is 206*5400c854SAndy Fiddaman * only having descriptor flags set must not disturb aio at all. 207*5400c854SAndy Fiddaman */ 208*5400c854SAndy Fiddaman static void 209*5400c854SAndy Fiddaman run_aio_tests(void) 210*5400c854SAndy Fiddaman { 211*5400c854SAndy Fiddaman struct aiocb cb_range, cb_below, cb_flag, cb_from; 212*5400c854SAndy Fiddaman char buf_range[4], buf_below[4], buf_flag[4], buf_from[4]; 213*5400c854SAndy Fiddaman ssize_t rv; 214*5400c854SAndy Fiddaman int wfd, e; 215*5400c854SAndy Fiddaman 216*5400c854SAndy Fiddaman (void) pipe_at(80); 217*5400c854SAndy Fiddaman wfd = pipe_at(40); 218*5400c854SAndy Fiddaman start_aio(&cb_range, 80, buf_range, sizeof (buf_range)); 219*5400c854SAndy Fiddaman start_aio(&cb_below, 40, buf_below, sizeof (buf_below)); 220*5400c854SAndy Fiddaman 221*5400c854SAndy Fiddaman /* Closing a range cancels requests against descriptors within it */ 222*5400c854SAndy Fiddaman if (close_range(60, UINT_MAX, 0) != 0) 223*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(60, UINT_MAX, 0)"); 224*5400c854SAndy Fiddaman if ((e = await_aio(&cb_range)) != ECANCELED) { 225*5400c854SAndy Fiddaman TFAIL("aio-cancel-range", "request finished with %s, " 226*5400c854SAndy Fiddaman "wanted ECANCELED", errname(e)); 227*5400c854SAndy Fiddaman } else if (aio_return(&cb_range) != -1) { 228*5400c854SAndy Fiddaman TFAIL("aio-cancel-range", "aio_return did not report an " 229*5400c854SAndy Fiddaman "error after cancellation"); 230*5400c854SAndy Fiddaman } else if (check_fd("aio-cancel-range", 80, -1)) { 231*5400c854SAndy Fiddaman TPASS("aio-cancel-range"); 232*5400c854SAndy Fiddaman } 233*5400c854SAndy Fiddaman 234*5400c854SAndy Fiddaman /* Requests against descriptors below the range are untouched */ 235*5400c854SAndy Fiddaman if (write(wfd, "ok", 2) != 2) 236*5400c854SAndy Fiddaman err(EXIT_FAILURE, "write to pipe"); 237*5400c854SAndy Fiddaman if ((e = await_aio(&cb_below)) != 0) { 238*5400c854SAndy Fiddaman TFAIL("aio-below-range", "request finished with %s, " 239*5400c854SAndy Fiddaman "wanted success", errname(e)); 240*5400c854SAndy Fiddaman } else if ((rv = aio_return(&cb_below)) != 2) { 241*5400c854SAndy Fiddaman TFAIL("aio-below-range", "aio_return gave %zd, wanted 2", rv); 242*5400c854SAndy Fiddaman } else { 243*5400c854SAndy Fiddaman TPASS("aio-below-range"); 244*5400c854SAndy Fiddaman } 245*5400c854SAndy Fiddaman 246*5400c854SAndy Fiddaman /* Setting descriptor flags must not cancel outstanding aio */ 247*5400c854SAndy Fiddaman start_aio(&cb_flag, 40, buf_flag, sizeof (buf_flag)); 248*5400c854SAndy Fiddaman if (close_range(40, 40, CLOSE_RANGE_CLOFORK) != 0) 249*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(40, 40, CLOSE_RANGE_CLOFORK)"); 250*5400c854SAndy Fiddaman if (close_range(40, 40, CLOSE_RANGE_CLOEXEC) != 0) 251*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(40, 40, CLOSE_RANGE_CLOEXEC)"); 252*5400c854SAndy Fiddaman e = aio_error(&cb_flag); 253*5400c854SAndy Fiddaman if (write(wfd, "ok", 2) != 2) 254*5400c854SAndy Fiddaman err(EXIT_FAILURE, "write to pipe"); 255*5400c854SAndy Fiddaman if (e != EINPROGRESS) { 256*5400c854SAndy Fiddaman TFAIL("aio-mark-keeps", "request no longer in progress " 257*5400c854SAndy Fiddaman "after flag marking: %s", errname(e)); 258*5400c854SAndy Fiddaman } else if ((e = await_aio(&cb_flag)) != 0) { 259*5400c854SAndy Fiddaman TFAIL("aio-mark-keeps", "request finished with %s, " 260*5400c854SAndy Fiddaman "wanted success", errname(e)); 261*5400c854SAndy Fiddaman } else if ((rv = aio_return(&cb_flag)) != 2) { 262*5400c854SAndy Fiddaman TFAIL("aio-mark-keeps", "aio_return gave %zd, wanted 2", rv); 263*5400c854SAndy Fiddaman } else if (check_fd("aio-mark-keeps", 40, FD_CLOEXEC | FD_CLOFORK)) { 264*5400c854SAndy Fiddaman TPASS("aio-mark-keeps"); 265*5400c854SAndy Fiddaman } 266*5400c854SAndy Fiddaman 267*5400c854SAndy Fiddaman /* closefrom() cancels through the same path */ 268*5400c854SAndy Fiddaman (void) pipe_at(80); 269*5400c854SAndy Fiddaman start_aio(&cb_from, 80, buf_from, sizeof (buf_from)); 270*5400c854SAndy Fiddaman closefrom(80); 271*5400c854SAndy Fiddaman if ((e = await_aio(&cb_from)) != ECANCELED) { 272*5400c854SAndy Fiddaman TFAIL("aio-cancel-closefrom", "request finished with %s, " 273*5400c854SAndy Fiddaman "wanted ECANCELED", errname(e)); 274*5400c854SAndy Fiddaman } else if (check_fd("aio-cancel-closefrom", 80, -1)) { 275*5400c854SAndy Fiddaman TPASS("aio-cancel-closefrom"); 276*5400c854SAndy Fiddaman } 277*5400c854SAndy Fiddaman } 278*5400c854SAndy Fiddaman 279*5400c854SAndy Fiddaman int 280*5400c854SAndy Fiddaman main(void) 281*5400c854SAndy Fiddaman { 282*5400c854SAndy Fiddaman open_fds(); 283*5400c854SAndy Fiddaman 284*5400c854SAndy Fiddaman /* Invalid arguments. An empty high range so a bug cannot bite. */ 285*5400c854SAndy Fiddaman expect_einval("low-gt-high", 5, 4, 0); 286*5400c854SAndy Fiddaman expect_einval("flag-unknown", 1000000, 1000001, 1 << 2); 287*5400c854SAndy Fiddaman expect_einval("flag-junk", 1000000, 1000001, ~0); 288*5400c854SAndy Fiddaman 289*5400c854SAndy Fiddaman /* A range beyond every open descriptor succeeds and does nothing */ 290*5400c854SAndy Fiddaman if (close_range(1000000, UINT_MAX, 0) != 0) { 291*5400c854SAndy Fiddaman TFAIL("range-empty", "failed: %s", strerrorname_np(errno)); 292*5400c854SAndy Fiddaman } else { 293*5400c854SAndy Fiddaman TPASS("range-empty"); 294*5400c854SAndy Fiddaman } 295*5400c854SAndy Fiddaman 296*5400c854SAndy Fiddaman /* A low bound above INT_MAX must not close anything */ 297*5400c854SAndy Fiddaman if (close_range(0x80000000U, UINT_MAX, 0) != 0) { 298*5400c854SAndy Fiddaman TFAIL("low-gt-intmax", "failed: %s", 299*5400c854SAndy Fiddaman strerrorname_np(errno)); 300*5400c854SAndy Fiddaman } else if (check_range("low-gt-intmax", FD_BASE, FD_LIMIT - 1, 0)) { 301*5400c854SAndy Fiddaman TPASS("low-gt-intmax"); 302*5400c854SAndy Fiddaman } 303*5400c854SAndy Fiddaman 304*5400c854SAndy Fiddaman /* Close the middle of the block and check the neighbours */ 305*5400c854SAndy Fiddaman if (close_range(55, 59, 0) != 0) 306*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(55, 59, 0)"); 307*5400c854SAndy Fiddaman if (check_range("close-mid", 50, 54, 0) && 308*5400c854SAndy Fiddaman check_range("close-mid", 55, 59, -1) && 309*5400c854SAndy Fiddaman check_range("close-mid", 60, 69, 0)) { 310*5400c854SAndy Fiddaman TPASS("close-mid"); 311*5400c854SAndy Fiddaman } 312*5400c854SAndy Fiddaman 313*5400c854SAndy Fiddaman /* Mark ranges with each flag, then both together */ 314*5400c854SAndy Fiddaman if (close_range(60, 64, CLOSE_RANGE_CLOEXEC) != 0) 315*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(CLOSE_RANGE_CLOEXEC)"); 316*5400c854SAndy Fiddaman if (check_range("mark-cloexec", 60, 64, FD_CLOEXEC) && 317*5400c854SAndy Fiddaman check_range("mark-cloexec", 65, 69, 0)) { 318*5400c854SAndy Fiddaman TPASS("mark-cloexec"); 319*5400c854SAndy Fiddaman } 320*5400c854SAndy Fiddaman 321*5400c854SAndy Fiddaman if (close_range(65, 67, CLOSE_RANGE_CLOFORK) != 0) 322*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(CLOSE_RANGE_CLOFORK)"); 323*5400c854SAndy Fiddaman if (check_range("mark-clofork", 65, 67, FD_CLOFORK) && 324*5400c854SAndy Fiddaman check_range("mark-clofork", 68, 69, 0)) { 325*5400c854SAndy Fiddaman TPASS("mark-clofork"); 326*5400c854SAndy Fiddaman } 327*5400c854SAndy Fiddaman 328*5400c854SAndy Fiddaman /* Adding a second flag must preserve the first */ 329*5400c854SAndy Fiddaman if (close_range(65, 67, CLOSE_RANGE_CLOEXEC) != 0) 330*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(add CLOSE_RANGE_CLOEXEC)"); 331*5400c854SAndy Fiddaman if (check_range("mark-accumulate", 65, 67, FD_CLOEXEC | FD_CLOFORK)) 332*5400c854SAndy Fiddaman TPASS("mark-accumulate"); 333*5400c854SAndy Fiddaman 334*5400c854SAndy Fiddaman if (close_range(68, 69, 335*5400c854SAndy Fiddaman CLOSE_RANGE_CLOEXEC | CLOSE_RANGE_CLOFORK) != 0) { 336*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(both flags)"); 337*5400c854SAndy Fiddaman } 338*5400c854SAndy Fiddaman if (check_range("mark-both", 68, 69, FD_CLOEXEC | FD_CLOFORK)) 339*5400c854SAndy Fiddaman TPASS("mark-both"); 340*5400c854SAndy Fiddaman 341*5400c854SAndy Fiddaman /* Marking a range that includes closed descriptors skips them */ 342*5400c854SAndy Fiddaman if (close_range(55, 64, CLOSE_RANGE_CLOEXEC) != 0) 343*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range over closed fds"); 344*5400c854SAndy Fiddaman if (check_range("mark-gaps", 55, 59, -1) && 345*5400c854SAndy Fiddaman check_range("mark-gaps", 60, 64, FD_CLOEXEC)) { 346*5400c854SAndy Fiddaman TPASS("mark-gaps"); 347*5400c854SAndy Fiddaman } 348*5400c854SAndy Fiddaman 349*5400c854SAndy Fiddaman /* The closefrom() form: everything at or above low goes */ 350*5400c854SAndy Fiddaman if (close_range(52, UINT_MAX, 0) != 0) 351*5400c854SAndy Fiddaman err(EXIT_FAILURE, "close_range(52, UINT_MAX, 0)"); 352*5400c854SAndy Fiddaman if (check_range("close-from", 50, 51, 0) && 353*5400c854SAndy Fiddaman check_range("close-from", 52, FD_LIMIT - 1, -1)) { 354*5400c854SAndy Fiddaman TPASS("close-from"); 355*5400c854SAndy Fiddaman } 356*5400c854SAndy Fiddaman 357*5400c854SAndy Fiddaman /* And closefrom(3C) itself, now built on close_range() */ 358*5400c854SAndy Fiddaman open_fds(); 359*5400c854SAndy Fiddaman closefrom(FD_BASE + 1); 360*5400c854SAndy Fiddaman if (check_fd("closefrom", FD_BASE, 0) && 361*5400c854SAndy Fiddaman check_range("closefrom", FD_BASE + 1, FD_LIMIT - 1, -1)) { 362*5400c854SAndy Fiddaman TPASS("closefrom"); 363*5400c854SAndy Fiddaman } 364*5400c854SAndy Fiddaman 365*5400c854SAndy Fiddaman run_aio_tests(); 366*5400c854SAndy Fiddaman 367*5400c854SAndy Fiddaman if (failures == 0) { 368*5400c854SAndy Fiddaman (void) printf("All tests passed\n"); 369*5400c854SAndy Fiddaman return (EXIT_SUCCESS); 370*5400c854SAndy Fiddaman } 371*5400c854SAndy Fiddaman 372*5400c854SAndy Fiddaman (void) fprintf(stderr, "%u test(s) failed\n", failures); 373*5400c854SAndy Fiddaman return (EXIT_FAILURE); 374*5400c854SAndy Fiddaman } 375