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