ldexpl; Update regarding AIX.
[gnulib.git] / tests / test-fcntl.c
1 /* Test of fcntl(2).
2    Copyright (C) 2009, 2010 Free Software Foundation, Inc.
3
4    This program is free software: you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 3 of the License, or
7    (at your option) any later version.
8
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13
14    You should have received a copy of the GNU General Public License
15    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
16
17 /* Written by Eric Blake <ebb9@byu.net>, 2009.  */
18
19 #include <config.h>
20
21 /* Specification.  */
22 #include <fcntl.h>
23
24 #include "signature.h"
25 SIGNATURE_CHECK (fcntl, int, (int, int, ...));
26
27 /* Helpers.  */
28 #include <errno.h>
29 #include <stdarg.h>
30 #include <stdbool.h>
31 #include <unistd.h>
32
33 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
34 /* Get declarations of the Win32 API functions.  */
35 # define WIN32_LEAN_AND_MEAN
36 # include <windows.h>
37 #endif
38
39 #include "binary-io.h"
40 #include "macros.h"
41
42 /* Use O_CLOEXEC if available, but test works without it.  */
43 #ifndef O_CLOEXEC
44 # define O_CLOEXEC 0
45 #endif
46
47 #if !O_BINARY
48 # define setmode(f,m) zero ()
49 static int zero (void) { return 0; }
50 #endif
51
52 /* Return true if FD is open.  */
53 static bool
54 is_open (int fd)
55 {
56 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
57   /* On Win32, the initial state of unassigned standard file
58      descriptors is that they are open but point to an
59      INVALID_HANDLE_VALUE, and there is no fcntl.  */
60   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
61 #else
62 # ifndef F_GETFL
63 #  error Please port fcntl to your platform
64 # endif
65   return 0 <= fcntl (fd, F_GETFL);
66 #endif
67 }
68
69 /* Return true if FD is open and inheritable across exec/spawn.  */
70 static bool
71 is_inheritable (int fd)
72 {
73 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
74   /* On Win32, the initial state of unassigned standard file
75      descriptors is that they are open but point to an
76      INVALID_HANDLE_VALUE, and there is no fcntl.  */
77   HANDLE h = (HANDLE) _get_osfhandle (fd);
78   DWORD flags;
79   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
80     return false;
81   return (flags & HANDLE_FLAG_INHERIT) != 0;
82 #else
83 # ifndef F_GETFD
84 #  error Please port fcntl to your platform
85 # endif
86   int i = fcntl (fd, F_GETFD);
87   return 0 <= i && (i & FD_CLOEXEC) == 0;
88 #endif
89 }
90
91 /* Return non-zero if FD is open in the given MODE, which is either
92    O_TEXT or O_BINARY.  */
93 static bool
94 is_mode (int fd, int mode)
95 {
96   int value = setmode (fd, O_BINARY);
97   setmode (fd, value);
98   return mode == value;
99 }
100
101 /* Since native fcntl can have more supported operations than our
102    replacement is aware of, and since various operations assign
103    different types to the vararg argument, a wrapper around fcntl must
104    be able to pass a vararg of unknown type on through to the original
105    fcntl.  Make sure that this works properly: func1 behaves like the
106    original fcntl interpreting the vararg as an int or a pointer to a
107    struct, and func2 behaves like rpl_fcntl that doesn't know what
108    type to forward.  */
109 struct dummy_struct
110 {
111   long filler;
112   int value;
113 };
114 static int
115 func1 (int a, ...)
116 {
117   va_list arg;
118   int i;
119   va_start (arg, a);
120   if (a < 4)
121     i = va_arg (arg, int);
122   else
123     {
124       struct dummy_struct *s = va_arg (arg, struct dummy_struct *);
125       i = s->value;
126     }
127   va_end (arg);
128   return i;
129 }
130 static int
131 func2 (int a, ...)
132 {
133   va_list arg;
134   void *p;
135   va_start (arg, a);
136   p = va_arg (arg, void *);
137   va_end (arg);
138   return func1 (a, p);
139 }
140
141 /* Ensure that all supported fcntl actions are distinct, and
142    usable in preprocessor expressions.  */
143 static void
144 check_flags (void)
145 {
146   switch (0)
147     {
148     case F_DUPFD:
149 #if F_DUPFD
150 #endif
151
152     case F_DUPFD_CLOEXEC:
153 #if F_DUPFD_CLOEXEC
154 #endif
155
156     case F_GETFD:
157 #if F_GETFD
158 #endif
159
160 #ifdef F_SETFD
161     case F_SETFD:
162 # if F_SETFD
163 # endif
164 #endif
165
166 #ifdef F_GETFL
167     case F_GETFL:
168 # if F_GETFL
169 # endif
170 #endif
171
172 #ifdef F_SETFL
173     case F_SETFL:
174 # if F_SETFL
175 # endif
176 #endif
177
178 #ifdef F_GETOWN
179     case F_GETOWN:
180 # if F_GETOWN
181 # endif
182 #endif
183
184 #ifdef F_SETOWN
185     case F_SETOWN:
186 # if F_SETOWN
187 # endif
188 #endif
189
190 #ifdef F_GETLK
191     case F_GETLK:
192 # if F_GETLK
193 # endif
194 #endif
195
196 #ifdef F_SETLK
197     case F_SETLK:
198 # if F_SETLK
199 # endif
200 #endif
201
202 #ifdef F_SETLKW
203     case F_SETLKW:
204 # if F_SETLKW
205 # endif
206 #endif
207
208       ;
209     }
210 }
211
212 int
213 main (void)
214 {
215   const char *file = "test-fcntl.tmp";
216   int fd;
217
218   /* Sanity check that rpl_fcntl is likely to work.  */
219   ASSERT (func2 (1, 2) == 2);
220   ASSERT (func2 (2, -2) == -2);
221   ASSERT (func2 (3, 0x80000000) == 0x80000000);
222   {
223     struct dummy_struct s = { 0L, 4 };
224     ASSERT (func2 (4, &s) == 4);
225   }
226   check_flags ();
227
228   /* Assume std descriptors were provided by invoker, and ignore fds
229      that might have been inherited.  */
230   fd = creat (file, 0600);
231   ASSERT (STDERR_FILENO < fd);
232   close (fd + 1);
233   close (fd + 2);
234
235   /* For F_DUPFD*, the source must be valid.  */
236   errno = 0;
237   ASSERT (fcntl (-1, F_DUPFD, 0) == -1);
238   ASSERT (errno == EBADF);
239   errno = 0;
240   ASSERT (fcntl (fd + 1, F_DUPFD, 0) == -1);
241   ASSERT (errno == EBADF);
242   errno = 0;
243   ASSERT (fcntl (10000000, F_DUPFD, 0) == -1);
244   ASSERT (errno == EBADF);
245   errno = 0;
246   ASSERT (fcntl (-1, F_DUPFD_CLOEXEC, 0) == -1);
247   ASSERT (errno == EBADF);
248   errno = 0;
249   ASSERT (fcntl (fd + 1, F_DUPFD_CLOEXEC, 0) == -1);
250   ASSERT (errno == EBADF);
251   errno = 0;
252   ASSERT (fcntl (10000000, F_DUPFD_CLOEXEC, 0) == -1);
253   ASSERT (errno == EBADF);
254
255   /* For F_DUPFD*, the destination must be valid.  */
256   ASSERT (getdtablesize () < 10000000);
257   errno = 0;
258   ASSERT (fcntl (fd, F_DUPFD, -1) == -1);
259   ASSERT (errno == EINVAL);
260   errno = 0;
261   ASSERT (fcntl (fd, F_DUPFD, 10000000) == -1);
262   ASSERT (errno == EINVAL);
263   ASSERT (getdtablesize () < 10000000);
264   errno = 0;
265   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, -1) == -1);
266   ASSERT (errno == EINVAL);
267   errno = 0;
268   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, 10000000) == -1);
269   ASSERT (errno == EINVAL);
270
271   /* For F_DUPFD*, check for correct inheritance, as well as
272      preservation of text vs. binary.  */
273   setmode (fd, O_BINARY);
274   ASSERT (is_open (fd));
275   ASSERT (!is_open (fd + 1));
276   ASSERT (!is_open (fd + 2));
277   ASSERT (is_inheritable (fd));
278   ASSERT (is_mode (fd, O_BINARY));
279
280   ASSERT (fcntl (fd, F_DUPFD, fd) == fd + 1);
281   ASSERT (is_open (fd));
282   ASSERT (is_open (fd + 1));
283   ASSERT (!is_open (fd + 2));
284   ASSERT (is_inheritable (fd + 1));
285   ASSERT (is_mode (fd, O_BINARY));
286   ASSERT (is_mode (fd + 1, O_BINARY));
287   ASSERT (close (fd + 1) == 0);
288
289   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, fd + 2) == fd + 2);
290   ASSERT (is_open (fd));
291   ASSERT (!is_open (fd + 1));
292   ASSERT (is_open (fd + 2));
293   ASSERT (is_inheritable (fd));
294   ASSERT (!is_inheritable (fd + 2));
295   ASSERT (is_mode (fd, O_BINARY));
296   ASSERT (is_mode (fd + 2, O_BINARY));
297   ASSERT (close (fd) == 0);
298
299   setmode (fd + 2, O_TEXT);
300   ASSERT (fcntl (fd + 2, F_DUPFD, fd + 1) == fd + 1);
301   ASSERT (!is_open (fd));
302   ASSERT (is_open (fd + 1));
303   ASSERT (is_open (fd + 2));
304   ASSERT (is_inheritable (fd + 1));
305   ASSERT (!is_inheritable (fd + 2));
306   ASSERT (is_mode (fd + 1, O_TEXT));
307   ASSERT (is_mode (fd + 2, O_TEXT));
308   ASSERT (close (fd + 1) == 0);
309
310   ASSERT (fcntl (fd + 2, F_DUPFD_CLOEXEC, 0) == fd);
311   ASSERT (is_open (fd));
312   ASSERT (!is_open (fd + 1));
313   ASSERT (is_open (fd + 2));
314   ASSERT (!is_inheritable (fd));
315   ASSERT (!is_inheritable (fd + 2));
316   ASSERT (is_mode (fd, O_TEXT));
317   ASSERT (is_mode (fd + 2, O_TEXT));
318   ASSERT (close (fd + 2) == 0);
319
320   /* Test F_GETFD.  */
321   errno = 0;
322   ASSERT (fcntl (-1, F_GETFD) == -1);
323   ASSERT (errno == EBADF);
324   errno = 0;
325   ASSERT (fcntl (fd + 1, F_GETFD) == -1);
326   ASSERT (errno == EBADF);
327   errno = 0;
328   ASSERT (fcntl (10000000, F_GETFD) == -1);
329   ASSERT (errno == EBADF);
330   {
331     int result = fcntl (fd, F_GETFD);
332     ASSERT (0 <= result);
333     ASSERT ((result & FD_CLOEXEC) == FD_CLOEXEC);
334     ASSERT (dup (fd) == fd + 1);
335     result = fcntl (fd + 1, F_GETFD);
336     ASSERT (0 <= result);
337     ASSERT ((result & FD_CLOEXEC) == 0);
338     ASSERT (close (fd + 1) == 0);
339   }
340
341   /* Cleanup.  */
342   ASSERT (close (fd) == 0);
343   ASSERT (unlink (file) == 0);
344
345   return 0;
346 }