Fix: lttng: add-context: silence coverity warning
[lttng-tools.git] / src / bin / lttng / utils.cpp
1 /*
2 * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
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
28 static const char *str_all = "ALL";
29 static const char *str_tracepoint = "Tracepoint";
30 static const char *str_syscall = "Syscall";
31 static const char *str_probe = "Probe";
32 static const char *str_userspace_probe = "Userspace Probe";
33 static const char *str_function = "Function";
34
35 static
36 char *_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
58 error:
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 */
68 char *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 */
79 char *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 */
90 void 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 */
109 void 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 */
128 void 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)
149 static inline
150 unsigned 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__)
165 static inline
166 unsigned 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
181 static __attribute__((unused))
182 unsigned 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
218 static __attribute__((unused))
219 unsigned 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
249 static
250 unsigned 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 */
263 int 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 */
275 int 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 */
287 int get_count_order_ulong(unsigned long x)
288 {
289 if (!x)
290 return -1;
291
292 return fls_ulong(x - 1);
293 }
294
295 const 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 */
329 int 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
368 end:
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 */
377 int 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
411 error:
412 if (close(fd) < 0) {
413 PERROR("close relayd fd");
414 }
415 error_socket:
416 return ret;
417 }
418
419 int 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 */
441 void 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
452 int 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 }
559 end:
560 free(sessions);
561 free(channels);
562 free(domains);
563 return ret;
564 }
565
566 int 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
582 int 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 }
670 end:
671 if (!printed_location) {
672 MSG(" at an unknown location");
673 }
674 return ret;
675 }
This page took 0.042965 seconds and 4 git commands to generate.