blob: 798052cbc7c006faf066c3e2ca474701d4c2cc0e [file] [log] [blame]
Cody P Schaferf2d96272014-05-27 17:21:56 -07001#include <ctype.h>
Borislav Petkovcd0cfad2013-12-09 17:14:24 +01002#include <errno.h>
3#include <stdbool.h>
4#include <stdio.h>
Cody P Schaferf2d96272014-05-27 17:21:56 -07005#include <stdlib.h>
Borislav Petkovcd0cfad2013-12-09 17:14:24 +01006#include <string.h>
7#include <sys/vfs.h>
Arnaldo Carvalho de Melo3a351122014-12-11 13:17:46 -03008#include <sys/types.h>
9#include <sys/stat.h>
10#include <fcntl.h>
11#include <unistd.h>
Jiri Olsa4299a542013-11-05 15:14:45 +010012
Borislav Petkovcd0cfad2013-12-09 17:14:24 +010013#include "debugfs.h"
14#include "fs.h"
Jiri Olsa4299a542013-11-05 15:14:45 +010015
Jiri Olsab86b0d32015-09-02 09:56:37 +020016#define _STR(x) #x
17#define STR(x) _STR(x)
18
Jiri Olsa41e3a1f2015-09-02 09:56:38 +020019#ifndef SYSFS_MAGIC
20#define SYSFS_MAGIC 0x62656572
21#endif
22
23#ifndef PROC_SUPER_MAGIC
24#define PROC_SUPER_MAGIC 0x9fa0
25#endif
26
Jiri Olsa8ccfabd2015-09-02 09:56:39 +020027#ifndef DEBUGFS_MAGIC
28#define DEBUGFS_MAGIC 0x64626720
29#endif
30
Jiri Olsa4299a542013-11-05 15:14:45 +010031static const char * const sysfs__fs_known_mountpoints[] = {
32 "/sys",
33 0,
34};
35
Jiri Olsaa9862412013-11-05 15:14:46 +010036static const char * const procfs__known_mountpoints[] = {
37 "/proc",
38 0,
39};
40
Jiri Olsa8ccfabd2015-09-02 09:56:39 +020041#ifndef DEBUGFS_DEFAULT_PATH
42#define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
43#endif
44
45static const char * const debugfs__known_mountpoints[] = {
46 DEBUGFS_DEFAULT_PATH,
47 "/debug",
48 0,
49};
50
Jiri Olsa4299a542013-11-05 15:14:45 +010051struct fs {
52 const char *name;
53 const char * const *mounts;
54 char path[PATH_MAX + 1];
55 bool found;
56 long magic;
57};
58
59enum {
Jiri Olsa8ccfabd2015-09-02 09:56:39 +020060 FS__SYSFS = 0,
61 FS__PROCFS = 1,
62 FS__DEBUGFS = 2,
Jiri Olsa4299a542013-11-05 15:14:45 +010063};
64
65static struct fs fs__entries[] = {
66 [FS__SYSFS] = {
67 .name = "sysfs",
68 .mounts = sysfs__fs_known_mountpoints,
69 .magic = SYSFS_MAGIC,
70 },
Jiri Olsaa9862412013-11-05 15:14:46 +010071 [FS__PROCFS] = {
72 .name = "proc",
73 .mounts = procfs__known_mountpoints,
74 .magic = PROC_SUPER_MAGIC,
75 },
Jiri Olsa8ccfabd2015-09-02 09:56:39 +020076 [FS__DEBUGFS] = {
77 .name = "debugfs",
78 .mounts = debugfs__known_mountpoints,
79 .magic = DEBUGFS_MAGIC,
80 },
Jiri Olsa4299a542013-11-05 15:14:45 +010081};
82
83static bool fs__read_mounts(struct fs *fs)
84{
85 bool found = false;
86 char type[100];
87 FILE *fp;
88
89 fp = fopen("/proc/mounts", "r");
90 if (fp == NULL)
91 return NULL;
92
93 while (!found &&
94 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
95 fs->path, type) == 2) {
96
97 if (strcmp(type, fs->name) == 0)
98 found = true;
99 }
100
101 fclose(fp);
102 return fs->found = found;
103}
104
105static int fs__valid_mount(const char *fs, long magic)
106{
107 struct statfs st_fs;
108
109 if (statfs(fs, &st_fs) < 0)
110 return -ENOENT;
Alexey Brodkindb1806e2015-01-10 16:40:50 +0530111 else if ((long)st_fs.f_type != magic)
Jiri Olsa4299a542013-11-05 15:14:45 +0100112 return -ENOENT;
113
114 return 0;
115}
116
117static bool fs__check_mounts(struct fs *fs)
118{
119 const char * const *ptr;
120
121 ptr = fs->mounts;
122 while (*ptr) {
123 if (fs__valid_mount(*ptr, fs->magic) == 0) {
124 fs->found = true;
125 strcpy(fs->path, *ptr);
126 return true;
127 }
128 ptr++;
129 }
130
131 return false;
132}
133
Cody P Schaferf2d96272014-05-27 17:21:56 -0700134static void mem_toupper(char *f, size_t len)
135{
136 while (len) {
137 *f = toupper(*f);
138 f++;
139 len--;
140 }
141}
142
143/*
144 * Check for "NAME_PATH" environment variable to override fs location (for
145 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
146 * for SYSFS_PATH.
147 */
148static bool fs__env_override(struct fs *fs)
149{
150 char *override_path;
151 size_t name_len = strlen(fs->name);
152 /* name + "_PATH" + '\0' */
153 char upper_name[name_len + 5 + 1];
154 memcpy(upper_name, fs->name, name_len);
155 mem_toupper(upper_name, name_len);
156 strcpy(&upper_name[name_len], "_PATH");
157
158 override_path = getenv(upper_name);
159 if (!override_path)
160 return false;
161
162 fs->found = true;
163 strncpy(fs->path, override_path, sizeof(fs->path));
164 return true;
165}
166
Jiri Olsa4299a542013-11-05 15:14:45 +0100167static const char *fs__get_mountpoint(struct fs *fs)
168{
Cody P Schaferf2d96272014-05-27 17:21:56 -0700169 if (fs__env_override(fs))
170 return fs->path;
171
Jiri Olsa4299a542013-11-05 15:14:45 +0100172 if (fs__check_mounts(fs))
173 return fs->path;
174
Cody P Schaferf2d96272014-05-27 17:21:56 -0700175 if (fs__read_mounts(fs))
176 return fs->path;
177
178 return NULL;
Jiri Olsa4299a542013-11-05 15:14:45 +0100179}
180
Arnaldo Carvalho de Melocf38fad2013-11-05 14:48:50 -0300181static const char *fs__mountpoint(int idx)
Jiri Olsa4299a542013-11-05 15:14:45 +0100182{
183 struct fs *fs = &fs__entries[idx];
184
185 if (fs->found)
186 return (const char *)fs->path;
187
188 return fs__get_mountpoint(fs);
189}
190
Arnaldo Carvalho de Melocf38fad2013-11-05 14:48:50 -0300191#define FS__MOUNTPOINT(name, idx) \
192const char *name##__mountpoint(void) \
193{ \
194 return fs__mountpoint(idx); \
Jiri Olsa4299a542013-11-05 15:14:45 +0100195}
196
Jiri Olsa8ccfabd2015-09-02 09:56:39 +0200197FS__MOUNTPOINT(sysfs, FS__SYSFS);
198FS__MOUNTPOINT(procfs, FS__PROCFS);
199FS__MOUNTPOINT(debugfs, FS__DEBUGFS);
Arnaldo Carvalho de Melo3a351122014-12-11 13:17:46 -0300200
201int filename__read_int(const char *filename, int *value)
202{
203 char line[64];
204 int fd = open(filename, O_RDONLY), err = -1;
205
206 if (fd < 0)
207 return -1;
208
209 if (read(fd, line, sizeof(line)) > 0) {
210 *value = atoi(line);
211 err = 0;
212 }
213
214 close(fd);
215 return err;
216}
Arnaldo Carvalho de Melo42e3c4a2014-12-11 13:37:10 -0300217
218int sysctl__read_int(const char *sysctl, int *value)
219{
220 char path[PATH_MAX];
221 const char *procfs = procfs__mountpoint();
222
223 if (!procfs)
224 return -1;
225
226 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
227
228 return filename__read_int(path, value);
229}