Commit | Line | Data |
---|---|---|
afe61f67 CW |
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 | ||
29c52aa2 | 109 | /* mount the debugfs somewhere if it's not mounted */ |
afe61f67 | 110 | |
29c52aa2 | 111 | char *debugfs_mount(const char *mountpoint) |
afe61f67 | 112 | { |
afe61f67 CW |
113 | /* see if it's already mounted */ |
114 | if (debugfs_find_mountpoint()) { | |
115 | debugfs_premounted = 1; | |
29c52aa2 | 116 | return debugfs_mountpoint; |
afe61f67 CW |
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 | ||
29c52aa2 XG |
128 | if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0) |
129 | return NULL; | |
130 | ||
afe61f67 CW |
131 | /* save the mountpoint */ |
132 | strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint)); | |
61be3e59 | 133 | debugfs_found = 1; |
afe61f67 | 134 | |
29c52aa2 | 135 | return debugfs_mountpoint; |
afe61f67 CW |
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 | } |