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