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 | } | ||
