blob: 0700eb953495196bc9f46cecc2557611574f9a3d [file] [log] [blame]
Borislav Petkovcd0cfad2013-12-09 17:14:24 +01001/* TODO merge/factor in debugfs.c here */
Jiri Olsa4299a542013-11-05 15:14:45 +01002
Cody P Schaferf2d96272014-05-27 17:21:56 -07003#include <ctype.h>
Borislav Petkovcd0cfad2013-12-09 17:14:24 +01004#include <errno.h>
5#include <stdbool.h>
6#include <stdio.h>
Cody P Schaferf2d96272014-05-27 17:21:56 -07007#include <stdlib.h>
Borislav Petkovcd0cfad2013-12-09 17:14:24 +01008#include <string.h>
9#include <sys/vfs.h>
Arnaldo Carvalho de Melo3a351122014-12-11 13:17:46 -030010#include <sys/types.h>
11#include <sys/stat.h>
12#include <fcntl.h>
13#include <unistd.h>
Jiri Olsa4299a542013-11-05 15:14:45 +010014
Borislav Petkovcd0cfad2013-12-09 17:14:24 +010015#include "debugfs.h"
16#include "fs.h"
Jiri Olsa4299a542013-11-05 15:14:45 +010017
Jiri Olsab86b0d32015-09-02 09:56:37 +020018#define _STR(x) #x
19#define STR(x) _STR(x)
20
Jiri Olsa41e3a1f2015-09-02 09:56:38 +020021#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
Jiri Olsa4299a542013-11-05 15:14:45 +010029static const char * const sysfs__fs_known_mountpoints[] = {
30 "/sys",
31 0,
32};
33
Jiri Olsaa9862412013-11-05 15:14:46 +010034static const char * const procfs__known_mountpoints[] = {
35 "/proc",
36 0,
37};
38
Jiri Olsa4299a542013-11-05 15:14:45 +010039struct fs {
40 const char *name;
41 const char * const *mounts;
42 char path[PATH_MAX + 1];
43 bool found;
44 long magic;
45};
46
47enum {
Jiri Olsaa9862412013-11-05 15:14:46 +010048 FS__SYSFS = 0,
49 FS__PROCFS = 1,
Jiri Olsa4299a542013-11-05 15:14:45 +010050};
51
52static struct fs fs__entries[] = {
53 [FS__SYSFS] = {
54 .name = "sysfs",
55 .mounts = sysfs__fs_known_mountpoints,
56 .magic = SYSFS_MAGIC,
57 },
Jiri Olsaa9862412013-11-05 15:14:46 +010058 [FS__PROCFS] = {
59 .name = "proc",
60 .mounts = procfs__known_mountpoints,
61 .magic = PROC_SUPER_MAGIC,
62 },
Jiri Olsa4299a542013-11-05 15:14:45 +010063};
64
65static bool fs__read_mounts(struct fs *fs)
66{
67 bool found = false;
68 char type[100];
69 FILE *fp;
70
71 fp = fopen("/proc/mounts", "r");
72 if (fp == NULL)
73 return NULL;
74
75 while (!found &&
76 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
77 fs->path, type) == 2) {
78
79 if (strcmp(type, fs->name) == 0)
80 found = true;
81 }
82
83 fclose(fp);
84 return fs->found = found;
85}
86
87static int fs__valid_mount(const char *fs, long magic)
88{
89 struct statfs st_fs;
90
91 if (statfs(fs, &st_fs) < 0)
92 return -ENOENT;
Alexey Brodkindb1806e2015-01-10 16:40:50 +053093 else if ((long)st_fs.f_type != magic)
Jiri Olsa4299a542013-11-05 15:14:45 +010094 return -ENOENT;
95
96 return 0;
97}
98
99static bool fs__check_mounts(struct fs *fs)
100{
101 const char * const *ptr;
102
103 ptr = fs->mounts;
104 while (*ptr) {
105 if (fs__valid_mount(*ptr, fs->magic) == 0) {
106 fs->found = true;
107 strcpy(fs->path, *ptr);
108 return true;
109 }
110 ptr++;
111 }
112
113 return false;
114}
115
Cody P Schaferf2d96272014-05-27 17:21:56 -0700116static void mem_toupper(char *f, size_t len)
117{
118 while (len) {
119 *f = toupper(*f);
120 f++;
121 len--;
122 }
123}
124
125/*
126 * Check for "NAME_PATH" environment variable to override fs location (for
127 * testing). This matches the recommendation in Documentation/sysfs-rules.txt
128 * for SYSFS_PATH.
129 */
130static bool fs__env_override(struct fs *fs)
131{
132 char *override_path;
133 size_t name_len = strlen(fs->name);
134 /* name + "_PATH" + '\0' */
135 char upper_name[name_len + 5 + 1];
136 memcpy(upper_name, fs->name, name_len);
137 mem_toupper(upper_name, name_len);
138 strcpy(&upper_name[name_len], "_PATH");
139
140 override_path = getenv(upper_name);
141 if (!override_path)
142 return false;
143
144 fs->found = true;
145 strncpy(fs->path, override_path, sizeof(fs->path));
146 return true;
147}
148
Jiri Olsa4299a542013-11-05 15:14:45 +0100149static const char *fs__get_mountpoint(struct fs *fs)
150{
Cody P Schaferf2d96272014-05-27 17:21:56 -0700151 if (fs__env_override(fs))
152 return fs->path;
153
Jiri Olsa4299a542013-11-05 15:14:45 +0100154 if (fs__check_mounts(fs))
155 return fs->path;
156
Cody P Schaferf2d96272014-05-27 17:21:56 -0700157 if (fs__read_mounts(fs))
158 return fs->path;
159
160 return NULL;
Jiri Olsa4299a542013-11-05 15:14:45 +0100161}
162
Arnaldo Carvalho de Melocf38fad2013-11-05 14:48:50 -0300163static const char *fs__mountpoint(int idx)
Jiri Olsa4299a542013-11-05 15:14:45 +0100164{
165 struct fs *fs = &fs__entries[idx];
166
167 if (fs->found)
168 return (const char *)fs->path;
169
170 return fs__get_mountpoint(fs);
171}
172
Arnaldo Carvalho de Melocf38fad2013-11-05 14:48:50 -0300173#define FS__MOUNTPOINT(name, idx) \
174const char *name##__mountpoint(void) \
175{ \
176 return fs__mountpoint(idx); \
Jiri Olsa4299a542013-11-05 15:14:45 +0100177}
178
Jiri Olsaa9862412013-11-05 15:14:46 +0100179FS__MOUNTPOINT(sysfs, FS__SYSFS);
180FS__MOUNTPOINT(procfs, FS__PROCFS);
Arnaldo Carvalho de Melo3a351122014-12-11 13:17:46 -0300181
182int filename__read_int(const char *filename, int *value)
183{
184 char line[64];
185 int fd = open(filename, O_RDONLY), err = -1;
186
187 if (fd < 0)
188 return -1;
189
190 if (read(fd, line, sizeof(line)) > 0) {
191 *value = atoi(line);
192 err = 0;
193 }
194
195 close(fd);
196 return err;
197}
Arnaldo Carvalho de Melo42e3c4a2014-12-11 13:37:10 -0300198
199int sysctl__read_int(const char *sysctl, int *value)
200{
201 char path[PATH_MAX];
202 const char *procfs = procfs__mountpoint();
203
204 if (!procfs)
205 return -1;
206
207 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
208
209 return filename__read_int(path, value);
210}