]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/netbsd-tests/lib/libc/sys/t_dup.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / netbsd-tests / lib / libc / sys / t_dup.c
1 /* $NetBSD: t_dup.c,v 1.8 2012/03/18 07:00:51 jruoho Exp $ */
2
3 /*-
4  * Copyright (c) 2011 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Jukka Ruohonen.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 #include <sys/cdefs.h>
32 __RCSID("$NetBSD: t_dup.c,v 1.8 2012/03/18 07:00:51 jruoho Exp $");
33
34 #include <sys/resource.h>
35 #include <sys/stat.h>
36 #include <sys/wait.h>
37
38 #include <atf-c.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <limits.h>
42 #include <stdio.h>
43 #include <stdlib.h>
44 #include <string.h>
45 #include <unistd.h>
46 #include <sysexits.h>
47
48 #ifdef __FreeBSD__
49 #include <stdbool.h>
50 #endif
51
52 static char     path[] = "dup";
53 #ifdef __NetBSD__
54 static void     check_mode(bool, bool, bool);
55 #endif
56
57 static void
58 check_mode(bool _dup, bool _dup2, bool _dup3)
59 {
60         int mode[3] = { O_RDONLY, O_WRONLY, O_RDWR   };
61         int perm[5] = { 0700, 0400, 0600, 0444, 0666 };
62         struct stat st, st1;
63         int fd, fd1, fd2;
64         size_t i, j;
65
66         /*
67          * Check that a duplicated descriptor
68          * retains the mode of the original file.
69          */
70         for (i = 0; i < __arraycount(mode); i++) {
71
72                 for (j = 0; j < __arraycount(perm); j++) {
73
74                         fd1 = open(path, mode[i] | O_CREAT, perm[j]);
75                         fd2 = open("/etc/passwd", O_RDONLY);
76
77                         ATF_REQUIRE(fd1 >= 0);
78                         ATF_REQUIRE(fd2 >= 0);
79
80                         if (_dup != false)
81                                 fd = dup(fd1);
82                         else if (_dup2 != false)
83                                 fd = dup2(fd1, fd2);
84                         else if (_dup3 != false)
85                                 fd = dup3(fd1, fd2, O_CLOEXEC);
86                         else {
87                                 fd = -1;
88                         }
89
90                         ATF_REQUIRE(fd >= 0);
91
92                         (void)memset(&st, 0, sizeof(struct stat));
93                         (void)memset(&st1, 0, sizeof(struct stat));
94
95                         ATF_REQUIRE(fstat(fd, &st) == 0);
96                         ATF_REQUIRE(fstat(fd1, &st1) == 0);
97
98                         if (st.st_mode != st1.st_mode)
99                                 atf_tc_fail("invalid mode");
100
101                         (void)close(fd);
102                         (void)close(fd1);
103                         (void)close(fd2);
104                         (void)unlink(path);
105                 }
106         }
107 }
108
109 ATF_TC(dup2_basic);
110 ATF_TC_HEAD(dup2_basic, tc)
111 {
112         atf_tc_set_md_var(tc, "descr", "A basic test of dup2(2)");
113 }
114
115 ATF_TC_BODY(dup2_basic, tc)
116 {
117         int fd, fd1, fd2;
118
119         fd1 = open("/etc/passwd", O_RDONLY);
120         fd2 = open("/etc/passwd", O_RDONLY);
121
122         ATF_REQUIRE(fd1 >= 0);
123         ATF_REQUIRE(fd2 >= 0);
124
125         fd = dup2(fd1, fd2);
126         ATF_REQUIRE(fd >= 0);
127
128         if (fd != fd2)
129                 atf_tc_fail("invalid descriptor");
130
131         (void)close(fd);
132         (void)close(fd1);
133
134         ATF_REQUIRE(close(fd2) != 0);
135 }
136
137 ATF_TC(dup2_err);
138 ATF_TC_HEAD(dup2_err, tc)
139 {
140         atf_tc_set_md_var(tc, "descr", "Test error conditions of dup2(2)");
141 }
142
143 ATF_TC_BODY(dup2_err, tc)
144 {
145         int fd;
146
147         fd = open("/etc/passwd", O_RDONLY);
148         ATF_REQUIRE(fd >= 0);
149
150         errno = 0;
151         ATF_REQUIRE_ERRNO(EBADF, dup2(-1, -1) == -1);
152
153         errno = 0;
154         ATF_REQUIRE_ERRNO(EBADF, dup2(fd, -1) == -1);
155
156         errno = 0;
157         ATF_REQUIRE_ERRNO(EBADF, dup2(-1, fd) == -1);
158
159         /*
160          * Note that this should not fail with EINVAL.
161          */
162         ATF_REQUIRE(dup2(fd, fd) != -1);
163
164         (void)close(fd);
165 }
166
167 ATF_TC(dup2_max);
168 ATF_TC_HEAD(dup2_max, tc)
169 {
170         atf_tc_set_md_var(tc, "descr", "Test dup2(2) against limits");
171 }
172
173 ATF_TC_BODY(dup2_max, tc)
174 {
175         struct rlimit res;
176
177         (void)memset(&res, 0, sizeof(struct rlimit));
178         (void)getrlimit(RLIMIT_NOFILE, &res);
179
180         errno = 0;
181         ATF_REQUIRE_ERRNO(EBADF, dup2(STDERR_FILENO, res.rlim_cur + 1) == -1);
182 }
183
184 ATF_TC_WITH_CLEANUP(dup2_mode);
185 ATF_TC_HEAD(dup2_mode, tc)
186 {
187         atf_tc_set_md_var(tc, "descr", "A basic test of dup2(2)");
188 }
189
190 ATF_TC_BODY(dup2_mode, tc)
191 {
192         check_mode(false, true, false);
193 }
194
195 ATF_TC_CLEANUP(dup2_mode, tc)
196 {
197         (void)unlink(path);
198 }
199
200
201 ATF_TC(dup3_err);
202 ATF_TC_HEAD(dup3_err, tc)
203 {
204         atf_tc_set_md_var(tc, "descr",
205             "Test error conditions of dup3(2) (PR lib/45148)");
206 }
207
208 ATF_TC_BODY(dup3_err, tc)
209 {
210         int fd;
211
212         fd = open("/etc/passwd", O_RDONLY);
213         ATF_REQUIRE(fd >= 0);
214
215         errno = 0;
216 #if defined(__FreeBSD__) || defined(__linux__)
217         /*
218          * FreeBSD and linux return EINVAL, because...
219          *
220          * [EINVAL] The oldd argument is equal to the newd argument.
221          */
222         ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) == -1);
223 #else
224         ATF_REQUIRE(dup3(fd, fd, O_CLOEXEC) != -1);
225 #endif
226
227         errno = 0;
228 #if defined(__FreeBSD__) || defined(__linux__)
229         ATF_REQUIRE_ERRNO(EINVAL, dup3(-1, -1, O_CLOEXEC) == -1);
230         ATF_REQUIRE_ERRNO(EBADF, dup3(fd, -1, O_CLOEXEC) == -1);
231 #else
232         ATF_REQUIRE_ERRNO(EBADF, dup3(-1, -1, O_CLOEXEC) == -1);
233 #endif
234
235         errno = 0;
236         ATF_REQUIRE_ERRNO(EBADF, dup3(fd, -1, O_CLOEXEC) == -1);
237
238         errno = 0;
239         ATF_REQUIRE_ERRNO(EBADF, dup3(-1, fd, O_CLOEXEC) == -1);
240
241         errno = 0;
242         ATF_REQUIRE_ERRNO(EINVAL, dup3(fd, 1, O_NOFOLLOW) == -1);
243
244         (void)close(fd);
245 }
246
247 ATF_TC(dup3_max);
248 ATF_TC_HEAD(dup3_max, tc)
249 {
250         atf_tc_set_md_var(tc, "descr", "Test dup3(2) against limits");
251 }
252
253 ATF_TC_BODY(dup3_max, tc)
254 {
255         struct rlimit res;
256
257         (void)memset(&res, 0, sizeof(struct rlimit));
258         (void)getrlimit(RLIMIT_NOFILE, &res);
259
260         errno = 0;
261         ATF_REQUIRE_ERRNO(EBADF, dup3(STDERR_FILENO,
262                 res.rlim_cur + 1, O_CLOEXEC) == -1);
263 }
264
265 ATF_TC_WITH_CLEANUP(dup3_mode);
266 ATF_TC_HEAD(dup3_mode, tc)
267 {
268         atf_tc_set_md_var(tc, "descr", "A basic test of dup3(2)");
269 }
270
271 ATF_TC_BODY(dup3_mode, tc)
272 {
273         check_mode(false, false, true);
274 }
275
276 ATF_TC_CLEANUP(dup3_mode, tc)
277 {
278         (void)unlink(path);
279 }
280
281 ATF_TC(dup_err);
282 ATF_TC_HEAD(dup_err, tc)
283 {
284         atf_tc_set_md_var(tc, "descr", "Test error conditions of dup(2)");
285 }
286
287 ATF_TC_BODY(dup_err, tc)
288 {
289
290         errno = 0;
291         ATF_REQUIRE_ERRNO(EBADF, dup(-1) == -1);
292 }
293
294 ATF_TC_WITH_CLEANUP(dup_max);
295 ATF_TC_HEAD(dup_max, tc)
296 {
297         atf_tc_set_md_var(tc, "descr", "Test dup(2) against limits");
298 }
299
300 ATF_TC_BODY(dup_max, tc)
301 {
302         struct rlimit res;
303         int *buf, fd, sta;
304         size_t i, n;
305         pid_t pid;
306
307         pid = fork();
308         ATF_REQUIRE(pid >= 0);
309
310         if (pid == 0) {
311
312                 /*
313                  * Open a temporary file until the
314                  * maximum number of open files is
315                  * reached. Ater that dup(2) family
316                  * should fail with EMFILE.
317                  */
318                 (void)closefrom(0);
319                 (void)memset(&res, 0, sizeof(struct rlimit));
320
321                 n = 10;
322                 res.rlim_cur = res.rlim_max = n;
323                 if (setrlimit(RLIMIT_NOFILE, &res) != 0)
324                         _exit(EX_OSERR);
325
326                 buf = calloc(n, sizeof(int));
327
328                 if (buf == NULL)
329                         _exit(EX_OSERR);
330
331                 buf[0] = mkstemp(path);
332
333                 if (buf[0] < 0)
334                         _exit(EX_OSERR);
335
336                 for (i = 1; i < n; i++) {
337
338                         buf[i] = open(path, O_RDONLY);
339
340                         if (buf[i] < 0)
341                                 _exit(EX_OSERR);
342                 }
343
344                 errno = 0;
345                 fd = dup(buf[0]);
346
347                 if (fd != -1 || errno != EMFILE)
348                         _exit(EX_DATAERR);
349
350                 _exit(EXIT_SUCCESS);
351         }
352
353         (void)wait(&sta);
354
355         if (WIFEXITED(sta) == 0 || WEXITSTATUS(sta) != EXIT_SUCCESS) {
356
357                 if (WEXITSTATUS(sta) == EX_OSERR)
358                         atf_tc_fail("system call error");
359
360                 if (WEXITSTATUS(sta) == EX_DATAERR)
361                         atf_tc_fail("dup(2) dupped more than RLIMIT_NOFILE");
362
363                 atf_tc_fail("unknown error");
364         }
365
366         (void)unlink(path);
367 }
368
369 ATF_TC_CLEANUP(dup_max, tc)
370 {
371         (void)unlink(path);
372 }
373
374 ATF_TC_WITH_CLEANUP(dup_mode);
375 ATF_TC_HEAD(dup_mode, tc)
376 {
377         atf_tc_set_md_var(tc, "descr", "A basic test of dup(2)");
378 }
379
380 ATF_TC_BODY(dup_mode, tc)
381 {
382         check_mode(true, false, false);
383 }
384
385 ATF_TC_CLEANUP(dup_mode, tc)
386 {
387         (void)unlink(path);
388 }
389
390 ATF_TP_ADD_TCS(tp)
391 {
392
393         ATF_TP_ADD_TC(tp, dup2_basic);
394         ATF_TP_ADD_TC(tp, dup2_err);
395         ATF_TP_ADD_TC(tp, dup2_max);
396         ATF_TP_ADD_TC(tp, dup2_mode);
397         ATF_TP_ADD_TC(tp, dup3_err);
398         ATF_TP_ADD_TC(tp, dup3_max);
399         ATF_TP_ADD_TC(tp, dup3_mode);
400         ATF_TP_ADD_TC(tp, dup_err);
401         ATF_TP_ADD_TC(tp, dup_max);
402         ATF_TP_ADD_TC(tp, dup_mode);
403
404         return atf_no_error();
405 }