Commit | Line | Data |
---|---|---|
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" | |
0729ea55 | 11 | #include "exception.hpp" |
28ab034a | 12 | #include "utils.hpp" |
f3ed775e | 13 | |
28ab034a | 14 | #include <common/defaults.hpp> |
c9e313bc | 15 | #include <common/error.hpp> |
ca938aa5 OD |
16 | #include <common/exception.hpp> |
17 | #include <common/make-unique-wrapper.hpp> | |
c9e313bc | 18 | #include <common/utils.hpp> |
f3ed775e | 19 | |
28ab034a JG |
20 | #include <arpa/inet.h> |
21 | #include <ctype.h> | |
ca938aa5 | 22 | #include <fnmatch.h> |
28ab034a | 23 | #include <inttypes.h> |
4d4c8b8e | 24 | #include <iostream> |
28ab034a JG |
25 | #include <limits.h> |
26 | #include <netinet/in.h> | |
27 | #include <signal.h> | |
28 | #include <stdlib.h> | |
29 | #include <sys/socket.h> | |
30 | #include <sys/types.h> | |
31 | #include <unistd.h> | |
f3ed775e | 32 | |
4fd2697f FD |
33 | static const char *str_all = "ALL"; |
34 | static const char *str_tracepoint = "Tracepoint"; | |
35 | static const char *str_syscall = "Syscall"; | |
36 | static const char *str_probe = "Probe"; | |
37 | static const char *str_userspace_probe = "Userspace Probe"; | |
38 | static const char *str_function = "Function"; | |
b9dfb167 | 39 | |
28ab034a | 40 | static char *_get_session_name(int quiet) |
f3ed775e | 41 | { |
4f00620d | 42 | const char *path; |
cd9adb8b | 43 | char *session_name = nullptr; |
f3ed775e DG |
44 | |
45 | /* Get path to config file */ | |
feb0f3e5 | 46 | path = utils_get_home_dir(); |
cd9adb8b | 47 | if (path == nullptr) { |
f3ed775e DG |
48 | goto error; |
49 | } | |
50 | ||
51 | /* Get session name from config */ | |
1dac0189 | 52 | session_name = quiet ? config_read_session_name_quiet(path) : |
28ab034a | 53 | config_read_session_name(path); |
cd9adb8b | 54 | if (session_name == nullptr) { |
58a97671 | 55 | goto error; |
f3ed775e DG |
56 | } |
57 | ||
3183dbb0 | 58 | DBG2("Config file path found: %s", path); |
cd80958d | 59 | DBG("Session name found: %s", session_name); |
f3ed775e | 60 | return session_name; |
3183dbb0 DG |
61 | |
62 | error: | |
cd9adb8b | 63 | return nullptr; |
f3ed775e | 64 | } |
679b4943 | 65 | |
1dac0189 PPM |
66 | /* |
67 | * get_session_name | |
68 | * | |
69 | * Return allocated string with the session name found in the config | |
70 | * directory. | |
71 | */ | |
cd9adb8b | 72 | char *get_session_name() |
1dac0189 PPM |
73 | { |
74 | return _get_session_name(0); | |
75 | } | |
76 | ||
77 | /* | |
78 | * get_session_name_quiet (no warnings/errors emitted) | |
79 | * | |
80 | * Return allocated string with the session name found in the config | |
81 | * directory. | |
82 | */ | |
cd9adb8b | 83 | char *get_session_name_quiet() |
1dac0189 PPM |
84 | { |
85 | return _get_session_name(1); | |
86 | } | |
87 | ||
3c9bd23c SM |
88 | /* |
89 | * list_commands | |
90 | * | |
91 | * List commands line by line. This is mostly for bash auto completion and to | |
92 | * avoid difficult parsing. | |
93 | */ | |
94 | void list_commands(struct cmd_struct *commands, FILE *ofp) | |
95 | { | |
96 | int i = 0; | |
cd9adb8b | 97 | struct cmd_struct *cmd = nullptr; |
3c9bd23c SM |
98 | |
99 | cmd = &commands[i]; | |
cd9adb8b | 100 | while (cmd->name != nullptr) { |
3c9bd23c SM |
101 | fprintf(ofp, "%s\n", cmd->name); |
102 | i++; | |
103 | cmd = &commands[i]; | |
104 | } | |
105 | } | |
679b4943 SM |
106 | |
107 | /* | |
108 | * list_cmd_options | |
109 | * | |
110 | * Prints a simple list of the options available to a command. This is intended | |
111 | * to be easily parsed for bash completion. | |
112 | */ | |
113 | void list_cmd_options(FILE *ofp, struct poptOption *options) | |
114 | { | |
115 | int i; | |
cd9adb8b | 116 | struct poptOption *option = nullptr; |
679b4943 | 117 | |
cd9adb8b | 118 | for (i = 0; options[i].longName != nullptr; i++) { |
679b4943 SM |
119 | option = &options[i]; |
120 | ||
121 | fprintf(ofp, "--%s\n", option->longName); | |
122 | ||
123 | if (isprint(option->shortName)) { | |
124 | fprintf(ofp, "-%c\n", option->shortName); | |
125 | } | |
126 | } | |
127 | } | |
8ce58bad | 128 | |
b083f028 JR |
129 | /* |
130 | * Same as list_cmd_options, but for options specified for argpar. | |
131 | */ | |
132 | void list_cmd_options_argpar(FILE *ofp, const struct argpar_opt_descr *options) | |
133 | { | |
134 | int i; | |
135 | ||
cd9adb8b | 136 | for (i = 0; options[i].long_name != nullptr; i++) { |
b083f028 JR |
137 | const struct argpar_opt_descr *option = &options[i]; |
138 | ||
139 | fprintf(ofp, "--%s\n", option->long_name); | |
140 | ||
141 | if (isprint(option->short_name)) { | |
142 | fprintf(ofp, "-%c\n", option->short_name); | |
143 | } | |
144 | } | |
145 | } | |
146 | ||
8ce58bad MD |
147 | /* |
148 | * fls: returns the position of the most significant bit. | |
149 | * Returns 0 if no bit is set, else returns the position of the most | |
150 | * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit). | |
151 | */ | |
152 | #if defined(__i386) || defined(__x86_64) | |
28ab034a | 153 | static inline unsigned int fls_u32(uint32_t x) |
8ce58bad MD |
154 | { |
155 | int r; | |
156 | ||
157 | asm("bsrl %1,%0\n\t" | |
158 | "jnz 1f\n\t" | |
159 | "movl $-1,%0\n\t" | |
160 | "1:\n\t" | |
28ab034a JG |
161 | : "=r"(r) |
162 | : "rm"(x)); | |
8ce58bad MD |
163 | return r + 1; |
164 | } | |
165 | #define HAS_FLS_U32 | |
166 | #endif | |
167 | ||
a1e4ab8b | 168 | #if defined(__x86_64) && defined(__LP64__) |
28ab034a | 169 | static inline unsigned int fls_u64(uint64_t x) |
8ce58bad MD |
170 | { |
171 | long r; | |
172 | ||
173 | asm("bsrq %1,%0\n\t" | |
174 | "jnz 1f\n\t" | |
175 | "movq $-1,%0\n\t" | |
176 | "1:\n\t" | |
28ab034a JG |
177 | : "=r"(r) |
178 | : "rm"(x)); | |
8ce58bad MD |
179 | return r + 1; |
180 | } | |
181 | #define HAS_FLS_U64 | |
182 | #endif | |
183 | ||
184 | #ifndef HAS_FLS_U64 | |
28ab034a | 185 | static __attribute__((unused)) unsigned int fls_u64(uint64_t x) |
8ce58bad MD |
186 | { |
187 | unsigned int r = 64; | |
188 | ||
189 | if (!x) | |
190 | return 0; | |
191 | ||
192 | if (!(x & 0xFFFFFFFF00000000ULL)) { | |
193 | x <<= 32; | |
194 | r -= 32; | |
195 | } | |
196 | if (!(x & 0xFFFF000000000000ULL)) { | |
197 | x <<= 16; | |
198 | r -= 16; | |
199 | } | |
200 | if (!(x & 0xFF00000000000000ULL)) { | |
201 | x <<= 8; | |
202 | r -= 8; | |
203 | } | |
204 | if (!(x & 0xF000000000000000ULL)) { | |
205 | x <<= 4; | |
206 | r -= 4; | |
207 | } | |
208 | if (!(x & 0xC000000000000000ULL)) { | |
209 | x <<= 2; | |
210 | r -= 2; | |
211 | } | |
212 | if (!(x & 0x8000000000000000ULL)) { | |
213 | x <<= 1; | |
214 | r -= 1; | |
215 | } | |
216 | return r; | |
217 | } | |
218 | #endif | |
219 | ||
220 | #ifndef HAS_FLS_U32 | |
28ab034a | 221 | static __attribute__((unused)) unsigned int fls_u32(uint32_t x) |
8ce58bad MD |
222 | { |
223 | unsigned int r = 32; | |
224 | ||
225 | if (!x) | |
226 | return 0; | |
227 | if (!(x & 0xFFFF0000U)) { | |
228 | x <<= 16; | |
229 | r -= 16; | |
230 | } | |
231 | if (!(x & 0xFF000000U)) { | |
232 | x <<= 8; | |
233 | r -= 8; | |
234 | } | |
235 | if (!(x & 0xF0000000U)) { | |
236 | x <<= 4; | |
237 | r -= 4; | |
238 | } | |
239 | if (!(x & 0xC0000000U)) { | |
240 | x <<= 2; | |
241 | r -= 2; | |
242 | } | |
243 | if (!(x & 0x80000000U)) { | |
244 | x <<= 1; | |
245 | r -= 1; | |
246 | } | |
247 | return r; | |
248 | } | |
249 | #endif | |
250 | ||
28ab034a | 251 | static unsigned int fls_ulong(unsigned long x) |
8ce58bad MD |
252 | { |
253 | #if (CAA_BITS_PER_LONG == 32) | |
254 | return fls_u32(x); | |
255 | #else | |
256 | return fls_u64(x); | |
257 | #endif | |
258 | } | |
259 | ||
260 | /* | |
261 | * Return the minimum order for which x <= (1UL << order). | |
262 | * Return -1 if x is 0. | |
263 | */ | |
264 | int get_count_order_u32(uint32_t x) | |
265 | { | |
266 | if (!x) | |
267 | return -1; | |
268 | ||
269 | return fls_u32(x - 1); | |
270 | } | |
271 | ||
272 | /* | |
273 | * Return the minimum order for which x <= (1UL << order). | |
274 | * Return -1 if x is 0. | |
275 | */ | |
276 | int get_count_order_u64(uint64_t x) | |
277 | { | |
278 | if (!x) | |
279 | return -1; | |
280 | ||
281 | return fls_u64(x - 1); | |
282 | } | |
283 | ||
284 | /* | |
285 | * Return the minimum order for which x <= (1UL << order). | |
286 | * Return -1 if x is 0. | |
287 | */ | |
288 | int get_count_order_ulong(unsigned long x) | |
289 | { | |
290 | if (!x) | |
291 | return -1; | |
292 | ||
293 | return fls_ulong(x - 1); | |
294 | } | |
b9dfb167 | 295 | |
4fd2697f FD |
296 | const char *get_event_type_str(enum lttng_event_type type) |
297 | { | |
298 | const char *str_event_type; | |
299 | ||
300 | switch (type) { | |
301 | case LTTNG_EVENT_ALL: | |
302 | str_event_type = str_all; | |
303 | break; | |
304 | case LTTNG_EVENT_TRACEPOINT: | |
305 | str_event_type = str_tracepoint; | |
306 | break; | |
307 | case LTTNG_EVENT_SYSCALL: | |
308 | str_event_type = str_syscall; | |
309 | break; | |
310 | case LTTNG_EVENT_PROBE: | |
311 | str_event_type = str_probe; | |
312 | break; | |
313 | case LTTNG_EVENT_USERSPACE_PROBE: | |
314 | str_event_type = str_userspace_probe; | |
315 | break; | |
316 | case LTTNG_EVENT_FUNCTION: | |
317 | str_event_type = str_function; | |
318 | break; | |
319 | default: | |
320 | /* Should not have an unknown event type or else define it. */ | |
a0377dfe | 321 | abort(); |
4fd2697f FD |
322 | } |
323 | ||
324 | return str_event_type; | |
325 | } | |
326 | ||
8960e9cd DG |
327 | /* |
328 | * Spawn a lttng relayd daemon by forking and execv. | |
329 | */ | |
330 | int spawn_relayd(const char *pathname, int port) | |
331 | { | |
332 | int ret = 0; | |
333 | pid_t pid; | |
334 | char url[255]; | |
335 | ||
336 | if (!port) { | |
337 | port = DEFAULT_NETWORK_VIEWER_PORT; | |
338 | } | |
339 | ||
340 | ret = snprintf(url, sizeof(url), "tcp://localhost:%d", port); | |
341 | if (ret < 0) { | |
342 | goto end; | |
343 | } | |
344 | ||
345 | MSG("Spawning a relayd daemon"); | |
346 | pid = fork(); | |
347 | if (pid == 0) { | |
348 | /* | |
349 | * Spawn session daemon and tell | |
350 | * it to signal us when ready. | |
351 | */ | |
352 | execlp(pathname, "lttng-relayd", "-L", url, NULL); | |
353 | /* execlp only returns if error happened */ | |
354 | if (errno == ENOENT) { | |
355 | ERR("No relayd found. Use --relayd-path."); | |
356 | } else { | |
6f04ed72 | 357 | PERROR("execlp"); |
8960e9cd | 358 | } |
28ab034a | 359 | kill(getppid(), SIGTERM); /* wake parent */ |
8960e9cd DG |
360 | exit(EXIT_FAILURE); |
361 | } else if (pid > 0) { | |
362 | goto end; | |
363 | } else { | |
6f04ed72 | 364 | PERROR("fork"); |
8960e9cd DG |
365 | ret = -1; |
366 | goto end; | |
367 | } | |
368 | ||
369 | end: | |
370 | return ret; | |
371 | } | |
372 | ||
373 | /* | |
374 | * Check if relayd is alive. | |
375 | * | |
376 | * Return 1 if found else 0 if NOT found. Negative value on error. | |
377 | */ | |
cd9adb8b | 378 | int check_relayd() |
8960e9cd DG |
379 | { |
380 | int ret, fd; | |
381 | struct sockaddr_in sin; | |
382 | ||
383 | fd = socket(AF_INET, SOCK_STREAM, 0); | |
384 | if (fd < 0) { | |
6f04ed72 | 385 | PERROR("socket check relayd"); |
dd02a4c1 DG |
386 | ret = -1; |
387 | goto error_socket; | |
8960e9cd DG |
388 | } |
389 | ||
390 | sin.sin_family = AF_INET; | |
391 | sin.sin_port = htons(DEFAULT_NETWORK_VIEWER_PORT); | |
392 | ret = inet_pton(sin.sin_family, "127.0.0.1", &sin.sin_addr); | |
393 | if (ret < 1) { | |
6f04ed72 | 394 | PERROR("inet_pton check relayd"); |
dd02a4c1 | 395 | ret = -1; |
8960e9cd DG |
396 | goto error; |
397 | } | |
398 | ||
399 | /* | |
400 | * A successful connect means the relayd exists thus returning 0 else a | |
401 | * negative value means it does NOT exists. | |
402 | */ | |
56efeab3 | 403 | ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin)); |
8960e9cd DG |
404 | if (ret < 0) { |
405 | /* Not found. */ | |
406 | ret = 0; | |
407 | } else { | |
408 | /* Already spawned. */ | |
409 | ret = 1; | |
410 | } | |
411 | ||
8960e9cd | 412 | error: |
dd02a4c1 | 413 | if (close(fd) < 0) { |
6f04ed72 | 414 | PERROR("close relayd fd"); |
dd02a4c1 DG |
415 | } |
416 | error_socket: | |
417 | return ret; | |
8960e9cd | 418 | } |
3ecec76a | 419 | |
28ab034a | 420 | int print_missing_or_multiple_domains(unsigned int domain_count, 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).", | |
47abf22b | 426 | include_agent_domains ? "/--jul/--log4j/--log4j2/--python" : ""); |
3ecec76a | 427 | ret = -1; |
3533d06b JG |
428 | } else if (domain_count > 1) { |
429 | ERR("Only one domain must be specified."); | |
3ecec76a PP |
430 | ret = -1; |
431 | } | |
432 | ||
433 | return ret; | |
434 | } | |
20fb9e02 JD |
435 | |
436 | /* | |
437 | * Get the discarded events and lost packet counts. | |
438 | */ | |
439 | void print_session_stats(const char *session_name) | |
440 | { | |
58f237ca JG |
441 | char *str; |
442 | const int ret = get_session_stats_str(session_name, &str); | |
443 | ||
444 | if (ret >= 0 && str) { | |
445 | MSG("%s", str); | |
446 | free(str); | |
447 | } | |
448 | } | |
449 | ||
450 | int get_session_stats_str(const char *session_name, char **out_str) | |
451 | { | |
452 | int count, nb_domains, domain_idx, channel_idx, session_idx, ret; | |
cd9adb8b JG |
453 | struct lttng_domain *domains = nullptr; |
454 | struct lttng_channel *channels = nullptr; | |
3e8f2238 | 455 | uint64_t discarded_events_total = 0, lost_packets_total = 0; |
cd9adb8b JG |
456 | struct lttng_session *sessions = nullptr; |
457 | const struct lttng_session *selected_session = nullptr; | |
458 | char *stats_str = nullptr; | |
58f237ca | 459 | bool print_discarded_events = false, print_lost_packets = false; |
3e8f2238 JG |
460 | |
461 | count = lttng_list_sessions(&sessions); | |
462 | if (count < 1) { | |
463 | ERR("Failed to retrieve session descriptions while printing session statistics."); | |
58f237ca | 464 | ret = -1; |
3e8f2238 JG |
465 | goto end; |
466 | } | |
467 | ||
468 | /* Identify the currently-selected sessions. */ | |
469 | for (session_idx = 0; session_idx < count; session_idx++) { | |
470 | if (!strcmp(session_name, sessions[session_idx].name)) { | |
471 | selected_session = &sessions[session_idx]; | |
472 | break; | |
473 | } | |
474 | } | |
475 | if (!selected_session) { | |
28ab034a JG |
476 | ERR("Failed to retrieve session \"%s\" description while printing session statistics.", |
477 | session_name); | |
58f237ca | 478 | ret = -1; |
3e8f2238 JG |
479 | goto end; |
480 | } | |
20fb9e02 JD |
481 | |
482 | nb_domains = lttng_list_domains(session_name, &domains); | |
483 | if (nb_domains < 0) { | |
58f237ca | 484 | ret = -1; |
20fb9e02 JD |
485 | goto end; |
486 | } | |
487 | for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) { | |
28ab034a JG |
488 | struct lttng_handle *handle = |
489 | lttng_create_handle(session_name, &domains[domain_idx]); | |
20fb9e02 JD |
490 | |
491 | if (!handle) { | |
3e8f2238 | 492 | ERR("Failed to create session handle while printing session statistics."); |
58f237ca | 493 | ret = -1; |
20fb9e02 JD |
494 | goto end; |
495 | } | |
496 | ||
092545c3 | 497 | free(channels); |
cd9adb8b | 498 | channels = nullptr; |
20fb9e02 JD |
499 | count = lttng_list_channels(handle, &channels); |
500 | for (channel_idx = 0; channel_idx < count; channel_idx++) { | |
3e8f2238 | 501 | uint64_t discarded_events = 0, lost_packets = 0; |
20fb9e02 JD |
502 | struct lttng_channel *channel = &channels[channel_idx]; |
503 | ||
28ab034a | 504 | ret = lttng_channel_get_discarded_event_count(channel, &discarded_events); |
20fb9e02 JD |
505 | if (ret) { |
506 | ERR("Failed to retrieve discarded event count from channel %s", | |
28ab034a | 507 | channel->name); |
20fb9e02 JD |
508 | } |
509 | ||
28ab034a | 510 | ret = lttng_channel_get_lost_packet_count(channel, &lost_packets); |
20fb9e02 JD |
511 | if (ret) { |
512 | ERR("Failed to retrieve lost packet count from channel %s", | |
28ab034a | 513 | channel->name); |
20fb9e02 JD |
514 | } |
515 | ||
3e8f2238 JG |
516 | discarded_events_total += discarded_events; |
517 | lost_packets_total += lost_packets; | |
20fb9e02 JD |
518 | } |
519 | lttng_destroy_handle(handle); | |
520 | } | |
58f237ca | 521 | |
28ab034a JG |
522 | print_discarded_events = discarded_events_total > 0 && !selected_session->snapshot_mode; |
523 | print_lost_packets = lost_packets_total > 0 && !selected_session->snapshot_mode; | |
58f237ca JG |
524 | |
525 | if (print_discarded_events && print_lost_packets) { | |
526 | ret = asprintf(&stats_str, | |
28ab034a JG |
527 | "Warning: %" PRIu64 " events were discarded and %" PRIu64 |
528 | " packets were lost, please refer to " | |
529 | "the documentation on channel configuration.", | |
530 | discarded_events_total, | |
531 | lost_packets_total); | |
58f237ca JG |
532 | } else if (print_discarded_events) { |
533 | ret = asprintf(&stats_str, | |
28ab034a JG |
534 | "Warning: %" PRIu64 " events were discarded, please refer to " |
535 | "the documentation on channel configuration.", | |
536 | discarded_events_total); | |
58f237ca JG |
537 | } else if (print_lost_packets) { |
538 | ret = asprintf(&stats_str, | |
28ab034a JG |
539 | "Warning: %" PRIu64 " packets were lost, please refer to " |
540 | "the documentation on channel configuration.", | |
541 | lost_packets_total); | |
58f237ca JG |
542 | } else { |
543 | ret = 0; | |
20fb9e02 JD |
544 | } |
545 | ||
58f237ca JG |
546 | if (ret < 0) { |
547 | ERR("Failed to format lost packet and discarded events statistics"); | |
548 | } else { | |
549 | *out_str = stats_str; | |
550 | ret = 0; | |
551 | } | |
20fb9e02 | 552 | end: |
3e8f2238 | 553 | free(sessions); |
092545c3 SM |
554 | free(channels); |
555 | free(domains); | |
58f237ca | 556 | return ret; |
20fb9e02 | 557 | } |
4ba92f18 | 558 | |
4fc83d94 | 559 | int show_cmd_help(const char *cmd_name, const char *help_msg) |
4ba92f18 PP |
560 | { |
561 | int ret; | |
562 | char page_name[32]; | |
563 | ||
564 | ret = sprintf(page_name, "lttng-%s", cmd_name); | |
a0377dfe | 565 | LTTNG_ASSERT(ret > 0 && ret < 32); |
4fc83d94 PP |
566 | ret = utils_show_help(1, page_name, help_msg); |
567 | if (ret && !help_msg) { | |
568 | ERR("Cannot view man page `lttng-%s(1)`", cmd_name); | |
569 | perror("exec"); | |
570 | } | |
4ba92f18 | 571 | |
4fc83d94 | 572 | return ret; |
4ba92f18 | 573 | } |
bbbfd849 | 574 | |
28ab034a JG |
575 | int print_trace_archive_location(const struct lttng_trace_archive_location *location, |
576 | const char *session_name) | |
bbbfd849 JG |
577 | { |
578 | int ret = 0; | |
579 | enum lttng_trace_archive_location_type location_type; | |
580 | enum lttng_trace_archive_location_status status; | |
581 | bool printed_location = false; | |
582 | ||
583 | location_type = lttng_trace_archive_location_get_type(location); | |
584 | ||
28ab034a | 585 | _MSG("Trace chunk archive for session %s is now readable", session_name); |
bbbfd849 JG |
586 | switch (location_type) { |
587 | case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL: | |
588 | { | |
589 | const char *absolute_path; | |
590 | ||
28ab034a JG |
591 | status = lttng_trace_archive_location_local_get_absolute_path(location, |
592 | &absolute_path); | |
bbbfd849 JG |
593 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
594 | ret = -1; | |
595 | goto end; | |
596 | } | |
597 | MSG(" at %s", absolute_path); | |
598 | printed_location = true; | |
599 | break; | |
600 | } | |
601 | case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY: | |
602 | { | |
603 | uint16_t control_port, data_port; | |
604 | const char *host, *relative_path, *protocol_str; | |
605 | enum lttng_trace_archive_location_relay_protocol_type protocol; | |
606 | ||
607 | /* Fetch all relay location parameters. */ | |
28ab034a | 608 | status = lttng_trace_archive_location_relay_get_protocol_type(location, &protocol); |
bbbfd849 JG |
609 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
610 | ret = -1; | |
611 | goto end; | |
612 | } | |
613 | ||
28ab034a | 614 | status = lttng_trace_archive_location_relay_get_host(location, &host); |
bbbfd849 JG |
615 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
616 | ret = -1; | |
617 | goto end; | |
618 | } | |
619 | ||
28ab034a JG |
620 | status = lttng_trace_archive_location_relay_get_control_port(location, |
621 | &control_port); | |
bbbfd849 JG |
622 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
623 | ret = -1; | |
624 | goto end; | |
625 | } | |
626 | ||
28ab034a | 627 | status = lttng_trace_archive_location_relay_get_data_port(location, &data_port); |
bbbfd849 JG |
628 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
629 | ret = -1; | |
630 | goto end; | |
631 | } | |
632 | ||
28ab034a JG |
633 | status = lttng_trace_archive_location_relay_get_relative_path(location, |
634 | &relative_path); | |
bbbfd849 JG |
635 | if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) { |
636 | ret = -1; | |
637 | goto end; | |
638 | } | |
639 | ||
640 | switch (protocol) { | |
641 | case LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP: | |
642 | protocol_str = "tcp"; | |
643 | break; | |
644 | default: | |
645 | protocol_str = "unknown"; | |
646 | break; | |
647 | } | |
648 | ||
28ab034a JG |
649 | MSG(" on relay %s://%s/%s [control port %" PRIu16 ", data port %" PRIu16 "]", |
650 | protocol_str, | |
651 | host, | |
652 | relative_path, | |
653 | control_port, | |
654 | data_port); | |
bbbfd849 JG |
655 | printed_location = true; |
656 | break; | |
657 | } | |
658 | default: | |
659 | break; | |
660 | } | |
661 | end: | |
662 | if (!printed_location) { | |
663 | MSG(" at an unknown location"); | |
664 | } | |
665 | return ret; | |
666 | } | |
ca938aa5 OD |
667 | |
668 | namespace { | |
669 | template <typename FilterFunctionType> | |
6e11909e JG |
670 | lttng::cli::session_list get_sessions(const FilterFunctionType& filter, |
671 | bool return_first_match_only = false) | |
ca938aa5 | 672 | { |
f74e820c | 673 | lttng::cli::session_list list = []() { |
ca938aa5 OD |
674 | int list_ret; |
675 | struct lttng_session *psessions; | |
676 | ||
677 | list_ret = lttng_list_sessions(&psessions); | |
678 | ||
679 | if (list_ret < 0) { | |
680 | LTTNG_THROW_CTL("Failed to list sessions", | |
681 | static_cast<lttng_error_code>(list_ret)); | |
682 | } | |
683 | ||
f74e820c JG |
684 | return lttng::cli::session_list(psessions, list_ret); |
685 | }(); | |
ca938aa5 OD |
686 | |
687 | std::size_t write_to = 0; | |
688 | for (std::size_t read_from = 0; read_from < list.size(); ++read_from) { | |
689 | if (!filter(list[read_from])) { | |
690 | continue; | |
691 | } | |
692 | ||
693 | if (read_from != write_to) { | |
694 | list[write_to] = list[read_from]; | |
695 | } | |
696 | ||
697 | ++write_to; | |
698 | ||
699 | if (return_first_match_only) { | |
6e11909e | 700 | return lttng::cli::session_list(std::move(list), 1); |
ca938aa5 OD |
701 | } |
702 | } | |
703 | ||
704 | list.resize(write_to); | |
705 | ||
706 | return list; | |
707 | } | |
708 | } /* namespace */ | |
709 | ||
6e11909e | 710 | lttng::cli::session_list lttng::cli::list_sessions(const struct session_spec& spec) |
ca938aa5 | 711 | { |
42a11b8f | 712 | switch (spec.type_) { |
6e11909e | 713 | case lttng::cli::session_spec::type::NAME: |
ca938aa5 OD |
714 | if (spec.value == nullptr) { |
715 | const auto configured_name = | |
303ac4ed JG |
716 | lttng::make_unique_wrapper<char, lttng::memory::free>( |
717 | get_session_name()); | |
ca938aa5 | 718 | |
0729ea55 JG |
719 | if (!configured_name) { |
720 | LTTNG_THROW_CLI_NO_DEFAULT_SESSION(); | |
9cde3a4a | 721 | } |
e8c353ad | 722 | |
0729ea55 JG |
723 | const struct lttng::cli::session_spec new_spec( |
724 | lttng::cli::session_spec::type::NAME, configured_name.get()); | |
725 | ||
726 | return list_sessions(new_spec); | |
ca938aa5 OD |
727 | } |
728 | ||
729 | return get_sessions( | |
730 | [&spec](const lttng_session& session) { | |
731 | return strcmp(session.name, spec.value) == 0; | |
732 | }, | |
733 | true); | |
6e11909e | 734 | case lttng::cli::session_spec::type::GLOB_PATTERN: |
ca938aa5 OD |
735 | return get_sessions([&spec](const lttng_session& session) { |
736 | return fnmatch(spec.value, session.name, 0) == 0; | |
737 | }); | |
6e11909e | 738 | case lttng::cli::session_spec::type::ALL: |
ca938aa5 OD |
739 | return get_sessions([](const lttng_session&) { return true; }); |
740 | } | |
741 | ||
6e11909e | 742 | return lttng::cli::session_list(); |
ca938aa5 | 743 | } |
4d4c8b8e JG |
744 | |
745 | void print_kernel_tracer_status_error() | |
746 | { | |
747 | if (lttng_opt_mi) { | |
748 | return; | |
749 | } | |
750 | ||
751 | enum lttng_kernel_tracer_status kernel_tracer_status; | |
752 | const auto ret = lttng_get_kernel_tracer_status(&kernel_tracer_status); | |
753 | ||
754 | if (ret < 0) { | |
755 | ERR("Failed to get kernel tracer status: %s", lttng_strerror(ret)); | |
756 | } else { | |
757 | switch (kernel_tracer_status) { | |
758 | case LTTNG_KERNEL_TRACER_STATUS_INITIALIZED: | |
759 | return; | |
760 | case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_UNKNOWN: | |
07c4863f | 761 | std::cerr << "\tKernel module loading failed" << '\n'; |
4d4c8b8e JG |
762 | break; |
763 | case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_MISSING: | |
07c4863f | 764 | std::cerr << "\tMissing one or more required kernel modules" << '\n'; |
4d4c8b8e JG |
765 | break; |
766 | case LTTNG_KERNEL_TRACER_STATUS_ERR_MODULES_SIGNATURE: | |
767 | std::cerr | |
768 | << "\tKernel module signature error prevented loading of one or more required kernel modules" | |
07c4863f | 769 | << '\n'; |
4d4c8b8e JG |
770 | break; |
771 | case LTTNG_KERNEL_TRACER_STATUS_ERR_NEED_ROOT: | |
07c4863f | 772 | std::cerr << "\tlttng-sessiond isn't running as root" << '\n'; |
4d4c8b8e JG |
773 | break; |
774 | case LTTNG_KERNEL_TRACER_STATUS_ERR_NOTIFIER: | |
07c4863f | 775 | std::cerr << "\tFailed to setup notifiers" << '\n'; |
4d4c8b8e JG |
776 | break; |
777 | case LTTNG_KERNEL_TRACER_STATUS_ERR_OPEN_PROC_LTTNG: | |
07c4863f | 778 | std::cerr << "\tlttng-sessiond failed to open /proc/lttng" << '\n'; |
4d4c8b8e JG |
779 | break; |
780 | case LTTNG_KERNEL_TRACER_STATUS_ERR_VERSION_MISMATCH: | |
11927a78 | 781 | std::cerr << "\tVersion mismatch between kernel tracer and kernel tracer ABI" |
07c4863f | 782 | << '\n'; |
4d4c8b8e JG |
783 | break; |
784 | default: | |
785 | std::cerr << lttng::format("\t\tUnknown kernel tracer status (%d)", | |
786 | static_cast<int>(kernel_tracer_status)) | |
07c4863f | 787 | << '\n'; |
4d4c8b8e JG |
788 | break; |
789 | } | |
790 | ||
07c4863f | 791 | std::cerr << "\tConsult lttng-sessiond logs for more information" << '\n'; |
4d4c8b8e JG |
792 | } |
793 | } |