linux/tools/testing/selftests/proc/fd-001-lookup.c
<<
>>
Prefs
   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}
 169