Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
at v4.4-rc3 340 lines 6.2 kB view raw
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 36static const char * const sysfs__fs_known_mountpoints[] = { 37 "/sys", 38 0, 39}; 40 41static 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 50static 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 61static const char * const tracefs__known_mountpoints[] = { 62 TRACEFS_DEFAULT_PATH, 63 "/sys/kernel/debug/tracing", 64 "/tracing", 65 "/trace", 66 0, 67}; 68 69struct fs { 70 const char *name; 71 const char * const *mounts; 72 char path[PATH_MAX]; 73 bool found; 74 long magic; 75}; 76 77enum { 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 88static 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 111static 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 133static 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 145static 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 162static 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 */ 176static 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 195static 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 209static 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 219static 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 231static 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) \ 248const char *name##__mountpoint(void) \ 249{ \ 250 return fs__mountpoint(idx); \ 251} \ 252 \ 253const char *name##__mount(void) \ 254{ \ 255 return fs__mount(idx); \ 256} \ 257 \ 258bool name##__configured(void) \ 259{ \ 260 return name##__mountpoint() != NULL; \ 261} 262 263FS(sysfs, FS__SYSFS); 264FS(procfs, FS__PROCFS); 265FS(debugfs, FS__DEBUGFS); 266FS(tracefs, FS__TRACEFS); 267 268int 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 285int 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 303int 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 316int 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 329int 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}