Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/tools/lib/api/fs/fs.c
26292 views
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, name_len, "PERF_%s_ENVIRONMENT", fs->name);
265
mem_toupper(upper_name, name_len);
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
298
if (fd < 0)
299
return -errno;
300
301
if (read(fd, line, sizeof(line)) > 0) {
302
*value = atoi(line);
303
err = 0;
304
}
305
306
close(fd);
307
return err;
308
}
309
310
static int filename__read_ull_base(const char *filename,
311
unsigned long long *value, int base)
312
{
313
char line[64];
314
int fd = open(filename, O_RDONLY), err = -1;
315
316
if (fd < 0)
317
return -errno;
318
319
if (read(fd, line, sizeof(line)) > 0) {
320
*value = strtoull(line, NULL, base);
321
if (*value != ULLONG_MAX)
322
err = 0;
323
}
324
325
close(fd);
326
return err;
327
}
328
329
/*
330
* Parses @value out of @filename with strtoull.
331
* By using 16 for base to treat the number as hex.
332
*/
333
int filename__read_xll(const char *filename, unsigned long long *value)
334
{
335
return filename__read_ull_base(filename, value, 16);
336
}
337
338
/*
339
* Parses @value out of @filename with strtoull.
340
* By using 0 for base, the strtoull detects the
341
* base automatically (see man strtoull).
342
*/
343
int filename__read_ull(const char *filename, unsigned long long *value)
344
{
345
return filename__read_ull_base(filename, value, 0);
346
}
347
348
int filename__read_str(const char *filename, char **buf, size_t *sizep)
349
{
350
struct io io;
351
char bf[128];
352
int err;
353
354
io.fd = open(filename, O_RDONLY);
355
if (io.fd < 0)
356
return -errno;
357
io__init(&io, io.fd, bf, sizeof(bf));
358
*buf = NULL;
359
err = io__getdelim(&io, buf, sizep, /*delim=*/-1);
360
if (err < 0) {
361
free(*buf);
362
*buf = NULL;
363
} else
364
err = 0;
365
close(io.fd);
366
return err;
367
}
368
369
int filename__write_int(const char *filename, int value)
370
{
371
int fd = open(filename, O_WRONLY), err = -1;
372
char buf[64];
373
374
if (fd < 0)
375
return -errno;
376
377
sprintf(buf, "%d", value);
378
if (write(fd, buf, sizeof(buf)) == sizeof(buf))
379
err = 0;
380
381
close(fd);
382
return err;
383
}
384
385
int procfs__read_str(const char *entry, char **buf, size_t *sizep)
386
{
387
char path[PATH_MAX];
388
const char *procfs = procfs__mountpoint();
389
390
if (!procfs)
391
return -1;
392
393
snprintf(path, sizeof(path), "%s/%s", procfs, entry);
394
395
return filename__read_str(path, buf, sizep);
396
}
397
398
static int sysfs__read_ull_base(const char *entry,
399
unsigned long long *value, int base)
400
{
401
char path[PATH_MAX];
402
const char *sysfs = sysfs__mountpoint();
403
404
if (!sysfs)
405
return -1;
406
407
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
408
409
return filename__read_ull_base(path, value, base);
410
}
411
412
int sysfs__read_xll(const char *entry, unsigned long long *value)
413
{
414
return sysfs__read_ull_base(entry, value, 16);
415
}
416
417
int sysfs__read_ull(const char *entry, unsigned long long *value)
418
{
419
return sysfs__read_ull_base(entry, value, 0);
420
}
421
422
int sysfs__read_int(const char *entry, int *value)
423
{
424
char path[PATH_MAX];
425
const char *sysfs = sysfs__mountpoint();
426
427
if (!sysfs)
428
return -1;
429
430
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
431
432
return filename__read_int(path, value);
433
}
434
435
int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
436
{
437
char path[PATH_MAX];
438
const char *sysfs = sysfs__mountpoint();
439
440
if (!sysfs)
441
return -1;
442
443
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
444
445
return filename__read_str(path, buf, sizep);
446
}
447
448
int sysfs__read_bool(const char *entry, bool *value)
449
{
450
struct io io;
451
char bf[16];
452
int ret = 0;
453
char path[PATH_MAX];
454
const char *sysfs = sysfs__mountpoint();
455
456
if (!sysfs)
457
return -1;
458
459
snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
460
io.fd = open(path, O_RDONLY);
461
if (io.fd < 0)
462
return -errno;
463
464
io__init(&io, io.fd, bf, sizeof(bf));
465
switch (io__get_char(&io)) {
466
case '1':
467
case 'y':
468
case 'Y':
469
*value = true;
470
break;
471
case '0':
472
case 'n':
473
case 'N':
474
*value = false;
475
break;
476
default:
477
ret = -1;
478
}
479
close(io.fd);
480
481
return ret;
482
}
483
int sysctl__read_int(const char *sysctl, int *value)
484
{
485
char path[PATH_MAX];
486
const char *procfs = procfs__mountpoint();
487
488
if (!procfs)
489
return -1;
490
491
snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
492
493
return filename__read_int(path, value);
494
}
495
496
int sysfs__write_int(const char *entry, int value)
497
{
498
char path[PATH_MAX];
499
const char *sysfs = sysfs__mountpoint();
500
501
if (!sysfs)
502
return -1;
503
504
if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
505
return -1;
506
507
return filename__write_int(path, value);
508
}
509
510