Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 #include <ctype.h>
0003 #include <errno.h>
0004 #include <limits.h>
0005 #include <stdbool.h>
0006 #include <stdio.h>
0007 #include <stdlib.h>
0008 #include <string.h>
0009 #include <sys/vfs.h>
0010 #include <sys/types.h>
0011 #include <sys/stat.h>
0012 #include <fcntl.h>
0013 #include <unistd.h>
0014 #include <sys/mount.h>
0015 
0016 #include "fs.h"
0017 #include "debug-internal.h"
0018 
0019 #define _STR(x) #x
0020 #define STR(x) _STR(x)
0021 
0022 #ifndef SYSFS_MAGIC
0023 #define SYSFS_MAGIC            0x62656572
0024 #endif
0025 
0026 #ifndef PROC_SUPER_MAGIC
0027 #define PROC_SUPER_MAGIC       0x9fa0
0028 #endif
0029 
0030 #ifndef DEBUGFS_MAGIC
0031 #define DEBUGFS_MAGIC          0x64626720
0032 #endif
0033 
0034 #ifndef TRACEFS_MAGIC
0035 #define TRACEFS_MAGIC          0x74726163
0036 #endif
0037 
0038 #ifndef HUGETLBFS_MAGIC
0039 #define HUGETLBFS_MAGIC        0x958458f6
0040 #endif
0041 
0042 #ifndef BPF_FS_MAGIC
0043 #define BPF_FS_MAGIC           0xcafe4a11
0044 #endif
0045 
0046 static const char * const sysfs__fs_known_mountpoints[] = {
0047     "/sys",
0048     0,
0049 };
0050 
0051 static const char * const procfs__known_mountpoints[] = {
0052     "/proc",
0053     0,
0054 };
0055 
0056 #ifndef DEBUGFS_DEFAULT_PATH
0057 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
0058 #endif
0059 
0060 static const char * const debugfs__known_mountpoints[] = {
0061     DEBUGFS_DEFAULT_PATH,
0062     "/debug",
0063     0,
0064 };
0065 
0066 
0067 #ifndef TRACEFS_DEFAULT_PATH
0068 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
0069 #endif
0070 
0071 static const char * const tracefs__known_mountpoints[] = {
0072     TRACEFS_DEFAULT_PATH,
0073     "/sys/kernel/debug/tracing",
0074     "/tracing",
0075     "/trace",
0076     0,
0077 };
0078 
0079 static const char * const hugetlbfs__known_mountpoints[] = {
0080     0,
0081 };
0082 
0083 static const char * const bpf_fs__known_mountpoints[] = {
0084     "/sys/fs/bpf",
0085     0,
0086 };
0087 
0088 struct fs {
0089     const char      *name;
0090     const char * const  *mounts;
0091     char             path[PATH_MAX];
0092     bool             found;
0093     bool             checked;
0094     long             magic;
0095 };
0096 
0097 enum {
0098     FS__SYSFS   = 0,
0099     FS__PROCFS  = 1,
0100     FS__DEBUGFS = 2,
0101     FS__TRACEFS = 3,
0102     FS__HUGETLBFS = 4,
0103     FS__BPF_FS = 5,
0104 };
0105 
0106 #ifndef TRACEFS_MAGIC
0107 #define TRACEFS_MAGIC 0x74726163
0108 #endif
0109 
0110 static struct fs fs__entries[] = {
0111     [FS__SYSFS] = {
0112         .name   = "sysfs",
0113         .mounts = sysfs__fs_known_mountpoints,
0114         .magic  = SYSFS_MAGIC,
0115         .checked = false,
0116     },
0117     [FS__PROCFS] = {
0118         .name   = "proc",
0119         .mounts = procfs__known_mountpoints,
0120         .magic  = PROC_SUPER_MAGIC,
0121         .checked = false,
0122     },
0123     [FS__DEBUGFS] = {
0124         .name   = "debugfs",
0125         .mounts = debugfs__known_mountpoints,
0126         .magic  = DEBUGFS_MAGIC,
0127         .checked = false,
0128     },
0129     [FS__TRACEFS] = {
0130         .name   = "tracefs",
0131         .mounts = tracefs__known_mountpoints,
0132         .magic  = TRACEFS_MAGIC,
0133         .checked = false,
0134     },
0135     [FS__HUGETLBFS] = {
0136         .name   = "hugetlbfs",
0137         .mounts = hugetlbfs__known_mountpoints,
0138         .magic  = HUGETLBFS_MAGIC,
0139         .checked = false,
0140     },
0141     [FS__BPF_FS] = {
0142         .name   = "bpf",
0143         .mounts = bpf_fs__known_mountpoints,
0144         .magic  = BPF_FS_MAGIC,
0145         .checked = false,
0146     },
0147 };
0148 
0149 static bool fs__read_mounts(struct fs *fs)
0150 {
0151     bool found = false;
0152     char type[100];
0153     FILE *fp;
0154 
0155     fp = fopen("/proc/mounts", "r");
0156     if (fp == NULL)
0157         return NULL;
0158 
0159     while (!found &&
0160            fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
0161               fs->path, type) == 2) {
0162 
0163         if (strcmp(type, fs->name) == 0)
0164             found = true;
0165     }
0166 
0167     fclose(fp);
0168     fs->checked = true;
0169     return fs->found = found;
0170 }
0171 
0172 static int fs__valid_mount(const char *fs, long magic)
0173 {
0174     struct statfs st_fs;
0175 
0176     if (statfs(fs, &st_fs) < 0)
0177         return -ENOENT;
0178     else if ((long)st_fs.f_type != magic)
0179         return -ENOENT;
0180 
0181     return 0;
0182 }
0183 
0184 static bool fs__check_mounts(struct fs *fs)
0185 {
0186     const char * const *ptr;
0187 
0188     ptr = fs->mounts;
0189     while (*ptr) {
0190         if (fs__valid_mount(*ptr, fs->magic) == 0) {
0191             fs->found = true;
0192             strcpy(fs->path, *ptr);
0193             return true;
0194         }
0195         ptr++;
0196     }
0197 
0198     return false;
0199 }
0200 
0201 static void mem_toupper(char *f, size_t len)
0202 {
0203     while (len) {
0204         *f = toupper(*f);
0205         f++;
0206         len--;
0207     }
0208 }
0209 
0210 /*
0211  * Check for "NAME_PATH" environment variable to override fs location (for
0212  * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
0213  * for SYSFS_PATH.
0214  */
0215 static bool fs__env_override(struct fs *fs)
0216 {
0217     char *override_path;
0218     size_t name_len = strlen(fs->name);
0219     /* name + "_PATH" + '\0' */
0220     char upper_name[name_len + 5 + 1];
0221 
0222     memcpy(upper_name, fs->name, name_len);
0223     mem_toupper(upper_name, name_len);
0224     strcpy(&upper_name[name_len], "_PATH");
0225 
0226     override_path = getenv(upper_name);
0227     if (!override_path)
0228         return false;
0229 
0230     fs->found = true;
0231     fs->checked = true;
0232     strncpy(fs->path, override_path, sizeof(fs->path) - 1);
0233     fs->path[sizeof(fs->path) - 1] = '\0';
0234     return true;
0235 }
0236 
0237 static const char *fs__get_mountpoint(struct fs *fs)
0238 {
0239     if (fs__env_override(fs))
0240         return fs->path;
0241 
0242     if (fs__check_mounts(fs))
0243         return fs->path;
0244 
0245     if (fs__read_mounts(fs))
0246         return fs->path;
0247 
0248     return NULL;
0249 }
0250 
0251 static const char *fs__mountpoint(int idx)
0252 {
0253     struct fs *fs = &fs__entries[idx];
0254 
0255     if (fs->found)
0256         return (const char *)fs->path;
0257 
0258     /* the mount point was already checked for the mount point
0259      * but and did not exist, so return NULL to avoid scanning again.
0260      * This makes the found and not found paths cost equivalent
0261      * in case of multiple calls.
0262      */
0263     if (fs->checked)
0264         return NULL;
0265 
0266     return fs__get_mountpoint(fs);
0267 }
0268 
0269 static const char *mount_overload(struct fs *fs)
0270 {
0271     size_t name_len = strlen(fs->name);
0272     /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
0273     char upper_name[5 + name_len + 12 + 1];
0274 
0275     snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
0276     mem_toupper(upper_name, name_len);
0277 
0278     return getenv(upper_name) ?: *fs->mounts;
0279 }
0280 
0281 static const char *fs__mount(int idx)
0282 {
0283     struct fs *fs = &fs__entries[idx];
0284     const char *mountpoint;
0285 
0286     if (fs__mountpoint(idx))
0287         return (const char *)fs->path;
0288 
0289     mountpoint = mount_overload(fs);
0290 
0291     if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
0292         return NULL;
0293 
0294     return fs__check_mounts(fs) ? fs->path : NULL;
0295 }
0296 
0297 #define FS(name, idx)               \
0298 const char *name##__mountpoint(void)        \
0299 {                       \
0300     return fs__mountpoint(idx);     \
0301 }                       \
0302                         \
0303 const char *name##__mount(void)         \
0304 {                       \
0305     return fs__mount(idx);          \
0306 }                       \
0307                         \
0308 bool name##__configured(void)           \
0309 {                       \
0310     return name##__mountpoint() != NULL;    \
0311 }
0312 
0313 FS(sysfs,   FS__SYSFS);
0314 FS(procfs,  FS__PROCFS);
0315 FS(debugfs, FS__DEBUGFS);
0316 FS(tracefs, FS__TRACEFS);
0317 FS(hugetlbfs, FS__HUGETLBFS);
0318 FS(bpf_fs, FS__BPF_FS);
0319 
0320 int filename__read_int(const char *filename, int *value)
0321 {
0322     char line[64];
0323     int fd = open(filename, O_RDONLY), err = -1;
0324 
0325     if (fd < 0)
0326         return -1;
0327 
0328     if (read(fd, line, sizeof(line)) > 0) {
0329         *value = atoi(line);
0330         err = 0;
0331     }
0332 
0333     close(fd);
0334     return err;
0335 }
0336 
0337 static int filename__read_ull_base(const char *filename,
0338                    unsigned long long *value, int base)
0339 {
0340     char line[64];
0341     int fd = open(filename, O_RDONLY), err = -1;
0342 
0343     if (fd < 0)
0344         return -1;
0345 
0346     if (read(fd, line, sizeof(line)) > 0) {
0347         *value = strtoull(line, NULL, base);
0348         if (*value != ULLONG_MAX)
0349             err = 0;
0350     }
0351 
0352     close(fd);
0353     return err;
0354 }
0355 
0356 /*
0357  * Parses @value out of @filename with strtoull.
0358  * By using 16 for base to treat the number as hex.
0359  */
0360 int filename__read_xll(const char *filename, unsigned long long *value)
0361 {
0362     return filename__read_ull_base(filename, value, 16);
0363 }
0364 
0365 /*
0366  * Parses @value out of @filename with strtoull.
0367  * By using 0 for base, the strtoull detects the
0368  * base automatically (see man strtoull).
0369  */
0370 int filename__read_ull(const char *filename, unsigned long long *value)
0371 {
0372     return filename__read_ull_base(filename, value, 0);
0373 }
0374 
0375 #define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
0376 
0377 int filename__read_str(const char *filename, char **buf, size_t *sizep)
0378 {
0379     size_t size = 0, alloc_size = 0;
0380     void *bf = NULL, *nbf;
0381     int fd, n, err = 0;
0382     char sbuf[STRERR_BUFSIZE];
0383 
0384     fd = open(filename, O_RDONLY);
0385     if (fd < 0)
0386         return -errno;
0387 
0388     do {
0389         if (size == alloc_size) {
0390             alloc_size += BUFSIZ;
0391             nbf = realloc(bf, alloc_size);
0392             if (!nbf) {
0393                 err = -ENOMEM;
0394                 break;
0395             }
0396 
0397             bf = nbf;
0398         }
0399 
0400         n = read(fd, bf + size, alloc_size - size);
0401         if (n < 0) {
0402             if (size) {
0403                 pr_warn("read failed %d: %s\n", errno,
0404                     strerror_r(errno, sbuf, sizeof(sbuf)));
0405                 err = 0;
0406             } else
0407                 err = -errno;
0408 
0409             break;
0410         }
0411 
0412         size += n;
0413     } while (n > 0);
0414 
0415     if (!err) {
0416         *sizep = size;
0417         *buf   = bf;
0418     } else
0419         free(bf);
0420 
0421     close(fd);
0422     return err;
0423 }
0424 
0425 int filename__write_int(const char *filename, int value)
0426 {
0427     int fd = open(filename, O_WRONLY), err = -1;
0428     char buf[64];
0429 
0430     if (fd < 0)
0431         return err;
0432 
0433     sprintf(buf, "%d", value);
0434     if (write(fd, buf, sizeof(buf)) == sizeof(buf))
0435         err = 0;
0436 
0437     close(fd);
0438     return err;
0439 }
0440 
0441 int procfs__read_str(const char *entry, char **buf, size_t *sizep)
0442 {
0443     char path[PATH_MAX];
0444     const char *procfs = procfs__mountpoint();
0445 
0446     if (!procfs)
0447         return -1;
0448 
0449     snprintf(path, sizeof(path), "%s/%s", procfs, entry);
0450 
0451     return filename__read_str(path, buf, sizep);
0452 }
0453 
0454 static int sysfs__read_ull_base(const char *entry,
0455                 unsigned long long *value, int base)
0456 {
0457     char path[PATH_MAX];
0458     const char *sysfs = sysfs__mountpoint();
0459 
0460     if (!sysfs)
0461         return -1;
0462 
0463     snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
0464 
0465     return filename__read_ull_base(path, value, base);
0466 }
0467 
0468 int sysfs__read_xll(const char *entry, unsigned long long *value)
0469 {
0470     return sysfs__read_ull_base(entry, value, 16);
0471 }
0472 
0473 int sysfs__read_ull(const char *entry, unsigned long long *value)
0474 {
0475     return sysfs__read_ull_base(entry, value, 0);
0476 }
0477 
0478 int sysfs__read_int(const char *entry, int *value)
0479 {
0480     char path[PATH_MAX];
0481     const char *sysfs = sysfs__mountpoint();
0482 
0483     if (!sysfs)
0484         return -1;
0485 
0486     snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
0487 
0488     return filename__read_int(path, value);
0489 }
0490 
0491 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
0492 {
0493     char path[PATH_MAX];
0494     const char *sysfs = sysfs__mountpoint();
0495 
0496     if (!sysfs)
0497         return -1;
0498 
0499     snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
0500 
0501     return filename__read_str(path, buf, sizep);
0502 }
0503 
0504 int sysfs__read_bool(const char *entry, bool *value)
0505 {
0506     char *buf;
0507     size_t size;
0508     int ret;
0509 
0510     ret = sysfs__read_str(entry, &buf, &size);
0511     if (ret < 0)
0512         return ret;
0513 
0514     switch (buf[0]) {
0515     case '1':
0516     case 'y':
0517     case 'Y':
0518         *value = true;
0519         break;
0520     case '0':
0521     case 'n':
0522     case 'N':
0523         *value = false;
0524         break;
0525     default:
0526         ret = -1;
0527     }
0528 
0529     free(buf);
0530 
0531     return ret;
0532 }
0533 int sysctl__read_int(const char *sysctl, int *value)
0534 {
0535     char path[PATH_MAX];
0536     const char *procfs = procfs__mountpoint();
0537 
0538     if (!procfs)
0539         return -1;
0540 
0541     snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
0542 
0543     return filename__read_int(path, value);
0544 }
0545 
0546 int sysfs__write_int(const char *entry, int value)
0547 {
0548     char path[PATH_MAX];
0549     const char *sysfs = sysfs__mountpoint();
0550 
0551     if (!sysfs)
0552         return -1;
0553 
0554     if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
0555         return -1;
0556 
0557     return filename__write_int(path, value);
0558 }