1 #include <ctype.h> 2 #include <errno.h> 3 #include <limits.h> 4 #include <stdbool.h> 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <string.h> 8 #include <sys/vfs.h> 9 #include <sys/types.h> 10 #include <sys/stat.h> 11 #include <fcntl.h> 12 #include <unistd.h> 13 #include <sys/mount.h> 14 15 #include "fs.h" 16 17 #define _STR(x) #x 18 #define STR(x) _STR(x) 19 20 #ifndef SYSFS_MAGIC 21 #define SYSFS_MAGIC 0x62656572 22 #endif 23 24 #ifndef PROC_SUPER_MAGIC 25 #define PROC_SUPER_MAGIC 0x9fa0 26 #endif 27 28 #ifndef DEBUGFS_MAGIC 29 #define DEBUGFS_MAGIC 0x64626720 30 #endif 31 32 #ifndef TRACEFS_MAGIC 33 #define TRACEFS_MAGIC 0x74726163 34 #endif 35 36 static const char * const sysfs__fs_known_mountpoints[] = { 37 "/sys", 38 0, 39 }; 40 41 static const char * const procfs__known_mountpoints[] = { 42 "/proc", 43 0, 44 }; 45 46 #ifndef DEBUGFS_DEFAULT_PATH 47 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" 48 #endif 49 50 static const char * const debugfs__known_mountpoints[] = { 51 DEBUGFS_DEFAULT_PATH, 52 "/debug", 53 0, 54 }; 55 56 57 #ifndef TRACEFS_DEFAULT_PATH 58 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" 59 #endif 60 61 static const char * const tracefs__known_mountpoints[] = { 62 TRACEFS_DEFAULT_PATH, 63 "/sys/kernel/debug/tracing", 64 "/tracing", 65 "/trace", 66 0, 67 }; 68 69 struct fs { 70 const char *name; 71 const char * const *mounts; 72 char path[PATH_MAX]; 73 bool found; 74 long magic; 75 }; 76 77 enum { 78 FS__SYSFS = 0, 79 FS__PROCFS = 1, 80 FS__DEBUGFS = 2, 81 FS__TRACEFS = 3, 82 }; 83 84 #ifndef TRACEFS_MAGIC 85 #define TRACEFS_MAGIC 0x74726163 86 #endif 87 88 static struct fs fs__entries[] = { 89 [FS__SYSFS] = { 90 .name = "sysfs", 91 .mounts = sysfs__fs_known_mountpoints, 92 .magic = SYSFS_MAGIC, 93 }, 94 [FS__PROCFS] = { 95 .name = "proc", 96 .mounts = procfs__known_mountpoints, 97 .magic = PROC_SUPER_MAGIC, 98 }, 99 [FS__DEBUGFS] = { 100 .name = "debugfs", 101 .mounts = debugfs__known_mountpoints, 102 .magic = DEBUGFS_MAGIC, 103 }, 104 [FS__TRACEFS] = { 105 .name = "tracefs", 106 .mounts = tracefs__known_mountpoints, 107 .magic = TRACEFS_MAGIC, 108 }, 109 }; 110 111 static bool fs__read_mounts(struct fs *fs) 112 { 113 bool found = false; 114 char type[100]; 115 FILE *fp; 116 117 fp = fopen("/proc/mounts", "r"); 118 if (fp == NULL) 119 return NULL; 120 121 while (!found && 122 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", 123 fs->path, type) == 2) { 124 125 if (strcmp(type, fs->name) == 0) 126 found = true; 127 } 128 129 fclose(fp); 130 return fs->found = found; 131 } 132 133 static int fs__valid_mount(const char *fs, long magic) 134 { 135 struct statfs st_fs; 136 137 if (statfs(fs, &st_fs) < 0) 138 return -ENOENT; 139 else if ((long)st_fs.f_type != magic) 140 return -ENOENT; 141 142 return 0; 143 } 144 145 static bool fs__check_mounts(struct fs *fs) 146 { 147 const char * const *ptr; 148 149 ptr = fs->mounts; 150 while (*ptr) { 151 if (fs__valid_mount(*ptr, fs->magic) == 0) { 152 fs->found = true; 153 strcpy(fs->path, *ptr); 154 return true; 155 } 156 ptr++; 157 } 158 159 return false; 160 } 161 162 static void mem_toupper(char *f, size_t len) 163 { 164 while (len) { 165 *f = toupper(*f); 166 f++; 167 len--; 168 } 169 } 170 171 /* 172 * Check for "NAME_PATH" environment variable to override fs location (for 173 * testing). This matches the recommendation in Documentation/sysfs-rules.txt 174 * for SYSFS_PATH. 175 */ 176 static bool fs__env_override(struct fs *fs) 177 { 178 char *override_path; 179 size_t name_len = strlen(fs->name); 180 /* name + "_PATH" + '\0' */ 181 char upper_name[name_len + 5 + 1]; 182 memcpy(upper_name, fs->name, name_len); 183 mem_toupper(upper_name, name_len); 184 strcpy(&upper_name[name_len], "_PATH"); 185 186 override_path = getenv(upper_name); 187 if (!override_path) 188 return false; 189 190 fs->found = true; 191 strncpy(fs->path, override_path, sizeof(fs->path)); 192 return true; 193 } 194 195 static const char *fs__get_mountpoint(struct fs *fs) 196 { 197 if (fs__env_override(fs)) 198 return fs->path; 199 200 if (fs__check_mounts(fs)) 201 return fs->path; 202 203 if (fs__read_mounts(fs)) 204 return fs->path; 205 206 return NULL; 207 } 208 209 static const char *fs__mountpoint(int idx) 210 { 211 struct fs *fs = &fs__entries[idx]; 212 213 if (fs->found) 214 return (const char *)fs->path; 215 216 return fs__get_mountpoint(fs); 217 } 218 219 static const char *mount_overload(struct fs *fs) 220 { 221 size_t name_len = strlen(fs->name); 222 /* "PERF_" + name + "_ENVIRONMENT" + '\0' */ 223 char upper_name[5 + name_len + 12 + 1]; 224 225 snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name); 226 mem_toupper(upper_name, name_len); 227 228 return getenv(upper_name) ?: *fs->mounts; 229 } 230 231 static const char *fs__mount(int idx) 232 { 233 struct fs *fs = &fs__entries[idx]; 234 const char *mountpoint; 235 236 if (fs__mountpoint(idx)) 237 return (const char *)fs->path; 238 239 mountpoint = mount_overload(fs); 240 241 if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0) 242 return NULL; 243 244 return fs__check_mounts(fs) ? fs->path : NULL; 245 } 246 247 #define FS(name, idx) \ 248 const char *name##__mountpoint(void) \ 249 { \ 250 return fs__mountpoint(idx); \ 251 } \ 252 \ 253 const char *name##__mount(void) \ 254 { \ 255 return fs__mount(idx); \ 256 } \ 257 \ 258 bool name##__configured(void) \ 259 { \ 260 return name##__mountpoint() != NULL; \ 261 } 262 263 FS(sysfs, FS__SYSFS); 264 FS(procfs, FS__PROCFS); 265 FS(debugfs, FS__DEBUGFS); 266 FS(tracefs, FS__TRACEFS); 267 268 int filename__read_int(const char *filename, int *value) 269 { 270 char line[64]; 271 int fd = open(filename, O_RDONLY), err = -1; 272 273 if (fd < 0) 274 return -1; 275 276 if (read(fd, line, sizeof(line)) > 0) { 277 *value = atoi(line); 278 err = 0; 279 } 280 281 close(fd); 282 return err; 283 } 284 285 int filename__read_ull(const char *filename, unsigned long long *value) 286 { 287 char line[64]; 288 int fd = open(filename, O_RDONLY), err = -1; 289 290 if (fd < 0) 291 return -1; 292 293 if (read(fd, line, sizeof(line)) > 0) { 294 *value = strtoull(line, NULL, 10); 295 if (*value != ULLONG_MAX) 296 err = 0; 297 } 298 299 close(fd); 300 return err; 301 } 302 303 int sysfs__read_ull(const char *entry, unsigned long long *value) 304 { 305 char path[PATH_MAX]; 306 const char *sysfs = sysfs__mountpoint(); 307 308 if (!sysfs) 309 return -1; 310 311 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 312 313 return filename__read_ull(path, value); 314 } 315 316 int sysfs__read_int(const char *entry, int *value) 317 { 318 char path[PATH_MAX]; 319 const char *sysfs = sysfs__mountpoint(); 320 321 if (!sysfs) 322 return -1; 323 324 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 325 326 return filename__read_int(path, value); 327 } 328 329 int sysctl__read_int(const char *sysctl, int *value) 330 { 331 char path[PATH_MAX]; 332 const char *procfs = procfs__mountpoint(); 333 334 if (!procfs) 335 return -1; 336 337 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); 338 339 return filename__read_int(path, value); 340 } 341