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