clang-tidy: add Chrome-inspired checks
[lttng-tools.git] / src / bin / lttng / utils.cpp
CommitLineData
f3ed775e 1/*
21cf9b6b 2 * Copyright (C) 2011 EfficiOS Inc.
f3ed775e 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
f3ed775e 5 *
f3ed775e
DG
6 */
7
6c1c0768 8#define _LGPL_SOURCE
28ab034a
JG
9#include "command.hpp"
10#include "conf.hpp"
11#include "utils.hpp"
f3ed775e 12
28ab034a 13#include <common/defaults.hpp>
c9e313bc
SM
14#include <common/error.hpp>
15#include <common/utils.hpp>
f3ed775e 16
28ab034a
JG
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>
f3ed775e 27
4fd2697f
FD
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";
b9dfb167 34
28ab034a 35static char *_get_session_name(int quiet)
f3ed775e 36{
4f00620d 37 const char *path;
cd9adb8b 38 char *session_name = nullptr;
f3ed775e
DG
39
40 /* Get path to config file */
feb0f3e5 41 path = utils_get_home_dir();
cd9adb8b 42 if (path == nullptr) {
f3ed775e
DG
43 goto error;
44 }
45
46 /* Get session name from config */
1dac0189 47 session_name = quiet ? config_read_session_name_quiet(path) :
28ab034a 48 config_read_session_name(path);
cd9adb8b 49 if (session_name == nullptr) {
58a97671 50 goto error;
f3ed775e
DG
51 }
52
3183dbb0 53 DBG2("Config file path found: %s", path);
cd80958d 54 DBG("Session name found: %s", session_name);
f3ed775e 55 return session_name;
3183dbb0
DG
56
57error:
cd9adb8b 58 return nullptr;
f3ed775e 59}
679b4943 60
1dac0189
PPM
61/*
62 * get_session_name
63 *
64 * Return allocated string with the session name found in the config
65 * directory.
66 */
cd9adb8b 67char *get_session_name()
1dac0189
PPM
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 */
cd9adb8b 78char *get_session_name_quiet()
1dac0189
PPM
79{
80 return _get_session_name(1);
81}
82
3c9bd23c
SM
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;
cd9adb8b 92 struct cmd_struct *cmd = nullptr;
3c9bd23c
SM
93
94 cmd = &commands[i];
cd9adb8b 95 while (cmd->name != nullptr) {
3c9bd23c
SM
96 fprintf(ofp, "%s\n", cmd->name);
97 i++;
98 cmd = &commands[i];
99 }
100}
679b4943
SM
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;
cd9adb8b 111 struct poptOption *option = nullptr;
679b4943 112
cd9adb8b 113 for (i = 0; options[i].longName != nullptr; i++) {
679b4943
SM
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}
8ce58bad 123
b083f028
JR
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
cd9adb8b 131 for (i = 0; options[i].long_name != nullptr; i++) {
b083f028
JR
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
8ce58bad
MD
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)
28ab034a 148static inline unsigned int fls_u32(uint32_t x)
8ce58bad
MD
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"
28ab034a
JG
156 : "=r"(r)
157 : "rm"(x));
8ce58bad
MD
158 return r + 1;
159}
160#define HAS_FLS_U32
161#endif
162
a1e4ab8b 163#if defined(__x86_64) && defined(__LP64__)
28ab034a 164static inline unsigned int fls_u64(uint64_t x)
8ce58bad
MD
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"
28ab034a
JG
172 : "=r"(r)
173 : "rm"(x));
8ce58bad
MD
174 return r + 1;
175}
176#define HAS_FLS_U64
177#endif
178
179#ifndef HAS_FLS_U64
28ab034a 180static __attribute__((unused)) unsigned int fls_u64(uint64_t x)
8ce58bad
MD
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
28ab034a 216static __attribute__((unused)) unsigned int fls_u32(uint32_t x)
8ce58bad
MD
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
28ab034a 246static unsigned int fls_ulong(unsigned long x)
8ce58bad
MD
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}
b9dfb167 290
4fd2697f
FD
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. */
a0377dfe 316 abort();
4fd2697f
FD
317 }
318
319 return str_event_type;
320}
321
8960e9cd
DG
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 {
6f04ed72 352 PERROR("execlp");
8960e9cd 353 }
28ab034a 354 kill(getppid(), SIGTERM); /* wake parent */
8960e9cd
DG
355 exit(EXIT_FAILURE);
356 } else if (pid > 0) {
357 goto end;
358 } else {
6f04ed72 359 PERROR("fork");
8960e9cd
DG
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 */
cd9adb8b 373int check_relayd()
8960e9cd
DG
374{
375 int ret, fd;
376 struct sockaddr_in sin;
377
378 fd = socket(AF_INET, SOCK_STREAM, 0);
379 if (fd < 0) {
6f04ed72 380 PERROR("socket check relayd");
dd02a4c1
DG
381 ret = -1;
382 goto error_socket;
8960e9cd
DG
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) {
6f04ed72 389 PERROR("inet_pton check relayd");
dd02a4c1 390 ret = -1;
8960e9cd
DG
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 */
56efeab3 398 ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
8960e9cd
DG
399 if (ret < 0) {
400 /* Not found. */
401 ret = 0;
402 } else {
403 /* Already spawned. */
404 ret = 1;
405 }
406
8960e9cd 407error:
dd02a4c1 408 if (close(fd) < 0) {
6f04ed72 409 PERROR("close relayd fd");
dd02a4c1
DG
410 }
411error_socket:
412 return ret;
8960e9cd 413}
3ecec76a 414
28ab034a 415int print_missing_or_multiple_domains(unsigned int domain_count, bool include_agent_domains)
3ecec76a
PP
416{
417 int ret = 0;
418
3533d06b
JG
419 if (domain_count == 0) {
420 ERR("Please specify a domain (--kernel/--userspace%s).",
28ab034a 421 include_agent_domains ? "/--jul/--log4j/--python" : "");
3ecec76a 422 ret = -1;
3533d06b
JG
423 } else if (domain_count > 1) {
424 ERR("Only one domain must be specified.");
3ecec76a
PP
425 ret = -1;
426 }
427
428 return ret;
429}
20fb9e02
JD
430
431/*
432 * Get the discarded events and lost packet counts.
433 */
434void print_session_stats(const char *session_name)
435{
58f237ca
JG
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;
cd9adb8b
JG
448 struct lttng_domain *domains = nullptr;
449 struct lttng_channel *channels = nullptr;
3e8f2238 450 uint64_t discarded_events_total = 0, lost_packets_total = 0;
cd9adb8b
JG
451 struct lttng_session *sessions = nullptr;
452 const struct lttng_session *selected_session = nullptr;
453 char *stats_str = nullptr;
58f237ca 454 bool print_discarded_events = false, print_lost_packets = false;
3e8f2238
JG
455
456 count = lttng_list_sessions(&sessions);
457 if (count < 1) {
458 ERR("Failed to retrieve session descriptions while printing session statistics.");
58f237ca 459 ret = -1;
3e8f2238
JG
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) {
28ab034a
JG
471 ERR("Failed to retrieve session \"%s\" description while printing session statistics.",
472 session_name);
58f237ca 473 ret = -1;
3e8f2238
JG
474 goto end;
475 }
20fb9e02
JD
476
477 nb_domains = lttng_list_domains(session_name, &domains);
478 if (nb_domains < 0) {
58f237ca 479 ret = -1;
20fb9e02
JD
480 goto end;
481 }
482 for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) {
28ab034a
JG
483 struct lttng_handle *handle =
484 lttng_create_handle(session_name, &domains[domain_idx]);
20fb9e02
JD
485
486 if (!handle) {
3e8f2238 487 ERR("Failed to create session handle while printing session statistics.");
58f237ca 488 ret = -1;
20fb9e02
JD
489 goto end;
490 }
491
092545c3 492 free(channels);
cd9adb8b 493 channels = nullptr;
20fb9e02
JD
494 count = lttng_list_channels(handle, &channels);
495 for (channel_idx = 0; channel_idx < count; channel_idx++) {
3e8f2238 496 uint64_t discarded_events = 0, lost_packets = 0;
20fb9e02
JD
497 struct lttng_channel *channel = &channels[channel_idx];
498
28ab034a 499 ret = lttng_channel_get_discarded_event_count(channel, &discarded_events);
20fb9e02
JD
500 if (ret) {
501 ERR("Failed to retrieve discarded event count from channel %s",
28ab034a 502 channel->name);
20fb9e02
JD
503 }
504
28ab034a 505 ret = lttng_channel_get_lost_packet_count(channel, &lost_packets);
20fb9e02
JD
506 if (ret) {
507 ERR("Failed to retrieve lost packet count from channel %s",
28ab034a 508 channel->name);
20fb9e02
JD
509 }
510
3e8f2238
JG
511 discarded_events_total += discarded_events;
512 lost_packets_total += lost_packets;
20fb9e02
JD
513 }
514 lttng_destroy_handle(handle);
515 }
58f237ca 516
28ab034a
JG
517 print_discarded_events = discarded_events_total > 0 && !selected_session->snapshot_mode;
518 print_lost_packets = lost_packets_total > 0 && !selected_session->snapshot_mode;
58f237ca
JG
519
520 if (print_discarded_events && print_lost_packets) {
521 ret = asprintf(&stats_str,
28ab034a
JG
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);
58f237ca
JG
527 } else if (print_discarded_events) {
528 ret = asprintf(&stats_str,
28ab034a
JG
529 "Warning: %" PRIu64 " events were discarded, please refer to "
530 "the documentation on channel configuration.",
531 discarded_events_total);
58f237ca
JG
532 } else if (print_lost_packets) {
533 ret = asprintf(&stats_str,
28ab034a
JG
534 "Warning: %" PRIu64 " packets were lost, please refer to "
535 "the documentation on channel configuration.",
536 lost_packets_total);
58f237ca
JG
537 } else {
538 ret = 0;
20fb9e02
JD
539 }
540
58f237ca
JG
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 }
20fb9e02 547end:
3e8f2238 548 free(sessions);
092545c3
SM
549 free(channels);
550 free(domains);
58f237ca 551 return ret;
20fb9e02 552}
4ba92f18 553
4fc83d94 554int show_cmd_help(const char *cmd_name, const char *help_msg)
4ba92f18
PP
555{
556 int ret;
557 char page_name[32];
558
559 ret = sprintf(page_name, "lttng-%s", cmd_name);
a0377dfe 560 LTTNG_ASSERT(ret > 0 && ret < 32);
4fc83d94
PP
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 }
4ba92f18 566
4fc83d94 567 return ret;
4ba92f18 568}
bbbfd849 569
28ab034a
JG
570int print_trace_archive_location(const struct lttng_trace_archive_location *location,
571 const char *session_name)
bbbfd849
JG
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
28ab034a 580 _MSG("Trace chunk archive for session %s is now readable", session_name);
bbbfd849
JG
581 switch (location_type) {
582 case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
583 {
584 const char *absolute_path;
585
28ab034a
JG
586 status = lttng_trace_archive_location_local_get_absolute_path(location,
587 &absolute_path);
bbbfd849
JG
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. */
28ab034a 603 status = lttng_trace_archive_location_relay_get_protocol_type(location, &protocol);
bbbfd849
JG
604 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
605 ret = -1;
606 goto end;
607 }
608
28ab034a 609 status = lttng_trace_archive_location_relay_get_host(location, &host);
bbbfd849
JG
610 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
611 ret = -1;
612 goto end;
613 }
614
28ab034a
JG
615 status = lttng_trace_archive_location_relay_get_control_port(location,
616 &control_port);
bbbfd849
JG
617 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
618 ret = -1;
619 goto end;
620 }
621
28ab034a 622 status = lttng_trace_archive_location_relay_get_data_port(location, &data_port);
bbbfd849
JG
623 if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
624 ret = -1;
625 goto end;
626 }
627
28ab034a
JG
628 status = lttng_trace_archive_location_relay_get_relative_path(location,
629 &relative_path);
bbbfd849
JG
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
28ab034a
JG
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);
bbbfd849
JG
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.095957 seconds and 4 git commands to generate.