notification-thread: drain all tracer notification on removal
[lttng-tools.git] / src / bin / lttng / commands / add_trigger.c
... / ...
CommitLineData
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 free(source);
793 strutils_free_null_terminated_array_of_strings(exclusion_list);
794 lttng_kernel_probe_location_destroy(kernel_probe_location);
795 lttng_userspace_probe_location_destroy(userspace_probe_location);
796 return er;
797}
798
799static
800struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
801{
802 struct lttng_event_rule *er;
803 struct lttng_condition *c;
804
805 er = parse_event_rule(argc, argv);
806 if (!er) {
807 c = NULL;
808 goto end;
809 }
810
811 c = lttng_condition_event_rule_create(er);
812 lttng_event_rule_destroy(er);
813 if (!c) {
814 goto end;
815 }
816
817end:
818 return c;
819}
820
821static
822struct lttng_condition *handle_condition_session_consumed_size(int *argc, const char ***argv)
823{
824 struct lttng_condition *cond = NULL;
825 struct argpar_state *state = NULL;
826 struct argpar_item *item = NULL;
827 const char *threshold_arg = NULL;
828 const char *session_name_arg = NULL;
829 uint64_t threshold;
830 char *error = NULL;
831 enum lttng_condition_status condition_status;
832
833 state = argpar_state_create(*argc, *argv, event_rule_opt_descrs);
834 if (!state) {
835 ERR("Failed to allocate an argpar state.");
836 goto error;
837 }
838
839 while (true) {
840 enum argpar_state_parse_next_status status;
841
842 ARGPAR_ITEM_DESTROY_AND_RESET(item);
843 status = argpar_state_parse_next(state, &item, &error);
844 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
845 ERR("%s", error);
846 goto error;
847 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
848 /* Just stop parsing here. */
849 break;
850 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
851 break;
852 }
853
854 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
855
856 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
857 const struct argpar_item_opt *item_opt =
858 (const struct argpar_item_opt *) item;
859
860 switch (item_opt->descr->id) {
861 default:
862 abort();
863 }
864 } else {
865 const struct argpar_item_non_opt *item_non_opt;
866
867 assert(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
868
869 item_non_opt = (const struct argpar_item_non_opt *) item;
870
871 switch (item_non_opt->non_opt_index) {
872 case 0:
873 session_name_arg = item_non_opt->arg;
874 break;
875 case 1:
876 threshold_arg = item_non_opt->arg;
877 break;
878 default:
879 ERR("Unexpected argument `%s`.",
880 item_non_opt->arg);
881 goto error;
882 }
883 }
884 }
885
886 *argc -= argpar_state_get_ingested_orig_args(state);
887 *argv += argpar_state_get_ingested_orig_args(state);
888
889 if (!session_name_arg) {
890 ERR("Missing session name argument.");
891 goto error;
892 }
893
894 if (!threshold_arg) {
895 ERR("Missing threshold argument.");
896 goto error;
897 }
898
899 if (utils_parse_size_suffix(threshold_arg, &threshold) != 0) {
900 ERR("Failed to parse `%s` as a size.", threshold_arg);
901 goto error;
902 }
903
904 cond = lttng_condition_session_consumed_size_create();
905 if (!cond) {
906 ERR("Failed to allocate a session consumed size condition.");
907 goto error;
908 }
909
910 condition_status = lttng_condition_session_consumed_size_set_session_name(
911 cond, session_name_arg);
912 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
913 ERR("Failed to set session consumed size condition's session name to '%s'.",
914 session_name_arg);
915 goto error;
916 }
917
918 condition_status = lttng_condition_session_consumed_size_set_threshold(
919 cond, threshold);
920 if (condition_status != LTTNG_CONDITION_STATUS_OK) {
921 ERR("Failed to set session consumed size condition threshold.");
922 goto error;
923 }
924
925 goto end;
926
927error:
928 lttng_condition_destroy(cond);
929 cond = NULL;
930
931end:
932 argpar_state_destroy(state);
933 argpar_item_destroy(item);
934 free(error);
935 return cond;
936}
937
938static
939struct lttng_condition *handle_condition_buffer_usage_high(int *argc, const char ***argv)
940{
941 ERR("High buffer usage threshold conditions are unsupported for the moment.");
942 return NULL;
943}
944
945static
946struct lttng_condition *handle_condition_buffer_usage_low(int *argc, const char ***argv)
947{
948 ERR("Low buffer usage threshold conditions are unsupported for the moment.");
949 return NULL;
950}
951
952static
953struct lttng_condition *handle_condition_session_rotation_ongoing(int *argc, const char ***argv)
954{
955 ERR("Session rotation ongoing conditions are unsupported for the moment.");
956 return NULL;
957}
958
959static
960struct lttng_condition *handle_condition_session_rotation_completed(int *argc, const char ***argv)
961{
962 ERR("Session rotation completed conditions are unsupported for the moment.");
963 return NULL;
964}
965
966struct condition_descr {
967 const char *name;
968 struct lttng_condition *(*handler) (int *argc, const char ***argv);
969};
970
971static const
972struct condition_descr condition_descrs[] = {
973 { "on-event", handle_condition_event },
974 { "on-session-consumed-size", handle_condition_session_consumed_size },
975 { "on-buffer-usage-high", handle_condition_buffer_usage_high },
976 { "on-buffer-usage-low", handle_condition_buffer_usage_low },
977 { "on-session-rotation-ongoing", handle_condition_session_rotation_ongoing },
978 { "on-session-rotation-completed", handle_condition_session_rotation_completed },
979};
980
981static
982struct lttng_condition *parse_condition(int *argc, const char ***argv)
983{
984 int i;
985 struct lttng_condition *cond;
986 const char *condition_name;
987 const struct condition_descr *descr = NULL;
988
989 if (*argc == 0) {
990 ERR("Missing condition name.");
991 goto error;
992 }
993
994 condition_name = (*argv)[0];
995
996 (*argc)--;
997 (*argv)++;
998
999 for (i = 0; i < ARRAY_SIZE(condition_descrs); i++) {
1000 if (strcmp(condition_name, condition_descrs[i].name) == 0) {
1001 descr = &condition_descrs[i];
1002 break;
1003 }
1004 }
1005
1006 if (!descr) {
1007 ERR("Unknown condition name '%s'", condition_name);
1008 goto error;
1009 }
1010
1011 cond = descr->handler(argc, argv);
1012 if (!cond) {
1013 /* The handler has already printed an error message. */
1014 goto error;
1015 }
1016
1017 goto end;
1018error:
1019 cond = NULL;
1020end:
1021 return cond;
1022}
1023
1024
1025static
1026struct lttng_action *handle_action_notify(int *argc, const char ***argv)
1027{
1028 return lttng_action_notify_create();
1029}
1030
1031static const struct argpar_opt_descr no_opt_descrs[] = {
1032 ARGPAR_OPT_DESCR_SENTINEL
1033};
1034
1035/*
1036 * Generic handler for a kind of action that takes a session name as its sole
1037 * argument.
1038 */
1039
1040static
1041struct lttng_action *handle_action_simple_session(
1042 int *argc, const char ***argv,
1043 struct lttng_action *(*create_action_cb)(void),
1044 enum lttng_action_status (*set_session_name_cb)(struct lttng_action *, const char *),
1045 const char *action_name)
1046{
1047 struct lttng_action *action = NULL;
1048 struct argpar_state *state = NULL;
1049 struct argpar_item *item = NULL;
1050 const char *session_name_arg = NULL;
1051 char *error = NULL;
1052 enum lttng_action_status action_status;
1053
1054 state = argpar_state_create(*argc, *argv, no_opt_descrs);
1055 if (!state) {
1056 ERR("Failed to allocate an argpar state.");
1057 goto error;
1058 }
1059
1060 while (true) {
1061 enum argpar_state_parse_next_status status;
1062 const struct argpar_item_non_opt *item_non_opt;
1063
1064 ARGPAR_ITEM_DESTROY_AND_RESET(item);
1065 status = argpar_state_parse_next(state, &item, &error);
1066 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
1067 ERR("%s", error);
1068 goto error;
1069 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
1070 /* Just stop parsing here. */
1071 break;
1072 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
1073 break;
1074 }
1075
1076 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
1077 assert(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
1078
1079 item_non_opt = (const struct argpar_item_non_opt *) item;
1080
1081 switch (item_non_opt->non_opt_index) {
1082 case 0:
1083 session_name_arg = item_non_opt->arg;
1084 break;
1085 default:
1086 ERR("Unexpected argument `%s`.", item_non_opt->arg);
1087 goto error;
1088 }
1089 }
1090
1091 *argc -= argpar_state_get_ingested_orig_args(state);
1092 *argv += argpar_state_get_ingested_orig_args(state);
1093
1094 if (!session_name_arg) {
1095 ERR("Missing session name.");
1096 goto error;
1097 }
1098
1099 action = create_action_cb();
1100 if (!action) {
1101 ERR("Failed to allocate %s session action.", action_name);
1102 goto error;
1103 }
1104
1105 action_status = set_session_name_cb(action, session_name_arg);
1106 if (action_status != LTTNG_ACTION_STATUS_OK) {
1107 ERR("Failed to set action %s session's session name to '%s'.",
1108 action_name, session_name_arg);
1109 goto error;
1110 }
1111
1112 goto end;
1113
1114error:
1115 lttng_action_destroy(action);
1116 action = NULL;
1117 argpar_item_destroy(item);
1118end:
1119 free(error);
1120 argpar_state_destroy(state);
1121 return action;
1122}
1123
1124static
1125struct lttng_action *handle_action_start_session(int *argc,
1126 const char ***argv)
1127{
1128 return handle_action_simple_session(argc, argv,
1129 lttng_action_start_session_create,
1130 lttng_action_start_session_set_session_name,
1131 "start");
1132}
1133
1134static
1135struct lttng_action *handle_action_stop_session(int *argc,
1136 const char ***argv)
1137{
1138 return handle_action_simple_session(argc, argv,
1139 lttng_action_stop_session_create,
1140 lttng_action_stop_session_set_session_name,
1141 "stop");
1142}
1143
1144static
1145struct lttng_action *handle_action_rotate_session(int *argc,
1146 const char ***argv)
1147{
1148 return handle_action_simple_session(argc, argv,
1149 lttng_action_rotate_session_create,
1150 lttng_action_rotate_session_set_session_name,
1151 "rotate");
1152}
1153
1154static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
1155 { OPT_NAME, 'n', "name", true },
1156 { OPT_MAX_SIZE, 'm', "max-size", true },
1157 { OPT_CTRL_URL, '\0', "ctrl-url", true },
1158 { OPT_DATA_URL, '\0', "data-url", true },
1159 { OPT_URL, '\0', "url", true },
1160 { OPT_PATH, '\0', "path", true },
1161 ARGPAR_OPT_DESCR_SENTINEL
1162};
1163
1164static
1165struct lttng_action *handle_action_snapshot_session(int *argc,
1166 const char ***argv)
1167{
1168 struct lttng_action *action = NULL;
1169 struct argpar_state *state = NULL;
1170 struct argpar_item *item = NULL;
1171 const char *session_name_arg = NULL;
1172 char *snapshot_name_arg = NULL;
1173 char *ctrl_url_arg = NULL;
1174 char *data_url_arg = NULL;
1175 char *max_size_arg = NULL;
1176 char *url_arg = NULL;
1177 char *path_arg = NULL;
1178 char *error = NULL;
1179 enum lttng_action_status action_status;
1180 struct lttng_snapshot_output *snapshot_output = NULL;
1181 int ret;
1182 unsigned int locations_specified = 0;
1183
1184 state = argpar_state_create(*argc, *argv, snapshot_action_opt_descrs);
1185 if (!state) {
1186 ERR("Failed to allocate an argpar state.");
1187 goto error;
1188 }
1189
1190 while (true) {
1191 enum argpar_state_parse_next_status status;
1192
1193 ARGPAR_ITEM_DESTROY_AND_RESET(item);
1194 status = argpar_state_parse_next(state, &item, &error);
1195 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
1196 ERR("%s", error);
1197 goto error;
1198 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
1199 /* Just stop parsing here. */
1200 break;
1201 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
1202 break;
1203 }
1204
1205 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
1206
1207 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
1208 const struct argpar_item_opt *item_opt =
1209 (const struct argpar_item_opt *) item;
1210
1211 switch (item_opt->descr->id) {
1212 case OPT_NAME:
1213 if (!assign_string(&snapshot_name_arg, item_opt->arg, "--name/-n")) {
1214 goto error;
1215 }
1216
1217 break;
1218 case OPT_MAX_SIZE:
1219 if (!assign_string(&max_size_arg, item_opt->arg, "--max-size/-m")) {
1220 goto error;
1221 }
1222
1223 break;
1224 case OPT_CTRL_URL:
1225 if (!assign_string(&ctrl_url_arg, item_opt->arg, "--ctrl-url")) {
1226 goto error;
1227 }
1228
1229 break;
1230 case OPT_DATA_URL:
1231 if (!assign_string(&data_url_arg, item_opt->arg, "--data-url")) {
1232 goto error;
1233 }
1234
1235 break;
1236 case OPT_URL:
1237 if (!assign_string(&url_arg, item_opt->arg, "--url")) {
1238 goto error;
1239 }
1240
1241 break;
1242 case OPT_PATH:
1243 if (!assign_string(&path_arg, item_opt->arg, "--path")) {
1244 goto error;
1245 }
1246
1247 break;
1248 default:
1249 abort();
1250 }
1251 } else {
1252 const struct argpar_item_non_opt *item_non_opt;
1253
1254 assert(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
1255
1256 item_non_opt = (const struct argpar_item_non_opt *) item;
1257
1258 switch (item_non_opt->non_opt_index) {
1259 case 0:
1260 session_name_arg = item_non_opt->arg;
1261 break;
1262 default:
1263 ERR("Unexpected argument `%s`.",
1264 item_non_opt->arg);
1265 goto error;
1266 }
1267 }
1268 }
1269
1270 *argc -= argpar_state_get_ingested_orig_args(state);
1271 *argv += argpar_state_get_ingested_orig_args(state);
1272
1273 if (!session_name_arg) {
1274 ERR("Missing session name.");
1275 goto error;
1276 }
1277
1278 /* --ctrl-url and --data-url must come in pair. */
1279 if (ctrl_url_arg && !data_url_arg) {
1280 ERR("--ctrl-url is specified, but --data-url is missing.");
1281 goto error;
1282 }
1283
1284 if (!ctrl_url_arg && data_url_arg) {
1285 ERR("--data-url is specified, but --ctrl-url is missing.");
1286 goto error;
1287 }
1288
1289 locations_specified += !!(ctrl_url_arg || data_url_arg);
1290 locations_specified += !!url_arg;
1291 locations_specified += !!path_arg;
1292
1293 /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
1294 if (locations_specified > 1) {
1295 ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
1296 goto error;
1297 }
1298
1299 /*
1300 * Did the user specify an option that implies using a
1301 * custom/unregistered output?
1302 */
1303 if (url_arg || ctrl_url_arg || path_arg) {
1304 snapshot_output = lttng_snapshot_output_create();
1305 if (!snapshot_output) {
1306 ERR("Failed to allocate a snapshot output.");
1307 goto error;
1308 }
1309 }
1310
1311 action = lttng_action_snapshot_session_create();
1312 if (!action) {
1313 ERR("Failed to allocate snapshot session action.");
1314 goto error;
1315 }
1316
1317 action_status = lttng_action_snapshot_session_set_session_name(
1318 action, session_name_arg);
1319 if (action_status != LTTNG_ACTION_STATUS_OK) {
1320 ERR("Failed to set action snapshot session's session name to '%s'.",
1321 session_name_arg);
1322 goto error;
1323 }
1324
1325 if (snapshot_name_arg) {
1326 if (!snapshot_output) {
1327 ERR("Can't provide a snapshot output name without a snapshot output destination.");
1328 goto error;
1329 }
1330
1331 ret = lttng_snapshot_output_set_name(
1332 snapshot_name_arg, snapshot_output);
1333 if (ret != 0) {
1334 ERR("Failed to set name of snapshot output.");
1335 goto error;
1336 }
1337 }
1338
1339 if (max_size_arg) {
1340 uint64_t max_size;
1341
1342 if (!snapshot_output) {
1343 ERR("Can't provide a snapshot output max size without a snapshot output destination.");
1344 goto error;
1345 }
1346
1347 ret = utils_parse_size_suffix(max_size_arg, &max_size);
1348 if (ret != 0) {
1349 ERR("Failed to parse `%s` as a size.", max_size_arg);
1350 goto error;
1351 }
1352
1353 ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
1354 if (ret != 0) {
1355 ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
1356 max_size);
1357 goto error;
1358 }
1359 }
1360
1361 if (url_arg) {
1362 int num_uris;
1363 struct lttng_uri *uris;
1364
1365 if (!strstr(url_arg, "://")) {
1366 ERR("Failed to parse '%s' as an URL.", url_arg);
1367 goto error;
1368 }
1369
1370 num_uris = uri_parse_str_urls(url_arg, NULL, &uris);
1371 if (num_uris < 1) {
1372 ERR("Failed to parse '%s' as an URL.", url_arg);
1373 goto error;
1374 }
1375
1376 if (uris[0].dtype == LTTNG_DST_PATH) {
1377 ret = lttng_snapshot_output_set_local_path(
1378 uris[0].dst.path, snapshot_output);
1379 free(uris);
1380 if (ret != 0) {
1381 ERR("Failed to assign '%s' as a local destination.",
1382 url_arg);
1383 goto error;
1384 }
1385 } else {
1386 ret = lttng_snapshot_output_set_network_url(
1387 url_arg, snapshot_output);
1388 free(uris);
1389 if (ret != 0) {
1390 ERR("Failed to assign '%s' as a network URL.",
1391 url_arg);
1392 goto error;
1393 }
1394 }
1395 }
1396
1397 if (path_arg) {
1398 ret = lttng_snapshot_output_set_local_path(
1399 path_arg, snapshot_output);
1400 if (ret != 0) {
1401 ERR("Failed to parse '%s' as a local path.", path_arg);
1402 goto error;
1403 }
1404 }
1405
1406 if (ctrl_url_arg) {
1407 /*
1408 * Two argument form, network output with separate control and
1409 * data URLs.
1410 */
1411 ret = lttng_snapshot_output_set_network_urls(
1412 ctrl_url_arg, data_url_arg, snapshot_output);
1413 if (ret != 0) {
1414 ERR("Failed to parse `%s` and `%s` as control and data URLs.",
1415 ctrl_url_arg, data_url_arg);
1416 goto error;
1417 }
1418 }
1419
1420 if (snapshot_output) {
1421 action_status = lttng_action_snapshot_session_set_output(
1422 action, snapshot_output);
1423 if (action_status != LTTNG_ACTION_STATUS_OK) {
1424 ERR("Failed to set snapshot session action's output.");
1425 goto error;
1426 }
1427
1428 /* Ownership of `snapshot_output` has been transferred to the action. */
1429 snapshot_output = NULL;
1430 }
1431
1432 goto end;
1433
1434error:
1435 lttng_action_destroy(action);
1436 action = NULL;
1437 free(error);
1438end:
1439 free(snapshot_name_arg);
1440 free(path_arg);
1441 free(url_arg);
1442 free(ctrl_url_arg);
1443 free(data_url_arg);
1444 free(snapshot_output);
1445 free(max_size_arg);
1446 argpar_state_destroy(state);
1447 argpar_item_destroy(item);
1448 return action;
1449}
1450
1451struct action_descr {
1452 const char *name;
1453 struct lttng_action *(*handler) (int *argc, const char ***argv);
1454};
1455
1456static const
1457struct action_descr action_descrs[] = {
1458 { "notify", handle_action_notify },
1459 { "start-session", handle_action_start_session },
1460 { "stop-session", handle_action_stop_session },
1461 { "rotate-session", handle_action_rotate_session },
1462 { "snapshot-session", handle_action_snapshot_session },
1463};
1464
1465static
1466struct lttng_action *parse_action(int *argc, const char ***argv)
1467{
1468 int i;
1469 struct lttng_action *action;
1470 const char *action_name;
1471 const struct action_descr *descr = NULL;
1472
1473 if (*argc == 0) {
1474 ERR("Missing action name.");
1475 goto error;
1476 }
1477
1478 action_name = (*argv)[0];
1479
1480 (*argc)--;
1481 (*argv)++;
1482
1483 for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
1484 if (strcmp(action_name, action_descrs[i].name) == 0) {
1485 descr = &action_descrs[i];
1486 break;
1487 }
1488 }
1489
1490 if (!descr) {
1491 ERR("Unknown action name: %s", action_name);
1492 goto error;
1493 }
1494
1495 action = descr->handler(argc, argv);
1496 if (!action) {
1497 /* The handler has already printed an error message. */
1498 goto error;
1499 }
1500
1501 goto end;
1502error:
1503 action = NULL;
1504end:
1505 return action;
1506}
1507
1508static const
1509struct argpar_opt_descr add_trigger_options[] = {
1510 { OPT_HELP, 'h', "help", false },
1511 { OPT_LIST_OPTIONS, '\0', "list-options", false },
1512 { OPT_CONDITION, '\0', "condition", false },
1513 { OPT_ACTION, '\0', "action", false },
1514 { OPT_ID, '\0', "id", true },
1515 { OPT_FIRE_ONCE_AFTER, '\0', "fire-once-after", true },
1516 { OPT_FIRE_EVERY, '\0', "fire-every", true },
1517 { OPT_USER_ID, '\0', "user-id", true },
1518 ARGPAR_OPT_DESCR_SENTINEL,
1519};
1520
1521static
1522void lttng_actions_destructor(void *p)
1523{
1524 struct lttng_action *action = p;
1525
1526 lttng_action_destroy(action);
1527}
1528
1529int cmd_add_trigger(int argc, const char **argv)
1530{
1531 int ret;
1532 int my_argc = argc - 1;
1533 const char **my_argv = argv + 1;
1534 struct lttng_condition *condition = NULL;
1535 struct lttng_dynamic_pointer_array actions;
1536 struct argpar_state *argpar_state = NULL;
1537 struct argpar_item *argpar_item = NULL;
1538 struct lttng_action *action_group = NULL;
1539 struct lttng_action *action = NULL;
1540 struct lttng_trigger *trigger = NULL;
1541 char *error = NULL;
1542 char *id = NULL;
1543 int i;
1544 char *fire_once_after_str = NULL;
1545 char *fire_every_str = NULL;
1546 char *user_id = NULL;
1547
1548 lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
1549
1550 while (true) {
1551 enum argpar_state_parse_next_status status;
1552 const struct argpar_item_opt *item_opt;
1553 int ingested_args;
1554
1555 argpar_state_destroy(argpar_state);
1556 argpar_state = argpar_state_create(my_argc, my_argv,
1557 add_trigger_options);
1558 if (!argpar_state) {
1559 ERR("Failed to create argpar state.");
1560 goto error;
1561 }
1562
1563 ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
1564 status = argpar_state_parse_next(argpar_state, &argpar_item, &error);
1565 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
1566 ERR("%s", error);
1567 goto error;
1568 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
1569 ERR("%s", error);
1570 goto error;
1571 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
1572 break;
1573 }
1574
1575 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
1576
1577 if (argpar_item->type == ARGPAR_ITEM_TYPE_NON_OPT) {
1578 const struct argpar_item_non_opt *item_non_opt =
1579 (const struct argpar_item_non_opt *)
1580 argpar_item;
1581
1582 ERR("Unexpected argument `%s`.", item_non_opt->arg);
1583 goto error;
1584 }
1585
1586 item_opt = (const struct argpar_item_opt *) argpar_item;
1587
1588 ingested_args = argpar_state_get_ingested_orig_args(
1589 argpar_state);
1590
1591 my_argc -= ingested_args;
1592 my_argv += ingested_args;
1593
1594 switch (item_opt->descr->id) {
1595 case OPT_HELP:
1596 SHOW_HELP();
1597 ret = 0;
1598 goto end;
1599 case OPT_LIST_OPTIONS:
1600 list_cmd_options_argpar(stdout, add_trigger_options);
1601 ret = 0;
1602 goto end;
1603 case OPT_CONDITION:
1604 {
1605 if (condition) {
1606 ERR("A --condition was already given.");
1607 goto error;
1608 }
1609
1610 condition = parse_condition(&my_argc, &my_argv);
1611 if (!condition) {
1612 /*
1613 * An error message was already printed by
1614 * parse_condition.
1615 */
1616 goto error;
1617 }
1618
1619 break;
1620 }
1621 case OPT_ACTION:
1622 {
1623 action = parse_action(&my_argc, &my_argv);
1624 if (!action) {
1625 /*
1626 * An error message was already printed by
1627 * parse_condition.
1628 */
1629 goto error;
1630 }
1631
1632 ret = lttng_dynamic_pointer_array_add_pointer(
1633 &actions, action);
1634 if (ret) {
1635 ERR("Failed to add pointer to pointer array.");
1636 goto error;
1637 }
1638
1639 /* Ownership of the action was transferred to the group. */
1640 action = NULL;
1641
1642 break;
1643 }
1644 case OPT_ID:
1645 {
1646 if (!assign_string(&id, item_opt->arg, "--id")) {
1647 goto error;
1648 }
1649
1650 break;
1651 }
1652 case OPT_FIRE_ONCE_AFTER:
1653 {
1654 if (!assign_string(&fire_once_after_str, item_opt->arg,
1655 "--fire-once-after")) {
1656 goto error;
1657 }
1658
1659 break;
1660 }
1661 case OPT_FIRE_EVERY:
1662 {
1663 if (!assign_string(&fire_every_str, item_opt->arg,
1664 "--fire-every")) {
1665 goto error;
1666 }
1667
1668 break;
1669 }
1670 case OPT_USER_ID:
1671 {
1672 if (!assign_string(&user_id, item_opt->arg,
1673 "--user-id")) {
1674 goto error;
1675 }
1676
1677 break;
1678 }
1679 default:
1680 abort();
1681 }
1682 }
1683
1684 if (!condition) {
1685 ERR("Missing --condition.");
1686 goto error;
1687 }
1688
1689 if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
1690 ERR("Need at least one --action.");
1691 goto error;
1692 }
1693
1694 if (fire_every_str && fire_once_after_str) {
1695 ERR("Can't specify both --fire-once-after and --fire-every.");
1696 goto error;
1697 }
1698
1699 action_group = lttng_action_group_create();
1700 if (!action_group) {
1701 goto error;
1702 }
1703
1704 for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
1705 enum lttng_action_status status;
1706
1707 action = lttng_dynamic_pointer_array_steal_pointer(&actions, i);
1708
1709 status = lttng_action_group_add_action(action_group, action);
1710 if (status != LTTNG_ACTION_STATUS_OK) {
1711 goto error;
1712 }
1713
1714 /*
1715 * The `lttng_action_group_add_action()` takes a reference to
1716 * the action. We can destroy ours.
1717 */
1718 lttng_action_destroy(action);
1719 action = NULL;
1720 }
1721
1722 trigger = lttng_trigger_create(condition, action_group);
1723 if (!trigger) {
1724 goto error;
1725 }
1726
1727 if (id) {
1728 enum lttng_trigger_status trigger_status =
1729 lttng_trigger_set_name(trigger, id);
1730
1731 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1732 ERR("Failed to set trigger id.");
1733 goto error;
1734 }
1735 }
1736
1737 if (fire_once_after_str) {
1738 unsigned long long threshold;
1739 enum lttng_trigger_status trigger_status;
1740
1741 if (utils_parse_unsigned_long_long(fire_once_after_str, &threshold) != 0) {
1742 ERR("Failed to parse `%s` as an integer.", fire_once_after_str);
1743 goto error;
1744 }
1745
1746 trigger_status = lttng_trigger_set_firing_policy(trigger,
1747 LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N,
1748 threshold);
1749 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1750 ERR("Failed to set trigger's policy to `fire once after N`.");
1751 goto error;
1752 }
1753 }
1754
1755 if (fire_every_str) {
1756 unsigned long long threshold;
1757 enum lttng_trigger_status trigger_status;
1758
1759 if (utils_parse_unsigned_long_long(fire_every_str, &threshold) != 0) {
1760 ERR("Failed to parse `%s` as an integer.", fire_every_str);
1761 goto error;
1762 }
1763
1764 trigger_status = lttng_trigger_set_firing_policy(trigger,
1765 LTTNG_TRIGGER_FIRING_POLICY_EVERY_N, threshold);
1766 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1767 ERR("Failed to set trigger's policy to `fire every N`.");
1768 goto error;
1769 }
1770 }
1771
1772 if (user_id) {
1773 enum lttng_trigger_status trigger_status;
1774 char *end;
1775 long long uid;
1776
1777 errno = 0;
1778 uid = strtol(user_id, &end, 10);
1779 if (end == user_id || *end != '\0' || errno != 0) {
1780 ERR("Failed to parse `%s` as a user id.", user_id);
1781 }
1782
1783 trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
1784 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1785 ERR("Failed to set trigger's user identity.");
1786 goto error;
1787 }
1788 }
1789
1790 ret = lttng_register_trigger(trigger);
1791 if (ret) {
1792 ERR("Failed to register trigger: %s.", lttng_strerror(ret));
1793 goto error;
1794 }
1795
1796 MSG("Trigger registered successfully.");
1797
1798 goto end;
1799
1800error:
1801 ret = 1;
1802
1803end:
1804 argpar_state_destroy(argpar_state);
1805 argpar_item_destroy(argpar_item);
1806 lttng_dynamic_pointer_array_reset(&actions);
1807 lttng_condition_destroy(condition);
1808 lttng_action_destroy(action_group);
1809 lttng_action_destroy(action);
1810 lttng_trigger_destroy(trigger);
1811 free(error);
1812 free(id);
1813 free(fire_once_after_str);
1814 free(fire_every_str);
1815 free(user_id);
1816 return ret;
1817}
This page took 0.073919 seconds and 4 git commands to generate.