support negative simple patterns; improved help options; added command line option to test simple patterns
Costa Tsaousis (ktsaou) committed
Jan 15, 2017 at 17:51 UTC
1fc3b1fd4c3d293dcf7ea959440824ad333266f0
3 files changed
+125
-24
src/main.c
+107
-19
@@ -214,20 +214,19 @@ void kill_childs()
214
}
215
216
struct option_def options[] = {
217
- // opt description arg name default value
218
- {'c', "Load alternate configuration file", "config_file", CONFIG_DIR "/" CONFIG_FILENAME},
219
- {'D', "Disable fork into background", NULL, NULL},
220
- {'h', "Display help message", NULL, NULL},
221
- {'P', "File to save a pid while running", "FILE", NULL},
222
- {'i', "The IP address to listen to.", "address", "All addresses"},
223
- {'k', "Check daemon configuration.", NULL, NULL},
224
- {'p', "Port to listen. Can be from 1 to 65535.", "port_number", "19999"},
225
- {'s', "Path to access host /proc and /sys when running in a container.", "PATH", NULL},
226
- {'t', "The frequency in seconds, for data collection. \
227
-Same as 'update every' config file option.", "seconds", "1"},
228
- {'u', "System username to run as.", "username", "netdata"},
229
- {'v', "Version of the program", NULL, NULL},
230
- {'W', "vendor options.", "stacksize=N|unittest|debug_flags=N", NULL},
217
+ // opt description arg name default value
218
+ { 'c', "Configuration file to load.", "filename", CONFIG_DIR "/" CONFIG_FILENAME},
219
+ { 'D', "Do not fork. Run in the foreground.", NULL, "run in the background"},
220
+ { 'h', "Display this help message.", NULL, NULL},
221
+ { 'P', "File to save a pid while running.", "filename", "do not save pid to a file"},
222
+ { 'i', "The IP address to listen to.", "IP", "all IP addresses IPv4 and IPv6"},
223
+ { 'k', "Check health configuration and exit.", NULL, NULL},
224
+ { 'p', "API/Web port to use.", "port", "19999"},
225
+ { 's', "Prefix for /proc and /sys (for containers).", "path", "no prefix"},
226
+ { 't', "The internal clock of netdata.", "seconds", "1"},
227
+ { 'u', "Run as user.", "username", "netdata"},
228
+ { 'v', "Print netdata version and exit.", NULL, NULL},
229
+ { 'W', "See Advanced options below.", "options", NULL},
230
};
231
232
void help(int exitcode) {
@@ -249,20 +248,63 @@ void help(int exitcode) {
248
}
249
}
250
252
- fprintf(stream, "SYNOPSIS: netdata [options]\n");
251
+ if(max_len_arg > 30) max_len_arg = 30;
252
+ if(max_len_arg < 20) max_len_arg = 20;
253
+
254
+ fprintf(stream, "\n"
255
+ " ^\n"
256
+ " |.-. .-. .-. .-. . netdata \n"
257
+ " | '-' '-' '-' '-' real-time performance monitoring, done right! \n"
258
+ " +----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+-----+--->\n"
259
+ "\n"
260
+ " Copyright (C) 2017, Costa Tsaousis <costa@tsaousis.gr>\n"
261
+ " Released under GNU Public License v3 or later.\n"
262
+ " All rights reserved.\n"
263
+ "\n"
264
+ " Home Page : https://my-netdata.io\n"
265
+ " Source Code: https://github.com/firehol/netdata\n"
266
+ " Wiki / Docs: https://github.com/firehol/netdata/wiki\n"
267
+ " Support : https://github.com/firehol/netdata/issues\n"
268
+ " License : https://github.com/firehol/netdata/blob/master/LICENSE.md\n"
269
+ "\n"
270
+ " Twitter : https://twitter.com/linuxnetdata\n"
271
+ " Facebook : https://www.facebook.com/linuxnetdata/\n"
272
+ "\n"
273
+ " netdata is a https://firehol.org project.\n"
274
+ "\n"
275
+ "\n"
276
+ );
277
+
278
+ fprintf(stream, " SYNOPSIS: netdata [options]\n");
279
fprintf(stream, "\n");
254
- fprintf(stream, "Options:\n");
280
+ fprintf(stream, " Options:\n\n");
281
282
// Output options description.
283
for( i = 0; i < num_opts; i++ ) {
284
fprintf(stream, " -%c %-*s %s", options[i].val, max_len_arg, options[i].arg_name ? options[i].arg_name : "", options[i].description);
285
if(options[i].default_value) {
260
- fprintf(stream, " Default: %s\n", options[i].default_value);
286
+ fprintf(stream, "\n %c %-*s Default: %s\n", ' ', max_len_arg, "", options[i].default_value);
287
} else {
288
fprintf(stream, "\n");
289
}
290
+ fprintf(stream, "\n");
291
}
292
293
+ fprintf(stream, "\n Advanced options:\n\n"
294
+ " -W stacksize=N Set the stacksize (in bytes).\n\n"
295
+ " -W debug_flags=N Set runtime tracing to debug.log.\n\n"
296
+ " -W unittest Run internal unittests and exit.\n\n"
297
+ " -W simple-pattern pattern string\n"
298
+ " Check if string matches pattern and exit.\n\n"
299
+ );
300
+
301
+ fprintf(stream, "\n Signals netdata handles:\n\n"
302
+ " - HUP Close and reopen log files.\n"
303
+ " - USR1 Save internal DB to disk.\n"
304
+ " - USR2 Reload health configuration.\n"
305
+ "\n"
306
+ );
307
+
308
fflush(stream);
309
exit(exitcode);
310
}
@@ -347,6 +389,9 @@ int main(int argc, char **argv)
389
string_i++;
390
}
391
}
392
+ // terminate optstring
393
+ optstring[string_i] ='\0';
394
+ optstring[(num_opts *2)] ='\0';
395
396
int opt;
397
while( (opt = getopt(argc, argv, optstring)) != -1 ) {
@@ -404,10 +449,53 @@ int main(int argc, char **argv)
449
if(unit_test_storage()) exit(1);
450
fprintf(stderr, "\n\nALL TESTS PASSED\n\n");
451
exit(0);
407
- } else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
452
+ }
453
+ else if(strcmp(optarg, "simple-pattern") == 0) {
454
+ if(optind + 2 > argc) {
455
+ fprintf(stderr, "%s", "\nUSAGE: -W simple-pattern 'pattern' 'string'\n\n"
456
+ " Checks if 'pattern' matches the given 'string'.\n"
457
+ " - 'pattern' can be one or more space separated words.\n"
458
+ " - each 'word' can contain one or more asterisks.\n"
459
+ " - words starting with '!' give negative matches.\n"
460
+ " - words are processed left to right\n"
461
+ "\n"
462
+ "Examples:\n"
463
+ "\n"
464
+ " > match all veth interfaces, except veth0:\n"
465
+ "\n"
466
+ " -W simple-pattern '!veth0 veth*' 'veth12'\n"
467
+ "\n"
468
+ "\n"
469
+ " > match all *.ext files directly in /path/:\n"
470
+ " (this will not match *.ext files in a subdir of /path/)\n"
471
+ "\n"
472
+ " -W simple-pattern '!/path/*/*.ext /path/*.ext' '/path/test.ext'\n"
473
+ "\n"
474
+ );
475
+ exit(1);
476
+ }
477
+
478
+ const char *heystack = argv[optind];
479
+ const char *needle = argv[optind + 1];
480
+
481
+ NETDATA_SIMPLE_PATTERN *p = netdata_simple_pattern_list_create(heystack, NETDATA_SIMPLE_PATTERN_MODE_EXACT);
482
+ int ret = netdata_simple_pattern_list_matches(p, needle);
483
+ netdata_simple_pattern_free(p);
484
+
485
+ if(ret) {
486
+ fprintf(stdout, "RESULT: MATCHED - pattern '%s' matches '%s'\n", heystack, needle);
487
+ exit(0);
488
+ }
489
+ else {
490
+ fprintf(stdout, "RESULT: NOT MATCHED - pattern '%s' does not match '%s'\n", heystack, needle);
491
+ exit(1);
492
+ }
493
+ }
494
+ else if(strncmp(optarg, stacksize_string, strlen(stacksize_string)) == 0) {
495
optarg += strlen(stacksize_string);
496
config_set("global", "pthread stack size", optarg);
410
- } else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
497
+ }
498
+ else if(strncmp(optarg, debug_flags_string, strlen(debug_flags_string)) == 0) {
499
optarg += strlen(debug_flags_string);
500
config_set("global", "debug flags", optarg);
501
debug_flags = strtoull(optarg, NULL, 0);
src/simple_pattern.c
+17
-4
@@ -3,7 +3,9 @@
3
struct simple_pattern {
4
const char *match;
5
size_t len;
6
+
7
NETDATA_SIMPLE_PREFIX_MODE mode;
8
+ char negative;
9
10
struct simple_pattern *child;
11
@@ -26,7 +28,7 @@ static inline struct simple_pattern *parse_pattern(const char *str, NETDATA_SIMP
28
while(*c == '*') c++;
29
30
// find the next asterisk
29
- while(*c && *c != '*') c++ ;
31
+ while(*c && *c != '*') c++;
32
33
// do we have an asterisk in the middle?
34
if(*c == '*' && c[1] != '\0') {
@@ -57,7 +59,7 @@ static inline struct simple_pattern *parse_pattern(const char *str, NETDATA_SIMP
59
// allocate the structure
60
struct simple_pattern *m = callocz(1, sizeof(struct simple_pattern));
61
if(*s) {
60
- m->match = strdup(s);
62
+ m->match = strdupz(s);
63
m->len = strlen(m->match);
64
m->mode = mode;
65
}
@@ -67,7 +69,7 @@ static inline struct simple_pattern *parse_pattern(const char *str, NETDATA_SIMP
69
70
m->child = child;
71
70
- free(buf);
72
+ freez(buf);
73
74
/*
75
* DEBUG
@@ -95,9 +97,16 @@ NETDATA_SIMPLE_PATTERN *netdata_simple_pattern_list_create(const char *list, NET
97
char *s = buf;
98
99
while(s && *s) {
100
+ char negative = 0;
101
+
102
// skip all spaces
103
while(isspace(*s)) s++;
104
105
+ if(*s == '!') {
106
+ negative = 1;
107
+ s++;
108
+ }
109
+
110
// empty string
111
if(unlikely(!*s)) break;
112
@@ -114,6 +123,7 @@ NETDATA_SIMPLE_PATTERN *netdata_simple_pattern_list_create(const char *list, NET
123
*c = '\0';
124
125
struct simple_pattern *m = parse_pattern(s, default_mode);
126
+ m->negative = negative;
127
128
if(likely(n)) *c = ' ';
129
@@ -130,7 +140,7 @@ NETDATA_SIMPLE_PATTERN *netdata_simple_pattern_list_create(const char *list, NET
140
}
141
}
142
133
- free(buf);
143
+ freez(buf);
144
return (NETDATA_SIMPLE_PATTERN *)root;
145
}
146
@@ -211,6 +221,7 @@ int netdata_simple_pattern_list_matches(NETDATA_SIMPLE_PATTERN *list, const char
221
p->mode);
222
*/
223
224
+ if(m->negative) return 0;
225
return 1;
226
}
227
@@ -218,6 +229,8 @@ int netdata_simple_pattern_list_matches(NETDATA_SIMPLE_PATTERN *list, const char
229
}
230
231
static inline void free_pattern(struct simple_pattern *m) {
232
+ if(!m) return;
233
+
234
if(m->next) free_pattern(m->next);
235
if(m->child) free_pattern(m->child);
236
freez((void *)m->match);
src/sys_fs_cgroup.c
+1
-1
@@ -144,7 +144,7 @@ void read_cgroup_plugin_configuration() {
144
if(cgroup_enable_systemd_services)
145
systemd_services_cgroups = netdata_simple_pattern_list_create(
146
config_get("plugin:cgroups", "cgroups to match as systemd services",
147
- " /system.slice/*.service "
147
+ " !/system.slice/*/*.service /system.slice/*.service "
148
), NETDATA_SIMPLE_PATTERN_MODE_EXACT);
149
150
mountinfo_free(root);