]> git.kernelconcepts.de Git - karo-tx-linux.git/blob - tools/lib/api/fs/fs.c
Merge branch 'ras-core-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[karo-tx-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
17 #define _STR(x) #x
18 #define STR(x) _STR(x)
19
20 #ifndef SYSFS_MAGIC
21 #define SYSFS_MAGIC            0x62656572
22 #endif
23
24 #ifndef PROC_SUPER_MAGIC
25 #define PROC_SUPER_MAGIC       0x9fa0
26 #endif
27
28 #ifndef DEBUGFS_MAGIC
29 #define DEBUGFS_MAGIC          0x64626720
30 #endif
31
32 #ifndef TRACEFS_MAGIC
33 #define TRACEFS_MAGIC          0x74726163
34 #endif
35
36 static const char * const sysfs__fs_known_mountpoints[] = {
37         "/sys",
38         0,
39 };
40
41 static const char * const procfs__known_mountpoints[] = {
42         "/proc",
43         0,
44 };
45
46 #ifndef DEBUGFS_DEFAULT_PATH
47 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
48 #endif
49
50 static const char * const debugfs__known_mountpoints[] = {
51         DEBUGFS_DEFAULT_PATH,
52         "/debug",
53         0,
54 };
55
56
57 #ifndef TRACEFS_DEFAULT_PATH
58 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
59 #endif
60
61 static const char * const tracefs__known_mountpoints[] = {
62         TRACEFS_DEFAULT_PATH,
63         "/sys/kernel/debug/tracing",
64         "/tracing",
65         "/trace",
66         0,
67 };
68
69 struct fs {
70         const char              *name;
71         const char * const      *mounts;
72         char                     path[PATH_MAX];
73         bool                     found;
74         long                     magic;
75 };
76
77 enum {
78         FS__SYSFS   = 0,
79         FS__PROCFS  = 1,
80         FS__DEBUGFS = 2,
81         FS__TRACEFS = 3,
82 };
83
84 #ifndef TRACEFS_MAGIC
85 #define TRACEFS_MAGIC 0x74726163
86 #endif
87
88 static struct fs fs__entries[] = {
89         [FS__SYSFS] = {
90                 .name   = "sysfs",
91                 .mounts = sysfs__fs_known_mountpoints,
92                 .magic  = SYSFS_MAGIC,
93         },
94         [FS__PROCFS] = {
95                 .name   = "proc",
96                 .mounts = procfs__known_mountpoints,
97                 .magic  = PROC_SUPER_MAGIC,
98         },
99         [FS__DEBUGFS] = {
100                 .name   = "debugfs",
101                 .mounts = debugfs__known_mountpoints,
102                 .magic  = DEBUGFS_MAGIC,
103         },
104         [FS__TRACEFS] = {
105                 .name   = "tracefs",
106                 .mounts = tracefs__known_mountpoints,
107                 .magic  = TRACEFS_MAGIC,
108         },
109 };
110
111 static bool fs__read_mounts(struct fs *fs)
112 {
113         bool found = false;
114         char type[100];
115         FILE *fp;
116
117         fp = fopen("/proc/mounts", "r");
118         if (fp == NULL)
119                 return NULL;
120
121         while (!found &&
122                fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
123                       fs->path, type) == 2) {
124
125                 if (strcmp(type, fs->name) == 0)
126                         found = true;
127         }
128
129         fclose(fp);
130         return fs->found = found;
131 }
132
133 static int fs__valid_mount(const char *fs, long magic)
134 {
135         struct statfs st_fs;
136
137         if (statfs(fs, &st_fs) < 0)
138                 return -ENOENT;
139         else if ((long)st_fs.f_type != magic)
140                 return -ENOENT;
141
142         return 0;
143 }
144
145 static bool fs__check_mounts(struct fs *fs)
146 {
147         const char * const *ptr;
148
149         ptr = fs->mounts;
150         while (*ptr) {
151                 if (fs__valid_mount(*ptr, fs->magic) == 0) {
152                         fs->found = true;
153                         strcpy(fs->path, *ptr);
154                         return true;
155                 }
156                 ptr++;
157         }
158
159         return false;
160 }
161
162 static void mem_toupper(char *f, size_t len)
163 {
164         while (len) {
165                 *f = toupper(*f);
166                 f++;
167                 len--;
168         }
169 }
170
171 /*
172  * Check for "NAME_PATH" environment variable to override fs location (for
173  * testing). This matches the recommendation in Documentation/sysfs-rules.txt
174  * for SYSFS_PATH.
175  */
176 static bool fs__env_override(struct fs *fs)
177 {
178         char *override_path;
179         size_t name_len = strlen(fs->name);
180         /* name + "_PATH" + '\0' */
181         char upper_name[name_len + 5 + 1];
182         memcpy(upper_name, fs->name, name_len);
183         mem_toupper(upper_name, name_len);
184         strcpy(&upper_name[name_len], "_PATH");
185
186         override_path = getenv(upper_name);
187         if (!override_path)
188                 return false;
189
190         fs->found = true;
191         strncpy(fs->path, override_path, sizeof(fs->path));
192         return true;
193 }
194
195 static const char *fs__get_mountpoint(struct fs *fs)
196 {
197         if (fs__env_override(fs))
198                 return fs->path;
199
200         if (fs__check_mounts(fs))
201                 return fs->path;
202
203         if (fs__read_mounts(fs))
204                 return fs->path;
205
206         return NULL;
207 }
208
209 static const char *fs__mountpoint(int idx)
210 {
211         struct fs *fs = &fs__entries[idx];
212
213         if (fs->found)
214                 return (const char *)fs->path;
215
216         return fs__get_mountpoint(fs);
217 }
218
219 static const char *mount_overload(struct fs *fs)
220 {
221         size_t name_len = strlen(fs->name);
222         /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
223         char upper_name[5 + name_len + 12 + 1];
224
225         snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
226         mem_toupper(upper_name, name_len);
227
228         return getenv(upper_name) ?: *fs->mounts;
229 }
230
231 static const char *fs__mount(int idx)
232 {
233         struct fs *fs = &fs__entries[idx];
234         const char *mountpoint;
235
236         if (fs__mountpoint(idx))
237                 return (const char *)fs->path;
238
239         mountpoint = mount_overload(fs);
240
241         if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
242                 return NULL;
243
244         return fs__check_mounts(fs) ? fs->path : NULL;
245 }
246
247 #define FS(name, idx)                           \
248 const char *name##__mountpoint(void)            \
249 {                                               \
250         return fs__mountpoint(idx);             \
251 }                                               \
252                                                 \
253 const char *name##__mount(void)                 \
254 {                                               \
255         return fs__mount(idx);                  \
256 }                                               \
257                                                 \
258 bool name##__configured(void)                   \
259 {                                               \
260         return name##__mountpoint() != NULL;    \
261 }
262
263 FS(sysfs,   FS__SYSFS);
264 FS(procfs,  FS__PROCFS);
265 FS(debugfs, FS__DEBUGFS);
266 FS(tracefs, FS__TRACEFS);
267
268 int filename__read_int(const char *filename, int *value)
269 {
270         char line[64];
271         int fd = open(filename, O_RDONLY), err = -1;
272
273         if (fd < 0)
274                 return -1;
275
276         if (read(fd, line, sizeof(line)) > 0) {
277                 *value = atoi(line);
278                 err = 0;
279         }
280
281         close(fd);
282         return err;
283 }
284
285 int filename__read_ull(const char *filename, unsigned long long *value)
286 {
287         char line[64];
288         int fd = open(filename, O_RDONLY), err = -1;
289
290         if (fd < 0)
291                 return -1;
292
293         if (read(fd, line, sizeof(line)) > 0) {
294                 *value = strtoull(line, NULL, 10);
295                 if (*value != ULLONG_MAX)
296                         err = 0;
297         }
298
299         close(fd);
300         return err;
301 }
302
303 int sysfs__read_ull(const char *entry, unsigned long long *value)
304 {
305         char path[PATH_MAX];
306         const char *sysfs = sysfs__mountpoint();
307
308         if (!sysfs)
309                 return -1;
310
311         snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
312
313         return filename__read_ull(path, value);
314 }
315
316 int sysfs__read_int(const char *entry, int *value)
317 {
318         char path[PATH_MAX];
319         const char *sysfs = sysfs__mountpoint();
320
321         if (!sysfs)
322                 return -1;
323
324         snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
325
326         return filename__read_int(path, value);
327 }
328
329 int sysctl__read_int(const char *sysctl, int *value)
330 {
331         char path[PATH_MAX];
332         const char *procfs = procfs__mountpoint();
333
334         if (!procfs)
335                 return -1;
336
337         snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
338
339         return filename__read_int(path, value);
340 }