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
 286int filename__read_ull(const char *filename, unsigned long long *value)
 287{
 288        char line[64];
 289        int fd = open(filename, O_RDONLY), err = -1;
 290
 291        if (fd < 0)
 292                return -1;
 293
 294        if (read(fd, line, sizeof(line)) > 0) {
 295                *value = strtoull(line, NULL, 10);
 296                if (*value != ULLONG_MAX)
 297                        err = 0;
 298        }
 299
 300        close(fd);
 301        return err;
 302}
 303
 304#define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
 305
 306int filename__read_str(const char *filename, char **buf, size_t *sizep)
 307{
 308        size_t size = 0, alloc_size = 0;
 309        void *bf = NULL, *nbf;
 310        int fd, n, err = 0;
 311        char sbuf[STRERR_BUFSIZE];
 312
 313        fd = open(filename, O_RDONLY);
 314        if (fd < 0)
 315                return -errno;
 316
 317        do {
 318                if (size == alloc_size) {
 319                        alloc_size += BUFSIZ;
 320                        nbf = realloc(bf, alloc_size);
 321                        if (!nbf) {
 322                                err = -ENOMEM;
 323                                break;
 324                        }
 325
 326                        bf = nbf;
 327                }
 328
 329                n = read(fd, bf + size, alloc_size - size);
 330                if (n < 0) {
 331                        if (size) {
 332                                pr_warning("read failed %d: %s\n", errno,
 333                                         strerror_r(errno, sbuf, sizeof(sbuf)));
 334                                err = 0;
 335                        } else
 336                                err = -errno;
 337
 338                        break;
 339                }
 340
 341                size += n;
 342        } while (n > 0);
 343
 344        if (!err) {
 345                *sizep = size;
 346                *buf   = bf;
 347        } else
 348                free(bf);
 349
 350        close(fd);
 351        return err;
 352}
 353
 354int sysfs__read_ull(const char *entry, unsigned long long *value)
 355{
 356        char path[PATH_MAX];
 357        const char *sysfs = sysfs__mountpoint();
 358
 359        if (!sysfs)
 360                return -1;
 361
 362        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 363
 364        return filename__read_ull(path, value);
 365}
 366
 367int sysfs__read_int(const char *entry, int *value)
 368{
 369        char path[PATH_MAX];
 370        const char *sysfs = sysfs__mountpoint();
 371
 372        if (!sysfs)
 373                return -1;
 374
 375        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 376
 377        return filename__read_int(path, value);
 378}
 379
 380int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
 381{
 382        char path[PATH_MAX];
 383        const char *sysfs = sysfs__mountpoint();
 384
 385        if (!sysfs)
 386                return -1;
 387
 388        snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
 389
 390        return filename__read_str(path, buf, sizep);
 391}
 392
 393int sysctl__read_int(const char *sysctl, int *value)
 394{
 395        char path[PATH_MAX];
 396        const char *procfs = procfs__mountpoint();
 397
 398        if (!procfs)
 399                return -1;
 400
 401        snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
 402
 403        return filename__read_int(path, value);
 404}
 405