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