debugfs_plugin.c 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. // SPDX-License-Identifier: GPL-3.0-or-later
  2. #include "debugfs_plugin.h"
  3. #include "libnetdata/required_dummies.h"
  4. static char *user_config_dir = CONFIG_DIR;
  5. static char *stock_config_dir = LIBCONFIG_DIR;
  6. static int update_every = 1;
  7. static struct debugfs_module {
  8. const char *name;
  9. int enabled;
  10. int (*func)(int update_every, const char *name);
  11. } debugfs_modules[] = {
  12. // Memory Fragmentation
  13. { .name = "/sys/kernel/debug/extfrag", .enabled = CONFIG_BOOLEAN_YES,
  14. .func = do_debugfs_extfrag},
  15. { .name = "/sys/kernel/debug/zswap", .enabled = CONFIG_BOOLEAN_YES,
  16. .func = do_debugfs_zswap},
  17. // Linux powercap metrics is here because it needs privilege to read each RAPL zone
  18. { .name = "/sys/devices/virtual/powercap", .enabled = CONFIG_BOOLEAN_YES,
  19. .func = do_sys_devices_virtual_powercap},
  20. // The terminator
  21. { .name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
  22. };
  23. #ifdef HAVE_SYS_CAPABILITY_H
  24. static int debugfs_check_capabilities()
  25. {
  26. cap_t caps = cap_get_proc();
  27. if (!caps) {
  28. netdata_log_error("Cannot get current capabilities.");
  29. return 0;
  30. }
  31. int ret = 1;
  32. cap_flag_value_t cfv = CAP_CLEAR;
  33. if (cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
  34. netdata_log_error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
  35. ret = 0;
  36. } else {
  37. if (cfv != CAP_SET) {
  38. netdata_log_error("debugfs.plugin should run with CAP_DAC_READ_SEARCH.");
  39. ret = 0;
  40. }
  41. }
  42. cap_free(caps);
  43. return ret;
  44. }
  45. #else
  46. static int debugfs_check_capabilities()
  47. {
  48. return 0;
  49. }
  50. #endif
  51. // TODO: This is a function used by 3 different collector, we should do it global (next PR)
  52. static int debugfs_am_i_running_as_root()
  53. {
  54. uid_t uid = getuid(), euid = geteuid();
  55. if (uid == 0 || euid == 0) {
  56. return 1;
  57. }
  58. return 0;
  59. }
  60. void debugfs2lower(char *name)
  61. {
  62. while (*name) {
  63. *name = tolower(*name);
  64. name++;
  65. }
  66. }
  67. // Consiidering our goal to redce binaries, I preferred to copy function, instead to force link with unecessary libs
  68. const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type) {
  69. switch(chart_type) {
  70. case RRDSET_TYPE_LINE:
  71. default:
  72. return RRDSET_TYPE_LINE_NAME;
  73. case RRDSET_TYPE_AREA:
  74. return RRDSET_TYPE_AREA_NAME;
  75. case RRDSET_TYPE_STACKED:
  76. return RRDSET_TYPE_STACKED_NAME;
  77. }
  78. }
  79. const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm) {
  80. switch(algorithm) {
  81. case RRD_ALGORITHM_ABSOLUTE:
  82. default:
  83. return RRD_ALGORITHM_ABSOLUTE_NAME;
  84. case RRD_ALGORITHM_INCREMENTAL:
  85. return RRD_ALGORITHM_INCREMENTAL_NAME;
  86. case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
  87. return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
  88. case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
  89. return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
  90. }
  91. }
  92. int debugfs_check_sys_permission() {
  93. int ret = 0;
  94. char filename[FILENAME_MAX + 1];
  95. snprintfz(filename, FILENAME_MAX, "%s/sys/kernel/debug/extfrag/extfrag_index", netdata_configured_host_prefix);
  96. procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
  97. if(!ff) goto dcsp_cleanup;
  98. ff = procfile_readall(ff);
  99. if(!ff) goto dcsp_cleanup;
  100. ret = 1;
  101. dcsp_cleanup:
  102. if (!ret)
  103. perror("Cannot open /sys/kernel/debug/extfrag/extfrag_index file");
  104. procfile_close(ff);
  105. return ret;
  106. }
  107. static void debugfs_parse_args(int argc, char **argv)
  108. {
  109. int i, freq = 0;
  110. for(i = 1; i < argc; i++) {
  111. if(!freq) {
  112. int n = (int)str2l(argv[i]);
  113. if(n > 0) {
  114. freq = n;
  115. continue;
  116. }
  117. }
  118. if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
  119. if(!debugfs_check_sys_permission()) {
  120. exit(2);
  121. }
  122. printf("OK\n");
  123. exit(0);
  124. }
  125. }
  126. if(freq > 0) update_every = freq;
  127. }
  128. int main(int argc, char **argv)
  129. {
  130. clocks_init();
  131. nd_log_initialize_for_external_plugins("debugfs.plugin");
  132. netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
  133. if (verify_netdata_host_prefix() == -1)
  134. exit(1);
  135. user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
  136. if (user_config_dir == NULL) {
  137. user_config_dir = CONFIG_DIR;
  138. }
  139. stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
  140. if (stock_config_dir == NULL) {
  141. // netdata_log_info("NETDATA_CONFIG_DIR is not passed from netdata");
  142. stock_config_dir = LIBCONFIG_DIR;
  143. }
  144. // FIXME: should first check if /sys/kernel/debug is mounted
  145. // FIXME: remove debugfs_check_sys_permission() after https://github.com/netdata/netdata/issues/15048 is fixed
  146. if (!debugfs_check_capabilities() && !debugfs_am_i_running_as_root() && !debugfs_check_sys_permission()) {
  147. uid_t uid = getuid(), euid = geteuid();
  148. #ifdef HAVE_SYS_CAPABILITY_H
  149. netdata_log_error(
  150. "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
  151. "Without these, debugfs.plugin cannot access /sys/kernel/debug. "
  152. "To enable capabilities run: sudo setcap cap_dac_read_search,cap_sys_ptrace+ep %s; "
  153. "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
  154. uid,
  155. euid,
  156. argv[0],
  157. argv[0],
  158. argv[0]);
  159. #else
  160. netdata_log_error(
  161. "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
  162. "Without these, debugfs.plugin cannot access /sys/kernel/debug."
  163. "Your system does not support capabilities. "
  164. "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
  165. uid,
  166. euid,
  167. argv[0],
  168. argv[0]);
  169. #endif
  170. exit(1);
  171. }
  172. // if (!debugfs_check_sys_permission()) {
  173. // exit(2);
  174. // }
  175. debugfs_parse_args(argc, argv);
  176. size_t iteration;
  177. usec_t step = update_every * USEC_PER_SEC;
  178. heartbeat_t hb;
  179. heartbeat_init(&hb);
  180. for (iteration = 0; iteration < 86400; iteration++) {
  181. heartbeat_next(&hb, step);
  182. int enabled = 0;
  183. for (int i = 0; debugfs_modules[i].name; i++) {
  184. struct debugfs_module *pm = &debugfs_modules[i];
  185. if (unlikely(!pm->enabled))
  186. continue;
  187. pm->enabled = !pm->func(update_every, pm->name);
  188. if (likely(pm->enabled))
  189. enabled++;
  190. }
  191. if (!enabled) {
  192. netdata_log_info("all modules are disabled, exiting...");
  193. return 1;
  194. }
  195. fprintf(stdout, "\n");
  196. fflush(stdout);
  197. if (ferror(stdout) && errno == EPIPE) {
  198. netdata_log_error("error writing to stdout: EPIPE. Exiting...");
  199. return 1;
  200. }
  201. }
  202. fprintf(stdout, "EXIT\n");
  203. fflush(stdout);
  204. return 0;
  205. }