linux/tools/testing/selftests/proc/read.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
  17// 1) read and lseek on every file in /proc
  18// 2) readlink of every symlink in /proc
  19// 3) recursively (1) + (2) for every directory in /proc
  20// 4) write to /proc/*/clear_refs and /proc/*/task/*/clear_refs
  21// 5) write to /proc/sysrq-trigger
  22#undef NDEBUG
  23#include <assert.h>
  24#include <errno.h>
  25#include <sys/types.h>
  26#include <dirent.h>
  27#include <stdbool.h>
  28#include <stdlib.h>
  29#include <stdio.h>
  30#include <string.h>
  31#include <sys/stat.h>
  32#include <sys/vfs.h>
  33#include <fcntl.h>
  34#include <unistd.h>
  35
  36#include "proc.h"
  37
  38static void f_reg(DIR *d, const char *filename)
  39{
  40        char buf[4096];
  41        int fd;
  42        ssize_t rv;
  43
  44        /* read from /proc/kmsg can block */
  45        fd = openat(dirfd(d), filename, O_RDONLY|O_NONBLOCK);
  46        if (fd == -1)
  47                return;
  48        /* struct proc_ops::proc_lseek is mandatory if file is seekable. */
  49        (void)lseek(fd, 0, SEEK_SET);
  50        rv = read(fd, buf, sizeof(buf));
  51        assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
  52        close(fd);
  53}
  54
  55static void f_reg_write(DIR *d, const char *filename, const char *buf, size_t len)
  56{
  57        int fd;
  58        ssize_t rv;
  59
  60        fd = openat(dirfd(d), filename, O_WRONLY);
  61        if (fd == -1)
  62                return;
  63        rv = write(fd, buf, len);
  64        assert((0 <= rv && rv <= len) || rv == -1);
  65        close(fd);
  66}
  67
  68static void f_lnk(DIR *d, const char *filename)
  69{
  70        char buf[4096];
  71        ssize_t rv;
  72
  73        rv = readlinkat(dirfd(d), filename, buf, sizeof(buf));
  74        assert((0 <= rv && rv <= sizeof(buf)) || rv == -1);
  75}
  76
  77static void f(DIR *d, unsigned int level)
  78{
  79        struct dirent *de;
  80
  81        de = xreaddir(d);
  82        assert(de->d_type == DT_DIR);
  83        assert(streq(de->d_name, "."));
  84
  85        de = xreaddir(d);
  86        assert(de->d_type == DT_DIR);
  87        assert(streq(de->d_name, ".."));
  88
  89        while ((de = xreaddir(d))) {
  90                assert(!streq(de->d_name, "."));
  91                assert(!streq(de->d_name, ".."));
  92
  93                switch (de->d_type) {
  94                        DIR *dd;
  95                        int fd;
  96
  97                case DT_REG:
  98                        if (level == 0 && streq(de->d_name, "sysrq-trigger")) {
  99                                f_reg_write(d, de->d_name, "h", 1);
 100                        } else if (level == 1 && streq(de->d_name, "clear_refs")) {
 101                                f_reg_write(d, de->d_name, "1", 1);
 102                        } else if (level == 3 && streq(de->d_name, "clear_refs")) {
 103                                f_reg_write(d, de->d_name, "1", 1);
 104                        } else {
 105                                f_reg(d, de->d_name);
 106                        }
 107                        break;
 108                case DT_DIR:
 109                        fd = openat(dirfd(d), de->d_name, O_DIRECTORY|O_RDONLY);
 110                        if (fd == -1)
 111                                continue;
 112                        dd = fdopendir(fd);
 113                        if (!dd)
 114                                continue;
 115                        f(dd, level + 1);
 116                        closedir(dd);
 117                        break;
 118                case DT_LNK:
 119                        f_lnk(d, de->d_name);
 120                        break;
 121                default:
 122                        assert(0);
 123                }
 124        }
 125}
 126
 127int main(void)
 128{
 129        DIR *d;
 130        struct statfs sfs;
 131
 132        d = opendir("/proc");
 133        if (!d)
 134                return 4;
 135
 136        /* Ensure /proc is proc. */
 137        if (fstatfs(dirfd(d), &sfs) == -1) {
 138                return 1;
 139        }
 140        if (sfs.f_type != 0x9fa0) {
 141                fprintf(stderr, "error: unexpected f_type %lx\n", (long)sfs.f_type);
 142                return 2;
 143        }
 144
 145        f(d, 0);
 146
 147        return 0;
 148}
 149