Fix: memory management in create.c
[lttng-tools.git] / src / bin / lttng / commands / create.c
index f020fff638957548cf90c7a2aed118f80f067abb..c8027133d2a0666cf9b2f79dc3c556a046293fc1 100644 (file)
@@ -30,6 +30,7 @@
 #include <sys/wait.h>
 
 #include <common/mi-lttng.h>
+#include <common/config/session-config.h>
 
 #include "../command.h"
 #include "../utils.h"
@@ -46,6 +47,7 @@ static char *opt_url;
 static char *opt_ctrl_url;
 static char *opt_data_url;
 static char *opt_shm_path;
+static char *opt_template_path;
 static int opt_no_consumer;
 static int opt_no_output;
 static int opt_snapshot;
@@ -57,13 +59,13 @@ enum {
        OPT_LIVE_TIMER,
 };
 
-enum {
+enum output_type {
        OUTPUT_UNKNOWN = -1,
        OUTPUT_NONE,
        OUTPUT_LOCAL,
        OUTPUT_NET,
 };
-enum {
+enum session_type {
        SESSION_UNKNOWN = -1,
        SESSION_NORMAL,
        SESSION_LIVE,
@@ -86,6 +88,7 @@ static struct poptOption long_options[] = {
        {"snapshot",        0, POPT_ARG_VAL, &opt_snapshot, 1, 0, 0},
        {"live",            0, POPT_ARG_INT | POPT_ARGFLAG_OPTIONAL, 0, OPT_LIVE_TIMER, 0, 0},
        {"shm-path",        0, POPT_ARG_STRING, &opt_shm_path, 0, 0, 0},
+       {"template-path",        0, POPT_ARG_STRING, &opt_template_path, 0, 0, 0},
        {0, 0, 0, 0, 0, 0, 0}
 };
 
@@ -225,9 +228,10 @@ error_create:
  * CMD_ERROR on error
  * CMD_SUCCESS on success
  */
-static int validate_command_options(void)
+static int validate_command_options(enum session_type type)
 {
        int ret = CMD_SUCCESS;
+
        if (opt_snapshot && opt_live_timer) {
                ERR("Snapshot and live modes are mutually exclusive.");
                ret = CMD_ERROR;
@@ -235,25 +239,37 @@ static int validate_command_options(void)
        }
 
        if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) {
-               ERR("You need both control and data URL.");
+               ERR("Control and data URLs must both be set.");
                ret = CMD_ERROR;
                goto error;
        }
 
+       if (opt_template_path) {
+               /* Restriction on flags exist when using template */
+               /* Session type flags are not permitted */
+               /* --live & --snapshot */
+               if ((opt_live_timer && type != SESSION_LIVE) ||
+                               (opt_snapshot && type != SESSION_SNAPSHOT)) {
+                       ERR("It is not possible to change the session type of a template");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
 error:
        return ret;
 }
 
 /*
- * Create a session via direct calls to liblttng-ctl.
+ * Create a session using direct calls to liblttng-ctl.
  *
  * Return CMD_SUCCESS on success, negative value on internal lttng errors and positive
  * value on command errors.
  */
 static int create_session_basic (const char *session_name,
-               int session_type,
+               enum session_type session_type,
                int live_timer,
-               int output_type,
+               enum output_type output_type,
                const char* url,
                const char* ctrl_url,
                const char* data_url,
@@ -369,9 +385,9 @@ error:
 }
 
 static int generate_output(const char *session_name,
-               int session_type,
+               enum session_type session_type,
                int live_timer,
-               int output_type,
+               enum output_type output_type,
                const char* url,
                const char* ctrl_url,
                const char* data_url,
@@ -432,6 +448,400 @@ error:
        return ret;
 }
 
+static int parse_template (struct config_document *template,
+               char **session_name,
+               enum session_type *session_type,
+               int *live_timer,
+               enum output_type *output_type,
+               char **url,
+               char **ctrl_url,
+               char **data_url,
+               char **shm_path)
+{
+       int ret = 0;
+       int printed_byte;
+       char *raw_value = NULL;
+
+       assert(template);
+
+       /* Session name */
+       *session_name = config_document_get_element_value(template,"/sessions/session/name");
+
+       /* Check the type of session we have in the template */
+       if(config_document_element_exist(template, "/sessions/session/attributes/snapshot_mode")) {
+               *session_type = SESSION_SNAPSHOT;
+       } else if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) {
+               *session_type = SESSION_LIVE;
+               raw_value = config_document_get_element_value(template,"/sessions/session/attributes/live_timer_interval");
+               *live_timer = config_parse_value(raw_value);
+               free(raw_value);
+               raw_value = NULL;
+       } else {
+               *session_type = SESSION_NORMAL;
+       }
+
+       /* Output */
+       switch (*session_type) {
+       case SESSION_NORMAL:
+       case SESSION_LIVE:
+               if (!config_document_element_exist(template, "/sessions/session/output/consumer_output/destination")){
+                       break;
+               }
+               if (config_document_element_exist(template, "/sessions/session/output/consumer_output/destination/path")){
+                       raw_value = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/path");
+                       if (!raw_value) {
+                               ret = -1;
+                               goto error;
+                       }
+
+                       if (strlen(raw_value) > 0) {
+                               *output_type = OUTPUT_LOCAL;
+                               printed_byte = asprintf(url, "file://%s", raw_value);
+                               if (printed_byte < 0) {
+                                       ret = -1;
+                                       goto error;
+                               }
+                       } else {
+                               *output_type = OUTPUT_NONE;
+                       }
+
+                       free(raw_value);
+                       raw_value = NULL;
+                       break;
+               } else if(config_document_element_exist(template, "/sessions/session/output/consumer_output/destination/net_output")) {
+                       *ctrl_url = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/net_output/control_uri");
+                       *data_url = config_document_get_element_value(template, "/sessions/session/output/consumer_output/destination/net_output/data_uri");
+                       if (!*ctrl_url || ! *data_url) {
+                               ret = -1;
+                               goto error;
+                       }
+                       *output_type = OUTPUT_NET;
+               } else {
+                       /* There is no output definition */
+               }
+               break;
+       case SESSION_SNAPSHOT:
+               if (!config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination")){
+                       break;
+               }
+               if (config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/path")){
+                       raw_value = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/path");
+                       if (!raw_value) {
+                               ret = -1;
+                               goto error;
+                       }
+
+                       if (strlen(raw_value) > 0) {
+                               *output_type = OUTPUT_LOCAL;
+                               printed_byte = asprintf(url, "file://%s", raw_value);
+                               if (printed_byte < 0) {
+                                       ret = -1;
+                                       goto error;
+                               }
+                       } else {
+                               *output_type = OUTPUT_NONE;
+                       }
+
+                       free(raw_value);
+                       raw_value = NULL;
+                       break;
+               } else if(config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output")) {
+                       *ctrl_url = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output/control_uri");
+                       *data_url = config_document_get_element_value(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination/net_output/data_uri");
+                       if (!*ctrl_url || ! *data_url) {
+                               ret = -1;
+                               goto error;
+                       }
+                       *output_type = OUTPUT_NET;
+               } else {
+                       /* There is no output definition */
+               }
+               break;
+       case SESSION_UNKNOWN:
+               ret = -1;
+               goto error;
+       }
+
+
+       /* shared memory path */
+       *shm_path = config_document_get_element_value(template,"/sessions/session/shared_memory_path");
+
+error:
+       free(raw_value);
+       return ret;
+
+}
+static int create_session_from_template(struct config_document *template,
+               const char *session_name,
+               enum session_type session_type,
+               int live_timer,
+               enum output_type output_type,
+               const char *url,
+               const char *ctrl_url,
+               const char *data_url,
+               const char *shm_path,
+               const char *datetime)
+{
+       int ret = CMD_SUCCESS;
+       int printed_byte;
+       struct config_element *temp_element = NULL;
+       struct config_element *temp_element_child = NULL;
+       char tmp_ctrl_uri[PATH_MAX];
+       char tmp_data_uri[PATH_MAX];
+       struct lttng_uri *uris = NULL;
+       ssize_t uri_array_size = 0;
+       char *tmp_string = NULL;
+
+       assert(template);
+       assert(session_name);
+
+       memset(tmp_ctrl_uri, 0, sizeof(tmp_ctrl_uri));
+       memset(tmp_data_uri, 0, sizeof(tmp_data_uri));
+
+       /* Session name */
+       if (config_document_element_exist(template, "/sessions/session/name")) {
+               /* Replace the node value */
+               config_document_replace_element_value(template, "/sessions/session/name", session_name);
+       } else {
+               /* insert the node */
+               temp_element = config_element_create("name", session_name);
+               if (!temp_element) {
+                       ERR("Could not create session name node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               ret = config_document_insert_element(template, "/sessions/session", temp_element);
+               if (ret) {
+                       ERR("Could not insert session name node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               config_element_free(temp_element);
+       }
+
+       /*
+        * Live timer
+        */
+       if (session_type == SESSION_LIVE) {
+               if (config_document_element_exist(template, "/sessions/session/attributes/live_timer_interval")) {
+                       printed_byte = asprintf(&tmp_string, "%d", live_timer);
+                       if (printed_byte < 0) {
+                               ERR("Asprintf failed for live timer");
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+                       ret = config_document_replace_element_value(template, "/sessions/session/attributes/live_timer_interval", tmp_string);
+
+                       if (ret) {
+                               printf("error: %d\n", ret);
+                               ERR("Replacement of live_timer_interval failed");
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       free(tmp_string);
+                       tmp_string = NULL;
+               } else {
+                       ERR("Invalid live timer template. Missing live timer node");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+       }
+
+       /*
+        * Generate the output node
+        */
+
+       /* Get output from urls */
+       if (url) {
+               /* Get lttng uris from single url */
+               uri_array_size = uri_parse_str_urls(url, NULL, &uris);
+               if (uri_array_size < 0) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else if (ctrl_url && data_url) {
+               uri_array_size = uri_parse_str_urls(ctrl_url, data_url, &uris);
+               if (uri_array_size < 0) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* --no-output */
+               uri_array_size = 0;
+       }
+
+       /* Validate if the session output type still match the passed data */
+       if ( (uri_array_size == 0 && output_type != OUTPUT_NONE) ||
+                       (uri_array_size == 1 && output_type != OUTPUT_LOCAL) ||
+                       (uri_array_size == 2 && output_type != OUTPUT_NET)) {
+               ERR("Overwriting value for output do not match the base output type");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       switch (output_type) {
+       case OUTPUT_NONE:
+               temp_element_child = config_element_create("path", "");
+               if (!temp_element_child) {
+                       ERR("Could not create empty path node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               break;
+       case OUTPUT_LOCAL:
+               temp_element_child = config_element_create("path", uris[0].dst.path);
+               if (!temp_element_child) {
+                       ERR("Could not create local path node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               break;
+       case OUTPUT_NET:
+               uri_to_str_url(&uris[0], tmp_ctrl_uri, sizeof(tmp_ctrl_uri));
+               uri_to_str_url(&uris[1], tmp_data_uri, sizeof(tmp_data_uri));
+
+               temp_element_child = config_element_create("net_output", NULL);
+               if (!temp_element_child) {
+                       ERR("Could not create net_output node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               temp_element = config_element_create("control_uri", tmp_ctrl_uri);
+               if (!temp_element_child) {
+                       ERR("Could not create ctrl uri node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               ret = config_element_add_child(temp_element_child, temp_element);
+               if (ret) {
+                       ERR("Could not append control uri to the net_output node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               config_element_free(temp_element);
+               temp_element = NULL;
+
+               temp_element = config_element_create("data_uri", tmp_data_uri);
+
+               if (!temp_element_child) {
+                       ERR("Could not create data_uri configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               ret = config_element_add_child(temp_element_child, temp_element);
+               if (ret) {
+                       ERR("Could not append data uri to the net_output node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               config_element_free(temp_element);
+               temp_element = NULL;
+               break;
+       default:
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       temp_element = config_element_create("destination", NULL);
+       if (!temp_element) {
+               ERR("Could not create destination node configuration");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       ret = config_element_add_child(temp_element, temp_element_child);
+       if (ret) {
+               ERR("Could not append output data to the destination node configuration");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       config_element_free(temp_element_child);
+       temp_element_child = NULL;
+
+
+       /*
+        * validate and replace the destination node for each session type
+        * TODO: export string as const and simply assign a base path for the
+        * destination node based on the session type
+        **/
+       switch (session_type) {
+       case SESSION_NORMAL:
+       case SESSION_LIVE:
+               if (!config_document_element_exist(template, "/sessions/session/output/consumer_output/destination")) {
+                       ERR("Invalid template no destination node configuration present");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               ret = config_document_replace_element(template, "/sessions/session/output/consumer_output/destination", temp_element);
+               break;
+       case SESSION_SNAPSHOT:
+               if (!config_document_element_exist(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination")) {
+                       ERR("Invalid template no destination node configuration present");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               ret = config_document_replace_element(template, "/sessions/session/output/snapshot_outputs/output/consumer_output/destination", temp_element);
+               break;
+       default:
+               ERR("Invalid session type");
+               ret = CMD_UNDEFINED;
+               goto error;
+       }
+
+       config_element_free(temp_element);
+       temp_element = NULL;
+
+       if (ret) {
+               ERR("%s", lttng_strerror(ret));
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+
+       /* Shm path */
+       if (shm_path && config_document_element_exist(template, "/sessions/session/shared_memory_path")) {
+               /* Replace the node value */
+               config_document_replace_element_value(template, "/sessions/session/shared_memory_path", shm_path);
+       } else if (shm_path) {
+               /* insert the node */
+               temp_element = config_element_create("shared_memory_path", shm_path);
+               if (!temp_element) {
+                       ERR("Could not create shared_memory_path node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               ret = config_document_insert_element(template, "/sessions/session", temp_element);
+               if (ret) {
+                       ERR("Could not insert shared_memory_path node configuration");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               config_element_free(temp_element);
+               temp_element = NULL;
+       }
+
+       ret = config_load_configuration_sessions(template, session_name, 0);
+
+
+error:
+       config_element_free(temp_element);
+       config_element_free(temp_element_child);
+       free(tmp_string);
+       free(uris);
+       return ret;
+
+}
+
 /*
  *  Create a tracing session.
  *  If no name is specified, a default name is generated.
@@ -441,10 +851,15 @@ error:
 static int create_session(void)
 {
        int ret;
+       int printed_byte;
+
+
+       /* Template */
+       struct config_document *template = NULL;
 
        /* Base data */
-       int base_session_type = SESSION_UNKNOWN;
-       int base_output_type = OUTPUT_UNKNOWN;
+       enum session_type base_session_type = SESSION_UNKNOWN;
+       enum output_type base_output_type = OUTPUT_UNKNOWN;
        char *base_session_name = NULL;
        char *base_url = NULL;
        char *base_ctrl_url = NULL;
@@ -466,17 +881,43 @@ static int create_session(void)
        struct lttng_uri *uris = NULL;
        ssize_t uri_array_size = 0;
 
-       /* Option validation */
-       if (validate_command_options() != CMD_SUCCESS) {
-               ret = CMD_ERROR;
-               goto error;
-       }
 
        /* Get date and time for automatic session name/path */
        time(&rawtime);
        timeinfo = localtime(&rawtime);
        strftime(datetime, sizeof(datetime), "%Y%m%d-%H%M%S", timeinfo);
 
+       if (opt_template_path) {
+               /* Restriction on flags exist when using template */
+               /* Session type flags are not permitted */
+               /* --live & --snapshot */
+               template = config_document_get(opt_template_path);
+               if (!template) {
+                       ERR("Template could not be parsed");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               /* Load info from template if any */
+               /* TODO: might want to use a struct in the end for the session... */
+               ret = parse_template(template, &base_session_name,
+                               &base_session_type,
+                               &base_live_timer,
+                               &base_output_type,
+                               &base_url,
+                               &base_ctrl_url,
+                               &base_data_url,
+                               &base_shm_path);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       /* Option validation */
+       if (validate_command_options(base_session_type) != CMD_SUCCESS) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
        /* Find the session type based on options */
        if(base_session_type == SESSION_UNKNOWN) {
                if (opt_snapshot) {
@@ -509,7 +950,7 @@ static int create_session(void)
                                strlen(DEFAULT_SESSION_NAME) + 1) == 0) ||
                        (strncmp(opt_session_name, DEFAULT_SESSION_NAME,
                                strlen(DEFAULT_SESSION_NAME)) == 0 &&
-                        strlen(opt_session_name) == strlen(DEFAULT_SESSION_NAME))) {
+                       strlen(opt_session_name) == strlen(DEFAULT_SESSION_NAME))) {
                        ERR("%s is a reserved keyword for default session(s)",
                                        DEFAULT_SESSION_NAME);
 
@@ -524,24 +965,26 @@ static int create_session(void)
                        goto error;
                }
 
-               ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime);
-               if (ret < 0) {
+               printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime);
+               if (printed_byte < 0) {
                        PERROR("Asprintf session name");
+                       ret = CMD_ERROR;
                        goto error;
                }
                DBG("Session name from command option set to %s", base_session_name);
        } else if (base_session_name) {
-               ret = asprintf(&session_name_date, "%s-%s", base_session_name, datetime);
-               if (ret < 0) {
+               printed_byte = asprintf(&session_name_date, "%s-%s", base_session_name, datetime);
+               if (printed_byte < 0) {
                        PERROR("Asprintf session name");
+                       ret = CMD_ERROR;
                        goto error;
                }
        } else {
                /* Generate a name */
-               /* TODO: use asprint */
-               ret = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime);
-               if (ret < 0) {
-                       PERROR("Asprintf generated session name");
+               printed_byte = asprintf(&base_session_name, DEFAULT_SESSION_NAME "-%s", datetime);
+               if (printed_byte < 0) {
+                       PERROR("Asprintf session name");
+                       ret = CMD_ERROR;
                        goto error;
                }
                session_name_date = strdup(base_session_name);
@@ -575,8 +1018,8 @@ static int create_session(void)
                }
 
                /* Create URL string from the local file system path */
-               ret = asprintf(&temp_url, "file://%s", traces_path);
-               if (ret < 0) {
+               printed_byte = asprintf(&temp_url, "file://%s", traces_path);
+               if (printed_byte < 0) {
                        PERROR("asprintf url path");
                        ret = CMD_FATAL;
                        goto error;
@@ -608,11 +1051,11 @@ static int create_session(void)
                                goto error;
                        }
 
-                       ret = asprintf(&tmp_url,
+                       printed_byte = asprintf(&tmp_url,
                                        "file://%s/" DEFAULT_TRACE_DIR_NAME "/%s",
                                        tmp_home_path, session_name_date);
 
-                       if (ret < 0) {
+                       if (printed_byte < 0) {
                                PERROR("asprintf trace dir name");
                                ret = CMD_FATAL;
                                goto error;
@@ -622,8 +1065,8 @@ static int create_session(void)
                        break;
                case SESSION_LIVE:
                        /* Default to a net output */
-                       ret = asprintf(&tmp_url, "net://127.0.0.1");
-                       if (ret < 0) {
+                       printed_byte = asprintf(&tmp_url, "net://127.0.0.1");
+                       if (printed_byte < 0) {
                                PERROR("asprintf default live URL");
                                ret = CMD_FATAL;
                                goto error;
@@ -641,9 +1084,12 @@ static int create_session(void)
          * Shared memory path handling
          */
        if (opt_shm_path) {
-               ret = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date);
-               if (ret < 0) {
+               /* Overwrite shm_path so clear any previously defined one */
+               free(base_shm_path);
+               printed_byte = asprintf(&base_shm_path, "%s/%s", opt_shm_path, session_name_date);
+               if (printed_byte < 0) {
                        PERROR("asprintf shm_path");
+                       ret = CMD_FATAL;
                        goto error;
                }
        }
@@ -689,15 +1135,28 @@ static int create_session(void)
                goto error;
        }
 
-       ret = create_session_basic (base_session_name,
-                       base_session_type,
-                       base_live_timer,
-                       base_output_type,
-                       base_url,
-                       base_ctrl_url,
-                       base_data_url,
-                       base_shm_path,
-                       datetime);
+       if (template) {
+               ret = create_session_from_template(template,
+                               base_session_name,
+                               base_session_type,
+                               base_live_timer,
+                               base_output_type,
+                               base_url,
+                               base_ctrl_url,
+                               base_data_url,
+                               base_shm_path,
+                               datetime);
+       } else {
+               ret = create_session_basic (base_session_name,
+                               base_session_type,
+                               base_live_timer,
+                               base_output_type,
+                               base_url,
+                               base_ctrl_url,
+                               base_data_url,
+                               base_shm_path,
+                               datetime);
+       }
        if (ret) {
                goto error;
        }
@@ -724,15 +1183,16 @@ static int create_session(void)
        ret = CMD_SUCCESS;
 
 error:
-
        /* Session temp stuff */
+       config_document_free(template);
        free(session_name_date);
-
        free(uris);
+       free(traces_path);
 
        if (ret < 0) {
                ERR("%s", lttng_strerror(ret));
        }
+
        free(base_session_name);
        free(base_url);
        free(base_ctrl_url);
This page took 0.037747 seconds and 5 git commands to generate.