~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/lib/api/fs/fs.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 -1;
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 -1;
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 err;
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 '':
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 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php