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