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