Copyright ownership transfer
[lttng-tools.git] / src / bin / lttng / utils.cpp
... / ...
CommitLineData
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 <stdlib.h>
10#include <ctype.h>
11#include <limits.h>
12#include <sys/types.h>
13#include <sys/socket.h>
14#include <signal.h>
15#include <netinet/in.h>
16#include <arpa/inet.h>
17#include <inttypes.h>
18#include <unistd.h>
19
20#include <common/error.h>
21#include <common/utils.h>
22#include <common/defaults.h>
23
24#include "conf.h"
25#include "utils.h"
26#include "command.h"
27
28static const char *str_all = "ALL";
29static const char *str_tracepoint = "Tracepoint";
30static const char *str_syscall = "Syscall";
31static const char *str_probe = "Probe";
32static const char *str_userspace_probe = "Userspace Probe";
33static const char *str_function = "Function";
34
35static
36char *_get_session_name(int quiet)
37{
38 const char *path;
39 char *session_name = NULL;
40
41 /* Get path to config file */
42 path = utils_get_home_dir();
43 if (path == NULL) {
44 goto error;
45 }
46
47 /* Get session name from config */
48 session_name = quiet ? config_read_session_name_quiet(path) :
49 config_read_session_name(path);
50 if (session_name == NULL) {
51 goto error;
52 }
53
54 DBG2("Config file path found: %s", path);
55 DBG("Session name found: %s", session_name);
56 return session_name;
57
58error:
59 return NULL;
60}
61
62/*
63 * get_session_name
64 *
65 * Return allocated string with the session name found in the config
66 * directory.
67 */
68char *get_session_name(void)
69{
70 return _get_session_name(0);
71}
72
73/*
74 * get_session_name_quiet (no warnings/errors emitted)
75 *
76 * Return allocated string with the session name found in the config
77 * directory.
78 */
79char *get_session_name_quiet(void)
80{
81 return _get_session_name(1);
82}
83
84/*
85 * list_commands
86 *
87 * List commands line by line. This is mostly for bash auto completion and to
88 * avoid difficult parsing.
89 */
90void list_commands(struct cmd_struct *commands, FILE *ofp)
91{
92 int i = 0;
93 struct cmd_struct *cmd = NULL;
94
95 cmd = &commands[i];
96 while (cmd->name != NULL) {
97 fprintf(ofp, "%s\n", cmd->name);
98 i++;
99 cmd = &commands[i];
100 }
101}
102
103/*
104 * list_cmd_options
105 *
106 * Prints a simple list of the options available to a command. This is intended
107 * to be easily parsed for bash completion.
108 */
109void list_cmd_options(FILE *ofp, struct poptOption *options)
110{
111 int i;
112 struct poptOption *option = NULL;
113
114 for (i = 0; options[i].longName != NULL; i++) {
115 option = &options[i];
116
117 fprintf(ofp, "--%s\n", option->longName);
118
119 if (isprint(option->shortName)) {
120 fprintf(ofp, "-%c\n", option->shortName);
121 }
122 }
123}
124
125/*
126 * Same as list_cmd_options, but for options specified for argpar.
127 */
128void list_cmd_options_argpar(FILE *ofp, const struct argpar_opt_descr *options)
129{
130 int i;
131
132 for (i = 0; options[i].long_name != NULL; i++) {
133 const struct argpar_opt_descr *option = &options[i];
134
135 fprintf(ofp, "--%s\n", option->long_name);
136
137 if (isprint(option->short_name)) {
138 fprintf(ofp, "-%c\n", option->short_name);
139 }
140 }
141}
142
143/*
144 * fls: returns the position of the most significant bit.
145 * Returns 0 if no bit is set, else returns the position of the most
146 * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
147 */
148#if defined(__i386) || defined(__x86_64)
149static inline
150unsigned int fls_u32(uint32_t x)
151{
152 int r;
153
154 asm("bsrl %1,%0\n\t"
155 "jnz 1f\n\t"
156 "movl $-1,%0\n\t"
157 "1:\n\t"
158 : "=r" (r) : "rm" (x));
159 return r + 1;
160}
161#define HAS_FLS_U32
162#endif
163
164#if defined(__x86_64) && defined(__LP64__)
165static inline
166unsigned int fls_u64(uint64_t x)
167{
168 long r;
169
170 asm("bsrq %1,%0\n\t"
171 "jnz 1f\n\t"
172 "movq $-1,%0\n\t"
173 "1:\n\t"
174 : "=r" (r) : "rm" (x));
175 return r + 1;
176}
177#define HAS_FLS_U64
178#endif
179
180#ifndef HAS_FLS_U64
181static __attribute__((unused))
182unsigned int fls_u64(uint64_t x)
183{
184 unsigned int r = 64;
185
186 if (!x)
187 return 0;
188
189 if (!(x & 0xFFFFFFFF00000000ULL)) {
190 x <<= 32;
191 r -= 32;
192 }
193 if (!(x & 0xFFFF000000000000ULL)) {
194 x <<= 16;
195 r -= 16;
196 }
197 if (!(x & 0xFF00000000000000ULL)) {
198 x <<= 8;
199 r -= 8;
200 }
201 if (!(x & 0xF000000000000000ULL)) {
202 x <<= 4;
203 r -= 4;
204 }
205 if (!(x & 0xC000000000000000ULL)) {
206 x <<= 2;
207 r -= 2;
208 }
209 if (!(x & 0x8000000000000000ULL)) {
210 x <<= 1;
211 r -= 1;
212 }
213 return r;
214}
215#endif
216
217#ifndef HAS_FLS_U32
218static __attribute__((unused))
219unsigned int fls_u32(uint32_t x)
220{
221 unsigned int r = 32;
222
223 if (!x)
224 return 0;
225 if (!(x & 0xFFFF0000U)) {
226 x <<= 16;
227 r -= 16;
228 }
229 if (!(x & 0xFF000000U)) {
230 x <<= 8;
231 r -= 8;
232 }
233 if (!(x & 0xF0000000U)) {
234 x <<= 4;
235 r -= 4;
236 }
237 if (!(x & 0xC0000000U)) {
238 x <<= 2;
239 r -= 2;
240 }
241 if (!(x & 0x80000000U)) {
242 x <<= 1;
243 r -= 1;
244 }
245 return r;
246}
247#endif
248
249static
250unsigned 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 */
263int 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 */
275int 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 */
287int get_count_order_ulong(unsigned long x)
288{
289 if (!x)
290 return -1;
291
292 return fls_ulong(x - 1);
293}
294
295const 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 */
329int 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
368end:
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 */
377int check_relayd(void)
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
411error:
412 if (close(fd) < 0) {
413 PERROR("close relayd fd");
414 }
415error_socket:
416 return ret;
417}
418
419int print_missing_or_multiple_domains(unsigned int domain_count,
420 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 ?
427 "/--jul/--log4j/--python" :
428 "");
429 ret = -1;
430 } else if (domain_count > 1) {
431 ERR("Only one domain must be specified.");
432 ret = -1;
433 }
434
435 return ret;
436}
437
438/*
439 * Get the discarded events and lost packet counts.
440 */
441void print_session_stats(const char *session_name)
442{
443 char *str;
444 const int ret = get_session_stats_str(session_name, &str);
445
446 if (ret >= 0 && str) {
447 MSG("%s", str);
448 free(str);
449 }
450}
451
452int get_session_stats_str(const char *session_name, char **out_str)
453{
454 int count, nb_domains, domain_idx, channel_idx, session_idx, ret;
455 struct lttng_domain *domains = NULL;
456 struct lttng_channel *channels = NULL;
457 uint64_t discarded_events_total = 0, lost_packets_total = 0;
458 struct lttng_session *sessions = NULL;
459 const struct lttng_session *selected_session = NULL;
460 char *stats_str = NULL;
461 bool print_discarded_events = false, print_lost_packets = false;
462
463 count = lttng_list_sessions(&sessions);
464 if (count < 1) {
465 ERR("Failed to retrieve session descriptions while printing session statistics.");
466 ret = -1;
467 goto end;
468 }
469
470 /* Identify the currently-selected sessions. */
471 for (session_idx = 0; session_idx < count; session_idx++) {
472 if (!strcmp(session_name, sessions[session_idx].name)) {
473 selected_session = &sessions[session_idx];
474 break;
475 }
476 }
477 if (!selected_session) {
478 ERR("Failed to retrieve session \"%s\" description while printing session statistics.", session_name);
479 ret = -1;
480 goto end;
481 }
482
483 nb_domains = lttng_list_domains(session_name, &domains);
484 if (nb_domains < 0) {
485 ret = -1;
486 goto end;
487 }
488 for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) {
489 struct lttng_handle *handle = lttng_create_handle(session_name,
490 &domains[domain_idx]);
491
492 if (!handle) {
493 ERR("Failed to create session handle while printing session statistics.");
494 ret = -1;
495 goto end;
496 }
497
498 free(channels);
499 channels = NULL;
500 count = lttng_list_channels(handle, &channels);
501 for (channel_idx = 0; channel_idx < count; channel_idx++) {
502 uint64_t discarded_events = 0, lost_packets = 0;
503 struct lttng_channel *channel = &channels[channel_idx];
504
505 ret = lttng_channel_get_discarded_event_count(channel,
506 &discarded_events);
507 if (ret) {
508 ERR("Failed to retrieve discarded event count from channel %s",
509 channel->name);
510 }
511
512 ret = lttng_channel_get_lost_packet_count(channel,
513 &lost_packets);
514 if (ret) {
515 ERR("Failed to retrieve lost packet count from channel %s",
516 channel->name);
517 }
518
519 discarded_events_total += discarded_events;
520 lost_packets_total += lost_packets;
521 }
522 lttng_destroy_handle(handle);
523 }
524
525 print_discarded_events = discarded_events_total > 0 &&
526 !selected_session->snapshot_mode;
527 print_lost_packets = lost_packets_total > 0 &&
528 !selected_session->snapshot_mode;
529
530 if (print_discarded_events && print_lost_packets) {
531 ret = asprintf(&stats_str,
532 "Warning: %" PRIu64
533 " events were discarded and %" PRIu64
534 " packets were lost, please refer to "
535 "the documentation on channel configuration.",
536 discarded_events_total, lost_packets_total);
537 } else if (print_discarded_events) {
538 ret = asprintf(&stats_str,
539 "Warning: %" PRIu64
540 " events were discarded, please refer to "
541 "the documentation on channel configuration.",
542 discarded_events_total);
543 } else if (print_lost_packets) {
544 ret = asprintf(&stats_str,
545 "Warning: %" PRIu64
546 " packets were lost, please refer to "
547 "the documentation on channel configuration.",
548 lost_packets_total);
549 } else {
550 ret = 0;
551 }
552
553 if (ret < 0) {
554 ERR("Failed to format lost packet and discarded events statistics");
555 } else {
556 *out_str = stats_str;
557 ret = 0;
558 }
559end:
560 free(sessions);
561 free(channels);
562 free(domains);
563 return ret;
564}
565
566int show_cmd_help(const char *cmd_name, const char *help_msg)
567{
568 int ret;
569 char page_name[32];
570
571 ret = sprintf(page_name, "lttng-%s", cmd_name);
572 LTTNG_ASSERT(ret > 0 && ret < 32);
573 ret = utils_show_help(1, page_name, help_msg);
574 if (ret && !help_msg) {
575 ERR("Cannot view man page `lttng-%s(1)`", cmd_name);
576 perror("exec");
577 }
578
579 return ret;
580}
581
582int print_trace_archive_location(
583 const struct lttng_trace_archive_location *location,
584 const char *session_name)
585{
586 int ret = 0;
587 enum lttng_trace_archive_location_type location_type;
588 enum lttng_trace_archive_location_status status;
589 bool printed_location = false;
590
591 location_type = lttng_trace_archive_location_get_type(location);
592
593 _MSG("Trace chunk archive for session %s is now readable",
594 session_name);
595 switch (location_type) {
596 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
597 {
598 const char *absolute_path;
599
600 status = lttng_trace_archive_location_local_get_absolute_path(
601 location, &absolute_path);
602 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
603 ret = -1;
604 goto end;
605 }
606 MSG(" at %s", absolute_path);
607 printed_location = true;
608 break;
609 }
610 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
611 {
612 uint16_t control_port, data_port;
613 const char *host, *relative_path, *protocol_str;
614 enum lttng_trace_archive_location_relay_protocol_type protocol;
615
616 /* Fetch all relay location parameters. */
617 status = lttng_trace_archive_location_relay_get_protocol_type(
618 location, &protocol);
619 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
620 ret = -1;
621 goto end;
622 }
623
624 status = lttng_trace_archive_location_relay_get_host(
625 location, &host);
626 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
627 ret = -1;
628 goto end;
629 }
630
631 status = lttng_trace_archive_location_relay_get_control_port(
632 location, &control_port);
633 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
634 ret = -1;
635 goto end;
636 }
637
638 status = lttng_trace_archive_location_relay_get_data_port(
639 location, &data_port);
640 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
641 ret = -1;
642 goto end;
643 }
644
645 status = lttng_trace_archive_location_relay_get_relative_path(
646 location, &relative_path);
647 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
648 ret = -1;
649 goto end;
650 }
651
652 switch (protocol) {
653 case LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP:
654 protocol_str = "tcp";
655 break;
656 default:
657 protocol_str = "unknown";
658 break;
659 }
660
661 MSG(" on relay %s://%s/%s [control port %" PRIu16 ", data port %"
662 PRIu16 "]", protocol_str, host,
663 relative_path, control_port, data_port);
664 printed_location = true;
665 break;
666 }
667 default:
668 break;
669 }
670end:
671 if (!printed_location) {
672 MSG(" at an unknown location");
673 }
674 return ret;
675}
This page took 0.024051 seconds and 4 git commands to generate.