1 /* Tests for support_open_dev_null_range.
2    Copyright (C) 2021 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 <dirent.h>
21 #include <fcntl.h>
22 #include <limits.h>
23 #include <support/check.h>
24 #include <support/support.h>
25 #include <support/xunistd.h>
26 #include <sys/resource.h>
27 #include <stdlib.h>
28 
29 #ifndef PATH_MAX
30 # define PATH_MAX 1024
31 #endif
32 
33 #include <stdio.h>
34 
35 static void
check_path(int fd)36 check_path (int fd)
37 {
38   char *proc_fd_path = xasprintf ("/proc/self/fd/%d", fd);
39   char file_path[PATH_MAX];
40   ssize_t file_path_length
41     = readlink (proc_fd_path, file_path, sizeof (file_path));
42   free (proc_fd_path);
43   if (file_path_length < 0)
44     FAIL_EXIT1 ("readlink (%s, %p, %zu)", proc_fd_path, file_path,
45 		sizeof (file_path));
46   file_path[file_path_length] = '\0';
47   TEST_COMPARE_STRING (file_path, "/dev/null");
48 }
49 
50 static int
number_of_opened_files(void)51 number_of_opened_files (void)
52 {
53   DIR *fds = opendir ("/proc/self/fd");
54   if (fds == NULL)
55     FAIL_EXIT1 ("opendir (\"/proc/self/fd\"): %m");
56 
57   int r = 0;
58   while (true)
59     {
60       errno = 0;
61       struct dirent64 *e = readdir64 (fds);
62       if (e == NULL)
63         {
64           if (errno != 0)
65             FAIL_EXIT1 ("readdir: %m");
66           break;
67         }
68 
69       if (e->d_name[0] == '.')
70         continue;
71 
72       char *endptr;
73       long int fd = strtol (e->d_name, &endptr, 10);
74       if (*endptr != '\0' || fd < 0 || fd > INT_MAX)
75         FAIL_EXIT1 ("readdir: invalid file descriptor name: /proc/self/fd/%s",
76                     e->d_name);
77 
78       /* Skip the descriptor which is used to enumerate the
79          descriptors.  */
80       if (fd == dirfd (fds))
81         continue;
82 
83       r = r + 1;
84     }
85 
86   closedir (fds);
87 
88   return r;
89 }
90 
91 static int
do_test(void)92 do_test (void)
93 {
94   const int nfds1 = 8;
95   int lowfd = support_open_dev_null_range (nfds1, O_RDONLY, 0600);
96   for (int i = 0; i < nfds1; i++)
97     {
98       TEST_VERIFY (fcntl (lowfd + i, F_GETFL) > -1);
99       check_path (lowfd + i);
100     }
101 
102   /* create some gaps.  */
103   xclose (lowfd + 1);
104   xclose (lowfd + 5);
105   xclose (lowfd + 6);
106 
107   const int nfds2 = 16;
108   int lowfd2 = support_open_dev_null_range (nfds2, O_RDONLY, 0600);
109   for (int i = 0; i < nfds2; i++)
110     {
111       TEST_VERIFY (fcntl (lowfd2 + i, F_GETFL) > -1);
112       check_path (lowfd2 + i);
113     }
114 
115   /* Decrease the maximum number of files.  */
116   {
117     struct rlimit rl;
118     if (getrlimit (RLIMIT_NOFILE, &rl) == -1)
119       FAIL_EXIT1 ("getrlimit (RLIMIT_NOFILE): %m");
120 
121     rl.rlim_cur = number_of_opened_files ();
122 
123     if (setrlimit (RLIMIT_NOFILE, &rl) == 1)
124       FAIL_EXIT1 ("setrlimit (RLIMIT_NOFILE): %m");
125   }
126 
127   const int nfds3 = 16;
128   int lowfd3 = support_open_dev_null_range (nfds3, O_RDONLY, 0600);
129   for (int i = 0; i < nfds3; i++)
130     {
131       TEST_VERIFY (fcntl (lowfd3 + i, F_GETFL) > -1);
132       check_path (lowfd3 + i);
133     }
134 
135   /* create a lot of gaps to trigger the range extension.  */
136   xclose (lowfd3 + 1);
137   xclose (lowfd3 + 3);
138   xclose (lowfd3 + 5);
139   xclose (lowfd3 + 7);
140   xclose (lowfd3 + 9);
141   xclose (lowfd3 + 11);
142   xclose (lowfd3 + 13);
143 
144   const int nfds4 = 16;
145   int lowfd4 = support_open_dev_null_range (nfds4, O_RDONLY, 0600);
146   for (int i = 0; i < nfds4; i++)
147     {
148       TEST_VERIFY (fcntl (lowfd4 + i, F_GETFL) > -1);
149       check_path (lowfd4 + i);
150     }
151 
152   return 0;
153 }
154 
155 #include <support/test-driver.c>
156