1194262Sjhb/*- 2282067Sngie * Copyright (c) 2009 Hudson River Trading LLC 3194262Sjhb * Written by: John H. Baldwin <jhb@FreeBSD.org> 4194262Sjhb * All rights reserved. 5194262Sjhb * 6194262Sjhb * Redistribution and use in source and binary forms, with or without 7194262Sjhb * modification, are permitted provided that the following conditions 8194262Sjhb * are met: 9194262Sjhb * 1. Redistributions of source code must retain the above copyright 10194262Sjhb * notice, this list of conditions and the following disclaimer. 11194262Sjhb * 2. Redistributions in binary form must reproduce the above copyright 12194262Sjhb * notice, this list of conditions and the following disclaimer in the 13194262Sjhb * documentation and/or other materials provided with the distribution. 14194262Sjhb * 15194262Sjhb * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16194262Sjhb * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17194262Sjhb * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18194262Sjhb * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19194262Sjhb * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20194262Sjhb * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21194262Sjhb * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22194262Sjhb * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23194262Sjhb * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24194262Sjhb * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25194262Sjhb * SUCH DAMAGE. 26194262Sjhb */ 27194262Sjhb 28194262Sjhb#include <sys/cdefs.h> 29194262Sjhb__FBSDID("$FreeBSD: releng/10.3/tests/sys/file/closefrom_test.c 282067 2015-04-27 08:15:17Z ngie $"); 30194262Sjhb 31194262Sjhb/* 32194262Sjhb * Regression tests for the closefrom(2) system call. 33194262Sjhb */ 34194262Sjhb 35194262Sjhb#include <sys/param.h> 36194262Sjhb#include <sys/mman.h> 37194262Sjhb#include <sys/user.h> 38194262Sjhb#include <sys/wait.h> 39194262Sjhb#include <errno.h> 40194262Sjhb#include <fcntl.h> 41194262Sjhb#include <libutil.h> 42281432Sngie#include <paths.h> 43194262Sjhb#include <stdarg.h> 44194262Sjhb#include <stdio.h> 45194262Sjhb#include <stdlib.h> 46194262Sjhb#include <string.h> 47194262Sjhb#include <unistd.h> 48194262Sjhb 49194262Sjhbstruct shared_info { 50194262Sjhb int failed; 51194262Sjhb char tag[64]; 52194262Sjhb char message[0]; 53194262Sjhb}; 54194262Sjhb 55194262Sjhbstatic int test = 1; 56194262Sjhb 57194262Sjhbstatic void 58194262Sjhbok(const char *descr) 59194262Sjhb{ 60194262Sjhb 61194262Sjhb printf("ok %d - %s\n", test, descr); 62194262Sjhb test++; 63194262Sjhb} 64194262Sjhb 65194262Sjhbstatic void 66194262Sjhbfail(const char *descr, const char *fmt, ...) 67194262Sjhb{ 68194262Sjhb va_list ap; 69194262Sjhb 70194262Sjhb printf("not ok %d - %s", test, descr); 71194262Sjhb test++; 72194262Sjhb if (fmt) { 73194262Sjhb va_start(ap, fmt); 74194262Sjhb printf(" # "); 75194262Sjhb vprintf(fmt, ap); 76194262Sjhb va_end(ap); 77194262Sjhb } 78194262Sjhb printf("\n"); 79194262Sjhb exit(1); 80194262Sjhb} 81194262Sjhb 82194262Sjhb#define fail_err(descr) fail((descr), "%s", strerror(errno)) 83194262Sjhb 84194262Sjhbstatic void 85194262Sjhbcok(struct shared_info *info, const char *descr) 86194262Sjhb{ 87194262Sjhb 88194262Sjhb info->failed = 0; 89194262Sjhb strlcpy(info->tag, descr, sizeof(info->tag)); 90194262Sjhb exit(0); 91194262Sjhb} 92194262Sjhb 93194262Sjhbstatic void 94194262Sjhbcfail(struct shared_info *info, const char *descr, const char *fmt, ...) 95194262Sjhb{ 96194262Sjhb va_list ap; 97194262Sjhb 98194262Sjhb info->failed = 1; 99194262Sjhb strlcpy(info->tag, descr, sizeof(info->tag)); 100194262Sjhb if (fmt) { 101194262Sjhb va_start(ap, fmt); 102194262Sjhb vsprintf(info->message, fmt, ap); 103194262Sjhb va_end(ap); 104194262Sjhb } 105194262Sjhb exit(0); 106194262Sjhb} 107194262Sjhb 108194262Sjhb#define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno)) 109194262Sjhb 110194262Sjhb/* 111194262Sjhb * Use kinfo_getfile() to fetch the list of file descriptors and figure out 112194262Sjhb * the highest open file descriptor. 113194262Sjhb */ 114194262Sjhbstatic int 115194262Sjhbhighest_fd(void) 116194262Sjhb{ 117194262Sjhb struct kinfo_file *kif; 118194262Sjhb int cnt, i, highest; 119194262Sjhb 120194262Sjhb kif = kinfo_getfile(getpid(), &cnt); 121194262Sjhb if (kif == NULL) 122194262Sjhb fail_err("kinfo_getfile"); 123194262Sjhb highest = INT_MIN; 124194262Sjhb for (i = 0; i < cnt; i++) 125194262Sjhb if (kif[i].kf_fd > highest) 126194262Sjhb highest = kif[i].kf_fd; 127194262Sjhb free(kif); 128194262Sjhb return (highest); 129194262Sjhb} 130194262Sjhb 131194262Sjhbstatic int 132194262Sjhbdevnull(void) 133194262Sjhb{ 134194262Sjhb int fd; 135194262Sjhb 136281432Sngie fd = open(_PATH_DEVNULL, O_RDONLY); 137194262Sjhb if (fd < 0) 138281432Sngie fail_err("open(\" "_PATH_DEVNULL" \")"); 139194262Sjhb return (fd); 140194262Sjhb} 141194262Sjhb 142194262Sjhbint 143281432Sngiemain(void) 144194262Sjhb{ 145194262Sjhb struct shared_info *info; 146194262Sjhb pid_t pid; 147281432Sngie int fd, i, start; 148194262Sjhb 149194262Sjhb printf("1..15\n"); 150194262Sjhb 151194262Sjhb /* We better start up with fd's 0, 1, and 2 open. */ 152281432Sngie start = devnull(); 153281432Sngie if (start == -1) 154281432Sngie fail("open", "bad descriptor %d", start); 155194262Sjhb ok("open"); 156194262Sjhb 157194262Sjhb /* Make sure highest_fd() works. */ 158194262Sjhb fd = highest_fd(); 159281432Sngie if (start != fd) 160281432Sngie fail("highest_fd", "bad descriptor %d != %d", start, fd); 161194262Sjhb ok("highest_fd"); 162194262Sjhb 163194262Sjhb /* Try to use closefrom() for just closing fd 3. */ 164281432Sngie closefrom(start + 1); 165194262Sjhb fd = highest_fd(); 166281432Sngie if (fd != start) 167194262Sjhb fail("closefrom", "highest fd %d", fd); 168194262Sjhb ok("closefrom"); 169194262Sjhb 170194262Sjhb /* Eat up 16 descriptors. */ 171194262Sjhb for (i = 0; i < 16; i++) 172194262Sjhb (void)devnull(); 173194262Sjhb fd = highest_fd(); 174281432Sngie if (fd != start + 16) 175194262Sjhb fail("open 16", "highest fd %d", fd); 176194262Sjhb ok("open 16"); 177194262Sjhb 178194262Sjhb /* Close half of them. */ 179194262Sjhb closefrom(11); 180194262Sjhb fd = highest_fd(); 181194262Sjhb if (fd != 10) 182194262Sjhb fail("closefrom", "highest fd %d", fd); 183194262Sjhb ok("closefrom"); 184194262Sjhb 185194262Sjhb /* Explicitly close descriptors 6 and 8 to create holes. */ 186194262Sjhb if (close(6) < 0 || close(8) < 0) 187194262Sjhb fail_err("close2 "); 188194262Sjhb ok("close 2"); 189194262Sjhb 190194262Sjhb /* Verify that close on 6 and 8 fails with EBADF. */ 191194262Sjhb if (close(6) == 0) 192194262Sjhb fail("close(6)", "did not fail"); 193194262Sjhb if (errno != EBADF) 194194262Sjhb fail_err("close(6)"); 195194262Sjhb ok("close(6)"); 196194262Sjhb if (close(8) == 0) 197194262Sjhb fail("close(8)", "did not fail"); 198194262Sjhb if (errno != EBADF) 199194262Sjhb fail_err("close(8)"); 200194262Sjhb ok("close(8)"); 201194262Sjhb 202194262Sjhb /* Close from 4 on. */ 203194262Sjhb closefrom(4); 204194262Sjhb fd = highest_fd(); 205194262Sjhb if (fd != 3) 206194262Sjhb fail("closefrom", "highest fd %d", fd); 207194262Sjhb ok("closefrom"); 208194262Sjhb 209194262Sjhb /* Allocate a small SHM region for IPC with our child. */ 210194262Sjhb info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON | 211194262Sjhb MAP_SHARED, -1, 0); 212194262Sjhb if (info == MAP_FAILED) 213194262Sjhb fail_err("mmap"); 214194262Sjhb ok("mmap"); 215194262Sjhb 216194262Sjhb /* Fork a child process to test closefrom(0). */ 217194262Sjhb pid = fork(); 218194262Sjhb if (pid < 0) 219194262Sjhb fail_err("fork"); 220194262Sjhb if (pid == 0) { 221194262Sjhb /* Child. */ 222194262Sjhb closefrom(0); 223194262Sjhb fd = highest_fd(); 224194262Sjhb if (fd >= 0) 225194262Sjhb cfail(info, "closefrom(0)", "highest fd %d", fd); 226194262Sjhb cok(info, "closefrom(0)"); 227194262Sjhb } 228194262Sjhb if (wait(NULL) < 0) 229194262Sjhb fail_err("wait"); 230194262Sjhb if (info->failed) 231194262Sjhb fail(info->tag, "%s", info->message); 232194262Sjhb ok(info->tag); 233194262Sjhb 234194262Sjhb /* Fork a child process to test closefrom(-1). */ 235194262Sjhb pid = fork(); 236194262Sjhb if (pid < 0) 237194262Sjhb fail_err("fork"); 238194262Sjhb if (pid == 0) { 239194262Sjhb /* Child. */ 240194262Sjhb closefrom(-1); 241194262Sjhb fd = highest_fd(); 242194262Sjhb if (fd >= 0) 243194262Sjhb cfail(info, "closefrom(-1)", "highest fd %d", fd); 244194262Sjhb cok(info, "closefrom(-1)"); 245194262Sjhb } 246194262Sjhb if (wait(NULL) < 0) 247194262Sjhb fail_err("wait"); 248194262Sjhb if (info->failed) 249194262Sjhb fail(info->tag, "%s", info->message); 250194262Sjhb ok(info->tag); 251194262Sjhb 252194262Sjhb /* Dup stdout to 6. */ 253194262Sjhb if (dup2(1, 6) < 0) 254194262Sjhb fail_err("dup2"); 255194262Sjhb fd = highest_fd(); 256194262Sjhb if (fd != 6) 257194262Sjhb fail("dup2", "highest fd %d", fd); 258194262Sjhb ok("dup2"); 259194262Sjhb 260194262Sjhb /* Do a closefrom() starting in a hole. */ 261194262Sjhb closefrom(4); 262194262Sjhb fd = highest_fd(); 263194262Sjhb if (fd != 3) 264194262Sjhb fail("closefrom", "highest fd %d", fd); 265194262Sjhb ok("closefrom"); 266194262Sjhb 267194262Sjhb /* Do a closefrom() beyond our highest open fd. */ 268194262Sjhb closefrom(32); 269194262Sjhb fd = highest_fd(); 270194262Sjhb if (fd != 3) 271194262Sjhb fail("closefrom", "highest fd %d", fd); 272194262Sjhb ok("closefrom"); 273281432Sngie 274194262Sjhb return (0); 275194262Sjhb} 276