Mi: support for command list
authorJonathan Rajotte <jonathan.r.julien@gmail.com>
Wed, 16 Apr 2014 21:03:31 +0000 (17:03 -0400)
committerJonathan Rajotte Julien <jonathan.r.julien@gmail.com>
Tue, 22 Jul 2014 20:14:56 +0000 (16:14 -0400)
Signed-off-by: Jonathan Rajotte <jonathan.r.julien@gmail.com>
include/lttng/lttng-error.h
src/bin/lttng/commands/list.c

index 6083959131c68d3ba3324861d6eef2ad1bda3b02..e6c30d6604c491034a65fb5ba35aa4794782108c 100644 (file)
@@ -111,10 +111,9 @@ enum lttng_error_code {
        LTTNG_ERR_LOAD_IO_FAIL           = 88,  /* IO error while reading a session configuration */
        LTTNG_ERR_LOAD_SESSION_NOENT     = 89,  /* Session file not found */
        LTTNG_ERR_MAX_SIZE_INVALID       = 90,  /* Snapshot max size is invalid. */
-       LTTNG_ERR_MI_OUTPUT_TYPE         = 91, /* Invalid MI output format */
-       LTTNG_ERR_MI_IO_FAIL             = 92, /* IO error while writing machine interface output */
-       LTTNG_ERR_MI_NOT_IMPLEMENTED     = 93, /* Mi feature not implemented */
-       /* 93 */
+       LTTNG_ERR_MI_OUTPUT_TYPE         = 91,  /* Invalid MI output format */
+       LTTNG_ERR_MI_IO_FAIL             = 92,  /* IO error while writing machine interface output */
+       LTTNG_ERR_MI_NOT_IMPLEMENTED     = 93,  /* Mi feature not implemented */
        /* 94 */
        /* 95 */
        /* 96 */
index d25b5632bb85513e40d028b21ae9c6335c8e5c20..2dd0dc8a331d0a34e09764ce1b3217c9d6e1bcf7 100644 (file)
@@ -23,6 +23,8 @@
 #include <string.h>
 #include <assert.h>
 
+#include <common/mi-lttng.h>
+
 #include "../command.h"
 
 static int opt_userspace;
@@ -48,6 +50,7 @@ enum {
 };
 
 static struct lttng_handle *handle;
+static struct mi_writer *writer;
 
 static struct poptOption long_options[] = {
        /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
@@ -209,46 +212,6 @@ static const char *loglevel_jul_string(int value)
        }
 }
 
-static const char *loglevel_string(int value)
-{
-       switch (value) {
-       case -1:
-               return "";
-       case LTTNG_LOGLEVEL_EMERG:
-               return "TRACE_EMERG";
-       case LTTNG_LOGLEVEL_ALERT:
-               return "TRACE_ALERT";
-       case LTTNG_LOGLEVEL_CRIT:
-               return "TRACE_CRIT";
-       case LTTNG_LOGLEVEL_ERR:
-               return "TRACE_ERR";
-       case LTTNG_LOGLEVEL_WARNING:
-               return "TRACE_WARNING";
-       case LTTNG_LOGLEVEL_NOTICE:
-               return "TRACE_NOTICE";
-       case LTTNG_LOGLEVEL_INFO:
-               return "TRACE_INFO";
-       case LTTNG_LOGLEVEL_DEBUG_SYSTEM:
-               return "TRACE_DEBUG_SYSTEM";
-       case LTTNG_LOGLEVEL_DEBUG_PROGRAM:
-               return "TRACE_DEBUG_PROGRAM";
-       case LTTNG_LOGLEVEL_DEBUG_PROCESS:
-               return "TRACE_DEBUG_PROCESS";
-       case LTTNG_LOGLEVEL_DEBUG_MODULE:
-               return "TRACE_DEBUG_MODULE";
-       case LTTNG_LOGLEVEL_DEBUG_UNIT:
-               return "TRACE_DEBUG_UNIT";
-       case LTTNG_LOGLEVEL_DEBUG_FUNCTION:
-               return "TRACE_DEBUG_FUNCTION";
-       case LTTNG_LOGLEVEL_DEBUG_LINE:
-               return "TRACE_DEBUG_LINE";
-       case LTTNG_LOGLEVEL_DEBUG:
-               return "TRACE_DEBUG";
-       default:
-               return "<<UNKNOWN>>";
-       }
-}
-
 static const char *logleveltype_string(enum lttng_loglevel_type value)
 {
        switch (value) {
@@ -276,7 +239,7 @@ static void print_events(struct lttng_event *event)
                                indent6,
                                event->name,
                                logleveltype_string(event->loglevel_type),
-                               loglevel_string(event->loglevel),
+                               mi_lttng_loglevel_string(event->loglevel),
                                event->loglevel,
                                enabled_string(event->enabled),
                                exclusion_string(event->exclusion),
@@ -365,9 +328,97 @@ static void print_event_field(struct lttng_event_field *field)
                field_type(field), field->nowrite ? " [no write]" : "");
 }
 
+/*
+ * Machine interface
+ * Jul and ust event listing
+ */
+static int mi_list_jul_ust_events(struct lttng_event *events, int count,
+               struct lttng_domain *domain)
+{
+       int ret, i;
+       pid_t cur_pid = 0;
+       char *cmdline = NULL;
+       int pid_element_open = 0;
+
+       /* Open domains element */
+       ret = mi_lttng_domains_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open pids element */
+       ret = mi_lttng_pids_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (cur_pid != events[i].pid) {
+                       if (pid_element_open) {
+                               /* Close the previous events and  pid element */
+                               ret = mi_lttng_close_multi_element(writer, 2);
+                               if (ret) {
+                                       goto end;
+                               }
+                               pid_element_open = 0;
+                       }
+
+                       cur_pid = events[i].pid;
+                       cmdline = get_cmdline_by_pid(cur_pid);
+                       if (!cmdline) {
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (!pid_element_open) {
+                               /* Open and write a pid element */
+                               ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               /* Open events element */
+                               ret = mi_lttng_events_open(writer);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               pid_element_open = 1;
+                       }
+                       free(cmdline);
+               }
+
+               /* Write an event */
+               ret = mi_lttng_event(writer, &events[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close pids */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close domain, domains */
+       ret = mi_lttng_close_multi_element(writer, 2);
+end:
+       return ret;
+error:
+       free(cmdline);
+       return ret;
+}
+
 static int list_jul_events(void)
 {
-       int i, size;
+       int i, size, ret = CMD_SUCCESS;
        struct lttng_domain domain;
        struct lttng_handle *handle;
        struct lttng_event *event_list;
@@ -381,42 +432,54 @@ static int list_jul_events(void)
 
        handle = lttng_create_handle(NULL, &domain);
        if (handle == NULL) {
-               goto error;
+               ret = CMD_ERROR;
+               goto end;
        }
 
        size = lttng_list_tracepoints(handle, &event_list);
        if (size < 0) {
                ERR("Unable to list JUL events: %s", lttng_strerror(size));
-               lttng_destroy_handle(handle);
-               return size;
-       }
-
-       MSG("JUL events (Logger name):\n-------------------------");
-
-       if (size == 0) {
-               MSG("None");
+               ret = CMD_ERROR;
+               goto end;
        }
 
-       for (i = 0; i < size; i++) {
-               if (cur_pid != event_list[i].pid) {
-                       cur_pid = event_list[i].pid;
-                       cmdline = get_cmdline_by_pid(cur_pid);
-                       MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
-                       free(cmdline);
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_jul_ust_events(event_list, size, &domain);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
                }
-               MSG("%s- %s", indent6, event_list[i].name);
-       }
+       } else {
+               /* Pretty print */
+               MSG("JUL events (Logger name):\n-------------------------");
 
-       MSG("");
+               if (size == 0) {
+                       MSG("None");
+               }
 
-       free(event_list);
-       lttng_destroy_handle(handle);
+               for (i = 0; i < size; i++) {
+                       if (cur_pid != event_list[i].pid) {
+                               cur_pid = event_list[i].pid;
+                               cmdline = get_cmdline_by_pid(cur_pid);
+                               if (cmdline == NULL) {
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
+                               free(cmdline);
+                       }
+                       MSG("%s- %s", indent6, event_list[i].name);
+               }
 
-       return CMD_SUCCESS;
+               MSG("");
+       }
 
 error:
+       free(event_list);
+end:
        lttng_destroy_handle(handle);
-       return -1;
+       return ret;
 }
 
 /*
@@ -424,7 +487,7 @@ error:
  */
 static int list_ust_events(void)
 {
-       int i, size;
+       int i, size, ret = CMD_SUCCESS;
        struct lttng_domain domain;
        struct lttng_handle *handle;
        struct lttng_event *event_list;
@@ -439,42 +502,170 @@ static int list_ust_events(void)
 
        handle = lttng_create_handle(NULL, &domain);
        if (handle == NULL) {
-               goto error;
+               ret = CMD_ERROR;
+               goto end;
        }
 
        size = lttng_list_tracepoints(handle, &event_list);
        if (size < 0) {
                ERR("Unable to list UST events: %s", lttng_strerror(size));
-               lttng_destroy_handle(handle);
-               return size;
+               ret = CMD_ERROR;
+               goto error;
        }
 
-       MSG("UST events:\n-------------");
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_jul_ust_events(event_list, size, &domain);
+       } else {
+               /* Pretty print */
+               MSG("UST events:\n-------------");
+
+               if (size == 0) {
+                       MSG("None");
+               }
+
+               for (i = 0; i < size; i++) {
+                       if (cur_pid != event_list[i].pid) {
+                               cur_pid = event_list[i].pid;
+                               cmdline = get_cmdline_by_pid(cur_pid);
+                               if (cmdline == NULL) {
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
+                               free(cmdline);
+                       }
+                       print_events(&event_list[i]);
+               }
 
-       if (size == 0) {
-               MSG("None");
+               MSG("");
        }
 
-       for (i = 0; i < size; i++) {
-               if (cur_pid != event_list[i].pid) {
-                       cur_pid = event_list[i].pid;
+error:
+       free(event_list);
+end:
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ * Machine interface
+ * List all ust event with their fields
+ */
+static int mi_list_ust_event_fields(struct lttng_event_field *fields, int count,
+               struct lttng_domain *domain)
+{
+       int ret, i;
+       pid_t cur_pid = 0;
+       char *cmdline = NULL;
+       int pid_element_open = 0;
+       int event_element_open = 0;
+       struct lttng_event cur_event;
+
+       /* Open domains element */
+       ret = mi_lttng_domains_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open pids element */
+       ret = mi_lttng_pids_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (cur_pid != fields[i].event.pid) {
+                       if (pid_element_open) {
+                               if (event_element_open) {
+                                       /* 
+                                        * Close the previous fields element
+                                        * and the previous event
+                                        */
+                                       ret = mi_lttng_close_multi_element(writer, 2);
+                                       if (ret) {
+                                               goto end;
+                                       }
+                                       event_element_open = 0;
+                               }
+                               /* Close the previous events, pid element */
+                               ret = mi_lttng_close_multi_element(writer, 2);
+                               if (ret) {
+                                       goto end;
+                               }
+                               pid_element_open = 0;
+                       }
+
+                       cur_pid = fields[i].event.pid;
                        cmdline = get_cmdline_by_pid(cur_pid);
-                       MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
+                       if (!pid_element_open) {
+                               /* Open and write a pid element */
+                               ret = mi_lttng_pid(writer, cur_pid, cmdline, 1);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               /* Open events element */
+                               ret = mi_lttng_events_open(writer);
+                               if (ret) {
+                                       goto error;
+                               }
+                               pid_element_open = 1;
+                       }
                        free(cmdline);
+                       /* Wipe current event since we are about to print a new PID. */
+                       memset(&cur_event, 0, sizeof(cur_event));
                }
-               print_events(&event_list[i]);
-       }
 
-       MSG("");
+               if (strcmp(cur_event.name, fields[i].event.name) != 0) {
+                       if (event_element_open) {
+                               /* Close the previous fields element and the previous event */
+                               ret = mi_lttng_close_multi_element(writer, 2);
+                               if (ret) {
+                                       goto end;
+                               }
+                               event_element_open = 0;
+                       }
+
+                       memcpy(&cur_event, &fields[i].event,
+                                       sizeof(cur_event));
 
-       free(event_list);
-       lttng_destroy_handle(handle);
+                       if (!event_element_open) {
+                               /* Open and write the event */
+                               ret = mi_lttng_event(writer, &cur_event, 1);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                               /* Open a fields element */
+                               ret = mi_lttng_event_fields_open(writer);
+                               if (ret) {
+                                       goto end;
+                               }
+                               event_element_open = 1;
+                       }
+               }
 
-       return CMD_SUCCESS;
+               /* Print the event_field */
+               ret = mi_lttng_event_field(writer, &fields[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
 
+       /* Close pids, domain, domains */
+       ret = mi_lttng_close_multi_element(writer, 3);
+end:
+       return ret;
 error:
-       lttng_destroy_handle(handle);
-       return -1;
+       free(cmdline);
+       return ret;
 }
 
 /*
@@ -482,7 +673,7 @@ error:
  */
 static int list_ust_event_fields(void)
 {
-       int i, size;
+       int i, size, ret = CMD_SUCCESS;
        struct lttng_domain domain;
        struct lttng_handle *handle;
        struct lttng_event_field *event_field_list;
@@ -500,57 +691,113 @@ static int list_ust_event_fields(void)
 
        handle = lttng_create_handle(NULL, &domain);
        if (handle == NULL) {
-               goto error;
+               ret = CMD_ERROR;
+               goto end;
        }
 
        size = lttng_list_tracepoint_fields(handle, &event_field_list);
        if (size < 0) {
                ERR("Unable to list UST event fields: %s", lttng_strerror(size));
-               lttng_destroy_handle(handle);
-               return size;
+               ret = CMD_ERROR;
+               goto end;
        }
 
-       MSG("UST events:\n-------------");
-
-       if (size == 0) {
-               MSG("None");
-       }
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_ust_event_fields(event_field_list, size, &domain);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* Pretty print */
+               MSG("UST events:\n-------------");
 
-       for (i = 0; i < size; i++) {
-               if (cur_pid != event_field_list[i].event.pid) {
-                       cur_pid = event_field_list[i].event.pid;
-                       cmdline = get_cmdline_by_pid(cur_pid);
-                       MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
-                       free(cmdline);
-                       /* Wipe current event since we are about to print a new PID. */
-                       memset(&cur_event, 0, sizeof(cur_event));
+               if (size == 0) {
+                       MSG("None");
                }
-               if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
-                       print_events(&event_field_list[i].event);
-                       memcpy(&cur_event, &event_field_list[i].event,
-                               sizeof(cur_event));
+
+               for (i = 0; i < size; i++) {
+                       if (cur_pid != event_field_list[i].event.pid) {
+                               cur_pid = event_field_list[i].event.pid;
+                               cmdline = get_cmdline_by_pid(cur_pid);
+                               if (cmdline == NULL) {
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               MSG("\nPID: %d - Name: %s", cur_pid, cmdline);
+                               free(cmdline);
+                               /* Wipe current event since we are about to print a new PID. */
+                               memset(&cur_event, 0, sizeof(cur_event));
+                       }
+                       if (strcmp(cur_event.name, event_field_list[i].event.name) != 0) {
+                               print_events(&event_field_list[i].event);
+                               memcpy(&cur_event, &event_field_list[i].event,
+                                               sizeof(cur_event));
+                       }
+                       print_event_field(&event_field_list[i]);
                }
-               print_event_field(&event_field_list[i]);
-       }
 
-       MSG("");
+               MSG("");
+       }
 
+error:
        free(event_field_list);
+end:
        lttng_destroy_handle(handle);
+       return ret;
+}
 
-       return CMD_SUCCESS;
+/*
+ * Machine interface
+ * Print a list of kernel events
+ */
+static int mi_list_kernel_events(struct lttng_event *events, int count,
+               struct lttng_domain *domain)
+{
+       int ret, i;
 
-error:
-       lttng_destroy_handle(handle);
-       return -1;
+       /* Open domains element */
+       ret = mi_lttng_domains_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open events */
+       ret = mi_lttng_events_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               mi_lttng_event(writer, &events[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* close events, domain and domains */
+       ret = mi_lttng_close_multi_element(writer, 3);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
 }
 
 /*
- * Ask for all trace events in the kernel and pretty print them.
+ * Ask for all trace events in the kernel
  */
 static int list_kernel_events(void)
 {
-       int i, size;
+       int i, size, ret = CMD_SUCCESS;
        struct lttng_domain domain;
        struct lttng_handle *handle;
        struct lttng_event *event_list;
@@ -563,6 +810,7 @@ static int list_kernel_events(void)
 
        handle = lttng_create_handle(NULL, &domain);
        if (handle == NULL) {
+               ret = CMD_ERROR;
                goto error;
        }
 
@@ -570,25 +818,63 @@ static int list_kernel_events(void)
        if (size < 0) {
                ERR("Unable to list kernel events: %s", lttng_strerror(size));
                lttng_destroy_handle(handle);
-               return size;
+               return CMD_ERROR;
        }
 
-       MSG("Kernel events:\n-------------");
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_kernel_events(event_list, size, &domain);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               MSG("Kernel events:\n-------------");
 
-       for (i = 0; i < size; i++) {
-               print_events(&event_list[i]);
-       }
+               for (i = 0; i < size; i++) {
+                       print_events(&event_list[i]);
+               }
 
-       MSG("");
+               MSG("");
+       }
 
+end:
        free(event_list);
 
        lttng_destroy_handle(handle);
-       return CMD_SUCCESS;
+       return ret;
 
 error:
        lttng_destroy_handle(handle);
-       return -1;
+       return ret;
+}
+
+/*
+ * Machine Interface
+ * Print a list of jul events
+ */
+static int mi_list_session_jul_events(struct lttng_event *events, int count)
+{
+       int ret, i;
+
+       /* Open events element */
+       ret = mi_lttng_events_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_event(writer, &events[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close events element */
+       ret = mi_lttng_writer_close_element(writer);
+
+end:
+       return ret;
 }
 
 /*
@@ -598,36 +884,72 @@ error:
  */
 static int list_session_jul_events(void)
 {
-       int ret, count, i;
+       int ret = CMD_SUCCESS, count, i;
        struct lttng_event *events = NULL;
 
        count = lttng_list_events(handle, "", &events);
        if (count < 0) {
-               ret = count;
-               ERR("%s", lttng_strerror(ret));
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
                goto error;
        }
 
-       MSG("Events (Logger name):\n---------------------");
-       if (count == 0) {
-               MSG("%sNone\n", indent6);
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_session_jul_events(events, count);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               /* Pretty print */
+               MSG("Events (Logger name):\n---------------------");
+               if (count == 0) {
+                       MSG("%sNone\n", indent6);
+                       goto end;
+               }
+
+               for (i = 0; i < count; i++) {
+                       MSG("%s- %s%s (loglevel%s %s)", indent4, events[i].name,
+                                       enabled_string(events[i].enabled),
+                                       logleveltype_string(events[i].loglevel_type),
+                                       loglevel_jul_string(events[i].loglevel));
+               }
+
+               MSG("");
+       }
+
+end:
+       free(events);
+error:
+       return ret;
+}
+
+/*
+ * Machine interface
+ * print a list of event
+ */
+static int mi_list_events(struct lttng_event *events, int count)
+{
+       int ret, i;
+
+       /* Open events element */
+       ret = mi_lttng_events_open(writer);
+       if (ret) {
                goto end;
        }
 
        for (i = 0; i < count; i++) {
-               MSG("%s- %s%s (loglevel%s %s)", indent4, events[i].name,
-                               enabled_string(events[i].enabled),
-                               logleveltype_string(events[i].loglevel_type),
-                               loglevel_jul_string(events[i].loglevel));
+               ret = mi_lttng_event(writer, &events[i], 0);
+               if (ret) {
+                       goto end;
+               }
        }
 
-       MSG("");
+       /* Close events element */
+       ret = mi_lttng_writer_close_element(writer);
 
 end:
-       free(events);
-       ret = CMD_SUCCESS;
-
-error:
        return ret;
 }
 
@@ -636,32 +958,39 @@ error:
  */
 static int list_events(const char *channel_name)
 {
-       int ret, count, i;
+       int ret = CMD_SUCCESS, count, i;
        struct lttng_event *events = NULL;
 
        count = lttng_list_events(handle, channel_name, &events);
        if (count < 0) {
-               ret = count;
-               ERR("%s", lttng_strerror(ret));
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
                goto error;
        }
 
-       MSG("\n%sEvents:", indent4);
-       if (count == 0) {
-               MSG("%sNone\n", indent6);
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               print_events(&events[i]);
-       }
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_events(events, count);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               /* Pretty print */
+               MSG("\n%sEvents:", indent4);
+               if (count == 0) {
+                       MSG("%sNone\n", indent6);
+                       goto end;
+               }
 
-       MSG("");
+               for (i = 0; i < count; i++) {
+                       print_events(&events[i]);
+               }
 
+               MSG("");
+       }
 end:
        free(events);
-       ret = CMD_SUCCESS;
-
 error:
        return ret;
 }
@@ -691,6 +1020,65 @@ static void print_channel(struct lttng_channel *channel)
        }
 }
 
+/*
+ * Machine interface
+ * Print a list of channel
+ *
+ */
+static int mi_list_channels(struct lttng_channel *channels, int count,
+               const char *channel_name)
+{
+       int i, ret;
+       unsigned int chan_found = 0;
+
+       /* Open channels element */
+       ret = mi_lttng_channels_open(writer);
+       if (ret) {
+               goto error;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (channel_name != NULL) {
+                       if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
+                               chan_found = 1;
+                       } else {
+                               continue;
+                       }
+               }
+
+               /* Write channel element  and leave it open */
+               ret = mi_lttng_channel(writer, &channels[i], 1);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Listing events per channel */
+               ret = list_events(channels[i].name);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Closing the channel element we opened earlier */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+
+               if (chan_found) {
+                       break;
+               }
+       }
+
+       /* Close channels element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
 /*
  * List channel(s) of session and domain.
  *
@@ -708,54 +1096,140 @@ static int list_channels(const char *channel_name)
        if (count < 0) {
                switch (-count) {
                case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
-                       ret = CMD_SUCCESS;
-                       WARN("No kernel channel");
+                       if (lttng_opt_mi) {
+                               /* When printing mi this is not an error
+                                * but an empty channels element */
+                               count = 0;
+                       } else {
+                               ret = CMD_SUCCESS;
+                               WARN("No kernel channel");
+                               goto error_channels;
+                       }
                        break;
                default:
                        /* We had a real error */
-                       ret = count;
-                       ERR("%s", lttng_strerror(ret));
+                       ret = CMD_ERROR;
+                       ERR("%s", lttng_strerror(count));
+                       goto error_channels;
                        break;
                }
-               goto error_channels;
        }
 
-       if (channel_name == NULL) {
-               MSG("Channels:\n-------------");
-       }
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_channels(channels, count, channel_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* Pretty print */
+               if (channel_name == NULL) {
+                       MSG("Channels:\n-------------");
+               }
 
-       for (i = 0; i < count; i++) {
-               if (channel_name != NULL) {
-                       if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
-                               chan_found = 1;
-                       } else {
-                               continue;
+               for (i = 0; i < count; i++) {
+                       if (channel_name != NULL) {
+                               if (strncmp(channels[i].name, channel_name, NAME_MAX) == 0) {
+                                       chan_found = 1;
+                               } else {
+                                       continue;
+                               }
+                       }
+                       print_channel(&channels[i]);
+
+                       /* Listing events per channel */
+                       ret = list_events(channels[i].name);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (chan_found) {
+                               break;
                        }
                }
-               print_channel(&channels[i]);
 
-               /* Listing events per channel */
-               ret = list_events(channels[i].name);
-               if (ret < 0) {
-                       ERR("%s", lttng_strerror(ret));
+               if (!chan_found && channel_name != NULL) {
+                       ret = CMD_ERROR;
+                       ERR("Channel %s not found", channel_name);
+                       goto error;
                }
+       }
+error:
+       free(channels);
 
-               if (chan_found) {
+error_channels:
+       return ret;
+}
+
+/*
+ * Machine interface
+ * Find the session with session_name as name
+ * and print his informations.
+ */
+static int mi_list_session(const char *session_name,
+               struct lttng_session *sessions, int count)
+{
+       int ret, i;
+       unsigned int session_found = 0;
+
+       if (session_name == NULL) {
+               ret = -LTTNG_ERR_SESS_NOT_FOUND;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                       /* We need to leave it open to append other informations
+                        * like domain, channel, events etc.*/
+                       session_found = 1;
+                       ret = mi_lttng_session(writer, &sessions[i], 1);
+                       if (ret) {
+                               goto end;
+                       }
                        break;
                }
        }
 
-       if (!chan_found && channel_name != NULL) {
-               ERR("Channel %s not found", channel_name);
-               goto error;
+       if (!session_found) {
+               ERR("Session '%s' not found", session_name);
+               ret = -LTTNG_ERR_SESS_NOT_FOUND;
+               goto end;
        }
 
-       ret = CMD_SUCCESS;
+end:
+       return ret;
+}
 
-error:
-       free(channels);
+/*
+ * Machine interface
+ * List all availables session
+ */
+static int mi_list_sessions(struct lttng_session *sessions, int count)
+{
+       int ret, i;
 
-error_channels:
+       /* Opening sessions element */
+       ret = mi_lttng_sessions_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Listing sessions */
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_session(writer, &sessions[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Closing sessions element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto end;
+       }
+
+end:
        return ret;
 }
 
@@ -766,30 +1240,58 @@ error_channels:
  */
 static int list_sessions(const char *session_name)
 {
-       int ret, count, i;
+       int ret = CMD_SUCCESS;
+       int count, i;
        unsigned int session_found = 0;
        struct lttng_session *sessions;
 
        count = lttng_list_sessions(&sessions);
        DBG("Session count %d", count);
        if (count < 0) {
-               ret = count;
-               ERR("%s", lttng_strerror(ret));
-               goto error;
-       } else if (count == 0) {
-               MSG("Currently no available tracing session");
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
                goto end;
        }
 
-       if (session_name == NULL) {
-               MSG("Available tracing sessions:");
-       }
+       if (lttng_opt_mi) {
+               /* Mi */
+               if (session_name == NULL) {
+                       /* List all session */
+                       ret = mi_list_sessions(sessions, count);
+               } else {
+                       /* Note : this return an open session element */
+                       ret = mi_list_session(session_name, sessions, count);
+               }
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* Pretty print */
+               if (count == 0) {
+                       MSG("Currently no available tracing session");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
 
-       for (i = 0; i < count; i++) {
-               if (session_name != NULL) {
-                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
-                               session_found = 1;
-                               MSG("Tracing session %s: [%s%s]", session_name,
+               if (session_name == NULL) {
+                       MSG("Available tracing sessions:");
+               }
+
+
+               for (i = 0; i < count; i++) {
+                       if (session_name != NULL) {
+                               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                                       session_found = 1;
+                                       MSG("Tracing session %s: [%s%s]", session_name,
+                                                       active_string(sessions[i].enabled),
+                                                       snapshot_string(sessions[i].snapshot_mode));
+                                       MSG("%sTrace path: %s\n", indent4, sessions[i].path);
+                                       break;
+                               }
+                       } else {
+                               MSG("  %d) %s (%s) [%s%s]", i + 1,
+                                               sessions[i].name, sessions[i].path,
                                                active_string(sessions[i].enabled),
                                                snapshot_string(sessions[i].snapshot_mode));
                                MSG("%sTrace path: %s", indent4, sessions[i].path);
@@ -797,29 +1299,52 @@ static int list_sessions(const char *session_name)
                                                sessions[i].live_timer_interval);
                                break;
                        }
-               } else {
-                       MSG("  %d) %s (%s) [%s%s]", i + 1, sessions[i].name, sessions[i].path,
-                                       active_string(sessions[i].enabled),
-                                       snapshot_string(sessions[i].snapshot_mode));
+               }
+
+               if (!session_found && session_name != NULL) {
+                       ERR("Session '%s' not found", session_name);
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               if (session_name == NULL) {
+                       MSG("\nUse lttng list <session_name> for more details");
                }
        }
 
+error:
        free(sessions);
+end:
+       return ret;
+}
 
-       if (!session_found && session_name != NULL) {
-               ERR("Session '%s' not found", session_name);
-               ret = CMD_ERROR;
-               goto error;
+
+/*
+ * Machine Interface
+ * list available domain(s) for a session.
+ */
+static int mi_list_domains(struct lttng_domain *domains, int count)
+{
+       int i, ret;
+       /* Open domains element */
+       ret = mi_lttng_domains_open(writer);
+       if (ret) {
+               goto end;
        }
 
-       if (session_name == NULL) {
-               MSG("\nUse lttng list <session_name> for more details");
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_domain(writer, &domains[i] , 0);
+               if (ret) {
+                       goto end;
+               }
        }
 
+       /* Closing domains element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               goto end;
+       }
 end:
-       return CMD_SUCCESS;
-
-error:
        return ret;
 }
 
@@ -831,38 +1356,50 @@ static int list_domains(const char *session_name)
        int i, count, ret = CMD_SUCCESS;
        struct lttng_domain *domains = NULL;
 
-       MSG("Domains:\n-------------");
 
        count = lttng_list_domains(session_name, &domains);
        if (count < 0) {
-               ret = count;
-               ERR("%s", lttng_strerror(ret));
-               goto error;
-       } else if (count == 0) {
-               MSG("  None");
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
                goto end;
        }
 
-       for (i = 0; i < count; i++) {
-               switch (domains[i].type) {
-               case LTTNG_DOMAIN_KERNEL:
-                       MSG("  - Kernel");
-                       break;
-               case LTTNG_DOMAIN_UST:
-                       MSG("  - UST global");
-                       break;
-               case LTTNG_DOMAIN_JUL:
-                       MSG("  - JUL (Java Util Logging)");
-                       break;
-               default:
-                       break;
+       if (lttng_opt_mi) {
+               /* Mi output */
+               ret = mi_list_domains(domains, count);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* Pretty print */
+               MSG("Domains:\n-------------");
+               if (count == 0) {
+                       MSG("  None");
+                       goto end;
+               }
+
+               for (i = 0; i < count; i++) {
+                       switch (domains[i].type) {
+                       case LTTNG_DOMAIN_KERNEL:
+                               MSG("  - Kernel");
+                               break;
+                       case LTTNG_DOMAIN_UST:
+                               MSG("  - UST global");
+                               break;
+                       case LTTNG_DOMAIN_JUL:
+                               MSG("  - JUL (Java Util Logging)");
+                               break;
+                       default:
+                               break;
+                       }
                }
        }
 
-end:
+error:
        free(domains);
 
-error:
+end:
        return ret;
 }
 
@@ -888,13 +1425,6 @@ int cmd_list(int argc, const char **argv)
        pc = poptGetContext(NULL, argc, argv, long_options, 0);
        poptReadDefaultConfig(pc, 0);
 
-       /* TODO: mi support */
-       if (lttng_opt_mi) {
-               ret = -LTTNG_ERR_MI_NOT_IMPLEMENTED;
-               ERR("mi option not supported");
-               goto end;
-       }
-
        while ((opt = poptGetNextOpt(pc)) != -1) {
                switch (opt) {
                case OPT_HELP:
@@ -913,6 +1443,31 @@ int cmd_list(int argc, const char **argv)
                }
        }
 
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_list);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
        /* Get session name (trailing argument) */
        session_name = poptGetArg(pc);
        DBG2("Session name: %s", session_name);
@@ -938,14 +1493,13 @@ int cmd_list(int argc, const char **argv)
        if (session_name == NULL) {
                if (!opt_kernel && !opt_userspace && !opt_jul) {
                        ret = list_sessions(NULL);
-                       if (ret != 0) {
+                       if (ret) {
                                goto end;
                        }
                }
                if (opt_kernel) {
                        ret = list_kernel_events();
-                       if (ret < 0) {
-                               ret = CMD_ERROR;
+                       if (ret) {
                                goto end;
                        }
                }
@@ -955,22 +1509,29 @@ int cmd_list(int argc, const char **argv)
                        } else {
                                ret = list_ust_events();
                        }
-                       if (ret < 0) {
-                               ret = CMD_ERROR;
+                       if (ret) {
                                goto end;
                        }
                }
                if (opt_jul) {
                        ret = list_jul_events();
-                       if (ret < 0) {
-                               ret = CMD_ERROR;
+                       if (ret) {
                                goto end;
                        }
                }
        } else {
                /* List session attributes */
+               if (lttng_opt_mi) {
+                       /* Open element sessions
+                        * Present for xml consistency */
+                       ret = mi_lttng_sessions_open(writer);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               /* MI: the ouptut of list_sessions is an unclosed session element */
                ret = list_sessions(session_name);
-               if (ret != 0) {
+               if (ret) {
                        goto end;
                }
 
@@ -980,23 +1541,59 @@ int cmd_list(int argc, const char **argv)
                        goto end;
                }
 
+               /* Channel listing */
                if (opt_kernel || opt_userspace) {
-                       /* Channel listing */
+                       if (lttng_opt_mi) {
+                               /* Add of domains and domain element for xml
+                                * consistency and validation
+                                */
+                               ret = mi_lttng_domains_open(writer);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                               /* Open domain and leave it open for
+                                * nested channels printing */
+                               ret = mi_lttng_domain(writer, &domain, 1);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                       }
+
                        ret = list_channels(opt_channel);
-                       if (ret < 0) {
+                       if (ret) {
+                               goto end;
+                       }
+
+                       if (lttng_opt_mi) {
+                               /* Close domain and domain element */
+                               ret = mi_lttng_close_multi_element(writer, 2);
+                       }
+                       if (ret) {
                                goto end;
                        }
+
+
                } else {
                        int i, nb_domain;
 
                        /* We want all domain(s) */
                        nb_domain = lttng_list_domains(session_name, &domains);
                        if (nb_domain < 0) {
-                               ret = nb_domain;
-                               ERR("%s", lttng_strerror(ret));
+                               ret = CMD_ERROR;
+                               ERR("%s", lttng_strerror(nb_domain));
                                goto end;
                        }
 
+                       if (lttng_opt_mi) {
+                               ret = mi_lttng_domains_open(writer);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+
                        for (i = 0; i < nb_domain; i++) {
                                switch (domains[i].type) {
                                case LTTNG_DOMAIN_KERNEL:
@@ -1016,6 +1613,14 @@ int cmd_list(int argc, const char **argv)
                                        break;
                                }
 
+                               if (lttng_opt_mi) {
+                                       ret = mi_lttng_domain(writer, &domains[i], 1);
+                                       if (ret) {
+                                               ret = CMD_ERROR;
+                                               goto end;
+                                       }
+                               }
+
                                /* Clean handle before creating a new one */
                                if (handle) {
                                        lttng_destroy_handle(handle);
@@ -1029,21 +1634,61 @@ int cmd_list(int argc, const char **argv)
 
                                if (domains[i].type == LTTNG_DOMAIN_JUL) {
                                        ret = list_session_jul_events();
-                                       if (ret < 0) {
+                                       if (ret) {
                                                goto end;
                                        }
                                        continue;
                                }
 
                                ret = list_channels(opt_channel);
-                               if (ret < 0) {
+                               if (ret) {
+                                       goto end;
+                               }
+
+                               if (lttng_opt_mi) {
+                                       /* Close domain element */
+                                       ret = mi_lttng_writer_close_element(writer);
+                                       if (ret) {
+                                               ret = CMD_ERROR;
+                                               goto end;
+                                       }
+                               }
+
+                       }
+                       if (lttng_opt_mi) {
+                               /* Close the domains, session and sessions element */
+                               ret = mi_lttng_close_multi_element(writer, 3);
+                               if (ret) {
+                                       ret = CMD_ERROR;
                                        goto end;
                                }
                        }
                }
        }
 
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
 end:
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
+       }
+
        free(domains);
        if (handle) {
                lttng_destroy_handle(handle);
This page took 0.070772 seconds and 4 git commands to generate.