fs.c 7.5 KB

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