diff options
Diffstat (limited to 'tools/perf/util/debugfs.c')
-rw-r--r-- | tools/perf/util/debugfs.c | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/tools/perf/util/debugfs.c b/tools/perf/util/debugfs.c new file mode 100644 index 000000000000..06b73ee02c49 --- /dev/null +++ b/tools/perf/util/debugfs.c | |||
@@ -0,0 +1,241 @@ | |||
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 */ | ||
110 | |||
111 | int debugfs_mount(const char *mountpoint) | ||
112 | { | ||
113 | char mountcmd[128]; | ||
114 | |||
115 | /* see if it's already mounted */ | ||
116 | if (debugfs_find_mountpoint()) { | ||
117 | debugfs_premounted = 1; | ||
118 | return 0; | ||
119 | } | ||
120 | |||
121 | /* if not mounted and no argument */ | ||
122 | if (mountpoint == NULL) { | ||
123 | /* see if environment variable set */ | ||
124 | mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT); | ||
125 | /* if no environment variable, use default */ | ||
126 | if (mountpoint == NULL) | ||
127 | mountpoint = "/sys/kernel/debug"; | ||
128 | } | ||
129 | |||
130 | /* save the mountpoint */ | ||
131 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | ||
132 | |||
133 | /* mount it */ | ||
134 | snprintf(mountcmd, sizeof(mountcmd), | ||
135 | "/bin/mount -t debugfs debugfs %s", mountpoint); | ||
136 | return system(mountcmd); | ||
137 | } | ||
138 | |||
139 | /* umount the debugfs */ | ||
140 | |||
141 | int debugfs_umount(void) | ||
142 | { | ||
143 | char umountcmd[128]; | ||
144 | int ret; | ||
145 | |||
146 | /* if it was already mounted, leave it */ | ||
147 | if (debugfs_premounted) | ||
148 | return 0; | ||
149 | |||
150 | /* make sure it's a valid mount point */ | ||
151 | ret = debugfs_valid_mountpoint(debugfs_mountpoint); | ||
152 | if (ret) | ||
153 | return ret; | ||
154 | |||
155 | snprintf(umountcmd, sizeof(umountcmd), | ||
156 | "/bin/umount %s", debugfs_mountpoint); | ||
157 | return system(umountcmd); | ||
158 | } | ||
159 | |||
160 | int debugfs_write(const char *entry, const char *value) | ||
161 | { | ||
162 | char path[MAX_PATH+1]; | ||
163 | int ret, count; | ||
164 | int fd; | ||
165 | |||
166 | /* construct the path */ | ||
167 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
168 | |||
169 | /* verify that it exists */ | ||
170 | ret = debugfs_valid_entry(path); | ||
171 | if (ret) | ||
172 | return ret; | ||
173 | |||
174 | /* get how many chars we're going to write */ | ||
175 | count = strlen(value); | ||
176 | |||
177 | /* open the debugfs entry */ | ||
178 | fd = open(path, O_RDWR); | ||
179 | if (fd < 0) | ||
180 | return -errno; | ||
181 | |||
182 | while (count > 0) { | ||
183 | /* write it */ | ||
184 | ret = write(fd, value, count); | ||
185 | if (ret <= 0) { | ||
186 | if (ret == EAGAIN) | ||
187 | continue; | ||
188 | close(fd); | ||
189 | return -errno; | ||
190 | } | ||
191 | count -= ret; | ||
192 | } | ||
193 | |||
194 | /* close it */ | ||
195 | close(fd); | ||
196 | |||
197 | /* return success */ | ||
198 | return 0; | ||
199 | } | ||
200 | |||
201 | /* | ||
202 | * read a debugfs entry | ||
203 | * returns the number of chars read or a negative errno | ||
204 | */ | ||
205 | int debugfs_read(const char *entry, char *buffer, size_t size) | ||
206 | { | ||
207 | char path[MAX_PATH+1]; | ||
208 | int ret; | ||
209 | int fd; | ||
210 | |||
211 | /* construct the path */ | ||
212 | snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry); | ||
213 | |||
214 | /* verify that it exists */ | ||
215 | ret = debugfs_valid_entry(path); | ||
216 | if (ret) | ||
217 | return ret; | ||
218 | |||
219 | /* open the debugfs entry */ | ||
220 | fd = open(path, O_RDONLY); | ||
221 | if (fd < 0) | ||
222 | return -errno; | ||
223 | |||
224 | do { | ||
225 | /* read it */ | ||
226 | ret = read(fd, buffer, size); | ||
227 | if (ret == 0) { | ||
228 | close(fd); | ||
229 | return EOF; | ||
230 | } | ||
231 | } while (ret < 0 && errno == EAGAIN); | ||
232 | |||
233 | /* close it */ | ||
234 | close(fd); | ||
235 | |||
236 | /* make *sure* there's a null character at the end */ | ||
237 | buffer[ret] = '\0'; | ||
238 | |||
239 | /* return the number of chars read */ | ||
240 | return ret; | ||
241 | } | ||