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
  37#ifndef HUGETLBFS_MAGIC
  38#define HUGETLBFS_MAGIC        0x958458f6
  39#endif
  40
  41#ifndef BPF_FS_MAGIC
  42#define BPF_FS_MAGIC           0xcafe4a11
  43#endif
  44
  45static const char * const sysfs__fs_known_mountpoints[] = {
  46        "/sys",
  47        0,
  48};
  49
  50static const char * const procfs__known_mountpoints[] = {
  51        "/proc",
  52        0,
  53};
  54
  55#ifndef DEBUGFS_DEFAULT_PATH
  56#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
  57#endif
  58
  59static const char * const debugfs__known_mountpoints[] = {
  60        DEBUGFS_DEFAULT_PATH,
  61        "/debug",
  62        0,
  63};
  64
  65
  66#ifndef TRACEFS_DEFAULT_PATH
  67#define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
  68#endif
  69
  70static const char * const tracefs__known_mountpoints[] = {
  71        TRACEFS_DEFAULT_PATH,
  72        "/sys/kernel/debug/tracing",
  73        "/tracing",
  74        "/trace",
  75        0,
  76};
  77
  78static const char * const hugetlbfs__known_mountpoints[] = {
  79        0,
  80};
  81
  82static const char * const bpf_fs__known_mountpoints[] = {
  83        "/sys/fs/bpf",
  84        0,
  85};
  86
  87struct fs {
  88        const char              *name;
  89        const char * const      *mounts;
  90        char                     path[PATH_MAX];
  91        bool                     found;
  92        long                     magic;
  93};
  94
  95enum {
  96        FS__SYSFS   = 0,
  97        FS__PROCFS  = 1,
  98        FS__DEBUGFS = 2,
  99        FS__TRACEFS = 3,
 100        FS__HUGETLBFS = 4,
 101        FS__BPF_FS = 5,
 102};
 103
 104#ifndef TRACEFS_MAGIC
 105#define TRACEFS_MAGIC 0x74726163
 106#endif
 107
 108static struct fs fs__entries[] = {
 109        [FS__SYSFS] = {
 110                .name   = "sysfs",
 111                .mounts = sysfs__fs_known_mountpoints,
 112                .magic  = SYSFS_MAGIC,
 113        },
 114        [FS__PROCFS] = {
 115                .name   = "proc",
 116                .mounts = procfs__known_mountpoints,
 117                .magic  = PROC_SUPER_MAGIC,
 118        },
 119        [FS__DEBUGFS] = {
 120                .name   = "debugfs",
 121                .mounts = debugfs__known_mountpoints,
 122                .magic  = DEBUGFS_MAGIC,
 123        },
 124        [FS__TRACEFS] = {
 125                .name   = "tracefs",
 126                .mounts = tracefs__known_mountpoints,
 127                .magic  = TRACEFS_MAGIC,
 128        },
 129        [FS__HUGETLBFS] = {
 130                .name   = "hugetlbfs",
 131                .mounts = hugetlbfs__known_mountpoints,
 132                .magic  = HUGETLBFS_MAGIC,
 133        },
 134        [FS__BPF_FS] = {
 135                .name   = "bpf",
 136                .mounts = bpf_fs__known_mountpoints,
 137                .magic  = BPF_FS_MAGIC,
 138        },
 139};
 140
 141static bool fs__read_mounts(struct fs *fs)
 142{
 143        bool found = false;
 144        char type[100];
 145        FILE *fp;
 146
 147        fp = fopen("/proc/mounts", "r");
 148        if (fp == NULL)
 149                return NULL;
 150
 151        while (!found &&
 152               fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
 153                      fs->path, type) == 2) {
 154
 155                if (strcmp(type, fs->name) == 0)
 156                        found = true;
 157        }
 158
 159        fclose(fp);
 160        return fs->found = found;
 161}
 162
 163static int fs__valid_mount(const char *fs, long magic)
 164{
 165        struct statfs st_fs;
 166
 167        if (statfs(fs, &st_fs) < 0)
 168                return -ENOENT;
 169        else if ((long)st_fs.f_type != magic)
 170                return -ENOENT;
 171
 172        return 0;
 173}
 174
 175static bool fs__check_mounts(struct fs *fs)
 176{
 177        const char * const *ptr;
 178
 179        ptr = fs->mounts;
 180        while (*ptr) {
 181                if (fs__valid_mount(*ptr, fs->magic) == 0) {
 182                        fs->found = true;
 183                        strcpy(fs->path, *ptr);
 184                        return true;
 185                }
 186                ptr++;
 187        }
 188
 189        return false;
 190}
 191
 192static void mem_toupper(char *f, size_t len)
 193{
 194        while (len) {
 195                *f = toupper(*f);
 196                f++;
 197                len--;
 198        }
 199}
 200
 201/*
 202 * Check for "NAME_PATH" environment variable to override fs location (for
 203 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
 204 * for SYSFS_PATH.
 205 */
 206static bool fs__env_override(struct fs *fs)
 207{
 208        char *override_path;
 209        size_t name_len = strlen(fs->name);
 210        /* name + "_PATH" + '\0' */
 211        char upper_name[name_len + 5 + 1];
 212        memcpy(upper_name, fs->name, name_len);
 213        mem_toupper(upper_name, name_len);
 214        strcpy(&upper_name[name_len], "_PATH");
 215
 216        override_path = getenv(upper_name);
 217        if (!override_path)
 218                return false;
 219
 220        fs->found = true;
 221        strncpy(fs->path, override_path, sizeof(fs->path));
 222        return true;
 223}
 224
 225static const char *fs__get_mountpoint(struct fs *fs)
 226{
 227        if (fs__env_override(fs))
 228                return fs->path;
 229
 230        if (fs__check_mounts(fs))
 231                return fs->path;
 232
 233        if (fs__read_mounts(fs))
 234                return fs->path;
 235
 236        return NULL;
 237}
 238
 239static const char *fs__mountpoint(int idx)
 240{
 241        struct fs *fs = &fs__entries[idx];
 242
 243        if (fs->found)
 244                return (const char *)fs->path;
 245
 246        return fs__get_mountpoint(fs);
 247}
 248
 249static const char *mount_overload(struct fs *fs)
 250{
 251        size_t name_len = strlen(fs->name);
 252        /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
 253        char upper_name[5 + name_len + 12 + 1];
 254
 255        snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
 256        mem_toupper(upper_name, name_len);
 257
 258        return getenv(upper_name) ?: *fs->mounts;
 259}
 260
 261static const char *fs__mount(int idx)
 262{
 263        struct fs *fs = &fs__entries[idx];
 264        const char *mountpoint;
 265
 266        if (fs__mountpoint(idx))
 267                return (const char *)fs->path;
 268
 269        mountpoint = mount_overload(fs);
 270
 271        if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
 272                return NULL;
 273
 274        return fs__check_mounts(fs) ? fs->path : NULL;
 275}
 276
 277#define FS(name, idx)                           \
 278const char *name##__mountpoint(void)            \
 279{                                               \
 280        return fs__mountpoint(idx);             \
 281}                                               \
 282                                                \
 283const char *name##__mount(void)                 \
 284{                                               \
 285        return fs__mount(idx);                  \
 286}                                               \
 287                                                \
 288bool name##__configured(void)                   \
 289{                                               \
 290        return name##__mountpoint() != NULL;    \
 291}
 292
 293FS(sysfs,   FS__SYSFS);
 294FS(procfs,  FS__PROCFS);
 295FS(debugfs, FS__DEBUGFS);
 296FS(tracefs, FS__TRACEFS);
 297FS(hugetlbfs, FS__HUGETLBFS);
 298FS(bpf_fs, FS__BPF_FS);
 299
 300int filename__read_int(const char *filename, int *value)
 301{
 302        char line[64];
 303        int fd = open(filename, O_RDONLY), err = -1;
 304
 305        if (fd < 0)
 306                return -1;
 307
 308        if (read(fd, line, sizeof(line)) > 0) {
 309                *value = atoi(line);
 310                err = 0;
 311        }
 312
 313        close(fd);
 314        return err;
 315}
 316
 317/*
 318 * Parses @value out of @filename with strtoull.
 319 * By using 0 for base, the strtoull detects the
 320 * base automatically (see man strtoull).
 321 */
 322int filename__read_ull(const char *filename, unsigned long long *value)
 323{
 324        char line[64];
 325        int fd = open(filename, O_RDONLY), err = -1;
 326
 327        if (fd < 0)
 328                return -1;
 329
 330        if (read(fd, line, sizeof(line)) > 0) {
 331                *value = strtoull(line, NULL, 0);
 332                if (*value != ULLONG_MAX)
 333                        err = 0;
 334        }
 335
 336        close(fd);
 337        return err;
 338}
 339
 340#define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
 341
 342int filename__read_str(const char *filename, char **buf, size_t *sizep)
 343{
 344        size_t size = 0, alloc_size = 0;
 345        void *bf = NULL, *nbf;
 346        int fd, n, err = 0;
 347        char sbuf[STRERR_BUFSIZE];
 348
 349        fd = open(filename, O_RDONLY);
 350        if (fd < 0)
 351                return -errno;
 352
 353        do {
 354                if (size == alloc_size) {
 355                        alloc_size += BUFSIZ;
 356                        nbf = realloc(bf, alloc_size);
 357                        if (!nbf) {
 358                                err = -ENOMEM;
 359                                break;
 360                        }
 361
 362                        bf = nbf;
 363                }
 364
 365                n = read(fd, bf + size, alloc_size - size);
 366                if (n < 0) {
 367                        if (size) {
 368                                pr_warning("read failed %d: %s\n", errno,
 369                                         strerror_r(errno, sbuf, sizeof(sbuf)));
 370                                err = 0;
 371                        } else
 372                                err = -errno;
 373
 374                        break;
 375                }
 376
 377                size += n;
 378        } while (n > 0);
 379
 380        if (!err) {
 381                *sizep = size;
 382                *buf   = bf;
 383        } else
 384                free(bf);
 385
 386        close(fd);
 387        return err;
 388}
 389
 390int filename__write_int(const char *filename, int value)
 391{
 392        int fd = open(filename, O_WRONLY), err = -1;
 393        char buf[64];
 394
 395        if (fd < 0)
 396                return err;
 397
 398        sprintf(buf, "%d", value);
 399        if (write(fd, buf, sizeof(buf)) == sizeof(buf))
 400                err = 0;
 401
 402        close(fd);
 403        return err;
 404}
 405
 406int procfs__read_str(const char *entry, char **buf, size_t *sizep)
 407{
 408        char path[PATH_MAX];
 409        const char *procfs = procfs__mountpoint();
 410
 411        if (!procfs)
 412                return -1;
 413
 414        snprintf(path, sizeof(path), "%s/%s", procfs, entry);
 415
 416        return filename__read_str(path, buf, sizep);
 417}
 418
 419int sysfs__read_ull(const char *entry, unsigned long long *value)
 420{
 421        char path[PATH_MAX];
 422        const char *sysfs = sysfs__mountpoint();
 423
 424        if (!sysfs)
 425                return -1;
 426
 427        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 428
 429        return filename__read_ull(path, value);
 430}
 431
 432int sysfs__read_int(const char *entry, int *value)
 433{
 434        char path[PATH_MAX];
 435        const char *sysfs = sysfs__mountpoint();
 436
 437        if (!sysfs)
 438                return -1;
 439
 440        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 441
 442        return filename__read_int(path, value);
 443}
 444
 445int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
 446{
 447        char path[PATH_MAX];
 448        const char *sysfs = sysfs__mountpoint();
 449
 450        if (!sysfs)
 451                return -1;
 452
 453        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 454
 455        return filename__read_str(path, buf, sizep);
 456}
 457
 458int sysfs__read_bool(const char *entry, bool *value)
 459{
 460        char *buf;
 461        size_t size;
 462        int ret;
 463
 464        ret = sysfs__read_str(entry, &buf, &size);
 465        if (ret < 0)
 466                return ret;
 467
 468        switch (buf[0]) {
 469        case '1':
 470        case 'y':
 471        case 'Y':
 472                *value = true;
 473                break;
 474        case '0':
 475        case 'n':
 476        case 'N':
 477                *value = false;
 478                break;
 479        default:
 480                ret = -1;
 481        }
 482
 483        free(buf);
 484
 485        return ret;
 486}
 487int sysctl__read_int(const char *sysctl, int *value)
 488{
 489        char path[PATH_MAX];
 490        const char *procfs = procfs__mountpoint();
 491
 492        if (!procfs)
 493                return -1;
 494
 495        snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
 496
 497        return filename__read_int(path, value);
 498}
 499
 500int sysfs__write_int(const char *entry, int value)
 501{
 502        char path[PATH_MAX];
 503        const char *sysfs = sysfs__mountpoint();
 504
 505        if (!sysfs)
 506                return -1;
 507
 508        if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
 509                return -1;
 510
 511        return filename__write_int(path, value);
 512}
 513