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