lttng: enable-channel: move kernel tracer status check to util
[lttng-tools.git] / src / bin / lttng / utils.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 "command.hpp"
10 #include "conf.hpp"
11 #include "utils.hpp"
12
13 #include <common/defaults.hpp>
14 #include <common/error.hpp>
15 #include <common/exception.hpp>
16 #include <common/make-unique-wrapper.hpp>
17 #include <common/utils.hpp>
18
19 #include <arpa/inet.h>
20 #include <ctype.h>
21 #include <fnmatch.h>
22 #include <inttypes.h>
23 #include <iostream>
24 #include <limits.h>
25 #include <netinet/in.h>
26 #include <signal.h>
27 #include <stdlib.h>
28 #include <sys/socket.h>
29 #include <sys/types.h>
30 #include <unistd.h>
31
32 static const char *str_all = "ALL";
33 static const char *str_tracepoint = "Tracepoint";
34 static const char *str_syscall = "Syscall";
35 static const char *str_probe = "Probe";
36 static const char *str_userspace_probe = "Userspace Probe";
37 static const char *str_function = "Function";
38
39 static char *_get_session_name(int quiet)
40 {
41 const char *path;
42 char *session_name = nullptr;
43
44 /* Get path to config file */
45 path = utils_get_home_dir();
46 if (path == nullptr) {
47 goto error;
48 }
49
50 /* Get session name from config */
51 session_name = quiet ? config_read_session_name_quiet(path) :
52 config_read_session_name(path);
53 if (session_name == nullptr) {
54 goto error;
55 }
56
57 DBG2("Config file path found: %s", path);
58 DBG("Session name found: %s", session_name);
59 return session_name;
60
61 error:
62 return nullptr;
63 }
64
65 /*
66 * get_session_name
67 *
68 * Return allocated string with the session name found in the config
69 * directory.
70 */
71 char *get_session_name()
72 {
73 return _get_session_name(0);
74 }
75
76 /*
77 * get_session_name_quiet (no warnings/errors emitted)
78 *
79 * Return allocated string with the session name found in the config
80 * directory.
81 */
82 char *get_session_name_quiet()
83 {
84 return _get_session_name(1);
85 }
86
87 /*
88 * list_commands
89 *
90 * List commands line by line. This is mostly for bash auto completion and to
91 * avoid difficult parsing.
92 */
93 void list_commands(struct cmd_struct *commands, FILE *ofp)
94 {
95 int i = 0;
96 struct cmd_struct *cmd = nullptr;
97
98 cmd = &commands[i];
99 while (cmd->name != nullptr) {
100 fprintf(ofp, "%s\n", cmd->name);
101 i++;
102 cmd = &commands[i];
103 }
104 }
105
106 /*
107 * list_cmd_options
108 *
109 * Prints a simple list of the options available to a command. This is intended
110 * to be easily parsed for bash completion.
111 */
112 void list_cmd_options(FILE *ofp, struct poptOption *options)
113 {
114 int i;
115 struct poptOption *option = nullptr;
116
117 for (i = 0; options[i].longName != nullptr; i++) {
118 option = &options[i];
119
120 fprintf(ofp, "--%s\n", option->longName);
121
122 if (isprint(option->shortName)) {
123 fprintf(ofp, "-%c\n", option->shortName);
124 }
125 }
126 }
127
128 /*
129 * Same as list_cmd_options, but for options specified for argpar.
130 */
131 void list_cmd_options_argpar(FILE *ofp, const struct argpar_opt_descr *options)
132 {
133 int i;
134
135 for (i = 0; options[i].long_name != nullptr; i++) {
136 const struct argpar_opt_descr *option = &options[i];
137
138 fprintf(ofp, "--%s\n", option->long_name);
139
140 if (isprint(option->short_name)) {
141 fprintf(ofp, "-%c\n", option->short_name);
142 }
143 }
144 }
145
146 /*
147 * fls: returns the position of the most significant bit.
148 * Returns 0 if no bit is set, else returns the position of the most
149 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
150 */
151 #if defined(__i386) || defined(__x86_64)
152 static inline unsigned int fls_u32(uint32_t x)
153 {
154 int r;
155
156 asm("bsrl %1,%0\n\t"
157 "jnz 1f\n\t"
158 "movl $-1,%0\n\t"
159 "1:\n\t"
160 : "=r"(r)
161 : "rm"(x));
162 return r + 1;
163 }
164 #define HAS_FLS_U32
165 #endif
166
167 #if defined(__x86_64) && defined(__LP64__)
168 static inline unsigned int fls_u64(uint64_t x)
169 {
170 long r;
171
172 asm("bsrq %1,%0\n\t"
173 "jnz 1f\n\t"
174 "movq $-1,%0\n\t"
175 "1:\n\t"
176 : "=r"(r)
177 : "rm"(x));
178 return r + 1;
179 }
180 #define HAS_FLS_U64
181 #endif
182
183 #ifndef HAS_FLS_U64
184 static __attribute__((unused)) unsigned int fls_u64(uint64_t x)
185 {
186 unsigned int r = 64;
187
188 if (!x)
189 return 0;
190
191 if (!(x & 0xFFFFFFFF00000000ULL)) {
192 x <<= 32;
193 r -= 32;
194 }
195 if (!(x & 0xFFFF000000000000ULL)) {
196 x <<= 16;
197 r -= 16;
198 }
199 if (!(x & 0xFF00000000000000ULL)) {
200 x <<= 8;
201 r -= 8;
202 }
203 if (!(x & 0xF000000000000000ULL)) {
204 x <<= 4;
205 r -= 4;
206 }
207 if (!(x & 0xC000000000000000ULL)) {
208 x <<= 2;
209 r -= 2;
210 }
211 if (!(x & 0x8000000000000000ULL)) {
212 x <<= 1;
213 r -= 1;
214 }
215 return r;
216 }
217 #endif
218
219 #ifndef HAS_FLS_U32
220 static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
221 {
222 unsigned int r = 32;
223
224 if (!x)
225 return 0;
226 if (!(x & 0xFFFF0000U)) {
227 x <<= 16;
228 r -= 16;
229 }
230 if (!(x & 0xFF000000U)) {
231 x <<= 8;
232 r -= 8;
233 }
234 if (!(x & 0xF0000000U)) {
235 x <<= 4;
236 r -= 4;
237 }
238 if (!(x & 0xC0000000U)) {
239 x <<= 2;
240 r -= 2;
241 }
242 if (!(x & 0x80000000U)) {
243 x <<= 1;
244 r -= 1;
245 }
246 return r;
247 }
248 #endif
249
250 static unsigned int fls_ulong(unsigned long x)
251 {
252 #if (CAA_BITS_PER_LONG == 32)
253 return fls_u32(x);
254 #else
255 return fls_u64(x);
256 #endif
257 }
258
259 /*
260 * Return the minimum order for which x <= (1UL << order).
261 * Return -1 if x is 0.
262 */
263 int get_count_order_u32(uint32_t x)
264 {
265 if (!x)
266 return -1;
267
268 return fls_u32(x - 1);
269 }
270
271 /*
272 * Return the minimum order for which x <= (1UL << order).
273 * Return -1 if x is 0.
274 */
275 int get_count_order_u64(uint64_t x)
276 {
277 if (!x)
278 return -1;
279
280 return fls_u64(x - 1);
281 }
282
283 /*
284 * Return the minimum order for which x <= (1UL << order).
285 * Return -1 if x is 0.
286 */
287 int get_count_order_ulong(unsigned long x)
288 {
289 if (!x)
290 return -1;
291
292 return fls_ulong(x - 1);
293 }
294
295 const char *get_event_type_str(enum lttng_event_type type)
296 {
297 const char *str_event_type;
298
299 switch (type) {
300 case LTTNG_EVENT_ALL:
301 str_event_type = str_all;
302 break;
303 case LTTNG_EVENT_TRACEPOINT:
304 str_event_type = str_tracepoint;
305 break;
306 case LTTNG_EVENT_SYSCALL:
307 str_event_type = str_syscall;
308 break;
309 case LTTNG_EVENT_PROBE:
310 str_event_type = str_probe;
311 break;
312 case LTTNG_EVENT_USERSPACE_PROBE:
313 str_event_type = str_userspace_probe;
314 break;
315 case LTTNG_EVENT_FUNCTION:
316 str_event_type = str_function;
317 break;
318 default:
319 /* Should not have an unknown event type or else define it. */
320 abort();
321 }
322
323 return str_event_type;
324 }
325
326 /*
327 * Spawn a lttng relayd daemon by forking and execv.
328 */
329 int spawn_relayd(const char *pathname, int port)
330 {
331 int ret = 0;
332 pid_t pid;
333 char url[255];
334
335 if (!port) {
336 port = DEFAULT_NETWORK_VIEWER_PORT;
337 }
338
339 ret = snprintf(url, sizeof(url), "tcp://localhost:%d", port);
340 if (ret < 0) {
341 goto end;
342 }
343
344 MSG("Spawning a relayd daemon");
345 pid = fork();
346 if (pid == 0) {
347 /*
348 * Spawn session daemon and tell
349 * it to signal us when ready.
350 */
351 execlp(pathname, "lttng-relayd", "-L", url, NULL);
352 /* execlp only returns if error happened */
353 if (errno == ENOENT) {
354 ERR("No relayd found. Use --relayd-path.");
355 } else {
356 PERROR("execlp");
357 }
358 kill(getppid(), SIGTERM); /* wake parent */
359 exit(EXIT_FAILURE);
360 } else if (pid > 0) {
361 goto end;
362 } else {
363 PERROR("fork");
364 ret = -1;
365 goto end;
366 }
367
368 end:
369 return ret;
370 }
371
372 /*
373 * Check if relayd is alive.
374 *
375 * Return 1 if found else 0 if NOT found. Negative value on error.
376 */
377 int check_relayd()
378 {
379 int ret, fd;
380 struct sockaddr_in sin;
381
382 fd = socket(AF_INET, SOCK_STREAM, 0);
383 if (fd < 0) {
384 PERROR("socket check relayd");
385 ret = -1;
386 goto error_socket;
387 }
388
389 sin.sin_family = AF_INET;
390 sin.sin_port = htons(DEFAULT_NETWORK_VIEWER_PORT);
391 ret = inet_pton(sin.sin_family, "127.0.0.1", &sin.sin_addr);
392 if (ret < 1) {
393 PERROR("inet_pton check relayd");
394 ret = -1;
395 goto error;
396 }
397
398 /*
399 * A successful connect means the relayd exists thus returning 0 else a
400 * negative value means it does NOT exists.
401 */
402 ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
403 if (ret < 0) {
404 /* Not found. */
405 ret = 0;
406 } else {
407 /* Already spawned. */
408 ret = 1;
409 }
410
411 error:
412 if (close(fd) < 0) {
413 PERROR("close relayd fd");
414 }
415 error_socket:
416 return ret;
417 }
418
419 int print_missing_or_multiple_domains(unsigned int domain_count, bool include_agent_domains)
420 {
421 int ret = 0;
422
423 if (domain_count == 0) {
424 ERR("Please specify a domain (--kernel/--userspace%s).",
425 include_agent_domains ? "/--jul/--log4j/--python" : "");
426 ret = -1;
427 } else if (domain_count > 1) {
428 ERR("Only one domain must be specified.");
429 ret = -1;
430 }
431
432 return ret;
433 }
434
435 /*
436 * Get the discarded events and lost packet counts.
437 */
438 void print_session_stats(const char *session_name)
439 {
440 char *str;
441 const int ret = get_session_stats_str(session_name, &str);
442
443 if (ret >= 0 && str) {
444 MSG("%s", str);
445 free(str);
446 }
447 }
448
449 int get_session_stats_str(const char *session_name, char **out_str)
450 {
451 int count, nb_domains, domain_idx, channel_idx, session_idx, ret;
452 struct lttng_domain *domains = nullptr;
453 struct lttng_channel *channels = nullptr;
454 uint64_t discarded_events_total = 0, lost_packets_total = 0;
455 struct lttng_session *sessions = nullptr;
456 const struct lttng_session *selected_session = nullptr;
457 char *stats_str = nullptr;
458 bool print_discarded_events = false, print_lost_packets = false;
459
460 count = lttng_list_sessions(&sessions);
461 if (count < 1) {
462 ERR("Failed to retrieve session descriptions while printing session statistics.");
463 ret = -1;
464 goto end;
465 }
466
467 /* Identify the currently-selected sessions. */
468 for (session_idx = 0; session_idx < count; session_idx++) {
469 if (!strcmp(session_name, sessions[session_idx].name)) {
470 selected_session = &sessions[session_idx];
471 break;
472 }
473 }
474 if (!selected_session) {
475 ERR("Failed to retrieve session \"%s\" description while printing session statistics.",
476 session_name);
477 ret = -1;
478 goto end;
479 }
480
481 nb_domains = lttng_list_domains(session_name, &domains);
482 if (nb_domains < 0) {
483 ret = -1;
484 goto end;
485 }
486 for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) {
487 struct lttng_handle *handle =
488 lttng_create_handle(session_name, &domains[domain_idx]);
489
490 if (!handle) {
491 ERR("Failed to create session handle while printing session statistics.");
492 ret = -1;
493 goto end;
494 }
495
496 free(channels);
497 channels = nullptr;
498 count = lttng_list_channels(handle, &channels);
499 for (channel_idx = 0; channel_idx < count; channel_idx++) {
500 uint64_t discarded_events = 0, lost_packets = 0;
501 struct lttng_channel *channel = &channels[channel_idx];
502
503 ret = lttng_channel_get_discarded_event_count(channel, &discarded_events);
504 if (ret) {
505 ERR("Failed to retrieve discarded event count from channel %s",
506 channel->name);
507 }
508
509 ret = lttng_channel_get_lost_packet_count(channel, &lost_packets);
510 if (ret) {
511 ERR("Failed to retrieve lost packet count from channel %s",
512 channel->name);
513 }
514
515 discarded_events_total += discarded_events;
516 lost_packets_total += lost_packets;
517 }
518 lttng_destroy_handle(handle);
519 }
520
521 print_discarded_events = discarded_events_total > 0 && !selected_session->snapshot_mode;
522 print_lost_packets = lost_packets_total > 0 && !selected_session->snapshot_mode;
523
524 if (print_discarded_events && print_lost_packets) {
525 ret = asprintf(&stats_str,
526 "Warning: %" PRIu64 " events were discarded and %" PRIu64
527 " packets were lost, please refer to "
528 "the documentation on channel configuration.",
529 discarded_events_total,
530 lost_packets_total);
531 } else if (print_discarded_events) {
532 ret = asprintf(&stats_str,
533 "Warning: %" PRIu64 " events were discarded, please refer to "
534 "the documentation on channel configuration.",
535 discarded_events_total);
536 } else if (print_lost_packets) {
537 ret = asprintf(&stats_str,
538 "Warning: %" PRIu64 " packets were lost, please refer to "
539 "the documentation on channel configuration.",
540 lost_packets_total);
541 } else {
542 ret = 0;
543 }
544
545 if (ret < 0) {
546 ERR("Failed to format lost packet and discarded events statistics");
547 } else {
548 *out_str = stats_str;
549 ret = 0;
550 }
551 end:
552 free(sessions);
553 free(channels);
554 free(domains);
555 return ret;
556 }
557
558 int show_cmd_help(const char *cmd_name, const char *help_msg)
559 {
560 int ret;
561 char page_name[32];
562
563 ret = sprintf(page_name, "lttng-%s", cmd_name);
564 LTTNG_ASSERT(ret > 0 && ret < 32);
565 ret = utils_show_help(1, page_name, help_msg);
566 if (ret && !help_msg) {
567 ERR("Cannot view man page `lttng-%s(1)`", cmd_name);
568 perror("exec");
569 }
570
571 return ret;
572 }
573
574 int print_trace_archive_location(const struct lttng_trace_archive_location *location,
575 const char *session_name)
576 {
577 int ret = 0;
578 enum lttng_trace_archive_location_type location_type;
579 enum lttng_trace_archive_location_status status;
580 bool printed_location = false;
581
582 location_type = lttng_trace_archive_location_get_type(location);
583
584 _MSG("Trace chunk archive for session %s is now readable", session_name);
585 switch (location_type) {
586 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
587 {
588 const char *absolute_path;
589
590 status = lttng_trace_archive_location_local_get_absolute_path(location,
591 &absolute_path);
592 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
593 ret = -1;
594 goto end;
595 }
596 MSG(" at %s", absolute_path);
597 printed_location = true;
598 break;
599 }
600 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
601 {
602 uint16_t control_port, data_port;
603 const char *host, *relative_path, *protocol_str;
604 enum lttng_trace_archive_location_relay_protocol_type protocol;
605
606 /* Fetch all relay location parameters. */
607 status = lttng_trace_archive_location_relay_get_protocol_type(location, &protocol);
608 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
609 ret = -1;
610 goto end;
611 }
612
613 status = lttng_trace_archive_location_relay_get_host(location, &host);
614 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
615 ret = -1;
616 goto end;
617 }
618
619 status = lttng_trace_archive_location_relay_get_control_port(location,
620 &control_port);
621 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
622 ret = -1;
623 goto end;
624 }
625
626 status = lttng_trace_archive_location_relay_get_data_port(location, &data_port);
627 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
628 ret = -1;
629 goto end;
630 }
631
632 status = lttng_trace_archive_location_relay_get_relative_path(location,
633 &relative_path);
634 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
635 ret = -1;
636 goto end;
637 }
638
639 switch (protocol) {
640 case LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP:
641 protocol_str = "tcp";
642 break;
643 default:
644 protocol_str = "unknown";
645 break;
646 }
647
648 MSG(" on relay %s://%s/%s [control port %" PRIu16 ", data port %" PRIu16 "]",
649 protocol_str,
650 host,
651 relative_path,
652 control_port,
653 data_port);
654 printed_location = true;
655 break;
656 }
657 default:
658 break;
659 }
660 end:
661 if (!printed_location) {
662 MSG(" at an unknown location");
663 }
664 return ret;
665 }
666
667 namespace {
668 template <typename FilterFunctionType>
669 lttng::cli::session_list get_sessions(const FilterFunctionType& filter,
670 bool return_first_match_only = false)
671 {
672 lttng::cli::session_list list = []() {
673 int list_ret;
674 struct lttng_session *psessions;
675
676 list_ret = lttng_list_sessions(&psessions);
677
678 if (list_ret < 0) {
679 LTTNG_THROW_CTL("Failed to list sessions",
680 static_cast<lttng_error_code>(list_ret));
681 }
682
683 return lttng::cli::session_list(psessions, list_ret);
684 }();
685
686 std::size_t write_to = 0;
687 for (std::size_t read_from = 0; read_from < list.size(); ++read_from) {
688 if (!filter(list[read_from])) {
689 continue;
690 }
691
692 if (read_from != write_to) {
693 list[write_to] = list[read_from];
694 }
695
696 ++write_to;
697
698 if (return_first_match_only) {
699 return lttng::cli::session_list(std::move(list), 1);
700 }
701 }
702
703 list.resize(write_to);
704
705 return list;
706 }
707 } /* namespace */
708
709 lttng::cli::session_list lttng::cli::list_sessions(const struct session_spec& spec)
710 {
711 switch (spec.type_) {
712 case lttng::cli::session_spec::type::NAME:
713 if (spec.value == nullptr) {
714 const auto configured_name =
715 lttng::make_unique_wrapper<char, lttng::free>(get_session_name());
716
717 if (configured_name) {
718 const struct lttng::cli::session_spec new_spec(
719 lttng::cli::session_spec::type::NAME,
720 configured_name.get());
721
722 return list_sessions(new_spec);
723 }
724
725 return lttng::cli::session_list();
726 }
727
728 return get_sessions(
729 [&spec](const lttng_session& session) {
730 return strcmp(session.name, spec.value) == 0;
731 },
732 true);
733 case lttng::cli::session_spec::type::GLOB_PATTERN:
734 return get_sessions([&spec](const lttng_session& session) {
735 return fnmatch(spec.value, session.name, 0) == 0;
736 });
737 case lttng::cli::session_spec::type::ALL:
738 return get_sessions([](const lttng_session&) { return true; });
739 }
740
741 return lttng::cli::session_list();
742 }
743
744 void print_kernel_tracer_status_error()
745 {
746 if (lttng_opt_mi) {
747 return;
748 }
749
750 enum lttng_kernel_tracer_status kernel_tracer_status;
751 const auto ret = lttng_get_kernel_tracer_status(&kernel_tracer_status);
752
753 if (ret < 0) {
754 ERR("Failed to get kernel tracer status: %s", lttng_strerror(ret));
755 } else {
756 switch (kernel_tracer_status) {
757 case LTTNG_KERNEL_TRACER_STATUS_INITIALIZED:
758 return;
759 case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN:
760 std::cerr << "\tKernel module loading failed" << std::endl;
761 break;
762 case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING:
763 std::cerr << "\tMissing one or more required kernel modules" << std::endl;
764 break;
765 case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE:
766 std::cerr
767 << "\tKernel module signature error prevented loading of one or more required kernel modules"
768 << std::endl;
769 break;
770 case LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT:
771 std::cerr << "\tlttng-sessiond isn't running as root" << std::endl;
772 break;
773 case LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER:
774 std::cerr << "\tFailed to setup notifiers" << std::endl;
775 break;
776 case LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG:
777 std::cerr << "\tlttng-sessiond failed to open /proc/lttng" << std::endl;
778 break;
779 case LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH:
780 std::cerr
781 << "\tVersion mismatch between kernel tracer and kernel tracer ABI"
782 << std::endl;
783 break;
784 default:
785 std::cerr << lttng::format("\t\tUnknown kernel tracer status (%d)",
786 static_cast<int>(kernel_tracer_status))
787 << std::endl;
788 break;
789 }
790
791 std::cerr << "\tConsult lttng-sessiond logs for more information" << std::endl;
792 }
793 }
This page took 0.044745 seconds and 5 git commands to generate.