2 * Copyright (c) 2009 Hudson River Trading LLC
3 * Written by: John H. Baldwin <jhb@FreeBSD.org>
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28 #include <sys/cdefs.h>
30 * Regression tests for the closefrom(2) system call.
33 #include <sys/param.h>
59 printf("ok %d - %s\n", test, descr);
64 fail(const char *descr, const char *fmt, ...)
68 printf("not ok %d - %s", test, descr);
80 #define fail_err(descr) fail((descr), "%s", strerror(errno))
83 cok(struct shared_info *info, const char *descr)
87 strlcpy(info->tag, descr, sizeof(info->tag));
92 cfail(struct shared_info *info, const char *descr, const char *fmt, ...)
97 strlcpy(info->tag, descr, sizeof(info->tag));
100 vsprintf(info->message, fmt, ap);
106 #define cfail_err(info, descr) cfail((info), (descr), "%s", strerror(errno))
109 * Use kinfo_getfile() to fetch the list of file descriptors and figure out
110 * the highest open file descriptor.
115 struct kinfo_file *kif;
118 kif = kinfo_getfile(getpid(), &cnt);
120 fail_err("kinfo_getfile");
122 for (i = 0; i < cnt; i++)
123 if (kif[i].kf_fd > highest)
124 highest = kif[i].kf_fd;
134 fd = open(_PATH_DEVNULL, O_RDONLY);
136 fail_err("open(\" "_PATH_DEVNULL" \")");
143 struct shared_info *info;
145 int fd, flags, i, start;
149 /* We better start up with fd's 0, 1, and 2 open. */
152 fail("open", "bad descriptor %d", start);
155 /* Make sure highest_fd() works. */
158 fail("highest_fd", "bad descriptor %d != %d", start, fd);
161 /* Try to use closefrom() for just closing fd 3. */
162 closefrom(start + 1);
165 fail("closefrom", "highest fd %d", fd);
168 /* Eat up 16 descriptors. */
169 for (i = 0; i < 16; i++)
172 if (fd != start + 16)
173 fail("open 16", "highest fd %d", fd);
176 /* Close half of them. */
180 fail("closefrom", "highest fd %d", fd);
183 /* Explicitly close descriptors 6 and 8 to create holes. */
184 if (close(6) < 0 || close(8) < 0)
188 /* Verify that close on 6 and 8 fails with EBADF. */
190 fail("close(6)", "did not fail");
192 fail_err("close(6)");
195 fail("close(8)", "did not fail");
197 fail_err("close(8)");
200 /* Close from 4 on. */
204 fail("closefrom", "highest fd %d", fd);
207 /* Allocate a small SHM region for IPC with our child. */
208 info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON |
210 if (info == MAP_FAILED)
214 /* Fork a child process to test closefrom(0). */
223 cfail(info, "closefrom(0)", "highest fd %d", fd);
224 cok(info, "closefrom(0)");
229 fail(info->tag, "%s", info->message);
232 /* Fork a child process to test closefrom(-1). */
241 cfail(info, "closefrom(-1)", "highest fd %d", fd);
242 cok(info, "closefrom(-1)");
247 fail(info->tag, "%s", info->message);
250 /* Dup stdout to 6. */
255 fail("dup2", "highest fd %d", fd);
258 /* Do a closefrom() starting in a hole. */
262 fail("closefrom", "highest fd %d", fd);
265 /* Do a closefrom() beyond our highest open fd. */
269 fail("closefrom", "highest fd %d", fd);
272 /* Chew up another 8 fd */
273 for (i = 0; i < 8; i++)
278 /* close_range() a hole in the middle */
279 close_range(start + 3, start + 5, 0);
280 for (i = start + 3; i < start + 6; ++i) {
281 if (close(i) == 0 || errno != EBADF) {
287 fail("close_range", "failed to close at %d in %d - %d", i + 1,
288 start + 3, start + 6);
291 /* close_range from the middle of the hole */
292 close_range(start + 4, start + 6, 0);
293 if ((i = highest_fd()) != fd)
294 fail("close_range", "highest fd %d", i);
297 /* close_range to the end; effectively closefrom(2) */
298 close_range(start + 3, ~0L, 0);
299 if ((i = highest_fd()) != start + 2)
300 fail("close_range", "highest fd %d", i);
303 /* Now close the rest */
304 close_range(start, start + 4, 0);
307 fail("close_range", "highest fd %d", fd);
310 /* Fork a child process to test closefrom(0) twice. */
318 cok(info, "closefrom(0)");
323 fail(info->tag, "%s", info->message);
326 /* test CLOSE_RANGE_CLOEXEC */
327 for (i = 0; i < 8; i++)
331 if (close_range(start + 1, start + 4, CLOSE_RANGE_CLOEXEC) < 0)
332 fail_err("close_range(..., CLOSE_RANGE_CLOEXEC)");
333 flags = fcntl(start, F_GETFD);
335 fail_err("fcntl(.., F_GETFD)");
336 if ((flags & FD_CLOEXEC) != 0)
337 fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec "
338 "when it should not have on fd %d", start);
339 for (i = start + 1; i <= start + 4; i++) {
340 flags = fcntl(i, F_GETFD);
342 fail_err("fcntl(.., F_GETFD)");
343 if ((flags & FD_CLOEXEC) == 0)
344 fail("close_range", "CLOSE_RANGE_CLOEXEC did not set "
345 "close-on-exec on fd %d", i);
347 for (; i < start + 8; i++) {
348 flags = fcntl(i, F_GETFD);
350 fail_err("fcntl(.., F_GETFD)");
351 if ((flags & FD_CLOEXEC) != 0)
352 fail("close_range", "CLOSE_RANGE_CLOEXEC set close-on-exec "
353 "when it should not have on fd %d", i);
355 if (close_range(start, start + 8, 0) < 0)
356 fail_err("close_range");
357 ok("close_range(..., CLOSE_RANGE_CLOEXEC)");