Fix message argument type
[lttng-tools.git] / lttng / lttng.c
index c7ff4edde334dd5131e1b207c902498cc8fc5ce1..b523960c33063be98e5bdf35fc9359fcdf76835f 100644 (file)
 #include <sys/wait.h>
 #include <unistd.h>
 
-#include <lttng/liblttngctl.h>
+#include <lttng/lttng.h>
 
-#include "lttng.h"
 #include "lttngerr.h"
+#include "options.h"
 
 /* Variables */
 static char *progname;
+static char *session_name;
+static uuid_t current_uuid;
+static int auto_session;
+static int auto_trace;
 
 /* 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_kernel_list_events(void);
+static int process_opt_create_session(void);
+static int process_kernel_create_trace(void);
+static int process_opt_kernel_event(void);
+static int process_kernel_start_trace(void);
+static int set_session_uuid(void);
 static void sighandler(int sig);
 static int set_signal_handler(void);
+static int validate_options(void);
+static char *get_cmdline_by_pid(pid_t pid);
+static void set_opt_session_info(void);
 
 /*
  *  start_client
@@ -56,17 +70,14 @@ static int process_client_opt(void)
 {
        int ret;
 
-       /* 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();
                if (ret < 0) {
                        goto end;
                }
+               goto error;
        }
 
        if (opt_list_session) {
@@ -74,12 +85,390 @@ static int process_client_opt(void)
                if (ret < 0) {
                        goto end;
                }
+               goto error;
+       }
+
+       if (opt_list_events) {
+               if (opt_trace_kernel) {
+                       ret = process_opt_kernel_list_events();
+                       if (ret < 0) {
+                               goto end;
+                       }
+               } else if (opt_trace_pid != 0) {
+                       // TODO
+               }
+               goto error;
+       }
+
+       /* Session creation or auto session set on */
+       if (auto_session || opt_create_session) {
+               DBG("Creating a new session");
+               ret = process_opt_create_session();
+               if (ret < 0) {
+                       goto end;
+               }
+       }
+
+       ret = set_session_uuid();
+       if (ret < 0) {
+               ERR("Session %s not found", opt_session_name);
+               goto error;
+       }
+
+       if (opt_destroy_session) {
+               ret = lttng_destroy_session(&current_uuid);
+               if (ret < 0) {
+                       goto end;
+               }
+               MSG("Session %s destroyed.", opt_session_name);
+       }
+
+       if (opt_list_traces) {
+               ret = process_opt_list_traces();
+               if (ret < 0) {
+                       goto end;
+               }
+       }
+
+       /*
+        * Action on traces (kernel or/and userspace).
+        */
+
+       if (opt_trace_kernel) {
+               if (auto_trace || opt_create_trace) {
+                       DBG("Creating a kernel trace");
+                       ret = process_kernel_create_trace();
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+
+               if (opt_event_list != NULL || opt_enable_all_event) {
+                       ret = process_opt_kernel_event();
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+
+               if (auto_trace || opt_start_trace) {
+                       DBG("Starting kernel tracing");
+                       ret = process_kernel_start_trace();
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+
+               if (opt_stop_trace) {
+                       DBG("Stopping kernel tracing");
+                       ret = lttng_kernel_stop_tracing();
+                       if (ret < 0) {
+                               goto end;
+                       }
+               }
+       }
+
+       if (opt_trace_pid != 0) {
+               if (auto_trace || 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!");
+               }
+
+               if (auto_trace || 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!");
+               }
+
        }
 
        return 0;
 
 end:
        ERR("%s", lttng_get_readable_code(ret));
+error: /* fall through */
+       return ret;
+}
+
+/*
+ *  process_kernel_start_trace
+ *
+ *  Start a kernel trace.
+ */
+static int process_kernel_start_trace(void)
+{
+       int ret;
+
+       ret = lttng_kernel_create_stream();
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = lttng_kernel_start_tracing();
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("Kernel tracing started");
+
+       return 0;
+
+error:
+       return ret;
+}
+
+/*
+ *  process_kernel_create_trace
+ *
+ *  Create a kernel trace.
+ */
+static int process_kernel_create_trace(void)
+{
+       int ret;
+
+       /* Setup kernel session */
+       ret = lttng_kernel_create_session();
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* Create an empty channel (with no event) */
+       ret = lttng_kernel_create_channel();
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* Opening metadata for session */
+       ret = lttng_kernel_open_metadata();
+       if (ret < 0) {
+               goto error;
+       }
+
+       return 0;
+
+error:
+       return ret;
+}
+
+/*
+ *  process_opt_kernel_list_events
+ *
+ *  Ask for all trace events in the kernel and pretty print them.
+ */
+static int process_opt_kernel_list_events(void)
+{
+       int ret, pos, size;
+       char *event_list, *event, *ptr;
+
+       DBG("Getting all tracing events");
+
+       ret = lttng_kernel_list_events(&event_list);
+       if (ret < 0) {
+               ERR("Unable to list events.");
+               return ret;
+       }
+
+       MSG("Kernel tracepoints:\n-------------");
+
+       ptr = event_list;
+       while ((size = sscanf(ptr, "event { name = %m[^;]; };%n\n", &event, &pos)) == 1) {
+               MSG("    - %s", event);
+               /* Move pointer to the next line */
+               ptr += pos + 1;
+               free(event);
+       }
+
+       free(event_list);
+
+       return 0;
+}
+
+/*
+ *  process_opt_kernel_event
+ *
+ *  Enable kernel event from the command line list given.
+ */
+static int process_opt_kernel_event(void)
+{
+       int ret;
+       char *event_name;
+
+       if (opt_enable_all_event) {
+               ret = lttng_kernel_enable_event(NULL);
+               if (ret < 0) {
+                       ERR("%s", lttng_get_readable_code(ret));
+               } else {
+                       MSG("All kernel event enabled");
+               }
+
+               goto end;
+       }
+
+       event_name = strtok(opt_event_list, ",");
+       while (event_name != NULL) {
+               DBG("Enabling kernel event %s", event_name);
+               ret = lttng_kernel_enable_event(event_name);
+               if (ret < 0) {
+                       ERR("%s %s", lttng_get_readable_code(ret), event_name);
+               } else {
+                       MSG("Kernel event %s enabled.", event_name);
+               }
+               /* Next event */
+               event_name = strtok(NULL, ",");
+       }
+
+end:
+       return 0;
+}
+
+/*
+ *  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)
+{
+       if (opt_session_name != NULL) {
+               session_name = strndup(opt_session_name, NAME_MAX);
+               DBG("Session name set to %s", session_name);
+       }
+}
+
+/*
+ *  set_session_uuid
+ *
+ *  Set current session uuid to the current flow of command(s) using the
+ *  session_name.
+ */
+static int set_session_uuid(void)
+{
+       int ret, count, i, found = 0;
+       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++) {
+               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                       lttng_set_current_session_uuid(&sessions[i].uuid);
+                       uuid_copy(current_uuid, sessions[i].uuid);
+                       found = 1;
+                       break;
+               }
+       }
+
+       free(sessions);
+
+       if (!found) {
+               return -1;
+       }
+
+end:
+       DBG("Session UUID set");
+       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);
+       DBG("Number of traces to list %d", ret);
+       if (ret < 0) {
+               goto error;
+       }
+
+       /* No traces */
+       if (ret == 0) {
+               MSG("No traces found.");
+               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;
+}
+
+/*
+ *  process_opt_create_session
+ *
+ *  Create a new session using the name pass
+ *  to the command line.
+ */
+static int process_opt_create_session(void)
+{
+       int ret;
+       char name[NAME_MAX];
+       time_t rawtime;
+       struct tm *timeinfo;
+
+       /* Auto session name creation */
+       if (opt_session_name == NULL) {
+               time(&rawtime);
+               timeinfo = localtime(&rawtime);
+               strftime(name, sizeof(name), "auto-%Y%m%d-%H%M%S", timeinfo);
+               session_name = strndup(name, sizeof(name));
+               DBG("Auto session name set to %s", session_name);
+       }
+
+       ret = lttng_create_session(session_name);
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("Session created: %s", session_name);
+
+error:
        return ret;
 }
 
@@ -92,21 +481,22 @@ end:
 static int process_opt_list_sessions(void)
 {
        int ret, count, i;
-       struct lttng_session *sess;
+       struct lttng_session *sessions;
 
-       count = lttng_list_sessions(&sess);
+       count = lttng_list_sessions(&sessions);
+       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);
+               MSG("    %d) %s", i+1, sessions[i].name);
        }
 
-       free(sess);
-       MSG("\nTo select a session, use --session UUID.");
+       free(sessions);
+       MSG("\nTo select a session, use -s, --session UUID.");
 
        return 0;
 
@@ -124,9 +514,7 @@ static int process_opt_list_apps(void)
 {
        int i, ret, count;
        pid_t *pids;
-       FILE *fp;
-       char path[24];  /* Can't go bigger than /proc/65535/cmdline */
-       char cmdline[PATH_MAX];
+       char *cmdline;
 
        count = lttng_ust_list_apps(&pids);
        if (count < 0) {
@@ -136,15 +524,13 @@ static int process_opt_list_apps(void)
 
        MSG("LTTng UST traceable application [name (pid)]:");
        for (i=0; i < count; i++) {
-               snprintf(path, sizeof(path), "/proc/%d/cmdline", pids[i]);
-               fp = fopen(path, "r");
-               if (fp == NULL) {
+               cmdline = get_cmdline_by_pid(pids[i]);
+               if (cmdline == NULL) {
                        MSG("\t(not running) (%d)", pids[i]);
                        continue;
                }
-               ret = fread(cmdline, 1, sizeof(cmdline), fp);
                MSG("\t%s (%d)", cmdline, pids[i]);
-               fclose(fp);
+               free(cmdline);
        }
 
        /* Allocated by lttng_ust_list_apps() */
@@ -156,6 +542,113 @@ error:
        return ret;
 }
 
+/*
+ *  get_cmdline_by_pid
+ *
+ *  Get command line from /proc for a specific pid.
+ *
+ *  On success, return an allocated string pointer pointing to
+ *  the proc cmdline.
+ *  On error, return NULL.
+ */
+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 end;
+       }
+
+       /* Caller must free() *cmdline */
+       cmdline = malloc(PATH_MAX);
+       ret = fread(cmdline, 1, PATH_MAX, fp);
+       fclose(fp);
+
+end:
+       return cmdline;
+}
+
+/*
+ *  validate_options
+ *
+ *  Make sure that all options passed to the command line are compatible with
+ *  each others.
+ *
+ *  On error, return -1
+ *  On success, return 0
+ */
+static int validate_options(void)
+{
+       /* If listing options, jump validation */
+       if (opt_list_apps || opt_list_session) {
+               goto end;
+       }
+       /* 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) &&
+                       (opt_create_trace || opt_start_trace || opt_stop_trace || opt_destroy_trace)) {
+               ERR("Please specify for which tracer (-k or -p PID).");
+               goto error;
+       /* List traces, we need a session name */
+       } else if (opt_list_traces && opt_session_name == NULL) {
+               ERR("Can't use -t without -s, --session option.");
+               goto error;
+       /* Can't set event for both kernel and userspace at the same time */
+       } else if (opt_event_list != NULL && (opt_trace_kernel && opt_trace_pid)) {
+               ERR("Please don't use --event for both kernel and userspace.\nOne at a time to enable events.");
+               goto error;
+       /* Don't need a trace name for kernel tracig */
+       } else if (opt_trace_name != NULL && opt_trace_kernel) {
+               ERR("For action on a kernel trace, please don't specify a trace name.");
+               goto error;
+       } else if (opt_destroy_trace && opt_session_name == NULL) {
+               ERR("Please specify a session in order to destroy a trace");
+               goto error;
+       } else if (opt_create_trace || opt_destroy_trace) {
+               /* Both kernel and user-space are denied for these options */
+               if (opt_trace_pid != 0 && opt_trace_kernel) {
+                       ERR("Kernel and user-space trace creation and destruction can't be used together.");
+                       goto error;
+               /* Need a trace name for user-space tracing */
+               } else if (opt_trace_name == NULL && opt_trace_pid != 0) {
+                       ERR("Please specify a trace name for user-space tracing");
+                       goto error;
+               }
+       } else if (opt_stop_trace && opt_trace_pid != 0 && opt_trace_name == NULL) {
+               ERR("Please specify a trace name for user-space tracing");
+               goto error;
+       } else if (opt_stop_trace && opt_session_name == NULL) {
+               ERR("Please specify a session to stop tracing");
+               goto error;
+       }
+
+       /* If start trace, auto start tracing */
+       if (opt_start_trace || opt_event_list != NULL || opt_enable_all_event) {
+               DBG("Requesting auto tracing");
+               auto_trace = 1;
+       }
+
+       /* If no session, auto create one */
+       if (opt_session_name == NULL) {
+               DBG("Requesting an auto session creation");
+               auto_session = 1;
+       }
+
+end:
+       return 0;
+
+error:
+       return -1;
+}
+
 /*
  *  spawn_sessiond
  *
@@ -169,20 +662,19 @@ static int spawn_sessiond(char *pathname)
        MSG("Spawning session daemon");
        pid = fork();
        if (pid == 0) {
-               /* Spawn session daemon and tell
+               /*
+                * Spawn session daemon and tell
                 * it to signal us when ready.
                 */
-               ret = execlp(pathname, "ltt-sessiond", "--sig-parent", "--quiet", NULL);
-               if (ret < 0) {
-                       if (errno == ENOENT) {
-                               ERR("No session daemon found. Use --sessiond-path.");
-                       } else {
-                               perror("execlp");
-                       }
-                       kill(getppid(), SIGTERM);
-                       exit(EXIT_FAILURE);
+               execlp(pathname, "ltt-sessiond", "--sig-parent", "--quiet", NULL);
+               /* execlp only returns if error happened */
+               if (errno == ENOENT) {
+                       ERR("No session daemon found. Use --sessiond-path.");
+               } else {
+                       perror("execlp");
                }
-               exit(EXIT_SUCCESS);
+               kill(getppid(), SIGTERM);       /* unpause parent */
+               exit(EXIT_FAILURE);
        } else if (pid > 0) {
                /* Wait for ltt-sessiond to start */
                pause();
@@ -207,10 +699,10 @@ end:
 static int check_ltt_sessiond(void)
 {
        int ret;
-       char *pathname = NULL;
+       char *pathname = NULL, *alloc_pathname = NULL;
 
-       ret = lttng_check_session_daemon();
-       if (ret < 0) {
+       ret = lttng_session_daemon_alive();
+       if (ret == 0) { /* not alive */
                /* Try command line option path */
                if (opt_sessiond_path != NULL) {
                        ret = access(opt_sessiond_path, F_OK | X_OK);
@@ -222,24 +714,19 @@ static int check_ltt_sessiond(void)
                } else {
                        /* Try LTTNG_SESSIOND_PATH env variable */
                        pathname = getenv(LTTNG_SESSIOND_PATH_ENV);
-                       if (pathname != NULL) {
-                               /* strdup here in order to make the free()
-                                * not fail later on.
-                                */
-                               pathname = strdup(pathname);
-                       }
                }
 
                /* Let's rock and roll */
                if (pathname == NULL) {
-                       ret = asprintf(&pathname, "ltt-sessiond");
+                       ret = asprintf(&alloc_pathname, "ltt-sessiond");
                        if (ret < 0) {
                                goto end;
                        }
+                       pathname = alloc_pathname;
                }
 
                ret = spawn_sessiond(pathname);
-               free(pathname);
+               free(alloc_pathname);
                if (ret < 0) {
                        ERR("Problem occurs when starting %s", pathname);
                        goto end;
@@ -290,26 +777,33 @@ end:
  */
 static void sighandler(int sig)
 {
-       DBG("%d received", sig);
        switch (sig) {
                case SIGTERM:
+                       DBG("SIGTERM catched");
                        clean_exit(EXIT_FAILURE);
                        break;
                case SIGCHLD:
                        /* Notify is done */
+                       DBG("SIGCHLD catched");
                        break;
                default:
+                       DBG("Unknown signal %d catched", sig);
                        break;
        }
 
        return;
 }
+
 /*
  * clean_exit
  */
 void clean_exit(int code)
 {
        DBG("Clean exit");
+       if (session_name) {
+               free(session_name);
+       }
+
        exit(code);
 }
 
@@ -328,13 +822,18 @@ int main(int argc, char *argv[])
        }
 
        ret = parse_args(argc, (const char **) argv);
+       if (ret < 0) {
+               clean_exit(EXIT_FAILURE);
+       }
+
+       ret = validate_options();
        if (ret < 0) {
                return EXIT_FAILURE;
        }
 
        ret = set_signal_handler();
        if (ret < 0) {
-               return ret;
+               clean_exit(ret);
        }
 
        if (opt_tracing_group != NULL) {
@@ -347,7 +846,7 @@ int main(int argc, char *argv[])
                DBG("Kernel tracing activated");
                if (getuid() != 0) {
                        ERR("%s must be setuid root", progname);
-                       return -EPERM;
+                       clean_exit(-EPERM);
                }
        }
 
@@ -355,13 +854,15 @@ int main(int argc, char *argv[])
         * If no, a daemon will be spawned.
         */
        if (opt_no_sessiond == 0 && (check_ltt_sessiond() < 0)) {
-               return EXIT_FAILURE;
+               clean_exit(EXIT_FAILURE);
        }
 
        ret = process_client_opt();
        if (ret < 0) {
-               return ret;
+               clean_exit(ret);
        }
 
+       clean_exit(0);
+
        return 0;
 }
This page took 0.032894 seconds and 5 git commands to generate.