|
@@ -0,0 +1,241 @@
|
|
|
+#include "util.h"
|
|
|
+#include "debugfs.h"
|
|
|
+#include "cache.h"
|
|
|
+
|
|
|
+static int debugfs_premounted;
|
|
|
+static char debugfs_mountpoint[MAX_PATH+1];
|
|
|
+
|
|
|
+static const char *debugfs_known_mountpoints[] = {
|
|
|
+ "/sys/kernel/debug/",
|
|
|
+ "/debug/",
|
|
|
+ 0,
|
|
|
+};
|
|
|
+
|
|
|
+/* use this to force a umount */
|
|
|
+void debugfs_force_cleanup(void)
|
|
|
+{
|
|
|
+ debugfs_find_mountpoint();
|
|
|
+ debugfs_premounted = 0;
|
|
|
+ debugfs_umount();
|
|
|
+}
|
|
|
+
|
|
|
+/* construct a full path to a debugfs element */
|
|
|
+int debugfs_make_path(const char *element, char *buffer, int size)
|
|
|
+{
|
|
|
+ int len;
|
|
|
+
|
|
|
+ if (strlen(debugfs_mountpoint) == 0) {
|
|
|
+ buffer[0] = '\0';
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
+
|
|
|
+ len = strlen(debugfs_mountpoint) + strlen(element) + 1;
|
|
|
+ if (len >= size)
|
|
|
+ return len+1;
|
|
|
+
|
|
|
+ snprintf(buffer, size-1, "%s/%s", debugfs_mountpoint, element);
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int debugfs_found;
|
|
|
+
|
|
|
+/* find the path to the mounted debugfs */
|
|
|
+const char *debugfs_find_mountpoint(void)
|
|
|
+{
|
|
|
+ const char **ptr;
|
|
|
+ char type[100];
|
|
|
+ FILE *fp;
|
|
|
+
|
|
|
+ if (debugfs_found)
|
|
|
+ return (const char *) debugfs_mountpoint;
|
|
|
+
|
|
|
+ ptr = debugfs_known_mountpoints;
|
|
|
+ while (*ptr) {
|
|
|
+ if (debugfs_valid_mountpoint(*ptr) == 0) {
|
|
|
+ debugfs_found = 1;
|
|
|
+ strcpy(debugfs_mountpoint, *ptr);
|
|
|
+ return debugfs_mountpoint;
|
|
|
+ }
|
|
|
+ ptr++;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* give up and parse /proc/mounts */
|
|
|
+ fp = fopen("/proc/mounts", "r");
|
|
|
+ if (fp == NULL)
|
|
|
+ die("Can't open /proc/mounts for read");
|
|
|
+
|
|
|
+ while (fscanf(fp, "%*s %"
|
|
|
+ STR(MAX_PATH)
|
|
|
+ "s %99s %*s %*d %*d\n",
|
|
|
+ debugfs_mountpoint, type) == 2) {
|
|
|
+ if (strcmp(type, "debugfs") == 0)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ fclose(fp);
|
|
|
+
|
|
|
+ if (strcmp(type, "debugfs") != 0)
|
|
|
+ return NULL;
|
|
|
+
|
|
|
+ debugfs_found = 1;
|
|
|
+
|
|
|
+ return debugfs_mountpoint;
|
|
|
+}
|
|
|
+
|
|
|
+/* verify that a mountpoint is actually a debugfs instance */
|
|
|
+
|
|
|
+int debugfs_valid_mountpoint(const char *debugfs)
|
|
|
+{
|
|
|
+ struct statfs st_fs;
|
|
|
+
|
|
|
+ if (statfs(debugfs, &st_fs) < 0)
|
|
|
+ return -ENOENT;
|
|
|
+ else if (st_fs.f_type != (long) DEBUGFS_MAGIC)
|
|
|
+ return -ENOENT;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+
|
|
|
+int debugfs_valid_entry(const char *path)
|
|
|
+{
|
|
|
+ struct stat st;
|
|
|
+
|
|
|
+ if (stat(path, &st))
|
|
|
+ return -errno;
|
|
|
+
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/* mount the debugfs somewhere */
|
|
|
+
|
|
|
+int debugfs_mount(const char *mountpoint)
|
|
|
+{
|
|
|
+ char mountcmd[128];
|
|
|
+
|
|
|
+ /* see if it's already mounted */
|
|
|
+ if (debugfs_find_mountpoint()) {
|
|
|
+ debugfs_premounted = 1;
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* if not mounted and no argument */
|
|
|
+ if (mountpoint == NULL) {
|
|
|
+ /* see if environment variable set */
|
|
|
+ mountpoint = getenv(PERF_DEBUGFS_ENVIRONMENT);
|
|
|
+ /* if no environment variable, use default */
|
|
|
+ if (mountpoint == NULL)
|
|
|
+ mountpoint = "/sys/kernel/debug";
|
|
|
+ }
|
|
|
+
|
|
|
+ /* save the mountpoint */
|
|
|
+ strncpy(debugfs_mountpoint, mountpoint, sizeof(debugfs_mountpoint));
|
|
|
+
|
|
|
+ /* mount it */
|
|
|
+ snprintf(mountcmd, sizeof(mountcmd),
|
|
|
+ "/bin/mount -t debugfs debugfs %s", mountpoint);
|
|
|
+ return system(mountcmd);
|
|
|
+}
|
|
|
+
|
|
|
+/* umount the debugfs */
|
|
|
+
|
|
|
+int debugfs_umount(void)
|
|
|
+{
|
|
|
+ char umountcmd[128];
|
|
|
+ int ret;
|
|
|
+
|
|
|
+ /* if it was already mounted, leave it */
|
|
|
+ if (debugfs_premounted)
|
|
|
+ return 0;
|
|
|
+
|
|
|
+ /* make sure it's a valid mount point */
|
|
|
+ ret = debugfs_valid_mountpoint(debugfs_mountpoint);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ snprintf(umountcmd, sizeof(umountcmd),
|
|
|
+ "/bin/umount %s", debugfs_mountpoint);
|
|
|
+ return system(umountcmd);
|
|
|
+}
|
|
|
+
|
|
|
+int debugfs_write(const char *entry, const char *value)
|
|
|
+{
|
|
|
+ char path[MAX_PATH+1];
|
|
|
+ int ret, count;
|
|
|
+ int fd;
|
|
|
+
|
|
|
+ /* construct the path */
|
|
|
+ snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
|
|
|
+
|
|
|
+ /* verify that it exists */
|
|
|
+ ret = debugfs_valid_entry(path);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /* get how many chars we're going to write */
|
|
|
+ count = strlen(value);
|
|
|
+
|
|
|
+ /* open the debugfs entry */
|
|
|
+ fd = open(path, O_RDWR);
|
|
|
+ if (fd < 0)
|
|
|
+ return -errno;
|
|
|
+
|
|
|
+ while (count > 0) {
|
|
|
+ /* write it */
|
|
|
+ ret = write(fd, value, count);
|
|
|
+ if (ret <= 0) {
|
|
|
+ if (ret == EAGAIN)
|
|
|
+ continue;
|
|
|
+ close(fd);
|
|
|
+ return -errno;
|
|
|
+ }
|
|
|
+ count -= ret;
|
|
|
+ }
|
|
|
+
|
|
|
+ /* close it */
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ /* return success */
|
|
|
+ return 0;
|
|
|
+}
|
|
|
+
|
|
|
+/*
|
|
|
+ * read a debugfs entry
|
|
|
+ * returns the number of chars read or a negative errno
|
|
|
+ */
|
|
|
+int debugfs_read(const char *entry, char *buffer, size_t size)
|
|
|
+{
|
|
|
+ char path[MAX_PATH+1];
|
|
|
+ int ret;
|
|
|
+ int fd;
|
|
|
+
|
|
|
+ /* construct the path */
|
|
|
+ snprintf(path, sizeof(path), "%s/%s", debugfs_mountpoint, entry);
|
|
|
+
|
|
|
+ /* verify that it exists */
|
|
|
+ ret = debugfs_valid_entry(path);
|
|
|
+ if (ret)
|
|
|
+ return ret;
|
|
|
+
|
|
|
+ /* open the debugfs entry */
|
|
|
+ fd = open(path, O_RDONLY);
|
|
|
+ if (fd < 0)
|
|
|
+ return -errno;
|
|
|
+
|
|
|
+ do {
|
|
|
+ /* read it */
|
|
|
+ ret = read(fd, buffer, size);
|
|
|
+ if (ret == 0) {
|
|
|
+ close(fd);
|
|
|
+ return EOF;
|
|
|
+ }
|
|
|
+ } while (ret < 0 && errno == EAGAIN);
|
|
|
+
|
|
|
+ /* close it */
|
|
|
+ close(fd);
|
|
|
+
|
|
|
+ /* make *sure* there's a null character at the end */
|
|
|
+ buffer[ret] = '\0';
|
|
|
+
|
|
|
+ /* return the number of chars read */
|
|
|
+ return ret;
|
|
|
+}
|