Fix: lttng: add-trigger: leak of argpar_item
[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);
14f27f79 255 if (!*location) {
4624dad0
SM
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);
97abbc84 1117 argpar_item_destroy(item);
4624dad0
SM
1118end:
1119 return action;
1120}
1121
1122static
1123struct lttng_action *handle_action_start_session(int *argc,
1124 const char ***argv)
1125{
1126 return handle_action_simple_session(argc, argv,
1127 lttng_action_start_session_create,
1128 lttng_action_start_session_set_session_name,
1129 "start");
1130}
1131
1132static
1133struct lttng_action *handle_action_stop_session(int *argc,
1134 const char ***argv)
1135{
1136 return handle_action_simple_session(argc, argv,
1137 lttng_action_stop_session_create,
1138 lttng_action_stop_session_set_session_name,
1139 "stop");
1140}
1141
1142static
1143struct lttng_action *handle_action_rotate_session(int *argc,
1144 const char ***argv)
1145{
1146 return handle_action_simple_session(argc, argv,
1147 lttng_action_rotate_session_create,
1148 lttng_action_rotate_session_set_session_name,
1149 "rotate");
1150}
1151
1152static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
1153 { OPT_NAME, 'n', "name", true },
1154 { OPT_MAX_SIZE, 'm', "max-size", true },
1155 { OPT_CTRL_URL, '\0', "ctrl-url", true },
1156 { OPT_DATA_URL, '\0', "data-url", true },
1157 { OPT_URL, '\0', "url", true },
1158 { OPT_PATH, '\0', "path", true },
1159 ARGPAR_OPT_DESCR_SENTINEL
1160};
1161
1162static
1163struct lttng_action *handle_action_snapshot_session(int *argc,
1164 const char ***argv)
1165{
1166 struct lttng_action *action = NULL;
1167 struct argpar_state *state = NULL;
1168 struct argpar_item *item = NULL;
1169 const char *session_name_arg = NULL;
1170 char *snapshot_name_arg = NULL;
1171 char *ctrl_url_arg = NULL;
1172 char *data_url_arg = NULL;
1173 char *max_size_arg = NULL;
1174 char *url_arg = NULL;
1175 char *path_arg = NULL;
1176 char *error = NULL;
1177 enum lttng_action_status action_status;
1178 struct lttng_snapshot_output *snapshot_output = NULL;
1179 int ret;
1180 unsigned int locations_specified = 0;
1181
1182 state = argpar_state_create(*argc, *argv, snapshot_action_opt_descrs);
1183 if (!state) {
1184 ERR("Failed to allocate an argpar state.");
1185 goto error;
1186 }
1187
1188 while (true) {
1189 enum argpar_state_parse_next_status status;
1190
1191 ARGPAR_ITEM_DESTROY_AND_RESET(item);
1192 status = argpar_state_parse_next(state, &item, &error);
1193 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
1194 ERR("%s", error);
1195 goto error;
1196 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
1197 /* Just stop parsing here. */
1198 break;
1199 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
1200 break;
1201 }
1202
1203 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
1204
1205 if (item->type == ARGPAR_ITEM_TYPE_OPT) {
1206 const struct argpar_item_opt *item_opt =
1207 (const struct argpar_item_opt *) item;
1208
1209 switch (item_opt->descr->id) {
1210 case OPT_NAME:
1211 if (!assign_string(&snapshot_name_arg, item_opt->arg, "--name/-n")) {
1212 goto error;
1213 }
1214
1215 break;
1216 case OPT_MAX_SIZE:
1217 if (!assign_string(&max_size_arg, item_opt->arg, "--max-size/-m")) {
1218 goto error;
1219 }
1220
1221 break;
1222 case OPT_CTRL_URL:
1223 if (!assign_string(&ctrl_url_arg, item_opt->arg, "--ctrl-url")) {
1224 goto error;
1225 }
1226
1227 break;
1228 case OPT_DATA_URL:
1229 if (!assign_string(&data_url_arg, item_opt->arg, "--data-url")) {
1230 goto error;
1231 }
1232
1233 break;
1234 case OPT_URL:
1235 if (!assign_string(&url_arg, item_opt->arg, "--url")) {
1236 goto error;
1237 }
1238
1239 break;
1240 case OPT_PATH:
1241 if (!assign_string(&path_arg, item_opt->arg, "--path")) {
1242 goto error;
1243 }
1244
1245 break;
1246 default:
1247 abort();
1248 }
1249 } else {
1250 const struct argpar_item_non_opt *item_non_opt;
1251
1252 assert(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
1253
1254 item_non_opt = (const struct argpar_item_non_opt *) item;
1255
1256 switch (item_non_opt->non_opt_index) {
1257 case 0:
1258 session_name_arg = item_non_opt->arg;
1259 break;
1260 default:
1261 ERR("Unexpected argument `%s`.",
1262 item_non_opt->arg);
1263 goto error;
1264 }
1265 }
1266 }
1267
1268 *argc -= argpar_state_get_ingested_orig_args(state);
1269 *argv += argpar_state_get_ingested_orig_args(state);
1270
1271 if (!session_name_arg) {
1272 ERR("Missing session name.");
1273 goto error;
1274 }
1275
1276 /* --ctrl-url and --data-url must come in pair. */
1277 if (ctrl_url_arg && !data_url_arg) {
1278 ERR("--ctrl-url is specified, but --data-url is missing.");
1279 goto error;
1280 }
1281
1282 if (!ctrl_url_arg && data_url_arg) {
1283 ERR("--data-url is specified, but --ctrl-url is missing.");
1284 goto error;
1285 }
1286
1287 locations_specified += !!(ctrl_url_arg || data_url_arg);
1288 locations_specified += !!url_arg;
1289 locations_specified += !!path_arg;
1290
1291 /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
1292 if (locations_specified > 1) {
1293 ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
1294 goto error;
1295 }
1296
1297 /*
1298 * Did the user specify an option that implies using a
1299 * custom/unregistered output?
1300 */
1301 if (url_arg || ctrl_url_arg || path_arg) {
1302 snapshot_output = lttng_snapshot_output_create();
1303 if (!snapshot_output) {
1304 ERR("Failed to allocate a snapshot output.");
1305 goto error;
1306 }
1307 }
1308
1309 action = lttng_action_snapshot_session_create();
1310 if (!action) {
1311 ERR("Failed to allocate snapshot session action.");
1312 goto error;
1313 }
1314
1315 action_status = lttng_action_snapshot_session_set_session_name(
1316 action, session_name_arg);
1317 if (action_status != LTTNG_ACTION_STATUS_OK) {
1318 ERR("Failed to set action snapshot session's session name to '%s'.",
1319 session_name_arg);
1320 goto error;
1321 }
1322
1323 if (snapshot_name_arg) {
1324 if (!snapshot_output) {
1325 ERR("Can't provide a snapshot output name without a snapshot output destination.");
1326 goto error;
1327 }
1328
1329 ret = lttng_snapshot_output_set_name(
1330 snapshot_name_arg, snapshot_output);
1331 if (ret != 0) {
1332 ERR("Failed to set name of snapshot output.");
1333 goto error;
1334 }
1335 }
1336
1337 if (max_size_arg) {
1338 uint64_t max_size;
1339
1340 if (!snapshot_output) {
1341 ERR("Can't provide a snapshot output max size without a snapshot output destination.");
1342 goto error;
1343 }
1344
1345 ret = utils_parse_size_suffix(max_size_arg, &max_size);
1346 if (ret != 0) {
1347 ERR("Failed to parse `%s` as a size.", max_size_arg);
1348 goto error;
1349 }
1350
1351 ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
1352 if (ret != 0) {
1353 ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
1354 max_size);
1355 goto error;
1356 }
1357 }
1358
1359 if (url_arg) {
1360 int num_uris;
1361 struct lttng_uri *uris;
1362
1363 if (!strstr(url_arg, "://")) {
1364 ERR("Failed to parse '%s' as an URL.", url_arg);
1365 goto error;
1366 }
1367
1368 num_uris = uri_parse_str_urls(url_arg, NULL, &uris);
1369 if (num_uris < 1) {
1370 ERR("Failed to parse '%s' as an URL.", url_arg);
1371 goto error;
1372 }
1373
1374 if (uris[0].dtype == LTTNG_DST_PATH) {
1375 ret = lttng_snapshot_output_set_local_path(
1376 uris[0].dst.path, snapshot_output);
1377 free(uris);
1378 if (ret != 0) {
1379 ERR("Failed to assign '%s' as a local destination.",
1380 url_arg);
1381 goto error;
1382 }
1383 } else {
1384 ret = lttng_snapshot_output_set_network_url(
1385 url_arg, snapshot_output);
1386 free(uris);
1387 if (ret != 0) {
1388 ERR("Failed to assign '%s' as a network URL.",
1389 url_arg);
1390 goto error;
1391 }
1392 }
1393 }
1394
1395 if (path_arg) {
1396 ret = lttng_snapshot_output_set_local_path(
1397 path_arg, snapshot_output);
1398 if (ret != 0) {
1399 ERR("Failed to parse '%s' as a local path.", path_arg);
1400 goto error;
1401 }
1402 }
1403
1404 if (ctrl_url_arg) {
1405 /*
1406 * Two argument form, network output with separate control and
1407 * data URLs.
1408 */
1409 ret = lttng_snapshot_output_set_network_urls(
1410 ctrl_url_arg, data_url_arg, snapshot_output);
1411 if (ret != 0) {
1412 ERR("Failed to parse `%s` and `%s` as control and data URLs.",
1413 ctrl_url_arg, data_url_arg);
1414 goto error;
1415 }
1416 }
1417
1418 if (snapshot_output) {
1419 action_status = lttng_action_snapshot_session_set_output(
1420 action, snapshot_output);
1421 if (action_status != LTTNG_ACTION_STATUS_OK) {
1422 ERR("Failed to set snapshot session action's output.");
1423 goto error;
1424 }
1425
1426 /* Ownership of `snapshot_output` has been transferred to the action. */
1427 snapshot_output = NULL;
1428 }
1429
1430 goto end;
1431
1432error:
1433 lttng_action_destroy(action);
1434 action = NULL;
1435 free(error);
1436end:
1437 free(snapshot_name_arg);
1438 free(path_arg);
1439 free(url_arg);
1440 free(ctrl_url_arg);
1441 free(data_url_arg);
1442 free(snapshot_output);
1443 argpar_state_destroy(state);
97abbc84 1444 argpar_item_destroy(item);
4624dad0
SM
1445 return action;
1446}
1447
1448struct action_descr {
1449 const char *name;
1450 struct lttng_action *(*handler) (int *argc, const char ***argv);
1451};
1452
1453static const
1454struct action_descr action_descrs[] = {
1455 { "notify", handle_action_notify },
1456 { "start-session", handle_action_start_session },
1457 { "stop-session", handle_action_stop_session },
1458 { "rotate-session", handle_action_rotate_session },
1459 { "snapshot-session", handle_action_snapshot_session },
1460};
1461
1462static
1463struct lttng_action *parse_action(int *argc, const char ***argv)
1464{
1465 int i;
1466 struct lttng_action *action;
1467 const char *action_name;
1468 const struct action_descr *descr = NULL;
1469
1470 if (*argc == 0) {
1471 ERR("Missing action name.");
1472 goto error;
1473 }
1474
1475 action_name = (*argv)[0];
1476
1477 (*argc)--;
1478 (*argv)++;
1479
1480 for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
1481 if (strcmp(action_name, action_descrs[i].name) == 0) {
1482 descr = &action_descrs[i];
1483 break;
1484 }
1485 }
1486
1487 if (!descr) {
1488 ERR("Unknown action name: %s", action_name);
1489 goto error;
1490 }
1491
1492 action = descr->handler(argc, argv);
1493 if (!action) {
1494 /* The handler has already printed an error message. */
1495 goto error;
1496 }
1497
1498 goto end;
1499error:
1500 action = NULL;
1501end:
1502 return action;
1503}
1504
1505static const
1506struct argpar_opt_descr add_trigger_options[] = {
1507 { OPT_HELP, 'h', "help", false },
1508 { OPT_LIST_OPTIONS, '\0', "list-options", false },
1509 { OPT_CONDITION, '\0', "condition", false },
1510 { OPT_ACTION, '\0', "action", false },
1511 { OPT_ID, '\0', "id", true },
1512 { OPT_FIRE_ONCE_AFTER, '\0', "fire-once-after", true },
1513 { OPT_FIRE_EVERY, '\0', "fire-every", true },
1514 { OPT_USER_ID, '\0', "user-id", true },
1515 ARGPAR_OPT_DESCR_SENTINEL,
1516};
1517
1518static
1519void lttng_actions_destructor(void *p)
1520{
1521 struct lttng_action *action = p;
1522
1523 lttng_action_destroy(action);
1524}
1525
1526int cmd_add_trigger(int argc, const char **argv)
1527{
1528 int ret;
1529 int my_argc = argc - 1;
1530 const char **my_argv = argv + 1;
1531 struct lttng_condition *condition = NULL;
1532 struct lttng_dynamic_pointer_array actions;
1533 struct argpar_state *argpar_state = NULL;
1534 struct argpar_item *argpar_item = NULL;
1535 struct lttng_action *action_group = NULL;
1536 struct lttng_action *action = NULL;
1537 struct lttng_trigger *trigger = NULL;
1538 char *error = NULL;
1539 char *id = NULL;
1540 int i;
1541 char *fire_once_after_str = NULL;
1542 char *fire_every_str = NULL;
1543 char *user_id = NULL;
1544
1545 lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
1546
1547 while (true) {
1548 enum argpar_state_parse_next_status status;
1549 const struct argpar_item_opt *item_opt;
1550 int ingested_args;
1551
1552 argpar_state_destroy(argpar_state);
1553 argpar_state = argpar_state_create(my_argc, my_argv,
1554 add_trigger_options);
1555 if (!argpar_state) {
1556 ERR("Failed to create argpar state.");
1557 goto error;
1558 }
1559
1560 ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
1561 status = argpar_state_parse_next(argpar_state, &argpar_item, &error);
1562 if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
1563 ERR("%s", error);
1564 goto error;
1565 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
1566 ERR("%s", error);
1567 goto error;
1568 } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
1569 break;
1570 }
1571
1572 assert(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
1573
1574 if (argpar_item->type == ARGPAR_ITEM_TYPE_NON_OPT) {
1575 const struct argpar_item_non_opt *item_non_opt =
1576 (const struct argpar_item_non_opt *)
1577 argpar_item;
1578
1579 ERR("Unexpected argument `%s`.", item_non_opt->arg);
1580 goto error;
1581 }
1582
1583 item_opt = (const struct argpar_item_opt *) argpar_item;
1584
1585 ingested_args = argpar_state_get_ingested_orig_args(
1586 argpar_state);
1587
1588 my_argc -= ingested_args;
1589 my_argv += ingested_args;
1590
1591 switch (item_opt->descr->id) {
1592 case OPT_HELP:
1593 SHOW_HELP();
1594 ret = 0;
1595 goto end;
1596 case OPT_LIST_OPTIONS:
1597 list_cmd_options_argpar(stdout, add_trigger_options);
1598 ret = 0;
1599 goto end;
1600 case OPT_CONDITION:
1601 {
1602 if (condition) {
1603 ERR("A --condition was already given.");
1604 goto error;
1605 }
1606
1607 condition = parse_condition(&my_argc, &my_argv);
1608 if (!condition) {
1609 /*
1610 * An error message was already printed by
1611 * parse_condition.
1612 */
1613 goto error;
1614 }
1615
1616 break;
1617 }
1618 case OPT_ACTION:
1619 {
1620 action = parse_action(&my_argc, &my_argv);
1621 if (!action) {
1622 /*
1623 * An error message was already printed by
1624 * parse_condition.
1625 */
1626 goto error;
1627 }
1628
1629 ret = lttng_dynamic_pointer_array_add_pointer(
1630 &actions, action);
1631 if (ret) {
1632 ERR("Failed to add pointer to pointer array.");
1633 goto error;
1634 }
1635
1636 /* Ownership of the action was transferred to the group. */
1637 action = NULL;
1638
1639 break;
1640 }
1641 case OPT_ID:
1642 {
1643 if (!assign_string(&id, item_opt->arg, "--id")) {
1644 goto error;
1645 }
1646
1647 break;
1648 }
1649 case OPT_FIRE_ONCE_AFTER:
1650 {
1651 if (!assign_string(&fire_once_after_str, item_opt->arg,
1652 "--fire-once-after")) {
1653 goto error;
1654 }
1655
1656 break;
1657 }
1658 case OPT_FIRE_EVERY:
1659 {
1660 if (!assign_string(&fire_every_str, item_opt->arg,
1661 "--fire-every")) {
1662 goto error;
1663 }
1664
1665 break;
1666 }
1667 case OPT_USER_ID:
1668 {
1669 if (!assign_string(&user_id, item_opt->arg,
1670 "--user-id")) {
1671 goto error;
1672 }
1673
1674 break;
1675 }
1676 default:
1677 abort();
1678 }
1679 }
1680
1681 if (!condition) {
1682 ERR("Missing --condition.");
1683 goto error;
1684 }
1685
1686 if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
1687 ERR("Need at least one --action.");
1688 goto error;
1689 }
1690
1691 if (fire_every_str && fire_once_after_str) {
1692 ERR("Can't specify both --fire-once-after and --fire-every.");
1693 goto error;
1694 }
1695
1696 action_group = lttng_action_group_create();
1697 if (!action_group) {
1698 goto error;
1699 }
1700
1701 for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
1702 enum lttng_action_status status;
1703
1704 action = lttng_dynamic_pointer_array_steal_pointer(&actions, i);
1705
1706 status = lttng_action_group_add_action(action_group, action);
1707 if (status != LTTNG_ACTION_STATUS_OK) {
1708 goto error;
1709 }
1710
1711 /*
1712 * The `lttng_action_group_add_action()` takes a reference to
1713 * the action. We can destroy ours.
1714 */
1715 lttng_action_destroy(action);
1716 action = NULL;
1717 }
1718
1719 trigger = lttng_trigger_create(condition, action_group);
1720 if (!trigger) {
1721 goto error;
1722 }
1723
1724 if (id) {
1725 enum lttng_trigger_status trigger_status =
1726 lttng_trigger_set_name(trigger, id);
1727
1728 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1729 ERR("Failed to set trigger id.");
1730 goto error;
1731 }
1732 }
1733
1734 if (fire_once_after_str) {
1735 unsigned long long threshold;
1736 enum lttng_trigger_status trigger_status;
1737
1738 if (utils_parse_unsigned_long_long(fire_once_after_str, &threshold) != 0) {
1739 ERR("Failed to parse `%s` as an integer.", fire_once_after_str);
1740 goto error;
1741 }
1742
1743 trigger_status = lttng_trigger_set_firing_policy(trigger,
1744 LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N,
1745 threshold);
1746 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1747 ERR("Failed to set trigger's policy to `fire once after N`.");
1748 goto error;
1749 }
1750 }
1751
1752 if (fire_every_str) {
1753 unsigned long long threshold;
1754 enum lttng_trigger_status trigger_status;
1755
1756 if (utils_parse_unsigned_long_long(fire_every_str, &threshold) != 0) {
1757 ERR("Failed to parse `%s` as an integer.", fire_every_str);
1758 goto error;
1759 }
1760
1761 trigger_status = lttng_trigger_set_firing_policy(trigger,
1762 LTTNG_TRIGGER_FIRING_POLICY_EVERY_N, threshold);
1763 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1764 ERR("Failed to set trigger's policy to `fire every N`.");
1765 goto error;
1766 }
1767 }
1768
1769 if (user_id) {
1770 enum lttng_trigger_status trigger_status;
1771 char *end;
1772 long long uid;
1773
1774 errno = 0;
1775 uid = strtol(user_id, &end, 10);
1776 if (end == user_id || *end != '\0' || errno != 0) {
1777 ERR("Failed to parse `%s` as a user id.", user_id);
1778 }
1779
1780 trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
1781 if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
1782 ERR("Failed to set trigger's user identity.");
1783 goto error;
1784 }
1785 }
1786
1787 ret = lttng_register_trigger(trigger);
1788 if (ret) {
1789 ERR("Failed to register trigger: %s.", lttng_strerror(ret));
1790 goto error;
1791 }
1792
1793 MSG("Trigger registered successfully.");
1794
1795 goto end;
1796
1797error:
1798 ret = 1;
1799
1800end:
1801 argpar_state_destroy(argpar_state);
1802 argpar_item_destroy(argpar_item);
1803 lttng_dynamic_pointer_array_reset(&actions);
1804 lttng_condition_destroy(condition);
1805 lttng_action_destroy(action_group);
1806 lttng_action_destroy(action);
1807 lttng_trigger_destroy(trigger);
1808 free(error);
1809 free(id);
1810 free(fire_once_after_str);
1811 free(fire_every_str);
1812 free(user_id);
1813 return ret;
1814}
This page took 0.0897289999999999 seconds and 4 git commands to generate.