f33e8d0e3d43ff85cd77eab67186f96bef120c26
[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 modify
5 * it under the terms of the GNU General Public License, version 2 only,
6 * as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 */
17
18 #define _GNU_SOURCE
19 #include <inttypes.h>
20 #include <popt.h>
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <assert.h>
25
26 #include <common/mi-lttng.h>
27
28 #include "../command.h"
29
30 static int opt_userspace;
31 static int opt_kernel;
32 static int opt_jul;
33 static char *opt_channel;
34 static int opt_domain;
35 static int opt_fields;
36 #if 0
37 /* Not implemented yet */
38 static char *opt_cmd_name;
39 static pid_t opt_pid;
40 #endif
41
42 const char *indent4 = " ";
43 const char *indent6 = " ";
44 const char *indent8 = " ";
45
46 enum {
47 OPT_HELP = 1,
48 OPT_USERSPACE,
49 OPT_LIST_OPTIONS,
50 };
51
52 static struct lttng_handle *handle;
53 static struct mi_writer *writer;
54
55 static struct poptOption long_options[] = {
56 /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
57 {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
58 {"kernel", 'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
59 {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
60 #if 0
61 /* Not implemented yet */
62 {"userspace", 'u', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_cmd_name, OPT_USERSPACE, 0, 0},
63 {"pid", 'p', POPT_ARG_INT, &opt_pid, 0, 0, 0},
64 #else
65 {"userspace", 'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
66 #endif
67 {"channel", 'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
68 {"domain", 'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
69 {"fields", 'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
70 {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
71 {0, 0, 0, 0, 0, 0, 0}
72 };
73
74 /*
75 * usage
76 */
77 static void usage(FILE *ofp)
78 {
79 fprintf(ofp, "usage: lttng list [OPTIONS] [SESSION [SESSION OPTIONS]]\n");
80 fprintf(ofp, "\n");
81 fprintf(ofp, "With no arguments, list available tracing session(s)\n");
82 fprintf(ofp, "\n");
83 fprintf(ofp, "Without a session, -k lists available kernel events\n");
84 fprintf(ofp, "Without a session, -u lists available userspace events\n");
85 fprintf(ofp, "\n");
86 fprintf(ofp, " -h, --help Show this help\n");
87 fprintf(ofp, " --list-options Simple listing of options\n");
88 fprintf(ofp, " -k, --kernel Select kernel domain\n");
89 fprintf(ofp, " -u, --userspace Select user-space domain.\n");
90 fprintf(ofp, " -j, --jul Apply for Java application using JUL\n");
91 fprintf(ofp, " -f, --fields List event fields.\n");
92 #if 0
93 fprintf(ofp, " -p, --pid PID List user-space events by PID\n");
94 #endif
95 fprintf(ofp, "\n");
96 fprintf(ofp, "Session Options:\n");
97 fprintf(ofp, " -c, --channel NAME List details of a channel\n");
98 fprintf(ofp, " -d, --domain List available domain(s)\n");
99 fprintf(ofp, "\n");
100 }
101
102 /*
103 * Get command line from /proc for a specific pid.
104 *
105 * On success, return an allocated string pointer to the proc cmdline.
106 * On error, return NULL.
107 */
108 static char *get_cmdline_by_pid(pid_t pid)
109 {
110 int ret;
111 FILE *fp;
112 char *cmdline = NULL;
113 char path[20]; /* Can't go bigger than /proc/65535/cmdline */
114
115 snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
116 fp = fopen(path, "r");
117 if (fp == NULL) {
118 goto end;
119 }
120
121 /* Caller must free() *cmdline */
122 cmdline = malloc(PATH_MAX);
123 if (!cmdline) {
124 perror("malloc cmdline");
125 goto end;
126 }
127 ret = fread(cmdline, 1, PATH_MAX, fp);
128 if (ret < 0) {
129 perror("fread proc list");
130 }
131 fclose(fp);
132
133 end:
134 return cmdline;
135 }
136
137 static
138 const char *active_string(int value)
139 {
140 switch (value) {
141 case 0: return "inactive";
142 case 1: return "active";
143 case -1: return "";
144 default: return NULL;
145 }
146 }
147
148 static const char *snapshot_string(int value)
149 {
150 switch (value) {
151 case 1:
152 return " snapshot";
153 default:
154 return "";
155 }
156 }
157
158 static
159 const char *enabled_string(int value)
160 {
161 switch (value) {
162 case 0: return " [disabled]";
163 case 1: return " [enabled]";
164 case -1: return "";
165 default: return NULL;
166 }
167 }
168
169 static
170 const char *filter_string(int value)
171 {
172 switch (value) {
173 case 1: return " [with filter]";
174 default: return "";
175 }
176 }
177
178 static
179 const char *exclusion_string(int value)
180 {
181 switch (value) {
182 case 1: return " [has exclusions]";
183 default: return "";
184 }
185 }
186
187 static const char *logleveltype_string(enum lttng_loglevel_type value)
188 {
189 switch (value) {
190 case LTTNG_EVENT_LOGLEVEL_ALL:
191 return ":";
192 case LTTNG_EVENT_LOGLEVEL_RANGE:
193 return " <=";
194 case LTTNG_EVENT_LOGLEVEL_SINGLE:
195 return " ==";
196 default:
197 return " <<TYPE UNKN>>";
198 }
199 }
200
201 /*
202 * Pretty print single event.
203 */
204 static void print_events(struct lttng_event *event)
205 {
206 switch (event->type) {
207 case LTTNG_EVENT_TRACEPOINT:
208 {
209 if (event->loglevel != -1) {
210 MSG("%s%s (loglevel%s %s (%d)) (type: tracepoint)%s%s%s",
211 indent6,
212 event->name,
213 logleveltype_string(event->loglevel_type),
214 mi_lttng_loglevel_string(event->loglevel),
215 event->loglevel,
216 enabled_string(event->enabled),
217 exclusion_string(event->exclusion),
218 filter_string(event->filter));
219 } else {
220 MSG("%s%s (type: tracepoint)%s%s%s",
221 indent6,
222 event->name,
223 enabled_string(event->enabled),
224 exclusion_string(event->exclusion),
225 filter_string(event->filter));
226 }
227 break;
228 }
229 case LTTNG_EVENT_FUNCTION:
230 MSG("%s%s (type: function)%s%s", indent6,
231 event->name, enabled_string(event->enabled),
232 filter_string(event->filter));
233 if (event->attr.probe.addr != 0) {
234 MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
235 } else {
236 MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
237 MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
238 }
239 break;
240 case LTTNG_EVENT_PROBE:
241 MSG("%s%s (type: probe)%s%s", indent6,
242 event->name, enabled_string(event->enabled),
243 filter_string(event->filter));
244 if (event->attr.probe.addr != 0) {
245 MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
246 } else {
247 MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
248 MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
249 }
250 break;
251 case LTTNG_EVENT_FUNCTION_ENTRY:
252 MSG("%s%s (type: function)%s%s", indent6,
253 event->name, enabled_string(event->enabled),
254 filter_string(event->filter));
255 MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name);
256 break;
257 case LTTNG_EVENT_SYSCALL:
258 MSG("%ssyscalls (type: syscall)%s%s", indent6,
259 enabled_string(event->enabled),
260 filter_string(event->filter));
261 break;
262 case LTTNG_EVENT_NOOP:
263 MSG("%s (type: noop)%s%s", indent6,
264 enabled_string(event->enabled),
265 filter_string(event->filter));
266 break;
267 case LTTNG_EVENT_ALL:
268 /* We should never have "all" events in list. */
269 assert(0);
270 break;
271 }
272 }
273
274 static const char *field_type(struct lttng_event_field *field)
275 {
276 switch(field->type) {
277 case LTTNG_EVENT_FIELD_INTEGER:
278 return "integer";
279 case LTTNG_EVENT_FIELD_ENUM:
280 return "enum";
281 case LTTNG_EVENT_FIELD_FLOAT:
282 return "float";
283 case LTTNG_EVENT_FIELD_STRING:
284 return "string";
285 case LTTNG_EVENT_FIELD_OTHER:
286 default: /* fall-through */
287 return "unknown";
288 }
289 }
290
291 /*
292 * Pretty print single event fields.
293 */
294 static void print_event_field(struct lttng_event_field *field)
295 {
296 if (!field->field_name[0]) {
297 return;
298 }
299 MSG("%sfield: %s (%s)%s", indent8, field->field_name,
300 field_type(field), field->nowrite ? " [no write]" : "");
301 }
302
303 /*
304 * Machine interface
305 * Jul and ust event listing
306 */
307 static int mi_list_jul_ust_events(struct lttng_event *events, int count,
308 struct lttng_domain *domain)
309 {
310 int ret, i;
311 pid_t cur_pid = 0;
312 char *cmdline = NULL;
313 int pid_element_open = 0;
314
315 /* Open domains element */
316 ret = mi_lttng_domains_open(writer);
317 if (ret) {
318 goto end;
319 }
320
321 /* Write domain */
322 ret = mi_lttng_domain(writer, domain, 1);
323 if (ret) {
324 goto end;
325 }
326
327 /* Open pids element */
328 ret = mi_lttng_pids_open(writer);
329 if (ret) {
330 goto end;
331 }
332
333 for (i = 0; i < count; i++) {
334 if (cur_pid != events[i].pid) {
335 if (pid_element_open) {
336 /* Close the previous events and pid element */
337 ret = mi_lttng_close_multi_element(writer, 2);
338 if (ret) {
339 goto end;
340 }
341 pid_element_open = 0;
342 }
343
344 cur_pid = events[i].pid;
345 cmdline = get_cmdline_by_pid(cur_pid);
346 if (!cmdline) {
347 ret = CMD_ERROR;
348 goto end;
349 }
350
351 if (!pid_element_open) {
352 /* Open and write a pid element */
353 ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
354 if (ret) {
355 goto error;
356 }
357
358 /* Open events element */
359 ret = mi_lttng_events_open(writer);
360 if (ret) {
361 goto error;
362 }
363
364 pid_element_open = 1;
365 }
366 free(cmdline);
367 }
368
369 /* Write an event */
370 ret = mi_lttng_event(writer, &events[i], 0);
371 if (ret) {
372 goto end;
373 }
374 }
375
376 /* Close pids */
377 ret = mi_lttng_writer_close_element(writer);
378 if (ret) {
379 goto end;
380 }
381
382 /* Close domain, domains */
383 ret = mi_lttng_close_multi_element(writer, 2);
384 end:
385 return ret;
386 error:
387 free(cmdline);
388 return ret;
389 }
390
391 static int list_jul_events(void)
392 {
393 int i, size, ret = CMD_SUCCESS;
394 struct lttng_domain domain;
395 struct lttng_handle *handle;
396 struct lttng_event *event_list;
397 pid_t cur_pid = 0;
398 char *cmdline = NULL;
399
400 DBG("Getting JUL tracing events");
401
402 memset(&domain, 0, sizeof(domain));
403 domain.type = LTTNG_DOMAIN_JUL;
404
405 handle = lttng_create_handle(NULL, &domain);
406 if (handle == NULL) {
407 ret = CMD_ERROR;
408 goto end;
409 }
410
411 size = lttng_list_tracepoints(handle, &event_list);
412 if (size < 0) {
413 ERR("Unable to list JUL events: %s", lttng_strerror(size));
414 ret = CMD_ERROR;
415 goto end;
416 }
417
418 if (lttng_opt_mi) {
419 /* Mi print */
420 ret = mi_list_jul_ust_events(event_list, size, &domain);
421 if (ret) {
422 ret = CMD_ERROR;
423 goto error;
424 }
425 } else {
426 /* Pretty print */
427 MSG("JUL events (Logger name):\n-------------------------");
428
429 if (size == 0) {
430 MSG("None");
431 }
432
433 for (i = 0; i < size; i++) {
434 if (cur_pid != event_list[i].pid) {
435 cur_pid = event_list[i].pid;
436 cmdline = get_cmdline_by_pid(cur_pid);
437 if (cmdline == NULL) {
438 ret = CMD_ERROR;
439 goto error;
440 }
441 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
442 free(cmdline);
443 }
444 MSG("%s- %s", indent6, event_list[i].name);
445 }
446
447 MSG("");
448 }
449
450 error:
451 free(event_list);
452 end:
453 lttng_destroy_handle(handle);
454 return ret;
455 }
456
457 /*
458 * Ask session daemon for all user space tracepoints available.
459 */
460 static int list_ust_events(void)
461 {
462 int i, size, ret = CMD_SUCCESS;
463 struct lttng_domain domain;
464 struct lttng_handle *handle;
465 struct lttng_event *event_list;
466 pid_t cur_pid = 0;
467 char *cmdline = NULL;
468
469 memset(&domain, 0, sizeof(domain));
470
471 DBG("Getting UST tracing events");
472
473 domain.type = LTTNG_DOMAIN_UST;
474
475 handle = lttng_create_handle(NULL, &domain);
476 if (handle == NULL) {
477 ret = CMD_ERROR;
478 goto end;
479 }
480
481 size = lttng_list_tracepoints(handle, &event_list);
482 if (size < 0) {
483 ERR("Unable to list UST events: %s", lttng_strerror(size));
484 ret = CMD_ERROR;
485 goto error;
486 }
487
488 if (lttng_opt_mi) {
489 /* Mi print */
490 ret = mi_list_jul_ust_events(event_list, size, &domain);
491 } else {
492 /* Pretty print */
493 MSG("UST events:\n-------------");
494
495 if (size == 0) {
496 MSG("None");
497 }
498
499 for (i = 0; i < size; i++) {
500 if (cur_pid != event_list[i].pid) {
501 cur_pid = event_list[i].pid;
502 cmdline = get_cmdline_by_pid(cur_pid);
503 if (cmdline == NULL) {
504 ret = CMD_ERROR;
505 goto error;
506 }
507 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
508 free(cmdline);
509 }
510 print_events(&event_list[i]);
511 }
512
513 MSG("");
514 }
515
516 error:
517 free(event_list);
518 end:
519 lttng_destroy_handle(handle);
520 return ret;
521 }
522
523 /*
524 * Machine interface
525 * List all ust event with their fields
526 */
527 static int mi_list_ust_event_fields(struct lttng_event_field *fields, int count,
528 struct lttng_domain *domain)
529 {
530 int ret, i;
531 pid_t cur_pid = 0;
532 char *cmdline = NULL;
533 int pid_element_open = 0;
534 int event_element_open = 0;
535 struct lttng_event cur_event;
536
537 /* Open domains element */
538 ret = mi_lttng_domains_open(writer);
539 if (ret) {
540 goto end;
541 }
542
543 /* Write domain */
544 ret = mi_lttng_domain(writer, domain, 1);
545 if (ret) {
546 goto end;
547 }
548
549 /* Open pids element */
550 ret = mi_lttng_pids_open(writer);
551 if (ret) {
552 goto end;
553 }
554
555 for (i = 0; i < count; i++) {
556 if (cur_pid != fields[i].event.pid) {
557 if (pid_element_open) {
558 if (event_element_open) {
559
560 /* Close the previous field element and event. */
561 ret = mi_lttng_close_multi_element(writer, 2);
562 if (ret) {
563 goto end;
564 }
565 event_element_open = 0;
566 }
567 /* Close the previous events, pid element */
568 ret = mi_lttng_close_multi_element(writer, 2);
569 if (ret) {
570 goto end;
571 }
572 pid_element_open = 0;
573 }
574
575 cur_pid = fields[i].event.pid;
576 cmdline = get_cmdline_by_pid(cur_pid);
577 if (!pid_element_open) {
578 /* Open and write a pid element */
579 ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
580 if (ret) {
581 goto error;
582 }
583
584 /* Open events element */
585 ret = mi_lttng_events_open(writer);
586 if (ret) {
587 goto error;
588 }
589 pid_element_open = 1;
590 }
591 free(cmdline);
592 /* Wipe current event since we are about to print a new PID. */
593 memset(&cur_event, 0, sizeof(cur_event));
594 }
595
596 if (strcmp(cur_event.name, fields[i].event.name) != 0) {
597 if (event_element_open) {
598 /* Close the previous fields element and the previous event */
599 ret = mi_lttng_close_multi_element(writer, 2);
600 if (ret) {
601 goto end;
602 }
603 event_element_open = 0;
604 }
605
606 memcpy(&cur_event, &fields[i].event,
607 sizeof(cur_event));
608
609 if (!event_element_open) {
610 /* Open and write the event */
611 ret = mi_lttng_event(writer, &cur_event, 1);
612 if (ret) {
613 goto end;
614 }
615
616 /* Open a fields element */
617 ret = mi_lttng_event_fields_open(writer);
618 if (ret) {
619 goto end;
620 }
621 event_element_open = 1;
622 }
623 }
624
625 /* Print the event_field */
626 ret = mi_lttng_event_field(writer, &fields[i]);
627 if (ret) {
628 goto end;
629 }
630 }
631
632 /* Close pids, domain, domains */
633 ret = mi_lttng_close_multi_element(writer, 3);
634 end:
635 return ret;
636 error:
637 free(cmdline);
638 return ret;
639 }
640
641 /*
642 * Ask session daemon for all user space tracepoint fields available.
643 */
644 static int list_ust_event_fields(void)
645 {
646 int i, size, ret = CMD_SUCCESS;
647 struct lttng_domain domain;
648 struct lttng_handle *handle;
649 struct lttng_event_field *event_field_list;
650 pid_t cur_pid = 0;
651 char *cmdline = NULL;
652
653 struct lttng_event cur_event;
654
655 memset(&domain, 0, sizeof(domain));
656 memset(&cur_event, 0, sizeof(cur_event));
657
658 DBG("Getting UST tracing event fields");
659
660 domain.type = LTTNG_DOMAIN_UST;
661
662 handle = lttng_create_handle(NULL, &domain);
663 if (handle == NULL) {
664 ret = CMD_ERROR;
665 goto end;
666 }
667
668 size = lttng_list_tracepoint_fields(handle, &event_field_list);
669 if (size < 0) {
670 ERR("Unable to list UST event fields: %s", lttng_strerror(size));
671 ret = CMD_ERROR;
672 goto end;
673 }
674
675 if (lttng_opt_mi) {
676 /* Mi print */
677 ret = mi_list_ust_event_fields(event_field_list, size, &domain);
678 if (ret) {
679 ret = CMD_ERROR;
680 goto error;
681 }
682 } else {
683 /* Pretty print */
684 MSG("UST events:\n-------------");
685
686 if (size == 0) {
687 MSG("None");
688 }
689
690 for (i = 0; i < size; i++) {
691 if (cur_pid != event_field_list[i].event.pid) {
692 cur_pid = event_field_list[i].event.pid;
693 cmdline = get_cmdline_by_pid(cur_pid);
694 if (cmdline == NULL) {
695 ret = CMD_ERROR;
696 goto error;
697 }
698 MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
699 free(cmdline);
700 /* Wipe current event since we are about to print a new PID. */
701 memset(&cur_event, 0, sizeof(cur_event));
702 }
703 if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
704 print_events(&event_field_list[i].event);
705 memcpy(&cur_event, &event_field_list[i].event,
706 sizeof(cur_event));
707 }
708 print_event_field(&event_field_list[i]);
709 }
710
711 MSG("");
712 }
713
714 error:
715 free(event_field_list);
716 end:
717 lttng_destroy_handle(handle);
718 return ret;
719 }
720
721 /*
722 * Machine interface
723 * Print a list of kernel events
724 */
725 static int mi_list_kernel_events(struct lttng_event *events, int count,
726 struct lttng_domain *domain)
727 {
728 int ret, i;
729
730 /* Open domains element */
731 ret = mi_lttng_domains_open(writer);
732 if (ret) {
733 goto end;
734 }
735
736 /* Write domain */
737 ret = mi_lttng_domain(writer, domain, 1);
738 if (ret) {
739 goto end;
740 }
741
742 /* Open events */
743 ret = mi_lttng_events_open(writer);
744 if (ret) {
745 goto end;
746 }
747
748 for (i = 0; i < count; i++) {
749 mi_lttng_event(writer, &events[i], 0);
750 if (ret) {
751 goto end;
752 }
753 }
754
755 /* close events, domain and domains */
756 ret = mi_lttng_close_multi_element(writer, 3);
757 if (ret) {
758 goto end;
759 }
760
761 end:
762 return ret;
763 }
764
765 /*
766 * Ask for all trace events in the kernel
767 */
768 static int list_kernel_events(void)
769 {
770 int i, size, ret = CMD_SUCCESS;
771 struct lttng_domain domain;
772 struct lttng_handle *handle;
773 struct lttng_event *event_list;
774
775 memset(&domain, 0, sizeof(domain));
776
777 DBG("Getting kernel tracing events");
778
779 domain.type = LTTNG_DOMAIN_KERNEL;
780
781 handle = lttng_create_handle(NULL, &domain);
782 if (handle == NULL) {
783 ret = CMD_ERROR;
784 goto error;
785 }
786
787 size = lttng_list_tracepoints(handle, &event_list);
788 if (size < 0) {
789 ERR("Unable to list kernel events: %s", lttng_strerror(size));
790 lttng_destroy_handle(handle);
791 return CMD_ERROR;
792 }
793
794 if (lttng_opt_mi) {
795 /* Mi print */
796 ret = mi_list_kernel_events(event_list, size, &domain);
797 if (ret) {
798 ret = CMD_ERROR;
799 goto end;
800 }
801 } else {
802 MSG("Kernel events:\n-------------");
803
804 for (i = 0; i < size; i++) {
805 print_events(&event_list[i]);
806 }
807
808 MSG("");
809 }
810
811 end:
812 free(event_list);
813
814 lttng_destroy_handle(handle);
815 return ret;
816
817 error:
818 lttng_destroy_handle(handle);
819 return ret;
820 }
821
822 /*
823 * Machine Interface
824 * Print a list of jul events
825 */
826 static int mi_list_session_jul_events(struct lttng_event *events, int count)
827 {
828 int ret, i;
829
830 /* Open events element */
831 ret = mi_lttng_events_open(writer);
832 if (ret) {
833 goto end;
834 }
835
836 for (i = 0; i < count; i++) {
837 ret = mi_lttng_event(writer, &events[i], 0);
838 if (ret) {
839 goto end;
840 }
841 }
842
843 /* Close events element */
844 ret = mi_lttng_writer_close_element(writer);
845
846 end:
847 return ret;
848 }
849
850 /*
851 * List JUL events for a specific session using the handle.
852 *
853 * Return CMD_SUCCESS on success else a negative value.
854 */
855 static int list_session_jul_events(void)
856 {
857 int ret = CMD_SUCCESS, count, i;
858 struct lttng_event *events = NULL;
859
860 count = lttng_list_events(handle, "", &events);
861 if (count < 0) {
862 ret = CMD_ERROR;
863 ERR("%s", lttng_strerror(count));
864 goto error;
865 }
866
867 if (lttng_opt_mi) {
868 /* Mi print */
869 ret = mi_list_session_jul_events(events, count);
870 if (ret) {
871 ret = CMD_ERROR;
872 goto end;
873 }
874 } else {
875 /* Pretty print */
876 MSG("Events (Logger name):\n---------------------");
877 if (count == 0) {
878 MSG("%sNone\n", indent6);
879 goto end;
880 }
881
882 for (i = 0; i < count; i++) {
883 MSG("%s- %s%s (loglevel%s %s)", indent4, events[i].name,
884 enabled_string(events[i].enabled),
885 logleveltype_string(events[i].loglevel_type),
886 mi_lttng_loglevel_string(events[i].loglevel));
887 }
888
889 MSG("");
890 }
891
892 end:
893 free(events);
894 error:
895 return ret;
896 }
897
898 /*
899 * Machine interface
900 * print a list of event
901 */
902 static int mi_list_events(struct lttng_event *events, int count)
903 {
904 int ret, i;
905
906 /* Open events element */
907 ret = mi_lttng_events_open(writer);
908 if (ret) {
909 goto end;
910 }
911
912 for (i = 0; i < count; i++) {
913 ret = mi_lttng_event(writer, &events[i], 0);
914 if (ret) {
915 goto end;
916 }
917 }
918
919 /* Close events element */
920 ret = mi_lttng_writer_close_element(writer);
921
922 end:
923 return ret;
924 }
925
926 /*
927 * List events of channel of session and domain.
928 */
929 static int list_events(const char *channel_name)
930 {
931 int ret = CMD_SUCCESS, count, i;
932 struct lttng_event *events = NULL;
933
934 count = lttng_list_events(handle, channel_name, &events);
935 if (count < 0) {
936 ret = CMD_ERROR;
937 ERR("%s", lttng_strerror(count));
938 goto error;
939 }
940
941 if (lttng_opt_mi) {
942 /* Mi print */
943 ret = mi_list_events(events, count);
944 if (ret) {
945 ret = CMD_ERROR;
946 goto end;
947 }
948 } else {
949 /* Pretty print */
950 MSG("\n%sEvents:", indent4);
951 if (count == 0) {
952 MSG("%sNone\n", indent6);
953 goto end;
954 }
955
956 for (i = 0; i < count; i++) {
957 print_events(&events[i]);
958 }
959
960 MSG("");
961 }
962 end:
963 free(events);
964 error:
965 return ret;
966 }
967
968 /*
969 * Pretty print channel
970 */
971 static void print_channel(struct lttng_channel *channel)
972 {
973 MSG("- %s:%s\n", channel->name, enabled_string(channel->enabled));
974
975 MSG("%sAttributes:", indent4);
976 MSG("%soverwrite mode: %d", indent6, channel->attr.overwrite);
977 MSG("%ssubbufers size: %" PRIu64, indent6, channel->attr.subbuf_size);
978 MSG("%snumber of subbufers: %" PRIu64, indent6, channel->attr.num_subbuf);
979 MSG("%sswitch timer interval: %u", indent6, channel->attr.switch_timer_interval);
980 MSG("%sread timer interval: %u", indent6, channel->attr.read_timer_interval);
981 MSG("%strace file count: %" PRIu64, indent6, channel->attr.tracefile_count);
982 MSG("%strace file size (bytes): %" PRIu64, indent6, channel->attr.tracefile_size);
983 switch (channel->attr.output) {
984 case LTTNG_EVENT_SPLICE:
985 MSG("%soutput: splice()", indent6);
986 break;
987 case LTTNG_EVENT_MMAP:
988 MSG("%soutput: mmap()", indent6);
989 break;
990 }
991 }
992
993 /*
994 * Machine interface
995 * Print a list of channel
996 *
997 */
998 static int mi_list_channels(struct lttng_channel *channels, int count,
999 const char *channel_name)
1000 {
1001 int i, ret;
1002 unsigned int chan_found = 0;
1003
1004 /* Open channels element */
1005 ret = mi_lttng_channels_open(writer);
1006 if (ret) {
1007 goto error;
1008 }
1009
1010 for (i = 0; i < count; i++) {
1011 if (channel_name != NULL) {
1012 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
1013 chan_found = 1;
1014 } else {
1015 continue;
1016 }
1017 }
1018
1019 /* Write channel element and leave it open */
1020 ret = mi_lttng_channel(writer, &channels[i], 1);
1021 if (ret) {
1022 goto error;
1023 }
1024
1025 /* Listing events per channel */
1026 ret = list_events(channels[i].name);
1027 if (ret) {
1028 goto error;
1029 }
1030
1031 /* Closing the channel element we opened earlier */
1032 ret = mi_lttng_writer_close_element(writer);
1033 if (ret) {
1034 goto error;
1035 }
1036
1037 if (chan_found) {
1038 break;
1039 }
1040 }
1041
1042 /* Close channels element */
1043 ret = mi_lttng_writer_close_element(writer);
1044 if (ret) {
1045 goto error;
1046 }
1047
1048 error:
1049 return ret;
1050 }
1051
1052 /*
1053 * List channel(s) of session and domain.
1054 *
1055 * If channel_name is NULL, all channels are listed.
1056 */
1057 static int list_channels(const char *channel_name)
1058 {
1059 int count, i, ret = CMD_SUCCESS;
1060 unsigned int chan_found = 0;
1061 struct lttng_channel *channels = NULL;
1062
1063 DBG("Listing channel(s) (%s)", channel_name ? : "<all>");
1064
1065 count = lttng_list_channels(handle, &channels);
1066 if (count < 0) {
1067 switch (-count) {
1068 case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
1069 if (lttng_opt_mi) {
1070 /* When printing mi this is not an error
1071 * but an empty channels element */
1072 count = 0;
1073 } else {
1074 ret = CMD_SUCCESS;
1075 WARN("No kernel channel");
1076 goto error_channels;
1077 }
1078 break;
1079 default:
1080 /* We had a real error */
1081 ret = CMD_ERROR;
1082 ERR("%s", lttng_strerror(count));
1083 goto error_channels;
1084 break;
1085 }
1086 }
1087
1088 if (lttng_opt_mi) {
1089 /* Mi print */
1090 ret = mi_list_channels(channels, count, channel_name);
1091 if (ret) {
1092 ret = CMD_ERROR;
1093 goto error;
1094 }
1095 } else {
1096 /* Pretty print */
1097 if (channel_name == NULL) {
1098 MSG("Channels:\n-------------");
1099 }
1100
1101 for (i = 0; i < count; i++) {
1102 if (channel_name != NULL) {
1103 if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
1104 chan_found = 1;
1105 } else {
1106 continue;
1107 }
1108 }
1109 print_channel(&channels[i]);
1110
1111 /* Listing events per channel */
1112 ret = list_events(channels[i].name);
1113 if (ret) {
1114 goto error;
1115 }
1116
1117 if (chan_found) {
1118 break;
1119 }
1120 }
1121
1122 if (!chan_found && channel_name != NULL) {
1123 ret = CMD_ERROR;
1124 ERR("Channel %s not found", channel_name);
1125 goto error;
1126 }
1127 }
1128 error:
1129 free(channels);
1130
1131 error_channels:
1132 return ret;
1133 }
1134
1135 /*
1136 * Machine interface
1137 * Find the session with session_name as name
1138 * and print his informations.
1139 */
1140 static int mi_list_session(const char *session_name,
1141 struct lttng_session *sessions, int count)
1142 {
1143 int ret, i;
1144 unsigned int session_found = 0;
1145
1146 if (session_name == NULL) {
1147 ret = -LTTNG_ERR_SESS_NOT_FOUND;
1148 goto end;
1149 }
1150
1151 for (i = 0; i < count; i++) {
1152 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
1153 /* We need to leave it open to append other informations
1154 * like domain, channel, events etc.*/
1155 session_found = 1;
1156 ret = mi_lttng_session(writer, &sessions[i], 1);
1157 if (ret) {
1158 goto end;
1159 }
1160 break;
1161 }
1162 }
1163
1164 if (!session_found) {
1165 ERR("Session '%s' not found", session_name);
1166 ret = -LTTNG_ERR_SESS_NOT_FOUND;
1167 goto end;
1168 }
1169
1170 end:
1171 return ret;
1172 }
1173
1174 /*
1175 * Machine interface
1176 * List all availables session
1177 */
1178 static int mi_list_sessions(struct lttng_session *sessions, int count)
1179 {
1180 int ret, i;
1181
1182 /* Opening sessions element */
1183 ret = mi_lttng_sessions_open(writer);
1184 if (ret) {
1185 goto end;
1186 }
1187
1188 /* Listing sessions */
1189 for (i = 0; i < count; i++) {
1190 ret = mi_lttng_session(writer, &sessions[i], 0);
1191 if (ret) {
1192 goto end;
1193 }
1194 }
1195
1196 /* Closing sessions element */
1197 ret = mi_lttng_writer_close_element(writer);
1198 if (ret) {
1199 goto end;
1200 }
1201
1202 end:
1203 return ret;
1204 }
1205
1206 /*
1207 * List available tracing session. List only basic information.
1208 *
1209 * If session_name is NULL, all sessions are listed.
1210 */
1211 static int list_sessions(const char *session_name)
1212 {
1213 int ret = CMD_SUCCESS;
1214 int count, i;
1215 unsigned int session_found = 0;
1216 struct lttng_session *sessions;
1217
1218 count = lttng_list_sessions(&sessions);
1219 DBG("Session count %d", count);
1220 if (count < 0) {
1221 ret = CMD_ERROR;
1222 ERR("%s", lttng_strerror(count));
1223 goto end;
1224 }
1225
1226 if (lttng_opt_mi) {
1227 /* Mi */
1228 if (session_name == NULL) {
1229 /* List all session */
1230 ret = mi_list_sessions(sessions, count);
1231 } else {
1232 /* Note : this return an open session element */
1233 ret = mi_list_session(session_name, sessions, count);
1234 }
1235 if (ret) {
1236 ret = CMD_ERROR;
1237 goto error;
1238 }
1239 } else {
1240 /* Pretty print */
1241 if (count == 0) {
1242 MSG("Currently no available tracing session");
1243 ret = CMD_ERROR;
1244 goto end;
1245 }
1246
1247 if (session_name == NULL) {
1248 MSG("Available tracing sessions:");
1249 }
1250
1251
1252 for (i = 0; i < count; i++) {
1253 if (session_name != NULL) {
1254 if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
1255 session_found = 1;
1256 MSG("Tracing session %s: [%s%s]", session_name,
1257 active_string(sessions[i].enabled),
1258 snapshot_string(sessions[i].snapshot_mode));
1259 MSG("%sTrace path: %s\n", indent4, sessions[i].path);
1260 break;
1261 }
1262 } else {
1263 MSG(" %d) %s (%s) [%s%s]", i + 1,
1264 sessions[i].name, sessions[i].path,
1265 active_string(sessions[i].enabled),
1266 snapshot_string(sessions[i].snapshot_mode));
1267 MSG("%sTrace path: %s", indent4, sessions[i].path);
1268 MSG("%sLive timer interval (usec): %u\n", indent4,
1269 sessions[i].live_timer_interval);
1270 break;
1271 }
1272 }
1273
1274 if (!session_found && session_name != NULL) {
1275 ERR("Session '%s' not found", session_name);
1276 ret = CMD_ERROR;
1277 goto error;
1278 }
1279
1280 if (session_name == NULL) {
1281 MSG("\nUse lttng list <session_name> for more details");
1282 }
1283 }
1284
1285 error:
1286 free(sessions);
1287 end:
1288 return ret;
1289 }
1290
1291
1292 /*
1293 * Machine Interface
1294 * list available domain(s) for a session.
1295 */
1296 static int mi_list_domains(struct lttng_domain *domains, int count)
1297 {
1298 int i, ret;
1299 /* Open domains element */
1300 ret = mi_lttng_domains_open(writer);
1301 if (ret) {
1302 goto end;
1303 }
1304
1305 for (i = 0; i < count; i++) {
1306 ret = mi_lttng_domain(writer, &domains[i] , 0);
1307 if (ret) {
1308 goto end;
1309 }
1310 }
1311
1312 /* Closing domains element */
1313 ret = mi_lttng_writer_close_element(writer);
1314 if (ret) {
1315 goto end;
1316 }
1317 end:
1318 return ret;
1319 }
1320
1321 /*
1322 * List available domain(s) for a session.
1323 */
1324 static int list_domains(const char *session_name)
1325 {
1326 int i, count, ret = CMD_SUCCESS;
1327 struct lttng_domain *domains = NULL;
1328
1329
1330 count = lttng_list_domains(session_name, &domains);
1331 if (count < 0) {
1332 ret = CMD_ERROR;
1333 ERR("%s", lttng_strerror(count));
1334 goto end;
1335 }
1336
1337 if (lttng_opt_mi) {
1338 /* Mi output */
1339 ret = mi_list_domains(domains, count);
1340 if (ret) {
1341 ret = CMD_ERROR;
1342 goto error;
1343 }
1344 } else {
1345 /* Pretty print */
1346 MSG("Domains:\n-------------");
1347 if (count == 0) {
1348 MSG(" None");
1349 goto end;
1350 }
1351
1352 for (i = 0; i < count; i++) {
1353 switch (domains[i].type) {
1354 case LTTNG_DOMAIN_KERNEL:
1355 MSG(" - Kernel");
1356 break;
1357 case LTTNG_DOMAIN_UST:
1358 MSG(" - UST global");
1359 break;
1360 case LTTNG_DOMAIN_JUL:
1361 MSG(" - JUL (Java Util Logging)");
1362 break;
1363 default:
1364 break;
1365 }
1366 }
1367 }
1368
1369 error:
1370 free(domains);
1371
1372 end:
1373 return ret;
1374 }
1375
1376 /*
1377 * The 'list <options>' first level command
1378 */
1379 int cmd_list(int argc, const char **argv)
1380 {
1381 int opt, ret = CMD_SUCCESS;
1382 const char *session_name;
1383 static poptContext pc;
1384 struct lttng_domain domain;
1385 struct lttng_domain *domains = NULL;
1386
1387 memset(&domain, 0, sizeof(domain));
1388
1389 if (argc < 1) {
1390 usage(stderr);
1391 ret = CMD_ERROR;
1392 goto end;
1393 }
1394
1395 pc = poptGetContext(NULL, argc, argv, long_options, 0);
1396 poptReadDefaultConfig(pc, 0);
1397
1398 while ((opt = poptGetNextOpt(pc)) != -1) {
1399 switch (opt) {
1400 case OPT_HELP:
1401 usage(stdout);
1402 goto end;
1403 case OPT_USERSPACE:
1404 opt_userspace = 1;
1405 break;
1406 case OPT_LIST_OPTIONS:
1407 list_cmd_options(stdout, long_options);
1408 goto end;
1409 default:
1410 usage(stderr);
1411 ret = CMD_UNDEFINED;
1412 goto end;
1413 }
1414 }
1415
1416 /* Mi check */
1417 if (lttng_opt_mi) {
1418 writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
1419 if (!writer) {
1420 ret = CMD_ERROR;
1421 goto end;
1422 }
1423
1424 /* Open command element */
1425 ret = mi_lttng_writer_command_open(writer,
1426 mi_lttng_element_command_list);
1427 if (ret) {
1428 ret = CMD_ERROR;
1429 goto end;
1430 }
1431
1432 /* Open output element */
1433 ret = mi_lttng_writer_open_element(writer,
1434 mi_lttng_element_command_output);
1435 if (ret) {
1436 ret = CMD_ERROR;
1437 goto end;
1438 }
1439 }
1440
1441 /* Get session name (trailing argument) */
1442 session_name = poptGetArg(pc);
1443 DBG2("Session name: %s", session_name);
1444
1445 if (opt_kernel) {
1446 domain.type = LTTNG_DOMAIN_KERNEL;
1447 } else if (opt_userspace) {
1448 DBG2("Listing userspace global domain");
1449 domain.type = LTTNG_DOMAIN_UST;
1450 } else if (opt_jul) {
1451 DBG2("Listing JUL domain");
1452 domain.type = LTTNG_DOMAIN_JUL;
1453 }
1454
1455 if (opt_kernel || opt_userspace || opt_jul) {
1456 handle = lttng_create_handle(session_name, &domain);
1457 if (handle == NULL) {
1458 ret = CMD_FATAL;
1459 goto end;
1460 }
1461 }
1462
1463 if (session_name == NULL) {
1464 if (!opt_kernel && !opt_userspace && !opt_jul) {
1465 ret = list_sessions(NULL);
1466 if (ret) {
1467 goto end;
1468 }
1469 }
1470 if (opt_kernel) {
1471 ret = list_kernel_events();
1472 if (ret) {
1473 goto end;
1474 }
1475 }
1476 if (opt_userspace) {
1477 if (opt_fields) {
1478 ret = list_ust_event_fields();
1479 } else {
1480 ret = list_ust_events();
1481 }
1482 if (ret) {
1483 goto end;
1484 }
1485 }
1486 if (opt_jul) {
1487 ret = list_jul_events();
1488 if (ret) {
1489 goto end;
1490 }
1491 }
1492 } else {
1493 /* List session attributes */
1494 if (lttng_opt_mi) {
1495 /* Open element sessions
1496 * Present for xml consistency */
1497 ret = mi_lttng_sessions_open(writer);
1498 if (ret) {
1499 goto end;
1500 }
1501 }
1502 /* MI: the ouptut of list_sessions is an unclosed session element */
1503 ret = list_sessions(session_name);
1504 if (ret) {
1505 goto end;
1506 }
1507
1508 /* Domain listing */
1509 if (opt_domain) {
1510 ret = list_domains(session_name);
1511 goto end;
1512 }
1513
1514 /* Channel listing */
1515 if (opt_kernel || opt_userspace) {
1516 if (lttng_opt_mi) {
1517 /* Add of domains and domain element for xml
1518 * consistency and validation
1519 */
1520 ret = mi_lttng_domains_open(writer);
1521 if (ret) {
1522 goto end;
1523 }
1524
1525 /* Open domain and leave it open for
1526 * nested channels printing */
1527 ret = mi_lttng_domain(writer, &domain, 1);
1528 if (ret) {
1529 goto end;
1530 }
1531
1532 }
1533
1534 ret = list_channels(opt_channel);
1535 if (ret) {
1536 goto end;
1537 }
1538
1539 if (lttng_opt_mi) {
1540 /* Close domain and domain element */
1541 ret = mi_lttng_close_multi_element(writer, 2);
1542 }
1543 if (ret) {
1544 goto end;
1545 }
1546
1547
1548 } else {
1549 int i, nb_domain;
1550
1551 /* We want all domain(s) */
1552 nb_domain = lttng_list_domains(session_name, &domains);
1553 if (nb_domain < 0) {
1554 ret = CMD_ERROR;
1555 ERR("%s", lttng_strerror(nb_domain));
1556 goto end;
1557 }
1558
1559 if (lttng_opt_mi) {
1560 ret = mi_lttng_domains_open(writer);
1561 if (ret) {
1562 ret = CMD_ERROR;
1563 goto end;
1564 }
1565 }
1566
1567 for (i = 0; i < nb_domain; i++) {
1568 switch (domains[i].type) {
1569 case LTTNG_DOMAIN_KERNEL:
1570 MSG("=== Domain: Kernel ===\n");
1571 break;
1572 case LTTNG_DOMAIN_UST:
1573 MSG("=== Domain: UST global ===\n");
1574 MSG("Buffer type: %s\n",
1575 domains[i].buf_type ==
1576 LTTNG_BUFFER_PER_PID ? "per PID" : "per UID");
1577 break;
1578 case LTTNG_DOMAIN_JUL:
1579 MSG("=== Domain: JUL (Java Util Logging) ===\n");
1580 break;
1581 default:
1582 MSG("=== Domain: Unimplemented ===\n");
1583 break;
1584 }
1585
1586 if (lttng_opt_mi) {
1587 ret = mi_lttng_domain(writer, &domains[i], 1);
1588 if (ret) {
1589 ret = CMD_ERROR;
1590 goto end;
1591 }
1592 }
1593
1594 /* Clean handle before creating a new one */
1595 if (handle) {
1596 lttng_destroy_handle(handle);
1597 }
1598
1599 handle = lttng_create_handle(session_name, &domains[i]);
1600 if (handle == NULL) {
1601 ret = CMD_FATAL;
1602 goto end;
1603 }
1604
1605 if (domains[i].type == LTTNG_DOMAIN_JUL) {
1606 ret = list_session_jul_events();
1607 if (ret) {
1608 goto end;
1609 }
1610 continue;
1611 }
1612
1613 ret = list_channels(opt_channel);
1614 if (ret) {
1615 goto end;
1616 }
1617
1618 if (lttng_opt_mi) {
1619 /* Close domain element */
1620 ret = mi_lttng_writer_close_element(writer);
1621 if (ret) {
1622 ret = CMD_ERROR;
1623 goto end;
1624 }
1625 }
1626
1627 }
1628 if (lttng_opt_mi) {
1629 /* Close the domains, session and sessions element */
1630 ret = mi_lttng_close_multi_element(writer, 3);
1631 if (ret) {
1632 ret = CMD_ERROR;
1633 goto end;
1634 }
1635 }
1636 }
1637 }
1638
1639 /* Mi closing */
1640 if (lttng_opt_mi) {
1641 /* Close output element */
1642 ret = mi_lttng_writer_close_element(writer);
1643 if (ret) {
1644 ret = CMD_ERROR;
1645 goto end;
1646 }
1647
1648 /* Command element close */
1649 ret = mi_lttng_writer_command_close(writer);
1650 if (ret) {
1651 ret = CMD_ERROR;
1652 goto end;
1653 }
1654 }
1655 end:
1656 /* Mi clean-up */
1657 if (writer && mi_lttng_writer_destroy(writer)) {
1658 /* Preserve original error code */
1659 ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
1660 }
1661
1662 free(domains);
1663 if (handle) {
1664 lttng_destroy_handle(handle);
1665 }
1666
1667 poptFreeContext(pc);
1668 return ret;
1669 }
This page took 0.104838 seconds and 3 git commands to generate.