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