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 int filename__read_ull(const char *filename, unsigned long long *value) 287 { 288 char line[64]; 289 int fd = open(filename, O_RDONLY), err = -1; 290 291 if (fd < 0) 292 return -1; 293 294 if (read(fd, line, sizeof(line)) > 0) { 295 *value = strtoull(line, NULL, 10); 296 if (*value != ULLONG_MAX) 297 err = 0; 298 } 299 300 close(fd); 301 return err; 302 } 303 304 #define STRERR_BUFSIZE 128 /* For the buffer size of strerror_r */ 305 306 int filename__read_str(const char *filename, char **buf, size_t *sizep) 307 { 308 size_t size = 0, alloc_size = 0; 309 void *bf = NULL, *nbf; 310 int fd, n, err = 0; 311 char sbuf[STRERR_BUFSIZE]; 312 313 fd = open(filename, O_RDONLY); 314 if (fd < 0) 315 return -errno; 316 317 do { 318 if (size == alloc_size) { 319 alloc_size += BUFSIZ; 320 nbf = realloc(bf, alloc_size); 321 if (!nbf) { 322 err = -ENOMEM; 323 break; 324 } 325 326 bf = nbf; 327 } 328 329 n = read(fd, bf + size, alloc_size - size); 330 if (n < 0) { 331 if (size) { 332 pr_warning("read failed %d: %s\n", errno, 333 strerror_r(errno, sbuf, sizeof(sbuf))); 334 err = 0; 335 } else 336 err = -errno; 337 338 break; 339 } 340 341 size += n; 342 } while (n > 0); 343 344 if (!err) { 345 *sizep = size; 346 *buf = bf; 347 } else 348 free(bf); 349 350 close(fd); 351 return err; 352 } 353 354 int procfs__read_str(const char *entry, char **buf, size_t *sizep) 355 { 356 char path[PATH_MAX]; 357 const char *procfs = procfs__mountpoint(); 358 359 if (!procfs) 360 return -1; 361 362 snprintf(path, sizeof(path), "%s/%s", procfs, entry); 363 364 return filename__read_str(path, buf, sizep); 365 } 366 367 int sysfs__read_ull(const char *entry, unsigned long long *value) 368 { 369 char path[PATH_MAX]; 370 const char *sysfs = sysfs__mountpoint(); 371 372 if (!sysfs) 373 return -1; 374 375 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 376 377 return filename__read_ull(path, value); 378 } 379 380 int sysfs__read_int(const char *entry, int *value) 381 { 382 char path[PATH_MAX]; 383 const char *sysfs = sysfs__mountpoint(); 384 385 if (!sysfs) 386 return -1; 387 388 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 389 390 return filename__read_int(path, value); 391 } 392 393 int sysfs__read_str(const char *entry, char **buf, size_t *sizep) 394 { 395 char path[PATH_MAX]; 396 const char *sysfs = sysfs__mountpoint(); 397 398 if (!sysfs) 399 return -1; 400 401 snprintf(path, sizeof(path), "%s/%s", sysfs, entry); 402 403 return filename__read_str(path, buf, sizep); 404 } 405 406 int sysctl__read_int(const char *sysctl, int *value) 407 { 408 char path[PATH_MAX]; 409 const char *procfs = procfs__mountpoint(); 410 411 if (!procfs) 412 return -1; 413 414 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); 415 416 return filename__read_int(path, value); 417 } 418