fs.c 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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. #include "fs.h"
  15. #define _STR(x) #x
  16. #define STR(x) _STR(x)
  17. #ifndef SYSFS_MAGIC
  18. #define SYSFS_MAGIC 0x62656572
  19. #endif
  20. #ifndef PROC_SUPER_MAGIC
  21. #define PROC_SUPER_MAGIC 0x9fa0
  22. #endif
  23. #ifndef DEBUGFS_MAGIC
  24. #define DEBUGFS_MAGIC 0x64626720
  25. #endif
  26. #ifndef TRACEFS_MAGIC
  27. #define TRACEFS_MAGIC 0x74726163
  28. #endif
  29. static const char * const sysfs__fs_known_mountpoints[] = {
  30. "/sys",
  31. 0,
  32. };
  33. static const char * const procfs__known_mountpoints[] = {
  34. "/proc",
  35. 0,
  36. };
  37. #ifndef DEBUGFS_DEFAULT_PATH
  38. #define DEBUGFS_DEFAULT_PATH "/sys/kernel/debug"
  39. #endif
  40. static const char * const debugfs__known_mountpoints[] = {
  41. DEBUGFS_DEFAULT_PATH,
  42. "/debug",
  43. 0,
  44. };
  45. #ifndef TRACEFS_DEFAULT_PATH
  46. #define TRACEFS_DEFAULT_PATH "/sys/kernel/tracing"
  47. #endif
  48. static const char * const tracefs__known_mountpoints[] = {
  49. TRACEFS_DEFAULT_PATH,
  50. "/sys/kernel/debug/tracing",
  51. "/tracing",
  52. "/trace",
  53. 0,
  54. };
  55. struct fs {
  56. const char *name;
  57. const char * const *mounts;
  58. char path[PATH_MAX];
  59. bool found;
  60. long magic;
  61. };
  62. enum {
  63. FS__SYSFS = 0,
  64. FS__PROCFS = 1,
  65. FS__DEBUGFS = 2,
  66. FS__TRACEFS = 3,
  67. };
  68. #ifndef TRACEFS_MAGIC
  69. #define TRACEFS_MAGIC 0x74726163
  70. #endif
  71. static struct fs fs__entries[] = {
  72. [FS__SYSFS] = {
  73. .name = "sysfs",
  74. .mounts = sysfs__fs_known_mountpoints,
  75. .magic = SYSFS_MAGIC,
  76. },
  77. [FS__PROCFS] = {
  78. .name = "proc",
  79. .mounts = procfs__known_mountpoints,
  80. .magic = PROC_SUPER_MAGIC,
  81. },
  82. [FS__DEBUGFS] = {
  83. .name = "debugfs",
  84. .mounts = debugfs__known_mountpoints,
  85. .magic = DEBUGFS_MAGIC,
  86. },
  87. [FS__TRACEFS] = {
  88. .name = "tracefs",
  89. .mounts = tracefs__known_mountpoints,
  90. .magic = TRACEFS_MAGIC,
  91. },
  92. };
  93. static bool fs__read_mounts(struct fs *fs)
  94. {
  95. bool found = false;
  96. char type[100];
  97. FILE *fp;
  98. fp = fopen("/proc/mounts", "r");
  99. if (fp == NULL)
  100. return NULL;
  101. while (!found &&
  102. fscanf(fp, "%*s %" STR(PATH_MAX) "s %99s %*s %*d %*d\n",
  103. fs->path, type) == 2) {
  104. if (strcmp(type, fs->name) == 0)
  105. found = true;
  106. }
  107. fclose(fp);
  108. return fs->found = found;
  109. }
  110. static int fs__valid_mount(const char *fs, long magic)
  111. {
  112. struct statfs st_fs;
  113. if (statfs(fs, &st_fs) < 0)
  114. return -ENOENT;
  115. else if ((long)st_fs.f_type != magic)
  116. return -ENOENT;
  117. return 0;
  118. }
  119. static bool fs__check_mounts(struct fs *fs)
  120. {
  121. const char * const *ptr;
  122. ptr = fs->mounts;
  123. while (*ptr) {
  124. if (fs__valid_mount(*ptr, fs->magic) == 0) {
  125. fs->found = true;
  126. strcpy(fs->path, *ptr);
  127. return true;
  128. }
  129. ptr++;
  130. }
  131. return false;
  132. }
  133. static void mem_toupper(char *f, size_t len)
  134. {
  135. while (len) {
  136. *f = toupper(*f);
  137. f++;
  138. len--;
  139. }
  140. }
  141. /*
  142. * Check for "NAME_PATH" environment variable to override fs location (for
  143. * testing). This matches the recommendation in Documentation/sysfs-rules.txt
  144. * for SYSFS_PATH.
  145. */
  146. static bool fs__env_override(struct fs *fs)
  147. {
  148. char *override_path;
  149. size_t name_len = strlen(fs->name);
  150. /* name + "_PATH" + '\0' */
  151. char upper_name[name_len + 5 + 1];
  152. memcpy(upper_name, fs->name, name_len);
  153. mem_toupper(upper_name, name_len);
  154. strcpy(&upper_name[name_len], "_PATH");
  155. override_path = getenv(upper_name);
  156. if (!override_path)
  157. return false;
  158. fs->found = true;
  159. strncpy(fs->path, override_path, sizeof(fs->path));
  160. return true;
  161. }
  162. static const char *fs__get_mountpoint(struct fs *fs)
  163. {
  164. if (fs__env_override(fs))
  165. return fs->path;
  166. if (fs__check_mounts(fs))
  167. return fs->path;
  168. if (fs__read_mounts(fs))
  169. return fs->path;
  170. return NULL;
  171. }
  172. static const char *fs__mountpoint(int idx)
  173. {
  174. struct fs *fs = &fs__entries[idx];
  175. if (fs->found)
  176. return (const char *)fs->path;
  177. return fs__get_mountpoint(fs);
  178. }
  179. static const char *mount_overload(struct fs *fs)
  180. {
  181. size_t name_len = strlen(fs->name);
  182. /* "PERF_" + name + "_ENVIRONMENT" + '\0' */
  183. char upper_name[5 + name_len + 12 + 1];
  184. snprintf(upper_name, name_len, "PERF_%s_ENVIRONMENT", fs->name);
  185. mem_toupper(upper_name, name_len);
  186. return getenv(upper_name) ?: *fs->mounts;
  187. }
  188. static const char *fs__mount(int idx)
  189. {
  190. struct fs *fs = &fs__entries[idx];
  191. const char *mountpoint;
  192. if (fs__mountpoint(idx))
  193. return (const char *)fs->path;
  194. mountpoint = mount_overload(fs);
  195. if (mount(NULL, mountpoint, fs->name, 0, NULL) < 0)
  196. return NULL;
  197. return fs__check_mounts(fs) ? fs->path : NULL;
  198. }
  199. #define FS(name, idx) \
  200. const char *name##__mountpoint(void) \
  201. { \
  202. return fs__mountpoint(idx); \
  203. } \
  204. \
  205. const char *name##__mount(void) \
  206. { \
  207. return fs__mount(idx); \
  208. } \
  209. \
  210. bool name##__configured(void) \
  211. { \
  212. return name##__mountpoint() != NULL; \
  213. }
  214. FS(sysfs, FS__SYSFS);
  215. FS(procfs, FS__PROCFS);
  216. FS(debugfs, FS__DEBUGFS);
  217. FS(tracefs, FS__TRACEFS);
  218. int filename__read_int(const char *filename, int *value)
  219. {
  220. char line[64];
  221. int fd = open(filename, O_RDONLY), err = -1;
  222. if (fd < 0)
  223. return -1;
  224. if (read(fd, line, sizeof(line)) > 0) {
  225. *value = atoi(line);
  226. err = 0;
  227. }
  228. close(fd);
  229. return err;
  230. }
  231. int filename__read_ull(const char *filename, unsigned long long *value)
  232. {
  233. char line[64];
  234. int fd = open(filename, O_RDONLY), err = -1;
  235. if (fd < 0)
  236. return -1;
  237. if (read(fd, line, sizeof(line)) > 0) {
  238. *value = strtoull(line, NULL, 10);
  239. if (*value != ULLONG_MAX)
  240. err = 0;
  241. }
  242. close(fd);
  243. return err;
  244. }
  245. int sysfs__read_ull(const char *entry, unsigned long long *value)
  246. {
  247. char path[PATH_MAX];
  248. const char *sysfs = sysfs__mountpoint();
  249. if (!sysfs)
  250. return -1;
  251. snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
  252. return filename__read_ull(path, value);
  253. }
  254. int sysfs__read_int(const char *entry, int *value)
  255. {
  256. char path[PATH_MAX];
  257. const char *sysfs = sysfs__mountpoint();
  258. if (!sysfs)
  259. return -1;
  260. snprintf(path, sizeof(path), "%s/%s", sysfs, entry);
  261. return filename__read_int(path, value);
  262. }
  263. int sysctl__read_int(const char *sysctl, int *value)
  264. {
  265. char path[PATH_MAX];
  266. const char *procfs = procfs__mountpoint();
  267. if (!procfs)
  268. return -1;
  269. snprintf(path, sizeof(path), "%s/sys/%s", procfs, sysctl);
  270. return filename__read_int(path, value);
  271. }