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