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