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 */
debugfs_force_cleanup(void)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 */
debugfs_make_path(const char * element,char * buffer,int size)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 */
debugfs_find_mountpoint(void)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
debugfs_valid_mountpoint(const char * debugfs)86 int debugfs_valid_mountpoint(const char *debugfs)
87 {
88 /* ANDROID_CHANGE_BEGIN */
89 #ifndef __APPLE__
90 struct statfs st_fs;
91
92 if (statfs(debugfs, &st_fs) < 0)
93 return -ENOENT;
94 else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
95 return -ENOENT;
96
97 #endif
98 /* ANDROID_CHANGE_END */
99 return 0;
100 }
101
102
debugfs_valid_entry(const char * path)103 int debugfs_valid_entry(const char *path)
104 {
105 struct stat st;
106
107 if (stat(path, &st))
108 return -errno;
109
110 return 0;
111 }
112
113 /* mount the debugfs somewhere if it's not mounted */
114
debugfs_mount(const char * mountpoint)115 char *debugfs_mount(const char *mountpoint)
116 {
117 /* ANDROID_CHANGE_BEGIN */
118 #ifndef __APPLE__
119 /* see if it's already mounted */
120 if (debugfs_find_mountpoint()) {
121 debugfs_premounted = 1;
122 return debugfs_mountpoint;
123 }
124
125 /* if not mounted and no argument */
126 if (mountpoint == NULL) {
127 /* see if environment variable set */
128 mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
129 /* if no environment variable, use default */
130 if (mountpoint == NULL)
131 mountpoint = "/sys/kernel/debug";
132 }
133
134 if (mount(NULL, mountpoint, "debugfs", 0, NULL) < 0)
135 return NULL;
136
137 /* save the mountpoint */
138 strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
139 debugfs_found = 1;
140
141 return debugfs_mountpoint;
142 #else
143 return "perfhost";
144 #endif
145 /* ANDROID_CHANGE_END */
146 }
147
148 /* umount the debugfs */
149
debugfs_umount(void)150 int debugfs_umount(void)
151 {
152 char umountcmd[128];
153 int ret;
154
155 /* if it was already mounted, leave it */
156 if (debugfs_premounted)
157 return 0;
158
159 /* make sure it's a valid mount point */
160 ret = debugfs_valid_mountpoint(debugfs_mountpoint);
161 if (ret)
162 return ret;
163
164 snprintf(umountcmd, sizeof(umountcmd),
165 "/bin/umount %s", debugfs_mountpoint);
166 return system(umountcmd);
167 }
168
debugfs_write(const char * entry,const char * value)169 int debugfs_write(const char *entry, const char *value)
170 {
171 char path[MAX_PATH+1];
172 int ret, count;
173 int fd;
174
175 /* construct the path */
176 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
177
178 /* verify that it exists */
179 ret = debugfs_valid_entry(path);
180 if (ret)
181 return ret;
182
183 /* get how many chars we're going to write */
184 count = strlen(value);
185
186 /* open the debugfs entry */
187 fd = open(path, O_RDWR);
188 if (fd < 0)
189 return -errno;
190
191 while (count > 0) {
192 /* write it */
193 ret = write(fd, value, count);
194 if (ret <= 0) {
195 if (ret == EAGAIN)
196 continue;
197 close(fd);
198 return -errno;
199 }
200 count -= ret;
201 }
202
203 /* close it */
204 close(fd);
205
206 /* return success */
207 return 0;
208 }
209
210 /*
211 * read a debugfs entry
212 * returns the number of chars read or a negative errno
213 */
debugfs_read(const char * entry,char * buffer,size_t size)214 int debugfs_read(const char *entry, char *buffer, size_t size)
215 {
216 char path[MAX_PATH+1];
217 int ret;
218 int fd;
219
220 /* construct the path */
221 snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
222
223 /* verify that it exists */
224 ret = debugfs_valid_entry(path);
225 if (ret)
226 return ret;
227
228 /* open the debugfs entry */
229 fd = open(path, O_RDONLY);
230 if (fd < 0)
231 return -errno;
232
233 do {
234 /* read it */
235 ret = read(fd, buffer, size);
236 if (ret == 0) {
237 close(fd);
238 return EOF;
239 }
240 } while (ret < 0 && errno == EAGAIN);
241
242 /* close it */
243 close(fd);
244
245 /* make *sure* there's a null character at the end */
246 buffer[ret] = '\0';
247
248 /* return the number of chars read */
249 return ret;
250 }
251