xref: /openbmc/linux/tools/testing/selftests/proc/fd-001-lookup.c (revision 3eb66e91a25497065c5322b1268cbc3953642227)
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