root/tools/testing/selftests/proc/fd-001-lookup.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. test_lookup_pass
  2. test_lookup_fail
  3. test_lookup
  4. main

   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. */
  33 static 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 
  44 static 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 
  53 static 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 
  99 int 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, ".."));
 122 next:
 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 }

/* [<][>][^][v][top][bottom][index][help] */