1 /* Smoke test for the closefrom.
2    Copyright (C) 2021-2022 Free Software Foundation, Inc.
3    This file is part of the GNU C Library.
4 
5    The GNU C Library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9 
10    The GNU C Library is distributed in the hope that it will be useful,
11    but WITHOUT ANY WARRANTY; without even the implied warranty of
12    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13    Lesser General Public License for more details.
14 
15    You should have received a copy of the GNU Lesser General Public
16    License along with the GNU C Library; if not, see
17    <https://www.gnu.org/licenses/>.  */
18 
19 #include <errno.h>
20 #include <fcntl.h>
21 #include <sys/resource.h>
22 #include <unistd.h>
23 
24 #include <support/check.h>
25 #include <support/descriptors.h>
26 #include <support/xunistd.h>
27 #include <support/support.h>
28 
29 #include <array_length.h>
30 
31 #define NFDS 100
32 
33 static int
closefrom_test(void)34 closefrom_test (void)
35 {
36   struct support_descriptors *descrs = support_descriptors_list ();
37 
38   int lowfd = support_open_dev_null_range (NFDS, O_RDONLY, 0600);
39 
40   const int maximum_fd = lowfd + NFDS - 1;
41   const int half_fd = lowfd + NFDS / 2;
42   const int gap = lowfd + NFDS / 4;
43 
44   /* Close half of the descriptors and check result.  */
45   closefrom (half_fd);
46 
47   for (int i = half_fd; i <= maximum_fd; i++)
48     {
49       TEST_COMPARE (fcntl (i, F_GETFL), -1);
50       TEST_COMPARE (errno, EBADF);
51     }
52   for (int i = lowfd; i < half_fd; i++)
53     TEST_VERIFY (fcntl (i, F_GETFL) > -1);
54 
55   /* Create some gaps, close up to a threshold, and check result.  */
56   xclose (lowfd + 35);
57   xclose (lowfd + 38);
58   xclose (lowfd + 42);
59   xclose (lowfd + 46);
60 
61   /* Close half of the descriptors and check result.  */
62   closefrom (gap);
63   for (int i = gap + 1; i < maximum_fd; i++)
64     {
65       TEST_COMPARE (fcntl (i, F_GETFL), -1);
66       TEST_COMPARE (errno, EBADF);
67     }
68   for (int i = lowfd; i < gap; i++)
69     TEST_VERIFY (fcntl (i, F_GETFL) > -1);
70 
71   /* Close the remmaining but the last one.  */
72   closefrom (lowfd + 1);
73   for (int i = lowfd + 1; i <= maximum_fd; i++)
74     {
75       TEST_COMPARE (fcntl (i, F_GETFL), -1);
76       TEST_COMPARE (errno, EBADF);
77     }
78   TEST_VERIFY (fcntl (lowfd, F_GETFL) > -1);
79 
80   /* Close the last one.  */
81   closefrom (lowfd);
82   TEST_COMPARE (fcntl (lowfd, F_GETFL), -1);
83   TEST_COMPARE (errno, EBADF);
84 
85   /* Double check by check the /proc.  */
86   support_descriptors_check (descrs);
87   support_descriptors_free (descrs);
88 
89   return 0;
90 }
91 
92 /* Check if closefrom works even when no new file descriptors can be
93    created.  */
94 static int
closefrom_test_file_desc_limit(void)95 closefrom_test_file_desc_limit (void)
96 {
97   int max_fd = NFDS;
98   {
99     struct rlimit rl;
100     if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
101       FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
102 
103     max_fd = (rl.rlim_cur < max_fd ? rl.rlim_cur : max_fd);
104     rl.rlim_cur = max_fd;
105 
106     if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
107       FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
108   }
109 
110   /* Exhauste the file descriptor limit.  */
111   int lowfd = xopen ("/dev/null", O_RDONLY, 0600);
112   for (;;)
113     {
114       int fd = open ("/dev/null", O_RDONLY, 0600);
115       if (fd == -1)
116 	{
117 	  if (errno != EMFILE)
118 	    FAIL_EXIT1 ("open: %m");
119 	  break;
120 	}
121       TEST_VERIFY_EXIT (fd < max_fd);
122     }
123 
124   closefrom (lowfd);
125   for (int i = lowfd; i < NFDS; i++)
126     {
127       TEST_COMPARE (fcntl (i, F_GETFL), -1);
128       TEST_COMPARE (errno, EBADF);
129     }
130 
131   return 0;
132 }
133 
134 static int
do_test(void)135 do_test (void)
136 {
137   closefrom_test ();
138   closefrom_test_file_desc_limit ();
139 
140   return 0;
141 }
142 
143 #include <support/test-driver.c>
144