xref: /linux/tools/lib/api/fs/fs.c (revision 3932b9ca55b0be314a36d3e84faff3e823c081f5)
1 /* TODO merge/factor in debugfs.c here */
2 
3 #include <ctype.h>
4 #include <errno.h>
5 #include <stdbool.h>
6 #include <stdio.h>
7 #include <stdlib.h>
8 #include <string.h>
9 #include <sys/vfs.h>
10 
11 #include "debugfs.h"
12 #include "fs.h"
13 
14 static const char * const sysfs__fs_known_mountpoints[] = {
15 	"/sys",
16 	0,
17 };
18 
19 static const char * const procfs__known_mountpoints[] = {
20 	"/proc",
21 	0,
22 };
23 
24 struct fs {
25 	const char		*name;
26 	const char * const	*mounts;
27 	char			 path[PATH_MAX + 1];
28 	bool			 found;
29 	long			 magic;
30 };
31 
32 enum {
33 	FS__SYSFS  = 0,
34 	FS__PROCFS = 1,
35 };
36 
37 static struct fs fs__entries[] = {
38 	[FS__SYSFS] = {
39 		.name	= "sysfs",
40 		.mounts	= sysfs__fs_known_mountpoints,
41 		.magic	= SYSFS_MAGIC,
42 	},
43 	[FS__PROCFS] = {
44 		.name	= "proc",
45 		.mounts	= procfs__known_mountpoints,
46 		.magic	= PROC_SUPER_MAGIC,
47 	},
48 };
49 
50 static bool fs__read_mounts(struct fs *fs)
51 {
52 	bool found = false;
53 	char type[100];
54 	FILE *fp;
55 
56 	fp = fopen("/proc/mounts", "r");
57 	if (fp == NULL)
58 		return NULL;
59 
60 	while (!found &&
61 	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
62 		      fs->path, type) == 2) {
63 
64 		if (strcmp(type, fs->name) == 0)
65 			found = true;
66 	}
67 
68 	fclose(fp);
69 	return fs->found = found;
70 }
71 
72 static int fs__valid_mount(const char *fs, long magic)
73 {
74 	struct statfs st_fs;
75 
76 	if (statfs(fs, &st_fs) < 0)
77 		return -ENOENT;
78 	else if (st_fs.f_type != magic)
79 		return -ENOENT;
80 
81 	return 0;
82 }
83 
84 static bool fs__check_mounts(struct fs *fs)
85 {
86 	const char * const *ptr;
87 
88 	ptr = fs->mounts;
89 	while (*ptr) {
90 		if (fs__valid_mount(*ptr, fs->magic) == 0) {
91 			fs->found = true;
92 			strcpy(fs->path, *ptr);
93 			return true;
94 		}
95 		ptr++;
96 	}
97 
98 	return false;
99 }
100 
101 static void mem_toupper(char *f, size_t len)
102 {
103 	while (len) {
104 		*f = toupper(*f);
105 		f++;
106 		len--;
107 	}
108 }
109 
110 /*
111  * Check for "NAME_PATH" environment variable to override fs location (for
112  * testing). This matches the recommendation in Documentation/sysfs-rules.txt
113  * for SYSFS_PATH.
114  */
115 static bool fs__env_override(struct fs *fs)
116 {
117 	char *override_path;
118 	size_t name_len = strlen(fs->name);
119 	/* name + "_PATH" + '\0' */
120 	char upper_name[name_len + 5 + 1];
121 	memcpy(upper_name, fs->name, name_len);
122 	mem_toupper(upper_name, name_len);
123 	strcpy(&upper_name[name_len], "_PATH");
124 
125 	override_path = getenv(upper_name);
126 	if (!override_path)
127 		return false;
128 
129 	fs->found = true;
130 	strncpy(fs->path, override_path, sizeof(fs->path));
131 	return true;
132 }
133 
134 static const char *fs__get_mountpoint(struct fs *fs)
135 {
136 	if (fs__env_override(fs))
137 		return fs->path;
138 
139 	if (fs__check_mounts(fs))
140 		return fs->path;
141 
142 	if (fs__read_mounts(fs))
143 		return fs->path;
144 
145 	return NULL;
146 }
147 
148 static const char *fs__mountpoint(int idx)
149 {
150 	struct fs *fs = &fs__entries[idx];
151 
152 	if (fs->found)
153 		return (const char *)fs->path;
154 
155 	return fs__get_mountpoint(fs);
156 }
157 
158 #define FS__MOUNTPOINT(name, idx)	\
159 const char *name##__mountpoint(void)	\
160 {					\
161 	return fs__mountpoint(idx);	\
162 }
163 
164 FS__MOUNTPOINT(sysfs,  FS__SYSFS);
165 FS__MOUNTPOINT(procfs, FS__PROCFS);
166