1/* TODO merge/factor in debugfs.c here */ 2 3#include <ctype.h> 4#include <errno.h> 5#include <stdbool.h> 6#include <stdio.h> 7#include <stdlib.h> 8#include <string.h> 9#include <sys/vfs.h> 10#include <sys/types.h> 11#include <sys/stat.h> 12#include <fcntl.h> 13#include <unistd.h> 14 15#include "debugfs.h" 16#include "fs.h" 17 18static const char * const sysfs__fs_known_mountpoints[] = { 19 "/sys", 20 0, 21}; 22 23static const char * const procfs__known_mountpoints[] = { 24 "/proc", 25 0, 26}; 27 28struct fs { 29 const char *name; 30 const char * const *mounts; 31 char path[PATH_MAX + 1]; 32 bool found; 33 long magic; 34}; 35 36enum { 37 FS__SYSFS = 0, 38 FS__PROCFS = 1, 39}; 40 41static struct fs fs__entries[] = { 42 [FS__SYSFS] = { 43 .name = "sysfs", 44 .mounts = sysfs__fs_known_mountpoints, 45 .magic = SYSFS_MAGIC, 46 }, 47 [FS__PROCFS] = { 48 .name = "proc", 49 .mounts = procfs__known_mountpoints, 50 .magic = PROC_SUPER_MAGIC, 51 }, 52}; 53 54static bool fs__read_mounts(struct fs *fs) 55{ 56 bool found = false; 57 char type[100]; 58 FILE *fp; 59 60 fp = fopen("/proc/mounts", "r"); 61 if (fp == NULL) 62 return NULL; 63 64 while (!found && 65 fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n", 66 fs->path, type) == 2) { 67 68 if (strcmp(type, fs->name) == 0) 69 found = true; 70 } 71 72 fclose(fp); 73 return fs->found = found; 74} 75 76static int fs__valid_mount(const char *fs, long magic) 77{ 78 struct statfs st_fs; 79 80 if (statfs(fs, &st_fs) < 0) 81 return -ENOENT; 82 else if ((long)st_fs.f_type != magic) 83 return -ENOENT; 84 85 return 0; 86} 87 88static bool fs__check_mounts(struct fs *fs) 89{ 90 const char * const *ptr; 91 92 ptr = fs->mounts; 93 while (*ptr) { 94 if (fs__valid_mount(*ptr, fs->magic) == 0) { 95 fs->found = true; 96 strcpy(fs->path, *ptr); 97 return true; 98 } 99 ptr++; 100 } 101 102 return false; 103} 104 105static void mem_toupper(char *f, size_t len) 106{ 107 while (len) { 108 *f = toupper(*f); 109 f++; 110 len--; 111 } 112} 113 114/* 115 * Check for "NAME_PATH" environment variable to override fs location (for 116 * testing). This matches the recommendation in Documentation/sysfs-rules.txt 117 * for SYSFS_PATH. 118 */ 119static bool fs__env_override(struct fs *fs) 120{ 121 char *override_path; 122 size_t name_len = strlen(fs->name); 123 /* name + "_PATH" + '\0' */ 124 char upper_name[name_len + 5 + 1]; 125 memcpy(upper_name, fs->name, name_len); 126 mem_toupper(upper_name, name_len); 127 strcpy(&upper_name[name_len], "_PATH"); 128 129 override_path = getenv(upper_name); 130 if (!override_path) 131 return false; 132 133 fs->found = true; 134 strncpy(fs->path, override_path, sizeof(fs->path)); 135 return true; 136} 137 138static const char *fs__get_mountpoint(struct fs *fs) 139{ 140 if (fs__env_override(fs)) 141 return fs->path; 142 143 if (fs__check_mounts(fs)) 144 return fs->path; 145 146 if (fs__read_mounts(fs)) 147 return fs->path; 148 149 return NULL; 150} 151 152static const char *fs__mountpoint(int idx) 153{ 154 struct fs *fs = &fs__entries[idx]; 155 156 if (fs->found) 157 return (const char *)fs->path; 158 159 return fs__get_mountpoint(fs); 160} 161 162#define FS__MOUNTPOINT(name, idx) \ 163const char *name##__mountpoint(void) \ 164{ \ 165 return fs__mountpoint(idx); \ 166} 167 168FS__MOUNTPOINT(sysfs, FS__SYSFS); 169FS__MOUNTPOINT(procfs, FS__PROCFS); 170 171int filename__read_int(const char *filename, int *value) 172{ 173 char line[64]; 174 int fd = open(filename, O_RDONLY), err = -1; 175 176 if (fd < 0) 177 return -1; 178 179 if (read(fd, line, sizeof(line)) > 0) { 180 *value = atoi(line); 181 err = 0; 182 } 183 184 close(fd); 185 return err; 186} 187 188int sysctl__read_int(const char *sysctl, int *value) 189{ 190 char path[PATH_MAX]; 191 const char *procfs = procfs__mountpoint(); 192 193 if (!procfs) 194 return -1; 195 196 snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl); 197 198 return filename__read_int(path, value); 199} 200