1 // SPDX-License-Identifier: GPL-2.0
10 #include <sys/types.h>
14 #include <sys/mount.h>
17 #include "debug-internal.h"
20 #define STR(x) _STR(x)
23 #define SYSFS_MAGIC 0x62656572
26 #ifndef PROC_SUPER_MAGIC
27 #define PROC_SUPER_MAGIC 0x9fa0
31 #define DEBUGFS_MAGIC 0x64626720
35 #define TRACEFS_MAGIC 0x74726163
38 #ifndef HUGETLBFS_MAGIC
39 #define HUGETLBFS_MAGIC 0x958458f6
43 #define BPF_FS_MAGIC 0xcafe4a11
46 static const char * const sysfs__fs_known_mountpoints
[] = {
51 static const char * const procfs__known_mountpoints
[] = {
56 #ifndef DEBUGFS_DEFAULT_PATH
57 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
60 static const char * const debugfs__known_mountpoints
[] = {
67 #ifndef TRACEFS_DEFAULT_PATH
68 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
71 static const char * const tracefs__known_mountpoints
[] = {
73 "/sys/kernel/debug/tracing",
79 static const char * const hugetlbfs__known_mountpoints
[] = {
83 static const char * const bpf_fs__known_mountpoints
[] = {
90 const char * const *mounts
;
105 #ifndef TRACEFS_MAGIC
106 #define TRACEFS_MAGIC 0x74726163
109 static struct fs fs__entries
[] = {
112 .mounts
= sysfs__fs_known_mountpoints
,
113 .magic
= SYSFS_MAGIC
,
117 .mounts
= procfs__known_mountpoints
,
118 .magic
= PROC_SUPER_MAGIC
,
122 .mounts
= debugfs__known_mountpoints
,
123 .magic
= DEBUGFS_MAGIC
,
127 .mounts
= tracefs__known_mountpoints
,
128 .magic
= TRACEFS_MAGIC
,
132 .mounts
= hugetlbfs__known_mountpoints
,
133 .magic
= HUGETLBFS_MAGIC
,
137 .mounts
= bpf_fs__known_mountpoints
,
138 .magic
= BPF_FS_MAGIC
,
142 static bool fs__read_mounts(struct fs
*fs
)
148 fp
= fopen("/proc/mounts", "r");
153 fscanf(fp
, "%*s %" STR(PATH_MAX
) "s %99s %*s %*d %*d\n",
154 fs
->path
, type
) == 2) {
156 if (strcmp(type
, fs
->name
) == 0)
161 return fs
->found
= found
;
164 static int fs__valid_mount(const char *fs
, long magic
)
168 if (statfs(fs
, &st_fs
) < 0)
170 else if ((long)st_fs
.f_type
!= magic
)
176 static bool fs__check_mounts(struct fs
*fs
)
178 const char * const *ptr
;
182 if (fs__valid_mount(*ptr
, fs
->magic
) == 0) {
184 strcpy(fs
->path
, *ptr
);
193 static void mem_toupper(char *f
, size_t len
)
203 * Check for "NAME_PATH" environment variable to override fs location (for
204 * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
207 static bool fs__env_override(struct fs
*fs
)
210 size_t name_len
= strlen(fs
->name
);
211 /* name + "_PATH" + '\0' */
212 char upper_name
[name_len
+ 5 + 1];
214 memcpy(upper_name
, fs
->name
, name_len
);
215 mem_toupper(upper_name
, name_len
);
216 strcpy(&upper_name
[name_len
], "_PATH");
218 override_path
= getenv(upper_name
);
223 strncpy(fs
->path
, override_path
, sizeof(fs
->path
) - 1);
224 fs
->path
[sizeof(fs
->path
) - 1] = '\0';
228 static const char *fs__get_mountpoint(struct fs
*fs
)
230 if (fs__env_override(fs
))
233 if (fs__check_mounts(fs
))
236 if (fs__read_mounts(fs
))
242 static const char *fs__mountpoint(int idx
)
244 struct fs
*fs
= &fs__entries
[idx
];
247 return (const char *)fs
->path
;
249 return fs__get_mountpoint(fs
);
252 static const char *mount_overload(struct fs
*fs
)
254 size_t name_len
= strlen(fs
->name
);
255 /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
256 char upper_name
[5 + name_len
+ 12 + 1];
258 snprintf(upper_name
, name_len
, "PERF_%s_ENVIRONMENT", fs
->name
);
259 mem_toupper(upper_name
, name_len
);
261 return getenv(upper_name
) ?: *fs
->mounts
;
264 static const char *fs__mount(int idx
)
266 struct fs
*fs
= &fs__entries
[idx
];
267 const char *mountpoint
;
269 if (fs__mountpoint(idx
))
270 return (const char *)fs
->path
;
272 mountpoint
= mount_overload(fs
);
274 if (mount(NULL
, mountpoint
, fs
->name
, 0, NULL
) < 0)
277 return fs__check_mounts(fs
) ? fs
->path
: NULL
;
280 #define FS(name, idx) \
281 const char *name##__mountpoint(void) \
283 return fs__mountpoint(idx); \
286 const char *name##__mount(void) \
288 return fs__mount(idx); \
291 bool name##__configured(void) \
293 return name##__mountpoint() != NULL; \
296 FS(sysfs
, FS__SYSFS
);
297 FS(procfs
, FS__PROCFS
);
298 FS(debugfs
, FS__DEBUGFS
);
299 FS(tracefs
, FS__TRACEFS
);
300 FS(hugetlbfs
, FS__HUGETLBFS
);
301 FS(bpf_fs
, FS__BPF_FS
);
303 int filename__read_int(const char *filename
, int *value
)
306 int fd
= open(filename
, O_RDONLY
), err
= -1;
311 if (read(fd
, line
, sizeof(line
)) > 0) {
320 static int filename__read_ull_base(const char *filename
,
321 unsigned long long *value
, int base
)
324 int fd
= open(filename
, O_RDONLY
), err
= -1;
329 if (read(fd
, line
, sizeof(line
)) > 0) {
330 *value
= strtoull(line
, NULL
, base
);
331 if (*value
!= ULLONG_MAX
)
340 * Parses @value out of @filename with strtoull.
341 * By using 16 for base to treat the number as hex.
343 int filename__read_xll(const char *filename
, unsigned long long *value
)
345 return filename__read_ull_base(filename
, value
, 16);
349 * Parses @value out of @filename with strtoull.
350 * By using 0 for base, the strtoull detects the
351 * base automatically (see man strtoull).
353 int filename__read_ull(const char *filename
, unsigned long long *value
)
355 return filename__read_ull_base(filename
, value
, 0);
358 #define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */
360 int filename__read_str(const char *filename
, char **buf
, size_t *sizep
)
362 size_t size
= 0, alloc_size
= 0;
363 void *bf
= NULL
, *nbf
;
365 char sbuf
[STRERR_BUFSIZE
];
367 fd
= open(filename
, O_RDONLY
);
372 if (size
== alloc_size
) {
373 alloc_size
+= BUFSIZ
;
374 nbf
= realloc(bf
, alloc_size
);
383 n
= read(fd
, bf
+ size
, alloc_size
- size
);
386 pr_warn("read failed %d: %s\n", errno
,
387 strerror_r(errno
, sbuf
, sizeof(sbuf
)));
408 int filename__write_int(const char *filename
, int value
)
410 int fd
= open(filename
, O_WRONLY
), err
= -1;
416 sprintf(buf
, "%d", value
);
417 if (write(fd
, buf
, sizeof(buf
)) == sizeof(buf
))
424 int procfs__read_str(const char *entry
, char **buf
, size_t *sizep
)
427 const char *procfs
= procfs__mountpoint();
432 snprintf(path
, sizeof(path
), "%s/%s", procfs
, entry
);
434 return filename__read_str(path
, buf
, sizep
);
437 static int sysfs__read_ull_base(const char *entry
,
438 unsigned long long *value
, int base
)
441 const char *sysfs
= sysfs__mountpoint();
446 snprintf(path
, sizeof(path
), "%s/%s", sysfs
, entry
);
448 return filename__read_ull_base(path
, value
, base
);
451 int sysfs__read_xll(const char *entry
, unsigned long long *value
)
453 return sysfs__read_ull_base(entry
, value
, 16);
456 int sysfs__read_ull(const char *entry
, unsigned long long *value
)
458 return sysfs__read_ull_base(entry
, value
, 0);
461 int sysfs__read_int(const char *entry
, int *value
)
464 const char *sysfs
= sysfs__mountpoint();
469 snprintf(path
, sizeof(path
), "%s/%s", sysfs
, entry
);
471 return filename__read_int(path
, value
);
474 int sysfs__read_str(const char *entry
, char **buf
, size_t *sizep
)
477 const char *sysfs
= sysfs__mountpoint();
482 snprintf(path
, sizeof(path
), "%s/%s", sysfs
, entry
);
484 return filename__read_str(path
, buf
, sizep
);
487 int sysfs__read_bool(const char *entry
, bool *value
)
493 ret
= sysfs__read_str(entry
, &buf
, &size
);
516 int sysctl__read_int(const char *sysctl
, int *value
)
519 const char *procfs
= procfs__mountpoint();
524 snprintf(path
, sizeof(path
), "%s/sys/%s", procfs
, sysctl
);
526 return filename__read_int(path
, value
);
529 int sysfs__write_int(const char *entry
, int value
)
532 const char *sysfs
= sysfs__mountpoint();
537 if (snprintf(path
, sizeof(path
), "%s/%s", sysfs
, entry
) >= PATH_MAX
)
540 return filename__write_int(path
, value
);