1b2f5de03SAlexey Dobriyan /*
2b2f5de03SAlexey Dobriyan * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
3b2f5de03SAlexey Dobriyan *
4b2f5de03SAlexey Dobriyan * Permission to use, copy, modify, and distribute this software for any
5b2f5de03SAlexey Dobriyan * purpose with or without fee is hereby granted, provided that the above
6b2f5de03SAlexey Dobriyan * copyright notice and this permission notice appear in all copies.
7b2f5de03SAlexey Dobriyan *
8b2f5de03SAlexey Dobriyan * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
9b2f5de03SAlexey Dobriyan * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
10b2f5de03SAlexey Dobriyan * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
11b2f5de03SAlexey Dobriyan * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
12b2f5de03SAlexey Dobriyan * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
13b2f5de03SAlexey Dobriyan * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
14b2f5de03SAlexey Dobriyan * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
15b2f5de03SAlexey Dobriyan */
16b2f5de03SAlexey Dobriyan // Test /proc/*/fd lookup.
17*0387662dSPeng Hao
18b2f5de03SAlexey Dobriyan #undef NDEBUG
19b2f5de03SAlexey Dobriyan #include <assert.h>
20b2f5de03SAlexey Dobriyan #include <dirent.h>
21b2f5de03SAlexey Dobriyan #include <errno.h>
22b2f5de03SAlexey Dobriyan #include <limits.h>
23b2f5de03SAlexey Dobriyan #include <sched.h>
24b2f5de03SAlexey Dobriyan #include <stdio.h>
25b2f5de03SAlexey Dobriyan #include <unistd.h>
26b2f5de03SAlexey Dobriyan #include <sys/types.h>
27b2f5de03SAlexey Dobriyan #include <sys/stat.h>
28b2f5de03SAlexey Dobriyan #include <fcntl.h>
29b2f5de03SAlexey Dobriyan
30b2f5de03SAlexey Dobriyan #include "proc.h"
31b2f5de03SAlexey Dobriyan
32b2f5de03SAlexey Dobriyan /* lstat(2) has more "coverage" in case non-symlink pops up somehow. */
test_lookup_pass(const char * pathname)33b2f5de03SAlexey Dobriyan static void test_lookup_pass(const char *pathname)
34b2f5de03SAlexey Dobriyan {
35b2f5de03SAlexey Dobriyan struct stat st;
36b2f5de03SAlexey Dobriyan ssize_t rv;
37b2f5de03SAlexey Dobriyan
38b2f5de03SAlexey Dobriyan memset(&st, 0, sizeof(struct stat));
39b2f5de03SAlexey Dobriyan rv = lstat(pathname, &st);
40b2f5de03SAlexey Dobriyan assert(rv == 0);
41b2f5de03SAlexey Dobriyan assert(S_ISLNK(st.st_mode));
42b2f5de03SAlexey Dobriyan }
43b2f5de03SAlexey Dobriyan
test_lookup_fail(const char * pathname)44b2f5de03SAlexey Dobriyan static void test_lookup_fail(const char *pathname)
45b2f5de03SAlexey Dobriyan {
46b2f5de03SAlexey Dobriyan struct stat st;
47b2f5de03SAlexey Dobriyan ssize_t rv;
48b2f5de03SAlexey Dobriyan
49b2f5de03SAlexey Dobriyan rv = lstat(pathname, &st);
50b2f5de03SAlexey Dobriyan assert(rv == -1 && errno == ENOENT);
51b2f5de03SAlexey Dobriyan }
52b2f5de03SAlexey Dobriyan
test_lookup(unsigned int fd)53b2f5de03SAlexey Dobriyan static void test_lookup(unsigned int fd)
54b2f5de03SAlexey Dobriyan {
55b2f5de03SAlexey Dobriyan char buf[64];
56b2f5de03SAlexey Dobriyan unsigned int c;
57b2f5de03SAlexey Dobriyan unsigned int u;
58b2f5de03SAlexey Dobriyan int i;
59b2f5de03SAlexey Dobriyan
60b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd);
61b2f5de03SAlexey Dobriyan test_lookup_pass(buf);
62b2f5de03SAlexey Dobriyan
63b2f5de03SAlexey Dobriyan /* leading junk */
64b2f5de03SAlexey Dobriyan for (c = 1; c <= 255; c++) {
65b2f5de03SAlexey Dobriyan if (c == '/')
66b2f5de03SAlexey Dobriyan continue;
67b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%c%u", c, fd);
68b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
69b2f5de03SAlexey Dobriyan }
70b2f5de03SAlexey Dobriyan
71b2f5de03SAlexey Dobriyan /* trailing junk */
72b2f5de03SAlexey Dobriyan for (c = 1; c <= 255; c++) {
73b2f5de03SAlexey Dobriyan if (c == '/')
74b2f5de03SAlexey Dobriyan continue;
75b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%u%c", fd, c);
76b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
77b2f5de03SAlexey Dobriyan }
78b2f5de03SAlexey Dobriyan
79b2f5de03SAlexey Dobriyan for (i = INT_MIN; i < INT_MIN + 1024; i++) {
80b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
81b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
82b2f5de03SAlexey Dobriyan }
83b2f5de03SAlexey Dobriyan for (i = -1024; i < 0; i++) {
84b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
85b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
86b2f5de03SAlexey Dobriyan }
87b2f5de03SAlexey Dobriyan for (u = INT_MAX - 1024; u <= (unsigned int)INT_MAX + 1024; u++) {
88b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
89b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
90b2f5de03SAlexey Dobriyan }
91b2f5de03SAlexey Dobriyan for (u = UINT_MAX - 1024; u != 0; u++) {
92b2f5de03SAlexey Dobriyan snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
93b2f5de03SAlexey Dobriyan test_lookup_fail(buf);
94b2f5de03SAlexey Dobriyan }
95b2f5de03SAlexey Dobriyan
96b2f5de03SAlexey Dobriyan
97b2f5de03SAlexey Dobriyan }
98b2f5de03SAlexey Dobriyan
main(void)99b2f5de03SAlexey Dobriyan int main(void)
100b2f5de03SAlexey Dobriyan {
101b2f5de03SAlexey Dobriyan struct dirent *de;
102b2f5de03SAlexey Dobriyan unsigned int fd, target_fd;
103b2f5de03SAlexey Dobriyan
104b2f5de03SAlexey Dobriyan if (unshare(CLONE_FILES) == -1)
105b2f5de03SAlexey Dobriyan return 1;
106b2f5de03SAlexey Dobriyan
107b2f5de03SAlexey Dobriyan /* Wipe fdtable. */
108b2f5de03SAlexey Dobriyan do {
109b2f5de03SAlexey Dobriyan DIR *d;
110b2f5de03SAlexey Dobriyan
111b2f5de03SAlexey Dobriyan d = opendir("/proc/self/fd");
112b2f5de03SAlexey Dobriyan if (!d)
113b2f5de03SAlexey Dobriyan return 1;
114b2f5de03SAlexey Dobriyan
115b2f5de03SAlexey Dobriyan de = xreaddir(d);
116b2f5de03SAlexey Dobriyan assert(de->d_type == DT_DIR);
117b2f5de03SAlexey Dobriyan assert(streq(de->d_name, "."));
118b2f5de03SAlexey Dobriyan
119b2f5de03SAlexey Dobriyan de = xreaddir(d);
120b2f5de03SAlexey Dobriyan assert(de->d_type == DT_DIR);
121b2f5de03SAlexey Dobriyan assert(streq(de->d_name, ".."));
122b2f5de03SAlexey Dobriyan next:
123b2f5de03SAlexey Dobriyan de = xreaddir(d);
124b2f5de03SAlexey Dobriyan if (de) {
125b2f5de03SAlexey Dobriyan unsigned long long fd_ull;
126b2f5de03SAlexey Dobriyan unsigned int fd;
127b2f5de03SAlexey Dobriyan char *end;
128b2f5de03SAlexey Dobriyan
129b2f5de03SAlexey Dobriyan assert(de->d_type == DT_LNK);
130b2f5de03SAlexey Dobriyan
131b2f5de03SAlexey Dobriyan fd_ull = xstrtoull(de->d_name, &end);
132b2f5de03SAlexey Dobriyan assert(*end == '\0');
133b2f5de03SAlexey Dobriyan assert(fd_ull == (unsigned int)fd_ull);
134b2f5de03SAlexey Dobriyan
135b2f5de03SAlexey Dobriyan fd = fd_ull;
136b2f5de03SAlexey Dobriyan if (fd == dirfd(d))
137b2f5de03SAlexey Dobriyan goto next;
138b2f5de03SAlexey Dobriyan close(fd);
139b2f5de03SAlexey Dobriyan }
140b2f5de03SAlexey Dobriyan
141b2f5de03SAlexey Dobriyan closedir(d);
142b2f5de03SAlexey Dobriyan } while (de);
143b2f5de03SAlexey Dobriyan
144b2f5de03SAlexey Dobriyan /* Now fdtable is clean. */
145b2f5de03SAlexey Dobriyan
146b2f5de03SAlexey Dobriyan fd = open("/", O_PATH|O_DIRECTORY);
147b2f5de03SAlexey Dobriyan assert(fd == 0);
148b2f5de03SAlexey Dobriyan test_lookup(fd);
149b2f5de03SAlexey Dobriyan close(fd);
150b2f5de03SAlexey Dobriyan
151b2f5de03SAlexey Dobriyan /* Clean again! */
152b2f5de03SAlexey Dobriyan
153b2f5de03SAlexey Dobriyan fd = open("/", O_PATH|O_DIRECTORY);
154b2f5de03SAlexey Dobriyan assert(fd == 0);
155b2f5de03SAlexey Dobriyan /* Default RLIMIT_NOFILE-1 */
156b2f5de03SAlexey Dobriyan target_fd = 1023;
157b2f5de03SAlexey Dobriyan while (target_fd > 0) {
158b2f5de03SAlexey Dobriyan if (dup2(fd, target_fd) == target_fd)
159b2f5de03SAlexey Dobriyan break;
160b2f5de03SAlexey Dobriyan target_fd /= 2;
161b2f5de03SAlexey Dobriyan }
162b2f5de03SAlexey Dobriyan assert(target_fd > 0);
163b2f5de03SAlexey Dobriyan close(fd);
164b2f5de03SAlexey Dobriyan test_lookup(target_fd);
165b2f5de03SAlexey Dobriyan close(target_fd);
166b2f5de03SAlexey Dobriyan
167b2f5de03SAlexey Dobriyan return 0;
168b2f5de03SAlexey Dobriyan }
169