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