xref: /OK3568_Linux_fs/kernel/tools/lib/api/fs/fs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun #include <ctype.h>
3*4882a593Smuzhiyun #include <errno.h>
4*4882a593Smuzhiyun #include <limits.h>
5*4882a593Smuzhiyun #include <stdbool.h>
6*4882a593Smuzhiyun #include <stdio.h>
7*4882a593Smuzhiyun #include <stdlib.h>
8*4882a593Smuzhiyun #include <string.h>
9*4882a593Smuzhiyun #include <sys/vfs.h>
10*4882a593Smuzhiyun #include <sys/types.h>
11*4882a593Smuzhiyun #include <sys/stat.h>
12*4882a593Smuzhiyun #include <fcntl.h>
13*4882a593Smuzhiyun #include <unistd.h>
14*4882a593Smuzhiyun #include <sys/mount.h>
15*4882a593Smuzhiyun 
16*4882a593Smuzhiyun #include "fs.h"
17*4882a593Smuzhiyun #include "debug-internal.h"
18*4882a593Smuzhiyun 
19*4882a593Smuzhiyun #define _STR(x) #x
20*4882a593Smuzhiyun #define STR(x) _STR(x)
21*4882a593Smuzhiyun 
22*4882a593Smuzhiyun #ifndef SYSFS_MAGIC
23*4882a593Smuzhiyun #define SYSFS_MAGIC            0x62656572
24*4882a593Smuzhiyun #endif
25*4882a593Smuzhiyun 
26*4882a593Smuzhiyun #ifndef PROC_SUPER_MAGIC
27*4882a593Smuzhiyun #define PROC_SUPER_MAGIC       0x9fa0
28*4882a593Smuzhiyun #endif
29*4882a593Smuzhiyun 
30*4882a593Smuzhiyun #ifndef DEBUGFS_MAGIC
31*4882a593Smuzhiyun #define DEBUGFS_MAGIC          0x64626720
32*4882a593Smuzhiyun #endif
33*4882a593Smuzhiyun 
34*4882a593Smuzhiyun #ifndef TRACEFS_MAGIC
35*4882a593Smuzhiyun #define TRACEFS_MAGIC          0x74726163
36*4882a593Smuzhiyun #endif
37*4882a593Smuzhiyun 
38*4882a593Smuzhiyun #ifndef HUGETLBFS_MAGIC
39*4882a593Smuzhiyun #define HUGETLBFS_MAGIC        0x958458f6
40*4882a593Smuzhiyun #endif
41*4882a593Smuzhiyun 
42*4882a593Smuzhiyun #ifndef BPF_FS_MAGIC
43*4882a593Smuzhiyun #define BPF_FS_MAGIC           0xcafe4a11
44*4882a593Smuzhiyun #endif
45*4882a593Smuzhiyun 
46*4882a593Smuzhiyun static const char * const sysfs__fs_known_mountpoints[] = {
47*4882a593Smuzhiyun 	"/sys",
48*4882a593Smuzhiyun 	0,
49*4882a593Smuzhiyun };
50*4882a593Smuzhiyun 
51*4882a593Smuzhiyun static const char * const procfs__known_mountpoints[] = {
52*4882a593Smuzhiyun 	"/proc",
53*4882a593Smuzhiyun 	0,
54*4882a593Smuzhiyun };
55*4882a593Smuzhiyun 
56*4882a593Smuzhiyun #ifndef DEBUGFS_DEFAULT_PATH
57*4882a593Smuzhiyun #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
58*4882a593Smuzhiyun #endif
59*4882a593Smuzhiyun 
60*4882a593Smuzhiyun static const char * const debugfs__known_mountpoints[] = {
61*4882a593Smuzhiyun 	DEBUGFS_DEFAULT_PATH,
62*4882a593Smuzhiyun 	"/debug",
63*4882a593Smuzhiyun 	0,
64*4882a593Smuzhiyun };
65*4882a593Smuzhiyun 
66*4882a593Smuzhiyun 
67*4882a593Smuzhiyun #ifndef TRACEFS_DEFAULT_PATH
68*4882a593Smuzhiyun #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
69*4882a593Smuzhiyun #endif
70*4882a593Smuzhiyun 
71*4882a593Smuzhiyun static const char * const tracefs__known_mountpoints[] = {
72*4882a593Smuzhiyun 	TRACEFS_DEFAULT_PATH,
73*4882a593Smuzhiyun 	"/sys/kernel/debug/tracing",
74*4882a593Smuzhiyun 	"/tracing",
75*4882a593Smuzhiyun 	"/trace",
76*4882a593Smuzhiyun 	0,
77*4882a593Smuzhiyun };
78*4882a593Smuzhiyun 
79*4882a593Smuzhiyun static const char * const hugetlbfs__known_mountpoints[] = {
80*4882a593Smuzhiyun 	0,
81*4882a593Smuzhiyun };
82*4882a593Smuzhiyun 
83*4882a593Smuzhiyun static const char * const bpf_fs__known_mountpoints[] = {
84*4882a593Smuzhiyun 	"/sys/fs/bpf",
85*4882a593Smuzhiyun 	0,
86*4882a593Smuzhiyun };
87*4882a593Smuzhiyun 
88*4882a593Smuzhiyun struct fs {
89*4882a593Smuzhiyun 	const char		*name;
90*4882a593Smuzhiyun 	const char * const	*mounts;
91*4882a593Smuzhiyun 	char			 path[PATH_MAX];
92*4882a593Smuzhiyun 	bool			 found;
93*4882a593Smuzhiyun 	bool			 checked;
94*4882a593Smuzhiyun 	long			 magic;
95*4882a593Smuzhiyun };
96*4882a593Smuzhiyun 
97*4882a593Smuzhiyun enum {
98*4882a593Smuzhiyun 	FS__SYSFS   = 0,
99*4882a593Smuzhiyun 	FS__PROCFS  = 1,
100*4882a593Smuzhiyun 	FS__DEBUGFS = 2,
101*4882a593Smuzhiyun 	FS__TRACEFS = 3,
102*4882a593Smuzhiyun 	FS__HUGETLBFS = 4,
103*4882a593Smuzhiyun 	FS__BPF_FS = 5,
104*4882a593Smuzhiyun };
105*4882a593Smuzhiyun 
106*4882a593Smuzhiyun #ifndef TRACEFS_MAGIC
107*4882a593Smuzhiyun #define TRACEFS_MAGIC 0x74726163
108*4882a593Smuzhiyun #endif
109*4882a593Smuzhiyun 
110*4882a593Smuzhiyun static struct fs fs__entries[] = {
111*4882a593Smuzhiyun 	[FS__SYSFS] = {
112*4882a593Smuzhiyun 		.name	= "sysfs",
113*4882a593Smuzhiyun 		.mounts	= sysfs__fs_known_mountpoints,
114*4882a593Smuzhiyun 		.magic	= SYSFS_MAGIC,
115*4882a593Smuzhiyun 		.checked = false,
116*4882a593Smuzhiyun 	},
117*4882a593Smuzhiyun 	[FS__PROCFS] = {
118*4882a593Smuzhiyun 		.name	= "proc",
119*4882a593Smuzhiyun 		.mounts	= procfs__known_mountpoints,
120*4882a593Smuzhiyun 		.magic	= PROC_SUPER_MAGIC,
121*4882a593Smuzhiyun 		.checked = false,
122*4882a593Smuzhiyun 	},
123*4882a593Smuzhiyun 	[FS__DEBUGFS] = {
124*4882a593Smuzhiyun 		.name	= "debugfs",
125*4882a593Smuzhiyun 		.mounts	= debugfs__known_mountpoints,
126*4882a593Smuzhiyun 		.magic	= DEBUGFS_MAGIC,
127*4882a593Smuzhiyun 		.checked = false,
128*4882a593Smuzhiyun 	},
129*4882a593Smuzhiyun 	[FS__TRACEFS] = {
130*4882a593Smuzhiyun 		.name	= "tracefs",
131*4882a593Smuzhiyun 		.mounts	= tracefs__known_mountpoints,
132*4882a593Smuzhiyun 		.magic	= TRACEFS_MAGIC,
133*4882a593Smuzhiyun 		.checked = false,
134*4882a593Smuzhiyun 	},
135*4882a593Smuzhiyun 	[FS__HUGETLBFS] = {
136*4882a593Smuzhiyun 		.name	= "hugetlbfs",
137*4882a593Smuzhiyun 		.mounts = hugetlbfs__known_mountpoints,
138*4882a593Smuzhiyun 		.magic	= HUGETLBFS_MAGIC,
139*4882a593Smuzhiyun 		.checked = false,
140*4882a593Smuzhiyun 	},
141*4882a593Smuzhiyun 	[FS__BPF_FS] = {
142*4882a593Smuzhiyun 		.name	= "bpf",
143*4882a593Smuzhiyun 		.mounts = bpf_fs__known_mountpoints,
144*4882a593Smuzhiyun 		.magic	= BPF_FS_MAGIC,
145*4882a593Smuzhiyun 		.checked = false,
146*4882a593Smuzhiyun 	},
147*4882a593Smuzhiyun };
148*4882a593Smuzhiyun 
fs__read_mounts(struct fs * fs)149*4882a593Smuzhiyun static bool fs__read_mounts(struct fs *fs)
150*4882a593Smuzhiyun {
151*4882a593Smuzhiyun 	bool found = false;
152*4882a593Smuzhiyun 	char type[100];
153*4882a593Smuzhiyun 	FILE *fp;
154*4882a593Smuzhiyun 
155*4882a593Smuzhiyun 	fp = fopen("/proc/mounts", "r");
156*4882a593Smuzhiyun 	if (fp == NULL)
157*4882a593Smuzhiyun 		return NULL;
158*4882a593Smuzhiyun 
159*4882a593Smuzhiyun 	while (!found &&
160*4882a593Smuzhiyun 	       fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
161*4882a593Smuzhiyun 		      fs->path, type) == 2) {
162*4882a593Smuzhiyun 
163*4882a593Smuzhiyun 		if (strcmp(type, fs->name) == 0)
164*4882a593Smuzhiyun 			found = true;
165*4882a593Smuzhiyun 	}
166*4882a593Smuzhiyun 
167*4882a593Smuzhiyun 	fclose(fp);
168*4882a593Smuzhiyun 	fs->checked = true;
169*4882a593Smuzhiyun 	return fs->found = found;
170*4882a593Smuzhiyun }
171*4882a593Smuzhiyun 
fs__valid_mount(const char * fs,long magic)172*4882a593Smuzhiyun static int fs__valid_mount(const char *fs, long magic)
173*4882a593Smuzhiyun {
174*4882a593Smuzhiyun 	struct statfs st_fs;
175*4882a593Smuzhiyun 
176*4882a593Smuzhiyun 	if (statfs(fs, &st_fs) < 0)
177*4882a593Smuzhiyun 		return -ENOENT;
178*4882a593Smuzhiyun 	else if ((long)st_fs.f_type != magic)
179*4882a593Smuzhiyun 		return -ENOENT;
180*4882a593Smuzhiyun 
181*4882a593Smuzhiyun 	return 0;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun 
fs__check_mounts(struct fs * fs)184*4882a593Smuzhiyun static bool fs__check_mounts(struct fs *fs)
185*4882a593Smuzhiyun {
186*4882a593Smuzhiyun 	const char * const *ptr;
187*4882a593Smuzhiyun 
188*4882a593Smuzhiyun 	ptr = fs->mounts;
189*4882a593Smuzhiyun 	while (*ptr) {
190*4882a593Smuzhiyun 		if (fs__valid_mount(*ptr, fs->magic) == 0) {
191*4882a593Smuzhiyun 			fs->found = true;
192*4882a593Smuzhiyun 			strcpy(fs->path, *ptr);
193*4882a593Smuzhiyun 			return true;
194*4882a593Smuzhiyun 		}
195*4882a593Smuzhiyun 		ptr++;
196*4882a593Smuzhiyun 	}
197*4882a593Smuzhiyun 
198*4882a593Smuzhiyun 	return false;
199*4882a593Smuzhiyun }
200*4882a593Smuzhiyun 
mem_toupper(char * f,size_t len)201*4882a593Smuzhiyun static void mem_toupper(char *f, size_t len)
202*4882a593Smuzhiyun {
203*4882a593Smuzhiyun 	while (len) {
204*4882a593Smuzhiyun 		*f = toupper(*f);
205*4882a593Smuzhiyun 		f++;
206*4882a593Smuzhiyun 		len--;
207*4882a593Smuzhiyun 	}
208*4882a593Smuzhiyun }
209*4882a593Smuzhiyun 
210*4882a593Smuzhiyun /*
211*4882a593Smuzhiyun  * Check for "NAME_PATH" environment variable to override fs location (for
212*4882a593Smuzhiyun  * testing). This matches the recommendation in Documentation/admin-guide/sysfs-rules.rst
213*4882a593Smuzhiyun  * for SYSFS_PATH.
214*4882a593Smuzhiyun  */
fs__env_override(struct fs * fs)215*4882a593Smuzhiyun static bool fs__env_override(struct fs *fs)
216*4882a593Smuzhiyun {
217*4882a593Smuzhiyun 	char *override_path;
218*4882a593Smuzhiyun 	size_t name_len = strlen(fs->name);
219*4882a593Smuzhiyun 	/* name + "_PATH" + '\0' */
220*4882a593Smuzhiyun 	char upper_name[name_len + 5 + 1];
221*4882a593Smuzhiyun 
222*4882a593Smuzhiyun 	memcpy(upper_name, fs->name, name_len);
223*4882a593Smuzhiyun 	mem_toupper(upper_name, name_len);
224*4882a593Smuzhiyun 	strcpy(&upper_name[name_len], "_PATH");
225*4882a593Smuzhiyun 
226*4882a593Smuzhiyun 	override_path = getenv(upper_name);
227*4882a593Smuzhiyun 	if (!override_path)
228*4882a593Smuzhiyun 		return false;
229*4882a593Smuzhiyun 
230*4882a593Smuzhiyun 	fs->found = true;
231*4882a593Smuzhiyun 	fs->checked = true;
232*4882a593Smuzhiyun 	strncpy(fs->path, override_path, sizeof(fs->path) - 1);
233*4882a593Smuzhiyun 	fs->path[sizeof(fs->path) - 1] = '\0';
234*4882a593Smuzhiyun 	return true;
235*4882a593Smuzhiyun }
236*4882a593Smuzhiyun 
fs__get_mountpoint(struct fs * fs)237*4882a593Smuzhiyun static const char *fs__get_mountpoint(struct fs *fs)
238*4882a593Smuzhiyun {
239*4882a593Smuzhiyun 	if (fs__env_override(fs))
240*4882a593Smuzhiyun 		return fs->path;
241*4882a593Smuzhiyun 
242*4882a593Smuzhiyun 	if (fs__check_mounts(fs))
243*4882a593Smuzhiyun 		return fs->path;
244*4882a593Smuzhiyun 
245*4882a593Smuzhiyun 	if (fs__read_mounts(fs))
246*4882a593Smuzhiyun 		return fs->path;
247*4882a593Smuzhiyun 
248*4882a593Smuzhiyun 	return NULL;
249*4882a593Smuzhiyun }
250*4882a593Smuzhiyun 
fs__mountpoint(int idx)251*4882a593Smuzhiyun static const char *fs__mountpoint(int idx)
252*4882a593Smuzhiyun {
253*4882a593Smuzhiyun 	struct fs *fs = &fs__entries[idx];
254*4882a593Smuzhiyun 
255*4882a593Smuzhiyun 	if (fs->found)
256*4882a593Smuzhiyun 		return (const char *)fs->path;
257*4882a593Smuzhiyun 
258*4882a593Smuzhiyun 	/* the mount point was already checked for the mount point
259*4882a593Smuzhiyun 	 * but and did not exist, so return NULL to avoid scanning again.
260*4882a593Smuzhiyun 	 * This makes the found and not found paths cost equivalent
261*4882a593Smuzhiyun 	 * in case of multiple calls.
262*4882a593Smuzhiyun 	 */
263*4882a593Smuzhiyun 	if (fs->checked)
264*4882a593Smuzhiyun 		return NULL;
265*4882a593Smuzhiyun 
266*4882a593Smuzhiyun 	return fs__get_mountpoint(fs);
267*4882a593Smuzhiyun }
268*4882a593Smuzhiyun 
mount_overload(struct fs * fs)269*4882a593Smuzhiyun static const char *mount_overload(struct fs *fs)
270*4882a593Smuzhiyun {
271*4882a593Smuzhiyun 	size_t name_len = strlen(fs->name);
272*4882a593Smuzhiyun 	/* "PERF_" + name + "_ENVIRONMENT" + '\0' */
273*4882a593Smuzhiyun 	char upper_name[5 + name_len + 12 + 1];
274*4882a593Smuzhiyun 
275*4882a593Smuzhiyun 	snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
276*4882a593Smuzhiyun 	mem_toupper(upper_name, name_len);
277*4882a593Smuzhiyun 
278*4882a593Smuzhiyun 	return getenv(upper_name) ?: *fs->mounts;
279*4882a593Smuzhiyun }
280*4882a593Smuzhiyun 
fs__mount(int idx)281*4882a593Smuzhiyun static const char *fs__mount(int idx)
282*4882a593Smuzhiyun {
283*4882a593Smuzhiyun 	struct fs *fs = &fs__entries[idx];
284*4882a593Smuzhiyun 	const char *mountpoint;
285*4882a593Smuzhiyun 
286*4882a593Smuzhiyun 	if (fs__mountpoint(idx))
287*4882a593Smuzhiyun 		return (const char *)fs->path;
288*4882a593Smuzhiyun 
289*4882a593Smuzhiyun 	mountpoint = mount_overload(fs);
290*4882a593Smuzhiyun 
291*4882a593Smuzhiyun 	if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
292*4882a593Smuzhiyun 		return NULL;
293*4882a593Smuzhiyun 
294*4882a593Smuzhiyun 	return fs__check_mounts(fs) ? fs->path : NULL;
295*4882a593Smuzhiyun }
296*4882a593Smuzhiyun 
297*4882a593Smuzhiyun #define FS(name, idx)				\
298*4882a593Smuzhiyun const char *name##__mountpoint(void)		\
299*4882a593Smuzhiyun {						\
300*4882a593Smuzhiyun 	return fs__mountpoint(idx);		\
301*4882a593Smuzhiyun }						\
302*4882a593Smuzhiyun 						\
303*4882a593Smuzhiyun const char *name##__mount(void)			\
304*4882a593Smuzhiyun {						\
305*4882a593Smuzhiyun 	return fs__mount(idx);			\
306*4882a593Smuzhiyun }						\
307*4882a593Smuzhiyun 						\
308*4882a593Smuzhiyun bool name##__configured(void)			\
309*4882a593Smuzhiyun {						\
310*4882a593Smuzhiyun 	return name##__mountpoint() != NULL;	\
311*4882a593Smuzhiyun }
312*4882a593Smuzhiyun 
313*4882a593Smuzhiyun FS(sysfs,   FS__SYSFS);
314*4882a593Smuzhiyun FS(procfs,  FS__PROCFS);
315*4882a593Smuzhiyun FS(debugfs, FS__DEBUGFS);
316*4882a593Smuzhiyun FS(tracefs, FS__TRACEFS);
317*4882a593Smuzhiyun FS(hugetlbfs, FS__HUGETLBFS);
318*4882a593Smuzhiyun FS(bpf_fs, FS__BPF_FS);
319*4882a593Smuzhiyun 
filename__read_int(const char * filename,int * value)320*4882a593Smuzhiyun int filename__read_int(const char *filename, int *value)
321*4882a593Smuzhiyun {
322*4882a593Smuzhiyun 	char line[64];
323*4882a593Smuzhiyun 	int fd = open(filename, O_RDONLY), err = -1;
324*4882a593Smuzhiyun 
325*4882a593Smuzhiyun 	if (fd < 0)
326*4882a593Smuzhiyun 		return -1;
327*4882a593Smuzhiyun 
328*4882a593Smuzhiyun 	if (read(fd, line, sizeof(line)) > 0) {
329*4882a593Smuzhiyun 		*value = atoi(line);
330*4882a593Smuzhiyun 		err = 0;
331*4882a593Smuzhiyun 	}
332*4882a593Smuzhiyun 
333*4882a593Smuzhiyun 	close(fd);
334*4882a593Smuzhiyun 	return err;
335*4882a593Smuzhiyun }
336*4882a593Smuzhiyun 
filename__read_ull_base(const char * filename,unsigned long long * value,int base)337*4882a593Smuzhiyun static int filename__read_ull_base(const char *filename,
338*4882a593Smuzhiyun 				   unsigned long long *value, int base)
339*4882a593Smuzhiyun {
340*4882a593Smuzhiyun 	char line[64];
341*4882a593Smuzhiyun 	int fd = open(filename, O_RDONLY), err = -1;
342*4882a593Smuzhiyun 
343*4882a593Smuzhiyun 	if (fd < 0)
344*4882a593Smuzhiyun 		return -1;
345*4882a593Smuzhiyun 
346*4882a593Smuzhiyun 	if (read(fd, line, sizeof(line)) > 0) {
347*4882a593Smuzhiyun 		*value = strtoull(line, NULL, base);
348*4882a593Smuzhiyun 		if (*value != ULLONG_MAX)
349*4882a593Smuzhiyun 			err = 0;
350*4882a593Smuzhiyun 	}
351*4882a593Smuzhiyun 
352*4882a593Smuzhiyun 	close(fd);
353*4882a593Smuzhiyun 	return err;
354*4882a593Smuzhiyun }
355*4882a593Smuzhiyun 
356*4882a593Smuzhiyun /*
357*4882a593Smuzhiyun  * Parses @value out of @filename with strtoull.
358*4882a593Smuzhiyun  * By using 16 for base to treat the number as hex.
359*4882a593Smuzhiyun  */
filename__read_xll(const char * filename,unsigned long long * value)360*4882a593Smuzhiyun int filename__read_xll(const char *filename, unsigned long long *value)
361*4882a593Smuzhiyun {
362*4882a593Smuzhiyun 	return filename__read_ull_base(filename, value, 16);
363*4882a593Smuzhiyun }
364*4882a593Smuzhiyun 
365*4882a593Smuzhiyun /*
366*4882a593Smuzhiyun  * Parses @value out of @filename with strtoull.
367*4882a593Smuzhiyun  * By using 0 for base, the strtoull detects the
368*4882a593Smuzhiyun  * base automatically (see man strtoull).
369*4882a593Smuzhiyun  */
filename__read_ull(const char * filename,unsigned long long * value)370*4882a593Smuzhiyun int filename__read_ull(const char *filename, unsigned long long *value)
371*4882a593Smuzhiyun {
372*4882a593Smuzhiyun 	return filename__read_ull_base(filename, value, 0);
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun 
375*4882a593Smuzhiyun #define STRERR_BUFSIZE  128     /* For the buffer size of strerror_r */
376*4882a593Smuzhiyun 
filename__read_str(const char * filename,char ** buf,size_t * sizep)377*4882a593Smuzhiyun int filename__read_str(const char *filename, char **buf, size_t *sizep)
378*4882a593Smuzhiyun {
379*4882a593Smuzhiyun 	size_t size = 0, alloc_size = 0;
380*4882a593Smuzhiyun 	void *bf = NULL, *nbf;
381*4882a593Smuzhiyun 	int fd, n, err = 0;
382*4882a593Smuzhiyun 	char sbuf[STRERR_BUFSIZE];
383*4882a593Smuzhiyun 
384*4882a593Smuzhiyun 	fd = open(filename, O_RDONLY);
385*4882a593Smuzhiyun 	if (fd < 0)
386*4882a593Smuzhiyun 		return -errno;
387*4882a593Smuzhiyun 
388*4882a593Smuzhiyun 	do {
389*4882a593Smuzhiyun 		if (size == alloc_size) {
390*4882a593Smuzhiyun 			alloc_size += BUFSIZ;
391*4882a593Smuzhiyun 			nbf = realloc(bf, alloc_size);
392*4882a593Smuzhiyun 			if (!nbf) {
393*4882a593Smuzhiyun 				err = -ENOMEM;
394*4882a593Smuzhiyun 				break;
395*4882a593Smuzhiyun 			}
396*4882a593Smuzhiyun 
397*4882a593Smuzhiyun 			bf = nbf;
398*4882a593Smuzhiyun 		}
399*4882a593Smuzhiyun 
400*4882a593Smuzhiyun 		n = read(fd, bf + size, alloc_size - size);
401*4882a593Smuzhiyun 		if (n < 0) {
402*4882a593Smuzhiyun 			if (size) {
403*4882a593Smuzhiyun 				pr_warn("read failed %d: %s\n", errno,
404*4882a593Smuzhiyun 					strerror_r(errno, sbuf, sizeof(sbuf)));
405*4882a593Smuzhiyun 				err = 0;
406*4882a593Smuzhiyun 			} else
407*4882a593Smuzhiyun 				err = -errno;
408*4882a593Smuzhiyun 
409*4882a593Smuzhiyun 			break;
410*4882a593Smuzhiyun 		}
411*4882a593Smuzhiyun 
412*4882a593Smuzhiyun 		size += n;
413*4882a593Smuzhiyun 	} while (n > 0);
414*4882a593Smuzhiyun 
415*4882a593Smuzhiyun 	if (!err) {
416*4882a593Smuzhiyun 		*sizep = size;
417*4882a593Smuzhiyun 		*buf   = bf;
418*4882a593Smuzhiyun 	} else
419*4882a593Smuzhiyun 		free(bf);
420*4882a593Smuzhiyun 
421*4882a593Smuzhiyun 	close(fd);
422*4882a593Smuzhiyun 	return err;
423*4882a593Smuzhiyun }
424*4882a593Smuzhiyun 
filename__write_int(const char * filename,int value)425*4882a593Smuzhiyun int filename__write_int(const char *filename, int value)
426*4882a593Smuzhiyun {
427*4882a593Smuzhiyun 	int fd = open(filename, O_WRONLY), err = -1;
428*4882a593Smuzhiyun 	char buf[64];
429*4882a593Smuzhiyun 
430*4882a593Smuzhiyun 	if (fd < 0)
431*4882a593Smuzhiyun 		return err;
432*4882a593Smuzhiyun 
433*4882a593Smuzhiyun 	sprintf(buf, "%d", value);
434*4882a593Smuzhiyun 	if (write(fd, buf, sizeof(buf)) == sizeof(buf))
435*4882a593Smuzhiyun 		err = 0;
436*4882a593Smuzhiyun 
437*4882a593Smuzhiyun 	close(fd);
438*4882a593Smuzhiyun 	return err;
439*4882a593Smuzhiyun }
440*4882a593Smuzhiyun 
procfs__read_str(const char * entry,char ** buf,size_t * sizep)441*4882a593Smuzhiyun int procfs__read_str(const char *entry, char **buf, size_t *sizep)
442*4882a593Smuzhiyun {
443*4882a593Smuzhiyun 	char path[PATH_MAX];
444*4882a593Smuzhiyun 	const char *procfs = procfs__mountpoint();
445*4882a593Smuzhiyun 
446*4882a593Smuzhiyun 	if (!procfs)
447*4882a593Smuzhiyun 		return -1;
448*4882a593Smuzhiyun 
449*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "%s/%s", procfs, entry);
450*4882a593Smuzhiyun 
451*4882a593Smuzhiyun 	return filename__read_str(path, buf, sizep);
452*4882a593Smuzhiyun }
453*4882a593Smuzhiyun 
sysfs__read_ull_base(const char * entry,unsigned long long * value,int base)454*4882a593Smuzhiyun static int sysfs__read_ull_base(const char *entry,
455*4882a593Smuzhiyun 				unsigned long long *value, int base)
456*4882a593Smuzhiyun {
457*4882a593Smuzhiyun 	char path[PATH_MAX];
458*4882a593Smuzhiyun 	const char *sysfs = sysfs__mountpoint();
459*4882a593Smuzhiyun 
460*4882a593Smuzhiyun 	if (!sysfs)
461*4882a593Smuzhiyun 		return -1;
462*4882a593Smuzhiyun 
463*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
464*4882a593Smuzhiyun 
465*4882a593Smuzhiyun 	return filename__read_ull_base(path, value, base);
466*4882a593Smuzhiyun }
467*4882a593Smuzhiyun 
sysfs__read_xll(const char * entry,unsigned long long * value)468*4882a593Smuzhiyun int sysfs__read_xll(const char *entry, unsigned long long *value)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun 	return sysfs__read_ull_base(entry, value, 16);
471*4882a593Smuzhiyun }
472*4882a593Smuzhiyun 
sysfs__read_ull(const char * entry,unsigned long long * value)473*4882a593Smuzhiyun int sysfs__read_ull(const char *entry, unsigned long long *value)
474*4882a593Smuzhiyun {
475*4882a593Smuzhiyun 	return sysfs__read_ull_base(entry, value, 0);
476*4882a593Smuzhiyun }
477*4882a593Smuzhiyun 
sysfs__read_int(const char * entry,int * value)478*4882a593Smuzhiyun int sysfs__read_int(const char *entry, int *value)
479*4882a593Smuzhiyun {
480*4882a593Smuzhiyun 	char path[PATH_MAX];
481*4882a593Smuzhiyun 	const char *sysfs = sysfs__mountpoint();
482*4882a593Smuzhiyun 
483*4882a593Smuzhiyun 	if (!sysfs)
484*4882a593Smuzhiyun 		return -1;
485*4882a593Smuzhiyun 
486*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
487*4882a593Smuzhiyun 
488*4882a593Smuzhiyun 	return filename__read_int(path, value);
489*4882a593Smuzhiyun }
490*4882a593Smuzhiyun 
sysfs__read_str(const char * entry,char ** buf,size_t * sizep)491*4882a593Smuzhiyun int sysfs__read_str(const char *entry, char **buf, size_t *sizep)
492*4882a593Smuzhiyun {
493*4882a593Smuzhiyun 	char path[PATH_MAX];
494*4882a593Smuzhiyun 	const char *sysfs = sysfs__mountpoint();
495*4882a593Smuzhiyun 
496*4882a593Smuzhiyun 	if (!sysfs)
497*4882a593Smuzhiyun 		return -1;
498*4882a593Smuzhiyun 
499*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
500*4882a593Smuzhiyun 
501*4882a593Smuzhiyun 	return filename__read_str(path, buf, sizep);
502*4882a593Smuzhiyun }
503*4882a593Smuzhiyun 
sysfs__read_bool(const char * entry,bool * value)504*4882a593Smuzhiyun int sysfs__read_bool(const char *entry, bool *value)
505*4882a593Smuzhiyun {
506*4882a593Smuzhiyun 	char *buf;
507*4882a593Smuzhiyun 	size_t size;
508*4882a593Smuzhiyun 	int ret;
509*4882a593Smuzhiyun 
510*4882a593Smuzhiyun 	ret = sysfs__read_str(entry, &buf, &size);
511*4882a593Smuzhiyun 	if (ret < 0)
512*4882a593Smuzhiyun 		return ret;
513*4882a593Smuzhiyun 
514*4882a593Smuzhiyun 	switch (buf[0]) {
515*4882a593Smuzhiyun 	case '1':
516*4882a593Smuzhiyun 	case 'y':
517*4882a593Smuzhiyun 	case 'Y':
518*4882a593Smuzhiyun 		*value = true;
519*4882a593Smuzhiyun 		break;
520*4882a593Smuzhiyun 	case '0':
521*4882a593Smuzhiyun 	case 'n':
522*4882a593Smuzhiyun 	case 'N':
523*4882a593Smuzhiyun 		*value = false;
524*4882a593Smuzhiyun 		break;
525*4882a593Smuzhiyun 	default:
526*4882a593Smuzhiyun 		ret = -1;
527*4882a593Smuzhiyun 	}
528*4882a593Smuzhiyun 
529*4882a593Smuzhiyun 	free(buf);
530*4882a593Smuzhiyun 
531*4882a593Smuzhiyun 	return ret;
532*4882a593Smuzhiyun }
sysctl__read_int(const char * sysctl,int * value)533*4882a593Smuzhiyun int sysctl__read_int(const char *sysctl, int *value)
534*4882a593Smuzhiyun {
535*4882a593Smuzhiyun 	char path[PATH_MAX];
536*4882a593Smuzhiyun 	const char *procfs = procfs__mountpoint();
537*4882a593Smuzhiyun 
538*4882a593Smuzhiyun 	if (!procfs)
539*4882a593Smuzhiyun 		return -1;
540*4882a593Smuzhiyun 
541*4882a593Smuzhiyun 	snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
542*4882a593Smuzhiyun 
543*4882a593Smuzhiyun 	return filename__read_int(path, value);
544*4882a593Smuzhiyun }
545*4882a593Smuzhiyun 
sysfs__write_int(const char * entry,int value)546*4882a593Smuzhiyun int sysfs__write_int(const char *entry, int value)
547*4882a593Smuzhiyun {
548*4882a593Smuzhiyun 	char path[PATH_MAX];
549*4882a593Smuzhiyun 	const char *sysfs = sysfs__mountpoint();
550*4882a593Smuzhiyun 
551*4882a593Smuzhiyun 	if (!sysfs)
552*4882a593Smuzhiyun 		return -1;
553*4882a593Smuzhiyun 
554*4882a593Smuzhiyun 	if (snprintf(path, sizeof(path), "%s/%s", sysfs, entry) >= PATH_MAX)
555*4882a593Smuzhiyun 		return -1;
556*4882a593Smuzhiyun 
557*4882a593Smuzhiyun 	return filename__write_int(path, value);
558*4882a593Smuzhiyun }
559