xref: /openbmc/linux/tools/lib/api/fs/fs.c (revision 110e6f26)
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 sysfs__read_ull(const char *entry, unsigned long long *value)
355 {
356 	char path[PATH_MAX];
357 	const char *sysfs = sysfs__mountpoint();
358 
359 	if (!sysfs)
360 		return -1;
361 
362 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
363 
364 	return filename__read_ull(path, value);
365 }
366 
367 int sysfs__read_int(const char *entry, int *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_int(path, value);
378 }
379 
380 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
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_str(path, buf, sizep);
391 }
392 
393 int sysctl__read_int(const char *sysctl, int *value)
394 {
395 	char path[PATH_MAX];
396 	const char *procfs = procfs__mountpoint();
397 
398 	if (!procfs)
399 		return -1;
400 
401 	snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
402 
403 	return filename__read_int(path, value);
404 }
405