0001
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
0212
0213
0214
0215 static bool fs__env_override(struct fs *fs)
0216 {
0217 char *override_path;
0218 size_t name_len = strlen(fs->name);
0219
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
0259
0260
0261
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
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
0358
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
0367
0368
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
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 }