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