Clean-up: replace uses of `int enabled` with boolean flags
[lttng-tools.git] / src / bin / lttng / commands / enable_events.cpp
1 /*
2 * Copyright (C) 2011 EfficiOS Inc.
3 *
4 * SPDX-License-Identifier: GPL-2.0-only
5 *
6 */
7
8 #define _LGPL_SOURCE
9 #include <common/compat/getenv.hpp>
10 #include <common/compat/string.hpp>
11 #include <common/sessiond-comm/sessiond-comm.hpp>
12 #include <common/string-utils/string-utils.hpp>
13 #include <common/utils.hpp>
14
15 #include <ctype.h>
16 #include <inttypes.h>
17 #include <popt.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/stat.h>
21 #include <sys/types.h>
22 #include <unistd.h>
23
24 /* Mi dependancy */
25 #include "../command.hpp"
26 #include "../loglevel.hpp"
27 #include "../uprobe.hpp"
28
29 #include <common/mi-lttng.hpp>
30
31 #include <lttng/domain-internal.hpp>
32 #include <lttng/event-internal.hpp>
33
34 #if (LTTNG_SYMBOL_NAME_LEN == 256)
35 #define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
36 #endif
37
38 static int opt_event_type;
39 static const char *opt_loglevel;
40 static int opt_loglevel_type;
41 static int opt_kernel;
42 static char *opt_session_name;
43 static int opt_userspace;
44 static int opt_jul;
45 static int opt_log4j;
46 static int opt_python;
47 static int opt_enable_all;
48 static char *opt_probe;
49 static char *opt_userspace_probe;
50 static char *opt_function;
51 static char *opt_channel_name;
52 static char *opt_filter;
53 static char *opt_exclude;
54
55 #ifdef LTTNG_EMBED_HELP
56 static const char help_msg[] =
57 #include <lttng-enable-event.1.h>
58 ;
59 #endif
60
61 enum {
62 OPT_HELP = 1,
63 OPT_TRACEPOINT,
64 OPT_PROBE,
65 OPT_USERSPACE_PROBE,
66 OPT_FUNCTION,
67 OPT_SYSCALL,
68 OPT_USERSPACE,
69 OPT_LOGLEVEL,
70 OPT_LOGLEVEL_ONLY,
71 OPT_LIST_OPTIONS,
72 OPT_FILTER,
73 OPT_EXCLUDE,
74 };
75
76 static struct lttng_handle *handle;
77 static struct mi_writer *writer;
78
79 static struct poptOption long_options[] = {
80 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
81 { "help", 'h', POPT_ARG_NONE, nullptr, OPT_HELP, nullptr, nullptr },
82 { "session", 's', POPT_ARG_STRING, &opt_session_name, 0, nullptr, nullptr },
83 { "all", 'a', POPT_ARG_VAL, &opt_enable_all, 1, nullptr, nullptr },
84 { "channel", 'c', POPT_ARG_STRING, &opt_channel_name, 0, nullptr, nullptr },
85 { "kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, nullptr, nullptr },
86 { "userspace", 'u', POPT_ARG_NONE, nullptr, OPT_USERSPACE, nullptr, nullptr },
87 { "jul", 'j', POPT_ARG_VAL, &opt_jul, 1, nullptr, nullptr },
88 { "log4j", 'l', POPT_ARG_VAL, &opt_log4j, 1, nullptr, nullptr },
89 { "python", 'p', POPT_ARG_VAL, &opt_python, 1, nullptr, nullptr },
90 { "tracepoint", 0, POPT_ARG_NONE, nullptr, OPT_TRACEPOINT, nullptr, nullptr },
91 { "probe", 0, POPT_ARG_STRING, &opt_probe, OPT_PROBE, nullptr, nullptr },
92 { "userspace-probe",
93 0,
94 POPT_ARG_STRING,
95 &opt_userspace_probe,
96 OPT_USERSPACE_PROBE,
97 nullptr,
98 nullptr },
99 { "function", 0, POPT_ARG_STRING, &opt_function, OPT_FUNCTION, nullptr, nullptr },
100 { "syscall", 0, POPT_ARG_NONE, nullptr, OPT_SYSCALL, nullptr, nullptr },
101 { "loglevel", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL, nullptr, nullptr },
102 { "loglevel-only", 0, POPT_ARG_STRING, nullptr, OPT_LOGLEVEL_ONLY, nullptr, nullptr },
103 { "list-options", 0, POPT_ARG_NONE, nullptr, OPT_LIST_OPTIONS, nullptr, nullptr },
104 { "filter", 'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, nullptr, nullptr },
105 { "exclude", 'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, nullptr, nullptr },
106 { nullptr, 0, 0, nullptr, 0, nullptr, nullptr }
107 };
108
109 /*
110 * Parse probe options.
111 */
112 static int parse_probe_opts(struct lttng_event *ev, char *opt)
113 {
114 int ret = CMD_SUCCESS;
115 int match;
116 char s_hex[19];
117 #define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18" /* 18 is (19 - 1) (\0 is extra) */
118 char name[LTTNG_SYMBOL_NAME_LEN];
119
120 if (opt == nullptr) {
121 ret = CMD_ERROR;
122 goto end;
123 }
124
125 /* Check for symbol+offset */
126 match = sscanf(opt,
127 "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
128 "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s",
129 name,
130 s_hex);
131 if (match == 2) {
132 strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
133 ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
134 DBG("probe symbol %s", ev->attr.probe.symbol_name);
135 if (*s_hex == '\0') {
136 ERR("Invalid probe offset %s", s_hex);
137 ret = CMD_ERROR;
138 goto end;
139 }
140 ev->attr.probe.offset = strtoull(s_hex, nullptr, 0);
141 DBG("probe offset %" PRIu64, ev->attr.probe.offset);
142 ev->attr.probe.addr = 0;
143 goto end;
144 }
145
146 /* Check for symbol */
147 if (isalpha(name[0]) || name[0] == '_') {
148 match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s", name);
149 if (match == 1) {
150 strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
151 ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
152 DBG("probe symbol %s", ev->attr.probe.symbol_name);
153 ev->attr.probe.offset = 0;
154 DBG("probe offset %" PRIu64, ev->attr.probe.offset);
155 ev->attr.probe.addr = 0;
156 goto end;
157 }
158 }
159
160 /* Check for address */
161 match = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex);
162 if (match > 0) {
163 /*
164 * Return an error if the first character of the tentative
165 * address is NULL or not a digit. It can be "0" if the address
166 * is in hexadecimal and can be 1 to 9 if it's in decimal.
167 */
168 if (*s_hex == '\0' || !isdigit(*s_hex)) {
169 ERR("Invalid probe description %s", s_hex);
170 ret = CMD_ERROR;
171 goto end;
172 }
173 ev->attr.probe.addr = strtoull(s_hex, nullptr, 0);
174 DBG("probe addr %" PRIu64, ev->attr.probe.addr);
175 ev->attr.probe.offset = 0;
176 memset(ev->attr.probe.symbol_name, 0, LTTNG_SYMBOL_NAME_LEN);
177 goto end;
178 }
179
180 /* No match */
181 ret = CMD_ERROR;
182
183 end:
184 return ret;
185 }
186
187 static const char *print_channel_name(const char *name)
188 {
189 return name ?: DEFAULT_CHANNEL_NAME;
190 }
191
192 static const char *print_raw_channel_name(const char *name)
193 {
194 return name ?: "<default>";
195 }
196
197 /*
198 * Mi print exlcusion list
199 */
200 static int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
201 {
202 int ret;
203 size_t i;
204 const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
205
206 LTTNG_ASSERT(writer);
207
208 if (count == 0) {
209 ret = 0;
210 goto end;
211 }
212
213 ret = mi_lttng_writer_open_element(writer, config_element_exclusions);
214 if (ret) {
215 goto end;
216 }
217
218 for (i = 0; i < count; i++) {
219 const char *exclusion =
220 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
221
222 ret = mi_lttng_writer_write_element_string(
223 writer, config_element_exclusion, exclusion);
224 if (ret) {
225 goto end;
226 }
227 }
228
229 /* Close exclusions element */
230 ret = mi_lttng_writer_close_element(writer);
231
232 end:
233 return ret;
234 }
235
236 /*
237 * Return allocated string for pretty-printing exclusion names.
238 */
239 static char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
240 {
241 int length = 0;
242 size_t i;
243 const char preamble[] = " excluding ";
244 char *ret;
245 const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
246
247 if (count == 0) {
248 return strdup("");
249 }
250
251 /* Calculate total required length. */
252 for (i = 0; i < count; i++) {
253 const char *exclusion =
254 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
255
256 length += strlen(exclusion) + 4;
257 }
258
259 length += sizeof(preamble);
260 ret = calloc<char>(length);
261 if (!ret) {
262 return nullptr;
263 }
264
265 strncpy(ret, preamble, length);
266 for (i = 0; i < count; i++) {
267 const char *exclusion =
268 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
269
270 strcat(ret, "\"");
271 strcat(ret, exclusion);
272 strcat(ret, "\"");
273 if (i != count - 1) {
274 strcat(ret, ", ");
275 }
276 }
277
278 return ret;
279 }
280
281 static int check_exclusion_subsets(const char *event_name, const char *exclusion)
282 {
283 bool warn = false;
284 int ret = 0;
285 const char *e = event_name;
286 const char *x = exclusion;
287
288 /* Scan both the excluder and the event letter by letter */
289 while (true) {
290 if (*e == '\\') {
291 if (*x != *e) {
292 warn = true;
293 goto end;
294 }
295
296 e++;
297 x++;
298 goto cmp_chars;
299 }
300
301 if (*x == '*') {
302 /* Event is a subset of the excluder */
303 ERR("Event %s: %s excludes all events from %s",
304 event_name,
305 exclusion,
306 event_name);
307 goto error;
308 }
309
310 if (*e == '*') {
311 /*
312 * Reached the end of the event name before the
313 * end of the exclusion: this is valid.
314 */
315 goto end;
316 }
317
318 cmp_chars:
319 if (*x != *e) {
320 warn = true;
321 break;
322 }
323
324 x++;
325 e++;
326 }
327
328 goto end;
329
330 error:
331 ret = -1;
332
333 end:
334 if (warn) {
335 WARN("Event %s: %s does not exclude any events from %s",
336 event_name,
337 exclusion,
338 event_name);
339 }
340
341 return ret;
342 }
343
344 int validate_exclusion_list(const char *event_name,
345 const struct lttng_dynamic_pointer_array *exclusions)
346 {
347 int ret;
348
349 /* Event name must be a valid globbing pattern to allow exclusions. */
350 if (!strutils_is_star_glob_pattern(event_name)) {
351 ERR("Event %s: Exclusions can only be used with a globbing pattern", event_name);
352 goto error;
353 }
354
355 /*
356 * If the event name is a star-at-end only globbing pattern,
357 * then we can validate the individual exclusions. Otherwise
358 * all exclusions are passed to the session daemon.
359 */
360 if (strutils_is_star_at_the_end_only_glob_pattern(event_name)) {
361 size_t i, num_exclusions;
362
363 num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
364
365 for (i = 0; i < num_exclusions; i++) {
366 const char *exclusion =
367 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions,
368 i);
369
370 if (!strutils_is_star_glob_pattern(exclusion) ||
371 strutils_is_star_at_the_end_only_glob_pattern(exclusion)) {
372 ret = check_exclusion_subsets(event_name, exclusion);
373 if (ret) {
374 goto error;
375 }
376 }
377 }
378 }
379
380 ret = 0;
381 goto end;
382
383 error:
384 ret = -1;
385
386 end:
387 return ret;
388 }
389
390 static int create_exclusion_list_and_validate(const char *event_name,
391 const char *exclusions_arg,
392 struct lttng_dynamic_pointer_array *exclusions)
393 {
394 int ret = 0;
395
396 /* Split exclusions. */
397 ret = strutils_split(exclusions_arg, ',', true, exclusions);
398 if (ret < 0) {
399 goto error;
400 }
401
402 if (validate_exclusion_list(event_name, exclusions) != 0) {
403 goto error;
404 }
405
406 goto end;
407
408 error:
409 ret = -1;
410 lttng_dynamic_pointer_array_reset(exclusions);
411
412 end:
413 return ret;
414 }
415
416 static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions,
417 int *warn)
418 {
419 size_t i;
420 const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
421
422 for (i = 0; i < num_exclusions; i++) {
423 const char *const exclusion =
424 (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
425
426 if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
427 WARN("Event exclusion \"%s\" will be truncated", exclusion);
428 *warn = 1;
429 }
430 }
431 }
432
433 /*
434 * Enabling event using the lttng API.
435 * Note: in case of error only the last error code will be return.
436 */
437 static int enable_events(char *session_name, char *event_list)
438 {
439 int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
440 int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1;
441 char *event_name, *channel_name = nullptr;
442 struct lttng_event *ev;
443 struct lttng_domain dom = {};
444 struct lttng_dynamic_pointer_array exclusions;
445 struct lttng_userspace_probe_location *uprobe_loc = nullptr;
446
447 lttng_dynamic_pointer_array_init(&exclusions, nullptr);
448
449 ev = lttng_event_create();
450 if (!ev) {
451 ret = CMD_ERROR;
452 goto error;
453 }
454
455 if (opt_kernel) {
456 if (opt_loglevel) {
457 WARN("Kernel loglevels are not supported.");
458 }
459 }
460
461 /* Create lttng domain */
462 if (opt_kernel) {
463 dom.type = LTTNG_DOMAIN_KERNEL;
464 dom.buf_type = LTTNG_BUFFER_GLOBAL;
465 } else if (opt_userspace) {
466 dom.type = LTTNG_DOMAIN_UST;
467 /* Default. */
468 dom.buf_type = LTTNG_BUFFER_PER_UID;
469 } else if (opt_jul) {
470 dom.type = LTTNG_DOMAIN_JUL;
471 /* Default. */
472 dom.buf_type = LTTNG_BUFFER_PER_UID;
473 } else if (opt_log4j) {
474 dom.type = LTTNG_DOMAIN_LOG4J;
475 /* Default. */
476 dom.buf_type = LTTNG_BUFFER_PER_UID;
477 } else if (opt_python) {
478 dom.type = LTTNG_DOMAIN_PYTHON;
479 /* Default. */
480 dom.buf_type = LTTNG_BUFFER_PER_UID;
481 } else {
482 /* Checked by the caller. */
483 abort();
484 }
485
486 if (opt_exclude) {
487 switch (dom.type) {
488 case LTTNG_DOMAIN_KERNEL:
489 case LTTNG_DOMAIN_JUL:
490 case LTTNG_DOMAIN_LOG4J:
491 case LTTNG_DOMAIN_PYTHON:
492 ERR("Event name exclusions are not yet implemented for %s events",
493 lttng_domain_type_str(dom.type));
494 ret = CMD_ERROR;
495 goto error;
496 case LTTNG_DOMAIN_UST:
497 /* Exclusions supported */
498 break;
499 default:
500 abort();
501 }
502 }
503
504 /*
505 * Adding a filter to a probe, function or userspace-probe would be
506 * denied by the kernel tracer as it's not supported at the moment. We
507 * do an early check here to warn the user.
508 */
509 if (opt_filter && opt_kernel) {
510 switch (opt_event_type) {
511 case LTTNG_EVENT_ALL:
512 case LTTNG_EVENT_TRACEPOINT:
513 case LTTNG_EVENT_SYSCALL:
514 break;
515 case LTTNG_EVENT_PROBE:
516 case LTTNG_EVENT_USERSPACE_PROBE:
517 case LTTNG_EVENT_FUNCTION:
518 ERR("Filter expressions are not supported for %s events",
519 get_event_type_str((lttng_event_type) opt_event_type));
520 ret = CMD_ERROR;
521 goto error;
522 default:
523 ret = CMD_UNDEFINED;
524 goto error;
525 }
526 }
527
528 channel_name = opt_channel_name;
529
530 handle = lttng_create_handle(session_name, &dom);
531 if (handle == nullptr) {
532 ret = -1;
533 goto error;
534 }
535
536 /* Prepare Mi */
537 if (lttng_opt_mi) {
538 /* Open a events element */
539 ret = mi_lttng_writer_open_element(writer, config_element_events);
540 if (ret) {
541 ret = CMD_ERROR;
542 goto error;
543 }
544 }
545
546 if (opt_enable_all) {
547 /* Default setup for enable all */
548 if (opt_kernel) {
549 ev->type = (lttng_event_type) opt_event_type;
550 strcpy(ev->name, "*");
551 /* kernel loglevels not implemented */
552 ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
553 } else {
554 ev->type = LTTNG_EVENT_TRACEPOINT;
555 strcpy(ev->name, "*");
556 ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
557 if (opt_loglevel) {
558 int name_search_ret;
559
560 LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
561
562 if (opt_userspace) {
563 enum lttng_loglevel loglevel;
564
565 name_search_ret =
566 loglevel_name_to_value(opt_loglevel, &loglevel);
567 ev->loglevel = (int) loglevel;
568 } else if (opt_jul) {
569 enum lttng_loglevel_jul loglevel;
570
571 name_search_ret =
572 loglevel_jul_name_to_value(opt_loglevel, &loglevel);
573 ev->loglevel = (int) loglevel;
574 } else if (opt_log4j) {
575 enum lttng_loglevel_log4j loglevel;
576
577 name_search_ret = loglevel_log4j_name_to_value(opt_loglevel,
578 &loglevel);
579 ev->loglevel = (int) loglevel;
580 } else {
581 /* python domain. */
582 enum lttng_loglevel_python loglevel;
583
584 name_search_ret = loglevel_python_name_to_value(
585 opt_loglevel, &loglevel);
586 ev->loglevel = (int) loglevel;
587 }
588
589 if (name_search_ret == -1) {
590 ERR("Unknown loglevel %s", opt_loglevel);
591 ret = -LTTNG_ERR_INVALID;
592 goto error;
593 }
594 } else {
595 LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
596 if (opt_userspace) {
597 ev->loglevel = -1;
598 } else if (opt_jul) {
599 ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
600 } else if (opt_log4j) {
601 ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
602 } else if (opt_python) {
603 ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
604 }
605 }
606 }
607
608 if (opt_exclude) {
609 ret = create_exclusion_list_and_validate("*", opt_exclude, &exclusions);
610 if (ret) {
611 ret = CMD_ERROR;
612 goto error;
613 }
614
615 ev->exclusion = 1;
616 warn_on_truncated_exclusion_names(&exclusions, &warn);
617 }
618 if (!opt_filter) {
619 ret = lttng_enable_event_with_exclusions(
620 handle,
621 ev,
622 channel_name,
623 nullptr,
624 lttng_dynamic_pointer_array_get_count(&exclusions),
625 (char **) exclusions.array.buffer.data);
626 if (ret < 0) {
627 switch (-ret) {
628 case LTTNG_ERR_KERN_EVENT_EXIST:
629 WARN("Kernel events already enabled (channel %s, session %s)",
630 print_channel_name(channel_name),
631 session_name);
632 warn = 1;
633 break;
634 case LTTNG_ERR_TRACE_ALREADY_STARTED:
635 {
636 const char *msg =
637 "The command tried to enable an event in a new domain for a session that has already been started once.";
638 ERR("Events: %s (channel %s, session %s)",
639 msg,
640 print_channel_name(channel_name),
641 session_name);
642 error = 1;
643 break;
644 }
645 default:
646 ERR("Events: %s (channel %s, session %s)",
647 lttng_strerror(ret),
648 ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
649 print_raw_channel_name(channel_name) :
650 print_channel_name(channel_name),
651 session_name);
652 error = 1;
653 break;
654 }
655 goto end;
656 }
657
658 switch (opt_event_type) {
659 case LTTNG_EVENT_TRACEPOINT:
660 if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
661 char *exclusion_string = print_exclusions(&exclusions);
662
663 if (!exclusion_string) {
664 PERROR("Cannot allocate exclusion_string");
665 error = 1;
666 goto end;
667 }
668 MSG("All %s tracepoints%s are enabled in channel %s for loglevel %s",
669 lttng_domain_type_str(dom.type),
670 exclusion_string,
671 print_channel_name(channel_name),
672 opt_loglevel);
673 free(exclusion_string);
674 } else {
675 char *exclusion_string = print_exclusions(&exclusions);
676
677 if (!exclusion_string) {
678 PERROR("Cannot allocate exclusion_string");
679 error = 1;
680 goto end;
681 }
682 MSG("All %s tracepoints%s are enabled in channel %s",
683 lttng_domain_type_str(dom.type),
684 exclusion_string,
685 print_channel_name(channel_name));
686 free(exclusion_string);
687 }
688 break;
689 case LTTNG_EVENT_SYSCALL:
690 if (opt_kernel) {
691 MSG("All %s system calls are enabled in channel %s",
692 lttng_domain_type_str(dom.type),
693 print_channel_name(channel_name));
694 }
695 break;
696 case LTTNG_EVENT_ALL:
697 if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
698 char *exclusion_string = print_exclusions(&exclusions);
699
700 if (!exclusion_string) {
701 PERROR("Cannot allocate exclusion_string");
702 error = 1;
703 goto end;
704 }
705 MSG("All %s events%s are enabled in channel %s for loglevel %s",
706 lttng_domain_type_str(dom.type),
707 exclusion_string,
708 print_channel_name(channel_name),
709 opt_loglevel);
710 free(exclusion_string);
711 } else {
712 char *exclusion_string = print_exclusions(&exclusions);
713
714 if (!exclusion_string) {
715 PERROR("Cannot allocate exclusion_string");
716 error = 1;
717 goto end;
718 }
719 MSG("All %s events%s are enabled in channel %s",
720 lttng_domain_type_str(dom.type),
721 exclusion_string,
722 print_channel_name(channel_name));
723 free(exclusion_string);
724 }
725 break;
726 default:
727 /*
728 * We should not be here since lttng_enable_event should have
729 * failed on the event type.
730 */
731 goto error;
732 }
733 }
734
735 if (opt_filter) {
736 command_ret = lttng_enable_event_with_exclusions(
737 handle,
738 ev,
739 channel_name,
740 opt_filter,
741 lttng_dynamic_pointer_array_get_count(&exclusions),
742 (char **) exclusions.array.buffer.data);
743 if (command_ret < 0) {
744 switch (-command_ret) {
745 case LTTNG_ERR_FILTER_EXIST:
746 WARN("Filter on all events is already enabled"
747 " (channel %s, session %s)",
748 print_channel_name(channel_name),
749 session_name);
750 warn = 1;
751 break;
752 case LTTNG_ERR_TRACE_ALREADY_STARTED:
753 {
754 const char *msg =
755 "The command tried to enable an event in a new domain for a session that has already been started once.";
756 ERR("All events: %s (channel %s, session %s, filter \'%s\')",
757 msg,
758 print_channel_name(channel_name),
759 session_name,
760 opt_filter);
761 error = 1;
762 break;
763 }
764 default:
765 ERR("All events: %s (channel %s, session %s, filter \'%s\')",
766 lttng_strerror(command_ret),
767 command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
768 print_raw_channel_name(channel_name) :
769 print_channel_name(channel_name),
770 session_name,
771 opt_filter);
772 error = 1;
773 break;
774 }
775 error_holder = command_ret;
776 } else {
777 ev->filter = 1;
778 MSG("Filter '%s' successfully set", opt_filter);
779 }
780 }
781
782 if (lttng_opt_mi) {
783 /* The wildcard * is used for kernel and ust domain to
784 * represent ALL. We copy * in event name to force the wildcard use
785 * for kernel domain
786 *
787 * Note: this is strictly for semantic and printing while in
788 * machine interface mode.
789 */
790 strcpy(ev->name, "*");
791
792 /* If we reach here the events are enabled */
793 if (!error && !warn) {
794 ev->enabled = 1;
795 } else {
796 ev->enabled = 0;
797 success = 0;
798 }
799 ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
800 if (ret) {
801 ret = CMD_ERROR;
802 goto error;
803 }
804
805 /* print exclusion */
806 ret = mi_print_exclusion(&exclusions);
807 if (ret) {
808 ret = CMD_ERROR;
809 goto error;
810 }
811
812 /* Success ? */
813 ret = mi_lttng_writer_write_element_bool(
814 writer, mi_lttng_element_command_success, success);
815 if (ret) {
816 ret = CMD_ERROR;
817 goto error;
818 }
819
820 /* Close event element */
821 ret = mi_lttng_writer_close_element(writer);
822 if (ret) {
823 ret = CMD_ERROR;
824 goto error;
825 }
826 }
827
828 goto end;
829 }
830
831 /* Strip event list */
832 event_name = strtok(event_list, ",");
833 while (event_name != nullptr) {
834 /* Copy name and type of the event */
835 strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
836 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
837 ev->type = (lttng_event_type) opt_event_type;
838
839 /* Kernel tracer action */
840 if (opt_kernel) {
841 DBG("Enabling kernel event %s for channel %s",
842 event_name,
843 print_channel_name(channel_name));
844
845 switch (opt_event_type) {
846 case LTTNG_EVENT_ALL: /* Enable tracepoints and syscalls */
847 /* If event name differs from *, select tracepoint. */
848 if (strcmp(ev->name, "*") != 0) {
849 ev->type = LTTNG_EVENT_TRACEPOINT;
850 }
851 break;
852 case LTTNG_EVENT_TRACEPOINT:
853 break;
854 case LTTNG_EVENT_PROBE:
855 ret = parse_probe_opts(ev, opt_probe);
856 if (ret) {
857 ERR("Unable to parse probe options");
858 ret = CMD_ERROR;
859 goto error;
860 }
861 break;
862 case LTTNG_EVENT_USERSPACE_PROBE:
863 LTTNG_ASSERT(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
864
865 ret = parse_userspace_probe_opts(opt_userspace_probe, &uprobe_loc);
866 if (ret) {
867 switch (ret) {
868 case CMD_UNSUPPORTED:
869 /*
870 * Error message describing
871 * what is not supported was
872 * printed in the function.
873 */
874 break;
875 case CMD_ERROR:
876 default:
877 ERR("Unable to parse userspace probe options");
878 break;
879 }
880 goto error;
881 }
882
883 ret = lttng_event_set_userspace_probe_location(ev, uprobe_loc);
884 if (ret) {
885 WARN("Failed to set probe location on event");
886 ret = CMD_ERROR;
887 goto error;
888 }
889
890 /* Ownership of the uprobe location was transferred to the event. */
891 uprobe_loc = nullptr;
892 break;
893 case LTTNG_EVENT_FUNCTION:
894 ret = parse_probe_opts(ev, opt_function);
895 if (ret) {
896 ERR("Unable to parse function probe options");
897 ret = CMD_ERROR;
898 goto error;
899 }
900 break;
901 case LTTNG_EVENT_SYSCALL:
902 ev->type = LTTNG_EVENT_SYSCALL;
903 break;
904 default:
905 ret = CMD_UNDEFINED;
906 goto error;
907 }
908
909 /* kernel loglevels not implemented */
910 ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
911 } else if (opt_userspace) { /* User-space tracer action */
912 DBG("Enabling UST event %s for channel %s, loglevel %s",
913 event_name,
914 print_channel_name(channel_name),
915 opt_loglevel ?: "<all>");
916
917 switch (opt_event_type) {
918 case LTTNG_EVENT_ALL: /* Default behavior is tracepoint */
919 /* Fall-through */
920 case LTTNG_EVENT_TRACEPOINT:
921 /* Copy name and type of the event */
922 ev->type = LTTNG_EVENT_TRACEPOINT;
923 strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
924 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
925 break;
926 case LTTNG_EVENT_PROBE:
927 case LTTNG_EVENT_FUNCTION:
928 case LTTNG_EVENT_SYSCALL:
929 case LTTNG_EVENT_USERSPACE_PROBE:
930 default:
931 ERR("Event type not available for user-space tracing");
932 ret = CMD_UNSUPPORTED;
933 goto error;
934 }
935
936 if (opt_exclude) {
937 ev->exclusion = 1;
938 if (opt_event_type != LTTNG_EVENT_ALL &&
939 opt_event_type != LTTNG_EVENT_TRACEPOINT) {
940 ERR("Exclusion option can only be used with tracepoint events");
941 ret = CMD_ERROR;
942 goto error;
943 }
944 /* Free previously allocated items. */
945 lttng_dynamic_pointer_array_reset(&exclusions);
946 ret = create_exclusion_list_and_validate(
947 event_name, opt_exclude, &exclusions);
948 if (ret) {
949 ret = CMD_ERROR;
950 goto error;
951 }
952
953 warn_on_truncated_exclusion_names(&exclusions, &warn);
954 }
955
956 ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
957 if (opt_loglevel) {
958 enum lttng_loglevel loglevel;
959 const int name_search_ret =
960 loglevel_name_to_value(opt_loglevel, &loglevel);
961
962 if (name_search_ret == -1) {
963 ERR("Unknown loglevel %s", opt_loglevel);
964 ret = -LTTNG_ERR_INVALID;
965 goto error;
966 }
967
968 ev->loglevel = (int) loglevel;
969 } else {
970 ev->loglevel = -1;
971 }
972 } else if (opt_jul || opt_log4j || opt_python) {
973 if (opt_event_type != LTTNG_EVENT_ALL &&
974 opt_event_type != LTTNG_EVENT_TRACEPOINT) {
975 ERR("Event type not supported for domain.");
976 ret = CMD_UNSUPPORTED;
977 goto error;
978 }
979
980 ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
981 if (opt_loglevel) {
982 int name_search_ret;
983
984 if (opt_jul) {
985 enum lttng_loglevel_jul loglevel;
986
987 name_search_ret =
988 loglevel_jul_name_to_value(opt_loglevel, &loglevel);
989 ev->loglevel = (int) loglevel;
990 } else if (opt_log4j) {
991 enum lttng_loglevel_log4j loglevel;
992
993 name_search_ret = loglevel_log4j_name_to_value(opt_loglevel,
994 &loglevel);
995 ev->loglevel = (int) loglevel;
996 } else {
997 /* python domain. */
998 enum lttng_loglevel_python loglevel;
999
1000 name_search_ret = loglevel_python_name_to_value(
1001 opt_loglevel, &loglevel);
1002 ev->loglevel = (int) loglevel;
1003 }
1004
1005 if (name_search_ret) {
1006 ERR("Unknown loglevel %s", opt_loglevel);
1007 ret = -LTTNG_ERR_INVALID;
1008 goto error;
1009 }
1010 } else {
1011 if (opt_jul) {
1012 ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
1013 } else if (opt_log4j) {
1014 ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
1015 } else if (opt_python) {
1016 ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
1017 }
1018 }
1019 ev->type = LTTNG_EVENT_TRACEPOINT;
1020 strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
1021 ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
1022 } else {
1023 abort();
1024 }
1025
1026 if (!opt_filter) {
1027 char *exclusion_string;
1028
1029 command_ret = lttng_enable_event_with_exclusions(
1030 handle,
1031 ev,
1032 channel_name,
1033 nullptr,
1034 lttng_dynamic_pointer_array_get_count(&exclusions),
1035 (char **) exclusions.array.buffer.data);
1036 exclusion_string = print_exclusions(&exclusions);
1037 if (!exclusion_string) {
1038 PERROR("Cannot allocate exclusion_string");
1039 error = 1;
1040 goto end;
1041 }
1042 if (command_ret < 0) {
1043 /* Turn ret to positive value to handle the positive error code */
1044 switch (-command_ret) {
1045 case LTTNG_ERR_KERN_EVENT_EXIST:
1046 WARN("Kernel event %s%s already enabled (channel %s, session %s)",
1047 event_name,
1048 exclusion_string,
1049 print_channel_name(channel_name),
1050 session_name);
1051 warn = 1;
1052 break;
1053 case LTTNG_ERR_TRACE_ALREADY_STARTED:
1054 {
1055 const char *msg =
1056 "The command tried to enable an event in a new domain for a session that has already been started once.";
1057 ERR("Event %s%s: %s (channel %s, session %s)",
1058 event_name,
1059 exclusion_string,
1060 msg,
1061 print_channel_name(channel_name),
1062 session_name);
1063 error = 1;
1064 break;
1065 }
1066 case LTTNG_ERR_SDT_PROBE_SEMAPHORE:
1067 ERR("SDT probes %s guarded by semaphores are not supported (channel %s, session %s)",
1068 event_name,
1069 print_channel_name(channel_name),
1070 session_name);
1071 error = 1;
1072 break;
1073 default:
1074 ERR("Event %s%s: %s (channel %s, session %s)",
1075 event_name,
1076 exclusion_string,
1077 lttng_strerror(command_ret),
1078 command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
1079 print_raw_channel_name(channel_name) :
1080 print_channel_name(channel_name),
1081 session_name);
1082 error = 1;
1083 break;
1084 }
1085 error_holder = command_ret;
1086 } else {
1087 switch (dom.type) {
1088 case LTTNG_DOMAIN_KERNEL:
1089 case LTTNG_DOMAIN_UST:
1090 MSG("%s event %s%s created in channel %s",
1091 lttng_domain_type_str(dom.type),
1092 event_name,
1093 exclusion_string,
1094 print_channel_name(channel_name));
1095 break;
1096 case LTTNG_DOMAIN_JUL:
1097 case LTTNG_DOMAIN_LOG4J:
1098 case LTTNG_DOMAIN_PYTHON:
1099 /*
1100 * Don't print the default channel
1101 * name for agent domains.
1102 */
1103 MSG("%s event %s%s enabled",
1104 lttng_domain_type_str(dom.type),
1105 event_name,
1106 exclusion_string);
1107 break;
1108 default:
1109 abort();
1110 }
1111 }
1112 free(exclusion_string);
1113 }
1114
1115 if (opt_filter) {
1116 char *exclusion_string;
1117
1118 /* Filter present */
1119 ev->filter = 1;
1120
1121 command_ret = lttng_enable_event_with_exclusions(
1122 handle,
1123 ev,
1124 channel_name,
1125 opt_filter,
1126 lttng_dynamic_pointer_array_get_count(&exclusions),
1127 (char **) exclusions.array.buffer.data);
1128 exclusion_string = print_exclusions(&exclusions);
1129 if (!exclusion_string) {
1130 PERROR("Cannot allocate exclusion_string");
1131 error = 1;
1132 goto end;
1133 }
1134 if (command_ret < 0) {
1135 switch (-command_ret) {
1136 case LTTNG_ERR_FILTER_EXIST:
1137 WARN("Filter on event %s%s is already enabled"
1138 " (channel %s, session %s)",
1139 event_name,
1140 exclusion_string,
1141 print_channel_name(channel_name),
1142 session_name);
1143 warn = 1;
1144 break;
1145 case LTTNG_ERR_TRACE_ALREADY_STARTED:
1146 {
1147 const char *msg =
1148 "The command tried to enable an event in a new domain for a session that has already been started once.";
1149 ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')",
1150 ev->name,
1151 exclusion_string,
1152 msg,
1153 print_channel_name(channel_name),
1154 session_name,
1155 opt_filter);
1156 error = 1;
1157 break;
1158 }
1159 default:
1160 ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')",
1161 ev->name,
1162 exclusion_string,
1163 lttng_strerror(command_ret),
1164 command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME ?
1165 print_raw_channel_name(channel_name) :
1166 print_channel_name(channel_name),
1167 session_name,
1168 opt_filter);
1169 error = 1;
1170 break;
1171 }
1172 error_holder = command_ret;
1173
1174 } else {
1175 MSG("Event %s%s: Filter '%s' successfully set",
1176 event_name,
1177 exclusion_string,
1178 opt_filter);
1179 }
1180 free(exclusion_string);
1181 }
1182
1183 if (lttng_opt_mi) {
1184 if (command_ret) {
1185 success = 0;
1186 ev->enabled = 0;
1187 } else {
1188 ev->enabled = 1;
1189 }
1190
1191 ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
1192 if (ret) {
1193 ret = CMD_ERROR;
1194 goto error;
1195 }
1196
1197 /* print exclusion */
1198 ret = mi_print_exclusion(&exclusions);
1199 if (ret) {
1200 ret = CMD_ERROR;
1201 goto error;
1202 }
1203
1204 /* Success ? */
1205 ret = mi_lttng_writer_write_element_bool(
1206 writer, mi_lttng_element_command_success, success);
1207 if (ret) {
1208 ret = CMD_ERROR;
1209 goto end;
1210 }
1211
1212 /* Close event element */
1213 ret = mi_lttng_writer_close_element(writer);
1214 if (ret) {
1215 ret = CMD_ERROR;
1216 goto end;
1217 }
1218 }
1219
1220 /* Next event */
1221 event_name = strtok(nullptr, ",");
1222 /* Reset warn, error and success */
1223 success = 1;
1224 }
1225
1226 end:
1227 /* Close Mi */
1228 if (lttng_opt_mi) {
1229 /* Close events element */
1230 ret = mi_lttng_writer_close_element(writer);
1231 if (ret) {
1232 ret = CMD_ERROR;
1233 goto error;
1234 }
1235 }
1236 error:
1237 if (warn) {
1238 ret = CMD_WARNING;
1239 }
1240 if (error) {
1241 ret = CMD_ERROR;
1242 }
1243 lttng_destroy_handle(handle);
1244 lttng_dynamic_pointer_array_reset(&exclusions);
1245 lttng_userspace_probe_location_destroy(uprobe_loc);
1246
1247 /* Overwrite ret with error_holder if there was an actual error with
1248 * enabling an event.
1249 */
1250 ret = error_holder ? error_holder : ret;
1251
1252 lttng_event_destroy(ev);
1253 return ret;
1254 }
1255
1256 /*
1257 * Add event to trace session
1258 */
1259 int cmd_enable_events(int argc, const char **argv)
1260 {
1261 int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
1262 static poptContext pc;
1263 char *session_name = nullptr;
1264 char *event_list = nullptr;
1265 const char *arg_event_list = nullptr;
1266 const char *leftover = nullptr;
1267 int event_type = -1;
1268
1269 pc = poptGetContext(nullptr, argc, argv, long_options, 0);
1270 poptReadDefaultConfig(pc, 0);
1271
1272 /* Default event type */
1273 opt_event_type = LTTNG_EVENT_ALL;
1274
1275 while ((opt = poptGetNextOpt(pc)) != -1) {
1276 switch (opt) {
1277 case OPT_HELP:
1278 SHOW_HELP();
1279 goto end;
1280 case OPT_TRACEPOINT:
1281 opt_event_type = LTTNG_EVENT_TRACEPOINT;
1282 break;
1283 case OPT_PROBE:
1284 opt_event_type = LTTNG_EVENT_PROBE;
1285 break;
1286 case OPT_USERSPACE_PROBE:
1287 opt_event_type = LTTNG_EVENT_USERSPACE_PROBE;
1288 break;
1289 case OPT_FUNCTION:
1290 opt_event_type = LTTNG_EVENT_FUNCTION;
1291 break;
1292 case OPT_SYSCALL:
1293 opt_event_type = LTTNG_EVENT_SYSCALL;
1294 break;
1295 case OPT_USERSPACE:
1296 opt_userspace = 1;
1297 break;
1298 case OPT_LOGLEVEL:
1299 opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
1300 opt_loglevel = poptGetOptArg(pc);
1301 break;
1302 case OPT_LOGLEVEL_ONLY:
1303 opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
1304 opt_loglevel = poptGetOptArg(pc);
1305 break;
1306 case OPT_LIST_OPTIONS:
1307 list_cmd_options(stdout, long_options);
1308 goto end;
1309 case OPT_FILTER:
1310 break;
1311 case OPT_EXCLUDE:
1312 break;
1313 default:
1314 ret = CMD_UNDEFINED;
1315 goto end;
1316 }
1317
1318 /* Validate event type. Multiple event type are not supported. */
1319 if (event_type == -1) {
1320 event_type = opt_event_type;
1321 } else {
1322 if (event_type != opt_event_type) {
1323 ERR("Multiple event type not supported.");
1324 ret = CMD_ERROR;
1325 goto end;
1326 }
1327 }
1328 }
1329
1330 ret = print_missing_or_multiple_domains(
1331 opt_kernel + opt_userspace + opt_jul + opt_log4j + opt_python, true);
1332 if (ret) {
1333 ret = CMD_ERROR;
1334 goto end;
1335 }
1336
1337 /* Mi check */
1338 if (lttng_opt_mi) {
1339 writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
1340 if (!writer) {
1341 ret = -LTTNG_ERR_NOMEM;
1342 goto end;
1343 }
1344
1345 /* Open command element */
1346 ret = mi_lttng_writer_command_open(writer, mi_lttng_element_command_enable_event);
1347 if (ret) {
1348 ret = CMD_ERROR;
1349 goto end;
1350 }
1351
1352 /* Open output element */
1353 ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_output);
1354 if (ret) {
1355 ret = CMD_ERROR;
1356 goto end;
1357 }
1358 }
1359
1360 arg_event_list = poptGetArg(pc);
1361 if (arg_event_list == nullptr && opt_enable_all == 0) {
1362 ERR("Missing event name(s).");
1363 ret = CMD_ERROR;
1364 goto end;
1365 }
1366
1367 if (opt_enable_all == 0) {
1368 event_list = strdup(arg_event_list);
1369 if (event_list == nullptr) {
1370 PERROR("Failed to copy event name(s)");
1371 ret = CMD_ERROR;
1372 goto end;
1373 }
1374 }
1375
1376 leftover = poptGetArg(pc);
1377 if (leftover) {
1378 ERR("Unknown argument: %s", leftover);
1379 ret = CMD_ERROR;
1380 goto end;
1381 }
1382
1383 if (!opt_session_name) {
1384 session_name = get_session_name();
1385 if (session_name == nullptr) {
1386 command_ret = CMD_ERROR;
1387 success = 0;
1388 goto mi_closing;
1389 }
1390 } else {
1391 session_name = opt_session_name;
1392 }
1393
1394 command_ret = enable_events(session_name, event_list);
1395 if (command_ret) {
1396 success = 0;
1397 goto mi_closing;
1398 }
1399
1400 mi_closing:
1401 /* Mi closing */
1402 if (lttng_opt_mi) {
1403 /* Close output element */
1404 ret = mi_lttng_writer_close_element(writer);
1405 if (ret) {
1406 ret = CMD_ERROR;
1407 goto end;
1408 }
1409
1410 ret = mi_lttng_writer_write_element_bool(
1411 writer, mi_lttng_element_command_success, success);
1412 if (ret) {
1413 ret = CMD_ERROR;
1414 goto end;
1415 }
1416
1417 /* Command element close */
1418 ret = mi_lttng_writer_command_close(writer);
1419 if (ret) {
1420 ret = CMD_ERROR;
1421 goto end;
1422 }
1423 }
1424
1425 end:
1426 /* Mi clean-up */
1427 if (writer && mi_lttng_writer_destroy(writer)) {
1428 /* Preserve original error code */
1429 ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
1430 }
1431
1432 if (opt_session_name == nullptr) {
1433 free(session_name);
1434 }
1435
1436 free(event_list);
1437
1438 /* Overwrite ret if an error occurred in enable_events */
1439 ret = command_ret ? command_ret : ret;
1440
1441 poptFreeContext(pc);
1442 return ret;
1443 }
This page took 0.09571 seconds and 4 git commands to generate.