diff options
Diffstat (limited to 'tools/perf/util/debugfs.c')
-rw-r--r-- | tools/perf/util/debugfs.c | 240 |
1 files changed, 240 insertions, 0 deletions
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c new file mode 100644 index 000000000000..a88fefc0cc0a --- /dev/null +++ b/tools/perf/util/debugfs.c | |||
@@ -0,0 +1,240 @@ | |||
1 | #include "util.h" | ||
2 | #include "debugfs.h" | ||
3 | #include "cache.h" | ||
4 | |||
5 | static int debugfs_premounted; | ||
6 | static char debugfs_mountpoint[MAX_PATH+1]; | ||
7 | |||
8 | static const char *debugfs_known_mountpoints[] = { | ||
9 | "/sys/kernel/debug/", | ||
10 | "/debug/", | ||
11 | 0, | ||
12 | }; | ||
13 | |||
14 | /* use this to force a umount */ | ||
15 | void debugfs_force_cleanup(void) | ||
16 | { | ||
17 | debugfs_find_mountpoint(); | ||
18 | debugfs_premounted = 0; | ||
19 | debugfs_umount(); | ||
20 | } | ||
21 | |||
22 | /* construct a full path to a debugfs element */ | ||
23 | int debugfs_make_path(const char *element, char *buffer, int size) | ||
24 | { | ||
25 | int len; | ||
26 | |||
27 | if (strlen(debugfs_mountpoint) == 0) { | ||
28 | buffer[0] = '\0'; | ||
29 | return -1; | ||
30 | } | ||
31 | |||
32 | len = strlen(debugfs_mountpoint) + strlen(element) + 1; | ||
33 | if (len >= size) | ||
34 | return len+1; | ||
35 | |||
36 | snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element); | ||
37 | return 0; | ||
38 | } | ||
39 | |||
40 | static int debugfs_found; | ||
41 | |||
42 | /* find the path to the mounted debugfs */ | ||
43 | const char *debugfs_find_mountpoint(void) | ||
44 | { | ||
45 | const char **ptr; | ||
46 | char type[100]; | ||
47 | FILE *fp; | ||
48 | |||
49 | if (debugfs_found) | ||
50 | return (const char *) debugfs_mountpoint; | ||
51 | |||
52 | ptr = debugfs_known_mountpoints; | ||
53 | while (*ptr) { | ||
54 | if (debugfs_valid_mountpoint(*ptr) == 0) { | ||
55 | debugfs_found = 1; | ||
56 | strcpy(debugfs_mountpoint, *ptr); | ||
57 | return debugfs_mountpoint; | ||
58 | } | ||
59 | ptr++; | ||
60 | } | ||
61 | |||
62 | /* give up and parse /proc/mounts */ | ||
63 | fp = fopen("/proc/mounts", "r"); | ||
64 | if (fp == NULL) | ||
65 | die("Can't open /proc/mounts for read"); | ||
66 | |||
67 | while (fscanf(fp, "%*s %" | ||
68 | STR(MAX_PATH) | ||
69 | "s %99s %*s %*d %*d\n", | ||
70 | debugfs_mountpoint, type) == 2) { | ||
71 | if (strcmp(type, "debugfs") == 0) | ||
72 | break; | ||
73 | } | ||
74 | fclose(fp); | ||
75 | |||
76 | if (strcmp(type, "debugfs") != 0) | ||
77 | return NULL; | ||
78 | |||
79 | debugfs_found = 1; | ||
80 | |||
81 | return debugfs_mountpoint; | ||
82 | } | ||
83 | |||
84 | /* verify that a mountpoint is actually a debugfs instance */ | ||
85 | |||
86 | int debugfs_valid_mountpoint(const char *debugfs) | ||
87 | { | ||
88 | struct statfs st_fs; | ||
89 | |||
90 | if (statfs(debugfs, &st_fs) < 0) | ||
91 | return -ENOENT; | ||
92 | else if (st_fs.f_type != (long) DEBUGFS_MAGIC) | ||
93 | return -ENOENT; | ||
94 | |||
95 | return 0; | ||
96 | } | ||
97 | |||
98 | |||
99 | int debugfs_valid_entry(const char *path) | ||
100 | { | ||
101 | struct stat st; | ||
102 | |||
103 | if (stat(path, &st)) | ||
104 | return -errno; | ||
105 | |||
106 | return 0; | ||
107 | } | ||
108 | |||
109 | /* mount the debugfs somewhere if it's not mounted */ | ||
110 | |||
111 | char *debugfs_mount(const char *mountpoint) | ||
112 | { | ||
113 | /* see if it's already mounted */ | ||
114 | if (debugfs_find_mountpoint()) { | ||
115 | debugfs_premounted = 1; | ||
116 | return debugfs_mountpoint; | ||
117 | } | ||
118 | |||
119 | /* if not mounted and no argument */ | ||
120 | if (mountpoint == NULL) { | ||
121 | /* see if environment variable set */ | ||
122 | mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); | ||
123 | /* if no environment variable, use default */ | ||
124 | if (mountpoint == NULL) | ||
125 | mountpoint = "/sys/kernel/debug"; | ||
126 | } | ||
127 | |||
128 | if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) | ||
129 | return NULL; | ||
130 | |||
131 | /* save the mountpoint */ | ||
132 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | ||
133 | debugfs_found = 1; | ||
134 | |||
135 | return debugfs_mountpoint; | ||
136 | } | ||
137 | |||
138 | /* umount the debugfs */ | ||
139 | |||
140 | int debugfs_umount(void) | ||
141 | { | ||
142 | char umountcmd[128]; | ||
143 | int ret; | ||
144 | |||
145 | /* if it was already mounted, leave it */ | ||
146 | if (debugfs_premounted) | ||
147 | return 0; | ||
148 | |||
149 | /* make sure it's a valid mount point */ | ||
150 | ret = debugfs_valid_mountpoint(debugfs_mountpoint); | ||
151 | if (ret) | ||
152 | return ret; | ||
153 | |||
154 | snprintf(umountcmd, sizeof(umountcmd), | ||
155 | "/bin/umount %s", debugfs_mountpoint); | ||
156 | return system(umountcmd); | ||
157 | } | ||
158 | |||
159 | int debugfs_write(const char *entry, const char *value) | ||
160 | { | ||
161 | char path[MAX_PATH+1]; | ||
162 | int ret, count; | ||
163 | int fd; | ||
164 | |||
165 | /* construct the path */ | ||
166 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
167 | |||
168 | /* verify that it exists */ | ||
169 | ret = debugfs_valid_entry(path); | ||
170 | if (ret) | ||
171 | return ret; | ||
172 | |||
173 | /* get how many chars we're going to write */ | ||
174 | count = strlen(value); | ||
175 | |||
176 | /* open the debugfs entry */ | ||
177 | fd = open(path, O_RDWR); | ||
178 | if (fd < 0) | ||
179 | return -errno; | ||
180 | |||
181 | while (count > 0) { | ||
182 | /* write it */ | ||
183 | ret = write(fd, value, count); | ||
184 | if (ret <= 0) { | ||
185 | if (ret == EAGAIN) | ||
186 | continue; | ||
187 | close(fd); | ||
188 | return -errno; | ||
189 | } | ||
190 | count -= ret; | ||
191 | } | ||
192 | |||
193 | /* close it */ | ||
194 | close(fd); | ||
195 | |||
196 | /* return success */ | ||
197 | return 0; | ||
198 | } | ||
199 | |||
200 | /* | ||
201 | * read a debugfs entry | ||
202 | * returns the number of chars read or a negative errno | ||
203 | */ | ||
204 | int debugfs_read(const char *entry, char *buffer, size_t size) | ||
205 | { | ||
206 | char path[MAX_PATH+1]; | ||
207 | int ret; | ||
208 | int fd; | ||
209 | |||
210 | /* construct the path */ | ||
211 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
212 | |||
213 | /* verify that it exists */ | ||
214 | ret = debugfs_valid_entry(path); | ||
215 | if (ret) | ||
216 | return ret; | ||
217 | |||
218 | /* open the debugfs entry */ | ||
219 | fd = open(path, O_RDONLY); | ||
220 | if (fd < 0) | ||
221 | return -errno; | ||
222 | |||
223 | do { | ||
224 | /* read it */ | ||
225 | ret = read(fd, buffer, size); | ||
226 | if (ret == 0) { | ||
227 | close(fd); | ||
228 | return EOF; | ||
229 | } | ||
230 | } while (ret < 0 && errno == EAGAIN); | ||
231 | |||
232 | /* close it */ | ||
233 | close(fd); | ||
234 | |||
235 | /* make *sure* there's a null character at the end */ | ||
236 | buffer[ret] = '\0'; | ||
237 | |||
238 | /* return the number of chars read */ | ||
239 | return ret; | ||
240 | } | ||