linux/tools/lib/api/fs/fs.c
<<
>>
Prefs
   1#include <ctype.h>
   2#include <errno.h>
   3#include <limits.h>
   4#include <stdbool.h>
   5#include <stdio.h>
   6#include <stdlib.h>
   7#include <string.h>
   8#include <sys/vfs.h>
   9#include <sys/types.h>
  10#include <sys/stat.h>
  11#include <fcntl.h>
  12#include <unistd.h>
  13#include <sys/mount.h>
  14
  15#include "fs.h"
  16#include "debug-internal.h"
  17
  18#define _STR(x) #x
  19#define STR(x) _STR(x)
  20
  21#ifndef SYSFS_MAGIC
  22#define SYSFS_MAGIC            0x62656572
  23#endif
  24
  25#ifndef PROC_SUPER_MAGIC
  26#define PROC_SUPER_MAGIC       0x9fa0
  27#endif
  28
  29#ifndef DEBUGFS_MAGIC
  30#define DEBUGFS_MAGIC          0x64626720
  31#endif
  32
  33#ifndef TRACEFS_MAGIC
  34#define TRACEFS_MAGIC          0x74726163
  35#endif
  36
  37static const char * const sysfs__fs_known_mountpoints[] = {
  38        "/sys",
  39        0,
  40};
  41
  42static const char * const procfs__known_mountpoints[] = {
  43        "/proc",
  44        0,
  45};
  46
  47#ifndef DEBUGFS_DEFAULT_PATH
  48#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
  49#endif
  50
  51static const char * const debugfs__known_mountpoints[] = {
  52        DEBUGFS_DEFAULT_PATH,
  53        "/debug",
  54        0,
  55};
  56
  57
  58#ifndef TRACEFS_DEFAULT_PATH
  59#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
  60#endif
  61
  62static const char * const tracefs__known_mountpoints[] = {
  63        TRACEFS_DEFAULT_PATH,
  64        "/sys/kernel/debug/tracing",
  65        "/tracing",
  66        "/trace",
  67        0,
  68};
  69
  70struct fs {
  71        const char              *name;
  72        const char * const      *mounts;
  73        char                     path[PATH_MAX];
  74        bool                     found;
  75        long                     magic;
  76};
  77
  78enum {
  79        FS__SYSFS   = 0,
  80        FS__PROCFS  = 1,
  81        FS__DEBUGFS = 2,
  82        FS__TRACEFS = 3,
  83};
  84
  85#ifndef TRACEFS_MAGIC
  86#define TRACEFS_MAGIC 0x74726163
  87#endif
  88
  89static struct fs fs__entries[] = {
  90        [FS__SYSFS] = {
  91                .name   = "sysfs",
  92                .mounts = sysfs__fs_known_mountpoints,
  93                .magic  = SYSFS_MAGIC,
  94        },
  95        [FS__PROCFS] = {
  96                .name   = "proc",
  97                .mounts = procfs__known_mountpoints,
  98                .magic  = PROC_SUPER_MAGIC,
  99        },
 100        [FS__DEBUGFS] = {
 101                .name   = "debugfs",
 102                .mounts = debugfs__known_mountpoints,
 103                .magic  = DEBUGFS_MAGIC,
 104        },
 105        [FS__TRACEFS] = {
 106                .name   = "tracefs",
 107                .mounts = tracefs__known_mountpoints,
 108                .magic  = TRACEFS_MAGIC,
 109        },
 110};
 111
 112static bool fs__read_mounts(struct fs *fs)
 113{
 114        bool found = false;
 115        char type[100];
 116        FILE *fp;
 117
 118        fp = fopen("/proc/mounts", "r");
 119        if (fp == NULL)
 120                return NULL;
 121
 122        while (!found &&
 123               fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
 124                      fs->path, type) == 2) {
 125
 126                if (strcmp(type, fs->name) == 0)
 127                        found = true;
 128        }
 129
 130        fclose(fp);
 131        return fs->found = found;
 132}
 133
 134static int fs__valid_mount(const char *fs, long magic)
 135{
 136        struct statfs st_fs;
 137
 138        if (statfs(fs, &st_fs) < 0)
 139                return -ENOENT;
 140        else if ((long)st_fs.f_type != magic)
 141                return -ENOENT;
 142
 143        return 0;
 144}
 145
 146static bool fs__check_mounts(struct fs *fs)
 147{
 148        const char * const *ptr;
 149
 150        ptr = fs->mounts;
 151        while (*ptr) {
 152                if (fs__valid_mount(*ptr, fs->magic) == 0) {
 153                        fs->found = true;
 154                        strcpy(fs->path, *ptr);
 155                        return true;
 156                }
 157                ptr++;
 158        }
 159
 160        return false;
 161}
 162
 163static void mem_toupper(char *f, size_t len)
 164{
 165        while (len) {
 166                *f = toupper(*f);
 167                f++;
 168                len--;
 169        }
 170}
 171
 172/*
 173 * Check for "NAME_PATH" environment variable to override fs location (for
 174 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
 175 * for SYSFS_PATH.
 176 */
 177static bool fs__env_override(struct fs *fs)
 178{
 179        char *override_path;
 180        size_t name_len = strlen(fs->name);
 181        /* name + "_PATH" + '\0' */
 182        char upper_name[name_len + 5 + 1];
 183        memcpy(upper_name, fs->name, name_len);
 184        mem_toupper(upper_name, name_len);
 185        strcpy(&upper_name[name_len], "_PATH");
 186
 187        override_path = getenv(upper_name);
 188        if (!override_path)
 189                return false;
 190
 191        fs->found = true;
 192        strncpy(fs->path, override_path, sizeof(fs->path));
 193        return true;
 194}
 195
 196static const char *fs__get_mountpoint(struct fs *fs)
 197{
 198        if (fs__env_override(fs))
 199                return fs->path;
 200
 201        if (fs__check_mounts(fs))
 202                return fs->path;
 203
 204        if (fs__read_mounts(fs))
 205                return fs->path;
 206
 207        return NULL;
 208}
 209
 210static const char *fs__mountpoint(int idx)
 211{
 212        struct fs *fs = &fs__entries[idx];
 213
 214        if (fs->found)
 215                return (const char *)fs->path;
 216
 217        return fs__get_mountpoint(fs);
 218}
 219
 220static const char *mount_overload(struct fs *fs)
 221{
 222        size_t name_len = strlen(fs->name);
 223        /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
 224        char upper_name[5 + name_len + 12 + 1];
 225
 226        snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
 227        mem_toupper(upper_name, name_len);
 228
 229        return getenv(upper_name) ?: *fs->mounts;
 230}
 231
 232static const char *fs__mount(int idx)
 233{
 234        struct fs *fs = &fs__entries[idx];
 235        const char *mountpoint;
 236
 237        if (fs__mountpoint(idx))
 238                return (const char *)fs->path;
 239
 240        mountpoint = mount_overload(fs);
 241
 242        if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
 243                return NULL;
 244
 245        return fs__check_mounts(fs) ? fs->path : NULL;
 246}
 247
 248#define FS(name, idx)                           \
 249const char *name##__mountpoint(void)            \
 250{                                               \
 251        return fs__mountpoint(idx);             \
 252}                                               \
 253                                                \
 254const char *name##__mount(void)                 \
 255{                                               \
 256        return fs__mount(idx);                  \
 257}                                               \
 258                                                \
 259bool name##__configured(void)                   \
 260{                                               \
 261        return name##__mountpoint() != NULL;    \
 262}
 263
 264FS(sysfs,   FS__SYSFS);
 265FS(procfs,  FS__PROCFS);
 266FS(debugfs, FS__DEBUGFS);
 267FS(tracefs, FS__TRACEFS);
 268
 269int filename__read_int(const char *filename, int *value)
 270{
 271        char line[64];
 272        int fd = open(filename, O_RDONLY), err = -1;
 273
 274        if (fd < 0)
 275                return -1;
 276
 277        if (read(fd, line, sizeof(line)) > 0) {
 278                *value = atoi(line);
 279                err = 0;
 280        }
 281
 282        close(fd);
 283        return err;
 284}
 285
 286/*
 287 * Parses @value out of @filename with strtoull.
 288 * By using 0 for base, the strtoull detects the
 289 * base automatically (see man strtoull).
 290 */
 291int filename__read_ull(const char *filename, unsigned long long *value)
 292{
 293        char line[64];
 294        int fd = open(filename, O_RDONLY), err = -1;
 295
 296        if (fd < 0)
 297                return -1;
 298
 299        if (read(fd, line, sizeof(line)) > 0) {
 300                *value = strtoull(line, NULL, 0);
 301                if (*value != ULLONG_MAX)
 302                        err = 0;
 303        }
 304
 305        close(fd);
 306        return err;
 307}
 308
 309#define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
 310
 311int filename__read_str(const char *filename, char **buf, size_t *sizep)
 312{
 313        size_t size = 0, alloc_size = 0;
 314        void *bf = NULL, *nbf;
 315        int fd, n, err = 0;
 316        char sbuf[STRERR_BUFSIZE];
 317
 318        fd = open(filename, O_RDONLY);
 319        if (fd < 0)
 320                return -errno;
 321
 322        do {
 323                if (size == alloc_size) {
 324                        alloc_size += BUFSIZ;
 325                        nbf = realloc(bf, alloc_size);
 326                        if (!nbf) {
 327                                err = -ENOMEM;
 328                                break;
 329                        }
 330
 331                        bf = nbf;
 332                }
 333
 334                n = read(fd, bf + size, alloc_size - size);
 335                if (n < 0) {
 336                        if (size) {
 337                                pr_warning("read failed %d: %s\n", errno,
 338                                         strerror_r(errno, sbuf, sizeof(sbuf)));
 339                                err = 0;
 340                        } else
 341                                err = -errno;
 342
 343                        break;
 344                }
 345
 346                size += n;
 347        } while (n > 0);
 348
 349        if (!err) {
 350                *sizep = size;
 351                *buf   = bf;
 352        } else
 353                free(bf);
 354
 355        close(fd);
 356        return err;
 357}
 358
 359int procfs__read_str(const char *entry, char **buf, size_t *sizep)
 360{
 361        char path[PATH_MAX];
 362        const char *procfs = procfs__mountpoint();
 363
 364        if (!procfs)
 365                return -1;
 366
 367        snprintf(path, sizeof(path), "%s/%s", procfs, entry);
 368
 369        return filename__read_str(path, buf, sizep);
 370}
 371
 372int sysfs__read_ull(const char *entry, unsigned long long *value)
 373{
 374        char path[PATH_MAX];
 375        const char *sysfs = sysfs__mountpoint();
 376
 377        if (!sysfs)
 378                return -1;
 379
 380        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 381
 382        return filename__read_ull(path, value);
 383}
 384
 385int sysfs__read_int(const char *entry, int *value)
 386{
 387        char path[PATH_MAX];
 388        const char *sysfs = sysfs__mountpoint();
 389
 390        if (!sysfs)
 391                return -1;
 392
 393        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 394
 395        return filename__read_int(path, value);
 396}
 397
 398int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
 399{
 400        char path[PATH_MAX];
 401        const char *sysfs = sysfs__mountpoint();
 402
 403        if (!sysfs)
 404                return -1;
 405
 406        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 407
 408        return filename__read_str(path, buf, sizep);
 409}
 410
 411int sysctl__read_int(const char *sysctl, int *value)
 412{
 413        char path[PATH_MAX];
 414        const char *procfs = procfs__mountpoint();
 415
 416        if (!procfs)
 417                return -1;
 418
 419        snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
 420
 421        return filename__read_int(path, value);
 422}
 423