Add support for auto session creation
[lttng-tools.git] / lttng / lttng.c
index e538df2fd403f0eefaf2be2c58b3c8a04973067d..4c74d21fefb665172f2fac166e9de0b5ffee20c8 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <lttng/liblttngctl.h>
+#include <lttng/lttng.h>
 
 #include "lttng.h"
 #include "lttngerr.h"
 
 /* Variables */
 static char *progname;
+static char *session_name;
+static char short_str_uuid[UUID_SHORT_STR_LEN];
+static char long_str_uuid[UUID_STR_LEN];
+static uuid_t current_uuid;
 
 /* Prototypes */
 static int process_client_opt(void);
 static int process_opt_list_apps(void);
 static int process_opt_list_sessions(void);
+static int process_opt_list_traces(void);
 static int process_opt_create_session(void);
+static int set_session_uuid(void);
 static void sighandler(int sig);
 static int set_signal_handler(void);
-static int get_cmdline_by_pid(pid_t pid, char **cmdline);
 static int validate_options(void);
+static char *get_cmdline_by_pid(pid_t pid);
+static void set_opt_session_info(void);
+static void shorten_uuid(char *long_u, char *short_u);
 
 /*
  *  start_client
@@ -58,13 +66,8 @@ static int validate_options(void);
 static int process_client_opt(void)
 {
        int ret;
-       uuid_t uuid;
 
-       /* Connect to the session daemon */
-       ret = lttng_connect_sessiond();
-       if (ret < 0) {
-               goto end;
-       }
+       set_opt_session_info();
 
        if (opt_list_apps) {
                ret = process_opt_list_apps();
@@ -80,42 +83,73 @@ static int process_client_opt(void)
                }
        }
 
-       if (opt_create_session != NULL) {
-               ret = process_opt_create_session();
+       if (opt_destroy_session) {
+               ret = lttng_destroy_session(&current_uuid);
                if (ret < 0) {
                        goto end;
                }
+               MSG("Session %s destroyed.", opt_session_uuid);
        }
 
-       if (opt_destroy_session != NULL) {
-               uuid_parse(opt_destroy_session, uuid);
-               ret = lttng_destroy_session(&uuid);
-               if (ret < 0) {
-                       goto end;
+       if (!opt_list_session && !opt_list_apps) {
+               if (uuid_is_null(current_uuid)) {
+                       /* If no session uuid, create session */
+                       DBG("No session specified. Creating session.");
+                       ret = process_opt_create_session();
+                       if (ret < 0) {
+                               goto end;
+                       }
                }
-       }
 
-       if (opt_session_uuid != NULL) {
-               DBG("Set session uuid to %s", opt_session_uuid);
-               lttng_set_current_session_uuid(opt_session_uuid);
+               DBG("Set session uuid to %s", long_str_uuid);
+               ret = set_session_uuid();
+               if (ret < 0) {
+                       ERR("Session UUID %s not found", opt_session_uuid);
+                       goto error;
+               }
        }
 
-       if (opt_create_trace) {
-               DBG("Create trace for pid %d", opt_create_trace);
-               ret = lttng_ust_create_trace(opt_create_trace);
+       if (opt_list_traces) {
+               ret = process_opt_list_traces();
                if (ret < 0) {
                        goto end;
                }
-               MSG("Trace created successfully!\nUse --start PID to start tracing.");
        }
 
-       if (opt_start_trace) {
-               DBG("Start trace for pid %d", opt_start_trace);
-               ret = lttng_ust_start_trace(opt_start_trace);
-               if (ret < 0) {
-                       goto end;
+       /*
+        * Action on traces (kernel or/and userspace).
+        */
+       if (opt_trace_kernel) {
+               ERR("Not implemented yet");
+               goto end;
+       }
+
+       if (opt_trace_pid != 0) {
+               if (opt_create_trace) {
+                       DBG("Create a userspace trace for pid %d", opt_trace_pid);
+                       ret = lttng_ust_create_trace(opt_trace_pid);
+                       if (ret < 0) {
+                               goto end;
+                       }
+                       MSG("Trace created successfully!\nUse --start to start tracing.");
+               }
+
+               if (opt_start_trace) {
+                       DBG("Start trace for pid %d", opt_trace_pid);
+                       ret = lttng_ust_start_trace(opt_trace_pid);
+                       if (ret < 0) {
+                               goto end;
+                       }
+                       MSG("Trace started successfully!");
+               } else if (opt_stop_trace) {
+                       DBG("Stop trace for pid %d", opt_trace_pid);
+                       ret = lttng_ust_stop_trace(opt_trace_pid);
+                       if (ret < 0) {
+                               goto end;
+                       }
+                       MSG("Trace stopped successfully!");
                }
-               MSG("Trace started successfully!");
+
        }
 
        return 0;
@@ -123,6 +157,138 @@ static int process_client_opt(void)
 end:
        ERR("%s", lttng_get_readable_code(ret));
        return ret;
+
+error:
+       return ret;
+}
+
+/*
+ *  set_opt_session_info
+ *
+ *  Setup session_name, current_uuid, short_str_uuid and
+ *  long_str_uuid using the command line options.
+ */
+static void set_opt_session_info(void)
+{
+       int count, i, short_len;
+       char *tok;
+       struct lttng_session *sessions;
+
+       if (opt_session_uuid != NULL) {
+               short_len = sizeof(short_str_uuid) - 1;
+               /* Shorten uuid */
+               tok = strchr(opt_session_uuid, '.');
+               if (strlen(tok + 1) == short_len) {
+                       memcpy(short_str_uuid, tok + 1, short_len);
+                       short_str_uuid[short_len] = '\0';
+               }
+
+               /* Get long real uuid_t from session daemon */
+               count = lttng_list_sessions(&sessions);
+               for (i = 0; i < count; i++) {
+                       uuid_unparse(sessions[i].uuid, long_str_uuid);
+                       if (strncmp(long_str_uuid, short_str_uuid, 8) == 0) {
+                               uuid_copy(current_uuid, sessions[i].uuid);
+                               break;
+                       }
+               }
+       }
+
+       if (opt_session_name != NULL) {
+               session_name = strndup(opt_session_name, NAME_MAX);
+       }
+}
+
+/*
+ * shorten_uuid
+ *
+ * Small function to shorten the 37 bytes long uuid_t
+ * string representation to 8 characters.
+ */
+static void shorten_uuid(char *long_u, char *short_u)
+{
+       memcpy(short_u, long_u, 8);
+       short_u[UUID_SHORT_STR_LEN - 1] = '\0';
+}
+
+/*
+ *  set_session_uuid
+ *
+ *  Set current session uuid to the current flow of
+ *  command(s) using the already shorten uuid or
+ *  current full uuid.
+ */
+static int set_session_uuid(void)
+{
+       int ret, count, i;
+       char str_uuid[37];
+       struct lttng_session *sessions;
+
+       if (!uuid_is_null(current_uuid)) {
+               lttng_set_current_session_uuid(&current_uuid);
+               goto end;
+       }
+
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ret = count;
+               goto error;
+       }
+
+       for (i = 0; i < count; i++) {
+               uuid_unparse(sessions[i].uuid, str_uuid);
+               if (strncmp(str_uuid, short_str_uuid, 8) == 0) {
+                       lttng_set_current_session_uuid(&sessions[i].uuid);
+                       break;
+               }
+       }
+
+       free(sessions);
+
+end:
+       return 0;
+
+error:
+       return ret;
+}
+
+/*
+ *  process_opt_list_traces
+ *
+ *  Get list of all traces for a specific session uuid.
+ */
+static int process_opt_list_traces(void)
+{
+       int ret, i;
+       struct lttng_trace *traces;
+
+       ret = lttng_list_traces(&current_uuid, &traces);
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("Userspace traces:");
+       for (i = 0; i < ret; i++) {
+               if (traces[i].type == USERSPACE) {
+                       MSG("\t%d) %s (pid: %d): %s",
+                                       i, traces[i].name, traces[i].pid,
+                                       get_cmdline_by_pid(traces[i].pid));
+               } else {
+                       break;
+               }
+       }
+
+       MSG("Kernel traces:");
+       for (;i < ret; i++) {
+               if (traces[i].type == KERNEL) {
+                       MSG("\t%d) %s", i, traces[i].name);
+               }
+       }
+
+       free(traces);
+
+error:
+       return ret;
 }
 
 /*
@@ -136,16 +302,28 @@ static int process_opt_create_session(void)
        int ret;
        uuid_t session_id;
        char str_uuid[37];
+       char name[NAME_MAX];
+       time_t rawtime;
+       struct tm *timeinfo;
+
+       /* Auto session creation */
+       if (opt_create_session == 0) {
+               time(&rawtime);
+               timeinfo = localtime(&rawtime);
+               strftime(name, sizeof(name), "%Y%m%d-%H%M%S", timeinfo);
+               session_name = strndup(name, sizeof(name));
+       }
 
-       ret = lttng_create_session(opt_create_session, &session_id);
+       ret = lttng_create_session(session_name, &session_id);
        if (ret < 0) {
                goto error;
        }
 
        uuid_unparse(session_id, str_uuid);
+       uuid_copy(current_uuid, session_id);
+       shorten_uuid(str_uuid, short_str_uuid);
 
-       MSG("Session created:");
-       MSG("    %s (%s)", opt_create_session, str_uuid);
+       MSG("Session UUID created: %s.%s", session_name, short_str_uuid);
 
 error:
        return ret;
@@ -160,21 +338,26 @@ error:
 static int process_opt_list_sessions(void)
 {
        int ret, count, i;
+       char tmp_short_uuid[9];
+       char str_uuid[37];
        struct lttng_session *sess;
 
        count = lttng_list_sessions(&sess);
+       DBG("Session count %d", count);
        if (count < 0) {
                ret = count;
                goto error;
        }
 
-       MSG("Available sessions [Name (uuid)]:");
+       MSG("Available sessions (UUIDs):");
        for (i = 0; i < count; i++) {
-               MSG("\tName: %s (uuid: %s)", sess[i].name, sess[i].uuid);
+               uuid_unparse(sess[i].uuid, str_uuid);
+               shorten_uuid(str_uuid, tmp_short_uuid);
+               MSG("    %d) %s.%s", i+1, sess[i].name, tmp_short_uuid);
        }
 
        free(sess);
-       MSG("\nTo select a session, use --session UUID.");
+       MSG("\nTo select a session, use -s, --session UUID.");
 
        return 0;
 
@@ -202,8 +385,8 @@ static int process_opt_list_apps(void)
 
        MSG("LTTng UST traceable application [name (pid)]:");
        for (i=0; i < count; i++) {
-               ret = get_cmdline_by_pid(pids[i], &cmdline);
-               if (!ret) {
+               cmdline = get_cmdline_by_pid(pids[i]);
+               if (cmdline == NULL) {
                        MSG("\t(not running) (%d)", pids[i]);
                        continue;
                }
@@ -223,34 +406,32 @@ error:
 /*
  *  get_cmdline_by_pid
  *
- *  Get command line from /proc for a
- *  specific pid. Allocate cmdline so the
- *  user must free() that pointer.
+ *  Get command line from /proc for a specific pid.
  *
- *  On success, return 1
- *  On error (not found), return 0
+ *  On success, return an allocated string pointer pointing to
+ *  the proc cmdline.
+ *  On error, return NULL.
  */
-static int get_cmdline_by_pid(pid_t pid, char **cmdline)
+static char *get_cmdline_by_pid(pid_t pid)
 {
        int ret;
        FILE *fp;
+       char *cmdline = NULL;
        char path[24];  /* Can't go bigger than /proc/65535/cmdline */
 
        snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
        fp = fopen(path, "r");
        if (fp == NULL) {
-               goto not_running;
+               goto end;
        }
 
        /* Caller must free() *cmdline */
-       *cmdline = malloc(PATH_MAX);
-       ret = fread(*cmdline, 1, PATH_MAX, fp);
+       cmdline = malloc(PATH_MAX);
+       ret = fread(cmdline, 1, PATH_MAX, fp);
        fclose(fp);
 
-       return 1;
-
-not_running:
-       return 0;
+end:
+       return cmdline;
 }
 
 /*
@@ -264,9 +445,20 @@ not_running:
  */
 static int validate_options(void)
 {
-       if ((opt_session_uuid == NULL) &&
-                       (opt_create_trace || opt_start_trace)) {
-               ERR("Can't act on trace without a session ID.\nPlease specify using --session UUID");
+       /* Conflicting command */
+       if (opt_start_trace && opt_stop_trace) {
+               ERR("Can't use --start and --stop together.");
+               goto error;
+       /* If no PID specified and trace_kernel is off */
+       } else if ((opt_trace_pid == 0 && opt_trace_kernel == 0) &&
+                       (opt_create_trace || opt_start_trace || opt_stop_trace)) {
+               ERR("Please specify a PID using -p, --pid PID.");
+               goto error;
+       } else if (opt_session_uuid && opt_create_session) {
+               ERR("Please don't use -s and -c together. Useless action.");
+               goto error;
+       } else if (opt_list_traces && opt_session_uuid == NULL) {
+               ERR("Can't use -t without -s, --session option.");
                goto error;
        }
 
@@ -426,15 +618,17 @@ static void sighandler(int sig)
 
        return;
 }
+
 /*
  * clean_exit
  */
 void clean_exit(int code)
 {
        DBG("Clean exit");
-       if (lttng_disconnect_sessiond() < 0) {
-               ERR("Session daemon disconnect failed.");
+       if (session_name) {
+               free(session_name);
        }
+
        exit(code);
 }
 
This page took 0.027835 seconds and 4 git commands to generate.