Use compiler-agnostic defines to silence warning
[lttng-tools.git] / src / bin / lttng / commands / add_trigger.cpp
1 /*
2 * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #include "../command.hpp"
9 #include "../loglevel.hpp"
10 #include "../uprobe.hpp"
11 #include "common/argpar-utils/argpar-utils.hpp"
12 #include "common/dynamic-array.hpp"
13 #include "common/mi-lttng.hpp"
14 #include "common/string-utils/string-utils.hpp"
15 #include "common/utils.hpp"
16 #include "vendor/argpar/argpar.h"
17
18 #include <lttng/domain-internal.hpp>
19
20 #include <ctype.h>
21 #include <stdarg.h>
22 #include <stdio.h>
23 #include <string.h>
24 /* For lttng_event_rule_type_str(). */
25 #include "common/dynamic-array.hpp"
26 #include "common/filter/filter-ast.hpp"
27 #include "common/filter/filter-ir.hpp"
28
29 #include <lttng/event-rule/event-rule-internal.hpp>
30 #include <lttng/lttng.h>
31
32 #if (LTTNG_SYMBOL_NAME_LEN == 256)
33 #define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
34 #endif
35
36 #ifdef LTTNG_EMBED_HELP
37 static const char help_msg[] =
38 #include <lttng-add-trigger.1.h>
39 ;
40 #endif
41
42 enum {
43 OPT_HELP,
44 OPT_LIST_OPTIONS,
45
46 OPT_CONDITION,
47 OPT_ACTION,
48 OPT_ID,
49 OPT_OWNER_UID,
50 OPT_RATE_POLICY,
51
52 OPT_NAME,
53 OPT_FILTER,
54 OPT_EXCLUDE_NAME,
55 OPT_EVENT_NAME,
56 OPT_LOG_LEVEL,
57
58 OPT_TYPE,
59 OPT_LOCATION,
60
61 OPT_MAX_SIZE,
62 OPT_DATA_URL,
63 OPT_CTRL_URL,
64 OPT_URL,
65 OPT_PATH,
66
67 OPT_CAPTURE,
68 };
69
70 static const struct argpar_opt_descr event_rule_opt_descrs[] = {
71 { OPT_FILTER, 'f', "filter", true },
72 { OPT_NAME, 'n', "name", true },
73 { OPT_EXCLUDE_NAME, 'x', "exclude-name", true },
74 { OPT_LOG_LEVEL, 'l', "log-level", true },
75 { OPT_EVENT_NAME, 'E', "event-name", true },
76
77 { OPT_TYPE, 't', "type", true },
78 { OPT_LOCATION, 'L', "location", true },
79
80 /* Capture descriptor */
81 { OPT_CAPTURE, '\0', "capture", true },
82
83 ARGPAR_OPT_DESCR_SENTINEL
84 };
85
86 static bool has_syscall_prefix(const char *arg)
87 {
88 bool matches = false;
89 const char kernel_syscall_type_opt_prefix[] = "kernel:syscall";
90 const size_t kernel_syscall_type_opt_prefix_len =
91 sizeof(kernel_syscall_type_opt_prefix) - 1;
92 const char syscall_type_opt_prefix[] = "syscall";
93 const size_t syscall_type_opt_prefix_len = sizeof(syscall_type_opt_prefix) - 1;
94
95 if (strncmp(arg, syscall_type_opt_prefix, syscall_type_opt_prefix_len) == 0) {
96 matches = true;
97 } else if (strncmp(arg,
98 kernel_syscall_type_opt_prefix,
99 kernel_syscall_type_opt_prefix_len) == 0) {
100 matches = true;
101 } else {
102 matches = false;
103 }
104
105 return matches;
106 }
107
108 static bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *arg)
109 {
110 bool ret;
111
112 if (*dest != LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
113 ERR("More than one `--type` was specified.");
114 goto error;
115 }
116
117 if (strcmp(arg, "user") == 0 || strcmp(arg, "user:tracepoint") == 0) {
118 *dest = LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT;
119 } else if (strcmp(arg, "kernel") == 0 || strcmp(arg, "kernel:tracepoint") == 0) {
120 *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT;
121 } else if (strcmp(arg, "jul") == 0 || strcmp(arg, "jul:logging") == 0) {
122 *dest = LTTNG_EVENT_RULE_TYPE_JUL_LOGGING;
123 } else if (strcmp(arg, "log4j") == 0 || strcmp(arg, "log4j:logging") == 0) {
124 *dest = LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING;
125 } else if (strcmp(arg, "log4j2") == 0 || strcmp(arg, "log4j2:logging") == 0) {
126 *dest = LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING;
127 } else if (strcmp(arg, "python") == 0 || strcmp(arg, "python:logging") == 0) {
128 *dest = LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING;
129 } else if (strcmp(arg, "kprobe") == 0 || strcmp(arg, "kernel:kprobe") == 0) {
130 *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE;
131 } else if (strcmp(arg, "kernel:uprobe") == 0) {
132 *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE;
133 } else if (has_syscall_prefix(arg)) {
134 /*
135 * Matches the following:
136 * - syscall
137 * - syscall:entry
138 * - syscall:exit
139 * - syscall:entry+exit
140 * - syscall:*
141 * - kernel:syscall
142 * - kernel:syscall:entry
143 * - kernel:syscall:exit
144 * - kernel:syscall:entry+exit
145 * - kernel:syscall:*
146 *
147 * Validation for the right side is left to further usage sites.
148 */
149 *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL;
150 } else {
151 ERR("Invalid `--type` value: %s", arg);
152 goto error;
153 }
154
155 ret = true;
156 goto end;
157
158 error:
159 ret = false;
160
161 end:
162 return ret;
163 }
164
165 static bool assign_string(char **dest, const char *src, const char *opt_name)
166 {
167 bool ret;
168
169 if (*dest) {
170 ERR("Duplicate '%s' given.", opt_name);
171 goto error;
172 }
173
174 *dest = strdup(src);
175 if (!*dest) {
176 PERROR("Failed to allocate string '%s'.", opt_name);
177 goto error;
178 }
179
180 ret = true;
181 goto end;
182
183 error:
184 ret = false;
185
186 end:
187 return ret;
188 }
189
190 static bool
191 parse_syscall_emission_site_from_type(const char *str,
192 enum lttng_event_rule_kernel_syscall_emission_site *type)
193 {
194 bool ret = false;
195 const char kernel_prefix[] = "kernel:";
196 const size_t kernel_prefix_len = sizeof(kernel_prefix) - 1;
197
198 /*
199 * If the passed string is of the form "kernel:syscall*", move the
200 * pointer passed "kernel:".
201 */
202 if (strncmp(str, kernel_prefix, kernel_prefix_len) == 0) {
203 str = &str[kernel_prefix_len];
204 }
205
206 if (strcmp(str, "syscall") == 0 || strcmp(str, "syscall:entry+exit") == 0) {
207 *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT;
208 } else if (strcmp(str, "syscall:entry") == 0) {
209 *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY;
210 } else if (strcmp(str, "syscall:exit") == 0) {
211 *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_EXIT;
212 } else {
213 goto error;
214 }
215
216 ret = true;
217
218 error:
219 return ret;
220 }
221
222 /*
223 * Parse `str` as a log level against the passed event rule type.
224 *
225 * Return the log level in `*log_level`. Return true in `*log_level_only` if
226 * the string specifies exactly this log level, false if it specifies at least
227 * this log level.
228 *
229 * Return true if the string was successfully parsed as a log level string.
230 */
231 static bool parse_log_level_string(const char *str,
232 enum lttng_event_rule_type event_rule_type,
233 int *log_level,
234 bool *log_level_only)
235 {
236 bool ret;
237
238 switch (event_rule_type) {
239 case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
240 {
241 enum lttng_loglevel log_level_least_severe, log_level_most_severe;
242 if (!loglevel_parse_range_string(
243 str, &log_level_least_severe, &log_level_most_severe)) {
244 goto error;
245 }
246
247 /* Only support VAL and VAL.. for now. */
248 if (log_level_least_severe != log_level_most_severe &&
249 log_level_most_severe != LTTNG_LOGLEVEL_EMERG) {
250 goto error;
251 }
252
253 *log_level = (int) log_level_least_severe;
254 *log_level_only = log_level_least_severe == log_level_most_severe;
255 break;
256 }
257 case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
258 {
259 enum lttng_loglevel_log4j log_level_least_severe, log_level_most_severe;
260 if (!loglevel_log4j_parse_range_string(
261 str, &log_level_least_severe, &log_level_most_severe)) {
262 goto error;
263 }
264
265 /* Only support VAL and VAL.. for now. */
266 if (log_level_least_severe != log_level_most_severe &&
267 log_level_most_severe != LTTNG_LOGLEVEL_LOG4J_FATAL) {
268 goto error;
269 }
270
271 *log_level = (int) log_level_least_severe;
272 *log_level_only = log_level_least_severe == log_level_most_severe;
273 break;
274 }
275 case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
276 {
277 enum lttng_loglevel_log4j2 log_level_least_severe, log_level_most_severe;
278 if (!loglevel_log4j2_parse_range_string(
279 str, &log_level_least_severe, &log_level_most_severe)) {
280 goto error;
281 }
282
283 /* Only support VAL and VAL.. for now. */
284 if (log_level_least_severe != log_level_most_severe &&
285 log_level_most_severe != LTTNG_LOGLEVEL_LOG4J2_FATAL) {
286 goto error;
287 }
288
289 *log_level = (int) log_level_least_severe;
290 *log_level_only = log_level_least_severe == log_level_most_severe;
291 break;
292 }
293 case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
294 {
295 enum lttng_loglevel_jul log_level_least_severe, log_level_most_severe;
296 if (!loglevel_jul_parse_range_string(
297 str, &log_level_least_severe, &log_level_most_severe)) {
298 goto error;
299 }
300
301 /* Only support VAL and VAL.. for now. */
302 if (log_level_least_severe != log_level_most_severe &&
303 log_level_most_severe != LTTNG_LOGLEVEL_JUL_SEVERE) {
304 goto error;
305 }
306
307 *log_level = (int) log_level_least_severe;
308 *log_level_only = log_level_least_severe == log_level_most_severe;
309 break;
310 }
311 case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
312 {
313 enum lttng_loglevel_python log_level_least_severe, log_level_most_severe;
314 if (!loglevel_python_parse_range_string(
315 str, &log_level_least_severe, &log_level_most_severe)) {
316 goto error;
317 }
318
319 /* Only support VAL and VAL.. for now. */
320 if (log_level_least_severe != log_level_most_severe &&
321 log_level_most_severe != LTTNG_LOGLEVEL_PYTHON_CRITICAL) {
322 goto error;
323 }
324
325 *log_level = (int) log_level_least_severe;
326 *log_level_only = log_level_least_severe == log_level_most_severe;
327 break;
328 }
329 default:
330 /* Invalid domain type. */
331 abort();
332 }
333
334 ret = true;
335 goto end;
336
337 error:
338 ret = false;
339
340 end:
341 return ret;
342 }
343
344 static int parse_kernel_probe_opts(const char *source,
345 struct lttng_kernel_probe_location **location)
346 {
347 int ret = 0;
348 int match;
349 char s_hex[19];
350 char name[LTTNG_SYMBOL_NAME_LEN];
351 char *symbol_name = nullptr;
352 uint64_t offset;
353
354 /* Check for symbol+offset. */
355 match = sscanf(
356 source, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "[^'+']+%18s", name, s_hex);
357 if (match == 2) {
358 if (*s_hex == '\0') {
359 ERR("Kernel probe symbol offset is missing.");
360 goto error;
361 }
362
363 symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
364 if (!symbol_name) {
365 PERROR("Failed to copy kernel probe location symbol name.");
366 goto error;
367 }
368 offset = strtoull(s_hex, nullptr, 0);
369
370 *location = lttng_kernel_probe_location_symbol_create(symbol_name, offset);
371 if (!*location) {
372 ERR("Failed to create symbol kernel probe location.");
373 goto error;
374 }
375
376 goto end;
377 }
378
379 /* Check for symbol. */
380 if (isalpha(name[0]) || name[0] == '_') {
381 match = sscanf(source, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", name);
382 if (match == 1) {
383 symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
384 if (!symbol_name) {
385 ERR("Failed to copy kernel probe location symbol name.");
386 goto error;
387 }
388
389 *location = lttng_kernel_probe_location_symbol_create(symbol_name, 0);
390 if (!*location) {
391 ERR("Failed to create symbol kernel probe location.");
392 goto error;
393 }
394
395 goto end;
396 }
397 }
398
399 /* Check for address. */
400 match = sscanf(source, "%18s", s_hex);
401 if (match > 0) {
402 uint64_t address;
403
404 if (*s_hex == '\0') {
405 ERR("Invalid kernel probe location address.");
406 goto error;
407 }
408
409 address = strtoull(s_hex, nullptr, 0);
410 *location = lttng_kernel_probe_location_address_create(address);
411 if (!*location) {
412 ERR("Failed to create symbol kernel probe location.");
413 goto error;
414 }
415
416 goto end;
417 }
418
419 error:
420 /* No match */
421 ret = -1;
422 *location = nullptr;
423
424 end:
425 free(symbol_name);
426 return ret;
427 }
428
429 static struct lttng_event_expr *
430 ir_op_load_expr_to_event_expr(const struct ir_load_expression *load_expr, const char *capture_str)
431 {
432 char *provider_name = nullptr;
433 struct lttng_event_expr *event_expr = nullptr;
434 const struct ir_load_expression_op *load_expr_op = load_expr->child;
435 const enum ir_load_expression_type load_expr_child_type = load_expr_op->type;
436
437 switch (load_expr_child_type) {
438 case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
439 case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
440 {
441 const char *field_name;
442
443 load_expr_op = load_expr_op->next;
444 LTTNG_ASSERT(load_expr_op);
445 LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
446 field_name = load_expr_op->u.symbol;
447 LTTNG_ASSERT(field_name);
448
449 event_expr = load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
450 lttng_event_expr_event_payload_field_create(field_name) :
451 lttng_event_expr_channel_context_field_create(field_name);
452 if (!event_expr) {
453 ERR("Failed to create %s event expression: field name = `%s`.",
454 load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
455 "payload field" :
456 "channel context",
457 field_name);
458 goto error;
459 }
460
461 break;
462 }
463 case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
464 {
465 const char *colon;
466 const char *type_name;
467 const char *field_name;
468
469 load_expr_op = load_expr_op->next;
470 LTTNG_ASSERT(load_expr_op);
471 LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
472 field_name = load_expr_op->u.symbol;
473 LTTNG_ASSERT(field_name);
474
475 /*
476 * The field name needs to be of the form PROVIDER:TYPE. We
477 * split it here.
478 */
479 colon = strchr(field_name, ':');
480 if (!colon) {
481 ERR("Invalid app-specific context field name: missing colon in `%s`.",
482 field_name);
483 goto error;
484 }
485
486 type_name = colon + 1;
487 if (*type_name == '\0') {
488 ERR("Invalid app-specific context field name: missing type name after colon in `%s`.",
489 field_name);
490 goto error;
491 }
492
493 provider_name = strndup(field_name, colon - field_name);
494 if (!provider_name) {
495 PERROR("Failed to allocate field name string");
496 goto error;
497 }
498
499 event_expr = lttng_event_expr_app_specific_context_field_create(provider_name,
500 type_name);
501 if (!event_expr) {
502 ERR("Failed to create app-specific context field event expression: provider name = `%s`, type name = `%s`",
503 provider_name,
504 type_name);
505 goto error;
506 }
507
508 break;
509 }
510 default:
511 ERR("%s: unexpected load expr type %d.", __func__, load_expr_op->type);
512 abort();
513 }
514
515 load_expr_op = load_expr_op->next;
516
517 /* There may be a single array index after that. */
518 if (load_expr_op->type == IR_LOAD_EXPRESSION_GET_INDEX) {
519 struct lttng_event_expr *index_event_expr;
520 const uint64_t index = load_expr_op->u.index;
521
522 index_event_expr = lttng_event_expr_array_field_element_create(event_expr, index);
523 if (!index_event_expr) {
524 ERR("Failed to create array field element event expression.");
525 goto error;
526 }
527
528 event_expr = index_event_expr;
529 load_expr_op = load_expr_op->next;
530 }
531
532 switch (load_expr_op->type) {
533 case IR_LOAD_EXPRESSION_LOAD_FIELD:
534 /*
535 * This is what we expect, IR_LOAD_EXPRESSION_LOAD_FIELD is
536 * always found at the end of the chain.
537 */
538 break;
539 case IR_LOAD_EXPRESSION_GET_SYMBOL:
540 ERR("While parsing expression `%s`: Capturing subfields is not supported.",
541 capture_str);
542 goto error;
543
544 default:
545 ERR("%s: unexpected load expression operator %s.",
546 __func__,
547 ir_load_expression_type_str(load_expr_op->type));
548 abort();
549 }
550
551 goto end;
552
553 error:
554 lttng_event_expr_destroy(event_expr);
555 event_expr = nullptr;
556
557 end:
558 free(provider_name);
559
560 return event_expr;
561 }
562
563 static struct lttng_event_expr *ir_op_load_to_event_expr(const struct ir_op *ir,
564 const char *capture_str)
565 {
566 struct lttng_event_expr *event_expr = nullptr;
567
568 LTTNG_ASSERT(ir->op == IR_OP_LOAD);
569
570 switch (ir->data_type) {
571 case IR_DATA_EXPRESSION:
572 {
573 const struct ir_load_expression *ir_load_expr = ir->u.load.u.expression;
574
575 event_expr = ir_op_load_expr_to_event_expr(ir_load_expr, capture_str);
576 break;
577 }
578 default:
579 ERR("%s: unexpected data type: %s.", __func__, ir_data_type_str(ir->data_type));
580 abort();
581 }
582
583 return event_expr;
584 }
585
586 static const char *ir_operator_type_human_str(enum ir_op_type op)
587 {
588 const char *name;
589
590 switch (op) {
591 case IR_OP_BINARY:
592 name = "Binary";
593 break;
594 case IR_OP_UNARY:
595 name = "Unary";
596 break;
597 case IR_OP_LOGICAL:
598 name = "Logical";
599 break;
600 default:
601 abort();
602 }
603
604 return name;
605 }
606
607 static struct lttng_event_expr *ir_op_root_to_event_expr(const struct ir_op *ir,
608 const char *capture_str)
609 {
610 struct lttng_event_expr *event_expr = nullptr;
611
612 LTTNG_ASSERT(ir->op == IR_OP_ROOT);
613 ir = ir->u.root.child;
614
615 switch (ir->op) {
616 case IR_OP_LOAD:
617 event_expr = ir_op_load_to_event_expr(ir, capture_str);
618 break;
619 case IR_OP_BINARY:
620 case IR_OP_UNARY:
621 case IR_OP_LOGICAL:
622 ERR("While parsing expression `%s`: %s operators are not allowed in capture expressions.",
623 capture_str,
624 ir_operator_type_human_str(ir->op));
625 break;
626 default:
627 ERR("%s: unexpected IR op type: %s.", __func__, ir_op_type_str(ir->op));
628 abort();
629 }
630
631 return event_expr;
632 }
633
634 static void destroy_event_expr(void *ptr)
635 {
636 lttng_event_expr_destroy((lttng_event_expr *) ptr);
637 }
638
639 namespace {
640 struct parse_event_rule_res {
641 /* Owned by this. */
642 struct lttng_event_rule *er;
643
644 /* Array of `struct lttng_event_expr *` */
645 struct lttng_dynamic_pointer_array capture_descriptors;
646 };
647 } /* namespace */
648
649 static struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv, int argc_offset)
650 {
651 enum lttng_event_rule_type event_rule_type = LTTNG_EVENT_RULE_TYPE_UNKNOWN;
652 struct argpar_iter *argpar_iter = nullptr;
653 const struct argpar_item *argpar_item = nullptr;
654 int consumed_args = -1;
655 struct lttng_kernel_probe_location *kernel_probe_location = nullptr;
656 struct lttng_userspace_probe_location *userspace_probe_location = nullptr;
657 struct parse_event_rule_res res = {};
658 struct lttng_event_expr *event_expr = nullptr;
659 struct filter_parser_ctx *parser_ctx = nullptr;
660 struct lttng_log_level_rule *log_level_rule = nullptr;
661
662 /* Event rule type option */
663 char *event_rule_type_str = nullptr;
664
665 /* Tracepoint and syscall options. */
666 char *name = nullptr;
667 /* Array of strings. */
668 struct lttng_dynamic_pointer_array exclude_names;
669
670 /* For userspace / kernel probe and function. */
671 char *location = nullptr;
672 char *event_name = nullptr;
673
674 /* Filter. */
675 char *filter = nullptr;
676
677 /* Log level. */
678 char *log_level_str = nullptr;
679
680 lttng_dynamic_pointer_array_init(&res.capture_descriptors, destroy_event_expr);
681
682 lttng_dynamic_pointer_array_init(&exclude_names, free);
683
684 argpar_iter = argpar_iter_create(*argc, *argv, event_rule_opt_descrs);
685 if (!argpar_iter) {
686 ERR("Failed to allocate an argpar iter.");
687 goto error;
688 }
689
690 while (true) {
691 enum parse_next_item_status status;
692
693 status = parse_next_item(
694 argpar_iter, &argpar_item, argc_offset, *argv, false, nullptr, nullptr);
695 if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
696 status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
697 goto error;
698 } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
699 break;
700 }
701
702 LTTNG_ASSERT(status == PARSE_NEXT_ITEM_STATUS_OK);
703
704 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
705 const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item);
706 const char *arg = argpar_item_opt_arg(argpar_item);
707
708 switch (descr->id) {
709 case OPT_TYPE:
710 if (!assign_event_rule_type(&event_rule_type, arg)) {
711 goto error;
712 }
713
714 /* Save the string for later use. */
715 if (!assign_string(&event_rule_type_str, arg, "--type/-t")) {
716 goto error;
717 }
718
719 break;
720 case OPT_LOCATION:
721 if (!assign_string(&location, arg, "--location/-L")) {
722 goto error;
723 }
724
725 break;
726 case OPT_EVENT_NAME:
727 if (!assign_string(&event_name, arg, "--event-name/-E")) {
728 goto error;
729 }
730
731 break;
732 case OPT_FILTER:
733 if (!assign_string(&filter, arg, "--filter/-f")) {
734 goto error;
735 }
736
737 break;
738 case OPT_NAME:
739 if (!assign_string(&name, arg, "--name/-n")) {
740 goto error;
741 }
742
743 break;
744 case OPT_EXCLUDE_NAME:
745 {
746 int ret;
747
748 ret = lttng_dynamic_pointer_array_add_pointer(&exclude_names,
749 strdup(arg));
750 if (ret != 0) {
751 ERR("Failed to add pointer to dynamic pointer array.");
752 goto error;
753 }
754
755 break;
756 }
757 case OPT_LOG_LEVEL:
758 if (!assign_string(&log_level_str, arg, "--log-level/-l")) {
759 goto error;
760 }
761
762 break;
763 case OPT_CAPTURE:
764 {
765 int ret;
766
767 ret = filter_parser_ctx_create_from_filter_expression(arg,
768 &parser_ctx);
769 if (ret) {
770 ERR("Failed to parse capture expression `%s`.", arg);
771 goto error;
772 }
773
774 event_expr = ir_op_root_to_event_expr(parser_ctx->ir_root, arg);
775 filter_parser_ctx_free(parser_ctx);
776 parser_ctx = nullptr;
777 if (!event_expr) {
778 /*
779 * ir_op_root_to_event_expr has printed
780 * an error message.
781 */
782 goto error;
783 }
784
785 ret = lttng_dynamic_pointer_array_add_pointer(
786 &res.capture_descriptors, event_expr);
787 if (ret) {
788 goto error;
789 }
790
791 /*
792 * The ownership of event expression was
793 * transferred to the dynamic array.
794 */
795 event_expr = nullptr;
796
797 break;
798 }
799 default:
800 abort();
801 }
802 } else {
803 const char *arg = argpar_item_non_opt_arg(argpar_item);
804
805 /* Don't accept non-option arguments. */
806 ERR("Unexpected argument '%s'", arg);
807 goto error;
808 }
809 }
810
811 if (event_rule_type == LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
812 ERR("Event rule requires a --type.");
813 goto error;
814 }
815
816 /*
817 * Option --name is applicable to event rules of type kernel, user, jul,
818 * log4j, log4j2, python and syscall. If --name is omitted, it is
819 * implicitly "*".
820 */
821 switch (event_rule_type) {
822 case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
823 case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
824 case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
825 case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
826 case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
827 case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
828 case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
829 if (!name) {
830 name = strdup("*");
831 }
832 break;
833
834 default:
835 if (name) {
836 ERR("Can't use --name with %s event rules.",
837 lttng_event_rule_type_str(event_rule_type));
838 goto error;
839 }
840
841 if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
842 ERR("Can't use --exclude-name/-x with %s event rules.",
843 lttng_event_rule_type_str(event_rule_type));
844 goto error;
845 }
846 }
847
848 /*
849 * Option --location is only applicable to (and mandatory for) event
850 * rules of type {k,u}probe and function.
851 *
852 * Option --event-name is only applicable to event rules of type probe.
853 * If omitted, it defaults to the location.
854 */
855 switch (event_rule_type) {
856 case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
857 case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
858 if (!location) {
859 ERR("Event rule of type %s requires a --location.",
860 lttng_event_rule_type_str(event_rule_type));
861 goto error;
862 }
863
864 if (!event_name) {
865 event_name = strdup(location);
866 }
867
868 break;
869
870 default:
871 if (location) {
872 ERR("Can't use --location with %s event rules.",
873 lttng_event_rule_type_str(event_rule_type));
874 goto error;
875 }
876
877 if (event_name) {
878 ERR("Can't use --event-name with %s event rules.",
879 lttng_event_rule_type_str(event_rule_type));
880 goto error;
881 }
882 }
883
884 /*
885 * Update *argc and *argv so our caller can keep parsing what follows.
886 */
887 consumed_args = argpar_iter_ingested_orig_args(argpar_iter);
888 LTTNG_ASSERT(consumed_args >= 0);
889 *argc -= consumed_args;
890 *argv += consumed_args;
891
892 /*
893 * Adding a filter to a probe, function or userspace-probe would be
894 * denied by the kernel tracer as it's not supported at the moment. We
895 * do an early check here to warn the user.
896 */
897 if (filter) {
898 switch (event_rule_type) {
899 case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
900 case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
901 case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
902 case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
903 case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
904 case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
905 case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
906 break;
907 default:
908 ERR("Filter expressions are not supported for %s event rules.",
909 lttng_event_rule_type_str(event_rule_type));
910 goto error;
911 }
912 }
913
914 /*
915 * If --exclude-name/-x was passed, split it into an exclusion list.
916 * Exclusions are only supported by
917 * LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT for now.
918 */
919 if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
920 if (event_rule_type != LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT) {
921 ERR("Event name exclusions are not yet implemented for %s event rules.",
922 lttng_event_rule_type_str(event_rule_type));
923 goto error;
924 }
925
926 if (validate_exclusion_list(name, &exclude_names) != 0) {
927 /*
928 * Assume validate_exclusion_list already prints an
929 * error message.
930 */
931 goto error;
932 }
933 }
934
935 if (log_level_str) {
936 switch (event_rule_type) {
937 case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
938 case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
939 case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
940 case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
941 case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
942 {
943 int log_level;
944 bool log_level_only;
945
946 if (strcmp(log_level_str, "..") == 0) {
947 /*
948 * ".." is the same as passing no log level
949 * option and correspond to the "ANY" case.
950 */
951 break;
952 }
953
954 if (!parse_log_level_string(
955 log_level_str, event_rule_type, &log_level, &log_level_only)) {
956 ERR("Failed to parse log level string `%s`.", log_level_str);
957 goto error;
958 }
959
960 if (log_level_only) {
961 log_level_rule = lttng_log_level_rule_exactly_create(log_level);
962 } else {
963 log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(
964 log_level);
965 }
966
967 if (log_level_rule == nullptr) {
968 ERR("Failed to create log level rule object.");
969 goto error;
970 }
971 break;
972 }
973 default:
974 ERR("Log levels are not supported for %s event rules.",
975 lttng_event_rule_type_str(event_rule_type));
976 goto error;
977 }
978 }
979
980 /* Finally, create the event rule object. */
981 switch (event_rule_type) {
982 case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
983 {
984 enum lttng_event_rule_status event_rule_status;
985
986 res.er = lttng_event_rule_user_tracepoint_create();
987 if (!res.er) {
988 ERR("Failed to create user_tracepoint event rule.");
989 goto error;
990 }
991
992 /* Set pattern. */
993 event_rule_status = lttng_event_rule_user_tracepoint_set_name_pattern(res.er, name);
994 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
995 ERR("Failed to set user_tracepoint event rule's pattern to '%s'.", name);
996 goto error;
997 }
998
999 /* Set filter. */
1000 if (filter) {
1001 event_rule_status =
1002 lttng_event_rule_user_tracepoint_set_filter(res.er, filter);
1003 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1004 ERR("Failed to set user_tracepoint event rule's filter to '%s'.",
1005 filter);
1006 goto error;
1007 }
1008 }
1009
1010 /* Set exclusion list. */
1011 if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
1012 int n;
1013 const int count = lttng_dynamic_pointer_array_get_count(&exclude_names);
1014
1015 for (n = 0; n < count; n++) {
1016 const char *exclude_name =
1017 (const char *) lttng_dynamic_pointer_array_get_pointer(
1018 &exclude_names, n);
1019
1020 event_rule_status =
1021 lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
1022 res.er, exclude_name);
1023 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1024 ERR("Failed to set user_tracepoint exclusion list element '%s'",
1025 exclude_name);
1026 goto error;
1027 }
1028 }
1029 }
1030
1031 if (log_level_rule) {
1032 event_rule_status = lttng_event_rule_user_tracepoint_set_log_level_rule(
1033 res.er, log_level_rule);
1034
1035 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1036 ERR("Failed to set log level on event fule.");
1037 goto error;
1038 }
1039 }
1040
1041 break;
1042 }
1043 case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
1044 {
1045 enum lttng_event_rule_status event_rule_status;
1046
1047 res.er = lttng_event_rule_kernel_tracepoint_create();
1048 if (!res.er) {
1049 ERR("Failed to create kernel_tracepoint event rule.");
1050 goto error;
1051 }
1052
1053 /* Set pattern. */
1054 event_rule_status =
1055 lttng_event_rule_kernel_tracepoint_set_name_pattern(res.er, name);
1056 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1057 ERR("Failed to set kernel_tracepoint event rule's pattern to '%s'.", name);
1058 goto error;
1059 }
1060
1061 /* Set filter. */
1062 if (filter) {
1063 event_rule_status =
1064 lttng_event_rule_kernel_tracepoint_set_filter(res.er, filter);
1065 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1066 ERR("Failed to set kernel_tracepoint event rule's filter to '%s'.",
1067 filter);
1068 goto error;
1069 }
1070 }
1071 break;
1072 }
1073 case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
1074 {
1075 enum lttng_event_rule_status event_rule_status;
1076
1077 res.er = lttng_event_rule_jul_logging_create();
1078 if (!res.er) {
1079 ERR("Failed to create jul_logging event rule.");
1080 goto error;
1081 }
1082
1083 /* Set pattern. */
1084 event_rule_status = lttng_event_rule_jul_logging_set_name_pattern(res.er, name);
1085 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1086 ERR("Failed to set jul_logging event rule's pattern to '%s'.", name);
1087 goto error;
1088 }
1089
1090 /* Set filter. */
1091 if (filter) {
1092 event_rule_status = lttng_event_rule_jul_logging_set_filter(res.er, filter);
1093 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1094 ERR("Failed to set jul_logging event rule's filter to '%s'.",
1095 filter);
1096 goto error;
1097 }
1098 }
1099
1100 if (log_level_rule) {
1101 event_rule_status = lttng_event_rule_jul_logging_set_log_level_rule(
1102 res.er, log_level_rule);
1103
1104 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1105 ERR("Failed to set log level on event fule.");
1106 goto error;
1107 }
1108 }
1109 break;
1110 }
1111 case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
1112 {
1113 enum lttng_event_rule_status event_rule_status;
1114
1115 res.er = lttng_event_rule_log4j_logging_create();
1116 if (!res.er) {
1117 ERR("Failed to create jul_logging event rule.");
1118 goto error;
1119 }
1120
1121 /* Set pattern. */
1122 event_rule_status = lttng_event_rule_log4j_logging_set_name_pattern(res.er, name);
1123 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1124 ERR("Failed to set jul_logging event rule's pattern to '%s'.", name);
1125 goto error;
1126 }
1127
1128 /* Set filter. */
1129 if (filter) {
1130 event_rule_status =
1131 lttng_event_rule_log4j_logging_set_filter(res.er, filter);
1132 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1133 ERR("Failed to set jul_logging event rule's filter to '%s'.",
1134 filter);
1135 goto error;
1136 }
1137 }
1138
1139 if (log_level_rule) {
1140 event_rule_status = lttng_event_rule_log4j_logging_set_log_level_rule(
1141 res.er, log_level_rule);
1142
1143 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1144 ERR("Failed to set log level on event fule.");
1145 goto error;
1146 }
1147 }
1148 break;
1149 }
1150 case LTTNG_EVENT_RULE_TYPE_LOG4J2_LOGGING:
1151 {
1152 enum lttng_event_rule_status event_rule_status;
1153
1154 res.er = lttng_event_rule_log4j2_logging_create();
1155 if (!res.er) {
1156 ERR("Failed to create log4j2_logging event rule.");
1157 goto error;
1158 }
1159
1160 /* Set pattern. */
1161 event_rule_status = lttng_event_rule_log4j2_logging_set_name_pattern(res.er, name);
1162 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1163 ERR("Failed to set log4j2_logging event rule's pattern to '%s'.", name);
1164 goto error;
1165 }
1166
1167 /* Set filter. */
1168 if (filter) {
1169 event_rule_status =
1170 lttng_event_rule_log4j2_logging_set_filter(res.er, filter);
1171 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1172 ERR("Failed to set log4j2_logging event rule's filter to '%s'.",
1173 filter);
1174 goto error;
1175 }
1176 }
1177
1178 if (log_level_rule) {
1179 event_rule_status = lttng_event_rule_log4j2_logging_set_log_level_rule(
1180 res.er, log_level_rule);
1181
1182 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1183 ERR("Failed to set log level on event fule.");
1184 goto error;
1185 }
1186 }
1187 break;
1188 }
1189 case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
1190 {
1191 enum lttng_event_rule_status event_rule_status;
1192
1193 res.er = lttng_event_rule_python_logging_create();
1194 if (!res.er) {
1195 ERR("Failed to create jul_logging event rule.");
1196 goto error;
1197 }
1198
1199 /* Set pattern. */
1200 event_rule_status = lttng_event_rule_python_logging_set_name_pattern(res.er, name);
1201 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1202 ERR("Failed to set jul_logging event rule's pattern to '%s'.", name);
1203 goto error;
1204 }
1205
1206 /* Set filter. */
1207 if (filter) {
1208 event_rule_status =
1209 lttng_event_rule_python_logging_set_filter(res.er, filter);
1210 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1211 ERR("Failed to set jul_logging event rule's filter to '%s'.",
1212 filter);
1213 goto error;
1214 }
1215 }
1216
1217 if (log_level_rule) {
1218 event_rule_status = lttng_event_rule_python_logging_set_log_level_rule(
1219 res.er, log_level_rule);
1220
1221 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1222 ERR("Failed to set log level on event fule.");
1223 goto error;
1224 }
1225 }
1226 break;
1227 }
1228 case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
1229 {
1230 int ret;
1231 enum lttng_event_rule_status event_rule_status;
1232
1233 ret = parse_kernel_probe_opts(location, &kernel_probe_location);
1234 if (ret) {
1235 ERR("Failed to parse kernel probe location.");
1236 goto error;
1237 }
1238
1239 LTTNG_ASSERT(kernel_probe_location);
1240 res.er = lttng_event_rule_kernel_kprobe_create(kernel_probe_location);
1241 if (!res.er) {
1242 ERR("Failed to create kprobe event rule.");
1243 goto error;
1244 }
1245
1246 event_rule_status =
1247 lttng_event_rule_kernel_kprobe_set_event_name(res.er, event_name);
1248 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1249 ERR("Failed to set kprobe event rule's name to '%s'.", event_name);
1250 goto error;
1251 }
1252
1253 break;
1254 }
1255 case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
1256 {
1257 int ret;
1258 enum lttng_event_rule_status event_rule_status;
1259
1260 ret = parse_userspace_probe_opts(location, &userspace_probe_location);
1261 if (ret) {
1262 ERR("Failed to parse user space probe location.");
1263 goto error;
1264 }
1265
1266 res.er = lttng_event_rule_kernel_uprobe_create(userspace_probe_location);
1267 if (!res.er) {
1268 ERR("Failed to create userspace probe event rule.");
1269 goto error;
1270 }
1271
1272 event_rule_status =
1273 lttng_event_rule_kernel_uprobe_set_event_name(res.er, event_name);
1274 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1275 ERR("Failed to set user space probe event rule's name to '%s'.",
1276 event_name);
1277 goto error;
1278 }
1279
1280 break;
1281 }
1282 case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
1283 {
1284 enum lttng_event_rule_status event_rule_status;
1285 enum lttng_event_rule_kernel_syscall_emission_site emission_site;
1286
1287 if (!parse_syscall_emission_site_from_type(event_rule_type_str, &emission_site)) {
1288 ERR("Failed to parse syscall type '%s'.", event_rule_type_str);
1289 goto error;
1290 }
1291
1292 res.er = lttng_event_rule_kernel_syscall_create(emission_site);
1293 if (!res.er) {
1294 ERR("Failed to create syscall event rule.");
1295 goto error;
1296 }
1297
1298 event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(res.er, name);
1299 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1300 ERR("Failed to set syscall event rule's pattern to '%s'.", name);
1301 goto error;
1302 }
1303
1304 if (filter) {
1305 event_rule_status =
1306 lttng_event_rule_kernel_syscall_set_filter(res.er, filter);
1307 if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
1308 ERR("Failed to set syscall event rule's filter to '%s'.", filter);
1309 goto error;
1310 }
1311 }
1312
1313 break;
1314 }
1315 default:
1316 abort();
1317 goto error;
1318 }
1319
1320 goto end;
1321
1322 error:
1323 lttng_event_rule_destroy(res.er);
1324 res.er = nullptr;
1325 lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
1326
1327 end:
1328 if (parser_ctx) {
1329 filter_parser_ctx_free(parser_ctx);
1330 }
1331
1332 lttng_event_expr_destroy(event_expr);
1333 argpar_item_destroy(argpar_item);
1334 argpar_iter_destroy(argpar_iter);
1335 free(filter);
1336 free(name);
1337 lttng_dynamic_pointer_array_reset(&exclude_names);
1338 free(log_level_str);
1339 free(location);
1340 free(event_name);
1341 free(event_rule_type_str);
1342
1343 lttng_kernel_probe_location_destroy(kernel_probe_location);
1344 lttng_userspace_probe_location_destroy(userspace_probe_location);
1345 lttng_log_level_rule_destroy(log_level_rule);
1346 return res;
1347 }
1348
1349 static struct lttng_condition *
1350 handle_condition_event(int *argc, const char ***argv, int argc_offset)
1351 {
1352 struct parse_event_rule_res res;
1353 struct lttng_condition *c;
1354 size_t i;
1355
1356 res = parse_event_rule(argc, argv, argc_offset);
1357 if (!res.er) {
1358 c = nullptr;
1359 goto error;
1360 }
1361
1362 c = lttng_condition_event_rule_matches_create(res.er);
1363 lttng_event_rule_destroy(res.er);
1364 res.er = nullptr;
1365 if (!c) {
1366 goto error;
1367 }
1368
1369 for (i = 0; i < lttng_dynamic_pointer_array_get_count(&res.capture_descriptors); i++) {
1370 enum lttng_condition_status status;
1371 struct lttng_event_expr **expr =
1372 (lttng_event_expr **) lttng_dynamic_array_get_element(
1373 &res.capture_descriptors.array, i);
1374
1375 LTTNG_ASSERT(expr);
1376 LTTNG_ASSERT(*expr);
1377 status = lttng_condition_event_rule_matches_append_capture_descriptor(c, *expr);
1378 if (status != LTTNG_CONDITION_STATUS_OK) {
1379 if (status == LTTNG_CONDITION_STATUS_UNSUPPORTED) {
1380 ERR("The capture feature is unsupported by the event-rule condition type");
1381 }
1382
1383 goto error;
1384 }
1385
1386 /* Ownership of event expression moved to `c` */
1387 *expr = nullptr;
1388 }
1389
1390 goto end;
1391
1392 error:
1393 lttng_condition_destroy(c);
1394 c = nullptr;
1395
1396 end:
1397 lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
1398 lttng_event_rule_destroy(res.er);
1399 return c;
1400 }
1401
1402 namespace {
1403 struct condition_descr {
1404 const char *name;
1405 struct lttng_condition *(*handler)(int *argc, const char ***argv, int argc_offset);
1406 };
1407 } /* namespace */
1408
1409 static const struct condition_descr condition_descrs[] = {
1410 { "event-rule-matches", handle_condition_event },
1411 };
1412
1413 static void print_valid_condition_names()
1414 {
1415 unsigned int i;
1416
1417 ERR("Valid condition names are:");
1418
1419 for (i = 0; i < ARRAY_SIZE(condition_descrs); ++i) {
1420 ERR(" %s", condition_descrs[i].name);
1421 }
1422 }
1423
1424 static struct lttng_condition *parse_condition(const char *condition_name,
1425 int *argc,
1426 const char ***argv,
1427 int argc_offset,
1428 int orig_arg_index,
1429 const char *orig_arg)
1430 {
1431 int i;
1432 struct lttng_condition *cond;
1433 const struct condition_descr *descr = nullptr;
1434
1435 for (i = 0; i < ARRAY_SIZE(condition_descrs); i++) {
1436 if (strcmp(condition_name, condition_descrs[i].name) == 0) {
1437 descr = &condition_descrs[i];
1438 break;
1439 }
1440 }
1441
1442 if (!descr) {
1443 ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown condition name '%s'",
1444 orig_arg_index + 1,
1445 orig_arg,
1446 condition_name);
1447 print_valid_condition_names();
1448 goto error;
1449 }
1450
1451 cond = descr->handler(argc, argv, argc_offset);
1452 if (!cond) {
1453 /* The handler has already printed an error message. */
1454 goto error;
1455 }
1456
1457 goto end;
1458 error:
1459 cond = nullptr;
1460 end:
1461 return cond;
1462 }
1463
1464 static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
1465 {
1466 int ret;
1467 size_t num_token = 0;
1468 struct lttng_dynamic_pointer_array tokens;
1469 struct lttng_rate_policy *policy = nullptr;
1470 enum lttng_rate_policy_type policy_type;
1471 unsigned long long value;
1472 char *policy_type_str;
1473 char *policy_value_str;
1474
1475 LTTNG_ASSERT(policy_str);
1476 lttng_dynamic_pointer_array_init(&tokens, nullptr);
1477
1478 /* Rate policy fields are separated by ':'. */
1479 ret = strutils_split(policy_str, ':', true, &tokens);
1480 if (ret == 0) {
1481 num_token = lttng_dynamic_pointer_array_get_count(&tokens);
1482 }
1483
1484 /*
1485 * Early sanity check that the number of parameter is exactly 2.
1486 * i.e : type:value
1487 */
1488 if (num_token != 2) {
1489 ERR("Rate policy format is invalid.");
1490 goto end;
1491 }
1492
1493 policy_type_str = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
1494 policy_value_str = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
1495
1496 /* Parse the type. */
1497 if (strcmp(policy_type_str, "once-after") == 0) {
1498 policy_type = LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N;
1499 } else if (strcmp(policy_type_str, "every") == 0) {
1500 policy_type = LTTNG_RATE_POLICY_TYPE_EVERY_N;
1501 } else {
1502 ERR("Rate policy type `%s` unknown.", policy_type_str);
1503 goto end;
1504 }
1505
1506 /* Parse the value. */
1507 if (utils_parse_unsigned_long_long(policy_value_str, &value) != 0) {
1508 ERR("Failed to parse rate policy value `%s` as an integer.", policy_value_str);
1509 goto end;
1510 }
1511
1512 if (value == 0) {
1513 ERR("Rate policy value `%s` must be > 0.", policy_value_str);
1514 goto end;
1515 }
1516
1517 switch (policy_type) {
1518 case LTTNG_RATE_POLICY_TYPE_EVERY_N:
1519 policy = lttng_rate_policy_every_n_create(value);
1520 break;
1521 case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
1522 policy = lttng_rate_policy_once_after_n_create(value);
1523 break;
1524 default:
1525 abort();
1526 }
1527
1528 if (policy == nullptr) {
1529 ERR("Failed to create rate policy `%s`.", policy_str);
1530 }
1531
1532 end:
1533 lttng_dynamic_pointer_array_reset(&tokens);
1534 return policy;
1535 }
1536
1537 static const struct argpar_opt_descr notify_action_opt_descrs[] = {
1538 { OPT_RATE_POLICY, '\0', "rate-policy", true }, ARGPAR_OPT_DESCR_SENTINEL
1539 };
1540
1541 static struct lttng_action *handle_action_notify(int *argc, const char ***argv, int argc_offset)
1542 {
1543 struct lttng_action *action = nullptr;
1544 struct argpar_iter *argpar_iter = nullptr;
1545 const struct argpar_item *argpar_item = nullptr;
1546 struct lttng_rate_policy *policy = nullptr;
1547
1548 argpar_iter = argpar_iter_create(*argc, *argv, notify_action_opt_descrs);
1549 if (!argpar_iter) {
1550 ERR("Failed to allocate an argpar iter.");
1551 goto error;
1552 }
1553
1554 while (true) {
1555 enum parse_next_item_status status;
1556
1557 status = parse_next_item(argpar_iter,
1558 &argpar_item,
1559 argc_offset,
1560 *argv,
1561 false,
1562 nullptr,
1563 "While parsing `notify` action:");
1564 if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
1565 status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
1566 goto error;
1567 } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
1568 break;
1569 }
1570
1571 LTTNG_ASSERT(status == PARSE_NEXT_ITEM_STATUS_OK);
1572
1573 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1574 const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item);
1575 const char *arg = argpar_item_opt_arg(argpar_item);
1576
1577 switch (descr->id) {
1578 case OPT_RATE_POLICY:
1579 {
1580 policy = parse_rate_policy(arg);
1581 if (!policy) {
1582 goto error;
1583 }
1584 break;
1585 }
1586 default:
1587 abort();
1588 }
1589 } else {
1590 const char *arg = argpar_item_non_opt_arg(argpar_item);
1591
1592 ERR("Unexpected argument `%s`.", arg);
1593 goto error;
1594 }
1595 }
1596
1597 *argc -= argpar_iter_ingested_orig_args(argpar_iter);
1598 *argv += argpar_iter_ingested_orig_args(argpar_iter);
1599
1600 action = lttng_action_notify_create();
1601 if (!action) {
1602 ERR("Failed to create notify action");
1603 goto error;
1604 }
1605
1606 if (policy) {
1607 enum lttng_action_status status;
1608 status = lttng_action_notify_set_rate_policy(action, policy);
1609 if (status != LTTNG_ACTION_STATUS_OK) {
1610 ERR("Failed to set rate policy");
1611 goto error;
1612 }
1613 }
1614
1615 goto end;
1616
1617 error:
1618 lttng_action_destroy(action);
1619 action = nullptr;
1620 end:
1621 lttng_rate_policy_destroy(policy);
1622 argpar_item_destroy(argpar_item);
1623 argpar_iter_destroy(argpar_iter);
1624 return action;
1625 }
1626
1627 /*
1628 * Generic handler for a kind of action that takes a session name and an
1629 * optional rate policy.
1630 */
1631
1632 static struct lttng_action *handle_action_simple_session_with_policy(
1633 int *argc,
1634 const char ***argv,
1635 int argc_offset,
1636 struct lttng_action *(*create_action_cb)(),
1637 enum lttng_action_status (*set_session_name_cb)(struct lttng_action *, const char *),
1638 enum lttng_action_status (*set_rate_policy_cb)(struct lttng_action *,
1639 const struct lttng_rate_policy *),
1640 const char *action_name)
1641 {
1642 struct lttng_action *action = nullptr;
1643 struct argpar_iter *argpar_iter = nullptr;
1644 const struct argpar_item *argpar_item = nullptr;
1645 const char *session_name_arg = nullptr;
1646 enum lttng_action_status action_status;
1647 struct lttng_rate_policy *policy = nullptr;
1648
1649 LTTNG_ASSERT(set_session_name_cb);
1650 LTTNG_ASSERT(set_rate_policy_cb);
1651
1652 const struct argpar_opt_descr rate_policy_opt_descrs[] = {
1653 { OPT_RATE_POLICY, '\0', "rate-policy", true }, ARGPAR_OPT_DESCR_SENTINEL
1654 };
1655
1656 argpar_iter = argpar_iter_create(*argc, *argv, rate_policy_opt_descrs);
1657 if (!argpar_iter) {
1658 ERR("Failed to allocate an argpar iter.");
1659 goto error;
1660 }
1661
1662 while (true) {
1663 enum parse_next_item_status status;
1664
1665 status = parse_next_item(argpar_iter,
1666 &argpar_item,
1667 argc_offset,
1668 *argv,
1669 false,
1670 nullptr,
1671 "While parsing `%s` action:",
1672 action_name);
1673 if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
1674 status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
1675 goto error;
1676 } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
1677 break;
1678 }
1679
1680 LTTNG_ASSERT(status == PARSE_NEXT_ITEM_STATUS_OK);
1681
1682 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1683 const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item);
1684 const char *arg = argpar_item_opt_arg(argpar_item);
1685
1686 switch (descr->id) {
1687 case OPT_RATE_POLICY:
1688 {
1689 policy = parse_rate_policy(arg);
1690 if (!policy) {
1691 goto error;
1692 }
1693 break;
1694 }
1695 default:
1696 abort();
1697 }
1698 } else {
1699 const char *arg = argpar_item_non_opt_arg(argpar_item);
1700 const unsigned int idx = argpar_item_non_opt_non_opt_index(argpar_item);
1701
1702 switch (idx) {
1703 case 0:
1704 session_name_arg = arg;
1705 break;
1706 default:
1707 ERR("Unexpected argument `%s`.", arg);
1708 goto error;
1709 }
1710 }
1711 }
1712
1713 *argc -= argpar_iter_ingested_orig_args(argpar_iter);
1714 *argv += argpar_iter_ingested_orig_args(argpar_iter);
1715
1716 if (!session_name_arg) {
1717 ERR("Missing session name.");
1718 goto error;
1719 }
1720
1721 action = create_action_cb();
1722 if (!action) {
1723 ERR("Failed to allocate %s session action.", action_name);
1724 goto error;
1725 }
1726
1727 action_status = set_session_name_cb(action, session_name_arg);
1728 if (action_status != LTTNG_ACTION_STATUS_OK) {
1729 ERR("Failed to set action %s session's session name to '%s'.",
1730 action_name,
1731 session_name_arg);
1732 goto error;
1733 }
1734
1735 if (policy) {
1736 action_status = set_rate_policy_cb(action, policy);
1737 if (action_status != LTTNG_ACTION_STATUS_OK) {
1738 ERR("Failed to set rate policy");
1739 goto error;
1740 }
1741 }
1742
1743 goto end;
1744
1745 error:
1746 lttng_action_destroy(action);
1747 action = nullptr;
1748
1749 end:
1750 lttng_rate_policy_destroy(policy);
1751 argpar_item_destroy(argpar_item);
1752 argpar_iter_destroy(argpar_iter);
1753 return action;
1754 }
1755
1756 static struct lttng_action *
1757 handle_action_start_session(int *argc, const char ***argv, int argc_offset)
1758 {
1759 return handle_action_simple_session_with_policy(argc,
1760 argv,
1761 argc_offset,
1762 lttng_action_start_session_create,
1763 lttng_action_start_session_set_session_name,
1764 lttng_action_start_session_set_rate_policy,
1765 "start");
1766 }
1767
1768 static struct lttng_action *
1769 handle_action_stop_session(int *argc, const char ***argv, int argc_offset)
1770 {
1771 return handle_action_simple_session_with_policy(argc,
1772 argv,
1773 argc_offset,
1774 lttng_action_stop_session_create,
1775 lttng_action_stop_session_set_session_name,
1776 lttng_action_stop_session_set_rate_policy,
1777 "stop");
1778 }
1779
1780 static struct lttng_action *
1781 handle_action_rotate_session(int *argc, const char ***argv, int argc_offset)
1782 {
1783 return handle_action_simple_session_with_policy(
1784 argc,
1785 argv,
1786 argc_offset,
1787 lttng_action_rotate_session_create,
1788 lttng_action_rotate_session_set_session_name,
1789 lttng_action_rotate_session_set_rate_policy,
1790 "rotate");
1791 }
1792
1793 static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
1794 { OPT_NAME, 'n', "name", true },
1795 { OPT_MAX_SIZE, 'm', "max-size", true },
1796 { OPT_CTRL_URL, '\0', "ctrl-url", true },
1797 { OPT_DATA_URL, '\0', "data-url", true },
1798 { OPT_URL, '\0', "url", true },
1799 { OPT_PATH, '\0', "path", true },
1800 { OPT_RATE_POLICY, '\0', "rate-policy", true },
1801 ARGPAR_OPT_DESCR_SENTINEL
1802 };
1803
1804 static struct lttng_action *
1805 handle_action_snapshot_session(int *argc, const char ***argv, int argc_offset)
1806 {
1807 struct lttng_action *action = nullptr;
1808 struct argpar_iter *argpar_iter = nullptr;
1809 const struct argpar_item *argpar_item = nullptr;
1810 const char *session_name_arg = nullptr;
1811 char *snapshot_name_arg = nullptr;
1812 char *ctrl_url_arg = nullptr;
1813 char *data_url_arg = nullptr;
1814 char *max_size_arg = nullptr;
1815 char *url_arg = nullptr;
1816 char *path_arg = nullptr;
1817 char *error = nullptr;
1818 enum lttng_action_status action_status;
1819 struct lttng_snapshot_output *snapshot_output = nullptr;
1820 struct lttng_rate_policy *policy = nullptr;
1821 int ret;
1822 unsigned int locations_specified = 0;
1823
1824 argpar_iter = argpar_iter_create(*argc, *argv, snapshot_action_opt_descrs);
1825 if (!argpar_iter) {
1826 ERR("Failed to allocate an argpar iter.");
1827 goto error;
1828 }
1829
1830 while (true) {
1831 enum parse_next_item_status status;
1832
1833 status = parse_next_item(argpar_iter,
1834 &argpar_item,
1835 argc_offset,
1836 *argv,
1837 false,
1838 nullptr,
1839 "While parsing `snapshot` action:");
1840 if (status == PARSE_NEXT_ITEM_STATUS_ERROR ||
1841 status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
1842 goto error;
1843 } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
1844 break;
1845 }
1846
1847 LTTNG_ASSERT(status == PARSE_NEXT_ITEM_STATUS_OK);
1848
1849 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_OPT) {
1850 const struct argpar_opt_descr *descr = argpar_item_opt_descr(argpar_item);
1851 const char *arg = argpar_item_opt_arg(argpar_item);
1852
1853 switch (descr->id) {
1854 case OPT_NAME:
1855 if (!assign_string(&snapshot_name_arg, arg, "--name/-n")) {
1856 goto error;
1857 }
1858
1859 break;
1860 case OPT_MAX_SIZE:
1861 if (!assign_string(&max_size_arg, arg, "--max-size/-m")) {
1862 goto error;
1863 }
1864
1865 break;
1866 case OPT_CTRL_URL:
1867 if (!assign_string(&ctrl_url_arg, arg, "--ctrl-url")) {
1868 goto error;
1869 }
1870
1871 break;
1872 case OPT_DATA_URL:
1873 if (!assign_string(&data_url_arg, arg, "--data-url")) {
1874 goto error;
1875 }
1876
1877 break;
1878 case OPT_URL:
1879 if (!assign_string(&url_arg, arg, "--url")) {
1880 goto error;
1881 }
1882
1883 break;
1884 case OPT_PATH:
1885 if (!assign_string(&path_arg, arg, "--path")) {
1886 goto error;
1887 }
1888
1889 break;
1890 case OPT_RATE_POLICY:
1891 {
1892 policy = parse_rate_policy(arg);
1893 if (!policy) {
1894 goto error;
1895 }
1896 break;
1897 }
1898 default:
1899 abort();
1900 }
1901 } else {
1902 const char *arg = argpar_item_non_opt_arg(argpar_item);
1903 const unsigned int idx = argpar_item_non_opt_non_opt_index(argpar_item);
1904
1905 switch (idx) {
1906 case 0:
1907 session_name_arg = arg;
1908 break;
1909 default:
1910 ERR("Unexpected argument `%s`.", arg);
1911 goto error;
1912 }
1913 }
1914 }
1915
1916 *argc -= argpar_iter_ingested_orig_args(argpar_iter);
1917 *argv += argpar_iter_ingested_orig_args(argpar_iter);
1918
1919 if (!session_name_arg) {
1920 ERR("Missing session name.");
1921 goto error;
1922 }
1923
1924 /* --ctrl-url and --data-url must come in pair. */
1925 if (ctrl_url_arg && !data_url_arg) {
1926 ERR("--ctrl-url is specified, but --data-url is missing.");
1927 goto error;
1928 }
1929
1930 if (!ctrl_url_arg && data_url_arg) {
1931 ERR("--data-url is specified, but --ctrl-url is missing.");
1932 goto error;
1933 }
1934
1935 locations_specified += !!(ctrl_url_arg || data_url_arg);
1936 locations_specified += !!url_arg;
1937 locations_specified += !!path_arg;
1938
1939 /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
1940 if (locations_specified > 1) {
1941 ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
1942 goto error;
1943 }
1944
1945 /*
1946 * Did the user specify an option that implies using a
1947 * custom/unregistered output?
1948 */
1949 if (url_arg || ctrl_url_arg || path_arg) {
1950 snapshot_output = lttng_snapshot_output_create();
1951 if (!snapshot_output) {
1952 ERR("Failed to allocate a snapshot output.");
1953 goto error;
1954 }
1955 }
1956
1957 action = lttng_action_snapshot_session_create();
1958 if (!action) {
1959 ERR("Failed to allocate snapshot session action.");
1960 goto error;
1961 }
1962
1963 action_status = lttng_action_snapshot_session_set_session_name(action, session_name_arg);
1964 if (action_status != LTTNG_ACTION_STATUS_OK) {
1965 ERR("Failed to set action snapshot session's session name to '%s'.",
1966 session_name_arg);
1967 goto error;
1968 }
1969
1970 if (snapshot_name_arg) {
1971 if (!snapshot_output) {
1972 ERR("Can't provide a snapshot output name without a snapshot output destination.");
1973 goto error;
1974 }
1975
1976 ret = lttng_snapshot_output_set_name(snapshot_name_arg, snapshot_output);
1977 if (ret != 0) {
1978 ERR("Failed to set name of snapshot output.");
1979 goto error;
1980 }
1981 }
1982
1983 if (max_size_arg) {
1984 uint64_t max_size;
1985
1986 if (!snapshot_output) {
1987 ERR("Can't provide a snapshot output max size without a snapshot output destination.");
1988 goto error;
1989 }
1990
1991 ret = utils_parse_size_suffix(max_size_arg, &max_size);
1992 if (ret != 0) {
1993 ERR("Failed to parse `%s` as a size.", max_size_arg);
1994 goto error;
1995 }
1996
1997 ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
1998 if (ret != 0) {
1999 ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
2000 max_size);
2001 goto error;
2002 }
2003 }
2004
2005 if (url_arg) {
2006 int num_uris;
2007 struct lttng_uri *uris;
2008
2009 if (!strstr(url_arg, "://")) {
2010 ERR("Failed to parse '%s' as an URL.", url_arg);
2011 goto error;
2012 }
2013
2014 num_uris = uri_parse_str_urls(url_arg, nullptr, &uris);
2015 if (num_uris < 1) {
2016 ERR("Failed to parse '%s' as an URL.", url_arg);
2017 goto error;
2018 }
2019
2020 if (uris[0].dtype == LTTNG_DST_PATH) {
2021 ret = lttng_snapshot_output_set_local_path(uris[0].dst.path,
2022 snapshot_output);
2023 free(uris);
2024 if (ret != 0) {
2025 ERR("Failed to assign '%s' as a local destination.", url_arg);
2026 goto error;
2027 }
2028 } else {
2029 ret = lttng_snapshot_output_set_network_url(url_arg, snapshot_output);
2030 free(uris);
2031 if (ret != 0) {
2032 ERR("Failed to assign '%s' as a network URL.", url_arg);
2033 goto error;
2034 }
2035 }
2036 }
2037
2038 if (path_arg) {
2039 ret = lttng_snapshot_output_set_local_path(path_arg, snapshot_output);
2040 if (ret != 0) {
2041 ERR("Failed to parse '%s' as a local path.", path_arg);
2042 goto error;
2043 }
2044 }
2045
2046 if (ctrl_url_arg) {
2047 /*
2048 * Two argument form, network output with separate control and
2049 * data URLs.
2050 */
2051 ret = lttng_snapshot_output_set_network_urls(
2052 ctrl_url_arg, data_url_arg, snapshot_output);
2053 if (ret != 0) {
2054 ERR("Failed to parse `%s` and `%s` as control and data URLs.",
2055 ctrl_url_arg,
2056 data_url_arg);
2057 goto error;
2058 }
2059 }
2060
2061 if (snapshot_output) {
2062 action_status = lttng_action_snapshot_session_set_output(action, snapshot_output);
2063 if (action_status != LTTNG_ACTION_STATUS_OK) {
2064 ERR("Failed to set snapshot session action's output.");
2065 goto error;
2066 }
2067
2068 /* Ownership of `snapshot_output` has been transferred to the action. */
2069 snapshot_output = nullptr;
2070 }
2071
2072 if (policy) {
2073 enum lttng_action_status status;
2074 status = lttng_action_snapshot_session_set_rate_policy(action, policy);
2075 if (status != LTTNG_ACTION_STATUS_OK) {
2076 ERR("Failed to set rate policy");
2077 goto error;
2078 }
2079 }
2080
2081 goto end;
2082
2083 error:
2084 lttng_action_destroy(action);
2085 action = nullptr;
2086 free(error);
2087 end:
2088 free(snapshot_name_arg);
2089 free(path_arg);
2090 free(url_arg);
2091 free(ctrl_url_arg);
2092 free(data_url_arg);
2093 free(snapshot_output);
2094 free(max_size_arg);
2095 lttng_rate_policy_destroy(policy);
2096 argpar_item_destroy(argpar_item);
2097 argpar_iter_destroy(argpar_iter);
2098 return action;
2099 }
2100
2101 namespace {
2102 struct action_descr {
2103 const char *name;
2104 struct lttng_action *(*handler)(int *argc, const char ***argv, int argc_offset);
2105 };
2106 } /* namespace */
2107
2108 static const struct action_descr action_descrs[] = {
2109 { "notify", handle_action_notify },
2110 { "start-session", handle_action_start_session },
2111 { "stop-session", handle_action_stop_session },
2112 { "rotate-session", handle_action_rotate_session },
2113 { "snapshot-session", handle_action_snapshot_session },
2114 };
2115
2116 static void print_valid_action_names()
2117 {
2118 unsigned int i;
2119
2120 ERR("Valid action names are:");
2121
2122 for (i = 0; i < ARRAY_SIZE(condition_descrs); ++i) {
2123 ERR(" %s", action_descrs[i].name);
2124 }
2125 }
2126
2127 static struct lttng_action *parse_action(const char *action_name,
2128 int *argc,
2129 const char ***argv,
2130 int argc_offset,
2131 int orig_arg_index,
2132 const char *orig_arg)
2133 {
2134 int i;
2135 struct lttng_action *action;
2136 const struct action_descr *descr = nullptr;
2137
2138 for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
2139 if (strcmp(action_name, action_descrs[i].name) == 0) {
2140 descr = &action_descrs[i];
2141 break;
2142 }
2143 }
2144
2145 if (!descr) {
2146 ERR(WHILE_PARSING_ARG_N_ARG_FMT "Unknown action name '%s'",
2147 orig_arg_index + 1,
2148 orig_arg,
2149 action_name);
2150 print_valid_action_names();
2151 goto error;
2152 }
2153
2154 action = descr->handler(argc, argv, argc_offset);
2155 if (!action) {
2156 /* The handler has already printed an error message. */
2157 goto error;
2158 }
2159
2160 goto end;
2161 error:
2162 action = nullptr;
2163 end:
2164 return action;
2165 }
2166
2167 static const struct argpar_opt_descr add_trigger_options[] = {
2168 { OPT_HELP, 'h', "help", false },
2169 { OPT_LIST_OPTIONS, '\0', "list-options", false },
2170 { OPT_CONDITION, '\0', "condition", true },
2171 { OPT_ACTION, '\0', "action", true },
2172 { OPT_NAME, '\0', "name", true },
2173 { OPT_OWNER_UID, '\0', "owner-uid", true },
2174 ARGPAR_OPT_DESCR_SENTINEL,
2175 };
2176
2177 static void lttng_actions_destructor(void *p)
2178 {
2179 struct lttng_action *action = (lttng_action *) p;
2180
2181 lttng_action_destroy(action);
2182 }
2183
2184 int cmd_add_trigger(int argc, const char **argv)
2185 {
2186 int ret;
2187 int my_argc = argc - 1;
2188 const char **my_argv = argv + 1;
2189 struct lttng_condition *condition = nullptr;
2190 struct lttng_dynamic_pointer_array actions;
2191 struct argpar_iter *argpar_iter = nullptr;
2192 const struct argpar_item *argpar_item = nullptr;
2193 const struct argpar_error *argpar_error = nullptr;
2194 struct lttng_action *action_list = nullptr;
2195 struct lttng_action *action = nullptr;
2196 struct lttng_trigger *trigger = nullptr;
2197 char *name = nullptr;
2198 int i;
2199 char *owner_uid = nullptr;
2200 enum lttng_error_code ret_code;
2201 struct mi_writer *mi_writer = nullptr;
2202
2203 lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
2204
2205 if (lttng_opt_mi) {
2206 mi_writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
2207 if (!mi_writer) {
2208 ret = CMD_ERROR;
2209 goto error;
2210 }
2211
2212 /* Open command element. */
2213 ret = mi_lttng_writer_command_open(mi_writer, mi_lttng_element_command_add_trigger);
2214 if (ret) {
2215 ret = CMD_ERROR;
2216 goto error;
2217 }
2218
2219 /* Open output element. */
2220 ret = mi_lttng_writer_open_element(mi_writer, mi_lttng_element_command_output);
2221 if (ret) {
2222 ret = CMD_ERROR;
2223 goto error;
2224 }
2225 }
2226
2227 while (true) {
2228 enum parse_next_item_status status;
2229 int ingested_args;
2230 const struct argpar_opt_descr *descr;
2231 const char *arg;
2232
2233 argpar_iter_destroy(argpar_iter);
2234 argpar_iter = argpar_iter_create(my_argc, my_argv, add_trigger_options);
2235 if (!argpar_iter) {
2236 ERR("Failed to create argpar iter.");
2237 goto error;
2238 }
2239
2240 status = parse_next_item(argpar_iter,
2241 &argpar_item,
2242 argc - my_argc,
2243 my_argv,
2244 true,
2245 &argpar_error,
2246 nullptr);
2247 if (status == PARSE_NEXT_ITEM_STATUS_ERROR) {
2248 if (argpar_error_type(argpar_error) == ARGPAR_ERROR_TYPE_MISSING_OPT_ARG) {
2249 const int opt_id =
2250 argpar_error_opt_descr(argpar_error, nullptr)->id;
2251
2252 if (opt_id == OPT_CONDITION) {
2253 print_valid_condition_names();
2254 } else if (opt_id == OPT_ACTION) {
2255 print_valid_action_names();
2256 }
2257 }
2258
2259 goto error;
2260 } else if (status == PARSE_NEXT_ITEM_STATUS_ERROR_MEMORY) {
2261 goto error;
2262 } else if (status == PARSE_NEXT_ITEM_STATUS_END) {
2263 break;
2264 }
2265
2266 LTTNG_ASSERT(status == PARSE_NEXT_ITEM_STATUS_OK);
2267
2268 if (argpar_item_type(argpar_item) == ARGPAR_ITEM_TYPE_NON_OPT) {
2269 ERR("Unexpected argument `%s`.", argpar_item_non_opt_arg(argpar_item));
2270 goto error;
2271 }
2272
2273 ingested_args = argpar_iter_ingested_orig_args(argpar_iter);
2274
2275 my_argc -= ingested_args;
2276 my_argv += ingested_args;
2277
2278 descr = argpar_item_opt_descr(argpar_item);
2279 arg = argpar_item_opt_arg(argpar_item);
2280
2281 switch (descr->id) {
2282 case OPT_HELP:
2283 SHOW_HELP();
2284 ret = 0;
2285 goto end;
2286 case OPT_LIST_OPTIONS:
2287 list_cmd_options_argpar(stdout, add_trigger_options);
2288 ret = 0;
2289 goto end;
2290 case OPT_CONDITION:
2291 {
2292 if (condition) {
2293 ERR("A --condition was already given.");
2294 goto error;
2295 }
2296
2297 condition = parse_condition(arg,
2298 &my_argc,
2299 &my_argv,
2300 argc - my_argc,
2301 argc - my_argc - ingested_args,
2302 my_argv[-ingested_args]);
2303 if (!condition) {
2304 /*
2305 * An error message was already printed by
2306 * parse_condition.
2307 */
2308 goto error;
2309 }
2310
2311 break;
2312 }
2313 case OPT_ACTION:
2314 {
2315 action = parse_action(arg,
2316 &my_argc,
2317 &my_argv,
2318 argc - my_argc,
2319 argc - my_argc - ingested_args,
2320 my_argv[-ingested_args]);
2321 if (!action) {
2322 /*
2323 * An error message was already printed by
2324 * parse_condition.
2325 */
2326 goto error;
2327 }
2328
2329 ret = lttng_dynamic_pointer_array_add_pointer(&actions, action);
2330 if (ret) {
2331 ERR("Failed to add pointer to pointer array.");
2332 goto error;
2333 }
2334
2335 /* Ownership of the action was transferred to the list. */
2336 action = nullptr;
2337
2338 break;
2339 }
2340 case OPT_NAME:
2341 {
2342 if (!assign_string(&name, arg, "--name")) {
2343 goto error;
2344 }
2345
2346 break;
2347 }
2348 case OPT_OWNER_UID:
2349 {
2350 if (!assign_string(&owner_uid, arg, "--owner-uid")) {
2351 goto error;
2352 }
2353
2354 break;
2355 }
2356 default:
2357 abort();
2358 }
2359 }
2360
2361 if (!condition) {
2362 ERR("Missing --condition.");
2363 goto error;
2364 }
2365
2366 if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
2367 ERR("Need at least one --action.");
2368 goto error;
2369 }
2370
2371 action_list = lttng_action_list_create();
2372 if (!action_list) {
2373 goto error;
2374 }
2375
2376 for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
2377 enum lttng_action_status status;
2378
2379 action = (lttng_action *) lttng_dynamic_pointer_array_steal_pointer(&actions, i);
2380
2381 status = lttng_action_list_add_action(action_list, action);
2382 if (status != LTTNG_ACTION_STATUS_OK) {
2383 goto error;
2384 }
2385
2386 /*
2387 * The `lttng_action_list_add_action()` takes a reference to
2388 * the action. We can destroy ours.
2389 */
2390 lttng_action_destroy(action);
2391 action = nullptr;
2392 }
2393
2394 trigger = lttng_trigger_create(condition, action_list);
2395 if (!trigger) {
2396 goto error;
2397 }
2398
2399 if (owner_uid) {
2400 enum lttng_trigger_status trigger_status;
2401 char *end;
2402 long long uid;
2403
2404 errno = 0;
2405 uid = strtol(owner_uid, &end, 10);
2406 if (end == owner_uid || *end != '\0' || errno != 0) {
2407 ERR("Failed to parse `%s` as a user id.", owner_uid);
2408 goto error;
2409 }
2410
2411 trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
2412 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
2413 ERR("Failed to set trigger's user identity.");
2414 goto error;
2415 }
2416 }
2417
2418 if (name) {
2419 ret_code = lttng_register_trigger_with_name(trigger, name);
2420 } else {
2421 ret_code = lttng_register_trigger_with_automatic_name(trigger);
2422 }
2423
2424 if (ret_code != LTTNG_OK) {
2425 ERR("Failed to register trigger: %s.", lttng_strerror(-ret_code));
2426 goto error;
2427 }
2428
2429 if (lttng_opt_mi) {
2430 ret_code = lttng_trigger_mi_serialize(trigger, mi_writer, nullptr);
2431 if (ret_code != LTTNG_OK) {
2432 goto error;
2433 }
2434 } else {
2435 const char *returned_trigger_name;
2436 const enum lttng_trigger_status trigger_status =
2437 lttng_trigger_get_name(trigger, &returned_trigger_name);
2438
2439 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
2440 WARN("Failed to retrieve the added trigger's name.");
2441 } else {
2442 MSG("Added trigger `%s`.", returned_trigger_name);
2443 }
2444 }
2445
2446 ret = 0;
2447
2448 goto end;
2449
2450 error:
2451 ret = 1;
2452
2453 end:
2454 /* Mi closing. */
2455 if (lttng_opt_mi && mi_writer) {
2456 int mi_ret;
2457
2458 /* Close output element. */
2459 mi_ret = mi_lttng_writer_close_element(mi_writer);
2460 if (mi_ret) {
2461 ret = 1;
2462 goto cleanup;
2463 }
2464
2465 mi_ret = mi_lttng_writer_write_element_bool(
2466 mi_writer, mi_lttng_element_command_success, ret ? 0 : 1);
2467 if (mi_ret) {
2468 ret = 1;
2469 goto cleanup;
2470 }
2471
2472 /* Command element close. */
2473 mi_ret = mi_lttng_writer_command_close(mi_writer);
2474 if (mi_ret) {
2475 ret = 1;
2476 goto cleanup;
2477 }
2478 }
2479
2480 cleanup:
2481 argpar_error_destroy(argpar_error);
2482 argpar_iter_destroy(argpar_iter);
2483 argpar_item_destroy(argpar_item);
2484 lttng_dynamic_pointer_array_reset(&actions);
2485 lttng_condition_destroy(condition);
2486 lttng_action_destroy(action_list);
2487 lttng_action_destroy(action);
2488 lttng_trigger_destroy(trigger);
2489 free(name);
2490 free(owner_uid);
2491 if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
2492 /* Preserve original error code. */
2493 ret = ret ? ret : CMD_ERROR;
2494 }
2495
2496 return ret;
2497 }
This page took 0.080363 seconds and 5 git commands to generate.