argpar: sync with upstream - adjust to iterator API
[lttng-tools.git] / src / bin / lttng / utils.cpp
CommitLineData
f3ed775e 1/*
ab5be9fa 2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
f3ed775e 3 *
ab5be9fa 4 * SPDX-License-Identifier: GPL-2.0-only
f3ed775e 5 *
f3ed775e
DG
6 */
7
6c1c0768 8#define _LGPL_SOURCE
f3ed775e 9#include <stdlib.h>
679b4943 10#include <ctype.h>
3badf2bf 11#include <limits.h>
8960e9cd
DG
12#include <sys/types.h>
13#include <sys/socket.h>
14#include <signal.h>
15#include <netinet/in.h>
16#include <arpa/inet.h>
20fb9e02 17#include <inttypes.h>
4ba92f18 18#include <unistd.h>
f3ed775e 19
db758600 20#include <common/error.h>
feb0f3e5 21#include <common/utils.h>
4ba92f18 22#include <common/defaults.h>
f3ed775e 23
beb8c75a 24#include "conf.h"
679b4943 25#include "utils.h"
3c9bd23c 26#include "command.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
1dac0189
PPM
35static
36char *_get_session_name(int quiet)
f3ed775e 37{
4f00620d
JG
38 const char *path;
39 char *session_name = NULL;
f3ed775e
DG
40
41 /* Get path to config file */
feb0f3e5 42 path = utils_get_home_dir();
f3ed775e
DG
43 if (path == NULL) {
44 goto error;
45 }
46
47 /* Get session name from config */
1dac0189
PPM
48 session_name = quiet ? config_read_session_name_quiet(path) :
49 config_read_session_name(path);
f3ed775e 50 if (session_name == NULL) {
58a97671 51 goto error;
f3ed775e
DG
52 }
53
3183dbb0 54 DBG2("Config file path found: %s", path);
cd80958d 55 DBG("Session name found: %s", session_name);
f3ed775e 56 return session_name;
3183dbb0
DG
57
58error:
59 return NULL;
f3ed775e 60}
679b4943 61
1dac0189
PPM
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
3c9bd23c
SM
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}
679b4943
SM
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}
8ce58bad 124
b083f028
JR
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
8ce58bad
MD
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
a1e4ab8b 164#if defined(__x86_64) && defined(__LP64__)
8ce58bad
MD
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}
b9dfb167 294
4fd2697f
FD
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. */
a0377dfe 320 abort();
4fd2697f
FD
321 }
322
323 return str_event_type;
324}
325
8960e9cd
DG
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 {
6f04ed72 356 PERROR("execlp");
8960e9cd
DG
357 }
358 kill(getppid(), SIGTERM); /* wake parent */
359 exit(EXIT_FAILURE);
360 } else if (pid > 0) {
361 goto end;
362 } else {
6f04ed72 363 PERROR("fork");
8960e9cd
DG
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) {
6f04ed72 384 PERROR("socket check relayd");
dd02a4c1
DG
385 ret = -1;
386 goto error_socket;
8960e9cd
DG
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) {
6f04ed72 393 PERROR("inet_pton check relayd");
dd02a4c1 394 ret = -1;
8960e9cd
DG
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 */
56efeab3 402 ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
8960e9cd
DG
403 if (ret < 0) {
404 /* Not found. */
405 ret = 0;
406 } else {
407 /* Already spawned. */
408 ret = 1;
409 }
410
8960e9cd 411error:
dd02a4c1 412 if (close(fd) < 0) {
6f04ed72 413 PERROR("close relayd fd");
dd02a4c1
DG
414 }
415error_socket:
416 return ret;
8960e9cd 417}
3ecec76a 418
3533d06b
JG
419int print_missing_or_multiple_domains(unsigned int domain_count,
420 bool include_agent_domains)
3ecec76a
PP
421{
422 int ret = 0;
423
3533d06b
JG
424 if (domain_count == 0) {
425 ERR("Please specify a domain (--kernel/--userspace%s).",
426 include_agent_domains ?
427 "/--jul/--log4j/--python" :
428 "");
3ecec76a 429 ret = -1;
3533d06b
JG
430 } else if (domain_count > 1) {
431 ERR("Only one domain must be specified.");
3ecec76a
PP
432 ret = -1;
433 }
434
435 return ret;
436}
20fb9e02
JD
437
438/*
439 * Get the discarded events and lost packet counts.
440 */
441void print_session_stats(const char *session_name)
442{
58f237ca
JG
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;
092545c3
SM
455 struct lttng_domain *domains = NULL;
456 struct lttng_channel *channels = NULL;
3e8f2238
JG
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;
58f237ca
JG
460 char *stats_str = NULL;
461 bool print_discarded_events = false, print_lost_packets = false;
3e8f2238
JG
462
463 count = lttng_list_sessions(&sessions);
464 if (count < 1) {
465 ERR("Failed to retrieve session descriptions while printing session statistics.");
58f237ca 466 ret = -1;
3e8f2238
JG
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);
58f237ca 479 ret = -1;
3e8f2238
JG
480 goto end;
481 }
20fb9e02
JD
482
483 nb_domains = lttng_list_domains(session_name, &domains);
484 if (nb_domains < 0) {
58f237ca 485 ret = -1;
20fb9e02
JD
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) {
3e8f2238 493 ERR("Failed to create session handle while printing session statistics.");
58f237ca 494 ret = -1;
20fb9e02
JD
495 goto end;
496 }
497
092545c3
SM
498 free(channels);
499 channels = NULL;
20fb9e02
JD
500 count = lttng_list_channels(handle, &channels);
501 for (channel_idx = 0; channel_idx < count; channel_idx++) {
3e8f2238 502 uint64_t discarded_events = 0, lost_packets = 0;
20fb9e02
JD
503 struct lttng_channel *channel = &channels[channel_idx];
504
505 ret = lttng_channel_get_discarded_event_count(channel,
3e8f2238 506 &discarded_events);
20fb9e02
JD
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,
3e8f2238 513 &lost_packets);
20fb9e02
JD
514 if (ret) {
515 ERR("Failed to retrieve lost packet count from channel %s",
516 channel->name);
517 }
518
3e8f2238
JG
519 discarded_events_total += discarded_events;
520 lost_packets_total += lost_packets;
20fb9e02
JD
521 }
522 lttng_destroy_handle(handle);
523 }
58f237ca
JG
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 "
20fb9e02 541 "the documentation on channel configuration.",
3e8f2238 542 discarded_events_total);
58f237ca
JG
543 } else if (print_lost_packets) {
544 ret = asprintf(&stats_str,
545 "Warning: %" PRIu64
546 " packets were lost, please refer to "
20fb9e02 547 "the documentation on channel configuration.",
3e8f2238 548 lost_packets_total);
58f237ca
JG
549 } else {
550 ret = 0;
20fb9e02
JD
551 }
552
58f237ca
JG
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 }
20fb9e02 559end:
3e8f2238 560 free(sessions);
092545c3
SM
561 free(channels);
562 free(domains);
58f237ca 563 return ret;
20fb9e02 564}
4ba92f18 565
4fc83d94 566int show_cmd_help(const char *cmd_name, const char *help_msg)
4ba92f18
PP
567{
568 int ret;
569 char page_name[32];
570
571 ret = sprintf(page_name, "lttng-%s", cmd_name);
a0377dfe 572 LTTNG_ASSERT(ret > 0 && ret < 32);
4fc83d94
PP
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 }
4ba92f18 578
4fc83d94 579 return ret;
4ba92f18 580}
bbbfd849
JG
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.092968 seconds and 4 git commands to generate.