Linux Audio

Check our new training course

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