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 #include "debug-internal.h" 17 18 #define _STR(x) #x 19 #define STR(x) _STR(x) 20 21 #ifndef SYSFS_MAGIC 22 #define SYSFS_MAGIC 0x62656572 23 #endif 24 25 #ifndef PROC_SUPER_MAGIC 26 #define PROC_SUPER_MAGIC 0x9fa0 27 #endif 28 29 #ifndef DEBUGFS_MAGIC 30 #define DEBUGFS_MAGIC 0x64626720 31 #endif 32 33 #ifndef TRACEFS_MAGIC 34 #define TRACEFS_MAGIC 0x74726163 35 #endif 36 37 static const char * const sysfs__fs_known_mountpoints[] = { 38 "/sys", 39 0, 40 }; 41 42 static const char * const procfs__known_mountpoints[] = { 43 "/proc", 44 0, 45 }; 46 47 #ifndef DEBUGFS_DEFAULT_PATH 48 #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug" 49 #endif 50 51 static const char * const debugfs__known_mountpoints[] = { 52 DEBUGFS_DEFAULT_PATH, 53 "/debug", 54 0, 55 }; 56 57 58 #ifndef TRACEFS_DEFAULT_PATH 59 #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing" 60 #endif 61 62 static const char * const tracefs__known_mountpoints[] = { 63 TRACEFS_DEFAULT_PATH, 64 "/sys/kernel/debug/tracing", 65 "/tracing", 66 "/trace", 67 0, 68 }; 69 70 struct fs { 71 const char *name; 72 const char * const *mounts; 73 char path[PATH_MAX]; 74 bool found; 75 long magic; 76 }; 77 78 enum { 79 FS__SYSFS = 0, 80 FS__PROCFS = 1, 81 FS__DEBUGFS = 2, 82 FS__TRACEFS = 3, 83 }; 84 85 #ifndef TRACEFS_MAGIC 86 #define TRACEFS_MAGIC 0x74726163 87 #endif 88 89 static struct fs fs__entries[] = { 90 [FS__SYSFS] = { 91 .name = "sysfs", 92 .mounts = sysfs__fs_known_mountpoints, 93 .magic = SYSFS_MAGIC, 94 }, 95 [FS__PROCFS] = { 96 .name = "proc", 97 .mounts = procfs__known_mountpoints, 98 .magic = PROC_SUPER_MAGIC, 99 }, 100 [FS__DEBUGFS] = { 101 .name = "debugfs", 102 .mounts = debugfs__known_mountpoints, 103 .magic = DEBUGFS_MAGIC, 104 }, 105 [FS__TRACEFS] = { 106 .name = "tracefs", 107 .mounts = tracefs__known_mountpoints, 108 .magic = TRACEFS_MAGIC, 109 }, 110 }; 111 112 static bool fs__read_mounts(struct fs *fs) 113 { 114 bool found = false; 115 char type[100]; 116 FILE *fp; 117 118 fp = fopen("/proc/mounts", "r"); 119 if (fp == NULL) 120 return NULL; 121 122 while (!found && 123 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", 124 fs->path, type) == 2) { 125 126 if (strcmp(type, fs->name) == 0) 127 found = true; 128 } 129 130 fclose(fp); 131 return fs->found = found; 132 } 133 134 static int fs__valid_mount(const char *fs, long magic) 135 { 136 struct statfs st_fs; 137 138 if (statfs(fs, &st_fs) < 0) 139 return -ENOENT; 140 else if ((long)st_fs.f_type != magic) 141 return -ENOENT; 142 143 return 0; 144 } 145 146 static bool fs__check_mounts(struct fs *fs) 147 { 148 const char * const *ptr; 149 150 ptr = fs->mounts; 151 while (*ptr) { 152 if (fs__valid_mount(*ptr, fs->magic) == 0) { 153 fs->found = true; 154 strcpy(fs->path, *ptr); 155 return true; 156 } 157 ptr++; 158 } 159 160 return false; 161 } 162 163 static void mem_toupper(char *f, size_t len) 164 { 165 while (len) { 166 *f = toupper(*f); 167 f++; 168 len--; 169 } 170 } 171 172 /* 173 * Check for "NAME_PATH" environment variable to override fs location (for 174 * testing). This matches the recommendation in Documentation/sysfs-rules.txt 175 * for SYSFS_PATH. 176 */ 177 static bool fs__env_override(struct fs *fs) 178 { 179 char *override_path; 180 size_t name_len = strlen(fs->name); 181 /* name + "_PATH" + '\0' */ 182 char upper_name[name_len + 5 + 1]; 183 memcpy(upper_name, fs->name, name_len); 184 mem_toupper(upper_name, name_len); 185 strcpy(&upper_name[name_len], "_PATH"); 186 187 override_path = getenv(upper_name); 188 if (!override_path) 189 return false; 190 191 fs->found = true; 192 strncpy(fs->path, override_path, sizeof(fs->path)); 193 return true; 194 } 195 196 static const char *fs__get_mountpoint(struct fs *fs) 197 { 198 if (fs__env_override(fs)) 199 return fs->path; 200 201 if (fs__check_mounts(fs)) 202 return fs->path; 203 204 if (fs__read_mounts(fs)) 205 return fs->path; 206 207 return NULL; 208 } 209 210 static const char *fs__mountpoint(int idx) 211 { 212 struct fs *fs = &fs__entries[idx]; 213 214 if (fs->found) 215 return (const char *)fs->path; 216 217 return fs__get_mountpoint(fs); 218 } 219 220 static const char *mount_overload(struct fs *fs) 221 { 222 size_t name_len = strlen(fs->name); 223 /* "PERF_" + name + "_ENVIRONMENT" + '\0' */ 224 char upper_name[5 + name_len + 12 + 1]; 225 226 snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name); 227 mem_toupper(upper_name, name_len); 228 229 return getenv(upper_name) ?: *fs->mounts; 230 } 231 232 static const char *fs__mount(int idx) 233 { 234 struct fs *fs = &fs__entries[idx]; 235 const char *mountpoint; 236 237 if (fs__mountpoint(idx)) 238 return (const char *)fs->path; 239 240 mountpoint = mount_overload(fs); 241 242 if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0) 243 return NULL; 244 245 return fs__check_mounts(fs) ? fs->path : NULL; 246 } 247 248 #define FS(name, idx) \ 249 const char *name##__mountpoint(void) \ 250 { \ 251 return fs__mountpoint(idx); \ 252 } \ 253 \ 254 const char *name##__mount(void) \ 255 { \ 256 return fs__mount(idx); \ 257 } \ 258 \ 259 bool name##__configured(void) \ 260 { \ 261 return name##__mountpoint() != NULL; \ 262 } 263 264 FS(sysfs, FS__SYSFS); 265 FS(procfs, FS__PROCFS); 266 FS(debugfs, FS__DEBUGFS); 267 FS(tracefs, FS__TRACEFS); 268 269 int filename__read_int(const char *filename, int *value) 270 { 271 char line[64]; 272 int fd = open(filename, O_RDONLY), err = -1; 273 274 if (fd < 0) 275 return -1; 276 277 if (read(fd, line, sizeof(line)) > 0) { 278 *value = atoi(line); 279 err = 0; 280 } 281 282 close(fd); 283 return err; 284 } 285 286 /* 287 * Parses @value out of @filename with strtoull. 288 * By using 0 for base, the strtoull detects the 289 * base automatically (see man strtoull). 290 */ 291 int filename__read_ull(const char *filename, unsigned long long *value) 292 { 293 char line[64]; 294 int fd = open(filename, O_RDONLY), err = -1; 295 296 if (fd < 0) 297 return -1; 298 299 if (read(fd, line, sizeof(line)) > 0) { 300 *value = strtoull(line, NULL, 0); 301 if (*value != ULLONG_MAX) 302 err = 0; 303 } 304 305 close(fd); 306 return err; 307 } 308 309 #define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ 310 311 int filename__read_str(const char *filename, char **buf, size_t *sizep) 312 { 313 size_t size = 0, alloc_size = 0; 314 void *bf = NULL, *nbf; 315 int fd, n, err = 0; 316 char sbuf[STRERR_BUFSIZE]; 317 318 fd = open(filename, O_RDONLY); 319 if (fd < 0) 320 return -errno; 321 322 do { 323 if (size == alloc_size) { 324 alloc_size += BUFSIZ; 325 nbf = realloc(bf, alloc_size); 326 if (!nbf) { 327 err = -ENOMEM; 328 break; 329 } 330 331 bf = nbf; 332 } 333 334 n = read(fd, bf + size, alloc_size - size); 335 if (n < 0) { 336 if (size) { 337 pr_warning("read failed %d: %s\n", errno, 338 strerror_r(errno, sbuf, sizeof(sbuf))); 339 err = 0; 340 } else 341 err = -errno; 342 343 break; 344 } 345 346 size += n; 347 } while (n > 0); 348 349 if (!err) { 350 *sizep = size; 351 *buf = bf; 352 } else 353 free(bf); 354 355 close(fd); 356 return err; 357 } 358 359 int procfs__read_str(const char *entry, char **buf, size_t *sizep) 360 { 361 char path[PATH_MAX]; 362 const char *procfs = procfs__mountpoint(); 363 364 if (!procfs) 365 return -1; 366 367 snprintf(path, sizeof(path), "%s/%s", procfs, entry); 368 369 return filename__read_str(path, buf, sizep); 370 } 371 372 int sysfs__read_ull(const char *entry, unsigned long long *value) 373 { 374 char path[PATH_MAX]; 375 const char *sysfs = sysfs__mountpoint(); 376 377 if (!sysfs) 378 return -1; 379 380 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 381 382 return filename__read_ull(path, value); 383 } 384 385 int sysfs__read_int(const char *entry, int *value) 386 { 387 char path[PATH_MAX]; 388 const char *sysfs = sysfs__mountpoint(); 389 390 if (!sysfs) 391 return -1; 392 393 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 394 395 return filename__read_int(path, value); 396 } 397 398 int sysfs__read_str(const char *entry, char **buf, size_t *sizep) 399 { 400 char path[PATH_MAX]; 401 const char *sysfs = sysfs__mountpoint(); 402 403 if (!sysfs) 404 return -1; 405 406 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 407 408 return filename__read_str(path, buf, sizep); 409 } 410 411 int sysctl__read_int(const char *sysctl, int *value) 412 { 413 char path[PATH_MAX]; 414 const char *procfs = procfs__mountpoint(); 415 416 if (!procfs) 417 return -1; 418 419 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); 420 421 return filename__read_int(path, value); 422 } 423