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 18 static const char * const sysfs__fs_known_mountpoints[] = { 19 "/sys", 20 0, 21 }; 22 23 static const char * const procfs__known_mountpoints[] = { 24 "/proc", 25 0, 26 }; 27 28 struct fs { 29 const char *name; 30 const char * const *mounts; 31 char path[PATH_MAX + 1]; 32 bool found; 33 long magic; 34 }; 35 36 enum { 37 FS__SYSFS = 0, 38 FS__PROCFS = 1, 39 }; 40 41 static 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 54 static 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 76 static 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 88 static 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 105 static 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 */ 119 static 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 138 static 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 152 static 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) \ 163 const char *name##__mountpoint(void) \ 164 { \ 165 return fs__mountpoint(idx); \ 166 } 167 168 FS__MOUNTPOINT(sysfs, FS__SYSFS); 169 FS__MOUNTPOINT(procfs, FS__PROCFS); 170 171 int 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 188 int 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