master
c 280 lines 7.69 KB
Raw
1 // SPDX-License-Identifier: GPL-3.0-or-later
2
3 #include "debugfs_plugin.h"
4
5 static char *user_config_dir = CONFIG_DIR;
6 static char *stock_config_dir = LIBCONFIG_DIR;
7
8 static int update_every = 1;
9
10 netdata_mutex_t stdout_mutex;
11
12 static void __attribute__((constructor)) init_mutex(void) {
13 netdata_mutex_init(&stdout_mutex);
14 }
15
16 static void __attribute__((destructor)) destroy_mutex(void) {
17 netdata_mutex_destroy(&stdout_mutex);
18 }
19
20 static struct debugfs_module {
21 const char *name;
22 int enabled;
23 int (*func)(int update_every, const char *name);
24 } debugfs_modules[] = {
25 {
26 // Memory Fragmentation
27 .name = "/sys/kernel/debug/extfrag",
28 .enabled = CONFIG_BOOLEAN_YES,
29 .func = do_module_numa_extfrag
30 },
31 {
32 .name = "/sys/kernel/debug/zswap",
33 .enabled = CONFIG_BOOLEAN_YES,
34 .func = do_module_zswap
35 },
36 {
37 // Linux powercap metrics is here because it needs privilege to read each RAPL zone
38 .name = "/sys/devices/virtual/powercap",
39 .enabled = CONFIG_BOOLEAN_YES,
40 .func = do_module_devices_powercap
41 },
42 {
43 .name = "libsensors",
44 .enabled = CONFIG_BOOLEAN_YES,
45 .func = do_module_libsensors
46 },
47 {
48 // Linux audit subsystem status via netlink
49 .name = "audit",
50 .enabled = CONFIG_BOOLEAN_YES,
51 .func = do_module_audit
52 },
53
54 // The terminator
55 {.name = NULL, .enabled = CONFIG_BOOLEAN_NO, .func = NULL}
56 };
57
58 #ifdef HAVE_CAPABILITY
59 static int debugfs_check_capabilities()
60 {
61 cap_t caps = cap_get_proc();
62 if (!caps) {
63 netdata_log_error("Cannot get current capabilities.");
64 return 0;
65 }
66
67 int ret = 1;
68 cap_flag_value_t cfv = CAP_CLEAR;
69 if (cap_get_flag(caps, CAP_DAC_READ_SEARCH, CAP_EFFECTIVE, &cfv) == -1) {
70 netdata_log_error("Cannot find if CAP_DAC_READ_SEARCH is effective.");
71 ret = 0;
72 } else {
73 if (cfv != CAP_SET) {
74 netdata_log_error("debugfs.plugin should run with CAP_DAC_READ_SEARCH.");
75 ret = 0;
76 }
77 }
78 cap_free(caps);
79
80 return ret;
81 }
82 #else
83 static int debugfs_check_capabilities()
84 {
85 return 0;
86 }
87 #endif
88
89 // TODO: This is a function used by 3 different collector, we should do it global (next PR)
90 static int debugfs_am_i_running_as_root()
91 {
92 uid_t uid = getuid(), euid = geteuid();
93
94 if (uid == 0 || euid == 0) {
95 return 1;
96 }
97
98 return 0;
99 }
100
101 void debugfs2lower(char *name)
102 {
103 while (*name) {
104 *name = tolower(*name);
105 name++;
106 }
107 }
108
109 // Consiidering our goal to redce binaries, I preferred to copy function, instead to force link with unecessary libs
110 const char *debugfs_rrdset_type_name(RRDSET_TYPE chart_type) {
111 switch(chart_type) {
112 case RRDSET_TYPE_LINE:
113 default:
114 return RRDSET_TYPE_LINE_NAME;
115
116 case RRDSET_TYPE_AREA:
117 return RRDSET_TYPE_AREA_NAME;
118
119 case RRDSET_TYPE_STACKED:
120 return RRDSET_TYPE_STACKED_NAME;
121 }
122 }
123
124 const char *debugfs_rrd_algorithm_name(RRD_ALGORITHM algorithm) {
125 switch(algorithm) {
126 case RRD_ALGORITHM_ABSOLUTE:
127 default:
128 return RRD_ALGORITHM_ABSOLUTE_NAME;
129
130 case RRD_ALGORITHM_INCREMENTAL:
131 return RRD_ALGORITHM_INCREMENTAL_NAME;
132
133 case RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL:
134 return RRD_ALGORITHM_PCENT_OVER_ROW_TOTAL_NAME;
135
136 case RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL:
137 return RRD_ALGORITHM_PCENT_OVER_DIFF_TOTAL_NAME;
138 }
139 }
140
141 int debugfs_check_sys_permission() {
142 int ret = 0;
143
144 char filename[FILENAME_MAX + 1];
145
146 snprintfz(filename, FILENAME_MAX, "%s/sys/kernel/debug/extfrag/extfrag_index", netdata_configured_host_prefix);
147
148 procfile *ff = procfile_open(filename, NULL, PROCFILE_FLAG_NO_ERROR_ON_FILE_IO);
149 if(!ff) goto dcsp_cleanup;
150
151 ff = procfile_readall(ff);
152 if(!ff) goto dcsp_cleanup;
153
154 ret = 1;
155
156 dcsp_cleanup:
157 if (!ret)
158 perror("Cannot open /sys/kernel/debug/extfrag/extfrag_index file");
159 procfile_close(ff);
160 return ret;
161 }
162
163 static void debugfs_parse_args(int argc, char **argv)
164 {
165 int i, freq = 0;
166 for(i = 1; i < argc; i++) {
167 if(!freq) {
168 int n = (int)str2l(argv[i]);
169 if(n > 0) {
170 freq = n;
171 continue;
172 }
173 }
174
175 if(strcmp("test-permissions", argv[i]) == 0 || strcmp("-t", argv[i]) == 0) {
176 if(!debugfs_check_sys_permission()) {
177 exit(2);
178 }
179 printf("OK\n");
180 exit(0);
181 }
182 }
183
184 if(freq > 0) update_every = freq;
185 }
186
187 int main(int argc, char **argv)
188 {
189 nd_log_initialize_for_external_plugins("debugfs.plugin");
190 netdata_threads_init_for_external_plugins(0);
191
192 netdata_configured_host_prefix = getenv("NETDATA_HOST_PREFIX");
193 if (verify_netdata_host_prefix(true) == -1)
194 exit(1);
195
196 user_config_dir = getenv("NETDATA_USER_CONFIG_DIR");
197 if (user_config_dir == NULL) {
198 user_config_dir = CONFIG_DIR;
199 }
200
201 stock_config_dir = getenv("NETDATA_STOCK_CONFIG_DIR");
202 if (stock_config_dir == NULL) {
203 // netdata_log_info("NETDATA_CONFIG_DIR is not passed from netdata");
204 stock_config_dir = LIBCONFIG_DIR;
205 }
206
207 // FIXME: should first check if /sys/kernel/debug is mounted
208
209 // FIXME: remove debugfs_check_sys_permission() after https://github.com/netdata/netdata/issues/15048 is fixed
210 if (!debugfs_check_capabilities() && !debugfs_am_i_running_as_root() && !debugfs_check_sys_permission()) {
211 uid_t uid = getuid(), euid = geteuid();
212 #ifdef HAVE_CAPABILITY
213 netdata_log_error(
214 "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
215 "cap_dac_read_search is needed for /sys/kernel/debug access, cap_audit_control for audit subsystem monitoring. "
216 "To enable capabilities run: sudo setcap cap_dac_read_search,cap_audit_control+ep %s; "
217 "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
218 uid,
219 euid,
220 argv[0],
221 argv[0],
222 argv[0]);
223 #else
224 netdata_log_error(
225 "debugfs.plugin should either run as root (now running with uid %u, euid %u) or have special capabilities. "
226 "Without these, debugfs.plugin cannot access /sys/kernel/debug."
227 "Your system does not support capabilities. "
228 "To enable setuid to root run: sudo chown root:netdata %s; sudo chmod 4750 %s; ",
229 uid,
230 euid,
231 argv[0],
232 argv[0]);
233 #endif
234 exit(1);
235 }
236
237 debugfs_parse_args(argc, argv);
238
239 size_t iteration;
240 heartbeat_t hb;
241 heartbeat_init(&hb, update_every * USEC_PER_SEC);
242
243 for (iteration = 0; iteration < 86400; iteration++) {
244 heartbeat_next(&hb);
245 int enabled = 0;
246
247 for (int i = 0; debugfs_modules[i].name; i++) {
248 struct debugfs_module *pm = &debugfs_modules[i];
249 if (unlikely(!pm->enabled))
250 continue;
251
252 pm->enabled = !pm->func(update_every, pm->name);
253 if (likely(pm->enabled))
254 enabled++;
255 }
256
257 if (!enabled) {
258 netdata_log_info("all modules are disabled, exiting...");
259 return 1;
260 }
261
262 netdata_mutex_lock(&stdout_mutex);
263 fprintf(stdout, "\n");
264 fflush(stdout);
265 netdata_mutex_unlock(&stdout_mutex);
266
267 if (ferror(stdout) && errno == EPIPE) {
268 netdata_log_error("error writing to stdout: EPIPE. Exiting...");
269 return 1;
270 }
271 }
272
273 module_libsensors_cleanup();
274
275 netdata_mutex_lock(&stdout_mutex);
276 fprintf(stdout, "EXIT\n");
277 fflush(stdout);
278 netdata_mutex_unlock(&stdout_mutex);
279 return 0;
280 }