xref: /openbmc/linux/tools/lib/api/fs/fs.c (revision bc5aa3a0)
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 /*
287  * Parses @value out of @filename with strtoull.
288  * By using 0 for base, the strtoull detects the
289  * base automatically (see man strtoull).
290  */
291 int filename__read_ull(const char *filename, unsigned long long *value)
292 {
293 	char line[64];
294 	int fd = open(filename, O_RDONLY), err = -1;
295 
296 	if (fd < 0)
297 		return -1;
298 
299 	if (read(fd, line, sizeof(line)) > 0) {
300 		*value = strtoull(line, NULL, 0);
301 		if (*value != ULLONG_MAX)
302 			err = 0;
303 	}
304 
305 	close(fd);
306 	return err;
307 }
308 
309 #define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
310 
311 int filename__read_str(const char *filename, char **buf, size_t *sizep)
312 {
313 	size_t size = 0, alloc_size = 0;
314 	void *bf = NULL, *nbf;
315 	int fd, n, err = 0;
316 	char sbuf[STRERR_BUFSIZE];
317 
318 	fd = open(filename, O_RDONLY);
319 	if (fd < 0)
320 		return -errno;
321 
322 	do {
323 		if (size == alloc_size) {
324 			alloc_size += BUFSIZ;
325 			nbf = realloc(bf, alloc_size);
326 			if (!nbf) {
327 				err = -ENOMEM;
328 				break;
329 			}
330 
331 			bf = nbf;
332 		}
333 
334 		n = read(fd, bf + size, alloc_size - size);
335 		if (n < 0) {
336 			if (size) {
337 				pr_warning("read failed %d: %s\n", errno,
338 					 strerror_r(errno, sbuf, sizeof(sbuf)));
339 				err = 0;
340 			} else
341 				err = -errno;
342 
343 			break;
344 		}
345 
346 		size += n;
347 	} while (n > 0);
348 
349 	if (!err) {
350 		*sizep = size;
351 		*buf   = bf;
352 	} else
353 		free(bf);
354 
355 	close(fd);
356 	return err;
357 }
358 
359 int procfs__read_str(const char *entry, char **buf, size_t *sizep)
360 {
361 	char path[PATH_MAX];
362 	const char *procfs = procfs__mountpoint();
363 
364 	if (!procfs)
365 		return -1;
366 
367 	snprintf(path, sizeof(path), "%s/%s", procfs, entry);
368 
369 	return filename__read_str(path, buf, sizep);
370 }
371 
372 int sysfs__read_ull(const char *entry, unsigned long long *value)
373 {
374 	char path[PATH_MAX];
375 	const char *sysfs = sysfs__mountpoint();
376 
377 	if (!sysfs)
378 		return -1;
379 
380 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
381 
382 	return filename__read_ull(path, value);
383 }
384 
385 int sysfs__read_int(const char *entry, int *value)
386 {
387 	char path[PATH_MAX];
388 	const char *sysfs = sysfs__mountpoint();
389 
390 	if (!sysfs)
391 		return -1;
392 
393 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
394 
395 	return filename__read_int(path, value);
396 }
397 
398 int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
399 {
400 	char path[PATH_MAX];
401 	const char *sysfs = sysfs__mountpoint();
402 
403 	if (!sysfs)
404 		return -1;
405 
406 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
407 
408 	return filename__read_str(path, buf, sizep);
409 }
410 
411 int sysctl__read_int(const char *sysctl, int *value)
412 {
413 	char path[PATH_MAX];
414 	const char *procfs = procfs__mountpoint();
415 
416 	if (!procfs)
417 		return -1;
418 
419 	snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
420 
421 	return filename__read_int(path, value);
422 }
423