8df733a70bfeeb85d56de8e87e3a8dc0e6d31459
[gnulib.git] / tests / test-cloexec.c
1 /* Test duplicating non-inheritable file descriptors.
2    Copyright (C) 2009 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 #include "cloexec.h"
22
23 #include <errno.h>
24 #include <fcntl.h>
25 #include <stdio.h>
26 #include <stdlib.h>
27 #include <unistd.h>
28
29 #if (defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__
30 /* Get declarations of the Win32 API functions.  */
31 # define WIN32_LEAN_AND_MEAN
32 # include <windows.h>
33 #endif
34
35 #define ASSERT(expr) \
36   do                                                                         \
37     {                                                                        \
38       if (!(expr))                                                           \
39         {                                                                    \
40           fprintf (stderr, "%s:%d: assertion failed\n", __FILE__, __LINE__); \
41           fflush (stderr);                                                   \
42           abort ();                                                          \
43         }                                                                    \
44     }                                                                        \
45   while (0)
46
47 /* Return non-zero if FD is open and inheritable across exec/spawn.  */
48 static int
49 is_inheritable (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   HANDLE h = (HANDLE) _get_osfhandle (fd);
56   DWORD flags;
57   if (h == INVALID_HANDLE_VALUE || GetHandleInformation (h, &flags) == 0)
58     return 0;
59   return (flags & HANDLE_FLAG_INHERIT) != 0;
60 #else
61 # ifndef F_GETFD
62 #  error Please port fcntl to your platform
63 # endif
64   int i = fcntl (fd, F_GETFD);
65   return 0 <= i && (i & FD_CLOEXEC) == 0;
66 #endif
67 }
68
69 int
70 main (void)
71 {
72   const char *file = "test-cloexec.tmp";
73   int fd = creat (file, 0600);
74   int fd2;
75
76   /* Assume std descriptors were provided by invoker.  */
77   ASSERT (STDERR_FILENO < fd);
78   ASSERT (is_inheritable (fd));
79
80   /* Normal use of set_cloexec_flag.  */
81   ASSERT (set_cloexec_flag (fd, true) == 0);
82 #if !((defined _WIN32 || defined __WIN32__) && ! defined __CYGWIN__)
83   ASSERT (!is_inheritable (fd));
84 #endif
85   ASSERT (set_cloexec_flag (fd, false) == 0);
86   ASSERT (is_inheritable (fd));
87
88   /* Normal use of dup_cloexec.  */
89   fd2 = dup_cloexec (fd);
90   ASSERT (fd < fd2);
91   ASSERT (!is_inheritable (fd2));
92   ASSERT (close (fd) == 0);
93   ASSERT (dup_cloexec (fd2) == fd);
94   ASSERT (!is_inheritable (fd));
95   ASSERT (close (fd2) == 0);
96
97   /* Test error handling.  */
98   errno = 0;
99   ASSERT (set_cloexec_flag (-1, false) == -1);
100   ASSERT (errno == EBADF);
101   errno = 0;
102   ASSERT (set_cloexec_flag (10000000, false) == -1);
103   ASSERT (errno == EBADF);
104   errno = 0;
105   ASSERT (set_cloexec_flag (fd2, false) == -1);
106   ASSERT (errno == EBADF);
107   errno = 0;
108   ASSERT (dup_cloexec (-1) == -1);
109   ASSERT (errno == EBADF);
110   errno = 0;
111   ASSERT (dup_cloexec (10000000) == -1);
112   ASSERT (errno == EBADF);
113   errno = 0;
114   ASSERT (dup_cloexec (fd2) == -1);
115   ASSERT (errno == EBADF);
116
117   /* Clean up.  */
118   ASSERT (close (fd) == 0);
119   ASSERT (unlink (file) == 0);
120
121   return 0;
122 }