Disable lttng ust domain not implemented
[lttng-tools.git] / src / bin / lttng / commands / list.c
1 /*
2 * Copyright (C) 2011 - David Goulet <david.goulet@polymtl.ca>
3 *
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; only version 2
7 * of the License.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17 */
18
19 #define _GNU_SOURCE
20 #include <inttypes.h>
21 #include <popt.h>
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
25 #include <assert.h>
26
27 #include "../command.h"
28
29 static int opt_userspace;
30 static int opt_kernel;
31 static char *opt_channel;
32 static int opt_domain;
33 #if 0
34 /* Not implemented yet */
35 static char *opt_cmd_name;
36 static pid_t opt_pid;
37 #endif
38
39 const char *indent4 = " ";
40 const char *indent6 = " ";
41 const char *indent8 = " ";
42
43 enum {
44 OPT_HELP = 1,
45 OPT_USERSPACE,
46 };
47
48 static struct lttng_handle *handle;
49
50 static struct poptOption long_options[] = {
51 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
52 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
53 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
54 #if 0
55 /* Not implemented yet */
56 {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
57 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
58 #else
59 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
60 #endif
61 {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
62 {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
63 {0, 0, 0, 0, 0, 0, 0}
64 };
65
66 /*
67 * usage
68 */
69 static void usage(FILE *ofp)
70 {
71 fprintf(ofp, "usage: lttng list [[-k] [-u] [-p PID] [SESSION [<options>]]]\n");
72 fprintf(ofp, "\n");
73 fprintf(ofp, "With no arguments, list available tracing session(s)\n");
74 fprintf(ofp, "\n");
75 fprintf(ofp, "With -k alone, list available kernel events\n");
76 fprintf(ofp, "With -u alone, list available userspace events\n");
77 fprintf(ofp, "\n");
78 fprintf(ofp, " -h, --help Show this help\n");
79 fprintf(ofp, " -k, --kernel Select kernel domain\n");
80 fprintf(ofp, " -u, --userspace Select user-space domain.\n");
81 #if 0
82 fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
83 #endif
84 fprintf(ofp, "\n");
85 fprintf(ofp, "Options:\n");
86 fprintf(ofp, " -c, --channel NAME List details of a channel\n");
87 fprintf(ofp, " -d, --domain List available domain(s)\n");
88 fprintf(ofp, "\n");
89 }
90
91 /*
92 * Get command line from /proc for a specific pid.
93 *
94 * On success, return an allocated string pointer to the proc cmdline.
95 * On error, return NULL.
96 */
97 static char *get_cmdline_by_pid(pid_t pid)
98 {
99 int ret;
100 FILE *fp;
101 char *cmdline = NULL;
102 char path[24]; /* Can't go bigger than /proc/65535/cmdline */
103
104 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
105 fp = fopen(path, "r");
106 if (fp == NULL) {
107 goto end;
108 }
109
110 /* Caller must free() *cmdline */
111 cmdline = malloc(PATH_MAX);
112 ret = fread(cmdline, 1, PATH_MAX, fp);
113 if (ret < 0) {
114 perror("fread proc list");
115 }
116 fclose(fp);
117
118 end:
119 return cmdline;
120 }
121
122 static
123 const char *active_string(int value)
124 {
125 switch (value) {
126 case 0: return " [inactive]";
127 case 1: return " [active]";
128 case -1: return "";
129 default: return NULL;
130 }
131 }
132
133 static
134 const char *enabled_string(int value)
135 {
136 switch (value) {
137 case 0: return " [disabled]";
138 case 1: return " [enabled]";
139 case -1: return "";
140 default: return NULL;
141 }
142 }
143
144 static
145 const char *loglevel_string_pre(const char *loglevel)
146 {
147 if (loglevel[0] == '\0') {
148 return "";
149 } else {
150 return " (loglevel: ";
151 }
152 }
153
154 static
155 const char *loglevel_string_post(const char *loglevel)
156 {
157 if (loglevel[0] == '\0') {
158 return "";
159 } else {
160 return ")";
161 }
162 }
163
164 /*
165 * Pretty print single event.
166 */
167 static void print_events(struct lttng_event *event)
168 {
169 switch (event->type) {
170 case LTTNG_EVENT_TRACEPOINT:
171 {
172 char ll_value[LTTNG_SYMBOL_NAME_LEN] = "";
173
174 if (event->loglevel[0] != '\0') {
175 int ret;
176
177 ret = snprintf(ll_value, LTTNG_SYMBOL_NAME_LEN,
178 " (%lld)", (long long) event->loglevel_value);
179 if (ret < 0)
180 ERR("snprintf error");
181 }
182 MSG("%s%s%s%s%s%s (type: tracepoint)%s", indent6,
183 event->name,
184 loglevel_string_pre(event->loglevel),
185 event->loglevel,
186 ll_value,
187 loglevel_string_post(event->loglevel),
188 enabled_string(event->enabled));
189 break;
190 }
191 case LTTNG_EVENT_PROBE:
192 MSG("%s%s (type: probe)%s", indent6,
193 event->name, enabled_string(event->enabled));
194 if (event->attr.probe.addr != 0) {
195 MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
196 } else {
197 MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
198 MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
199 }
200 break;
201 case LTTNG_EVENT_FUNCTION:
202 case LTTNG_EVENT_FUNCTION_ENTRY:
203 MSG("%s%s (type: function)%s", indent6,
204 event->name, enabled_string(event->enabled));
205 MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name);
206 break;
207 case LTTNG_EVENT_SYSCALL:
208 MSG("%s (type: syscall)%s", indent6,
209 enabled_string(event->enabled));
210 break;
211 case LTTNG_EVENT_NOOP:
212 MSG("%s (type: noop)%s", indent6,
213 enabled_string(event->enabled));
214 break;
215 case LTTNG_EVENT_TRACEPOINT_LOGLEVEL:
216 MSG("%s%s (type: tracepoint loglevel)%s", indent6,
217 event->name,
218 enabled_string(event->enabled));
219 break;
220 case LTTNG_EVENT_ALL:
221 /* We should never have "all" events in list. */
222 assert(0);
223 break;
224 }
225 }
226
227 /*
228 * Ask session daemon for all user space tracepoints available.
229 */
230 static int list_ust_events(void)
231 {
232 int i, size;
233 struct lttng_domain domain;
234 struct lttng_handle *handle;
235 struct lttng_event *event_list;
236 pid_t cur_pid = 0;
237
238 DBG("Getting UST tracing events");
239
240 domain.type = LTTNG_DOMAIN_UST;
241
242 handle = lttng_create_handle(NULL, &domain);
243 if (handle == NULL) {
244 goto error;
245 }
246
247 size = lttng_list_tracepoints(handle, &event_list);
248 if (size < 0) {
249 ERR("Unable to list UST events");
250 return size;
251 }
252
253 MSG("UST events:\n-------------");
254
255 if (size == 0) {
256 MSG("None");
257 }
258
259 for (i = 0; i < size; i++) {
260 if (cur_pid != event_list[i].pid) {
261 cur_pid = event_list[i].pid;
262 MSG("\nPID: %d - Name: %s", cur_pid, get_cmdline_by_pid(cur_pid));
263 }
264 print_events(&event_list[i]);
265 }
266
267 MSG("");
268
269 free(event_list);
270
271 return CMD_SUCCESS;
272
273 error:
274 return -1;
275 }
276
277 /*
278 * Ask for all trace events in the kernel and pretty print them.
279 */
280 static int list_kernel_events(void)
281 {
282 int i, size;
283 struct lttng_domain domain;
284 struct lttng_handle *handle;
285 struct lttng_event *event_list;
286
287 DBG("Getting kernel tracing events");
288
289 domain.type = LTTNG_DOMAIN_KERNEL;
290
291 handle = lttng_create_handle(NULL, &domain);
292 if (handle == NULL) {
293 goto error;
294 }
295
296 size = lttng_list_tracepoints(handle, &event_list);
297 if (size < 0) {
298 ERR("Unable to list kernel events");
299 return size;
300 }
301
302 MSG("Kernel events:\n-------------");
303
304 for (i = 0; i < size; i++) {
305 print_events(&event_list[i]);
306 }
307
308 MSG("");
309
310 free(event_list);
311
312 return CMD_SUCCESS;
313
314 error:
315 return -1;
316 }
317
318 /*
319 * List events of channel of session and domain.
320 */
321 static int list_events(const char *channel_name)
322 {
323 int ret, count, i;
324 struct lttng_event *events = NULL;
325
326 count = lttng_list_events(handle, channel_name, &events);
327 if (count < 0) {
328 ret = count;
329 goto error;
330 }
331
332 MSG("\n%sEvents:", indent4);
333 if (count == 0) {
334 MSG("%sNone\n", indent6);
335 goto end;
336 }
337
338 for (i = 0; i < count; i++) {
339 print_events(&events[i]);
340 }
341
342 MSG("");
343
344 end:
345 if (events) {
346 free(events);
347 }
348 ret = CMD_SUCCESS;
349
350 error:
351 return ret;
352 }
353
354 /*
355 * Pretty print channel
356 */
357 static void print_channel(struct lttng_channel *channel)
358 {
359 MSG("- %s:%s\n", channel->name, enabled_string(channel->enabled));
360
361 MSG("%sAttributes:", indent4);
362 MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite);
363 MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size);
364 MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf);
365 MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval);
366 MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval);
367 switch (channel->attr.output) {
368 case LTTNG_EVENT_SPLICE:
369 MSG("%soutput: splice()", indent6);
370 break;
371 case LTTNG_EVENT_MMAP:
372 MSG("%soutput: mmap()", indent6);
373 break;
374 }
375 }
376
377 /*
378 * List channel(s) of session and domain.
379 *
380 * If channel_name is NULL, all channels are listed.
381 */
382 static int list_channels(const char *channel_name)
383 {
384 int count, i, ret = CMD_SUCCESS;
385 unsigned int chan_found = 0;
386 struct lttng_channel *channels = NULL;
387
388 DBG("Listing channel(s) (%s)", channel_name ? : "<all>");
389
390 count = lttng_list_channels(handle, &channels);
391 if (count < 0) {
392 ret = count;
393 goto error;
394 } else if (count == 0) {
395 MSG("No channel found");
396 goto end;
397 }
398
399 if (channel_name == NULL) {
400 MSG("Channels:\n-------------");
401 }
402
403 for (i = 0; i < count; i++) {
404 if (channel_name != NULL) {
405 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
406 chan_found = 1;
407 } else {
408 continue;
409 }
410 }
411 print_channel(&channels[i]);
412
413 /* Listing events per channel */
414 ret = list_events(channels[i].name);
415 if (ret < 0) {
416 MSG("%s", lttng_strerror(ret));
417 }
418
419 if (chan_found) {
420 break;
421 }
422 }
423
424 if (!chan_found && channel_name != NULL) {
425 MSG("Channel %s not found", channel_name);
426 }
427
428 end:
429 free(channels);
430 ret = CMD_SUCCESS;
431
432 error:
433 return ret;
434 }
435
436 /*
437 * List available tracing session. List only basic information.
438 *
439 * If session_name is NULL, all sessions are listed.
440 */
441 static int list_sessions(const char *session_name)
442 {
443 int ret, count, i;
444 unsigned int session_found = 0;
445 struct lttng_session *sessions;
446
447 count = lttng_list_sessions(&sessions);
448 DBG("Session count %d", count);
449 if (count < 0) {
450 ret = count;
451 goto error;
452 }
453
454 if (session_name == NULL) {
455 MSG("Available tracing sessions:");
456 }
457
458 for (i = 0; i < count; i++) {
459 if (session_name != NULL) {
460 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
461 session_found = 1;
462 MSG("Tracing session %s:%s", session_name, active_string(sessions[i].enabled));
463 MSG("%sTrace path: %s\n", indent4, sessions[i].path);
464 break;
465 }
466 continue;
467 }
468
469 MSG(" %d) %s (%s)%s", i + 1, sessions[i].name, sessions[i].path, active_string(sessions[i].enabled));
470
471 if (session_found) {
472 break;
473 }
474 }
475
476 free(sessions);
477
478 if (!session_found && session_name != NULL) {
479 MSG("Session %s not found", session_name);
480 }
481
482 if (session_name == NULL) {
483 MSG("\nUse lttng list <session_name> for more details");
484 }
485
486 return CMD_SUCCESS;
487
488 error:
489 return ret;
490 }
491
492 /*
493 * List available domain(s) for a session.
494 */
495 static int list_domains(const char *session_name)
496 {
497 int i, count, ret = CMD_SUCCESS;
498 struct lttng_domain *domains = NULL;
499
500 MSG("Domains:\n-------------");
501
502 count = lttng_list_domains(session_name, &domains);
503 if (count < 0) {
504 ret = count;
505 goto error;
506 } else if (count == 0) {
507 MSG(" None");
508 goto end;
509 }
510
511 for (i = 0; i < count; i++) {
512 switch (domains[i].type) {
513 case LTTNG_DOMAIN_KERNEL:
514 MSG(" - Kernel");
515 break;
516 case LTTNG_DOMAIN_UST:
517 MSG(" - UST global");
518 break;
519 default:
520 break;
521 }
522 }
523
524 end:
525 free(domains);
526
527 error:
528 return ret;
529 }
530
531 /*
532 * The 'list <options>' first level command
533 */
534 int cmd_list(int argc, const char **argv)
535 {
536 int opt, i, ret = CMD_SUCCESS;
537 int nb_domain;
538 const char *session_name;
539 static poptContext pc;
540 struct lttng_domain domain;
541 struct lttng_domain *domains = NULL;
542
543 if (argc < 1) {
544 usage(stderr);
545 goto end;
546 }
547
548 pc = poptGetContext(NULL, argc, argv, long_options, 0);
549 poptReadDefaultConfig(pc, 0);
550
551 while ((opt = poptGetNextOpt(pc)) != -1) {
552 switch (opt) {
553 case OPT_HELP:
554 usage(stderr);
555 goto end;
556 case OPT_USERSPACE:
557 opt_userspace = 1;
558 break;
559 default:
560 usage(stderr);
561 ret = CMD_UNDEFINED;
562 goto end;
563 }
564 }
565
566 /* Get session name (trailing argument) */
567 session_name = poptGetArg(pc);
568 DBG2("Session name: %s", session_name);
569
570 if (opt_kernel) {
571 domain.type = LTTNG_DOMAIN_KERNEL;
572 } else if (opt_userspace) {
573 DBG2("Listing userspace global domain");
574 domain.type = LTTNG_DOMAIN_UST;
575 }
576
577 handle = lttng_create_handle(session_name, &domain);
578 if (handle == NULL) {
579 goto end;
580 }
581
582 if (session_name == NULL) {
583 if (!opt_kernel && !opt_userspace) {
584 ret = list_sessions(NULL);
585 if (ret < 0) {
586 goto end;
587 }
588 }
589 if (opt_kernel) {
590 ret = list_kernel_events();
591 if (ret < 0) {
592 goto end;
593 }
594 }
595 if (opt_userspace) {
596 ret = list_ust_events();
597 if (ret < 0) {
598 goto end;
599 }
600 }
601 } else {
602 /* List session attributes */
603 ret = list_sessions(session_name);
604 if (ret < 0) {
605 goto end;
606 }
607
608 /* Domain listing */
609 if (opt_domain) {
610 ret = list_domains(session_name);
611 goto end;
612 }
613
614 if (opt_kernel) {
615 /* Channel listing */
616 ret = list_channels(opt_channel);
617 if (ret < 0) {
618 goto end;
619 }
620 } else {
621 /* We want all domain(s) */
622 nb_domain = lttng_list_domains(session_name, &domains);
623 if (nb_domain < 0) {
624 ret = nb_domain;
625 goto end;
626 }
627
628 for (i = 0; i < nb_domain; i++) {
629 switch (domains[i].type) {
630 case LTTNG_DOMAIN_KERNEL:
631 MSG("=== Domain: Kernel ===\n");
632 break;
633 case LTTNG_DOMAIN_UST:
634 MSG("=== Domain: UST global ===\n");
635 break;
636 default:
637 MSG("=== Domain: Unimplemented ===\n");
638 break;
639 }
640
641 /* Clean handle before creating a new one */
642 lttng_destroy_handle(handle);
643
644 handle = lttng_create_handle(session_name, &domains[i]);
645 if (handle == NULL) {
646 goto end;
647 }
648
649 ret = list_channels(opt_channel);
650 if (ret < 0) {
651 goto end;
652 }
653 }
654 }
655 }
656
657 end:
658 if (domains) {
659 free(domains);
660 }
661 lttng_destroy_handle(handle);
662
663 return ret;
664 }
This page took 0.042516 seconds and 4 git commands to generate.