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