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