]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - tests/sys/file/closefrom_test.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / tests / sys / file / closefrom_test.c
1 /*-
2  * Copyright (c) 2009 Hudson River Trading LLC
3  * Written by: John H. Baldwin <jhb@FreeBSD.org>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
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.
14  *
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
25  * SUCH DAMAGE.
26  */
27
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30
31 /*
32  * Regression tests for the closefrom(2) system call.
33  */
34
35 #include <sys/param.h>
36 #include <sys/mman.h>
37 #include <sys/user.h>
38 #include <sys/wait.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <libutil.h>
42 #include <paths.h>
43 #include <stdarg.h>
44 #include <stdio.h>
45 #include <stdlib.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 struct shared_info {
50         int     failed;
51         char    tag[64];
52         char    message[0];
53 };
54
55 static int test = 1;
56
57 static void
58 ok(const char *descr)
59 {
60
61         printf("ok %d - %s\n", test, descr);
62         test++;
63 }
64
65 static void
66 fail(const char *descr, const char *fmt, ...)
67 {
68         va_list ap;
69
70         printf("not ok %d - %s", test, descr);
71         test++;
72         if (fmt) {
73                 va_start(ap, fmt);
74                 printf(" # ");
75                 vprintf(fmt, ap);
76                 va_end(ap);
77         }
78         printf("\n");
79         exit(1);
80 }
81
82 #define fail_err(descr)         fail((descr), "%s", strerror(errno))
83
84 static void
85 cok(struct shared_info *info, const char *descr)
86 {
87
88         info->failed = 0;
89         strlcpy(info->tag, descr, sizeof(info->tag));
90         exit(0);
91 }
92
93 static void
94 cfail(struct shared_info *info, const char *descr, const char *fmt, ...)
95 {
96         va_list ap;
97
98         info->failed = 1;
99         strlcpy(info->tag, descr, sizeof(info->tag));
100         if (fmt) {
101                 va_start(ap, fmt);
102                 vsprintf(info->message, fmt, ap);
103                 va_end(ap);
104         }
105         exit(0);
106 }
107
108 #define cfail_err(info, descr)  cfail((info), (descr), "%s", strerror(errno))
109
110 /*
111  * Use kinfo_getfile() to fetch the list of file descriptors and figure out
112  * the highest open file descriptor.
113  */
114 static int
115 highest_fd(void)
116 {
117         struct kinfo_file *kif;
118         int cnt, i, highest;
119
120         kif = kinfo_getfile(getpid(), &cnt);
121         if (kif == NULL)
122                 fail_err("kinfo_getfile");
123         highest = INT_MIN;
124         for (i = 0; i < cnt; i++)
125                 if (kif[i].kf_fd > highest)
126                         highest = kif[i].kf_fd;
127         free(kif);
128         return (highest);
129 }
130
131 static int
132 devnull(void)
133 {
134         int fd;
135
136         fd = open(_PATH_DEVNULL, O_RDONLY);
137         if (fd < 0)
138                 fail_err("open(\" "_PATH_DEVNULL" \")");
139         return (fd);
140 }
141
142 int
143 main(void)
144 {
145         struct shared_info *info;
146         pid_t pid;
147         int fd, i, start;
148
149         printf("1..15\n");
150
151         /* We better start up with fd's 0, 1, and 2 open. */
152         start = devnull();
153         if (start == -1)
154                 fail("open", "bad descriptor %d", start);
155         ok("open");
156
157         /* Make sure highest_fd() works. */
158         fd = highest_fd();
159         if (start != fd)
160                 fail("highest_fd", "bad descriptor %d != %d", start, fd);
161         ok("highest_fd");
162
163         /* Try to use closefrom() for just closing fd 3. */
164         closefrom(start + 1);
165         fd = highest_fd();
166         if (fd != start)
167                 fail("closefrom", "highest fd %d", fd);
168         ok("closefrom");
169
170         /* Eat up 16 descriptors. */
171         for (i = 0; i < 16; i++)
172                 (void)devnull();
173         fd = highest_fd();
174         if (fd != start + 16)
175                 fail("open 16", "highest fd %d", fd);
176         ok("open 16");
177
178         /* Close half of them. */
179         closefrom(11);
180         fd = highest_fd();
181         if (fd != 10)
182                 fail("closefrom", "highest fd %d", fd);
183         ok("closefrom");
184
185         /* Explicitly close descriptors 6 and 8 to create holes. */
186         if (close(6) < 0 || close(8) < 0)
187                 fail_err("close2 ");
188         ok("close 2");
189
190         /* Verify that close on 6 and 8 fails with EBADF. */
191         if (close(6) == 0)
192                 fail("close(6)", "did not fail");
193         if (errno != EBADF)
194                 fail_err("close(6)");
195         ok("close(6)");
196         if (close(8) == 0)
197                 fail("close(8)", "did not fail");
198         if (errno != EBADF)
199                 fail_err("close(8)");
200         ok("close(8)");
201
202         /* Close from 4 on. */
203         closefrom(4);
204         fd = highest_fd();
205         if (fd != 3)
206                 fail("closefrom", "highest fd %d", fd);
207         ok("closefrom");
208
209         /* Allocate a small SHM region for IPC with our child. */
210         info = mmap(NULL, getpagesize(), PROT_READ | PROT_WRITE, MAP_ANON |
211             MAP_SHARED, -1, 0);
212         if (info == MAP_FAILED)
213                 fail_err("mmap");
214         ok("mmap");
215
216         /* Fork a child process to test closefrom(0). */
217         pid = fork();
218         if (pid < 0)
219                 fail_err("fork");
220         if (pid == 0) {
221                 /* Child. */
222                 closefrom(0);
223                 fd = highest_fd();
224                 if (fd >= 0)
225                         cfail(info, "closefrom(0)", "highest fd %d", fd);
226                 cok(info, "closefrom(0)");
227         }
228         if (wait(NULL) < 0)
229                 fail_err("wait");
230         if (info->failed)
231                 fail(info->tag, "%s", info->message);
232         ok(info->tag);
233
234         /* Fork a child process to test closefrom(-1). */
235         pid = fork();
236         if (pid < 0)
237                 fail_err("fork");
238         if (pid == 0) {
239                 /* Child. */
240                 closefrom(-1);
241                 fd = highest_fd();
242                 if (fd >= 0)
243                         cfail(info, "closefrom(-1)", "highest fd %d", fd);
244                 cok(info, "closefrom(-1)");
245         }
246         if (wait(NULL) < 0)
247                 fail_err("wait");
248         if (info->failed)
249                 fail(info->tag, "%s", info->message);
250         ok(info->tag);
251
252         /* Dup stdout to 6. */
253         if (dup2(1, 6) < 0)
254                 fail_err("dup2");
255         fd = highest_fd();
256         if (fd != 6)
257                 fail("dup2", "highest fd %d", fd);
258         ok("dup2");
259
260         /* Do a closefrom() starting in a hole. */
261         closefrom(4);
262         fd = highest_fd();
263         if (fd != 3)
264                 fail("closefrom", "highest fd %d", fd);
265         ok("closefrom");
266
267         /* Do a closefrom() beyond our highest open fd. */
268         closefrom(32);
269         fd = highest_fd();
270         if (fd != 3)
271                 fail("closefrom", "highest fd %d", fd);
272         ok("closefrom");
273
274         return (0);
275 }