update NEWS.stable
[gnulib.git] / tests / test-fcntl.c
1 /* Test of fcntl(2).
2    Copyright (C) 2009-2011 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 #if !O_BINARY
43 # define setmode(f,m) zero ()
44 static int zero (void) { return 0; }
45 #endif
46
47 /* Return true if FD is open.  */
48 static bool
49 is_open (int fd)
50 {
51 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
52   /* On Win32, the initial state of unassigned standard file
53      descriptors is that they are open but point to an
54      INVALID_HANDLE_VALUE, and there is no fcntl.  */
55   return (HANDLE) _get_osfhandle (fd) != INVALID_HANDLE_VALUE;
56 #else
57 # ifndef F_GETFL
58 #  error Please port fcntl to your platform
59 # endif
60   return 0 <= fcntl (fd, F_GETFL);
61 #endif
62 }
63
64 /* Return true if FD is open and inheritable across exec/spawn.  */
65 static bool
66 is_inheritable (int fd)
67 {
68 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
69   /* On Win32, the initial state of unassigned standard file
70      descriptors is that they are open but point to an
71      INVALID_HANDLE_VALUE, and there is no fcntl.  */
72   HANDLE h = (HANDLE) _get_osfhandle (fd);
73   DWORD flags;
74   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
75     return false;
76   return (flags & HANDLE_FLAG_INHERIT) != 0;
77 #else
78 # ifndef F_GETFD
79 #  error Please port fcntl to your platform
80 # endif
81   int i = fcntl (fd, F_GETFD);
82   return 0 <= i && (i & FD_CLOEXEC) == 0;
83 #endif
84 }
85
86 /* Return non-zero if FD is open in the given MODE, which is either
87    O_TEXT or O_BINARY.  */
88 static bool
89 is_mode (int fd, int mode)
90 {
91   int value = setmode (fd, O_BINARY);
92   setmode (fd, value);
93   return mode == value;
94 }
95
96 /* Since native fcntl can have more supported operations than our
97    replacement is aware of, and since various operations assign
98    different types to the vararg argument, a wrapper around fcntl must
99    be able to pass a vararg of unknown type on through to the original
100    fcntl.  Make sure that this works properly: func1 behaves like the
101    original fcntl interpreting the vararg as an int or a pointer to a
102    struct, and func2 behaves like rpl_fcntl that doesn't know what
103    type to forward.  */
104 struct dummy_struct
105 {
106   long filler;
107   int value;
108 };
109 static int
110 func1 (int a, ...)
111 {
112   va_list arg;
113   int i;
114   va_start (arg, a);
115   if (a < 4)
116     i = va_arg (arg, int);
117   else
118     {
119       struct dummy_struct *s = va_arg (arg, struct dummy_struct *);
120       i = s->value;
121     }
122   va_end (arg);
123   return i;
124 }
125 static int
126 func2 (int a, ...)
127 {
128   va_list arg;
129   void *p;
130   va_start (arg, a);
131   p = va_arg (arg, void *);
132   va_end (arg);
133   return func1 (a, p);
134 }
135
136 /* Ensure that all supported fcntl actions are distinct, and
137    usable in preprocessor expressions.  */
138 static void
139 check_flags (void)
140 {
141   switch (0)
142     {
143     case F_DUPFD:
144 #if F_DUPFD
145 #endif
146
147     case F_DUPFD_CLOEXEC:
148 #if F_DUPFD_CLOEXEC
149 #endif
150
151     case F_GETFD:
152 #if F_GETFD
153 #endif
154
155 #ifdef F_SETFD
156     case F_SETFD:
157 # if F_SETFD
158 # endif
159 #endif
160
161 #ifdef F_GETFL
162     case F_GETFL:
163 # if F_GETFL
164 # endif
165 #endif
166
167 #ifdef F_SETFL
168     case F_SETFL:
169 # if F_SETFL
170 # endif
171 #endif
172
173 #ifdef F_GETOWN
174     case F_GETOWN:
175 # if F_GETOWN
176 # endif
177 #endif
178
179 #ifdef F_SETOWN
180     case F_SETOWN:
181 # if F_SETOWN
182 # endif
183 #endif
184
185 #ifdef F_GETLK
186     case F_GETLK:
187 # if F_GETLK
188 # endif
189 #endif
190
191 #ifdef F_SETLK
192     case F_SETLK:
193 # if F_SETLK
194 # endif
195 #endif
196
197 #ifdef F_SETLKW
198     case F_SETLKW:
199 # if F_SETLKW
200 # endif
201 #endif
202
203       ;
204     }
205 }
206
207 int
208 main (void)
209 {
210   const char *file = "test-fcntl.tmp";
211   int fd;
212
213   /* Sanity check that rpl_fcntl is likely to work.  */
214   ASSERT (func2 (1, 2) == 2);
215   ASSERT (func2 (2, -2) == -2);
216   ASSERT (func2 (3, 0x80000000) == 0x80000000);
217   {
218     struct dummy_struct s = { 0L, 4 };
219     ASSERT (func2 (4, &s) == 4);
220   }
221   check_flags ();
222
223   /* Assume std descriptors were provided by invoker, and ignore fds
224      that might have been inherited.  */
225   fd = creat (file, 0600);
226   ASSERT (STDERR_FILENO < fd);
227   close (fd + 1);
228   close (fd + 2);
229
230   /* For F_DUPFD*, the source must be valid.  */
231   errno = 0;
232   ASSERT (fcntl (-1, F_DUPFD, 0) == -1);
233   ASSERT (errno == EBADF);
234   errno = 0;
235   ASSERT (fcntl (fd + 1, F_DUPFD, 0) == -1);
236   ASSERT (errno == EBADF);
237   errno = 0;
238   ASSERT (fcntl (10000000, F_DUPFD, 0) == -1);
239   ASSERT (errno == EBADF);
240   errno = 0;
241   ASSERT (fcntl (-1, F_DUPFD_CLOEXEC, 0) == -1);
242   ASSERT (errno == EBADF);
243   errno = 0;
244   ASSERT (fcntl (fd + 1, F_DUPFD_CLOEXEC, 0) == -1);
245   ASSERT (errno == EBADF);
246   errno = 0;
247   ASSERT (fcntl (10000000, F_DUPFD_CLOEXEC, 0) == -1);
248   ASSERT (errno == EBADF);
249
250   /* For F_DUPFD*, the destination must be valid.  */
251   ASSERT (getdtablesize () < 10000000);
252   errno = 0;
253   ASSERT (fcntl (fd, F_DUPFD, -1) == -1);
254   ASSERT (errno == EINVAL);
255   errno = 0;
256   ASSERT (fcntl (fd, F_DUPFD, 10000000) == -1);
257   ASSERT (errno == EINVAL);
258   ASSERT (getdtablesize () < 10000000);
259   errno = 0;
260   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, -1) == -1);
261   ASSERT (errno == EINVAL);
262   errno = 0;
263   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, 10000000) == -1);
264   ASSERT (errno == EINVAL);
265
266   /* For F_DUPFD*, check for correct inheritance, as well as
267      preservation of text vs. binary.  */
268   setmode (fd, O_BINARY);
269   ASSERT (is_open (fd));
270   ASSERT (!is_open (fd + 1));
271   ASSERT (!is_open (fd + 2));
272   ASSERT (is_inheritable (fd));
273   ASSERT (is_mode (fd, O_BINARY));
274
275   ASSERT (fcntl (fd, F_DUPFD, fd) == fd + 1);
276   ASSERT (is_open (fd));
277   ASSERT (is_open (fd + 1));
278   ASSERT (!is_open (fd + 2));
279   ASSERT (is_inheritable (fd + 1));
280   ASSERT (is_mode (fd, O_BINARY));
281   ASSERT (is_mode (fd + 1, O_BINARY));
282   ASSERT (close (fd + 1) == 0);
283
284   ASSERT (fcntl (fd, F_DUPFD_CLOEXEC, fd + 2) == fd + 2);
285   ASSERT (is_open (fd));
286   ASSERT (!is_open (fd + 1));
287   ASSERT (is_open (fd + 2));
288   ASSERT (is_inheritable (fd));
289   ASSERT (!is_inheritable (fd + 2));
290   ASSERT (is_mode (fd, O_BINARY));
291   ASSERT (is_mode (fd + 2, O_BINARY));
292   ASSERT (close (fd) == 0);
293
294   setmode (fd + 2, O_TEXT);
295   ASSERT (fcntl (fd + 2, F_DUPFD, fd + 1) == fd + 1);
296   ASSERT (!is_open (fd));
297   ASSERT (is_open (fd + 1));
298   ASSERT (is_open (fd + 2));
299   ASSERT (is_inheritable (fd + 1));
300   ASSERT (!is_inheritable (fd + 2));
301   ASSERT (is_mode (fd + 1, O_TEXT));
302   ASSERT (is_mode (fd + 2, O_TEXT));
303   ASSERT (close (fd + 1) == 0);
304
305   ASSERT (fcntl (fd + 2, F_DUPFD_CLOEXEC, 0) == fd);
306   ASSERT (is_open (fd));
307   ASSERT (!is_open (fd + 1));
308   ASSERT (is_open (fd + 2));
309   ASSERT (!is_inheritable (fd));
310   ASSERT (!is_inheritable (fd + 2));
311   ASSERT (is_mode (fd, O_TEXT));
312   ASSERT (is_mode (fd + 2, O_TEXT));
313   ASSERT (close (fd + 2) == 0);
314
315   /* Test F_GETFD.  */
316   errno = 0;
317   ASSERT (fcntl (-1, F_GETFD) == -1);
318   ASSERT (errno == EBADF);
319   errno = 0;
320   ASSERT (fcntl (fd + 1, F_GETFD) == -1);
321   ASSERT (errno == EBADF);
322   errno = 0;
323   ASSERT (fcntl (10000000, F_GETFD) == -1);
324   ASSERT (errno == EBADF);
325   {
326     int result = fcntl (fd, F_GETFD);
327     ASSERT (0 <= result);
328     ASSERT ((result & FD_CLOEXEC) == FD_CLOEXEC);
329     ASSERT (dup (fd) == fd + 1);
330     result = fcntl (fd + 1, F_GETFD);
331     ASSERT (0 <= result);
332     ASSERT ((result & FD_CLOEXEC) == 0);
333     ASSERT (close (fd + 1) == 0);
334   }
335
336   /* Cleanup.  */
337   ASSERT (close (fd) == 0);
338   ASSERT (unlink (file) == 0);
339
340   return 0;
341 }