]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/lib/api/fs/fs.c
Merge branches 'pm-core', 'pm-qos', 'pm-domains' and 'pm-opp'
[linux.git] / tools / lib / api / fs / fs.c
1 #include <ctype.h>
2 #include <errno.h>
3 #include <limits.h>
4 #include <stdbool.h>
5 #include <stdio.h>
6 #include <stdlib.h>
7 #include <string.h>
8 #include <sys/vfs.h>
9 #include <sys/types.h>
10 #include <sys/stat.h>
11 #include <fcntl.h>
12 #include <unistd.h>
13 #include <sys/mount.h>
14
15 #include "fs.h"
16 #include "debug-internal.h"
17
18 #define _STR(x) #x
19 #define STR(x) _STR(x)
20
21 #ifndef SYSFS_MAGIC
22 #define SYSFS_MAGIC            0x62656572
23 #endif
24
25 #ifndef PROC_SUPER_MAGIC
26 #define PROC_SUPER_MAGIC       0x9fa0
27 #endif
28
29 #ifndef DEBUGFS_MAGIC
30 #define DEBUGFS_MAGIC          0x64626720
31 #endif
32
33 #ifndef TRACEFS_MAGIC
34 #define TRACEFS_MAGIC          0x74726163
35 #endif
36
37 #ifndef HUGETLBFS_MAGIC
38 #define HUGETLBFS_MAGIC        0x958458f6
39 #endif
40
41 #ifndef BPF_FS_MAGIC
42 #define BPF_FS_MAGIC           0xcafe4a11
43 #endif
44
45 static const char * const sysfs__fs_known_mountpoints[] = {
46         "/sys",
47         0,
48 };
49
50 static const char * const procfs__known_mountpoints[] = {
51         "/proc",
52         0,
53 };
54
55 #ifndef DEBUGFS_DEFAULT_PATH
56 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
57 #endif
58
59 static const char * const debugfs__known_mountpoints[] = {
60         DEBUGFS_DEFAULT_PATH,
61         "/debug",
62         0,
63 };
64
65
66 #ifndef TRACEFS_DEFAULT_PATH
67 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
68 #endif
69
70 static const char * const tracefs__known_mountpoints[] = {
71         TRACEFS_DEFAULT_PATH,
72         "/sys/kernel/debug/tracing",
73         "/tracing",
74         "/trace",
75         0,
76 };
77
78 static const char * const hugetlbfs__known_mountpoints[] = {
79         0,
80 };
81
82 static const char * const bpf_fs__known_mountpoints[] = {
83         "/sys/fs/bpf",
84         0,
85 };
86
87 struct fs {
88         const char              *name;
89         const char * const      *mounts;
90         char                     path[PATH_MAX];
91         bool                     found;
92         long                     magic;
93 };
94
95 enum {
96         FS__SYSFS   = 0,
97         FS__PROCFS  = 1,
98         FS__DEBUGFS = 2,
99         FS__TRACEFS = 3,
100         FS__HUGETLBFS = 4,
101         FS__BPF_FS = 5,
102 };
103
104 #ifndef TRACEFS_MAGIC
105 #define TRACEFS_MAGIC 0x74726163
106 #endif
107
108 static struct fs fs__entries[] = {
109         [FS__SYSFS] = {
110                 .name   = "sysfs",
111                 .mounts = sysfs__fs_known_mountpoints,
112                 .magic  = SYSFS_MAGIC,
113         },
114         [FS__PROCFS] = {
115                 .name   = "proc",
116                 .mounts = procfs__known_mountpoints,
117                 .magic  = PROC_SUPER_MAGIC,
118         },
119         [FS__DEBUGFS] = {
120                 .name   = "debugfs",
121                 .mounts = debugfs__known_mountpoints,
122                 .magic  = DEBUGFS_MAGIC,
123         },
124         [FS__TRACEFS] = {
125                 .name   = "tracefs",
126                 .mounts = tracefs__known_mountpoints,
127                 .magic  = TRACEFS_MAGIC,
128         },
129         [FS__HUGETLBFS] = {
130                 .name   = "hugetlbfs",
131                 .mounts = hugetlbfs__known_mountpoints,
132                 .magic  = HUGETLBFS_MAGIC,
133         },
134         [FS__BPF_FS] = {
135                 .name   = "bpf",
136                 .mounts = bpf_fs__known_mountpoints,
137                 .magic  = BPF_FS_MAGIC,
138         },
139 };
140
141 static bool fs__read_mounts(struct fs *fs)
142 {
143         bool found = false;
144         char type[100];
145         FILE *fp;
146
147         fp = fopen("/proc/mounts", "r");
148         if (fp == NULL)
149                 return NULL;
150
151         while (!found &&
152                fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
153                       fs->path, type) == 2) {
154
155                 if (strcmp(type, fs->name) == 0)
156                         found = true;
157         }
158
159         fclose(fp);
160         return fs->found = found;
161 }
162
163 static int fs__valid_mount(const char *fs, long magic)
164 {
165         struct statfs st_fs;
166
167         if (statfs(fs, &st_fs) < 0)
168                 return -ENOENT;
169         else if ((long)st_fs.f_type != magic)
170                 return -ENOENT;
171
172         return 0;
173 }
174
175 static bool fs__check_mounts(struct fs *fs)
176 {
177         const char * const *ptr;
178
179         ptr = fs->mounts;
180         while (*ptr) {
181                 if (fs__valid_mount(*ptr, fs->magic) == 0) {
182                         fs->found = true;
183                         strcpy(fs->path, *ptr);
184                         return true;
185                 }
186                 ptr++;
187         }
188
189         return false;
190 }
191
192 static void mem_toupper(char *f, size_t len)
193 {
194         while (len) {
195                 *f = toupper(*f);
196                 f++;
197                 len--;
198         }
199 }
200
201 /*
202  * Check for "NAME_PATH" environment variable to override fs location (for
203  * testing). This matches the recommendation in Documentation/sysfs-rules.txt
204  * for SYSFS_PATH.
205  */
206 static bool fs__env_override(struct fs *fs)
207 {
208         char *override_path;
209         size_t name_len = strlen(fs->name);
210         /* name + "_PATH" + '\0' */
211         char upper_name[name_len + 5 + 1];
212         memcpy(upper_name, fs->name, name_len);
213         mem_toupper(upper_name, name_len);
214         strcpy(&upper_name[name_len], "_PATH");
215
216         override_path = getenv(upper_name);
217         if (!override_path)
218                 return false;
219
220         fs->found = true;
221         strncpy(fs->path, override_path, sizeof(fs->path));
222         return true;
223 }
224
225 static const char *fs__get_mountpoint(struct fs *fs)
226 {
227         if (fs__env_override(fs))
228                 return fs->path;
229
230         if (fs__check_mounts(fs))
231                 return fs->path;
232
233         if (fs__read_mounts(fs))
234                 return fs->path;
235
236         return NULL;
237 }
238
239 static const char *fs__mountpoint(int idx)
240 {
241         struct fs *fs = &fs__entries[idx];
242
243         if (fs->found)
244                 return (const char *)fs->path;
245
246         return fs__get_mountpoint(fs);
247 }
248
249 static const char *mount_overload(struct fs *fs)
250 {
251         size_t name_len = strlen(fs->name);
252         /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
253         char upper_name[5 + name_len + 12 + 1];
254
255         snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
256         mem_toupper(upper_name, name_len);
257
258         return getenv(upper_name) ?: *fs->mounts;
259 }
260
261 static const char *fs__mount(int idx)
262 {
263         struct fs *fs = &fs__entries[idx];
264         const char *mountpoint;
265
266         if (fs__mountpoint(idx))
267                 return (const char *)fs->path;
268
269         mountpoint = mount_overload(fs);
270
271         if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
272                 return NULL;
273
274         return fs__check_mounts(fs) ? fs->path : NULL;
275 }
276
277 #define FS(name, idx)                           \
278 const char *name##__mountpoint(void)            \
279 {                                               \
280         return fs__mountpoint(idx);             \
281 }                                               \
282                                                 \
283 const char *name##__mount(void)                 \
284 {                                               \
285         return fs__mount(idx);                  \
286 }                                               \
287                                                 \
288 bool name##__configured(void)                   \
289 {                                               \
290         return name##__mountpoint() != NULL;    \
291 }
292
293 FS(sysfs,   FS__SYSFS);
294 FS(procfs,  FS__PROCFS);
295 FS(debugfs, FS__DEBUGFS);
296 FS(tracefs, FS__TRACEFS);
297 FS(hugetlbfs, FS__HUGETLBFS);
298 FS(bpf_fs, FS__BPF_FS);
299
300 int filename__read_int(const char *filename, int *value)
301 {
302         char line[64];
303         int fd = open(filename, O_RDONLY), err = -1;
304
305         if (fd < 0)
306                 return -1;
307
308         if (read(fd, line, sizeof(line)) > 0) {
309                 *value = atoi(line);
310                 err = 0;
311         }
312
313         close(fd);
314         return err;
315 }
316
317 /*
318  * Parses @value out of @filename with strtoull.
319  * By using 0 for base, the strtoull detects the
320  * base automatically (see man strtoull).
321  */
322 int filename__read_ull(const char *filename, unsigned long long *value)
323 {
324         char line[64];
325         int fd = open(filename, O_RDONLY), err = -1;
326
327         if (fd < 0)
328                 return -1;
329
330         if (read(fd, line, sizeof(line)) > 0) {
331                 *value = strtoull(line, NULL, 0);
332                 if (*value != ULLONG_MAX)
333                         err = 0;
334         }
335
336         close(fd);
337         return err;
338 }
339
340 #define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
341
342 int filename__read_str(const char *filename, char **buf, size_t *sizep)
343 {
344         size_t size = 0, alloc_size = 0;
345         void *bf = NULL, *nbf;
346         int fd, n, err = 0;
347         char sbuf[STRERR_BUFSIZE];
348
349         fd = open(filename, O_RDONLY);
350         if (fd < 0)
351                 return -errno;
352
353         do {
354                 if (size == alloc_size) {
355                         alloc_size += BUFSIZ;
356                         nbf = realloc(bf, alloc_size);
357                         if (!nbf) {
358                                 err = -ENOMEM;
359                                 break;
360                         }
361
362                         bf = nbf;
363                 }
364
365                 n = read(fd, bf + size, alloc_size - size);
366                 if (n < 0) {
367                         if (size) {
368                                 pr_warning("read failed %d: %s\n", errno,
369                                          strerror_r(errno, sbuf, sizeof(sbuf)));
370                                 err = 0;
371                         } else
372                                 err = -errno;
373
374                         break;
375                 }
376
377                 size += n;
378         } while (n > 0);
379
380         if (!err) {
381                 *sizep = size;
382                 *buf   = bf;
383         } else
384                 free(bf);
385
386         close(fd);
387         return err;
388 }
389
390 int procfs__read_str(const char *entry, char **buf, size_t *sizep)
391 {
392         char path[PATH_MAX];
393         const char *procfs = procfs__mountpoint();
394
395         if (!procfs)
396                 return -1;
397
398         snprintf(path, sizeof(path), "%s/%s", procfs, entry);
399
400         return filename__read_str(path, buf, sizep);
401 }
402
403 int sysfs__read_ull(const char *entry, unsigned long long *value)
404 {
405         char path[PATH_MAX];
406         const char *sysfs = sysfs__mountpoint();
407
408         if (!sysfs)
409                 return -1;
410
411         snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
412
413         return filename__read_ull(path, value);
414 }
415
416 int sysfs__read_int(const char *entry, int *value)
417 {
418         char path[PATH_MAX];
419         const char *sysfs = sysfs__mountpoint();
420
421         if (!sysfs)
422                 return -1;
423
424         snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
425
426         return filename__read_int(path, value);
427 }
428
429 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
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_str(path, buf, sizep);
440 }
441
442 int sysctl__read_int(const char *sysctl, int *value)
443 {
444         char path[PATH_MAX];
445         const char *procfs = procfs__mountpoint();
446
447         if (!procfs)
448                 return -1;
449
450         snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
451
452         return filename__read_int(path, value);
453 }