Back to home page

OSCL-LXR

 
 

    


0001 /*
0002  * Copyright © 2018 Alexey Dobriyan <adobriyan@gmail.com>
0003  *
0004  * Permission to use, copy, modify, and distribute this software for any
0005  * purpose with or without fee is hereby granted, provided that the above
0006  * copyright notice and this permission notice appear in all copies.
0007  *
0008  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
0009  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
0010  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
0011  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
0012  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
0013  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
0014  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
0015  */
0016 // Test /proc/*/fd lookup.
0017 
0018 #undef NDEBUG
0019 #include <assert.h>
0020 #include <dirent.h>
0021 #include <errno.h>
0022 #include <limits.h>
0023 #include <sched.h>
0024 #include <stdio.h>
0025 #include <unistd.h>
0026 #include <sys/types.h>
0027 #include <sys/stat.h>
0028 #include <fcntl.h>
0029 
0030 #include "proc.h"
0031 
0032 /* lstat(2) has more "coverage" in case non-symlink pops up somehow. */
0033 static void test_lookup_pass(const char *pathname)
0034 {
0035     struct stat st;
0036     ssize_t rv;
0037 
0038     memset(&st, 0, sizeof(struct stat));
0039     rv = lstat(pathname, &st);
0040     assert(rv == 0);
0041     assert(S_ISLNK(st.st_mode));
0042 }
0043 
0044 static void test_lookup_fail(const char *pathname)
0045 {
0046     struct stat st;
0047     ssize_t rv;
0048 
0049     rv = lstat(pathname, &st);
0050     assert(rv == -1 && errno == ENOENT);
0051 }
0052 
0053 static void test_lookup(unsigned int fd)
0054 {
0055     char buf[64];
0056     unsigned int c;
0057     unsigned int u;
0058     int i;
0059 
0060     snprintf(buf, sizeof(buf), "/proc/self/fd/%u", fd);
0061     test_lookup_pass(buf);
0062 
0063     /* leading junk */
0064     for (c = 1; c <= 255; c++) {
0065         if (c == '/')
0066             continue;
0067         snprintf(buf, sizeof(buf), "/proc/self/fd/%c%u", c, fd);
0068         test_lookup_fail(buf);
0069     }
0070 
0071     /* trailing junk */
0072     for (c = 1; c <= 255; c++) {
0073         if (c == '/')
0074             continue;
0075         snprintf(buf, sizeof(buf), "/proc/self/fd/%u%c", fd, c);
0076         test_lookup_fail(buf);
0077     }
0078 
0079     for (i = INT_MIN; i < INT_MIN + 1024; i++) {
0080         snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
0081         test_lookup_fail(buf);
0082     }
0083     for (i = -1024; i < 0; i++) {
0084         snprintf(buf, sizeof(buf), "/proc/self/fd/%d", i);
0085         test_lookup_fail(buf);
0086     }
0087     for (u = INT_MAX - 1024; u <= (unsigned int)INT_MAX + 1024; u++) {
0088         snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
0089         test_lookup_fail(buf);
0090     }
0091     for (u = UINT_MAX - 1024; u != 0; u++) {
0092         snprintf(buf, sizeof(buf), "/proc/self/fd/%u", u);
0093         test_lookup_fail(buf);
0094     }
0095 
0096 
0097 }
0098 
0099 int main(void)
0100 {
0101     struct dirent *de;
0102     unsigned int fd, target_fd;
0103 
0104     if (unshare(CLONE_FILES) == -1)
0105         return 1;
0106 
0107     /* Wipe fdtable. */
0108     do {
0109         DIR *d;
0110 
0111         d = opendir("/proc/self/fd");
0112         if (!d)
0113             return 1;
0114 
0115         de = xreaddir(d);
0116         assert(de->d_type == DT_DIR);
0117         assert(streq(de->d_name, "."));
0118 
0119         de = xreaddir(d);
0120         assert(de->d_type == DT_DIR);
0121         assert(streq(de->d_name, ".."));
0122 next:
0123         de = xreaddir(d);
0124         if (de) {
0125             unsigned long long fd_ull;
0126             unsigned int fd;
0127             char *end;
0128 
0129             assert(de->d_type == DT_LNK);
0130 
0131             fd_ull = xstrtoull(de->d_name, &end);
0132             assert(*end == '\0');
0133             assert(fd_ull == (unsigned int)fd_ull);
0134 
0135             fd = fd_ull;
0136             if (fd == dirfd(d))
0137                 goto next;
0138             close(fd);
0139         }
0140 
0141         closedir(d);
0142     } while (de);
0143 
0144     /* Now fdtable is clean. */
0145 
0146     fd = open("/", O_PATH|O_DIRECTORY);
0147     assert(fd == 0);
0148     test_lookup(fd);
0149     close(fd);
0150 
0151     /* Clean again! */
0152 
0153     fd = open("/", O_PATH|O_DIRECTORY);
0154     assert(fd == 0);
0155     /* Default RLIMIT_NOFILE-1 */
0156     target_fd = 1023;
0157     while (target_fd > 0) {
0158         if (dup2(fd, target_fd) == target_fd)
0159             break;
0160         target_fd /= 2;
0161     }
0162     assert(target_fd > 0);
0163     close(fd);
0164     test_lookup(target_fd);
0165     close(target_fd);
0166 
0167     return 0;
0168 }