bin: compile lttng as C++
authorSimon Marchi <simon.marchi@efficios.com>
Fri, 3 Sep 2021 21:31:28 +0000 (17:31 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 15 Oct 2021 20:57:45 +0000 (16:57 -0400)
Compile the code of the lttng binary as C++ source.

 - start by renaming all files under src/bin/lttng to have the .cpp
   extension, adjust Makefile.am accordingly
 - apply the sophisticated algorithm:

     while does_not_build():
       fix_error()

   until completion

Fixes fall in these categories:

 - add extern "C" to headers of functions implemented in C.  This is
   likely temporary: at some point some of these things will be
   implemented in C++, at which point we'll remove the extern "C".

 - rename mi_lttng_version to mi_lttng_version_data, to avoid a -Wshadow
   warning about the mi_lttng_version function hiding the
   mi_lttng_version's struct constructor

 - we have the same warning about lttng_calibrate, but we can't rename
   it, it's exposed in a public header.  Add some pragmas to disable the
   warning around there.  We will need more macro smartness in case we
   need to support a compiler that doesn't understand these pragmas.

 - in filter-ast.h, add a dummy field to the empty struct, to avoid a
   -Wextern-c-compat warning with clang++ (it warns us that the struct
   has size 0 in C but size 1 in C++).

 - in add_context.cpp, we can't initialize ctx_opts' union field like we
   did in C. Fix that by adding a ctx_opts constructor for each kind of
   context and implement the PERF_* macros to use them.

 - need to explicitly cast void pointer to type of the destination, for
   example the eturn value of allocation functions, or parameter of
   "destroy" functions

 - need to explicitly cast when passing an int to an enum parameter, for
   example an lttng_error_code parameter

 - remove use of designated array initializers, for example for
   schedule_type_str in disable_rotation.cpp

 - fix order of struct initializers to match order of field
   declarations, for example in list_triggers.cpp, function
   cmd_list_triggers

 - rename some things to avoid clashing with keywords, for example in
   runas.h

Change-Id: Id743b141552a412b4104af4dda8969eef5032388
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
88 files changed:
configure.ac
include/lttng/condition/condition-internal.h
include/lttng/event-rule/event-rule-internal.h
include/lttng/event-rule/kernel-syscall-internal.h
include/lttng/lttng.h
include/lttng/trigger/trigger-internal.h
src/bin/lttng/Makefile.am
src/bin/lttng/commands/add_context.c [deleted file]
src/bin/lttng/commands/add_context.cpp [new file with mode: 0644]
src/bin/lttng/commands/add_trigger.c [deleted file]
src/bin/lttng/commands/add_trigger.cpp [new file with mode: 0644]
src/bin/lttng/commands/clear.c [deleted file]
src/bin/lttng/commands/clear.cpp [new file with mode: 0644]
src/bin/lttng/commands/create.c [deleted file]
src/bin/lttng/commands/create.cpp [new file with mode: 0644]
src/bin/lttng/commands/destroy.c [deleted file]
src/bin/lttng/commands/destroy.cpp [new file with mode: 0644]
src/bin/lttng/commands/disable_channels.c [deleted file]
src/bin/lttng/commands/disable_channels.cpp [new file with mode: 0644]
src/bin/lttng/commands/disable_events.c [deleted file]
src/bin/lttng/commands/disable_events.cpp [new file with mode: 0644]
src/bin/lttng/commands/disable_rotation.c [deleted file]
src/bin/lttng/commands/disable_rotation.cpp [new file with mode: 0644]
src/bin/lttng/commands/enable_channels.c [deleted file]
src/bin/lttng/commands/enable_channels.cpp [new file with mode: 0644]
src/bin/lttng/commands/enable_events.c [deleted file]
src/bin/lttng/commands/enable_events.cpp [new file with mode: 0644]
src/bin/lttng/commands/enable_rotation.c [deleted file]
src/bin/lttng/commands/enable_rotation.cpp [new file with mode: 0644]
src/bin/lttng/commands/help.c [deleted file]
src/bin/lttng/commands/help.cpp [new file with mode: 0644]
src/bin/lttng/commands/list.c [deleted file]
src/bin/lttng/commands/list.cpp [new file with mode: 0644]
src/bin/lttng/commands/list_triggers.c [deleted file]
src/bin/lttng/commands/list_triggers.cpp [new file with mode: 0644]
src/bin/lttng/commands/load.c [deleted file]
src/bin/lttng/commands/load.cpp [new file with mode: 0644]
src/bin/lttng/commands/metadata.c [deleted file]
src/bin/lttng/commands/metadata.cpp [new file with mode: 0644]
src/bin/lttng/commands/regenerate.c [deleted file]
src/bin/lttng/commands/regenerate.cpp [new file with mode: 0644]
src/bin/lttng/commands/remove_trigger.c [deleted file]
src/bin/lttng/commands/remove_trigger.cpp [new file with mode: 0644]
src/bin/lttng/commands/rotate.c [deleted file]
src/bin/lttng/commands/rotate.cpp [new file with mode: 0644]
src/bin/lttng/commands/save.c [deleted file]
src/bin/lttng/commands/save.cpp [new file with mode: 0644]
src/bin/lttng/commands/set_session.c [deleted file]
src/bin/lttng/commands/set_session.cpp [new file with mode: 0644]
src/bin/lttng/commands/snapshot.c [deleted file]
src/bin/lttng/commands/snapshot.cpp [new file with mode: 0644]
src/bin/lttng/commands/start.c [deleted file]
src/bin/lttng/commands/start.cpp [new file with mode: 0644]
src/bin/lttng/commands/status.c [deleted file]
src/bin/lttng/commands/status.cpp [new file with mode: 0644]
src/bin/lttng/commands/stop.c [deleted file]
src/bin/lttng/commands/stop.cpp [new file with mode: 0644]
src/bin/lttng/commands/track-untrack.c [deleted file]
src/bin/lttng/commands/track-untrack.cpp [new file with mode: 0644]
src/bin/lttng/commands/version.c [deleted file]
src/bin/lttng/commands/version.cpp [new file with mode: 0644]
src/bin/lttng/commands/view.c [deleted file]
src/bin/lttng/commands/view.cpp [new file with mode: 0644]
src/bin/lttng/conf.c [deleted file]
src/bin/lttng/conf.cpp [new file with mode: 0644]
src/bin/lttng/loglevel.c [deleted file]
src/bin/lttng/loglevel.cpp [new file with mode: 0644]
src/bin/lttng/loglevel.h
src/bin/lttng/lttng.c [deleted file]
src/bin/lttng/lttng.cpp [new file with mode: 0644]
src/bin/lttng/uprobe.c [deleted file]
src/bin/lttng/uprobe.cpp [new file with mode: 0644]
src/bin/lttng/utils.c [deleted file]
src/bin/lttng/utils.cpp [new file with mode: 0644]
src/common/argpar/argpar.h
src/common/compat/string.h
src/common/dynamic-array.h
src/common/error.h
src/common/filter/filter-ast.h
src/common/mi-lttng.c
src/common/mi-lttng.h
src/common/runas.h
src/common/spawn-viewer.h
src/common/string-utils/string-utils.h
src/common/time.h
src/common/tracker.h
src/common/uri.h
src/common/utils.h

index ea327f9b8ee82fa2ab7f2d3893fd855e21191e06..12cc7a17ed79a85ebedf0436dc420f02348c239f 100644 (file)
@@ -71,6 +71,9 @@ m4_define([WARN_FLAGS_LIST], [ dnl
   -Wmissing-parameter-type dnl
   -Wshadow dnl
   -Wno-gnu-folding-constant dnl
+  dnl GCC enables this with -Wall in C++, and that generates a
+  dnl lot of warnings that have on average a low value to fix.
+  -Wno-sign-compare dnl
 ])
 
 # Pass -Werror as an extra flag during the test: this is needed to make the
index 5bafaf05b266e00fee1b1ee03e8b58268244a77b..a491d3fe34a46e33bf02f6d4a5c585724a17c89f 100644 (file)
 #include <urcu/list.h>
 #include <urcu/ref.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct mi_writer;
 struct mi_lttng_error_query_callbacks;
 struct lttng_trigger;
@@ -82,4 +86,8 @@ enum lttng_error_code lttng_condition_mi_serialize(
 
 const char *lttng_condition_type_str(enum lttng_condition_type type);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_CONDITION_INTERNAL_H */
index 8026748634fd0f9efa80121ee74c0d2499865ff5..98d1f449d2e9000d6d781a6802275d8e74af45e7 100644 (file)
 #include <sys/types.h>
 #include <urcu/ref.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct lttng_payload;
 struct lttng_payload_view;
 struct mi_writer;
@@ -153,4 +157,8 @@ bool lttng_event_rule_targets_agent_domain(const struct lttng_event_rule *rule);
 enum lttng_error_code lttng_event_rule_mi_serialize(
                const struct lttng_event_rule *rule, struct mi_writer *writer);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_EVENT_RULE_INTERNAL_H */
index 31905cef6c18cefa1b64c8c4498fb0504382f0be..3e5e0991d64cf498b3f77afb53bf4b6466b29a4d 100644 (file)
 #include <lttng/event-rule/event-rule-internal.h>
 #include <lttng/event-rule/kernel-syscall.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct lttng_event_rule_kernel_syscall {
        struct lttng_event_rule parent;
        enum lttng_event_rule_kernel_syscall_emission_site emission_site;
@@ -46,4 +50,9 @@ ssize_t lttng_event_rule_kernel_syscall_create_from_payload(
 
 const char *lttng_event_rule_kernel_syscall_emission_site_str(
                enum lttng_event_rule_kernel_syscall_emission_site emission_site);
+
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_EVENT_RULE_KERNEL_SYSCALL_INTERNAL_H */
index 5f3df911369f4b4c736bb4cd1528ca493a135c69..01c4089e532f0c1433977097d585ad16aac75f83 100644 (file)
@@ -148,8 +148,11 @@ extern int lttng_stop_tracing_no_wait(const char *session_name);
  * Deprecated: As of LTTng 2.9, this function always returns
  * -LTTNG_ERR_UND.
  */
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wshadow"
 extern int lttng_calibrate(struct lttng_handle *handle,
                struct lttng_calibrate *calibrate);
+#pragma GCC diagnostic pop
 
 /*
  * Set URL for a consumer for a session and domain.
index dab46ae075dfa61fcea30168e9d74784281c01a8..69226bce75b3a5f45dfba06584e8192ff8195ef5 100644 (file)
 #include <sys/types.h>
 #include <urcu/ref.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct lttng_payload;
 struct lttng_payload_view;
 struct mi_writer;
@@ -278,4 +282,8 @@ enum lttng_trigger_status lttng_trigger_add_action_error_query_results(
 enum lttng_trigger_status lttng_trigger_set_name(
                struct lttng_trigger *trigger, const char *name);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_TRIGGER_INTERNAL_H */
index 50ab92988db3d88b957bc3aba9af6181d12d73ec..5d01c45a8c14341e548260c2ad2ddc0b0aed2896 100644 (file)
@@ -10,33 +10,33 @@ AUTOMAKE_OPTIONS = subdir-objects
 
 bin_PROGRAMS = lttng
 
-lttng_SOURCES = command.h conf.c conf.h commands/start.c \
-                               commands/list.c commands/create.c commands/destroy.c \
-                               commands/stop.c commands/enable_events.c \
-                               commands/disable_events.c commands/enable_channels.c \
-                               commands/disable_channels.c commands/add_context.c \
-                               commands/set_session.c commands/version.c \
-                               commands/view.c \
-                               commands/snapshot.c \
-                               commands/save.c \
-                               commands/load.c \
-                               commands/track-untrack.c \
-                               commands/status.c \
-                               commands/metadata.c \
-                               commands/regenerate.c \
-                               commands/help.c \
-                               commands/rotate.c \
-                               commands/enable_rotation.c \
-                               commands/disable_rotation.c \
-                               commands/clear.c \
-                               loglevel.c loglevel.h \
-                               commands/add_trigger.c \
-                               commands/list_triggers.c \
-                               commands/remove_trigger.c \
-                               utils.c utils.h lttng.c \
-                               uprobe.c uprobe.h
+lttng_SOURCES = command.h conf.cpp conf.h commands/start.cpp \
+                               commands/list.cpp commands/create.cpp commands/destroy.cpp \
+                               commands/stop.cpp commands/enable_events.cpp \
+                               commands/disable_events.cpp commands/enable_channels.cpp \
+                               commands/disable_channels.cpp commands/add_context.cpp \
+                               commands/set_session.cpp commands/version.cpp \
+                               commands/view.cpp \
+                               commands/snapshot.cpp \
+                               commands/save.cpp \
+                               commands/load.cpp \
+                               commands/track-untrack.cpp \
+                               commands/status.cpp \
+                               commands/metadata.cpp \
+                               commands/regenerate.cpp \
+                               commands/help.cpp \
+                               commands/rotate.cpp \
+                               commands/enable_rotation.cpp \
+                               commands/disable_rotation.cpp \
+                               commands/clear.cpp \
+                               loglevel.cpp loglevel.h \
+                               commands/add_trigger.cpp \
+                               commands/list_triggers.cpp \
+                               commands/remove_trigger.cpp \
+                               utils.cpp utils.h lttng.cpp \
+                               uprobe.cpp uprobe.h
 
-lttng_CFLAGS = $(AM_CFLAGS) $(POPT_CFLAGS)
+lttng_CXXFLAGS = $(AM_CXXFLAGS) $(POPT_CFLAGS)
 
 lttng_LDADD = $(top_builddir)/src/lib/lttng-ctl/liblttng-ctl.la \
                        $(top_builddir)/src/common/libcommon.la \
diff --git a/src/bin/lttng/commands/add_context.c b/src/bin/lttng/commands/add_context.c
deleted file mode 100644 (file)
index 90a54f7..0000000
+++ /dev/null
@@ -1,1209 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <ctype.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <urcu/list.h>
-
-#include <lttng/domain-internal.h>
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-static char *opt_channel_name;
-static char *opt_session_name;
-static int opt_kernel;
-static int opt_userspace;
-static int opt_jul;
-static int opt_log4j;
-static char *opt_type;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-add-context.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_TYPE,
-       OPT_USERSPACE,
-       OPT_JUL,
-       OPT_LOG4J,
-       OPT_LIST_OPTIONS,
-       OPT_LIST,
-};
-
-static struct lttng_handle *handle;
-static struct mi_writer *writer;
-
-/*
- * Taken from the LTTng ABI
- */
-enum context_type {
-       CONTEXT_PID          = 0,
-       CONTEXT_PERF_COUNTER = 1,       /* Backward compat. */
-       CONTEXT_PROCNAME     = 2,
-       CONTEXT_PRIO         = 3,
-       CONTEXT_NICE         = 4,
-       CONTEXT_VPID         = 5,
-       CONTEXT_TID          = 6,
-       CONTEXT_VTID         = 7,
-       CONTEXT_PPID         = 8,
-       CONTEXT_VPPID        = 9,
-       CONTEXT_PTHREAD_ID   = 10,
-       CONTEXT_HOSTNAME     = 11,
-       CONTEXT_IP           = 12,
-       CONTEXT_PERF_CPU_COUNTER = 13,
-       CONTEXT_PERF_THREAD_COUNTER = 14,
-       CONTEXT_APP_CONTEXT  = 15,
-       CONTEXT_INTERRUPTIBLE = 16,
-       CONTEXT_PREEMPTIBLE  = 17,
-       CONTEXT_NEED_RESCHEDULE = 18,
-       CONTEXT_MIGRATABLE   = 19,
-       CONTEXT_CALLSTACK_KERNEL = 20,
-       CONTEXT_CALLSTACK_USER = 21,
-       CONTEXT_CGROUP_NS    = 22,
-       CONTEXT_IPC_NS       = 23,
-       CONTEXT_MNT_NS       = 24,
-       CONTEXT_NET_NS       = 25,
-       CONTEXT_PID_NS       = 26,
-       CONTEXT_USER_NS      = 27,
-       CONTEXT_UTS_NS       = 28,
-       CONTEXT_UID          = 29,
-       CONTEXT_EUID         = 30,
-       CONTEXT_SUID         = 31,
-       CONTEXT_GID          = 32,
-       CONTEXT_EGID         = 33,
-       CONTEXT_SGID         = 34,
-       CONTEXT_VUID         = 35,
-       CONTEXT_VEUID        = 36,
-       CONTEXT_VSUID        = 37,
-       CONTEXT_VGID         = 38,
-       CONTEXT_VEGID        = 39,
-       CONTEXT_VSGID        = 40,
-       CONTEXT_TIME_NS      = 41,
-};
-
-/*
- * Taken from the Perf ABI (all enum perf_*)
- */
-enum perf_type {
-       PERF_TYPE_HARDWARE = 0,
-       PERF_TYPE_SOFTWARE = 1,
-       PERF_TYPE_HW_CACHE = 3,
-       PERF_TYPE_RAW = 4,
-};
-
-enum perf_count_hard {
-       PERF_COUNT_HW_CPU_CYCLES                = 0,
-       PERF_COUNT_HW_INSTRUCTIONS              = 1,
-       PERF_COUNT_HW_CACHE_REFERENCES          = 2,
-       PERF_COUNT_HW_CACHE_MISSES              = 3,
-       PERF_COUNT_HW_BRANCH_INSTRUCTIONS       = 4,
-       PERF_COUNT_HW_BRANCH_MISSES             = 5,
-       PERF_COUNT_HW_BUS_CYCLES                = 6,
-       PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
-       PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
-};
-
-enum perf_count_soft {
-       PERF_COUNT_SW_CPU_CLOCK        = 0,
-       PERF_COUNT_SW_TASK_CLOCK       = 1,
-       PERF_COUNT_SW_PAGE_FAULTS      = 2,
-       PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
-       PERF_COUNT_SW_CPU_MIGRATIONS   = 4,
-       PERF_COUNT_SW_PAGE_FAULTS_MIN  = 5,
-       PERF_COUNT_SW_PAGE_FAULTS_MAJ  = 6,
-       PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
-       PERF_COUNT_SW_EMULATION_FAULTS = 8,
-};
-
-/*
- * Generalized hardware cache events:
- *
- *       { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
- *       { read, write, prefetch } x
- *       { accesses, misses }
- */
-enum perf_hw_cache_id {
-       PERF_COUNT_HW_CACHE_L1D                 = 0,
-       PERF_COUNT_HW_CACHE_L1I                 = 1,
-       PERF_COUNT_HW_CACHE_LL                  = 2,
-       PERF_COUNT_HW_CACHE_DTLB                = 3,
-       PERF_COUNT_HW_CACHE_ITLB                = 4,
-       PERF_COUNT_HW_CACHE_BPU                 = 5,
-
-       PERF_COUNT_HW_CACHE_MAX,                /* non-ABI */
-};
-
-enum perf_hw_cache_op_id {
-       PERF_COUNT_HW_CACHE_OP_READ             = 0,
-       PERF_COUNT_HW_CACHE_OP_WRITE            = 1,
-       PERF_COUNT_HW_CACHE_OP_PREFETCH         = 2,
-
-       PERF_COUNT_HW_CACHE_OP_MAX,             /* non-ABI */
-};
-
-enum perf_hw_cache_op_result_id {
-       PERF_COUNT_HW_CACHE_RESULT_ACCESS       = 0,
-       PERF_COUNT_HW_CACHE_RESULT_MISS         = 1,
-
-       PERF_COUNT_HW_CACHE_RESULT_MAX,         /* non-ABI */
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
-       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-       {"jul",            'j', POPT_ARG_NONE, 0, OPT_JUL, 0, 0},
-       {"log4j",          'l', POPT_ARG_NONE, 0, OPT_LOG4J, 0, 0},
-       {"type",           't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
-       {"list",           0, POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL},
-       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Context options
- */
-#define PERF_HW(optstr, name, type, hide)                              \
-       {                                                               \
-               (char *) optstr, type, hide,                            \
-               .u.perf = { PERF_TYPE_HARDWARE, PERF_COUNT_HW_##name, },\
-       }
-
-#define PERF_SW(optstr, name, type, hide)                              \
-       {                                                               \
-               (char *) optstr, type, hide,                            \
-               .u.perf = { PERF_TYPE_SOFTWARE, PERF_COUNT_SW_##name, },\
-       }
-
-#define _PERF_HW_CACHE(optstr, name, type, op, result, hide)           \
-       {                                                               \
-               (char *) optstr, type, hide,                            \
-               .u.perf = {                                             \
-                       PERF_TYPE_HW_CACHE,                             \
-                       (uint64_t) PERF_COUNT_HW_CACHE_##name           \
-                       | ((uint64_t) PERF_COUNT_HW_CACHE_OP_##op << 8) \
-                       | ((uint64_t) PERF_COUNT_HW_CACHE_RESULT_##result << 16), \
-               },                                                      \
-       }
-
-#define PERF_HW_CACHE(optstr, name, type, hide)                                \
-       _PERF_HW_CACHE(optstr "-loads", name, type,                     \
-               READ, ACCESS, hide),                                    \
-       _PERF_HW_CACHE(optstr "-load-misses", name, type,               \
-               READ, MISS, hide),                                      \
-       _PERF_HW_CACHE(optstr "-stores", name, type,                    \
-               WRITE, ACCESS, hide),                                   \
-       _PERF_HW_CACHE(optstr "-store-misses", name, type,              \
-               WRITE, MISS, hide),                                     \
-       _PERF_HW_CACHE(optstr "-prefetches", name, type,                \
-               PREFETCH, ACCESS, hide),                                \
-       _PERF_HW_CACHE(optstr "-prefetch-misses", name, type,           \
-               PREFETCH, MISS, hide)
-
-static
-const struct ctx_opts {
-       char *symbol;
-       enum context_type ctx_type;
-       int hide_help;  /* Hide from --help */
-       union {
-               struct {
-                       uint32_t type;
-                       uint64_t config;
-               } perf;
-               struct {
-                       char *provider_name;
-                       char *ctx_name;
-               } app_ctx;
-       } u;
-} ctx_opts[] = {
-       /*
-        * These (char *) casts (as well as those in the PERF_* macros) are
-        * safe because we never free these instances of `struct ctx_opts`.
-        */
-       { (char *) "pid", CONTEXT_PID },
-       { (char *) "procname", CONTEXT_PROCNAME },
-       { (char *) "prio", CONTEXT_PRIO },
-       { (char *) "nice", CONTEXT_NICE },
-       { (char *) "vpid", CONTEXT_VPID },
-       { (char *) "tid", CONTEXT_TID },
-       { (char *) "pthread_id", CONTEXT_PTHREAD_ID },
-       { (char *) "vtid", CONTEXT_VTID },
-       { (char *) "ppid", CONTEXT_PPID },
-       { (char *) "vppid", CONTEXT_VPPID },
-       { (char *) "hostname", CONTEXT_HOSTNAME },
-       { (char *) "ip", CONTEXT_IP },
-       { (char *) "interruptible", CONTEXT_INTERRUPTIBLE },
-       { (char *) "preemptible", CONTEXT_PREEMPTIBLE },
-       { (char *) "need_reschedule", CONTEXT_NEED_RESCHEDULE },
-       { (char *) "migratable", CONTEXT_MIGRATABLE },
-       { (char *) "callstack-kernel", CONTEXT_CALLSTACK_KERNEL },
-#if HAVE_MODULES_USERSPACE_CALLSTACK_CONTEXT
-       { (char *) "callstack-user", CONTEXT_CALLSTACK_USER },
-#endif
-       { (char *) "cgroup_ns", CONTEXT_CGROUP_NS },
-       { (char *) "ipc_ns", CONTEXT_IPC_NS },
-       { (char *) "mnt_ns", CONTEXT_MNT_NS },
-       { (char *) "net_ns", CONTEXT_NET_NS },
-       { (char *) "pid_ns", CONTEXT_PID_NS },
-       { (char *) "time_ns", CONTEXT_TIME_NS },
-       { (char *) "user_ns", CONTEXT_USER_NS },
-       { (char *) "uts_ns", CONTEXT_UTS_NS },
-       { (char *) "uid", CONTEXT_UID },
-       { (char *) "euid", CONTEXT_EUID },
-       { (char *) "suid", CONTEXT_SUID },
-       { (char *) "gid", CONTEXT_GID },
-       { (char *) "egid", CONTEXT_EGID },
-       { (char *) "sgid", CONTEXT_SGID },
-       { (char *) "vuid", CONTEXT_VUID },
-       { (char *) "veuid", CONTEXT_VEUID },
-       { (char *) "vsuid", CONTEXT_VSUID },
-       { (char *) "vgid", CONTEXT_VGID },
-       { (char *) "vegid", CONTEXT_VEGID },
-       { (char *) "vsgid", CONTEXT_VSGID },
-
-       /* Perf options */
-
-       /* Perf per-CPU counters */
-       PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:cycles", CPU_CYCLES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:instructions", INSTRUCTIONS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:cache-misses", CACHE_MISSES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-
-       PERF_HW_CACHE("perf:cpu:L1-dcache", L1D,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW_CACHE("perf:cpu:L1-icache", L1I,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW_CACHE("perf:cpu:LLC", LL,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_HW_CACHE("perf:cpu:dTLB", DTLB,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB,
-               CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
-       _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB,
-               CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
-       _PERF_HW_CACHE("perf:cpu:branch-loads", BPU,
-               CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
-       _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU,
-               CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
-
-       PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:task-clock", TASK_CLOCK,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:page-fault", PAGE_FAULTS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:faults", PAGE_FAULTS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-       PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS,
-               CONTEXT_PERF_CPU_COUNTER, 0),
-
-       /* Perf per-thread counters */
-       PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:cycles", CPU_CYCLES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:instructions", INSTRUCTIONS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:cache-references", CACHE_REFERENCES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:cache-misses", CACHE_MISSES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:branch-misses", BRANCH_MISSES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW("perf:thread:bus-cycles", BUS_CYCLES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-
-       PERF_HW_CACHE("perf:thread:L1-dcache", L1D,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW_CACHE("perf:thread:L1-icache", L1I,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW_CACHE("perf:thread:LLC", LL,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_HW_CACHE("perf:thread:dTLB", DTLB,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB,
-               CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
-       _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB,
-               CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
-       _PERF_HW_CACHE("perf:thread:branch-loads", BPU,
-               CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
-       _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU,
-               CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
-
-       PERF_SW("perf:thread:cpu-clock", CPU_CLOCK,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:task-clock", TASK_CLOCK,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:page-fault", PAGE_FAULTS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:faults", PAGE_FAULTS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:cs", CONTEXT_SWITCHES,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-       PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS,
-               CONTEXT_PERF_THREAD_COUNTER, 0),
-
-       /*
-        * Perf per-CPU counters, backward compatibilty for names.
-        * Hidden from help listing.
-        */
-       PERF_HW("perf:cpu-cycles", CPU_CYCLES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:cycles", CPU_CYCLES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:instructions", INSTRUCTIONS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:cache-references", CACHE_REFERENCES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:cache-misses", CACHE_MISSES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:branches", BRANCH_INSTRUCTIONS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:branch-misses", BRANCH_MISSES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW("perf:bus-cycles", BUS_CYCLES,
-               CONTEXT_PERF_COUNTER, 1),
-
-       PERF_HW_CACHE("perf:L1-dcache", L1D,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW_CACHE("perf:L1-icache", L1I,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW_CACHE("perf:LLC", LL,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_HW_CACHE("perf:dTLB", DTLB,
-               CONTEXT_PERF_COUNTER, 1),
-       _PERF_HW_CACHE("perf:iTLB-loads", ITLB,
-               CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
-       _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB,
-               CONTEXT_PERF_COUNTER, READ, MISS, 1),
-       _PERF_HW_CACHE("perf:branch-loads", BPU,
-               CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
-       _PERF_HW_CACHE("perf:branch-load-misses", BPU,
-               CONTEXT_PERF_COUNTER, READ, MISS, 1),
-
-       PERF_SW("perf:cpu-clock", CPU_CLOCK,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:task-clock", TASK_CLOCK,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:page-fault", PAGE_FAULTS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:faults", PAGE_FAULTS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:context-switches", CONTEXT_SWITCHES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:cs", CONTEXT_SWITCHES,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:migrations", CPU_MIGRATIONS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS,
-               CONTEXT_PERF_COUNTER, 1),
-       PERF_SW("perf:emulation-faults", EMULATION_FAULTS,
-               CONTEXT_PERF_COUNTER, 1),
-
-       { NULL, -1 },           /* Closure */
-};
-
-#undef PERF_HW_CACHE
-#undef _PERF_HW_CACHE
-#undef PERF_SW
-#undef PERF_HW
-
-/*
- * Context type for command line option parsing.
- */
-struct ctx_type {
-       struct ctx_opts *opt;
-       struct cds_list_head list;
-};
-
-/*
- * List of context type. Use to enable multiple context on a single command
- * line entry.
- */
-struct ctx_type_list {
-       struct cds_list_head head;
-} ctx_type_list = {
-       .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
-};
-
-
-
-/*
- * Find context numerical value from string.
- *
- * Return -1 if not found.
- */
-static int find_ctx_type_idx(const char *opt)
-{
-       int ret, i = 0;
-
-       while (ctx_opts[i].symbol != NULL) {
-               if (strcmp(opt, ctx_opts[i].symbol) == 0) {
-                       ret = i;
-                       goto end;
-               }
-               i++;
-       }
-
-       ret = -1;
-end:
-       return ret;
-}
-
-static
-enum lttng_domain_type get_domain(void)
-{
-       if (opt_kernel) {
-               return LTTNG_DOMAIN_KERNEL;
-       } else if (opt_userspace) {
-               return LTTNG_DOMAIN_UST;
-       } else if (opt_jul) {
-               return LTTNG_DOMAIN_JUL;
-       } else if (opt_log4j) {
-               return LTTNG_DOMAIN_LOG4J;
-       } else {
-               abort();
-       }
-}
-
-static
-int mi_open(void)
-{
-       int ret;
-
-       /* MI check */
-       if (!lttng_opt_mi) {
-               ret = 0;
-               goto end;
-       }
-
-       ret = fileno(stdout);
-       if (ret < 0) {
-               PERROR("Unable to retrieve fileno of stdout");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       writer = mi_lttng_writer_create(ret, lttng_opt_mi);
-       if (!writer) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Open command element */
-       ret = mi_lttng_writer_command_open(writer,
-                       mi_lttng_element_command_add_context);
-       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;
-       }
-end:
-       return ret;
-}
-
-static
-int mi_close(enum cmd_error_code success)
-{
-       int ret;
-
-       /* MI closing */
-       if (!lttng_opt_mi) {
-               ret = 0;
-               goto end;
-       }
-       /* Close  output element */
-       ret = mi_lttng_writer_close_element(writer);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Success ? */
-       ret = mi_lttng_writer_write_element_bool(writer,
-                       mi_lttng_element_command_success, !success);
-       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:
-       return ret;
-}
-
-static
-void populate_context(struct lttng_event_context *context,
-               const struct ctx_opts *opt)
-{
-       char *ptr;
-
-       context->ctx = (enum lttng_event_context_type) opt->ctx_type;
-       switch (context->ctx) {
-       case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
-       case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
-       case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
-               context->u.perf_counter.type = opt->u.perf.type;
-               context->u.perf_counter.config = opt->u.perf.config;
-               strncpy(context->u.perf_counter.name, opt->symbol,
-                               LTTNG_SYMBOL_NAME_LEN);
-               context->u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-               /* Replace : and - by _ */
-               while ((ptr = strchr(context->u.perf_counter.name, '-')) != NULL) {
-                       *ptr = '_';
-               }
-               while ((ptr = strchr(context->u.perf_counter.name, ':')) != NULL) {
-                       *ptr = '_';
-               }
-               break;
-       case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
-               context->u.app_ctx.provider_name =
-                       opt->u.app_ctx.provider_name;
-               context->u.app_ctx.ctx_name =
-                       opt->u.app_ctx.ctx_name;
-               break;
-       default:
-               break;
-       }
-}
-
-/*
- * Pretty print context type.
- */
-static
-int print_ctx_type(void)
-{
-
-       FILE *ofp = stdout;
-       int i = 0;
-       int ret;
-       struct lttng_event_context context;
-
-       memset(&context, 0, sizeof(context));
-
-       ret = mi_open();
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (lttng_opt_mi) {
-               /* Open a contexts element */
-               ret = mi_lttng_writer_open_element(writer, config_element_contexts);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       while (ctx_opts[i].symbol != NULL) {
-               if (!ctx_opts[i].hide_help) {
-                       if (lttng_opt_mi) {
-                               populate_context(&context, &ctx_opts[i]);
-                               ret = mi_lttng_context(writer, &context, 1);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               ret = mi_lttng_writer_write_element_string(
-                                               writer,
-                                               mi_lttng_element_context_symbol,
-                                               ctx_opts[i].symbol);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               ret = mi_lttng_writer_close_element(writer);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       } else {
-                               fprintf(ofp, "%s\n", ctx_opts[i].symbol);
-                       }
-               }
-               i++;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close contexts element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       ret = mi_close(ret);
-       if (ret) {
-               ret = CMD_ERROR;
-       }
-       return ret;
-}
-
-/*
- * Add context to channel or event.
- */
-static int add_context(char *session_name)
-{
-       int ret = CMD_SUCCESS, warn = 0, success = 0;
-       struct lttng_event_context context;
-       struct lttng_domain dom;
-       struct ctx_type *type;
-
-       memset(&context, 0, sizeof(context));
-       memset(&dom, 0, sizeof(dom));
-
-       dom.type = get_domain();
-       handle = lttng_create_handle(session_name, &dom);
-       if (handle == NULL) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               /* Open a contexts element */
-               ret = mi_lttng_writer_open_element(writer, config_element_contexts);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       /* Iterate over all the context types given */
-       cds_list_for_each_entry(type, &ctx_type_list.head, list) {
-               DBG("Adding context...");
-
-               populate_context(&context, type->opt);
-
-               if (lttng_opt_mi) {
-                       /* We leave context open the update the success of the command */
-                       ret = mi_lttng_context(writer, &context, 1);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       ret = mi_lttng_writer_write_element_string(writer,
-                                       mi_lttng_element_context_symbol,
-                                       type->opt->symbol);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-
-               ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
-               if (ret < 0) {
-                       ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
-                       warn = 1;
-                       success = 0;
-               } else {
-                       if (opt_channel_name) {
-                               MSG("%s context %s added to channel %s",
-                                               lttng_domain_type_str(dom.type),
-                                               type->opt->symbol,
-                                               opt_channel_name);
-                       } else {
-                               MSG("%s context %s added to all channels",
-                                               lttng_domain_type_str(dom.type),
-                                               type->opt->symbol);
-                       }
-                       success = 1;
-               }
-
-               if (lttng_opt_mi) {
-                       /* Is the single operation a success ? */
-                       ret = mi_lttng_writer_write_element_bool(writer,
-                                       mi_lttng_element_success, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Close the context element */
-                       ret = mi_lttng_writer_close_element(writer);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-       }
-
-       if (lttng_opt_mi) {
-               /* Close contexts element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       ret = CMD_SUCCESS;
-
-error:
-       lttng_destroy_handle(handle);
-
-       /*
-        * This means that at least one add_context failed and tells the user to
-        * look on stderr for error(s).
-        */
-       if (!ret && warn) {
-               ret = CMD_WARNING;
-       }
-       return ret;
-}
-
-static
-void destroy_ctx_type(struct ctx_type *type)
-{
-       if (!type) {
-               return;
-       }
-       if (type->opt) {
-               free(type->opt->symbol);
-       }
-       free(type->opt);
-       free(type);
-}
-
-static
-struct ctx_type *create_ctx_type(void)
-{
-       struct ctx_type *type = zmalloc(sizeof(*type));
-
-       if (!type) {
-               PERROR("malloc ctx_type");
-               goto end;
-       }
-
-       type->opt = zmalloc(sizeof(*type->opt));
-       if (!type->opt) {
-               PERROR("malloc ctx_type options");
-               destroy_ctx_type(type);
-               type = NULL;
-               goto end;
-       }
-end:
-       return type;
-}
-
-static
-int find_ctx_type_perf_raw(const char *ctx, struct ctx_type *type)
-{
-       int ret;
-       int field_pos = 0;
-       char *tmp_list, *cur_list;
-
-       cur_list = tmp_list = strdup(ctx);
-       if (!tmp_list) {
-               PERROR("strdup temp list");
-               ret = -ENOMEM;
-               goto end;
-       }
-
-       /* Looking for "perf:[cpu|thread]:raw:<mask>:<name>". */
-       for (;;) {
-               char *next;
-
-               next = strtok(cur_list, ":");
-               if (!next) {
-                       break;
-               }
-               cur_list = NULL;
-               switch (field_pos) {
-               case 0:
-                       if (strncmp(next, "perf", 4) != 0) {
-                               ret = -1;
-                               goto end;
-                       }
-                       break;
-               case 1:
-                       if (strncmp(next, "cpu", 3) == 0) {
-                               type->opt->ctx_type = CONTEXT_PERF_CPU_COUNTER;
-                       } else if (strncmp(next, "thread", 4) == 0) {
-                               type->opt->ctx_type = CONTEXT_PERF_THREAD_COUNTER;
-                       } else {
-                               ret = -1;
-                               goto end;
-                       }
-                       break;
-               case 2:
-                       if (strncmp(next, "raw", 3) != 0) {
-                               ret = -1;
-                               goto end;
-                       }
-                       break;
-               case 3:
-               {
-                       char *endptr;
-
-                       if (strlen(next) < 2 || next[0] != 'r') {
-                               ERR("Wrong perf raw mask format: expected rNNN");
-                               ret = -1;
-                               goto end;
-                       }
-                       errno = 0;
-                       type->opt->u.perf.config = strtoll(next +  1, &endptr, 16);
-                       if (errno != 0 || !endptr || *endptr) {
-                               ERR("Wrong perf raw mask format: expected rNNN");
-                               ret = -1;
-                               goto end;
-                       }
-                       break;
-               }
-               case 4:
-                       /* name */
-                       break;
-               case 5:
-                       ERR("Too many ':' in perf raw format");
-                       ret = -1;
-                       goto end;
-               };
-               field_pos++;
-       }
-
-       if (field_pos < 5) {
-               ERR("Invalid perf counter specifier, expected a specifier of "
-                       "the form perf:cpu:raw:rNNN:<name> or "
-                       "perf:thread:raw:rNNN:<name>");
-               ret = -1;
-               goto end;
-       }
-
-       ret = 0;
-       goto end;
-
-end:
-       free(tmp_list);
-       return ret;
-}
-
-static
-struct ctx_type *get_context_type(const char *ctx)
-{
-       int opt_index, ret;
-       struct ctx_type *type = NULL;
-       const char app_ctx_prefix[] = "$app.";
-       char *provider_name = NULL, *ctx_name = NULL;
-       size_t i, len, colon_pos = 0, provider_name_len, ctx_name_len;
-
-       if (!ctx) {
-               goto not_found;
-       }
-
-       type = create_ctx_type();
-       if (!type) {
-               goto not_found;
-       }
-
-       /* Check if ctx matches a known static context. */
-       opt_index = find_ctx_type_idx(ctx);
-       if (opt_index >= 0) {
-               *type->opt = ctx_opts[opt_index];
-               type->opt->symbol = strdup(ctx_opts[opt_index].symbol);
-               goto found;
-       }
-
-       /* Check if ctx is a raw perf context. */
-       ret = find_ctx_type_perf_raw(ctx, type);
-       if (ret == 0) {
-               type->opt->u.perf.type = PERF_TYPE_RAW;
-               type->opt->symbol = strdup(ctx);
-               if (!type->opt->symbol) {
-                       PERROR("Copy perf field name");
-                       goto not_found;
-               }
-               goto found;
-       }
-
-       /*
-        * No match found against static contexts; check if it is an app
-        * context.
-        */
-       len = strlen(ctx);
-       if (len <= sizeof(app_ctx_prefix) - 1) {
-               goto not_found;
-       }
-
-       /* String starts with $app. */
-       if (strncmp(ctx, app_ctx_prefix, sizeof(app_ctx_prefix) - 1)) {
-               goto not_found;
-       }
-
-       /* Validate that the ':' separator is present. */
-       for (i = sizeof(app_ctx_prefix); i < len; i++) {
-               const char c = ctx[i];
-
-               if (c == ':') {
-                       colon_pos = i;
-                       break;
-               }
-       }
-
-       /*
-        * No colon found or no ctx name ("$app.provider:") or no provider name
-        * given ("$app.:..."), which is invalid.
-        */
-       if (!colon_pos || colon_pos == len ||
-                       colon_pos == sizeof(app_ctx_prefix)) {
-               ERR("Invalid application context provided: no provider or context name provided.");
-               goto not_found;
-       }
-
-       provider_name_len = colon_pos - sizeof(app_ctx_prefix) + 2;
-       provider_name = zmalloc(provider_name_len);
-       if (!provider_name) {
-               PERROR("malloc provider_name");
-               goto not_found;
-       }
-       strncpy(provider_name, ctx + sizeof(app_ctx_prefix) - 1,
-                       provider_name_len - 1);
-       type->opt->u.app_ctx.provider_name = provider_name;
-
-       ctx_name_len = len - colon_pos;
-       ctx_name = zmalloc(ctx_name_len);
-       if (!ctx_name) {
-               PERROR("malloc ctx_name");
-               goto not_found;
-       }
-       strncpy(ctx_name, ctx + colon_pos + 1, ctx_name_len - 1);
-       type->opt->u.app_ctx.ctx_name = ctx_name;
-       type->opt->ctx_type = CONTEXT_APP_CONTEXT;
-       type->opt->symbol = strdup(ctx);
-found:
-       return type;
-not_found:
-       free(provider_name);
-       free(ctx_name);
-       destroy_ctx_type(type);
-       return NULL;
-}
-
-/*
- * Add context to channel or event.
- */
-int cmd_add_context(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
-       static poptContext pc;
-       struct ctx_type *type, *tmptype;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-
-       if (argc < 2) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST:
-                       ret = print_ctx_type();
-                       goto end;
-               case OPT_TYPE:
-               {
-                       type = get_context_type(opt_type);
-                       if (!type) {
-                               ERR("Unknown context type %s", opt_type);
-                               ret = CMD_FATAL;
-                               goto end;
-                       }
-                       cds_list_add_tail(&type->list, &ctx_type_list.head);
-                       break;
-               }
-               case OPT_USERSPACE:
-                       opt_userspace = 1;
-                       break;
-               case OPT_JUL:
-                       opt_jul = 1;
-                       break;
-               case OPT_LOG4J:
-                       opt_log4j = 1;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace + opt_jul + opt_log4j, true);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!opt_type) {
-               ERR("Missing mandatory -t TYPE");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       ret = mi_open();
-       if (ret) {
-               goto end;
-       }
-
-       command_ret = add_context(session_name);
-       ret = mi_close(command_ret);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       if (!opt_session_name) {
-               free(session_name);
-       }
-
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
-       }
-
-       /* Cleanup allocated memory */
-       cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
-               destroy_ctx_type(type);
-       }
-
-       /* Overwrite ret if an error occurred during add_context() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/add_context.cpp b/src/bin/lttng/commands/add_context.cpp
new file mode 100644 (file)
index 0000000..d078471
--- /dev/null
@@ -0,0 +1,1239 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <ctype.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <urcu/list.h>
+
+#include <lttng/domain-internal.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_channel_name;
+static char *opt_session_name;
+static int opt_kernel;
+static int opt_userspace;
+static int opt_jul;
+static int opt_log4j;
+static char *opt_type;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-add-context.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_TYPE,
+       OPT_USERSPACE,
+       OPT_JUL,
+       OPT_LOG4J,
+       OPT_LIST_OPTIONS,
+       OPT_LIST,
+};
+
+static struct lttng_handle *handle;
+static struct mi_writer *writer;
+
+/*
+ * Taken from the LTTng ABI
+ */
+enum context_type {
+       CONTEXT_PID          = 0,
+       CONTEXT_PERF_COUNTER = 1,       /* Backward compat. */
+       CONTEXT_PROCNAME     = 2,
+       CONTEXT_PRIO         = 3,
+       CONTEXT_NICE         = 4,
+       CONTEXT_VPID         = 5,
+       CONTEXT_TID          = 6,
+       CONTEXT_VTID         = 7,
+       CONTEXT_PPID         = 8,
+       CONTEXT_VPPID        = 9,
+       CONTEXT_PTHREAD_ID   = 10,
+       CONTEXT_HOSTNAME     = 11,
+       CONTEXT_IP           = 12,
+       CONTEXT_PERF_CPU_COUNTER = 13,
+       CONTEXT_PERF_THREAD_COUNTER = 14,
+       CONTEXT_APP_CONTEXT  = 15,
+       CONTEXT_INTERRUPTIBLE = 16,
+       CONTEXT_PREEMPTIBLE  = 17,
+       CONTEXT_NEED_RESCHEDULE = 18,
+       CONTEXT_MIGRATABLE   = 19,
+       CONTEXT_CALLSTACK_KERNEL = 20,
+       CONTEXT_CALLSTACK_USER = 21,
+       CONTEXT_CGROUP_NS    = 22,
+       CONTEXT_IPC_NS       = 23,
+       CONTEXT_MNT_NS       = 24,
+       CONTEXT_NET_NS       = 25,
+       CONTEXT_PID_NS       = 26,
+       CONTEXT_USER_NS      = 27,
+       CONTEXT_UTS_NS       = 28,
+       CONTEXT_UID          = 29,
+       CONTEXT_EUID         = 30,
+       CONTEXT_SUID         = 31,
+       CONTEXT_GID          = 32,
+       CONTEXT_EGID         = 33,
+       CONTEXT_SGID         = 34,
+       CONTEXT_VUID         = 35,
+       CONTEXT_VEUID        = 36,
+       CONTEXT_VSUID        = 37,
+       CONTEXT_VGID         = 38,
+       CONTEXT_VEGID        = 39,
+       CONTEXT_VSGID        = 40,
+       CONTEXT_TIME_NS      = 41,
+};
+
+/*
+ * Taken from the Perf ABI (all enum perf_*)
+ */
+enum perf_type {
+       PERF_TYPE_HARDWARE = 0,
+       PERF_TYPE_SOFTWARE = 1,
+       PERF_TYPE_HW_CACHE = 3,
+       PERF_TYPE_RAW = 4,
+};
+
+enum perf_count_hard {
+       PERF_COUNT_HW_CPU_CYCLES                = 0,
+       PERF_COUNT_HW_INSTRUCTIONS              = 1,
+       PERF_COUNT_HW_CACHE_REFERENCES          = 2,
+       PERF_COUNT_HW_CACHE_MISSES              = 3,
+       PERF_COUNT_HW_BRANCH_INSTRUCTIONS       = 4,
+       PERF_COUNT_HW_BRANCH_MISSES             = 5,
+       PERF_COUNT_HW_BUS_CYCLES                = 6,
+       PERF_COUNT_HW_STALLED_CYCLES_FRONTEND   = 7,
+       PERF_COUNT_HW_STALLED_CYCLES_BACKEND    = 8,
+};
+
+enum perf_count_soft {
+       PERF_COUNT_SW_CPU_CLOCK        = 0,
+       PERF_COUNT_SW_TASK_CLOCK       = 1,
+       PERF_COUNT_SW_PAGE_FAULTS      = 2,
+       PERF_COUNT_SW_CONTEXT_SWITCHES = 3,
+       PERF_COUNT_SW_CPU_MIGRATIONS   = 4,
+       PERF_COUNT_SW_PAGE_FAULTS_MIN  = 5,
+       PERF_COUNT_SW_PAGE_FAULTS_MAJ  = 6,
+       PERF_COUNT_SW_ALIGNMENT_FAULTS = 7,
+       PERF_COUNT_SW_EMULATION_FAULTS = 8,
+};
+
+/*
+ * Generalized hardware cache events:
+ *
+ *       { L1-D, L1-I, LLC, ITLB, DTLB, BPU } x
+ *       { read, write, prefetch } x
+ *       { accesses, misses }
+ */
+enum perf_hw_cache_id {
+       PERF_COUNT_HW_CACHE_L1D                 = 0,
+       PERF_COUNT_HW_CACHE_L1I                 = 1,
+       PERF_COUNT_HW_CACHE_LL                  = 2,
+       PERF_COUNT_HW_CACHE_DTLB                = 3,
+       PERF_COUNT_HW_CACHE_ITLB                = 4,
+       PERF_COUNT_HW_CACHE_BPU                 = 5,
+
+       PERF_COUNT_HW_CACHE_MAX,                /* non-ABI */
+};
+
+enum perf_hw_cache_op_id {
+       PERF_COUNT_HW_CACHE_OP_READ             = 0,
+       PERF_COUNT_HW_CACHE_OP_WRITE            = 1,
+       PERF_COUNT_HW_CACHE_OP_PREFETCH         = 2,
+
+       PERF_COUNT_HW_CACHE_OP_MAX,             /* non-ABI */
+};
+
+enum perf_hw_cache_op_result_id {
+       PERF_COUNT_HW_CACHE_RESULT_ACCESS       = 0,
+       PERF_COUNT_HW_CACHE_RESULT_MISS         = 1,
+
+       PERF_COUNT_HW_CACHE_RESULT_MAX,         /* non-ABI */
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
+       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
+       {"jul",            'j', POPT_ARG_NONE, 0, OPT_JUL, 0, 0},
+       {"log4j",          'l', POPT_ARG_NONE, 0, OPT_LOG4J, 0, 0},
+       {"type",           't', POPT_ARG_STRING, &opt_type, OPT_TYPE, 0, 0},
+       {"list",           0, POPT_ARG_NONE, NULL, OPT_LIST, NULL, NULL},
+       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Context options
+ */
+#define PERF_HW(optstr, name, type, hide)                              \
+       {                                                               \
+               optstr, type, PERF_COUNT_HW_##name, hide                \
+       }
+
+#define PERF_SW(optstr, name, type, hide)                              \
+       {                                                               \
+               optstr, type, PERF_COUNT_SW_##name, hide                \
+       }
+
+#define _PERF_HW_CACHE(optstr, name, type, op, result, hide)           \
+       {                                                               \
+               optstr, type,                                           \
+               PERF_COUNT_HW_CACHE_##name,                             \
+               PERF_COUNT_HW_CACHE_OP_##op,                            \
+               PERF_COUNT_HW_CACHE_RESULT_##result,                    \
+               hide,                                                   \
+       }
+
+#define PERF_HW_CACHE(optstr, name, type, hide)                                \
+       _PERF_HW_CACHE(optstr "-loads", name, type,                     \
+               READ, ACCESS, hide),                                    \
+       _PERF_HW_CACHE(optstr "-load-misses", name, type,               \
+               READ, MISS, hide),                                      \
+       _PERF_HW_CACHE(optstr "-stores", name, type,                    \
+               WRITE, ACCESS, hide),                                   \
+       _PERF_HW_CACHE(optstr "-store-misses", name, type,              \
+               WRITE, MISS, hide),                                     \
+       _PERF_HW_CACHE(optstr "-prefetches", name, type,                \
+               PREFETCH, ACCESS, hide),                                \
+       _PERF_HW_CACHE(optstr "-prefetch-misses", name, type,           \
+               PREFETCH, MISS, hide)
+
+static
+const struct ctx_opts {
+       /* Needed for end-of-list item. */
+       ctx_opts()
+               : symbol(nullptr)
+       {}
+
+       ctx_opts(const char *symbol_, context_type ctx_type_, bool hide_help_ = false)
+               : symbol((char *) symbol_), ctx_type(ctx_type_), hide_help(hide_help_)
+       {}
+
+       ctx_opts(const char *symbol_, context_type ctx_type_, perf_count_hard perf_count_hard, bool hide_help_)
+               : ctx_opts(symbol_, ctx_type_, hide_help_)
+       {
+               u.perf.type = PERF_TYPE_HARDWARE;
+               u.perf.config = perf_count_hard;
+       }
+
+       ctx_opts(const char *symbol_, context_type ctx_type_, perf_count_soft perf_count_soft, bool hide_help_)
+               : ctx_opts(symbol_, ctx_type_, hide_help_)
+       {
+               u.perf.type = PERF_TYPE_SOFTWARE;
+               u.perf.config = perf_count_soft;
+       }
+
+       ctx_opts(const char *symbol_, context_type ctx_type_,
+                       perf_hw_cache_id perf_hw_cache_id,
+                       perf_hw_cache_op_id perf_hw_cache_op_id,
+                       perf_hw_cache_op_result_id perf_hw_cache_op_result_id,
+                       bool hide_help_)
+               : ctx_opts(symbol_, ctx_type_, hide_help_)
+       {
+               u.perf.type = PERF_TYPE_HW_CACHE;
+               u.perf.config = perf_hw_cache_id | perf_hw_cache_op_id << 8 | perf_hw_cache_op_result_id << 16;
+       }
+
+       char *symbol;
+       enum context_type ctx_type;
+       bool hide_help; /* Hide from --help */
+       union {
+               struct {
+                       uint32_t type;
+                       uint64_t config;
+               } perf;
+               struct {
+                       char *provider_name;
+                       char *ctx_name;
+               } app_ctx;
+       } u;
+} ctx_opts[] = {
+       /*
+        * These (char *) casts (as well as those in the PERF_* macros) are
+        * safe because we never free these instances of `struct ctx_opts`.
+        */
+       { (char *) "pid", CONTEXT_PID },
+       { (char *) "procname", CONTEXT_PROCNAME },
+       { (char *) "prio", CONTEXT_PRIO },
+       { (char *) "nice", CONTEXT_NICE },
+       { (char *) "vpid", CONTEXT_VPID },
+       { (char *) "tid", CONTEXT_TID },
+       { (char *) "pthread_id", CONTEXT_PTHREAD_ID },
+       { (char *) "vtid", CONTEXT_VTID },
+       { (char *) "ppid", CONTEXT_PPID },
+       { (char *) "vppid", CONTEXT_VPPID },
+       { (char *) "hostname", CONTEXT_HOSTNAME },
+       { (char *) "ip", CONTEXT_IP },
+       { (char *) "interruptible", CONTEXT_INTERRUPTIBLE },
+       { (char *) "preemptible", CONTEXT_PREEMPTIBLE },
+       { (char *) "need_reschedule", CONTEXT_NEED_RESCHEDULE },
+       { (char *) "migratable", CONTEXT_MIGRATABLE },
+       { (char *) "callstack-kernel", CONTEXT_CALLSTACK_KERNEL },
+#if HAVE_MODULES_USERSPACE_CALLSTACK_CONTEXT
+       { (char *) "callstack-user", CONTEXT_CALLSTACK_USER },
+#endif
+       { (char *) "cgroup_ns", CONTEXT_CGROUP_NS },
+       { (char *) "ipc_ns", CONTEXT_IPC_NS },
+       { (char *) "mnt_ns", CONTEXT_MNT_NS },
+       { (char *) "net_ns", CONTEXT_NET_NS },
+       { (char *) "pid_ns", CONTEXT_PID_NS },
+       { (char *) "time_ns", CONTEXT_TIME_NS },
+       { (char *) "user_ns", CONTEXT_USER_NS },
+       { (char *) "uts_ns", CONTEXT_UTS_NS },
+       { (char *) "uid", CONTEXT_UID },
+       { (char *) "euid", CONTEXT_EUID },
+       { (char *) "suid", CONTEXT_SUID },
+       { (char *) "gid", CONTEXT_GID },
+       { (char *) "egid", CONTEXT_EGID },
+       { (char *) "sgid", CONTEXT_SGID },
+       { (char *) "vuid", CONTEXT_VUID },
+       { (char *) "veuid", CONTEXT_VEUID },
+       { (char *) "vsuid", CONTEXT_VSUID },
+       { (char *) "vgid", CONTEXT_VGID },
+       { (char *) "vegid", CONTEXT_VEGID },
+       { (char *) "vsgid", CONTEXT_VSGID },
+
+       /* Perf options */
+
+       /* Perf per-CPU counters */
+       PERF_HW("perf:cpu:cpu-cycles", CPU_CYCLES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:cycles", CPU_CYCLES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:idle-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:instructions", INSTRUCTIONS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:cache-references", CACHE_REFERENCES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:cache-misses", CACHE_MISSES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:branch-instructions", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:branches", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:branch-misses", BRANCH_MISSES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW("perf:cpu:bus-cycles", BUS_CYCLES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+
+       PERF_HW_CACHE("perf:cpu:L1-dcache", L1D,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW_CACHE("perf:cpu:L1-icache", L1I,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW_CACHE("perf:cpu:LLC", LL,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_HW_CACHE("perf:cpu:dTLB", DTLB,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       _PERF_HW_CACHE("perf:cpu:iTLB-loads", ITLB,
+               CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
+       _PERF_HW_CACHE("perf:cpu:iTLB-load-misses", ITLB,
+               CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
+       _PERF_HW_CACHE("perf:cpu:branch-loads", BPU,
+               CONTEXT_PERF_CPU_COUNTER, READ, ACCESS, 0),
+       _PERF_HW_CACHE("perf:cpu:branch-load-misses", BPU,
+               CONTEXT_PERF_CPU_COUNTER, READ, MISS, 0),
+
+       PERF_SW("perf:cpu:cpu-clock", CPU_CLOCK,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:task-clock", TASK_CLOCK,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:page-fault", PAGE_FAULTS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:faults", PAGE_FAULTS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:major-faults", PAGE_FAULTS_MAJ,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:minor-faults", PAGE_FAULTS_MIN,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:context-switches", CONTEXT_SWITCHES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:cs", CONTEXT_SWITCHES,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:cpu-migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:alignment-faults", ALIGNMENT_FAULTS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+       PERF_SW("perf:cpu:emulation-faults", EMULATION_FAULTS,
+               CONTEXT_PERF_CPU_COUNTER, 0),
+
+       /* Perf per-thread counters */
+       PERF_HW("perf:thread:cpu-cycles", CPU_CYCLES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:cycles", CPU_CYCLES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:idle-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:instructions", INSTRUCTIONS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:cache-references", CACHE_REFERENCES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:cache-misses", CACHE_MISSES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:branch-instructions", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:branches", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:branch-misses", BRANCH_MISSES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW("perf:thread:bus-cycles", BUS_CYCLES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+
+       PERF_HW_CACHE("perf:thread:L1-dcache", L1D,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW_CACHE("perf:thread:L1-icache", L1I,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW_CACHE("perf:thread:LLC", LL,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_HW_CACHE("perf:thread:dTLB", DTLB,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       _PERF_HW_CACHE("perf:thread:iTLB-loads", ITLB,
+               CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
+       _PERF_HW_CACHE("perf:thread:iTLB-load-misses", ITLB,
+               CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
+       _PERF_HW_CACHE("perf:thread:branch-loads", BPU,
+               CONTEXT_PERF_THREAD_COUNTER, READ, ACCESS, 0),
+       _PERF_HW_CACHE("perf:thread:branch-load-misses", BPU,
+               CONTEXT_PERF_THREAD_COUNTER, READ, MISS, 0),
+
+       PERF_SW("perf:thread:cpu-clock", CPU_CLOCK,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:task-clock", TASK_CLOCK,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:page-fault", PAGE_FAULTS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:faults", PAGE_FAULTS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:major-faults", PAGE_FAULTS_MAJ,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:minor-faults", PAGE_FAULTS_MIN,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:context-switches", CONTEXT_SWITCHES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:cs", CONTEXT_SWITCHES,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:cpu-migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:alignment-faults", ALIGNMENT_FAULTS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+       PERF_SW("perf:thread:emulation-faults", EMULATION_FAULTS,
+               CONTEXT_PERF_THREAD_COUNTER, 0),
+
+       /*
+        * Perf per-CPU counters, backward compatibilty for names.
+        * Hidden from help listing.
+        */
+       PERF_HW("perf:cpu-cycles", CPU_CYCLES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:cycles", CPU_CYCLES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:stalled-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:idle-cycles-frontend", STALLED_CYCLES_FRONTEND,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:stalled-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:idle-cycles-backend", STALLED_CYCLES_BACKEND,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:instructions", INSTRUCTIONS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:cache-references", CACHE_REFERENCES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:cache-misses", CACHE_MISSES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:branch-instructions", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:branches", BRANCH_INSTRUCTIONS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:branch-misses", BRANCH_MISSES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW("perf:bus-cycles", BUS_CYCLES,
+               CONTEXT_PERF_COUNTER, 1),
+
+       PERF_HW_CACHE("perf:L1-dcache", L1D,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW_CACHE("perf:L1-icache", L1I,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW_CACHE("perf:LLC", LL,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_HW_CACHE("perf:dTLB", DTLB,
+               CONTEXT_PERF_COUNTER, 1),
+       _PERF_HW_CACHE("perf:iTLB-loads", ITLB,
+               CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
+       _PERF_HW_CACHE("perf:iTLB-load-misses", ITLB,
+               CONTEXT_PERF_COUNTER, READ, MISS, 1),
+       _PERF_HW_CACHE("perf:branch-loads", BPU,
+               CONTEXT_PERF_COUNTER, READ, ACCESS, 1),
+       _PERF_HW_CACHE("perf:branch-load-misses", BPU,
+               CONTEXT_PERF_COUNTER, READ, MISS, 1),
+
+       PERF_SW("perf:cpu-clock", CPU_CLOCK,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:task-clock", TASK_CLOCK,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:page-fault", PAGE_FAULTS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:faults", PAGE_FAULTS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:major-faults", PAGE_FAULTS_MAJ,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:minor-faults", PAGE_FAULTS_MIN,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:context-switches", CONTEXT_SWITCHES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:cs", CONTEXT_SWITCHES,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:cpu-migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:migrations", CPU_MIGRATIONS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:alignment-faults", ALIGNMENT_FAULTS,
+               CONTEXT_PERF_COUNTER, 1),
+       PERF_SW("perf:emulation-faults", EMULATION_FAULTS,
+               CONTEXT_PERF_COUNTER, 1),
+
+       {},             /* Closure */
+};
+
+#undef PERF_HW_CACHE
+#undef _PERF_HW_CACHE
+#undef PERF_SW
+#undef PERF_HW
+
+/*
+ * Context type for command line option parsing.
+ */
+struct ctx_type {
+       struct ctx_opts *opt;
+       struct cds_list_head list;
+};
+
+/*
+ * List of context type. Use to enable multiple context on a single command
+ * line entry.
+ */
+struct ctx_type_list {
+       struct cds_list_head head;
+} ctx_type_list = {
+       .head = CDS_LIST_HEAD_INIT(ctx_type_list.head),
+};
+
+
+
+/*
+ * Find context numerical value from string.
+ *
+ * Return -1 if not found.
+ */
+static int find_ctx_type_idx(const char *opt)
+{
+       int ret, i = 0;
+
+       while (ctx_opts[i].symbol != NULL) {
+               if (strcmp(opt, ctx_opts[i].symbol) == 0) {
+                       ret = i;
+                       goto end;
+               }
+               i++;
+       }
+
+       ret = -1;
+end:
+       return ret;
+}
+
+static
+enum lttng_domain_type get_domain(void)
+{
+       if (opt_kernel) {
+               return LTTNG_DOMAIN_KERNEL;
+       } else if (opt_userspace) {
+               return LTTNG_DOMAIN_UST;
+       } else if (opt_jul) {
+               return LTTNG_DOMAIN_JUL;
+       } else if (opt_log4j) {
+               return LTTNG_DOMAIN_LOG4J;
+       } else {
+               abort();
+       }
+}
+
+static
+int mi_open(void)
+{
+       int ret;
+
+       /* MI check */
+       if (!lttng_opt_mi) {
+               ret = 0;
+               goto end;
+       }
+
+       ret = fileno(stdout);
+       if (ret < 0) {
+               PERROR("Unable to retrieve fileno of stdout");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       writer = mi_lttng_writer_create(ret, lttng_opt_mi);
+       if (!writer) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Open command element */
+       ret = mi_lttng_writer_command_open(writer,
+                       mi_lttng_element_command_add_context);
+       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;
+       }
+end:
+       return ret;
+}
+
+static
+int mi_close(enum cmd_error_code success)
+{
+       int ret;
+
+       /* MI closing */
+       if (!lttng_opt_mi) {
+               ret = 0;
+               goto end;
+       }
+       /* Close  output element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Success ? */
+       ret = mi_lttng_writer_write_element_bool(writer,
+                       mi_lttng_element_command_success, !success);
+       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:
+       return ret;
+}
+
+static
+void populate_context(struct lttng_event_context *context,
+               const struct ctx_opts *opt)
+{
+       char *ptr;
+
+       context->ctx = (enum lttng_event_context_type) opt->ctx_type;
+       switch (context->ctx) {
+       case LTTNG_EVENT_CONTEXT_PERF_COUNTER:
+       case LTTNG_EVENT_CONTEXT_PERF_CPU_COUNTER:
+       case LTTNG_EVENT_CONTEXT_PERF_THREAD_COUNTER:
+               context->u.perf_counter.type = opt->u.perf.type;
+               context->u.perf_counter.config = opt->u.perf.config;
+               strncpy(context->u.perf_counter.name, opt->symbol,
+                               LTTNG_SYMBOL_NAME_LEN);
+               context->u.perf_counter.name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+               /* Replace : and - by _ */
+               while ((ptr = strchr(context->u.perf_counter.name, '-')) != NULL) {
+                       *ptr = '_';
+               }
+               while ((ptr = strchr(context->u.perf_counter.name, ':')) != NULL) {
+                       *ptr = '_';
+               }
+               break;
+       case LTTNG_EVENT_CONTEXT_APP_CONTEXT:
+               context->u.app_ctx.provider_name =
+                       opt->u.app_ctx.provider_name;
+               context->u.app_ctx.ctx_name =
+                       opt->u.app_ctx.ctx_name;
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * Pretty print context type.
+ */
+static
+int print_ctx_type(void)
+{
+
+       FILE *ofp = stdout;
+       int i = 0;
+       int ret;
+       struct lttng_event_context context;
+
+       memset(&context, 0, sizeof(context));
+
+       ret = mi_open();
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (lttng_opt_mi) {
+               /* Open a contexts element */
+               ret = mi_lttng_writer_open_element(writer, config_element_contexts);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       while (ctx_opts[i].symbol != NULL) {
+               if (!ctx_opts[i].hide_help) {
+                       if (lttng_opt_mi) {
+                               populate_context(&context, &ctx_opts[i]);
+                               ret = mi_lttng_context(writer, &context, 1);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               ret = mi_lttng_writer_write_element_string(
+                                               writer,
+                                               mi_lttng_element_context_symbol,
+                                               ctx_opts[i].symbol);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               ret = mi_lttng_writer_close_element(writer);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       } else {
+                               fprintf(ofp, "%s\n", ctx_opts[i].symbol);
+                       }
+               }
+               i++;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close contexts element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       ret = mi_close((cmd_error_code) ret);
+       if (ret) {
+               ret = CMD_ERROR;
+       }
+       return ret;
+}
+
+/*
+ * Add context to channel or event.
+ */
+static int add_context(char *session_name)
+{
+       int ret = CMD_SUCCESS, warn = 0, success = 0;
+       struct lttng_event_context context;
+       struct lttng_domain dom;
+       struct ctx_type *type;
+
+       memset(&context, 0, sizeof(context));
+       memset(&dom, 0, sizeof(dom));
+
+       dom.type = get_domain();
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               /* Open a contexts element */
+               ret = mi_lttng_writer_open_element(writer, config_element_contexts);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       /* Iterate over all the context types given */
+       cds_list_for_each_entry(type, &ctx_type_list.head, list) {
+               DBG("Adding context...");
+
+               populate_context(&context, type->opt);
+
+               if (lttng_opt_mi) {
+                       /* We leave context open the update the success of the command */
+                       ret = mi_lttng_context(writer, &context, 1);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       ret = mi_lttng_writer_write_element_string(writer,
+                                       mi_lttng_element_context_symbol,
+                                       type->opt->symbol);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+
+               ret = lttng_add_context(handle, &context, NULL, opt_channel_name);
+               if (ret < 0) {
+                       ERR("%s: %s", type->opt->symbol, lttng_strerror(ret));
+                       warn = 1;
+                       success = 0;
+               } else {
+                       if (opt_channel_name) {
+                               MSG("%s context %s added to channel %s",
+                                               lttng_domain_type_str(dom.type),
+                                               type->opt->symbol,
+                                               opt_channel_name);
+                       } else {
+                               MSG("%s context %s added to all channels",
+                                               lttng_domain_type_str(dom.type),
+                                               type->opt->symbol);
+                       }
+                       success = 1;
+               }
+
+               if (lttng_opt_mi) {
+                       /* Is the single operation a success ? */
+                       ret = mi_lttng_writer_write_element_bool(writer,
+                                       mi_lttng_element_success, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Close the context element */
+                       ret = mi_lttng_writer_close_element(writer);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+       }
+
+       if (lttng_opt_mi) {
+               /* Close contexts element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       ret = CMD_SUCCESS;
+
+error:
+       lttng_destroy_handle(handle);
+
+       /*
+        * This means that at least one add_context failed and tells the user to
+        * look on stderr for error(s).
+        */
+       if (!ret && warn) {
+               ret = CMD_WARNING;
+       }
+       return ret;
+}
+
+static
+void destroy_ctx_type(struct ctx_type *type)
+{
+       if (!type) {
+               return;
+       }
+       if (type->opt) {
+               free(type->opt->symbol);
+       }
+       free(type->opt);
+       free(type);
+}
+
+static
+struct ctx_type *create_ctx_type(void)
+{
+       struct ctx_type *type = (ctx_type *) zmalloc(sizeof(*type));
+
+       if (!type) {
+               PERROR("malloc ctx_type");
+               goto end;
+       }
+
+       type->opt = (struct ctx_opts *) zmalloc(sizeof(*type->opt));
+       if (!type->opt) {
+               PERROR("malloc ctx_type options");
+               destroy_ctx_type(type);
+               type = NULL;
+               goto end;
+       }
+end:
+       return type;
+}
+
+static
+int find_ctx_type_perf_raw(const char *ctx, struct ctx_type *type)
+{
+       int ret;
+       int field_pos = 0;
+       char *tmp_list, *cur_list;
+
+       cur_list = tmp_list = strdup(ctx);
+       if (!tmp_list) {
+               PERROR("strdup temp list");
+               ret = -ENOMEM;
+               goto end;
+       }
+
+       /* Looking for "perf:[cpu|thread]:raw:<mask>:<name>". */
+       for (;;) {
+               char *next;
+
+               next = strtok(cur_list, ":");
+               if (!next) {
+                       break;
+               }
+               cur_list = NULL;
+               switch (field_pos) {
+               case 0:
+                       if (strncmp(next, "perf", 4) != 0) {
+                               ret = -1;
+                               goto end;
+                       }
+                       break;
+               case 1:
+                       if (strncmp(next, "cpu", 3) == 0) {
+                               type->opt->ctx_type = CONTEXT_PERF_CPU_COUNTER;
+                       } else if (strncmp(next, "thread", 4) == 0) {
+                               type->opt->ctx_type = CONTEXT_PERF_THREAD_COUNTER;
+                       } else {
+                               ret = -1;
+                               goto end;
+                       }
+                       break;
+               case 2:
+                       if (strncmp(next, "raw", 3) != 0) {
+                               ret = -1;
+                               goto end;
+                       }
+                       break;
+               case 3:
+               {
+                       char *endptr;
+
+                       if (strlen(next) < 2 || next[0] != 'r') {
+                               ERR("Wrong perf raw mask format: expected rNNN");
+                               ret = -1;
+                               goto end;
+                       }
+                       errno = 0;
+                       type->opt->u.perf.config = strtoll(next +  1, &endptr, 16);
+                       if (errno != 0 || !endptr || *endptr) {
+                               ERR("Wrong perf raw mask format: expected rNNN");
+                               ret = -1;
+                               goto end;
+                       }
+                       break;
+               }
+               case 4:
+                       /* name */
+                       break;
+               case 5:
+                       ERR("Too many ':' in perf raw format");
+                       ret = -1;
+                       goto end;
+               };
+               field_pos++;
+       }
+
+       if (field_pos < 5) {
+               ERR("Invalid perf counter specifier, expected a specifier of "
+                       "the form perf:cpu:raw:rNNN:<name> or "
+                       "perf:thread:raw:rNNN:<name>");
+               ret = -1;
+               goto end;
+       }
+
+       ret = 0;
+       goto end;
+
+end:
+       free(tmp_list);
+       return ret;
+}
+
+static
+struct ctx_type *get_context_type(const char *ctx)
+{
+       int opt_index, ret;
+       struct ctx_type *type = NULL;
+       const char app_ctx_prefix[] = "$app.";
+       char *provider_name = NULL, *ctx_name = NULL;
+       size_t i, len, colon_pos = 0, provider_name_len, ctx_name_len;
+
+       if (!ctx) {
+               goto not_found;
+       }
+
+       type = create_ctx_type();
+       if (!type) {
+               goto not_found;
+       }
+
+       /* Check if ctx matches a known static context. */
+       opt_index = find_ctx_type_idx(ctx);
+       if (opt_index >= 0) {
+               *type->opt = ctx_opts[opt_index];
+               type->opt->symbol = strdup(ctx_opts[opt_index].symbol);
+               goto found;
+       }
+
+       /* Check if ctx is a raw perf context. */
+       ret = find_ctx_type_perf_raw(ctx, type);
+       if (ret == 0) {
+               type->opt->u.perf.type = PERF_TYPE_RAW;
+               type->opt->symbol = strdup(ctx);
+               if (!type->opt->symbol) {
+                       PERROR("Copy perf field name");
+                       goto not_found;
+               }
+               goto found;
+       }
+
+       /*
+        * No match found against static contexts; check if it is an app
+        * context.
+        */
+       len = strlen(ctx);
+       if (len <= sizeof(app_ctx_prefix) - 1) {
+               goto not_found;
+       }
+
+       /* String starts with $app. */
+       if (strncmp(ctx, app_ctx_prefix, sizeof(app_ctx_prefix) - 1)) {
+               goto not_found;
+       }
+
+       /* Validate that the ':' separator is present. */
+       for (i = sizeof(app_ctx_prefix); i < len; i++) {
+               const char c = ctx[i];
+
+               if (c == ':') {
+                       colon_pos = i;
+                       break;
+               }
+       }
+
+       /*
+        * No colon found or no ctx name ("$app.provider:") or no provider name
+        * given ("$app.:..."), which is invalid.
+        */
+       if (!colon_pos || colon_pos == len ||
+                       colon_pos == sizeof(app_ctx_prefix)) {
+               ERR("Invalid application context provided: no provider or context name provided.");
+               goto not_found;
+       }
+
+       provider_name_len = colon_pos - sizeof(app_ctx_prefix) + 2;
+       provider_name = (char *) zmalloc(provider_name_len);
+       if (!provider_name) {
+               PERROR("malloc provider_name");
+               goto not_found;
+       }
+       strncpy(provider_name, ctx + sizeof(app_ctx_prefix) - 1,
+                       provider_name_len - 1);
+       type->opt->u.app_ctx.provider_name = provider_name;
+
+       ctx_name_len = len - colon_pos;
+       ctx_name = (char *) zmalloc(ctx_name_len);
+       if (!ctx_name) {
+               PERROR("malloc ctx_name");
+               goto not_found;
+       }
+       strncpy(ctx_name, ctx + colon_pos + 1, ctx_name_len - 1);
+       type->opt->u.app_ctx.ctx_name = ctx_name;
+       type->opt->ctx_type = CONTEXT_APP_CONTEXT;
+       type->opt->symbol = strdup(ctx);
+found:
+       return type;
+not_found:
+       free(provider_name);
+       free(ctx_name);
+       destroy_ctx_type(type);
+       return NULL;
+}
+
+/*
+ * Add context to channel or event.
+ */
+int cmd_add_context(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
+       static poptContext pc;
+       struct ctx_type *type, *tmptype;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+
+       if (argc < 2) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST:
+                       ret = print_ctx_type();
+                       goto end;
+               case OPT_TYPE:
+               {
+                       type = get_context_type(opt_type);
+                       if (!type) {
+                               ERR("Unknown context type %s", opt_type);
+                               ret = CMD_FATAL;
+                               goto end;
+                       }
+                       cds_list_add_tail(&type->list, &ctx_type_list.head);
+                       break;
+               }
+               case OPT_USERSPACE:
+                       opt_userspace = 1;
+                       break;
+               case OPT_JUL:
+                       opt_jul = 1;
+                       break;
+               case OPT_LOG4J:
+                       opt_log4j = 1;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace + opt_jul + opt_log4j, true);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!opt_type) {
+               ERR("Missing mandatory -t TYPE");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       ret = mi_open();
+       if (ret) {
+               goto end;
+       }
+
+       command_ret = add_context(session_name);
+       ret = mi_close((cmd_error_code) command_ret);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       if (!opt_session_name) {
+               free(session_name);
+       }
+
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
+       }
+
+       /* Cleanup allocated memory */
+       cds_list_for_each_entry_safe(type, tmptype, &ctx_type_list.head, list) {
+               destroy_ctx_type(type);
+       }
+
+       /* Overwrite ret if an error occurred during add_context() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/add_trigger.c b/src/bin/lttng/commands/add_trigger.c
deleted file mode 100644 (file)
index 27f6cc8..0000000
+++ /dev/null
@@ -1,2475 +0,0 @@
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <ctype.h>
-#include <stdio.h>
-#include <string.h>
-
-#include "../command.h"
-#include "../loglevel.h"
-#include "../uprobe.h"
-
-#include "common/argpar/argpar.h"
-#include "common/dynamic-array.h"
-#include "common/mi-lttng.h"
-#include "common/string-utils/string-utils.h"
-#include "common/utils.h"
-#include <lttng/domain-internal.h>
-/* For lttng_event_rule_type_str(). */
-#include <lttng/event-rule/event-rule-internal.h>
-#include <lttng/lttng.h>
-#include "common/filter/filter-ast.h"
-#include "common/filter/filter-ir.h"
-#include "common/dynamic-array.h"
-
-#if (LTTNG_SYMBOL_NAME_LEN == 256)
-#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
-#endif
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-add-trigger.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP,
-       OPT_LIST_OPTIONS,
-
-       OPT_CONDITION,
-       OPT_ACTION,
-       OPT_ID,
-       OPT_OWNER_UID,
-       OPT_RATE_POLICY,
-
-       OPT_NAME,
-       OPT_FILTER,
-       OPT_EXCLUDE_NAME,
-       OPT_EVENT_NAME,
-       OPT_LOG_LEVEL,
-
-       OPT_TYPE,
-       OPT_LOCATION,
-
-       OPT_MAX_SIZE,
-       OPT_DATA_URL,
-       OPT_CTRL_URL,
-       OPT_URL,
-       OPT_PATH,
-
-       OPT_CAPTURE,
-};
-
-static const struct argpar_opt_descr event_rule_opt_descrs[] = {
-       { OPT_FILTER, 'f', "filter", true },
-       { OPT_NAME, 'n', "name", true },
-       { OPT_EXCLUDE_NAME, 'x', "exclude-name", true },
-       { OPT_LOG_LEVEL, 'l', "log-level", true },
-       { OPT_EVENT_NAME, 'E', "event-name", true },
-
-       { OPT_TYPE, 't', "type", true },
-       { OPT_LOCATION, 'L', "location", true },
-
-       /* Capture descriptor */
-       { OPT_CAPTURE, '\0', "capture", true },
-
-       ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-bool has_syscall_prefix(const char *arg)
-{
-       bool matches = false;
-       const char kernel_syscall_type_opt_prefix[] = "kernel:syscall";
-       const size_t kernel_syscall_type_opt_prefix_len =
-                       sizeof(kernel_syscall_type_opt_prefix) - 1;
-       const char syscall_type_opt_prefix[] = "syscall";
-       const size_t syscall_type_opt_prefix_len =
-                       sizeof(syscall_type_opt_prefix) - 1;
-
-       if (strncmp(arg, syscall_type_opt_prefix,
-                           syscall_type_opt_prefix_len) == 0) {
-               matches = true;
-       } else if (strncmp(arg, kernel_syscall_type_opt_prefix,
-                                  kernel_syscall_type_opt_prefix_len) == 0) {
-               matches = true;
-       } else {
-               matches = false;
-       }
-
-       return matches;
-}
-
-static
-bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *arg)
-{
-       bool ret;
-
-       if (*dest != LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
-               ERR("More than one `--type` was specified.");
-               goto error;
-       }
-
-       if (strcmp(arg, "user") == 0 || strcmp(arg, "user:tracepoint") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT;
-       } else if (strcmp(arg, "kernel") == 0 ||
-                       strcmp(arg, "kernel:tracepoint") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT;
-       } else if (strcmp(arg, "jul") == 0 || strcmp(arg, "jul:logging") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_JUL_LOGGING;
-       } else if (strcmp(arg, "log4j") == 0 ||
-                       strcmp(arg, "log4j:logging") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING;
-       } else if (strcmp(arg, "python") == 0 ||
-                       strcmp(arg, "python:logging") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING;
-       } else if (strcmp(arg, "kprobe") == 0 ||
-                       strcmp(arg, "kernel:kprobe") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE;
-       } else if (strcmp(arg, "kernel:uprobe") == 0) {
-               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE;
-       } else if (has_syscall_prefix(arg)) {
-               /*
-                * Matches the following:
-                *   - syscall
-                *   - syscall:entry
-                *   - syscall:exit
-                *   - syscall:entry+exit
-                *   - syscall:*
-                *   - kernel:syscall
-                *   - kernel:syscall:entry
-                *   - kernel:syscall:exit
-                *   - kernel:syscall:entry+exit
-                *   - kernel:syscall:*
-                *
-                * Validation for the right side is left to further usage sites.
-                */
-               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL;
-       } else {
-               ERR("Invalid `--type` value: %s", arg);
-               goto error;
-       }
-
-       ret = true;
-       goto end;
-
-error:
-       ret = false;
-
-end:
-       return ret;
-}
-
-static
-bool assign_string(char **dest, const char *src, const char *opt_name)
-{
-       bool ret;
-
-       if (*dest) {
-               ERR("Duplicate '%s' given.", opt_name);
-               goto error;
-       }
-
-       *dest = strdup(src);
-       if (!*dest) {
-               PERROR("Failed to allocate string '%s'.", opt_name);
-               goto error;
-       }
-
-       ret = true;
-       goto end;
-
-error:
-       ret = false;
-
-end:
-       return ret;
-}
-
-static bool parse_syscall_emission_site_from_type(const char *str,
-               enum lttng_event_rule_kernel_syscall_emission_site *type)
-{
-       bool ret = false;
-       const char kernel_prefix[] = "kernel:";
-       const size_t kernel_prefix_len = sizeof(kernel_prefix) - 1;
-
-       /*
-        * If the passed string is of the form "kernel:syscall*", move the
-        * pointer passed "kernel:".
-        */
-       if (strncmp(str, kernel_prefix, kernel_prefix_len) == 0) {
-               str = &str[kernel_prefix_len];
-       }
-
-       if (strcmp(str, "syscall") == 0 ||
-                       strcmp(str, "syscall:entry+exit") == 0) {
-               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT;
-       } else if (strcmp(str, "syscall:entry") == 0) {
-               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY;
-       } else if (strcmp(str, "syscall:exit") == 0) {
-               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_EXIT;
-       } else {
-               goto error;
-       }
-
-       ret = true;
-
-error:
-       return ret;
-}
-
-/*
- * Parse `str` as a log level against the passed event rule type.
- *
- * Return the log level in `*log_level`.  Return true in `*log_level_only` if
- * the string specifies exactly this log level, false if it specifies at least
- * this log level.
- *
- * Return true if the string was successfully parsed as a log level string.
- */
-static bool parse_log_level_string(const char *str,
-               enum lttng_event_rule_type event_rule_type,
-               int *log_level,
-               bool *log_level_only)
-{
-       bool ret;
-
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-       {
-               enum lttng_loglevel log_level_min, log_level_max;
-               if (!loglevel_parse_range_string(
-                                   str, &log_level_min, &log_level_max)) {
-                       goto error;
-               }
-
-               /* Only support VAL and VAL.. for now. */
-               if (log_level_min != log_level_max &&
-                               log_level_max != LTTNG_LOGLEVEL_EMERG) {
-                       goto error;
-               }
-
-               *log_level = (int) log_level_min;
-               *log_level_only = log_level_min == log_level_max;
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-       {
-               enum lttng_loglevel_log4j log_level_min, log_level_max;
-               if (!loglevel_log4j_parse_range_string(
-                                   str, &log_level_min, &log_level_max)) {
-                       goto error;
-               }
-
-               /* Only support VAL and VAL.. for now. */
-               if (log_level_min != log_level_max &&
-                               log_level_max != LTTNG_LOGLEVEL_LOG4J_FATAL) {
-                       goto error;
-               }
-
-               *log_level = (int) log_level_min;
-               *log_level_only = log_level_min == log_level_max;
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-       {
-               enum lttng_loglevel_jul log_level_min, log_level_max;
-               if (!loglevel_jul_parse_range_string(
-                                   str, &log_level_min, &log_level_max)) {
-                       goto error;
-               }
-
-               /* Only support VAL and VAL.. for now. */
-               if (log_level_min != log_level_max &&
-                               log_level_max != LTTNG_LOGLEVEL_JUL_SEVERE) {
-                       goto error;
-               }
-
-               *log_level = (int) log_level_min;
-               *log_level_only = log_level_min == log_level_max;
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-       {
-               enum lttng_loglevel_python log_level_min, log_level_max;
-               if (!loglevel_python_parse_range_string(
-                                   str, &log_level_min, &log_level_max)) {
-                       goto error;
-               }
-
-               /* Only support VAL and VAL.. for now. */
-               if (log_level_min != log_level_max &&
-                               log_level_max !=
-                                               LTTNG_LOGLEVEL_PYTHON_CRITICAL) {
-                       goto error;
-               }
-
-               *log_level = (int) log_level_min;
-               *log_level_only = log_level_min == log_level_max;
-               break;
-       }
-       default:
-               /* Invalid domain type. */
-               abort();
-       }
-
-       ret = true;
-       goto end;
-
-error:
-       ret = false;
-
-end:
-       return ret;
-}
-
-static int parse_kernel_probe_opts(const char *source,
-               struct lttng_kernel_probe_location **location)
-{
-       int ret = 0;
-       int match;
-       char s_hex[19];
-       char name[LTTNG_SYMBOL_NAME_LEN];
-       char *symbol_name = NULL;
-       uint64_t offset;
-
-       /* Check for symbol+offset. */
-       match = sscanf(source,
-                       "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
-                       "[^'+']+%18s",
-                       name, s_hex);
-       if (match == 2) {
-               if (*s_hex == '\0') {
-                       ERR("Kernel probe symbol offset is missing.");
-                       goto error;
-               }
-
-               symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
-               if (!symbol_name) {
-                       PERROR("Failed to copy kernel probe location symbol name.");
-                       goto error;
-               }
-               offset = strtoul(s_hex, NULL, 0);
-
-               *location = lttng_kernel_probe_location_symbol_create(
-                               symbol_name, offset);
-               if (!*location) {
-                       ERR("Failed to create symbol kernel probe location.");
-                       goto error;
-               }
-
-               goto end;
-       }
-
-       /* Check for symbol. */
-       if (isalpha(name[0]) || name[0] == '_') {
-               match = sscanf(source,
-                               "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
-                               "s",
-                               name);
-               if (match == 1) {
-                       symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
-                       if (!symbol_name) {
-                               ERR("Failed to copy kernel probe location symbol name.");
-                               goto error;
-                       }
-
-                       *location = lttng_kernel_probe_location_symbol_create(
-                                       symbol_name, 0);
-                       if (!*location) {
-                               ERR("Failed to create symbol kernel probe location.");
-                               goto error;
-                       }
-
-                       goto end;
-               }
-       }
-
-       /* Check for address. */
-       match = sscanf(source, "%18s", s_hex);
-       if (match > 0) {
-               uint64_t address;
-
-               if (*s_hex == '\0') {
-                       ERR("Invalid kernel probe location address.");
-                       goto error;
-               }
-
-               address = strtoul(s_hex, NULL, 0);
-               *location = lttng_kernel_probe_location_address_create(address);
-               if (!*location) {
-                       ERR("Failed to create symbol kernel probe location.");
-                       goto error;
-               }
-
-               goto end;
-       }
-
-error:
-       /* No match */
-       ret = -1;
-       *location = NULL;
-
-end:
-       free(symbol_name);
-       return ret;
-}
-
-static
-struct lttng_event_expr *ir_op_load_expr_to_event_expr(
-               const struct ir_load_expression *load_expr,
-               const char *capture_str)
-{
-       char *provider_name = NULL;
-       struct lttng_event_expr *event_expr = NULL;
-       const struct ir_load_expression_op *load_expr_op = load_expr->child;
-       const enum ir_load_expression_type load_expr_child_type =
-                       load_expr_op->type;
-
-       switch (load_expr_child_type) {
-       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
-       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
-       {
-               const char *field_name;
-
-               load_expr_op = load_expr_op->next;
-               LTTNG_ASSERT(load_expr_op);
-               LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
-               field_name = load_expr_op->u.symbol;
-               LTTNG_ASSERT(field_name);
-
-               event_expr = load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
-                               lttng_event_expr_event_payload_field_create(field_name) :
-                               lttng_event_expr_channel_context_field_create(field_name);
-               if (!event_expr) {
-                       ERR("Failed to create %s event expression: field name = `%s`.",
-                                       load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
-                                                       "payload field" : "channel context",
-                                                       field_name);
-                       goto error;
-               }
-
-               break;
-       }
-       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
-       {
-               const char *colon;
-               const char *type_name;
-               const char *field_name;
-
-               load_expr_op = load_expr_op->next;
-               LTTNG_ASSERT(load_expr_op);
-               LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
-               field_name = load_expr_op->u.symbol;
-               LTTNG_ASSERT(field_name);
-
-               /*
-                * The field name needs to be of the form PROVIDER:TYPE. We
-                * split it here.
-                */
-               colon = strchr(field_name, ':');
-               if (!colon) {
-                       ERR("Invalid app-specific context field name: missing colon in `%s`.",
-                                       field_name);
-                       goto error;
-               }
-
-               type_name = colon + 1;
-               if (*type_name == '\0') {
-                       ERR("Invalid app-specific context field name: missing type name after colon in `%s`.",
-                                       field_name);
-                       goto error;
-               }
-
-               provider_name = strndup(field_name, colon - field_name);
-               if (!provider_name) {
-                       PERROR("Failed to allocate field name string");
-                       goto error;
-               }
-
-               event_expr = lttng_event_expr_app_specific_context_field_create(
-                               provider_name, type_name);
-               if (!event_expr) {
-                       ERR("Failed to create app-specific context field event expression: provider name = `%s`, type name = `%s`",
-                                       provider_name, type_name);
-                       goto error;
-               }
-
-               break;
-       }
-       default:
-               ERR("%s: unexpected load expr type %d.", __func__,
-                               load_expr_op->type);
-               abort();
-       }
-
-       load_expr_op = load_expr_op->next;
-
-       /* There may be a single array index after that. */
-       if (load_expr_op->type == IR_LOAD_EXPRESSION_GET_INDEX) {
-               struct lttng_event_expr *index_event_expr;
-               const uint64_t index = load_expr_op->u.index;
-
-               index_event_expr = lttng_event_expr_array_field_element_create(event_expr, index);
-               if (!index_event_expr) {
-                       ERR("Failed to create array field element event expression.");
-                       goto error;
-               }
-
-               event_expr = index_event_expr;
-               load_expr_op = load_expr_op->next;
-       }
-
-       switch (load_expr_op->type) {
-       case IR_LOAD_EXPRESSION_LOAD_FIELD:
-               /*
-                * This is what we expect, IR_LOAD_EXPRESSION_LOAD_FIELD is
-                * always found at the end of the chain.
-                */
-               break;
-       case IR_LOAD_EXPRESSION_GET_SYMBOL:
-               ERR("While parsing expression `%s`: Capturing subfields is not supported.",
-                               capture_str);
-               goto error;
-
-       default:
-               ERR("%s: unexpected load expression operator %s.", __func__,
-                               ir_load_expression_type_str(load_expr_op->type));
-               abort();
-       }
-
-       goto end;
-
-error:
-       lttng_event_expr_destroy(event_expr);
-       event_expr = NULL;
-
-end:
-       free(provider_name);
-
-       return event_expr;
-}
-
-static
-struct lttng_event_expr *ir_op_load_to_event_expr(
-               const struct ir_op *ir, const char *capture_str)
-{
-       struct lttng_event_expr *event_expr = NULL;
-
-       LTTNG_ASSERT(ir->op == IR_OP_LOAD);
-
-       switch (ir->data_type) {
-       case IR_DATA_EXPRESSION:
-       {
-               const struct ir_load_expression *ir_load_expr =
-                               ir->u.load.u.expression;
-
-               event_expr = ir_op_load_expr_to_event_expr(
-                               ir_load_expr, capture_str);
-               break;
-       }
-       default:
-               ERR("%s: unexpected data type: %s.", __func__,
-                               ir_data_type_str(ir->data_type));
-               abort();
-       }
-
-       return event_expr;
-}
-
-static
-const char *ir_operator_type_human_str(enum ir_op_type op)
-{
-       const char *name;
-
-       switch (op) {
-       case IR_OP_BINARY:
-               name = "Binary";
-               break;
-       case IR_OP_UNARY:
-               name = "Unary";
-               break;
-       case IR_OP_LOGICAL:
-               name = "Logical";
-               break;
-       default:
-               abort();
-       }
-
-       return name;
-}
-
-static
-struct lttng_event_expr *ir_op_root_to_event_expr(const struct ir_op *ir,
-               const char *capture_str)
-{
-       struct lttng_event_expr *event_expr = NULL;
-
-       LTTNG_ASSERT(ir->op == IR_OP_ROOT);
-       ir = ir->u.root.child;
-
-       switch (ir->op) {
-       case IR_OP_LOAD:
-               event_expr = ir_op_load_to_event_expr(ir, capture_str);
-               break;
-       case IR_OP_BINARY:
-       case IR_OP_UNARY:
-       case IR_OP_LOGICAL:
-               ERR("While parsing expression `%s`: %s operators are not allowed in capture expressions.",
-                               capture_str,
-                               ir_operator_type_human_str(ir->op));
-               break;
-       default:
-               ERR("%s: unexpected IR op type: %s.", __func__,
-                               ir_op_type_str(ir->op));
-               abort();
-       }
-
-       return event_expr;
-}
-
-static
-void destroy_event_expr(void *ptr)
-{
-       lttng_event_expr_destroy(ptr);
-}
-
-struct parse_event_rule_res {
-       /* Owned by this. */
-       struct lttng_event_rule *er;
-
-       /* Array of `struct lttng_event_expr *` */
-       struct lttng_dynamic_pointer_array capture_descriptors;
-};
-
-static
-struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
-{
-       enum lttng_event_rule_type event_rule_type =
-                       LTTNG_EVENT_RULE_TYPE_UNKNOWN;
-       struct argpar_state *state;
-       struct argpar_item *item = NULL;
-       char *error = NULL;
-       int consumed_args = -1;
-       struct lttng_kernel_probe_location *kernel_probe_location = NULL;
-       struct lttng_userspace_probe_location *userspace_probe_location = NULL;
-       struct parse_event_rule_res res = { 0 };
-       struct lttng_event_expr *event_expr = NULL;
-       struct filter_parser_ctx *parser_ctx = NULL;
-       struct lttng_log_level_rule *log_level_rule = NULL;
-
-       /* Event rule type option */
-       char *event_rule_type_str = NULL;
-
-       /* Tracepoint and syscall options. */
-       char *name = NULL;
-       /* Array of strings. */
-       struct lttng_dynamic_pointer_array exclude_names;
-
-       /* For userspace / kernel probe and function. */
-       char *location = NULL;
-       char *event_name = NULL;
-
-       /* Filter. */
-       char *filter = NULL;
-
-       /* Log level. */
-       char *log_level_str = NULL;
-
-       lttng_dynamic_pointer_array_init(&res.capture_descriptors,
-                               destroy_event_expr);
-
-       lttng_dynamic_pointer_array_init(&exclude_names, free);
-
-       state = argpar_state_create(*argc, *argv, event_rule_opt_descrs);
-       if (!state) {
-               ERR("Failed to allocate an argpar state.");
-               goto error;
-       }
-
-       while (true) {
-               enum argpar_state_parse_next_status status;
-
-               ARGPAR_ITEM_DESTROY_AND_RESET(item);
-               status = argpar_state_parse_next(state, &item, &error);
-               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
-                       /* Just stop parsing here. */
-                       break;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
-                       break;
-               }
-
-               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_TYPE:
-                               if (!assign_event_rule_type(&event_rule_type,
-                                               item_opt->arg)) {
-                                       goto error;
-                               }
-
-                               /* Save the string for later use. */
-                               if (!assign_string(&event_rule_type_str,
-                                                   item_opt->arg,
-                                                   "--type/-t")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_LOCATION:
-                               if (!assign_string(&location,
-                                               item_opt->arg,
-                                               "--location/-L")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_EVENT_NAME:
-                               if (!assign_string(&event_name,
-                                                   item_opt->arg,
-                                                   "--event-name/-E")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_FILTER:
-                               if (!assign_string(&filter, item_opt->arg,
-                                                   "--filter/-f")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_NAME:
-                               if (!assign_string(&name, item_opt->arg,
-                                                   "--name/-n")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_EXCLUDE_NAME:
-                       {
-                               int ret;
-
-                               ret = lttng_dynamic_pointer_array_add_pointer(
-                                               &exclude_names,
-                                               strdup(item_opt->arg));
-                               if (ret != 0) {
-                                       ERR("Failed to add pointer to dynamic pointer array.");
-                                       goto error;
-                               }
-
-                               break;
-                       }
-                       case OPT_LOG_LEVEL:
-                               if (!assign_string(&log_level_str,
-                                                   item_opt->arg, "--log-level/-l")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_CAPTURE:
-                       {
-                               int ret;
-                               const char *capture_str = item_opt->arg;
-
-                               ret = filter_parser_ctx_create_from_filter_expression(
-                                               capture_str, &parser_ctx);
-                               if (ret) {
-                                       ERR("Failed to parse capture expression `%s`.",
-                                                       capture_str);
-                                       goto error;
-                               }
-
-                               event_expr = ir_op_root_to_event_expr(
-                                               parser_ctx->ir_root,
-                                               capture_str);
-                               if (!event_expr) {
-                                       /*
-                                        * ir_op_root_to_event_expr has printed
-                                        * an error message.
-                                        */
-                                       goto error;
-                               }
-
-                               ret = lttng_dynamic_pointer_array_add_pointer(
-                                               &res.capture_descriptors,
-                                               event_expr);
-                               if (ret) {
-                                       goto error;
-                               }
-
-                               /*
-                                * The ownership of event expression was
-                                * transferred to the dynamic array.
-                                */
-                               event_expr = NULL;
-
-                               break;
-                       }
-                       default:
-                               abort();
-                       }
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt =
-                                       (const struct argpar_item_non_opt *)
-                                                       item;
-
-                       /* Don't accept non-option arguments. */
-                       ERR("Unexpected argument '%s'", item_non_opt->arg);
-                       goto error;
-               }
-       }
-
-       if (event_rule_type == LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
-               ERR("Event rule requires a --type.");
-               goto error;
-       }
-
-       /*
-        * Option --name is applicable to event rules of type kernel, user, jul,
-        * log4j,python and syscall.  If --name is omitted, it is implicitly
-        * "*".
-        */
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
-               if (!name) {
-                       name = strdup("*");
-               }
-               break;
-
-       default:
-               if (name) {
-                       ERR("Can't use --name with %s event rules.",
-                                       lttng_event_rule_type_str(
-                                                       event_rule_type));
-                       goto error;
-               }
-
-               if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
-                       ERR("Can't use --exclude-name/-x with %s event rules.",
-                                       lttng_event_rule_type_str(
-                                                       event_rule_type));
-                       goto error;
-               }
-       }
-
-       /*
-        * Option --location is only applicable to (and mandatory for) event
-        * rules of type {k,u}probe and function.
-        *
-        * Option --event-name is only applicable to event rules of type probe.
-        * If omitted, it defaults to the location.
-        */
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
-               if (!location) {
-                       ERR("Event rule of type %s requires a --location.",
-                       lttng_event_rule_type_str(event_rule_type));
-                       goto error;
-               }
-
-               if (!event_name) {
-                       event_name = strdup(location);
-               }
-
-               break;
-
-       default:
-               if (location) {
-                       ERR("Can't use --location with %s event rules.",
-                       lttng_event_rule_type_str(event_rule_type));
-                       goto error;
-               }
-
-               if (event_name) {
-                       ERR("Can't use --event-name with %s event rules.",
-                                       lttng_event_rule_type_str(
-                                                       event_rule_type));
-                       goto error;
-               }
-       }
-
-       /*
-        * Update *argc and *argv so our caller can keep parsing what follows.
-        */
-       consumed_args = argpar_state_get_ingested_orig_args(state);
-       LTTNG_ASSERT(consumed_args >= 0);
-       *argc -= consumed_args;
-       *argv += consumed_args;
-
-       /*
-        * Adding a filter to a probe, function or userspace-probe would be
-        * denied by the kernel tracer as it's not supported at the moment. We
-        * do an early check here to warn the user.
-        */
-       if (filter) {
-               switch (event_rule_type) {
-               case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-               case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
-               case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-               case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-               case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-               case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
-                       break;
-               default:
-                       ERR("Filter expressions are not supported for %s event rules.",
-                                       lttng_event_rule_type_str(event_rule_type));
-                       goto error;
-               }
-       }
-
-       /*
-        * If --exclude-name/-x was passed, split it into an exclusion list.
-        * Exclusions are only supported by
-        * LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT for now.
-        */
-       if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
-               if (event_rule_type != LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT) {
-                       ERR("Event name exclusions are not yet implemented for %s event rules.",
-                                       lttng_event_rule_type_str(event_rule_type));
-                       goto error;
-               }
-
-               if (validate_exclusion_list(name, &exclude_names) != 0) {
-                       /*
-                        * Assume validate_exclusion_list already prints an
-                        * error message.
-                        */
-                       goto error;
-               }
-       }
-
-       if (log_level_str) {
-               switch (event_rule_type) {
-               case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-               case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-               case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-               case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-               {
-                       int log_level;
-                       bool log_level_only;
-
-                       if (strcmp(log_level_str, "..") == 0) {
-                               /*
-                                * ".." is the same as passing no log level
-                                * option and correspond to the "ANY" case.
-                                */
-                               break;
-                       }
-
-                       if (!parse_log_level_string(log_level_str, event_rule_type,
-                                           &log_level, &log_level_only)) {
-                               ERR("Failed to parse log level string `%s`.",
-                                               log_level_str);
-                               goto error;
-                       }
-
-                       if (log_level_only) {
-                               log_level_rule = lttng_log_level_rule_exactly_create(log_level);
-                       } else {
-                               log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(log_level);
-                       }
-
-                       if (log_level_rule == NULL) {
-                               ERR("Failed to create log level rule object.");
-                               goto error;
-                       }
-                       break;
-               }
-               default:
-                       ERR("Log levels are not supported for %s event rules.",
-                                       lttng_event_rule_type_str(event_rule_type));
-                       goto error;
-               }
-       }
-
-       /* Finally, create the event rule object. */
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-       {
-               enum lttng_event_rule_status event_rule_status;
-
-               res.er = lttng_event_rule_user_tracepoint_create();
-               if (!res.er) {
-                       ERR("Failed to create user_tracepoint event rule.");
-                       goto error;
-               }
-
-               /* Set pattern. */
-               event_rule_status = lttng_event_rule_user_tracepoint_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set user_tracepoint event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               /* Set filter. */
-               if (filter) {
-                       event_rule_status = lttng_event_rule_user_tracepoint_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set user_tracepoint event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-
-               /* Set exclusion list. */
-               if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
-                       int n;
-                       int count = lttng_dynamic_pointer_array_get_count(
-                                       &exclude_names);
-
-                       for (n = 0; n < count; n++) {
-                               const char *exclude_name =
-                                               lttng_dynamic_pointer_array_get_pointer(
-                                                               &exclude_names,
-                                                               n);
-
-                               event_rule_status =
-                                               lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
-                                                               res.er,
-                                                               exclude_name);
-                               if (event_rule_status !=
-                                               LTTNG_EVENT_RULE_STATUS_OK) {
-                                       ERR("Failed to set user_tracepoint exclusion list element '%s'",
-                                                       exclude_name);
-                                       goto error;
-                               }
-                       }
-               }
-
-               if (log_level_rule) {
-                       event_rule_status =
-                                       lttng_event_rule_user_tracepoint_set_log_level_rule(
-                                                       res.er, log_level_rule);
-
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set log level on event fule.");
-                               goto error;
-                       }
-               }
-
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
-       {
-               enum lttng_event_rule_status event_rule_status;
-
-               res.er = lttng_event_rule_kernel_tracepoint_create();
-               if (!res.er) {
-                       ERR("Failed to create kernel_tracepoint event rule.");
-                       goto error;
-               }
-
-               /* Set pattern. */
-               event_rule_status = lttng_event_rule_kernel_tracepoint_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set kernel_tracepoint event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               /* Set filter. */
-               if (filter) {
-                       event_rule_status = lttng_event_rule_kernel_tracepoint_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set kernel_tracepoint event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-       {
-               enum lttng_event_rule_status event_rule_status;
-
-               res.er = lttng_event_rule_jul_logging_create();
-               if (!res.er) {
-                       ERR("Failed to create jul_logging event rule.");
-                       goto error;
-               }
-
-               /* Set pattern. */
-               event_rule_status = lttng_event_rule_jul_logging_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               /* Set filter. */
-               if (filter) {
-                       event_rule_status = lttng_event_rule_jul_logging_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-
-               if (log_level_rule) {
-                       event_rule_status =
-                                       lttng_event_rule_jul_logging_set_log_level_rule(
-                                                       res.er, log_level_rule);
-
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set log level on event fule.");
-                               goto error;
-                       }
-               }
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-       {
-               enum lttng_event_rule_status event_rule_status;
-
-               res.er = lttng_event_rule_log4j_logging_create();
-               if (!res.er) {
-                       ERR("Failed to create jul_logging event rule.");
-                       goto error;
-               }
-
-               /* Set pattern. */
-               event_rule_status = lttng_event_rule_log4j_logging_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               /* Set filter. */
-               if (filter) {
-                       event_rule_status = lttng_event_rule_log4j_logging_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-
-               if (log_level_rule) {
-                       event_rule_status =
-                                       lttng_event_rule_log4j_logging_set_log_level_rule(
-                                                       res.er, log_level_rule);
-
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set log level on event fule.");
-                               goto error;
-                       }
-               }
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-       {
-               enum lttng_event_rule_status event_rule_status;
-
-               res.er = lttng_event_rule_python_logging_create();
-               if (!res.er) {
-                       ERR("Failed to create jul_logging event rule.");
-                       goto error;
-               }
-
-               /* Set pattern. */
-               event_rule_status = lttng_event_rule_python_logging_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               /* Set filter. */
-               if (filter) {
-                       event_rule_status = lttng_event_rule_python_logging_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-
-               if (log_level_rule) {
-                       event_rule_status =
-                                       lttng_event_rule_python_logging_set_log_level_rule(
-                                                       res.er, log_level_rule);
-
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set log level on event fule.");
-                               goto error;
-                       }
-               }
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
-       {
-               int ret;
-               enum lttng_event_rule_status event_rule_status;
-
-               ret = parse_kernel_probe_opts(
-                               location, &kernel_probe_location);
-               if (ret) {
-                       ERR("Failed to parse kernel probe location.");
-                       goto error;
-               }
-
-               LTTNG_ASSERT(kernel_probe_location);
-               res.er = lttng_event_rule_kernel_kprobe_create(kernel_probe_location);
-               if (!res.er) {
-                       ERR("Failed to create kprobe event rule.");
-                       goto error;
-               }
-
-               event_rule_status =
-                               lttng_event_rule_kernel_kprobe_set_event_name(
-                                               res.er, event_name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set kprobe event rule's name to '%s'.",
-                                       event_name);
-                       goto error;
-               }
-
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
-       {
-               int ret;
-               enum lttng_event_rule_status event_rule_status;
-
-               ret = parse_userspace_probe_opts(
-                               location, &userspace_probe_location);
-               if (ret) {
-                       ERR("Failed to parse user space probe location.");
-                       goto error;
-               }
-
-               res.er = lttng_event_rule_kernel_uprobe_create(userspace_probe_location);
-               if (!res.er) {
-                       ERR("Failed to create userspace probe event rule.");
-                       goto error;
-               }
-
-               event_rule_status =
-                               lttng_event_rule_kernel_uprobe_set_event_name(
-                                               res.er, event_name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set user space probe event rule's name to '%s'.",
-                                       event_name);
-                       goto error;
-               }
-
-               break;
-       }
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
-       {
-               enum lttng_event_rule_status event_rule_status;
-               enum lttng_event_rule_kernel_syscall_emission_site emission_site;
-
-               if (!parse_syscall_emission_site_from_type(
-                                   event_rule_type_str, &emission_site)) {
-                       ERR("Failed to parse syscall type '%s'.", event_rule_type_str);
-                       goto error;
-               }
-
-               res.er = lttng_event_rule_kernel_syscall_create(emission_site);
-               if (!res.er) {
-                       ERR("Failed to create syscall event rule.");
-                       goto error;
-               }
-
-               event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
-                               res.er, name);
-               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                       ERR("Failed to set syscall event rule's pattern to '%s'.",
-                                       name);
-                       goto error;
-               }
-
-               if (filter) {
-                       event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
-                                       res.er, filter);
-                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-                               ERR("Failed to set syscall event rule's filter to '%s'.",
-                                               filter);
-                               goto error;
-                       }
-               }
-
-               break;
-       }
-       default:
-               abort();
-               goto error;
-       }
-
-       goto end;
-
-error:
-       lttng_event_rule_destroy(res.er);
-       res.er = NULL;
-       lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
-
-end:
-       if (parser_ctx) {
-               filter_parser_ctx_free(parser_ctx);
-       }
-
-       lttng_event_expr_destroy(event_expr);
-       argpar_item_destroy(item);
-       free(error);
-       argpar_state_destroy(state);
-       free(filter);
-       free(name);
-       lttng_dynamic_pointer_array_reset(&exclude_names);
-       free(log_level_str);
-       free(location);
-       free(event_name);
-       free(event_rule_type_str);
-
-       lttng_kernel_probe_location_destroy(kernel_probe_location);
-       lttng_userspace_probe_location_destroy(userspace_probe_location);
-       lttng_log_level_rule_destroy(log_level_rule);
-       return res;
-}
-
-static
-struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
-{
-       struct parse_event_rule_res res;
-       struct lttng_condition *c;
-       size_t i;
-
-       res = parse_event_rule(argc, argv);
-       if (!res.er) {
-               c = NULL;
-               goto error;
-       }
-
-       c = lttng_condition_event_rule_matches_create(res.er);
-       lttng_event_rule_destroy(res.er);
-       res.er = NULL;
-       if (!c) {
-               goto error;
-       }
-
-       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&res.capture_descriptors);
-                       i++) {
-               enum lttng_condition_status status;
-               struct lttng_event_expr **expr =
-                               lttng_dynamic_array_get_element(
-                                       &res.capture_descriptors.array, i);
-
-               LTTNG_ASSERT(expr);
-               LTTNG_ASSERT(*expr);
-               status = lttng_condition_event_rule_matches_append_capture_descriptor(
-                               c, *expr);
-               if (status != LTTNG_CONDITION_STATUS_OK) {
-                       if (status == LTTNG_CONDITION_STATUS_UNSUPPORTED) {
-                               ERR("The capture feature is unsupported by the event-rule condition type");
-                       }
-
-                       goto error;
-               }
-
-               /* Ownership of event expression moved to `c` */
-               *expr = NULL;
-       }
-
-       goto end;
-
-error:
-       lttng_condition_destroy(c);
-       c = NULL;
-
-end:
-       lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
-       lttng_event_rule_destroy(res.er);
-       return c;
-}
-
-struct condition_descr {
-       const char *name;
-       struct lttng_condition *(*handler) (int *argc, const char ***argv);
-};
-
-static const
-struct condition_descr condition_descrs[] = {
-       { "event-rule-matches", handle_condition_event },
-};
-
-static
-struct lttng_condition *parse_condition(const char *condition_name, int *argc,
-               const char ***argv)
-{
-       int i;
-       struct lttng_condition *cond;
-       const struct condition_descr *descr = NULL;
-
-       for (i = 0; i < ARRAY_SIZE(condition_descrs); i++) {
-               if (strcmp(condition_name, condition_descrs[i].name) == 0) {
-                       descr = &condition_descrs[i];
-                       break;
-               }
-       }
-
-       if (!descr) {
-               ERR("Unknown condition name '%s'", condition_name);
-               goto error;
-       }
-
-       cond = descr->handler(argc, argv);
-       if (!cond) {
-               /* The handler has already printed an error message. */
-               goto error;
-       }
-
-       goto end;
-error:
-       cond = NULL;
-end:
-       return cond;
-}
-
-static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
-{
-       int ret;
-       size_t num_token = 0;
-       struct lttng_dynamic_pointer_array tokens;
-       struct lttng_rate_policy *policy = NULL;
-       enum lttng_rate_policy_type policy_type;
-       unsigned long long value;
-       char *policy_type_str;
-       char *policy_value_str;
-
-       LTTNG_ASSERT(policy_str);
-       lttng_dynamic_pointer_array_init(&tokens, NULL);
-
-       /* Rate policy fields are separated by ':'. */
-       ret = strutils_split(policy_str, ':', 1, &tokens);
-       if (ret == 0) {
-               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
-       }
-
-       /*
-        * Early sanity check that the number of parameter is exactly 2.
-        * i.e : type:value
-        */
-       if (num_token != 2) {
-               ERR("Rate policy format is invalid.");
-               goto end;
-       }
-
-       policy_type_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
-       policy_value_str = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
-
-       /* Parse the type. */
-       if (strcmp(policy_type_str, "once-after") == 0) {
-               policy_type = LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N;
-       } else if (strcmp(policy_type_str, "every") == 0) {
-               policy_type = LTTNG_RATE_POLICY_TYPE_EVERY_N;
-       } else {
-               ERR("Rate policy type `%s` unknown.", policy_type_str);
-               goto end;
-       }
-
-       /* Parse the value. */
-       if (utils_parse_unsigned_long_long(policy_value_str, &value) != 0) {
-               ERR("Failed to parse rate policy value `%s` as an integer.",
-                               policy_value_str);
-               goto end;
-       }
-
-       if (value == 0) {
-               ERR("Rate policy value `%s` must be > 0.", policy_value_str);
-               goto end;
-       }
-
-       switch (policy_type) {
-       case LTTNG_RATE_POLICY_TYPE_EVERY_N:
-               policy = lttng_rate_policy_every_n_create(value);
-               break;
-       case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
-               policy = lttng_rate_policy_once_after_n_create(value);
-               break;
-       default:
-               abort();
-       }
-
-       if (policy == NULL) {
-               ERR("Failed to create rate policy `%s`.", policy_str);
-       }
-
-end:
-       lttng_dynamic_pointer_array_reset(&tokens);
-       return policy;
-}
-
-static const struct argpar_opt_descr notify_action_opt_descrs[] = {
-       { OPT_RATE_POLICY, '\0', "rate-policy", true },
-       ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-struct lttng_action *handle_action_notify(int *argc, const char ***argv)
-{
-       struct lttng_action *action = NULL;
-       struct argpar_state *state = NULL;
-       struct argpar_item *item = NULL;
-       char *error = NULL;
-       struct lttng_rate_policy *policy = NULL;
-
-       state = argpar_state_create(*argc, *argv, notify_action_opt_descrs);
-       if (!state) {
-               ERR("Failed to allocate an argpar state.");
-               goto error;
-       }
-
-       while (true) {
-               enum argpar_state_parse_next_status status;
-
-               ARGPAR_ITEM_DESTROY_AND_RESET(item);
-               status = argpar_state_parse_next(state, &item, &error);
-               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
-                       /* Just stop parsing here. */
-                       break;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
-                       break;
-               }
-
-               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_RATE_POLICY:
-                       {
-                               policy = parse_rate_policy(item_opt->arg);
-                               if (!policy) {
-                                       goto error;
-                               }
-                               break;
-                       }
-                       default:
-                               abort();
-                       }
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt;
-
-                       LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
-
-                       item_non_opt = (const struct argpar_item_non_opt *) item;
-
-                       switch (item_non_opt->non_opt_index) {
-                       default:
-                               ERR("Unexpected argument `%s`.",
-                                               item_non_opt->arg);
-                               goto error;
-                       }
-               }
-       }
-
-       *argc -= argpar_state_get_ingested_orig_args(state);
-       *argv += argpar_state_get_ingested_orig_args(state);
-
-       action = lttng_action_notify_create();
-       if (!action) {
-               ERR("Failed to create notify action");
-               goto error;
-       }
-
-       if (policy) {
-               enum lttng_action_status status;
-               status = lttng_action_notify_set_rate_policy(action, policy);
-               if (status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to set rate policy");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       lttng_action_destroy(action);
-       action = NULL;
-end:
-       free(error);
-       lttng_rate_policy_destroy(policy);
-       argpar_state_destroy(state);
-       argpar_item_destroy(item);
-       return action;
-}
-
-/*
- * Generic handler for a kind of action that takes a session name and an
- * optional rate policy.
- */
-
-static struct lttng_action *handle_action_simple_session_with_policy(int *argc,
-               const char ***argv,
-               struct lttng_action *(*create_action_cb)(void),
-               enum lttng_action_status (*set_session_name_cb)(
-                               struct lttng_action *, const char *),
-               enum lttng_action_status (*set_rate_policy_cb)(
-                               struct lttng_action *,
-                               const struct lttng_rate_policy *),
-               const char *action_name)
-{
-       struct lttng_action *action = NULL;
-       struct argpar_state *state = NULL;
-       struct argpar_item *item = NULL;
-       const char *session_name_arg = NULL;
-       char *error = NULL;
-       enum lttng_action_status action_status;
-       struct lttng_rate_policy *policy = NULL;
-
-       LTTNG_ASSERT(set_session_name_cb);
-       LTTNG_ASSERT(set_rate_policy_cb);
-
-       const struct argpar_opt_descr rate_policy_opt_descrs[] = {
-               { OPT_RATE_POLICY, '\0', "rate-policy", true },
-               ARGPAR_OPT_DESCR_SENTINEL
-       };
-
-       state = argpar_state_create(*argc, *argv, rate_policy_opt_descrs);
-       if (!state) {
-               ERR("Failed to allocate an argpar state.");
-               goto error;
-       }
-
-       while (true) {
-               enum argpar_state_parse_next_status status;
-
-               ARGPAR_ITEM_DESTROY_AND_RESET(item);
-               status = argpar_state_parse_next(state, &item, &error);
-               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status ==
-                               ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
-                       /* Just stop parsing here. */
-                       break;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
-                       break;
-               }
-
-               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_RATE_POLICY:
-                       {
-                               policy = parse_rate_policy(item_opt->arg);
-                               if (!policy) {
-                                       goto error;
-                               }
-                               break;
-                       }
-                       default:
-                               abort();
-                       }
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt;
-                       item_non_opt = (const struct argpar_item_non_opt *) item;
-
-                       switch (item_non_opt->non_opt_index) {
-                       case 0:
-                               session_name_arg = item_non_opt->arg;
-                               break;
-                       default:
-                               ERR("Unexpected argument `%s`.",
-                                               item_non_opt->arg);
-                               goto error;
-                       }
-               }
-       }
-
-       *argc -= argpar_state_get_ingested_orig_args(state);
-       *argv += argpar_state_get_ingested_orig_args(state);
-
-       if (!session_name_arg) {
-               ERR("Missing session name.");
-               goto error;
-       }
-
-       action = create_action_cb();
-       if (!action) {
-               ERR("Failed to allocate %s session action.", action_name);
-               goto error;
-       }
-
-       action_status = set_session_name_cb(action, session_name_arg);
-       if (action_status != LTTNG_ACTION_STATUS_OK) {
-               ERR("Failed to set action %s session's session name to '%s'.",
-                               action_name, session_name_arg);
-               goto error;
-       }
-
-       if (policy) {
-               action_status = set_rate_policy_cb(action, policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to set rate policy");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       lttng_action_destroy(action);
-       action = NULL;
-       argpar_item_destroy(item);
-end:
-       lttng_rate_policy_destroy(policy);
-       free(error);
-       argpar_state_destroy(state);
-       return action;
-}
-
-static
-struct lttng_action *handle_action_start_session(int *argc,
-               const char ***argv)
-{
-       return handle_action_simple_session_with_policy(argc, argv,
-                       lttng_action_start_session_create,
-                       lttng_action_start_session_set_session_name,
-                       lttng_action_start_session_set_rate_policy, "start");
-}
-
-static
-struct lttng_action *handle_action_stop_session(int *argc,
-               const char ***argv)
-{
-       return handle_action_simple_session_with_policy(argc, argv,
-                       lttng_action_stop_session_create,
-                       lttng_action_stop_session_set_session_name,
-                       lttng_action_stop_session_set_rate_policy, "stop");
-}
-
-static
-struct lttng_action *handle_action_rotate_session(int *argc,
-               const char ***argv)
-{
-       return handle_action_simple_session_with_policy(argc, argv,
-               lttng_action_rotate_session_create,
-               lttng_action_rotate_session_set_session_name,
-               lttng_action_rotate_session_set_rate_policy,
-               "rotate");
-}
-
-static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
-       { OPT_NAME, 'n', "name", true },
-       { OPT_MAX_SIZE, 'm', "max-size", true },
-       { OPT_CTRL_URL, '\0', "ctrl-url", true },
-       { OPT_DATA_URL, '\0', "data-url", true },
-       { OPT_URL, '\0', "url", true },
-       { OPT_PATH, '\0', "path", true },
-       { OPT_RATE_POLICY, '\0', "rate-policy", true },
-       ARGPAR_OPT_DESCR_SENTINEL
-};
-
-static
-struct lttng_action *handle_action_snapshot_session(int *argc,
-               const char ***argv)
-{
-       struct lttng_action *action = NULL;
-       struct argpar_state *state = NULL;
-       struct argpar_item *item = NULL;
-       const char *session_name_arg = NULL;
-       char *snapshot_name_arg = NULL;
-       char *ctrl_url_arg = NULL;
-       char *data_url_arg = NULL;
-       char *max_size_arg = NULL;
-       char *url_arg = NULL;
-       char *path_arg = NULL;
-       char *error = NULL;
-       enum lttng_action_status action_status;
-       struct lttng_snapshot_output *snapshot_output = NULL;
-       struct lttng_rate_policy *policy = NULL;
-       int ret;
-       unsigned int locations_specified = 0;
-
-       state = argpar_state_create(*argc, *argv, snapshot_action_opt_descrs);
-       if (!state) {
-               ERR("Failed to allocate an argpar state.");
-               goto error;
-       }
-
-       while (true) {
-               enum argpar_state_parse_next_status status;
-
-               ARGPAR_ITEM_DESTROY_AND_RESET(item);
-               status = argpar_state_parse_next(state, &item, &error);
-               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
-                       /* Just stop parsing here. */
-                       break;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
-                       break;
-               }
-
-               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_NAME:
-                               if (!assign_string(&snapshot_name_arg, item_opt->arg, "--name/-n")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_MAX_SIZE:
-                               if (!assign_string(&max_size_arg, item_opt->arg, "--max-size/-m")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_CTRL_URL:
-                               if (!assign_string(&ctrl_url_arg, item_opt->arg, "--ctrl-url")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_DATA_URL:
-                               if (!assign_string(&data_url_arg, item_opt->arg, "--data-url")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_URL:
-                               if (!assign_string(&url_arg, item_opt->arg, "--url")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_PATH:
-                               if (!assign_string(&path_arg, item_opt->arg, "--path")) {
-                                       goto error;
-                               }
-
-                               break;
-                       case OPT_RATE_POLICY:
-                       {
-                               policy = parse_rate_policy(item_opt->arg);
-                               if (!policy) {
-                                       goto error;
-                               }
-                               break;
-                       }
-                       default:
-                               abort();
-                       }
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt;
-
-                       LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
-
-                       item_non_opt = (const struct argpar_item_non_opt *) item;
-
-                       switch (item_non_opt->non_opt_index) {
-                       case 0:
-                               session_name_arg = item_non_opt->arg;
-                               break;
-                       default:
-                               ERR("Unexpected argument `%s`.",
-                                               item_non_opt->arg);
-                               goto error;
-                       }
-               }
-       }
-
-       *argc -= argpar_state_get_ingested_orig_args(state);
-       *argv += argpar_state_get_ingested_orig_args(state);
-
-       if (!session_name_arg) {
-               ERR("Missing session name.");
-               goto error;
-       }
-
-       /* --ctrl-url and --data-url must come in pair. */
-       if (ctrl_url_arg && !data_url_arg) {
-               ERR("--ctrl-url is specified, but --data-url is missing.");
-               goto error;
-       }
-
-       if (!ctrl_url_arg && data_url_arg) {
-               ERR("--data-url is specified, but --ctrl-url is missing.");
-               goto error;
-       }
-
-       locations_specified += !!(ctrl_url_arg || data_url_arg);
-       locations_specified += !!url_arg;
-       locations_specified += !!path_arg;
-
-       /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
-       if (locations_specified > 1) {
-               ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
-               goto error;
-       }
-
-       /*
-        * Did the user specify an option that implies using a
-        * custom/unregistered output?
-        */
-       if (url_arg || ctrl_url_arg || path_arg) {
-               snapshot_output = lttng_snapshot_output_create();
-               if (!snapshot_output) {
-                       ERR("Failed to allocate a snapshot output.");
-                       goto error;
-               }
-       }
-
-       action = lttng_action_snapshot_session_create();
-       if (!action) {
-               ERR("Failed to allocate snapshot session action.");
-               goto error;
-       }
-
-       action_status = lttng_action_snapshot_session_set_session_name(
-                       action, session_name_arg);
-       if (action_status != LTTNG_ACTION_STATUS_OK) {
-               ERR("Failed to set action snapshot session's session name to '%s'.",
-                               session_name_arg);
-               goto error;
-       }
-
-       if (snapshot_name_arg) {
-               if (!snapshot_output) {
-                       ERR("Can't provide a snapshot output name without a snapshot output destination.");
-                       goto error;
-               }
-
-               ret = lttng_snapshot_output_set_name(
-                               snapshot_name_arg, snapshot_output);
-               if (ret != 0) {
-                       ERR("Failed to set name of snapshot output.");
-                       goto error;
-               }
-       }
-
-       if (max_size_arg) {
-               uint64_t max_size;
-
-               if (!snapshot_output) {
-                       ERR("Can't provide a snapshot output max size without a snapshot output destination.");
-                       goto error;
-               }
-
-               ret = utils_parse_size_suffix(max_size_arg, &max_size);
-               if (ret != 0) {
-                       ERR("Failed to parse `%s` as a size.", max_size_arg);
-                       goto error;
-               }
-
-               ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
-               if (ret != 0) {
-                       ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
-                                       max_size);
-                       goto error;
-               }
-       }
-
-       if (url_arg) {
-               int num_uris;
-               struct lttng_uri *uris;
-
-               if (!strstr(url_arg, "://")) {
-                       ERR("Failed to parse '%s' as an URL.", url_arg);
-                       goto error;
-               }
-
-               num_uris = uri_parse_str_urls(url_arg, NULL, &uris);
-               if (num_uris < 1) {
-                       ERR("Failed to parse '%s' as an URL.", url_arg);
-                       goto error;
-               }
-
-               if (uris[0].dtype == LTTNG_DST_PATH) {
-                       ret = lttng_snapshot_output_set_local_path(
-                                       uris[0].dst.path, snapshot_output);
-                       free(uris);
-                       if (ret != 0) {
-                               ERR("Failed to assign '%s' as a local destination.",
-                                               url_arg);
-                               goto error;
-                       }
-               } else {
-                       ret = lttng_snapshot_output_set_network_url(
-                                       url_arg, snapshot_output);
-                       free(uris);
-                       if (ret != 0) {
-                               ERR("Failed to assign '%s' as a network URL.",
-                                               url_arg);
-                               goto error;
-                       }
-               }
-       }
-
-       if (path_arg) {
-               ret = lttng_snapshot_output_set_local_path(
-                               path_arg, snapshot_output);
-               if (ret != 0) {
-                       ERR("Failed to parse '%s' as a local path.", path_arg);
-                       goto error;
-               }
-       }
-
-       if (ctrl_url_arg) {
-               /*
-                * Two argument form, network output with separate control and
-                * data URLs.
-                */
-               ret = lttng_snapshot_output_set_network_urls(
-                               ctrl_url_arg, data_url_arg, snapshot_output);
-               if (ret != 0) {
-                       ERR("Failed to parse `%s` and `%s` as control and data URLs.",
-                                       ctrl_url_arg, data_url_arg);
-                       goto error;
-               }
-       }
-
-       if (snapshot_output) {
-               action_status = lttng_action_snapshot_session_set_output(
-                               action, snapshot_output);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to set snapshot session action's output.");
-                       goto error;
-               }
-
-               /* Ownership of `snapshot_output` has been transferred to the action. */
-               snapshot_output = NULL;
-       }
-
-       if (policy) {
-               enum lttng_action_status status;
-               status = lttng_action_snapshot_session_set_rate_policy(
-                               action, policy);
-               if (status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to set rate policy");
-                       goto error;
-               }
-       }
-
-       goto end;
-
-error:
-       lttng_action_destroy(action);
-       action = NULL;
-       free(error);
-end:
-       free(snapshot_name_arg);
-       free(path_arg);
-       free(url_arg);
-       free(ctrl_url_arg);
-       free(data_url_arg);
-       free(snapshot_output);
-       free(max_size_arg);
-       lttng_rate_policy_destroy(policy);
-       argpar_state_destroy(state);
-       argpar_item_destroy(item);
-       return action;
-}
-
-struct action_descr {
-       const char *name;
-       struct lttng_action *(*handler) (int *argc, const char ***argv);
-};
-
-static const
-struct action_descr action_descrs[] = {
-       { "notify", handle_action_notify },
-       { "start-session", handle_action_start_session },
-       { "stop-session", handle_action_stop_session },
-       { "rotate-session", handle_action_rotate_session },
-       { "snapshot-session", handle_action_snapshot_session },
-};
-
-static
-struct lttng_action *parse_action(const char *action_name, int *argc, const char ***argv)
-{
-       int i;
-       struct lttng_action *action;
-       const struct action_descr *descr = NULL;
-
-       for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
-               if (strcmp(action_name, action_descrs[i].name) == 0) {
-                       descr = &action_descrs[i];
-                       break;
-               }
-       }
-
-       if (!descr) {
-               ERR("Unknown action name: %s", action_name);
-               goto error;
-       }
-
-       action = descr->handler(argc, argv);
-       if (!action) {
-               /* The handler has already printed an error message. */
-               goto error;
-       }
-
-       goto end;
-error:
-       action = NULL;
-end:
-       return action;
-}
-
-static const
-struct argpar_opt_descr add_trigger_options[] = {
-       { OPT_HELP, 'h', "help", false },
-       { OPT_LIST_OPTIONS, '\0', "list-options", false },
-       { OPT_CONDITION, '\0', "condition", true },
-       { OPT_ACTION, '\0', "action", true },
-       { OPT_NAME, '\0', "name", true },
-       { OPT_OWNER_UID, '\0', "owner-uid", true },
-       ARGPAR_OPT_DESCR_SENTINEL,
-};
-
-static
-void lttng_actions_destructor(void *p)
-{
-       struct lttng_action *action = p;
-
-       lttng_action_destroy(action);
-}
-
-int cmd_add_trigger(int argc, const char **argv)
-{
-       int ret;
-       int my_argc = argc - 1;
-       const char **my_argv = argv + 1;
-       struct lttng_condition *condition = NULL;
-       struct lttng_dynamic_pointer_array actions;
-       struct argpar_state *argpar_state = NULL;
-       struct argpar_item *argpar_item = NULL;
-       struct lttng_action *action_list = NULL;
-       struct lttng_action *action = NULL;
-       struct lttng_trigger *trigger = NULL;
-       char *error = NULL;
-       char *name = NULL;
-       int i;
-       char *owner_uid = NULL;
-       enum lttng_error_code ret_code;
-       struct mi_writer *mi_writer = NULL;
-
-       lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
-
-       if (lttng_opt_mi) {
-               mi_writer = mi_lttng_writer_create(
-                               fileno(stdout), lttng_opt_mi);
-               if (!mi_writer) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               /* Open command element. */
-               ret = mi_lttng_writer_command_open(mi_writer,
-                               mi_lttng_element_command_add_trigger);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               /* Open output element. */
-               ret = mi_lttng_writer_open_element(
-                               mi_writer, mi_lttng_element_command_output);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       while (true) {
-               enum argpar_state_parse_next_status status;
-               const struct argpar_item_opt *item_opt;
-               int ingested_args;
-
-               argpar_state_destroy(argpar_state);
-               argpar_state = argpar_state_create(my_argc, my_argv,
-                       add_trigger_options);
-               if (!argpar_state) {
-                       ERR("Failed to create argpar state.");
-                       goto error;
-               }
-
-               ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
-               status = argpar_state_parse_next(argpar_state, &argpar_item, &error);
-               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
-                       ERR("%s", error);
-                       goto error;
-               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
-                       break;
-               }
-
-               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
-
-               if (argpar_item->type == ARGPAR_ITEM_TYPE_NON_OPT) {
-                       const struct argpar_item_non_opt *item_non_opt =
-                                       (const struct argpar_item_non_opt *)
-                                                       argpar_item;
-
-                       ERR("Unexpected argument `%s`.", item_non_opt->arg);
-                       goto error;
-               }
-
-               item_opt = (const struct argpar_item_opt *) argpar_item;
-
-               ingested_args = argpar_state_get_ingested_orig_args(
-                               argpar_state);
-
-               my_argc -= ingested_args;
-               my_argv += ingested_args;
-
-               switch (item_opt->descr->id) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       ret = 0;
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options_argpar(stdout, add_trigger_options);
-                       ret = 0;
-                       goto end;
-               case OPT_CONDITION:
-               {
-                       if (condition) {
-                               ERR("A --condition was already given.");
-                               goto error;
-                       }
-
-                       condition = parse_condition(item_opt->arg, &my_argc, &my_argv);
-                       if (!condition) {
-                               /*
-                                * An error message was already printed by
-                                * parse_condition.
-                                */
-                               goto error;
-                       }
-
-                       break;
-               }
-               case OPT_ACTION:
-               {
-                       action = parse_action(item_opt->arg, &my_argc, &my_argv);
-                       if (!action) {
-                               /*
-                                * An error message was already printed by
-                                * parse_condition.
-                                */
-                               goto error;
-                       }
-
-                       ret = lttng_dynamic_pointer_array_add_pointer(
-                                       &actions, action);
-                       if (ret) {
-                               ERR("Failed to add pointer to pointer array.");
-                               goto error;
-                       }
-
-                       /* Ownership of the action was transferred to the list. */
-                       action = NULL;
-
-                       break;
-               }
-               case OPT_NAME:
-               {
-                       if (!assign_string(&name, item_opt->arg, "--name")) {
-                               goto error;
-                       }
-
-                       break;
-               }
-               case OPT_OWNER_UID:
-               {
-                       if (!assign_string(&owner_uid, item_opt->arg,
-                                       "--owner-uid")) {
-                               goto error;
-                       }
-
-                       break;
-               }
-               default:
-                       abort();
-               }
-       }
-
-       if (!condition) {
-               ERR("Missing --condition.");
-               goto error;
-       }
-
-       if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
-               ERR("Need at least one --action.");
-               goto error;
-       }
-
-       action_list = lttng_action_list_create();
-       if (!action_list) {
-               goto error;
-       }
-
-       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
-               enum lttng_action_status status;
-
-               action = lttng_dynamic_pointer_array_steal_pointer(&actions, i);
-
-               status = lttng_action_list_add_action(action_list, action);
-               if (status != LTTNG_ACTION_STATUS_OK) {
-                       goto error;
-               }
-
-               /*
-                * The `lttng_action_list_add_action()` takes a reference to
-                * the action. We can destroy ours.
-                */
-               lttng_action_destroy(action);
-               action = NULL;
-       }
-
-       trigger = lttng_trigger_create(condition, action_list);
-       if (!trigger) {
-               goto error;
-       }
-
-       if (owner_uid) {
-               enum lttng_trigger_status trigger_status;
-               char *end;
-               long long uid;
-
-               errno = 0;
-               uid = strtol(owner_uid, &end, 10);
-               if (end == owner_uid || *end != '\0' || errno != 0) {
-                       ERR("Failed to parse `%s` as a user id.", owner_uid);
-                       goto error;
-               }
-
-               trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
-               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-                       ERR("Failed to set trigger's user identity.");
-                       goto error;
-               }
-       }
-
-       if (name) {
-               ret_code = lttng_register_trigger_with_name(trigger, name);
-       } else {
-               ret_code = lttng_register_trigger_with_automatic_name(trigger);
-       }
-
-       if (ret_code != LTTNG_OK) {
-               ERR("Failed to register trigger: %s.",
-                               lttng_strerror(-ret_code));
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               ret_code = lttng_trigger_mi_serialize(trigger, mi_writer, NULL);
-               if (ret_code != LTTNG_OK) {
-                       goto error;
-               }
-       } else {
-               const char *returned_trigger_name;
-               const enum lttng_trigger_status trigger_status =
-                               lttng_trigger_get_name(trigger,
-                                               &returned_trigger_name);
-
-               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-                       WARN("Failed to retrieve the added trigger's name.");
-               } else {
-                       MSG("Added trigger `%s`.", returned_trigger_name);
-               }
-       }
-
-       ret = 0;
-
-       goto end;
-
-error:
-       ret = 1;
-
-end:
-       /* Mi closing. */
-       if (lttng_opt_mi && mi_writer) {
-               int mi_ret;
-
-               /* Close output element. */
-               mi_ret = mi_lttng_writer_close_element(mi_writer);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-
-               mi_ret = mi_lttng_writer_write_element_bool(mi_writer,
-                               mi_lttng_element_command_success, ret ? 0 : 1);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-
-               /* Command element close. */
-               mi_ret = mi_lttng_writer_command_close(mi_writer);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-       }
-
-cleanup:
-       argpar_state_destroy(argpar_state);
-       argpar_item_destroy(argpar_item);
-       lttng_dynamic_pointer_array_reset(&actions);
-       lttng_condition_destroy(condition);
-       lttng_action_destroy(action_list);
-       lttng_action_destroy(action);
-       lttng_trigger_destroy(trigger);
-       free(error);
-       free(name);
-       free(owner_uid);
-       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
-               /* Preserve original error code. */
-               ret = ret ? ret : CMD_ERROR;
-       }
-
-       return ret;
-}
diff --git a/src/bin/lttng/commands/add_trigger.cpp b/src/bin/lttng/commands/add_trigger.cpp
new file mode 100644 (file)
index 0000000..939d510
--- /dev/null
@@ -0,0 +1,2475 @@
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <ctype.h>
+#include <stdio.h>
+#include <string.h>
+
+#include "../command.h"
+#include "../loglevel.h"
+#include "../uprobe.h"
+
+#include "common/argpar/argpar.h"
+#include "common/dynamic-array.h"
+#include "common/mi-lttng.h"
+#include "common/string-utils/string-utils.h"
+#include "common/utils.h"
+#include <lttng/domain-internal.h>
+/* For lttng_event_rule_type_str(). */
+#include <lttng/event-rule/event-rule-internal.h>
+#include <lttng/lttng.h>
+#include "common/filter/filter-ast.h"
+#include "common/filter/filter-ir.h"
+#include "common/dynamic-array.h"
+
+#if (LTTNG_SYMBOL_NAME_LEN == 256)
+#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "255"
+#endif
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-add-trigger.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP,
+       OPT_LIST_OPTIONS,
+
+       OPT_CONDITION,
+       OPT_ACTION,
+       OPT_ID,
+       OPT_OWNER_UID,
+       OPT_RATE_POLICY,
+
+       OPT_NAME,
+       OPT_FILTER,
+       OPT_EXCLUDE_NAME,
+       OPT_EVENT_NAME,
+       OPT_LOG_LEVEL,
+
+       OPT_TYPE,
+       OPT_LOCATION,
+
+       OPT_MAX_SIZE,
+       OPT_DATA_URL,
+       OPT_CTRL_URL,
+       OPT_URL,
+       OPT_PATH,
+
+       OPT_CAPTURE,
+};
+
+static const struct argpar_opt_descr event_rule_opt_descrs[] = {
+       { OPT_FILTER, 'f', "filter", true },
+       { OPT_NAME, 'n', "name", true },
+       { OPT_EXCLUDE_NAME, 'x', "exclude-name", true },
+       { OPT_LOG_LEVEL, 'l', "log-level", true },
+       { OPT_EVENT_NAME, 'E', "event-name", true },
+
+       { OPT_TYPE, 't', "type", true },
+       { OPT_LOCATION, 'L', "location", true },
+
+       /* Capture descriptor */
+       { OPT_CAPTURE, '\0', "capture", true },
+
+       ARGPAR_OPT_DESCR_SENTINEL
+};
+
+static
+bool has_syscall_prefix(const char *arg)
+{
+       bool matches = false;
+       const char kernel_syscall_type_opt_prefix[] = "kernel:syscall";
+       const size_t kernel_syscall_type_opt_prefix_len =
+                       sizeof(kernel_syscall_type_opt_prefix) - 1;
+       const char syscall_type_opt_prefix[] = "syscall";
+       const size_t syscall_type_opt_prefix_len =
+                       sizeof(syscall_type_opt_prefix) - 1;
+
+       if (strncmp(arg, syscall_type_opt_prefix,
+                           syscall_type_opt_prefix_len) == 0) {
+               matches = true;
+       } else if (strncmp(arg, kernel_syscall_type_opt_prefix,
+                                  kernel_syscall_type_opt_prefix_len) == 0) {
+               matches = true;
+       } else {
+               matches = false;
+       }
+
+       return matches;
+}
+
+static
+bool assign_event_rule_type(enum lttng_event_rule_type *dest, const char *arg)
+{
+       bool ret;
+
+       if (*dest != LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
+               ERR("More than one `--type` was specified.");
+               goto error;
+       }
+
+       if (strcmp(arg, "user") == 0 || strcmp(arg, "user:tracepoint") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT;
+       } else if (strcmp(arg, "kernel") == 0 ||
+                       strcmp(arg, "kernel:tracepoint") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT;
+       } else if (strcmp(arg, "jul") == 0 || strcmp(arg, "jul:logging") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_JUL_LOGGING;
+       } else if (strcmp(arg, "log4j") == 0 ||
+                       strcmp(arg, "log4j:logging") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING;
+       } else if (strcmp(arg, "python") == 0 ||
+                       strcmp(arg, "python:logging") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING;
+       } else if (strcmp(arg, "kprobe") == 0 ||
+                       strcmp(arg, "kernel:kprobe") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE;
+       } else if (strcmp(arg, "kernel:uprobe") == 0) {
+               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE;
+       } else if (has_syscall_prefix(arg)) {
+               /*
+                * Matches the following:
+                *   - syscall
+                *   - syscall:entry
+                *   - syscall:exit
+                *   - syscall:entry+exit
+                *   - syscall:*
+                *   - kernel:syscall
+                *   - kernel:syscall:entry
+                *   - kernel:syscall:exit
+                *   - kernel:syscall:entry+exit
+                *   - kernel:syscall:*
+                *
+                * Validation for the right side is left to further usage sites.
+                */
+               *dest = LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL;
+       } else {
+               ERR("Invalid `--type` value: %s", arg);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate '%s' given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               PERROR("Failed to allocate string '%s'.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+static bool parse_syscall_emission_site_from_type(const char *str,
+               enum lttng_event_rule_kernel_syscall_emission_site *type)
+{
+       bool ret = false;
+       const char kernel_prefix[] = "kernel:";
+       const size_t kernel_prefix_len = sizeof(kernel_prefix) - 1;
+
+       /*
+        * If the passed string is of the form "kernel:syscall*", move the
+        * pointer passed "kernel:".
+        */
+       if (strncmp(str, kernel_prefix, kernel_prefix_len) == 0) {
+               str = &str[kernel_prefix_len];
+       }
+
+       if (strcmp(str, "syscall") == 0 ||
+                       strcmp(str, "syscall:entry+exit") == 0) {
+               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY_EXIT;
+       } else if (strcmp(str, "syscall:entry") == 0) {
+               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_ENTRY;
+       } else if (strcmp(str, "syscall:exit") == 0) {
+               *type = LTTNG_EVENT_RULE_KERNEL_SYSCALL_EMISSION_SITE_EXIT;
+       } else {
+               goto error;
+       }
+
+       ret = true;
+
+error:
+       return ret;
+}
+
+/*
+ * Parse `str` as a log level against the passed event rule type.
+ *
+ * Return the log level in `*log_level`.  Return true in `*log_level_only` if
+ * the string specifies exactly this log level, false if it specifies at least
+ * this log level.
+ *
+ * Return true if the string was successfully parsed as a log level string.
+ */
+static bool parse_log_level_string(const char *str,
+               enum lttng_event_rule_type event_rule_type,
+               int *log_level,
+               bool *log_level_only)
+{
+       bool ret;
+
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+       {
+               enum lttng_loglevel log_level_min, log_level_max;
+               if (!loglevel_parse_range_string(
+                                   str, &log_level_min, &log_level_max)) {
+                       goto error;
+               }
+
+               /* Only support VAL and VAL.. for now. */
+               if (log_level_min != log_level_max &&
+                               log_level_max != LTTNG_LOGLEVEL_EMERG) {
+                       goto error;
+               }
+
+               *log_level = (int) log_level_min;
+               *log_level_only = log_level_min == log_level_max;
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+       {
+               enum lttng_loglevel_log4j log_level_min, log_level_max;
+               if (!loglevel_log4j_parse_range_string(
+                                   str, &log_level_min, &log_level_max)) {
+                       goto error;
+               }
+
+               /* Only support VAL and VAL.. for now. */
+               if (log_level_min != log_level_max &&
+                               log_level_max != LTTNG_LOGLEVEL_LOG4J_FATAL) {
+                       goto error;
+               }
+
+               *log_level = (int) log_level_min;
+               *log_level_only = log_level_min == log_level_max;
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+       {
+               enum lttng_loglevel_jul log_level_min, log_level_max;
+               if (!loglevel_jul_parse_range_string(
+                                   str, &log_level_min, &log_level_max)) {
+                       goto error;
+               }
+
+               /* Only support VAL and VAL.. for now. */
+               if (log_level_min != log_level_max &&
+                               log_level_max != LTTNG_LOGLEVEL_JUL_SEVERE) {
+                       goto error;
+               }
+
+               *log_level = (int) log_level_min;
+               *log_level_only = log_level_min == log_level_max;
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+       {
+               enum lttng_loglevel_python log_level_min, log_level_max;
+               if (!loglevel_python_parse_range_string(
+                                   str, &log_level_min, &log_level_max)) {
+                       goto error;
+               }
+
+               /* Only support VAL and VAL.. for now. */
+               if (log_level_min != log_level_max &&
+                               log_level_max !=
+                                               LTTNG_LOGLEVEL_PYTHON_CRITICAL) {
+                       goto error;
+               }
+
+               *log_level = (int) log_level_min;
+               *log_level_only = log_level_min == log_level_max;
+               break;
+       }
+       default:
+               /* Invalid domain type. */
+               abort();
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+static int parse_kernel_probe_opts(const char *source,
+               struct lttng_kernel_probe_location **location)
+{
+       int ret = 0;
+       int match;
+       char s_hex[19];
+       char name[LTTNG_SYMBOL_NAME_LEN];
+       char *symbol_name = NULL;
+       uint64_t offset;
+
+       /* Check for symbol+offset. */
+       match = sscanf(source,
+                       "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+                       "[^'+']+%18s",
+                       name, s_hex);
+       if (match == 2) {
+               if (*s_hex == '\0') {
+                       ERR("Kernel probe symbol offset is missing.");
+                       goto error;
+               }
+
+               symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
+               if (!symbol_name) {
+                       PERROR("Failed to copy kernel probe location symbol name.");
+                       goto error;
+               }
+               offset = strtoul(s_hex, NULL, 0);
+
+               *location = lttng_kernel_probe_location_symbol_create(
+                               symbol_name, offset);
+               if (!*location) {
+                       ERR("Failed to create symbol kernel probe location.");
+                       goto error;
+               }
+
+               goto end;
+       }
+
+       /* Check for symbol. */
+       if (isalpha(name[0]) || name[0] == '_') {
+               match = sscanf(source,
+                               "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+                               "s",
+                               name);
+               if (match == 1) {
+                       symbol_name = strndup(name, LTTNG_SYMBOL_NAME_LEN);
+                       if (!symbol_name) {
+                               ERR("Failed to copy kernel probe location symbol name.");
+                               goto error;
+                       }
+
+                       *location = lttng_kernel_probe_location_symbol_create(
+                                       symbol_name, 0);
+                       if (!*location) {
+                               ERR("Failed to create symbol kernel probe location.");
+                               goto error;
+                       }
+
+                       goto end;
+               }
+       }
+
+       /* Check for address. */
+       match = sscanf(source, "%18s", s_hex);
+       if (match > 0) {
+               uint64_t address;
+
+               if (*s_hex == '\0') {
+                       ERR("Invalid kernel probe location address.");
+                       goto error;
+               }
+
+               address = strtoul(s_hex, NULL, 0);
+               *location = lttng_kernel_probe_location_address_create(address);
+               if (!*location) {
+                       ERR("Failed to create symbol kernel probe location.");
+                       goto error;
+               }
+
+               goto end;
+       }
+
+error:
+       /* No match */
+       ret = -1;
+       *location = NULL;
+
+end:
+       free(symbol_name);
+       return ret;
+}
+
+static
+struct lttng_event_expr *ir_op_load_expr_to_event_expr(
+               const struct ir_load_expression *load_expr,
+               const char *capture_str)
+{
+       char *provider_name = NULL;
+       struct lttng_event_expr *event_expr = NULL;
+       const struct ir_load_expression_op *load_expr_op = load_expr->child;
+       const enum ir_load_expression_type load_expr_child_type =
+                       load_expr_op->type;
+
+       switch (load_expr_child_type) {
+       case IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT:
+       case IR_LOAD_EXPRESSION_GET_CONTEXT_ROOT:
+       {
+               const char *field_name;
+
+               load_expr_op = load_expr_op->next;
+               LTTNG_ASSERT(load_expr_op);
+               LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
+               field_name = load_expr_op->u.symbol;
+               LTTNG_ASSERT(field_name);
+
+               event_expr = load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
+                               lttng_event_expr_event_payload_field_create(field_name) :
+                               lttng_event_expr_channel_context_field_create(field_name);
+               if (!event_expr) {
+                       ERR("Failed to create %s event expression: field name = `%s`.",
+                                       load_expr_child_type == IR_LOAD_EXPRESSION_GET_PAYLOAD_ROOT ?
+                                                       "payload field" : "channel context",
+                                                       field_name);
+                       goto error;
+               }
+
+               break;
+       }
+       case IR_LOAD_EXPRESSION_GET_APP_CONTEXT_ROOT:
+       {
+               const char *colon;
+               const char *type_name;
+               const char *field_name;
+
+               load_expr_op = load_expr_op->next;
+               LTTNG_ASSERT(load_expr_op);
+               LTTNG_ASSERT(load_expr_op->type == IR_LOAD_EXPRESSION_GET_SYMBOL);
+               field_name = load_expr_op->u.symbol;
+               LTTNG_ASSERT(field_name);
+
+               /*
+                * The field name needs to be of the form PROVIDER:TYPE. We
+                * split it here.
+                */
+               colon = strchr(field_name, ':');
+               if (!colon) {
+                       ERR("Invalid app-specific context field name: missing colon in `%s`.",
+                                       field_name);
+                       goto error;
+               }
+
+               type_name = colon + 1;
+               if (*type_name == '\0') {
+                       ERR("Invalid app-specific context field name: missing type name after colon in `%s`.",
+                                       field_name);
+                       goto error;
+               }
+
+               provider_name = strndup(field_name, colon - field_name);
+               if (!provider_name) {
+                       PERROR("Failed to allocate field name string");
+                       goto error;
+               }
+
+               event_expr = lttng_event_expr_app_specific_context_field_create(
+                               provider_name, type_name);
+               if (!event_expr) {
+                       ERR("Failed to create app-specific context field event expression: provider name = `%s`, type name = `%s`",
+                                       provider_name, type_name);
+                       goto error;
+               }
+
+               break;
+       }
+       default:
+               ERR("%s: unexpected load expr type %d.", __func__,
+                               load_expr_op->type);
+               abort();
+       }
+
+       load_expr_op = load_expr_op->next;
+
+       /* There may be a single array index after that. */
+       if (load_expr_op->type == IR_LOAD_EXPRESSION_GET_INDEX) {
+               struct lttng_event_expr *index_event_expr;
+               const uint64_t index = load_expr_op->u.index;
+
+               index_event_expr = lttng_event_expr_array_field_element_create(event_expr, index);
+               if (!index_event_expr) {
+                       ERR("Failed to create array field element event expression.");
+                       goto error;
+               }
+
+               event_expr = index_event_expr;
+               load_expr_op = load_expr_op->next;
+       }
+
+       switch (load_expr_op->type) {
+       case IR_LOAD_EXPRESSION_LOAD_FIELD:
+               /*
+                * This is what we expect, IR_LOAD_EXPRESSION_LOAD_FIELD is
+                * always found at the end of the chain.
+                */
+               break;
+       case IR_LOAD_EXPRESSION_GET_SYMBOL:
+               ERR("While parsing expression `%s`: Capturing subfields is not supported.",
+                               capture_str);
+               goto error;
+
+       default:
+               ERR("%s: unexpected load expression operator %s.", __func__,
+                               ir_load_expression_type_str(load_expr_op->type));
+               abort();
+       }
+
+       goto end;
+
+error:
+       lttng_event_expr_destroy(event_expr);
+       event_expr = NULL;
+
+end:
+       free(provider_name);
+
+       return event_expr;
+}
+
+static
+struct lttng_event_expr *ir_op_load_to_event_expr(
+               const struct ir_op *ir, const char *capture_str)
+{
+       struct lttng_event_expr *event_expr = NULL;
+
+       LTTNG_ASSERT(ir->op == IR_OP_LOAD);
+
+       switch (ir->data_type) {
+       case IR_DATA_EXPRESSION:
+       {
+               const struct ir_load_expression *ir_load_expr =
+                               ir->u.load.u.expression;
+
+               event_expr = ir_op_load_expr_to_event_expr(
+                               ir_load_expr, capture_str);
+               break;
+       }
+       default:
+               ERR("%s: unexpected data type: %s.", __func__,
+                               ir_data_type_str(ir->data_type));
+               abort();
+       }
+
+       return event_expr;
+}
+
+static
+const char *ir_operator_type_human_str(enum ir_op_type op)
+{
+       const char *name;
+
+       switch (op) {
+       case IR_OP_BINARY:
+               name = "Binary";
+               break;
+       case IR_OP_UNARY:
+               name = "Unary";
+               break;
+       case IR_OP_LOGICAL:
+               name = "Logical";
+               break;
+       default:
+               abort();
+       }
+
+       return name;
+}
+
+static
+struct lttng_event_expr *ir_op_root_to_event_expr(const struct ir_op *ir,
+               const char *capture_str)
+{
+       struct lttng_event_expr *event_expr = NULL;
+
+       LTTNG_ASSERT(ir->op == IR_OP_ROOT);
+       ir = ir->u.root.child;
+
+       switch (ir->op) {
+       case IR_OP_LOAD:
+               event_expr = ir_op_load_to_event_expr(ir, capture_str);
+               break;
+       case IR_OP_BINARY:
+       case IR_OP_UNARY:
+       case IR_OP_LOGICAL:
+               ERR("While parsing expression `%s`: %s operators are not allowed in capture expressions.",
+                               capture_str,
+                               ir_operator_type_human_str(ir->op));
+               break;
+       default:
+               ERR("%s: unexpected IR op type: %s.", __func__,
+                               ir_op_type_str(ir->op));
+               abort();
+       }
+
+       return event_expr;
+}
+
+static
+void destroy_event_expr(void *ptr)
+{
+       lttng_event_expr_destroy((lttng_event_expr *) ptr);
+}
+
+struct parse_event_rule_res {
+       /* Owned by this. */
+       struct lttng_event_rule *er;
+
+       /* Array of `struct lttng_event_expr *` */
+       struct lttng_dynamic_pointer_array capture_descriptors;
+};
+
+static
+struct parse_event_rule_res parse_event_rule(int *argc, const char ***argv)
+{
+       enum lttng_event_rule_type event_rule_type =
+                       LTTNG_EVENT_RULE_TYPE_UNKNOWN;
+       struct argpar_state *state;
+       struct argpar_item *item = NULL;
+       char *error = NULL;
+       int consumed_args = -1;
+       struct lttng_kernel_probe_location *kernel_probe_location = NULL;
+       struct lttng_userspace_probe_location *userspace_probe_location = NULL;
+       struct parse_event_rule_res res = { 0 };
+       struct lttng_event_expr *event_expr = NULL;
+       struct filter_parser_ctx *parser_ctx = NULL;
+       struct lttng_log_level_rule *log_level_rule = NULL;
+
+       /* Event rule type option */
+       char *event_rule_type_str = NULL;
+
+       /* Tracepoint and syscall options. */
+       char *name = NULL;
+       /* Array of strings. */
+       struct lttng_dynamic_pointer_array exclude_names;
+
+       /* For userspace / kernel probe and function. */
+       char *location = NULL;
+       char *event_name = NULL;
+
+       /* Filter. */
+       char *filter = NULL;
+
+       /* Log level. */
+       char *log_level_str = NULL;
+
+       lttng_dynamic_pointer_array_init(&res.capture_descriptors,
+                               destroy_event_expr);
+
+       lttng_dynamic_pointer_array_init(&exclude_names, free);
+
+       state = argpar_state_create(*argc, *argv, event_rule_opt_descrs);
+       if (!state) {
+               ERR("Failed to allocate an argpar state.");
+               goto error;
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(item);
+               status = argpar_state_parse_next(state, &item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       /* Just stop parsing here. */
+                       break;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_TYPE:
+                               if (!assign_event_rule_type(&event_rule_type,
+                                               item_opt->arg)) {
+                                       goto error;
+                               }
+
+                               /* Save the string for later use. */
+                               if (!assign_string(&event_rule_type_str,
+                                                   item_opt->arg,
+                                                   "--type/-t")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_LOCATION:
+                               if (!assign_string(&location,
+                                               item_opt->arg,
+                                               "--location/-L")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_EVENT_NAME:
+                               if (!assign_string(&event_name,
+                                                   item_opt->arg,
+                                                   "--event-name/-E")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_FILTER:
+                               if (!assign_string(&filter, item_opt->arg,
+                                                   "--filter/-f")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_NAME:
+                               if (!assign_string(&name, item_opt->arg,
+                                                   "--name/-n")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_EXCLUDE_NAME:
+                       {
+                               int ret;
+
+                               ret = lttng_dynamic_pointer_array_add_pointer(
+                                               &exclude_names,
+                                               strdup(item_opt->arg));
+                               if (ret != 0) {
+                                       ERR("Failed to add pointer to dynamic pointer array.");
+                                       goto error;
+                               }
+
+                               break;
+                       }
+                       case OPT_LOG_LEVEL:
+                               if (!assign_string(&log_level_str,
+                                                   item_opt->arg, "--log-level/-l")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_CAPTURE:
+                       {
+                               int ret;
+                               const char *capture_str = item_opt->arg;
+
+                               ret = filter_parser_ctx_create_from_filter_expression(
+                                               capture_str, &parser_ctx);
+                               if (ret) {
+                                       ERR("Failed to parse capture expression `%s`.",
+                                                       capture_str);
+                                       goto error;
+                               }
+
+                               event_expr = ir_op_root_to_event_expr(
+                                               parser_ctx->ir_root,
+                                               capture_str);
+                               if (!event_expr) {
+                                       /*
+                                        * ir_op_root_to_event_expr has printed
+                                        * an error message.
+                                        */
+                                       goto error;
+                               }
+
+                               ret = lttng_dynamic_pointer_array_add_pointer(
+                                               &res.capture_descriptors,
+                                               event_expr);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               /*
+                                * The ownership of event expression was
+                                * transferred to the dynamic array.
+                                */
+                               event_expr = NULL;
+
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt =
+                                       (const struct argpar_item_non_opt *)
+                                                       item;
+
+                       /* Don't accept non-option arguments. */
+                       ERR("Unexpected argument '%s'", item_non_opt->arg);
+                       goto error;
+               }
+       }
+
+       if (event_rule_type == LTTNG_EVENT_RULE_TYPE_UNKNOWN) {
+               ERR("Event rule requires a --type.");
+               goto error;
+       }
+
+       /*
+        * Option --name is applicable to event rules of type kernel, user, jul,
+        * log4j,python and syscall.  If --name is omitted, it is implicitly
+        * "*".
+        */
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+               if (!name) {
+                       name = strdup("*");
+               }
+               break;
+
+       default:
+               if (name) {
+                       ERR("Can't use --name with %s event rules.",
+                                       lttng_event_rule_type_str(
+                                                       event_rule_type));
+                       goto error;
+               }
+
+               if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
+                       ERR("Can't use --exclude-name/-x with %s event rules.",
+                                       lttng_event_rule_type_str(
+                                                       event_rule_type));
+                       goto error;
+               }
+       }
+
+       /*
+        * Option --location is only applicable to (and mandatory for) event
+        * rules of type {k,u}probe and function.
+        *
+        * Option --event-name is only applicable to event rules of type probe.
+        * If omitted, it defaults to the location.
+        */
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+               if (!location) {
+                       ERR("Event rule of type %s requires a --location.",
+                       lttng_event_rule_type_str(event_rule_type));
+                       goto error;
+               }
+
+               if (!event_name) {
+                       event_name = strdup(location);
+               }
+
+               break;
+
+       default:
+               if (location) {
+                       ERR("Can't use --location with %s event rules.",
+                       lttng_event_rule_type_str(event_rule_type));
+                       goto error;
+               }
+
+               if (event_name) {
+                       ERR("Can't use --event-name with %s event rules.",
+                                       lttng_event_rule_type_str(
+                                                       event_rule_type));
+                       goto error;
+               }
+       }
+
+       /*
+        * Update *argc and *argv so our caller can keep parsing what follows.
+        */
+       consumed_args = argpar_state_get_ingested_orig_args(state);
+       LTTNG_ASSERT(consumed_args >= 0);
+       *argc -= consumed_args;
+       *argv += consumed_args;
+
+       /*
+        * Adding a filter to a probe, function or userspace-probe would be
+        * denied by the kernel tracer as it's not supported at the moment. We
+        * do an early check here to warn the user.
+        */
+       if (filter) {
+               switch (event_rule_type) {
+               case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+               case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+               case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+               case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+                       break;
+               default:
+                       ERR("Filter expressions are not supported for %s event rules.",
+                                       lttng_event_rule_type_str(event_rule_type));
+                       goto error;
+               }
+       }
+
+       /*
+        * If --exclude-name/-x was passed, split it into an exclusion list.
+        * Exclusions are only supported by
+        * LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT for now.
+        */
+       if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
+               if (event_rule_type != LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT) {
+                       ERR("Event name exclusions are not yet implemented for %s event rules.",
+                                       lttng_event_rule_type_str(event_rule_type));
+                       goto error;
+               }
+
+               if (validate_exclusion_list(name, &exclude_names) != 0) {
+                       /*
+                        * Assume validate_exclusion_list already prints an
+                        * error message.
+                        */
+                       goto error;
+               }
+       }
+
+       if (log_level_str) {
+               switch (event_rule_type) {
+               case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+               case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+               case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+               case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               {
+                       int log_level;
+                       bool log_level_only;
+
+                       if (strcmp(log_level_str, "..") == 0) {
+                               /*
+                                * ".." is the same as passing no log level
+                                * option and correspond to the "ANY" case.
+                                */
+                               break;
+                       }
+
+                       if (!parse_log_level_string(log_level_str, event_rule_type,
+                                           &log_level, &log_level_only)) {
+                               ERR("Failed to parse log level string `%s`.",
+                                               log_level_str);
+                               goto error;
+                       }
+
+                       if (log_level_only) {
+                               log_level_rule = lttng_log_level_rule_exactly_create(log_level);
+                       } else {
+                               log_level_rule = lttng_log_level_rule_at_least_as_severe_as_create(log_level);
+                       }
+
+                       if (log_level_rule == NULL) {
+                               ERR("Failed to create log level rule object.");
+                               goto error;
+                       }
+                       break;
+               }
+               default:
+                       ERR("Log levels are not supported for %s event rules.",
+                                       lttng_event_rule_type_str(event_rule_type));
+                       goto error;
+               }
+       }
+
+       /* Finally, create the event rule object. */
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+       {
+               enum lttng_event_rule_status event_rule_status;
+
+               res.er = lttng_event_rule_user_tracepoint_create();
+               if (!res.er) {
+                       ERR("Failed to create user_tracepoint event rule.");
+                       goto error;
+               }
+
+               /* Set pattern. */
+               event_rule_status = lttng_event_rule_user_tracepoint_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set user_tracepoint event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               /* Set filter. */
+               if (filter) {
+                       event_rule_status = lttng_event_rule_user_tracepoint_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set user_tracepoint event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+
+               /* Set exclusion list. */
+               if (lttng_dynamic_pointer_array_get_count(&exclude_names) > 0) {
+                       int n;
+                       int count = lttng_dynamic_pointer_array_get_count(
+                                       &exclude_names);
+
+                       for (n = 0; n < count; n++) {
+                               const char *exclude_name =
+                                               (const char *) lttng_dynamic_pointer_array_get_pointer(
+                                                               &exclude_names,
+                                                               n);
+
+                               event_rule_status =
+                                               lttng_event_rule_user_tracepoint_add_name_pattern_exclusion(
+                                                               res.er,
+                                                               exclude_name);
+                               if (event_rule_status !=
+                                               LTTNG_EVENT_RULE_STATUS_OK) {
+                                       ERR("Failed to set user_tracepoint exclusion list element '%s'",
+                                                       exclude_name);
+                                       goto error;
+                               }
+                       }
+               }
+
+               if (log_level_rule) {
+                       event_rule_status =
+                                       lttng_event_rule_user_tracepoint_set_log_level_rule(
+                                                       res.er, log_level_rule);
+
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set log level on event fule.");
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+       {
+               enum lttng_event_rule_status event_rule_status;
+
+               res.er = lttng_event_rule_kernel_tracepoint_create();
+               if (!res.er) {
+                       ERR("Failed to create kernel_tracepoint event rule.");
+                       goto error;
+               }
+
+               /* Set pattern. */
+               event_rule_status = lttng_event_rule_kernel_tracepoint_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set kernel_tracepoint event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               /* Set filter. */
+               if (filter) {
+                       event_rule_status = lttng_event_rule_kernel_tracepoint_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set kernel_tracepoint event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+       {
+               enum lttng_event_rule_status event_rule_status;
+
+               res.er = lttng_event_rule_jul_logging_create();
+               if (!res.er) {
+                       ERR("Failed to create jul_logging event rule.");
+                       goto error;
+               }
+
+               /* Set pattern. */
+               event_rule_status = lttng_event_rule_jul_logging_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               /* Set filter. */
+               if (filter) {
+                       event_rule_status = lttng_event_rule_jul_logging_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+
+               if (log_level_rule) {
+                       event_rule_status =
+                                       lttng_event_rule_jul_logging_set_log_level_rule(
+                                                       res.er, log_level_rule);
+
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set log level on event fule.");
+                               goto error;
+                       }
+               }
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+       {
+               enum lttng_event_rule_status event_rule_status;
+
+               res.er = lttng_event_rule_log4j_logging_create();
+               if (!res.er) {
+                       ERR("Failed to create jul_logging event rule.");
+                       goto error;
+               }
+
+               /* Set pattern. */
+               event_rule_status = lttng_event_rule_log4j_logging_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               /* Set filter. */
+               if (filter) {
+                       event_rule_status = lttng_event_rule_log4j_logging_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+
+               if (log_level_rule) {
+                       event_rule_status =
+                                       lttng_event_rule_log4j_logging_set_log_level_rule(
+                                                       res.er, log_level_rule);
+
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set log level on event fule.");
+                               goto error;
+                       }
+               }
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+       {
+               enum lttng_event_rule_status event_rule_status;
+
+               res.er = lttng_event_rule_python_logging_create();
+               if (!res.er) {
+                       ERR("Failed to create jul_logging event rule.");
+                       goto error;
+               }
+
+               /* Set pattern. */
+               event_rule_status = lttng_event_rule_python_logging_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set jul_logging event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               /* Set filter. */
+               if (filter) {
+                       event_rule_status = lttng_event_rule_python_logging_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set jul_logging event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+
+               if (log_level_rule) {
+                       event_rule_status =
+                                       lttng_event_rule_python_logging_set_log_level_rule(
+                                                       res.er, log_level_rule);
+
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set log level on event fule.");
+                               goto error;
+                       }
+               }
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+       {
+               int ret;
+               enum lttng_event_rule_status event_rule_status;
+
+               ret = parse_kernel_probe_opts(
+                               location, &kernel_probe_location);
+               if (ret) {
+                       ERR("Failed to parse kernel probe location.");
+                       goto error;
+               }
+
+               LTTNG_ASSERT(kernel_probe_location);
+               res.er = lttng_event_rule_kernel_kprobe_create(kernel_probe_location);
+               if (!res.er) {
+                       ERR("Failed to create kprobe event rule.");
+                       goto error;
+               }
+
+               event_rule_status =
+                               lttng_event_rule_kernel_kprobe_set_event_name(
+                                               res.er, event_name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set kprobe event rule's name to '%s'.",
+                                       event_name);
+                       goto error;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+       {
+               int ret;
+               enum lttng_event_rule_status event_rule_status;
+
+               ret = parse_userspace_probe_opts(
+                               location, &userspace_probe_location);
+               if (ret) {
+                       ERR("Failed to parse user space probe location.");
+                       goto error;
+               }
+
+               res.er = lttng_event_rule_kernel_uprobe_create(userspace_probe_location);
+               if (!res.er) {
+                       ERR("Failed to create userspace probe event rule.");
+                       goto error;
+               }
+
+               event_rule_status =
+                               lttng_event_rule_kernel_uprobe_set_event_name(
+                                               res.er, event_name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set user space probe event rule's name to '%s'.",
+                                       event_name);
+                       goto error;
+               }
+
+               break;
+       }
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+       {
+               enum lttng_event_rule_status event_rule_status;
+               enum lttng_event_rule_kernel_syscall_emission_site emission_site;
+
+               if (!parse_syscall_emission_site_from_type(
+                                   event_rule_type_str, &emission_site)) {
+                       ERR("Failed to parse syscall type '%s'.", event_rule_type_str);
+                       goto error;
+               }
+
+               res.er = lttng_event_rule_kernel_syscall_create(emission_site);
+               if (!res.er) {
+                       ERR("Failed to create syscall event rule.");
+                       goto error;
+               }
+
+               event_rule_status = lttng_event_rule_kernel_syscall_set_name_pattern(
+                               res.er, name);
+               if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                       ERR("Failed to set syscall event rule's pattern to '%s'.",
+                                       name);
+                       goto error;
+               }
+
+               if (filter) {
+                       event_rule_status = lttng_event_rule_kernel_syscall_set_filter(
+                                       res.er, filter);
+                       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+                               ERR("Failed to set syscall event rule's filter to '%s'.",
+                                               filter);
+                               goto error;
+                       }
+               }
+
+               break;
+       }
+       default:
+               abort();
+               goto error;
+       }
+
+       goto end;
+
+error:
+       lttng_event_rule_destroy(res.er);
+       res.er = NULL;
+       lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
+
+end:
+       if (parser_ctx) {
+               filter_parser_ctx_free(parser_ctx);
+       }
+
+       lttng_event_expr_destroy(event_expr);
+       argpar_item_destroy(item);
+       free(error);
+       argpar_state_destroy(state);
+       free(filter);
+       free(name);
+       lttng_dynamic_pointer_array_reset(&exclude_names);
+       free(log_level_str);
+       free(location);
+       free(event_name);
+       free(event_rule_type_str);
+
+       lttng_kernel_probe_location_destroy(kernel_probe_location);
+       lttng_userspace_probe_location_destroy(userspace_probe_location);
+       lttng_log_level_rule_destroy(log_level_rule);
+       return res;
+}
+
+static
+struct lttng_condition *handle_condition_event(int *argc, const char ***argv)
+{
+       struct parse_event_rule_res res;
+       struct lttng_condition *c;
+       size_t i;
+
+       res = parse_event_rule(argc, argv);
+       if (!res.er) {
+               c = NULL;
+               goto error;
+       }
+
+       c = lttng_condition_event_rule_matches_create(res.er);
+       lttng_event_rule_destroy(res.er);
+       res.er = NULL;
+       if (!c) {
+               goto error;
+       }
+
+       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&res.capture_descriptors);
+                       i++) {
+               enum lttng_condition_status status;
+               struct lttng_event_expr **expr =
+                               (lttng_event_expr **) lttng_dynamic_array_get_element(
+                                       &res.capture_descriptors.array, i);
+
+               LTTNG_ASSERT(expr);
+               LTTNG_ASSERT(*expr);
+               status = lttng_condition_event_rule_matches_append_capture_descriptor(
+                               c, *expr);
+               if (status != LTTNG_CONDITION_STATUS_OK) {
+                       if (status == LTTNG_CONDITION_STATUS_UNSUPPORTED) {
+                               ERR("The capture feature is unsupported by the event-rule condition type");
+                       }
+
+                       goto error;
+               }
+
+               /* Ownership of event expression moved to `c` */
+               *expr = NULL;
+       }
+
+       goto end;
+
+error:
+       lttng_condition_destroy(c);
+       c = NULL;
+
+end:
+       lttng_dynamic_pointer_array_reset(&res.capture_descriptors);
+       lttng_event_rule_destroy(res.er);
+       return c;
+}
+
+struct condition_descr {
+       const char *name;
+       struct lttng_condition *(*handler) (int *argc, const char ***argv);
+};
+
+static const
+struct condition_descr condition_descrs[] = {
+       { "event-rule-matches", handle_condition_event },
+};
+
+static
+struct lttng_condition *parse_condition(const char *condition_name, int *argc,
+               const char ***argv)
+{
+       int i;
+       struct lttng_condition *cond;
+       const struct condition_descr *descr = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(condition_descrs); i++) {
+               if (strcmp(condition_name, condition_descrs[i].name) == 0) {
+                       descr = &condition_descrs[i];
+                       break;
+               }
+       }
+
+       if (!descr) {
+               ERR("Unknown condition name '%s'", condition_name);
+               goto error;
+       }
+
+       cond = descr->handler(argc, argv);
+       if (!cond) {
+               /* The handler has already printed an error message. */
+               goto error;
+       }
+
+       goto end;
+error:
+       cond = NULL;
+end:
+       return cond;
+}
+
+static struct lttng_rate_policy *parse_rate_policy(const char *policy_str)
+{
+       int ret;
+       size_t num_token = 0;
+       struct lttng_dynamic_pointer_array tokens;
+       struct lttng_rate_policy *policy = NULL;
+       enum lttng_rate_policy_type policy_type;
+       unsigned long long value;
+       char *policy_type_str;
+       char *policy_value_str;
+
+       LTTNG_ASSERT(policy_str);
+       lttng_dynamic_pointer_array_init(&tokens, NULL);
+
+       /* Rate policy fields are separated by ':'. */
+       ret = strutils_split(policy_str, ':', 1, &tokens);
+       if (ret == 0) {
+               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
+       }
+
+       /*
+        * Early sanity check that the number of parameter is exactly 2.
+        * i.e : type:value
+        */
+       if (num_token != 2) {
+               ERR("Rate policy format is invalid.");
+               goto end;
+       }
+
+       policy_type_str = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
+       policy_value_str = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+
+       /* Parse the type. */
+       if (strcmp(policy_type_str, "once-after") == 0) {
+               policy_type = LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N;
+       } else if (strcmp(policy_type_str, "every") == 0) {
+               policy_type = LTTNG_RATE_POLICY_TYPE_EVERY_N;
+       } else {
+               ERR("Rate policy type `%s` unknown.", policy_type_str);
+               goto end;
+       }
+
+       /* Parse the value. */
+       if (utils_parse_unsigned_long_long(policy_value_str, &value) != 0) {
+               ERR("Failed to parse rate policy value `%s` as an integer.",
+                               policy_value_str);
+               goto end;
+       }
+
+       if (value == 0) {
+               ERR("Rate policy value `%s` must be > 0.", policy_value_str);
+               goto end;
+       }
+
+       switch (policy_type) {
+       case LTTNG_RATE_POLICY_TYPE_EVERY_N:
+               policy = lttng_rate_policy_every_n_create(value);
+               break;
+       case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
+               policy = lttng_rate_policy_once_after_n_create(value);
+               break;
+       default:
+               abort();
+       }
+
+       if (policy == NULL) {
+               ERR("Failed to create rate policy `%s`.", policy_str);
+       }
+
+end:
+       lttng_dynamic_pointer_array_reset(&tokens);
+       return policy;
+}
+
+static const struct argpar_opt_descr notify_action_opt_descrs[] = {
+       { OPT_RATE_POLICY, '\0', "rate-policy", true },
+       ARGPAR_OPT_DESCR_SENTINEL
+};
+
+static
+struct lttng_action *handle_action_notify(int *argc, const char ***argv)
+{
+       struct lttng_action *action = NULL;
+       struct argpar_state *state = NULL;
+       struct argpar_item *item = NULL;
+       char *error = NULL;
+       struct lttng_rate_policy *policy = NULL;
+
+       state = argpar_state_create(*argc, *argv, notify_action_opt_descrs);
+       if (!state) {
+               ERR("Failed to allocate an argpar state.");
+               goto error;
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(item);
+               status = argpar_state_parse_next(state, &item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       /* Just stop parsing here. */
+                       break;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_RATE_POLICY:
+                       {
+                               policy = parse_rate_policy(item_opt->arg);
+                               if (!policy) {
+                                       goto error;
+                               }
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt;
+
+                       LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
+
+                       item_non_opt = (const struct argpar_item_non_opt *) item;
+
+                       switch (item_non_opt->non_opt_index) {
+                       default:
+                               ERR("Unexpected argument `%s`.",
+                                               item_non_opt->arg);
+                               goto error;
+                       }
+               }
+       }
+
+       *argc -= argpar_state_get_ingested_orig_args(state);
+       *argv += argpar_state_get_ingested_orig_args(state);
+
+       action = lttng_action_notify_create();
+       if (!action) {
+               ERR("Failed to create notify action");
+               goto error;
+       }
+
+       if (policy) {
+               enum lttng_action_status status;
+               status = lttng_action_notify_set_rate_policy(action, policy);
+               if (status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to set rate policy");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_action_destroy(action);
+       action = NULL;
+end:
+       free(error);
+       lttng_rate_policy_destroy(policy);
+       argpar_state_destroy(state);
+       argpar_item_destroy(item);
+       return action;
+}
+
+/*
+ * Generic handler for a kind of action that takes a session name and an
+ * optional rate policy.
+ */
+
+static struct lttng_action *handle_action_simple_session_with_policy(int *argc,
+               const char ***argv,
+               struct lttng_action *(*create_action_cb)(void),
+               enum lttng_action_status (*set_session_name_cb)(
+                               struct lttng_action *, const char *),
+               enum lttng_action_status (*set_rate_policy_cb)(
+                               struct lttng_action *,
+                               const struct lttng_rate_policy *),
+               const char *action_name)
+{
+       struct lttng_action *action = NULL;
+       struct argpar_state *state = NULL;
+       struct argpar_item *item = NULL;
+       const char *session_name_arg = NULL;
+       char *error = NULL;
+       enum lttng_action_status action_status;
+       struct lttng_rate_policy *policy = NULL;
+
+       LTTNG_ASSERT(set_session_name_cb);
+       LTTNG_ASSERT(set_rate_policy_cb);
+
+       const struct argpar_opt_descr rate_policy_opt_descrs[] = {
+               { OPT_RATE_POLICY, '\0', "rate-policy", true },
+               ARGPAR_OPT_DESCR_SENTINEL
+       };
+
+       state = argpar_state_create(*argc, *argv, rate_policy_opt_descrs);
+       if (!state) {
+               ERR("Failed to allocate an argpar state.");
+               goto error;
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(item);
+               status = argpar_state_parse_next(state, &item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status ==
+                               ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       /* Just stop parsing here. */
+                       break;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_RATE_POLICY:
+                       {
+                               policy = parse_rate_policy(item_opt->arg);
+                               if (!policy) {
+                                       goto error;
+                               }
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt;
+                       item_non_opt = (const struct argpar_item_non_opt *) item;
+
+                       switch (item_non_opt->non_opt_index) {
+                       case 0:
+                               session_name_arg = item_non_opt->arg;
+                               break;
+                       default:
+                               ERR("Unexpected argument `%s`.",
+                                               item_non_opt->arg);
+                               goto error;
+                       }
+               }
+       }
+
+       *argc -= argpar_state_get_ingested_orig_args(state);
+       *argv += argpar_state_get_ingested_orig_args(state);
+
+       if (!session_name_arg) {
+               ERR("Missing session name.");
+               goto error;
+       }
+
+       action = create_action_cb();
+       if (!action) {
+               ERR("Failed to allocate %s session action.", action_name);
+               goto error;
+       }
+
+       action_status = set_session_name_cb(action, session_name_arg);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to set action %s session's session name to '%s'.",
+                               action_name, session_name_arg);
+               goto error;
+       }
+
+       if (policy) {
+               action_status = set_rate_policy_cb(action, policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to set rate policy");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_action_destroy(action);
+       action = NULL;
+       argpar_item_destroy(item);
+end:
+       lttng_rate_policy_destroy(policy);
+       free(error);
+       argpar_state_destroy(state);
+       return action;
+}
+
+static
+struct lttng_action *handle_action_start_session(int *argc,
+               const char ***argv)
+{
+       return handle_action_simple_session_with_policy(argc, argv,
+                       lttng_action_start_session_create,
+                       lttng_action_start_session_set_session_name,
+                       lttng_action_start_session_set_rate_policy, "start");
+}
+
+static
+struct lttng_action *handle_action_stop_session(int *argc,
+               const char ***argv)
+{
+       return handle_action_simple_session_with_policy(argc, argv,
+                       lttng_action_stop_session_create,
+                       lttng_action_stop_session_set_session_name,
+                       lttng_action_stop_session_set_rate_policy, "stop");
+}
+
+static
+struct lttng_action *handle_action_rotate_session(int *argc,
+               const char ***argv)
+{
+       return handle_action_simple_session_with_policy(argc, argv,
+               lttng_action_rotate_session_create,
+               lttng_action_rotate_session_set_session_name,
+               lttng_action_rotate_session_set_rate_policy,
+               "rotate");
+}
+
+static const struct argpar_opt_descr snapshot_action_opt_descrs[] = {
+       { OPT_NAME, 'n', "name", true },
+       { OPT_MAX_SIZE, 'm', "max-size", true },
+       { OPT_CTRL_URL, '\0', "ctrl-url", true },
+       { OPT_DATA_URL, '\0', "data-url", true },
+       { OPT_URL, '\0', "url", true },
+       { OPT_PATH, '\0', "path", true },
+       { OPT_RATE_POLICY, '\0', "rate-policy", true },
+       ARGPAR_OPT_DESCR_SENTINEL
+};
+
+static
+struct lttng_action *handle_action_snapshot_session(int *argc,
+               const char ***argv)
+{
+       struct lttng_action *action = NULL;
+       struct argpar_state *state = NULL;
+       struct argpar_item *item = NULL;
+       const char *session_name_arg = NULL;
+       char *snapshot_name_arg = NULL;
+       char *ctrl_url_arg = NULL;
+       char *data_url_arg = NULL;
+       char *max_size_arg = NULL;
+       char *url_arg = NULL;
+       char *path_arg = NULL;
+       char *error = NULL;
+       enum lttng_action_status action_status;
+       struct lttng_snapshot_output *snapshot_output = NULL;
+       struct lttng_rate_policy *policy = NULL;
+       int ret;
+       unsigned int locations_specified = 0;
+
+       state = argpar_state_create(*argc, *argv, snapshot_action_opt_descrs);
+       if (!state) {
+               ERR("Failed to allocate an argpar state.");
+               goto error;
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(item);
+               status = argpar_state_parse_next(state, &item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       /* Just stop parsing here. */
+                       break;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_NAME:
+                               if (!assign_string(&snapshot_name_arg, item_opt->arg, "--name/-n")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_MAX_SIZE:
+                               if (!assign_string(&max_size_arg, item_opt->arg, "--max-size/-m")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_CTRL_URL:
+                               if (!assign_string(&ctrl_url_arg, item_opt->arg, "--ctrl-url")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_DATA_URL:
+                               if (!assign_string(&data_url_arg, item_opt->arg, "--data-url")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_URL:
+                               if (!assign_string(&url_arg, item_opt->arg, "--url")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_PATH:
+                               if (!assign_string(&path_arg, item_opt->arg, "--path")) {
+                                       goto error;
+                               }
+
+                               break;
+                       case OPT_RATE_POLICY:
+                       {
+                               policy = parse_rate_policy(item_opt->arg);
+                               if (!policy) {
+                                       goto error;
+                               }
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt;
+
+                       LTTNG_ASSERT(item->type == ARGPAR_ITEM_TYPE_NON_OPT);
+
+                       item_non_opt = (const struct argpar_item_non_opt *) item;
+
+                       switch (item_non_opt->non_opt_index) {
+                       case 0:
+                               session_name_arg = item_non_opt->arg;
+                               break;
+                       default:
+                               ERR("Unexpected argument `%s`.",
+                                               item_non_opt->arg);
+                               goto error;
+                       }
+               }
+       }
+
+       *argc -= argpar_state_get_ingested_orig_args(state);
+       *argv += argpar_state_get_ingested_orig_args(state);
+
+       if (!session_name_arg) {
+               ERR("Missing session name.");
+               goto error;
+       }
+
+       /* --ctrl-url and --data-url must come in pair. */
+       if (ctrl_url_arg && !data_url_arg) {
+               ERR("--ctrl-url is specified, but --data-url is missing.");
+               goto error;
+       }
+
+       if (!ctrl_url_arg && data_url_arg) {
+               ERR("--data-url is specified, but --ctrl-url is missing.");
+               goto error;
+       }
+
+       locations_specified += !!(ctrl_url_arg || data_url_arg);
+       locations_specified += !!url_arg;
+       locations_specified += !!path_arg;
+
+       /* --ctrl-url/--data-url, --url and --path are mutually exclusive. */
+       if (locations_specified > 1) {
+               ERR("The --ctrl-url/--data-url, --url, and --path options can't be used together.");
+               goto error;
+       }
+
+       /*
+        * Did the user specify an option that implies using a
+        * custom/unregistered output?
+        */
+       if (url_arg || ctrl_url_arg || path_arg) {
+               snapshot_output = lttng_snapshot_output_create();
+               if (!snapshot_output) {
+                       ERR("Failed to allocate a snapshot output.");
+                       goto error;
+               }
+       }
+
+       action = lttng_action_snapshot_session_create();
+       if (!action) {
+               ERR("Failed to allocate snapshot session action.");
+               goto error;
+       }
+
+       action_status = lttng_action_snapshot_session_set_session_name(
+                       action, session_name_arg);
+       if (action_status != LTTNG_ACTION_STATUS_OK) {
+               ERR("Failed to set action snapshot session's session name to '%s'.",
+                               session_name_arg);
+               goto error;
+       }
+
+       if (snapshot_name_arg) {
+               if (!snapshot_output) {
+                       ERR("Can't provide a snapshot output name without a snapshot output destination.");
+                       goto error;
+               }
+
+               ret = lttng_snapshot_output_set_name(
+                               snapshot_name_arg, snapshot_output);
+               if (ret != 0) {
+                       ERR("Failed to set name of snapshot output.");
+                       goto error;
+               }
+       }
+
+       if (max_size_arg) {
+               uint64_t max_size;
+
+               if (!snapshot_output) {
+                       ERR("Can't provide a snapshot output max size without a snapshot output destination.");
+                       goto error;
+               }
+
+               ret = utils_parse_size_suffix(max_size_arg, &max_size);
+               if (ret != 0) {
+                       ERR("Failed to parse `%s` as a size.", max_size_arg);
+                       goto error;
+               }
+
+               ret = lttng_snapshot_output_set_size(max_size, snapshot_output);
+               if (ret != 0) {
+                       ERR("Failed to set snapshot output's max size to %" PRIu64 " bytes.",
+                                       max_size);
+                       goto error;
+               }
+       }
+
+       if (url_arg) {
+               int num_uris;
+               struct lttng_uri *uris;
+
+               if (!strstr(url_arg, "://")) {
+                       ERR("Failed to parse '%s' as an URL.", url_arg);
+                       goto error;
+               }
+
+               num_uris = uri_parse_str_urls(url_arg, NULL, &uris);
+               if (num_uris < 1) {
+                       ERR("Failed to parse '%s' as an URL.", url_arg);
+                       goto error;
+               }
+
+               if (uris[0].dtype == LTTNG_DST_PATH) {
+                       ret = lttng_snapshot_output_set_local_path(
+                                       uris[0].dst.path, snapshot_output);
+                       free(uris);
+                       if (ret != 0) {
+                               ERR("Failed to assign '%s' as a local destination.",
+                                               url_arg);
+                               goto error;
+                       }
+               } else {
+                       ret = lttng_snapshot_output_set_network_url(
+                                       url_arg, snapshot_output);
+                       free(uris);
+                       if (ret != 0) {
+                               ERR("Failed to assign '%s' as a network URL.",
+                                               url_arg);
+                               goto error;
+                       }
+               }
+       }
+
+       if (path_arg) {
+               ret = lttng_snapshot_output_set_local_path(
+                               path_arg, snapshot_output);
+               if (ret != 0) {
+                       ERR("Failed to parse '%s' as a local path.", path_arg);
+                       goto error;
+               }
+       }
+
+       if (ctrl_url_arg) {
+               /*
+                * Two argument form, network output with separate control and
+                * data URLs.
+                */
+               ret = lttng_snapshot_output_set_network_urls(
+                               ctrl_url_arg, data_url_arg, snapshot_output);
+               if (ret != 0) {
+                       ERR("Failed to parse `%s` and `%s` as control and data URLs.",
+                                       ctrl_url_arg, data_url_arg);
+                       goto error;
+               }
+       }
+
+       if (snapshot_output) {
+               action_status = lttng_action_snapshot_session_set_output(
+                               action, snapshot_output);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to set snapshot session action's output.");
+                       goto error;
+               }
+
+               /* Ownership of `snapshot_output` has been transferred to the action. */
+               snapshot_output = NULL;
+       }
+
+       if (policy) {
+               enum lttng_action_status status;
+               status = lttng_action_snapshot_session_set_rate_policy(
+                               action, policy);
+               if (status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to set rate policy");
+                       goto error;
+               }
+       }
+
+       goto end;
+
+error:
+       lttng_action_destroy(action);
+       action = NULL;
+       free(error);
+end:
+       free(snapshot_name_arg);
+       free(path_arg);
+       free(url_arg);
+       free(ctrl_url_arg);
+       free(data_url_arg);
+       free(snapshot_output);
+       free(max_size_arg);
+       lttng_rate_policy_destroy(policy);
+       argpar_state_destroy(state);
+       argpar_item_destroy(item);
+       return action;
+}
+
+struct action_descr {
+       const char *name;
+       struct lttng_action *(*handler) (int *argc, const char ***argv);
+};
+
+static const
+struct action_descr action_descrs[] = {
+       { "notify", handle_action_notify },
+       { "start-session", handle_action_start_session },
+       { "stop-session", handle_action_stop_session },
+       { "rotate-session", handle_action_rotate_session },
+       { "snapshot-session", handle_action_snapshot_session },
+};
+
+static
+struct lttng_action *parse_action(const char *action_name, int *argc, const char ***argv)
+{
+       int i;
+       struct lttng_action *action;
+       const struct action_descr *descr = NULL;
+
+       for (i = 0; i < ARRAY_SIZE(action_descrs); i++) {
+               if (strcmp(action_name, action_descrs[i].name) == 0) {
+                       descr = &action_descrs[i];
+                       break;
+               }
+       }
+
+       if (!descr) {
+               ERR("Unknown action name: %s", action_name);
+               goto error;
+       }
+
+       action = descr->handler(argc, argv);
+       if (!action) {
+               /* The handler has already printed an error message. */
+               goto error;
+       }
+
+       goto end;
+error:
+       action = NULL;
+end:
+       return action;
+}
+
+static const
+struct argpar_opt_descr add_trigger_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_LIST_OPTIONS, '\0', "list-options", false },
+       { OPT_CONDITION, '\0', "condition", true },
+       { OPT_ACTION, '\0', "action", true },
+       { OPT_NAME, '\0', "name", true },
+       { OPT_OWNER_UID, '\0', "owner-uid", true },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+void lttng_actions_destructor(void *p)
+{
+       struct lttng_action *action = (lttng_action *) p;
+
+       lttng_action_destroy(action);
+}
+
+int cmd_add_trigger(int argc, const char **argv)
+{
+       int ret;
+       int my_argc = argc - 1;
+       const char **my_argv = argv + 1;
+       struct lttng_condition *condition = NULL;
+       struct lttng_dynamic_pointer_array actions;
+       struct argpar_state *argpar_state = NULL;
+       struct argpar_item *argpar_item = NULL;
+       struct lttng_action *action_list = NULL;
+       struct lttng_action *action = NULL;
+       struct lttng_trigger *trigger = NULL;
+       char *error = NULL;
+       char *name = NULL;
+       int i;
+       char *owner_uid = NULL;
+       enum lttng_error_code ret_code;
+       struct mi_writer *mi_writer = NULL;
+
+       lttng_dynamic_pointer_array_init(&actions, lttng_actions_destructor);
+
+       if (lttng_opt_mi) {
+               mi_writer = mi_lttng_writer_create(
+                               fileno(stdout), lttng_opt_mi);
+               if (!mi_writer) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               /* Open command element. */
+               ret = mi_lttng_writer_command_open(mi_writer,
+                               mi_lttng_element_command_add_trigger);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               /* Open output element. */
+               ret = mi_lttng_writer_open_element(
+                               mi_writer, mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       while (true) {
+               enum argpar_state_parse_next_status status;
+               const struct argpar_item_opt *item_opt;
+               int ingested_args;
+
+               argpar_state_destroy(argpar_state);
+               argpar_state = argpar_state_create(my_argc, my_argv,
+                       add_trigger_options);
+               if (!argpar_state) {
+                       ERR("Failed to create argpar state.");
+                       goto error;
+               }
+
+               ARGPAR_ITEM_DESTROY_AND_RESET(argpar_item);
+               status = argpar_state_parse_next(argpar_state, &argpar_item, &error);
+               if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_ERROR_UNKNOWN_OPT) {
+                       ERR("%s", error);
+                       goto error;
+               } else if (status == ARGPAR_STATE_PARSE_NEXT_STATUS_END) {
+                       break;
+               }
+
+               LTTNG_ASSERT(status == ARGPAR_STATE_PARSE_NEXT_STATUS_OK);
+
+               if (argpar_item->type == ARGPAR_ITEM_TYPE_NON_OPT) {
+                       const struct argpar_item_non_opt *item_non_opt =
+                                       (const struct argpar_item_non_opt *)
+                                                       argpar_item;
+
+                       ERR("Unexpected argument `%s`.", item_non_opt->arg);
+                       goto error;
+               }
+
+               item_opt = (const struct argpar_item_opt *) argpar_item;
+
+               ingested_args = argpar_state_get_ingested_orig_args(
+                               argpar_state);
+
+               my_argc -= ingested_args;
+               my_argv += ingested_args;
+
+               switch (item_opt->descr->id) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       ret = 0;
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options_argpar(stdout, add_trigger_options);
+                       ret = 0;
+                       goto end;
+               case OPT_CONDITION:
+               {
+                       if (condition) {
+                               ERR("A --condition was already given.");
+                               goto error;
+                       }
+
+                       condition = parse_condition(item_opt->arg, &my_argc, &my_argv);
+                       if (!condition) {
+                               /*
+                                * An error message was already printed by
+                                * parse_condition.
+                                */
+                               goto error;
+                       }
+
+                       break;
+               }
+               case OPT_ACTION:
+               {
+                       action = parse_action(item_opt->arg, &my_argc, &my_argv);
+                       if (!action) {
+                               /*
+                                * An error message was already printed by
+                                * parse_condition.
+                                */
+                               goto error;
+                       }
+
+                       ret = lttng_dynamic_pointer_array_add_pointer(
+                                       &actions, action);
+                       if (ret) {
+                               ERR("Failed to add pointer to pointer array.");
+                               goto error;
+                       }
+
+                       /* Ownership of the action was transferred to the list. */
+                       action = NULL;
+
+                       break;
+               }
+               case OPT_NAME:
+               {
+                       if (!assign_string(&name, item_opt->arg, "--name")) {
+                               goto error;
+                       }
+
+                       break;
+               }
+               case OPT_OWNER_UID:
+               {
+                       if (!assign_string(&owner_uid, item_opt->arg,
+                                       "--owner-uid")) {
+                               goto error;
+                       }
+
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       if (!condition) {
+               ERR("Missing --condition.");
+               goto error;
+       }
+
+       if (lttng_dynamic_pointer_array_get_count(&actions) == 0) {
+               ERR("Need at least one --action.");
+               goto error;
+       }
+
+       action_list = lttng_action_list_create();
+       if (!action_list) {
+               goto error;
+       }
+
+       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&actions); i++) {
+               enum lttng_action_status status;
+
+               action = (lttng_action *) lttng_dynamic_pointer_array_steal_pointer(&actions, i);
+
+               status = lttng_action_list_add_action(action_list, action);
+               if (status != LTTNG_ACTION_STATUS_OK) {
+                       goto error;
+               }
+
+               /*
+                * The `lttng_action_list_add_action()` takes a reference to
+                * the action. We can destroy ours.
+                */
+               lttng_action_destroy(action);
+               action = NULL;
+       }
+
+       trigger = lttng_trigger_create(condition, action_list);
+       if (!trigger) {
+               goto error;
+       }
+
+       if (owner_uid) {
+               enum lttng_trigger_status trigger_status;
+               char *end;
+               long long uid;
+
+               errno = 0;
+               uid = strtol(owner_uid, &end, 10);
+               if (end == owner_uid || *end != '\0' || errno != 0) {
+                       ERR("Failed to parse `%s` as a user id.", owner_uid);
+                       goto error;
+               }
+
+               trigger_status = lttng_trigger_set_owner_uid(trigger, uid);
+               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+                       ERR("Failed to set trigger's user identity.");
+                       goto error;
+               }
+       }
+
+       if (name) {
+               ret_code = lttng_register_trigger_with_name(trigger, name);
+       } else {
+               ret_code = lttng_register_trigger_with_automatic_name(trigger);
+       }
+
+       if (ret_code != LTTNG_OK) {
+               ERR("Failed to register trigger: %s.",
+                               lttng_strerror(-ret_code));
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               ret_code = lttng_trigger_mi_serialize(trigger, mi_writer, NULL);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+       } else {
+               const char *returned_trigger_name;
+               const enum lttng_trigger_status trigger_status =
+                               lttng_trigger_get_name(trigger,
+                                               &returned_trigger_name);
+
+               if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+                       WARN("Failed to retrieve the added trigger's name.");
+               } else {
+                       MSG("Added trigger `%s`.", returned_trigger_name);
+               }
+       }
+
+       ret = 0;
+
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       /* Mi closing. */
+       if (lttng_opt_mi && mi_writer) {
+               int mi_ret;
+
+               /* Close output element. */
+               mi_ret = mi_lttng_writer_close_element(mi_writer);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+
+               mi_ret = mi_lttng_writer_write_element_bool(mi_writer,
+                               mi_lttng_element_command_success, ret ? 0 : 1);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+
+               /* Command element close. */
+               mi_ret = mi_lttng_writer_command_close(mi_writer);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+       }
+
+cleanup:
+       argpar_state_destroy(argpar_state);
+       argpar_item_destroy(argpar_item);
+       lttng_dynamic_pointer_array_reset(&actions);
+       lttng_condition_destroy(condition);
+       lttng_action_destroy(action_list);
+       lttng_action_destroy(action);
+       lttng_trigger_destroy(trigger);
+       free(error);
+       free(name);
+       free(owner_uid);
+       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
+               /* Preserve original error code. */
+               ret = ret ? ret : CMD_ERROR;
+       }
+
+       return ret;
+}
diff --git a/src/bin/lttng/commands/clear.c b/src/bin/lttng/commands/clear.c
deleted file mode 100644 (file)
index 61879d6..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-/*
- * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-#include <common/mi-lttng.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/utils.h>
-
-static int opt_clear_all;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-clear.1.h>
-;
-#endif
-
-/* Mi writer */
-static struct mi_writer *writer;
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"all",       'a', POPT_ARG_VAL, &opt_clear_all, 1, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * clear session
- */
-static int clear_session(struct lttng_session *session)
-{
-       enum lttng_clear_handle_status status =
-                       LTTNG_CLEAR_HANDLE_STATUS_OK;
-       struct lttng_clear_handle *handle = NULL;
-       enum lttng_error_code ret_code;
-       bool printed_wait_msg = false;
-       char *session_name = NULL;
-       int ret;
-
-       ret = lttng_clear_session(session->name, &handle);
-       if (ret < 0) {
-               ERR("%s", lttng_strerror(ret));
-               goto error;
-       }
-
-       do {
-               status = lttng_clear_handle_wait_for_completion(handle,
-                               DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US / USEC_PER_MSEC);
-               switch (status) {
-               case LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT:
-                       if (!printed_wait_msg) {
-                               _MSG("Waiting for clear of session \"%s\"",
-                                               session->name);
-                               printed_wait_msg = true;
-                       }
-                       _MSG(".");
-                       fflush(stdout);
-                       break;
-               case LTTNG_CLEAR_HANDLE_STATUS_COMPLETED:
-                       break;
-               default:
-                       ERR("Failed to wait for the completion of clear for session \"%s\"",
-                                       session->name);
-                       ret = -1;
-                       goto error;
-               }
-       } while (status == LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT);
-
-       status = lttng_clear_handle_get_result(handle, &ret_code);
-       if (status != LTTNG_CLEAR_HANDLE_STATUS_OK) {
-               ERR("Failed to get the result of session clear");
-               ret = -1;
-               goto error;
-       }
-       if (ret_code != LTTNG_OK) {
-               ret = -ret_code;
-               goto error;
-       }
-
-       MSG("%sSession \"%s\" cleared", printed_wait_msg ? "\n" : "",
-                       session->name);
-       printed_wait_msg = false;
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_session(writer, session, 0);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       ret = CMD_SUCCESS;
-error:
-       if (printed_wait_msg) {
-               MSG("");
-       }
-       lttng_clear_handle_destroy(handle);
-       free(session_name);
-       return ret;
-}
-
-/*
- * clear all sessions
- *
- * Call clear_session for each registered sessions
- */
-static int clear_all_sessions(struct lttng_session *sessions, int count)
-{
-       int i, ret = CMD_SUCCESS;
-
-       if (count == 0) {
-               MSG("No session found, nothing to do.");
-       } else if (count < 0) {
-               ERR("%s", lttng_strerror(ret));
-               goto error;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = clear_session(&sessions[i]);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-error:
-       return ret;
-}
-
-/*
- * The 'clear <options>' first level command
- */
-int cmd_clear(int argc, const char **argv)
-{
-       int opt;
-       int ret = CMD_SUCCESS , i, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-       bool free_session_name = false;
-       struct lttng_session *sessions = NULL;
-       int count;
-       int found;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       break;
-               default:
-                       ret = CMD_UNDEFINED;
-                       break;
-               }
-               goto end;
-       }
-
-       /* Mi preparation */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_clear);
-               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;
-               }
-
-               /* For validation and semantic purpose we open a sessions element */
-               ret = mi_lttng_sessions_open(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       if (!opt_clear_all) {
-               session_name = (char *) poptGetArg(pc);
-               if (!session_name) {
-                       /* No session name specified, lookup default */
-                       session_name = get_session_name();
-                       if (session_name == NULL) {
-                               command_ret = CMD_ERROR;
-                               success = 0;
-                               goto mi_closing;
-                       }
-                       free_session_name = true;
-               }
-       } else {
-               session_name = NULL;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-       /* Recuperate all sessions for further operation */
-       count = lttng_list_sessions(&sessions);
-       if (count < 0) {
-               ERR("%s", lttng_strerror(count));
-               command_ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-       /* Ignore session name in case all sessions are to be cleaned */
-       if (opt_clear_all) {
-               command_ret = clear_all_sessions(sessions, count);
-               if (command_ret) {
-                       ERR("%s", lttng_strerror(command_ret));
-                       success = 0;
-               }
-       } else {
-               /* Find the corresponding lttng_session struct */
-               found = 0;
-               for (i = 0; i < count; i++) {
-                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
-                               found = 1;
-                               command_ret = clear_session(&sessions[i]);
-                               if (command_ret) {
-                                       ERR("%s", lttng_strerror(command_ret));
-                                       success = 0;
-                               }
-                       }
-               }
-
-               if (!found) {
-                       ERR("Session name %s not found", session_name);
-                       command_ret = LTTNG_ERR_SESS_NOT_FOUND;
-                       success = 0;
-                       goto mi_closing;
-               }
-       }
-
-mi_closing:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close sessions and output element element */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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(sessions);
-       if (free_session_name) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred during clear_session/all */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/clear.cpp b/src/bin/lttng/commands/clear.cpp
new file mode 100644 (file)
index 0000000..61879d6
--- /dev/null
@@ -0,0 +1,319 @@
+/*
+ * Copyright (C) 2019 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+#include <common/mi-lttng.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/utils.h>
+
+static int opt_clear_all;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-clear.1.h>
+;
+#endif
+
+/* Mi writer */
+static struct mi_writer *writer;
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"all",       'a', POPT_ARG_VAL, &opt_clear_all, 1, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * clear session
+ */
+static int clear_session(struct lttng_session *session)
+{
+       enum lttng_clear_handle_status status =
+                       LTTNG_CLEAR_HANDLE_STATUS_OK;
+       struct lttng_clear_handle *handle = NULL;
+       enum lttng_error_code ret_code;
+       bool printed_wait_msg = false;
+       char *session_name = NULL;
+       int ret;
+
+       ret = lttng_clear_session(session->name, &handle);
+       if (ret < 0) {
+               ERR("%s", lttng_strerror(ret));
+               goto error;
+       }
+
+       do {
+               status = lttng_clear_handle_wait_for_completion(handle,
+                               DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US / USEC_PER_MSEC);
+               switch (status) {
+               case LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT:
+                       if (!printed_wait_msg) {
+                               _MSG("Waiting for clear of session \"%s\"",
+                                               session->name);
+                               printed_wait_msg = true;
+                       }
+                       _MSG(".");
+                       fflush(stdout);
+                       break;
+               case LTTNG_CLEAR_HANDLE_STATUS_COMPLETED:
+                       break;
+               default:
+                       ERR("Failed to wait for the completion of clear for session \"%s\"",
+                                       session->name);
+                       ret = -1;
+                       goto error;
+               }
+       } while (status == LTTNG_CLEAR_HANDLE_STATUS_TIMEOUT);
+
+       status = lttng_clear_handle_get_result(handle, &ret_code);
+       if (status != LTTNG_CLEAR_HANDLE_STATUS_OK) {
+               ERR("Failed to get the result of session clear");
+               ret = -1;
+               goto error;
+       }
+       if (ret_code != LTTNG_OK) {
+               ret = -ret_code;
+               goto error;
+       }
+
+       MSG("%sSession \"%s\" cleared", printed_wait_msg ? "\n" : "",
+                       session->name);
+       printed_wait_msg = false;
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_session(writer, session, 0);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       ret = CMD_SUCCESS;
+error:
+       if (printed_wait_msg) {
+               MSG("");
+       }
+       lttng_clear_handle_destroy(handle);
+       free(session_name);
+       return ret;
+}
+
+/*
+ * clear all sessions
+ *
+ * Call clear_session for each registered sessions
+ */
+static int clear_all_sessions(struct lttng_session *sessions, int count)
+{
+       int i, ret = CMD_SUCCESS;
+
+       if (count == 0) {
+               MSG("No session found, nothing to do.");
+       } else if (count < 0) {
+               ERR("%s", lttng_strerror(ret));
+               goto error;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = clear_session(&sessions[i]);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+error:
+       return ret;
+}
+
+/*
+ * The 'clear <options>' first level command
+ */
+int cmd_clear(int argc, const char **argv)
+{
+       int opt;
+       int ret = CMD_SUCCESS , i, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+       bool free_session_name = false;
+       struct lttng_session *sessions = NULL;
+       int count;
+       int found;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       break;
+               default:
+                       ret = CMD_UNDEFINED;
+                       break;
+               }
+               goto end;
+       }
+
+       /* Mi preparation */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_clear);
+               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;
+               }
+
+               /* For validation and semantic purpose we open a sessions element */
+               ret = mi_lttng_sessions_open(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       if (!opt_clear_all) {
+               session_name = (char *) poptGetArg(pc);
+               if (!session_name) {
+                       /* No session name specified, lookup default */
+                       session_name = get_session_name();
+                       if (session_name == NULL) {
+                               command_ret = CMD_ERROR;
+                               success = 0;
+                               goto mi_closing;
+                       }
+                       free_session_name = true;
+               }
+       } else {
+               session_name = NULL;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+       /* Recuperate all sessions for further operation */
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ERR("%s", lttng_strerror(count));
+               command_ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+       /* Ignore session name in case all sessions are to be cleaned */
+       if (opt_clear_all) {
+               command_ret = clear_all_sessions(sessions, count);
+               if (command_ret) {
+                       ERR("%s", lttng_strerror(command_ret));
+                       success = 0;
+               }
+       } else {
+               /* Find the corresponding lttng_session struct */
+               found = 0;
+               for (i = 0; i < count; i++) {
+                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                               found = 1;
+                               command_ret = clear_session(&sessions[i]);
+                               if (command_ret) {
+                                       ERR("%s", lttng_strerror(command_ret));
+                                       success = 0;
+                               }
+                       }
+               }
+
+               if (!found) {
+                       ERR("Session name %s not found", session_name);
+                       command_ret = LTTNG_ERR_SESS_NOT_FOUND;
+                       success = 0;
+                       goto mi_closing;
+               }
+       }
+
+mi_closing:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close sessions and output element element */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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(sessions);
+       if (free_session_name) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred during clear_session/all */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/create.c b/src/bin/lttng/commands/create.c
deleted file mode 100644 (file)
index b266c10..0000000
+++ /dev/null
@@ -1,807 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <ctype.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <common/compat/time.h>
-#include <unistd.h>
-#include <signal.h>
-#include <sys/wait.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-#include "../utils.h"
-
-#include <common/defaults.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/uri.h>
-#include <common/utils.h>
-#include <lttng/lttng.h>
-
-static char *opt_output_path;
-static char *opt_session_name;
-static char *opt_url;
-static char *opt_ctrl_url;
-static char *opt_data_url;
-static char *opt_shm_path;
-static int opt_no_consumer;
-static int opt_no_output;
-static int opt_snapshot;
-static uint32_t opt_live_timer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-create.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_LIVE_TIMER,
-};
-
-enum output_type {
-       OUTPUT_NONE,
-       OUTPUT_LOCAL,
-       OUTPUT_NETWORK,
-       OUTPUT_UNSPECIFIED,
-};
-
-static struct mi_writer *writer;
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
-       {"output", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"set-url",        'U', POPT_ARG_STRING, &opt_url, 0, 0, 0},
-       {"ctrl-url",       'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
-       {"data-url",       'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
-       {"no-output",       0, POPT_ARG_VAL, &opt_no_output, 1, 0, 0},
-       {"no-consumer",     0, POPT_ARG_VAL, &opt_no_consumer, 1, 0, 0},
-       {"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},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Retrieve the created session and mi output it based on provided argument
- * This is currently a summary of what was pretty printed and is subject to
- * enhancements.
- */
-static int mi_created_session(const char *session_name)
-{
-       int ret, i, count, found;
-       struct lttng_session *sessions;
-
-       /* session_name should not be null */
-       LTTNG_ASSERT(session_name);
-       LTTNG_ASSERT(writer);
-
-       count = lttng_list_sessions(&sessions);
-       if (count < 0) {
-               ret = count;
-               ERR("%s", lttng_strerror(ret));
-               goto error;
-       }
-
-       if (count == 0) {
-               ERR("Error session creation failed: session %s not found", session_name);
-               ret = -LTTNG_ERR_SESS_NOT_FOUND;
-               goto end;
-       }
-
-       found = 0;
-       for (i = 0; i < count; i++) {
-               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
-                       found = 1;
-                       ret = mi_lttng_session(writer, &sessions[i], 0);
-                       if (ret) {
-                               goto error;
-                       }
-                       break;
-               }
-       }
-
-       if (!found) {
-               ret = -LTTNG_ERR_SESS_NOT_FOUND;
-       } else {
-               ret = CMD_SUCCESS;
-       }
-
-error:
-       free(sessions);
-end:
-       return ret;
-}
-
-static
-struct lttng_session_descriptor *create_session_descriptor(void)
-{
-       ssize_t uri_count;
-       enum output_type output_type;
-       struct lttng_uri *uris = NULL;
-       struct lttng_session_descriptor *descriptor = NULL;
-       const char *uri_str1 = NULL, *uri_str2 = NULL;
-       char local_output_path[LTTNG_PATH_MAX] = {};
-
-       if (opt_no_output) {
-               output_type = OUTPUT_NONE;
-       } else if (opt_output_path) {
-               char *expanded_output_path;
-               int ret;
-
-               output_type = OUTPUT_LOCAL;
-               expanded_output_path = utils_expand_path(opt_output_path);
-               if (!expanded_output_path) {
-                       ERR("Failed to expand output path.");
-                       goto end;
-               }
-               ret = lttng_strncpy(local_output_path, expanded_output_path,
-                               sizeof(local_output_path));
-               free(expanded_output_path);
-               if (ret) {
-                       ERR("Output path exceeds the maximal supported length (%zu bytes)",
-                                       sizeof(local_output_path));
-                       goto end;
-               }
-       } else if (opt_url || opt_ctrl_url) {
-               int ret;
-
-               uri_str1 = opt_ctrl_url ? opt_ctrl_url : opt_url;
-               uri_str2 = opt_data_url;
-
-               uri_count = uri_parse_str_urls(uri_str1, uri_str2, &uris);
-               if (uri_count != 1 && uri_count != 2) {
-                       ERR("Unrecognized URL format.");
-                       goto end;
-               }
-
-               switch (uri_count) {
-               case 1:
-                       output_type = OUTPUT_LOCAL;
-                       if (uris[0].dtype != LTTNG_DST_PATH) {
-                               ERR("Unrecognized URL format.");
-                               goto end;
-                       }
-                       ret = lttng_strncpy(local_output_path, uris[0].dst.path,
-                                       sizeof(local_output_path));
-                       if (ret) {
-                               ERR("Output path exceeds the maximal supported length (%zu bytes)",
-                                               sizeof(local_output_path));
-                       }
-                       break;
-               case 2:
-                       output_type = OUTPUT_NETWORK;
-                       break;
-               default:
-                       /* Already checked. */
-                       abort();
-               }
-       } else {
-               output_type = OUTPUT_UNSPECIFIED;
-       }
-
-       if (opt_snapshot) {
-               /* Snapshot session. */
-               switch (output_type) {
-               case OUTPUT_UNSPECIFIED:
-               case OUTPUT_LOCAL:
-                       descriptor = lttng_session_descriptor_snapshot_local_create(
-                                       opt_session_name,
-                                       output_type == OUTPUT_LOCAL ?
-                                               local_output_path : NULL);
-                       break;
-               case OUTPUT_NONE:
-                       descriptor = lttng_session_descriptor_snapshot_create(
-                                       opt_session_name);
-                       break;
-               case OUTPUT_NETWORK:
-                       descriptor = lttng_session_descriptor_snapshot_network_create(
-                                       opt_session_name, uri_str1, uri_str2);
-                       break;
-               default:
-                       abort();
-               }
-       } else if (opt_live_timer) {
-               /* Live session. */
-               if (output_type != OUTPUT_UNSPECIFIED &&
-                               output_type != OUTPUT_NETWORK) {
-                       ERR("Unsupported output type specified for live session.");
-                       goto end;
-               }
-               descriptor = lttng_session_descriptor_live_network_create(
-                               opt_session_name, uri_str1, uri_str2,
-                               opt_live_timer);
-       } else {
-               /* Regular session. */
-               switch (output_type) {
-               case OUTPUT_UNSPECIFIED:
-               case OUTPUT_LOCAL:
-                       descriptor = lttng_session_descriptor_local_create(
-                                       opt_session_name,
-                                       output_type == OUTPUT_LOCAL ?
-                                               local_output_path : NULL);
-                       break;
-               case OUTPUT_NONE:
-                       descriptor = lttng_session_descriptor_create(
-                                       opt_session_name);
-                       break;
-               case OUTPUT_NETWORK:
-                       descriptor = lttng_session_descriptor_network_create(
-                                       opt_session_name, uri_str1, uri_str2);
-                       break;
-               default:
-                       abort();
-               }
-       }
-       if (!descriptor) {
-               ERR("Failed to initialize session creation command.");
-       } else {
-               /*
-                * Auto-launch the relay daemon when a live session
-                * is created using default URLs.
-                */
-               if (!opt_url && !opt_ctrl_url && !opt_data_url &&
-                               opt_live_timer && !check_relayd()) {
-                       int ret;
-                       const char *pathname = opt_relayd_path ? :
-                                       INSTALL_BIN_PATH "/lttng-relayd";
-
-                       ret = spawn_relayd(pathname, 0);
-                       if (ret < 0) {
-                               lttng_session_descriptor_destroy(descriptor);
-                               descriptor = NULL;
-                       }
-               }
-       }
-end:
-       free(uris);
-       return descriptor;
-}
-
-/*
- *  Create a tracing session.
- *  If no name is specified, a default name is generated.
- *
- *  Returns one of the CMD_* result constants.
- */
-static int create_session(void)
-{
-       int ret, i;
-       char shm_path[LTTNG_PATH_MAX] = {};
-       struct lttng_session_descriptor *session_descriptor = NULL;
-       enum lttng_session_descriptor_status descriptor_status;
-       enum lttng_error_code ret_code;
-       struct lttng_session *sessions = NULL;
-       const struct lttng_session *created_session = NULL;
-       const char *created_session_name;
-
-       /* Validate options. */
-       if (opt_session_name) {
-               if (strlen(opt_session_name) > NAME_MAX) {
-                       ERR("Session name too long. Length must be lower or equal to %d",
-                                       NAME_MAX);
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-               /*
-                * Check if the session name begins with "auto-" or is exactly "auto".
-                * Both are reserved for the default session name. See bug #449 to
-                * understand why we need to check both here.
-                */
-               if ((strncmp(opt_session_name, DEFAULT_SESSION_NAME "-",
-                                       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))) {
-                       ERR("%s is a reserved keyword for default session(s)",
-                                       DEFAULT_SESSION_NAME);
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       if (opt_snapshot && opt_live_timer) {
-               ERR("Snapshot and live modes are mutually exclusive.");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) {
-               ERR("Both control and data URLs must be specified.");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       session_descriptor = create_session_descriptor();
-       if (!session_descriptor) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-       ret_code = lttng_create_session_ext(session_descriptor);
-       if (ret_code != LTTNG_OK) {
-               ERR("%s", lttng_strerror(-ret_code));
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       descriptor_status = lttng_session_descriptor_get_session_name(
-               session_descriptor, &created_session_name);
-       if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
-               ERR("Failed to obtain created session name");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       ret = lttng_list_sessions(&sessions);
-       if (ret < 0) {
-               ERR("Failed to fetch properties of created session: %s",
-                               lttng_strerror(ret));
-               ret = CMD_ERROR;
-               goto error;
-       }
-       for (i = 0; i < ret; i++) {
-               if (!strcmp(created_session_name, sessions[i].name)) {
-                       created_session = &sessions[i];
-                       break;
-               }
-       }
-       if (!created_session) {
-               ERR("Failed to fetch properties of created session");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if (opt_shm_path) {
-               char datetime_suffix[17] = {};
-
-               /*
-                * An auto-generated session name already includes the creation
-                * timestamp.
-                */
-               if (opt_session_name) {
-                       uint64_t creation_time;
-                       struct tm *timeinfo;
-                       time_t creation_time_t;
-                       size_t strftime_ret;
-
-                       ret_code = lttng_session_get_creation_time(
-                                       created_session,
-                                       &creation_time);
-                       if (ret_code != LTTNG_OK) {
-                               ERR("%s", lttng_strerror(-ret_code));
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-                       creation_time_t = (time_t) creation_time;
-                       timeinfo = localtime(&creation_time_t);
-                       if (!timeinfo) {
-                               PERROR("Failed to interpret session creation time");
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-                       strftime_ret = strftime(datetime_suffix,
-                                       sizeof(datetime_suffix),
-                                       "-%Y%m%d-%H%M%S", timeinfo);
-                       if (strftime_ret == 0) {
-                               ERR("Failed to format session creation time.");
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-
-               ret = snprintf(shm_path, sizeof(shm_path),
-                               "%s/%s%s", opt_shm_path, created_session_name,
-                               datetime_suffix);
-               if (ret < 0 || ret >= sizeof(shm_path)) {
-                       ERR("Failed to format the shared memory path.");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-               ret = lttng_set_session_shm_path(created_session_name,
-                               shm_path);
-               if (ret < 0) {
-                       lttng_destroy_session(created_session_name);
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       if (opt_snapshot) {
-               MSG("Snapshot session %s created.", created_session_name);
-       } else if (opt_live_timer) {
-               MSG("Live session %s created.", created_session_name);
-       } else {
-               MSG("Session %s created.", created_session_name);
-       }
-
-       if (*created_session->path && !opt_snapshot) {
-               MSG("Traces will be output to %s", created_session->path);
-
-               if (opt_live_timer) {
-                       MSG("Live timer interval set to %u %s", opt_live_timer,
-                                       USEC_UNIT);
-               }
-       } else if (opt_snapshot) {
-               struct lttng_snapshot_output_list *list;
-               struct lttng_snapshot_output *iter;
-               char snapshot_url[LTTNG_PATH_MAX] = {};
-
-               ret = lttng_snapshot_list_output(created_session_name, &list);
-               if (ret < 0) {
-                       ERR("Failed to list snapshot outputs.");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               while ((iter = lttng_snapshot_output_list_get_next(list))) {
-                       const char *url = NULL;
-
-                       url = lttng_snapshot_output_get_ctrl_url(
-                                       iter);
-                       ret = lttng_strncpy(snapshot_url, url,
-                                       sizeof(snapshot_url));
-                       if (ret) {
-                               snapshot_url[0] = '\0';
-                               ERR("Failed to retrieve snapshot output destination");
-                       }
-                       break;
-               }
-               lttng_snapshot_output_list_destroy(list);
-
-               if (*snapshot_url) {
-                       MSG("Default snapshot output set to %s",
-                                       snapshot_url);
-               }
-               MSG("Every channel enabled for this session will be set to mmap output and default to overwrite mode.");
-       }
-       if (opt_shm_path) {
-               MSG("Shared memory path set to %s", shm_path);
-       }
-
-       /* Mi output */
-       if (lttng_opt_mi) {
-               ret = mi_created_session(created_session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       /* Init lttng session config */
-       ret = config_init(created_session_name);
-       if (ret < 0) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       ret = CMD_SUCCESS;
-error:
-       lttng_session_descriptor_destroy(session_descriptor);
-       free(sessions);
-       return ret;
-}
-
-/*
- *  spawn_sessiond
- *
- *  Spawn a session daemon by forking and execv.
- */
-static int spawn_sessiond(const char *pathname)
-{
-       int ret = 0;
-       pid_t pid;
-
-       MSG("Spawning a session daemon");
-       pid = fork();
-       if (pid == 0) {
-               /*
-                * Spawn session daemon in daemon mode.
-                */
-               execlp(pathname, "lttng-sessiond",
-                               "--daemonize", NULL);
-               /* execlp only returns if error happened */
-               if (errno == ENOENT) {
-                       ERR("No session daemon found. Use --sessiond-path.");
-               } else {
-                       PERROR("execlp");
-               }
-               kill(getppid(), SIGTERM);       /* wake parent */
-               exit(EXIT_FAILURE);
-       } else if (pid > 0) {
-               /*
-                * In daemon mode (--daemonize), sessiond only exits when
-                * it's ready to accept commands.
-                */
-               for (;;) {
-                       int status;
-                       pid_t wait_pid_ret = waitpid(pid, &status, 0);
-
-                       if (wait_pid_ret < 0) {
-                               if (errno == EINTR) {
-                                       continue;
-                               }
-                               PERROR("waitpid");
-                               ret = -errno;
-                               goto end;
-                       }
-
-                       if (WIFSIGNALED(status)) {
-                               ERR("Session daemon was killed by signal %d",
-                                               WTERMSIG(status));
-                               ret = -1;
-                               goto end;
-                       } else if (WIFEXITED(status)) {
-                               DBG("Session daemon terminated normally (exit status: %d)",
-                                               WEXITSTATUS(status));
-
-                               if (WEXITSTATUS(status) != 0) {
-                                       ERR("Session daemon terminated with an error (exit status: %d)",
-                                                       WEXITSTATUS(status));
-                                       ret = -1;
-                                       goto end;
-                               }
-                               break;
-                       }
-               }
-
-               goto end;
-       } else {
-               PERROR("fork");
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- *  launch_sessiond
- *
- *  Check if the session daemon is available using
- *  the liblttngctl API for the check. If not, try to
- *  spawn a daemon.
- */
-static int launch_sessiond(void)
-{
-       int ret;
-       const char *pathname = NULL;
-
-       ret = lttng_session_daemon_alive();
-       if (ret) {
-               /* Sessiond is alive, not an error */
-               ret = 0;
-               goto end;
-       }
-
-       /* Try command line option path */
-       pathname = opt_sessiond_path;
-
-       /* Try LTTNG_SESSIOND_PATH env variable */
-       if (pathname == NULL) {
-               pathname = getenv(DEFAULT_SESSIOND_PATH_ENV);
-       }
-
-       /* Try with configured path */
-       if (pathname == NULL) {
-               if (CONFIG_SESSIOND_BIN[0] != '\0') {
-                       pathname = CONFIG_SESSIOND_BIN;
-               }
-       }
-
-       /* Try the default path */
-       if (pathname == NULL) {
-               pathname = INSTALL_BIN_PATH "/lttng-sessiond";
-       }
-
-       DBG("Session daemon binary path: %s", pathname);
-
-       /* Check existence and permissions */
-       ret = access(pathname, F_OK | X_OK);
-       if (ret < 0) {
-               ERR("No such file or access denied: %s", pathname);
-               goto end;
-       }
-
-       ret = spawn_sessiond(pathname);
-end:
-       if (ret) {
-               ERR("Problem occurred while launching session daemon (%s)",
-                               pathname);
-       }
-       return ret;
-}
-
-static
-int validate_url_option_combination(void)
-{
-       int ret = 0;
-       int used_count = 0;
-
-       used_count += !!opt_url;
-       used_count += !!opt_output_path;
-       used_count += (opt_data_url || opt_ctrl_url);
-       if (used_count > 1) {
-               ERR("Only one of the --set-url, --ctrl-url/data-url, or --output options may be used at once.");
-               ret = -1;
-       }
-
-       return ret;
-}
-
-/*
- *  The 'create <options>' first level command
- *
- *  Returns one of the CMD_* result constants.
- */
-int cmd_create(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       char *opt_arg = NULL;
-       const char *leftover = NULL;
-       static poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_LIVE_TIMER:
-               {
-                       uint64_t v;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-                       if (!opt_arg) {
-                               /* Set up default values. */
-                               opt_live_timer = (uint32_t) DEFAULT_LTTNG_LIVE_TIMER;
-                               DBG("Session live timer interval set to default value %d",
-                                               opt_live_timer);
-                               break;
-                       }
-
-                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
-                               ERR("Wrong value for --live parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (v != (uint32_t) v) {
-                               ERR("32-bit overflow in --live parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (v == 0) {
-                               ERR("Live timer interval must be greater than zero");
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       opt_live_timer = (uint32_t) v;
-                       DBG("Session live timer interval set to %d", opt_live_timer);
-                       break;
-               }
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (opt_no_consumer) {
-               MSG("The option --no-consumer is obsolete. Use --no-output now.");
-               ret = CMD_WARNING;
-               goto end;
-       }
-
-       ret = validate_url_option_combination();
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Spawn a session daemon if needed */
-       if (!opt_no_sessiond) {
-               ret = launch_sessiond();
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       /* MI initialization */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_create);
-               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;
-               }
-       }
-       opt_session_name = (char*) poptGetArg(pc);
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       command_ret = create_session();
-       if (command_ret) {
-               success = 0;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       /* Overwrite ret if an error occurred in create_session() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/create.cpp b/src/bin/lttng/commands/create.cpp
new file mode 100644 (file)
index 0000000..b266c10
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2019 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <ctype.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <common/compat/time.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/wait.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include "../utils.h"
+
+#include <common/defaults.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/uri.h>
+#include <common/utils.h>
+#include <lttng/lttng.h>
+
+static char *opt_output_path;
+static char *opt_session_name;
+static char *opt_url;
+static char *opt_ctrl_url;
+static char *opt_data_url;
+static char *opt_shm_path;
+static int opt_no_consumer;
+static int opt_no_output;
+static int opt_snapshot;
+static uint32_t opt_live_timer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-create.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_LIVE_TIMER,
+};
+
+enum output_type {
+       OUTPUT_NONE,
+       OUTPUT_LOCAL,
+       OUTPUT_NETWORK,
+       OUTPUT_UNSPECIFIED,
+};
+
+static struct mi_writer *writer;
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help", 'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
+       {"output", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"set-url",        'U', POPT_ARG_STRING, &opt_url, 0, 0, 0},
+       {"ctrl-url",       'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
+       {"data-url",       'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
+       {"no-output",       0, POPT_ARG_VAL, &opt_no_output, 1, 0, 0},
+       {"no-consumer",     0, POPT_ARG_VAL, &opt_no_consumer, 1, 0, 0},
+       {"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},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Retrieve the created session and mi output it based on provided argument
+ * This is currently a summary of what was pretty printed and is subject to
+ * enhancements.
+ */
+static int mi_created_session(const char *session_name)
+{
+       int ret, i, count, found;
+       struct lttng_session *sessions;
+
+       /* session_name should not be null */
+       LTTNG_ASSERT(session_name);
+       LTTNG_ASSERT(writer);
+
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ret = count;
+               ERR("%s", lttng_strerror(ret));
+               goto error;
+       }
+
+       if (count == 0) {
+               ERR("Error session creation failed: session %s not found", session_name);
+               ret = -LTTNG_ERR_SESS_NOT_FOUND;
+               goto end;
+       }
+
+       found = 0;
+       for (i = 0; i < count; i++) {
+               if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                       found = 1;
+                       ret = mi_lttng_session(writer, &sessions[i], 0);
+                       if (ret) {
+                               goto error;
+                       }
+                       break;
+               }
+       }
+
+       if (!found) {
+               ret = -LTTNG_ERR_SESS_NOT_FOUND;
+       } else {
+               ret = CMD_SUCCESS;
+       }
+
+error:
+       free(sessions);
+end:
+       return ret;
+}
+
+static
+struct lttng_session_descriptor *create_session_descriptor(void)
+{
+       ssize_t uri_count;
+       enum output_type output_type;
+       struct lttng_uri *uris = NULL;
+       struct lttng_session_descriptor *descriptor = NULL;
+       const char *uri_str1 = NULL, *uri_str2 = NULL;
+       char local_output_path[LTTNG_PATH_MAX] = {};
+
+       if (opt_no_output) {
+               output_type = OUTPUT_NONE;
+       } else if (opt_output_path) {
+               char *expanded_output_path;
+               int ret;
+
+               output_type = OUTPUT_LOCAL;
+               expanded_output_path = utils_expand_path(opt_output_path);
+               if (!expanded_output_path) {
+                       ERR("Failed to expand output path.");
+                       goto end;
+               }
+               ret = lttng_strncpy(local_output_path, expanded_output_path,
+                               sizeof(local_output_path));
+               free(expanded_output_path);
+               if (ret) {
+                       ERR("Output path exceeds the maximal supported length (%zu bytes)",
+                                       sizeof(local_output_path));
+                       goto end;
+               }
+       } else if (opt_url || opt_ctrl_url) {
+               int ret;
+
+               uri_str1 = opt_ctrl_url ? opt_ctrl_url : opt_url;
+               uri_str2 = opt_data_url;
+
+               uri_count = uri_parse_str_urls(uri_str1, uri_str2, &uris);
+               if (uri_count != 1 && uri_count != 2) {
+                       ERR("Unrecognized URL format.");
+                       goto end;
+               }
+
+               switch (uri_count) {
+               case 1:
+                       output_type = OUTPUT_LOCAL;
+                       if (uris[0].dtype != LTTNG_DST_PATH) {
+                               ERR("Unrecognized URL format.");
+                               goto end;
+                       }
+                       ret = lttng_strncpy(local_output_path, uris[0].dst.path,
+                                       sizeof(local_output_path));
+                       if (ret) {
+                               ERR("Output path exceeds the maximal supported length (%zu bytes)",
+                                               sizeof(local_output_path));
+                       }
+                       break;
+               case 2:
+                       output_type = OUTPUT_NETWORK;
+                       break;
+               default:
+                       /* Already checked. */
+                       abort();
+               }
+       } else {
+               output_type = OUTPUT_UNSPECIFIED;
+       }
+
+       if (opt_snapshot) {
+               /* Snapshot session. */
+               switch (output_type) {
+               case OUTPUT_UNSPECIFIED:
+               case OUTPUT_LOCAL:
+                       descriptor = lttng_session_descriptor_snapshot_local_create(
+                                       opt_session_name,
+                                       output_type == OUTPUT_LOCAL ?
+                                               local_output_path : NULL);
+                       break;
+               case OUTPUT_NONE:
+                       descriptor = lttng_session_descriptor_snapshot_create(
+                                       opt_session_name);
+                       break;
+               case OUTPUT_NETWORK:
+                       descriptor = lttng_session_descriptor_snapshot_network_create(
+                                       opt_session_name, uri_str1, uri_str2);
+                       break;
+               default:
+                       abort();
+               }
+       } else if (opt_live_timer) {
+               /* Live session. */
+               if (output_type != OUTPUT_UNSPECIFIED &&
+                               output_type != OUTPUT_NETWORK) {
+                       ERR("Unsupported output type specified for live session.");
+                       goto end;
+               }
+               descriptor = lttng_session_descriptor_live_network_create(
+                               opt_session_name, uri_str1, uri_str2,
+                               opt_live_timer);
+       } else {
+               /* Regular session. */
+               switch (output_type) {
+               case OUTPUT_UNSPECIFIED:
+               case OUTPUT_LOCAL:
+                       descriptor = lttng_session_descriptor_local_create(
+                                       opt_session_name,
+                                       output_type == OUTPUT_LOCAL ?
+                                               local_output_path : NULL);
+                       break;
+               case OUTPUT_NONE:
+                       descriptor = lttng_session_descriptor_create(
+                                       opt_session_name);
+                       break;
+               case OUTPUT_NETWORK:
+                       descriptor = lttng_session_descriptor_network_create(
+                                       opt_session_name, uri_str1, uri_str2);
+                       break;
+               default:
+                       abort();
+               }
+       }
+       if (!descriptor) {
+               ERR("Failed to initialize session creation command.");
+       } else {
+               /*
+                * Auto-launch the relay daemon when a live session
+                * is created using default URLs.
+                */
+               if (!opt_url && !opt_ctrl_url && !opt_data_url &&
+                               opt_live_timer && !check_relayd()) {
+                       int ret;
+                       const char *pathname = opt_relayd_path ? :
+                                       INSTALL_BIN_PATH "/lttng-relayd";
+
+                       ret = spawn_relayd(pathname, 0);
+                       if (ret < 0) {
+                               lttng_session_descriptor_destroy(descriptor);
+                               descriptor = NULL;
+                       }
+               }
+       }
+end:
+       free(uris);
+       return descriptor;
+}
+
+/*
+ *  Create a tracing session.
+ *  If no name is specified, a default name is generated.
+ *
+ *  Returns one of the CMD_* result constants.
+ */
+static int create_session(void)
+{
+       int ret, i;
+       char shm_path[LTTNG_PATH_MAX] = {};
+       struct lttng_session_descriptor *session_descriptor = NULL;
+       enum lttng_session_descriptor_status descriptor_status;
+       enum lttng_error_code ret_code;
+       struct lttng_session *sessions = NULL;
+       const struct lttng_session *created_session = NULL;
+       const char *created_session_name;
+
+       /* Validate options. */
+       if (opt_session_name) {
+               if (strlen(opt_session_name) > NAME_MAX) {
+                       ERR("Session name too long. Length must be lower or equal to %d",
+                                       NAME_MAX);
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               /*
+                * Check if the session name begins with "auto-" or is exactly "auto".
+                * Both are reserved for the default session name. See bug #449 to
+                * understand why we need to check both here.
+                */
+               if ((strncmp(opt_session_name, DEFAULT_SESSION_NAME "-",
+                                       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))) {
+                       ERR("%s is a reserved keyword for default session(s)",
+                                       DEFAULT_SESSION_NAME);
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       if (opt_snapshot && opt_live_timer) {
+               ERR("Snapshot and live modes are mutually exclusive.");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if ((!opt_ctrl_url && opt_data_url) || (opt_ctrl_url && !opt_data_url)) {
+               ERR("Both control and data URLs must be specified.");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       session_descriptor = create_session_descriptor();
+       if (!session_descriptor) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+       ret_code = lttng_create_session_ext(session_descriptor);
+       if (ret_code != LTTNG_OK) {
+               ERR("%s", lttng_strerror(-ret_code));
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       descriptor_status = lttng_session_descriptor_get_session_name(
+               session_descriptor, &created_session_name);
+       if (descriptor_status != LTTNG_SESSION_DESCRIPTOR_STATUS_OK) {
+               ERR("Failed to obtain created session name");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       ret = lttng_list_sessions(&sessions);
+       if (ret < 0) {
+               ERR("Failed to fetch properties of created session: %s",
+                               lttng_strerror(ret));
+               ret = CMD_ERROR;
+               goto error;
+       }
+       for (i = 0; i < ret; i++) {
+               if (!strcmp(created_session_name, sessions[i].name)) {
+                       created_session = &sessions[i];
+                       break;
+               }
+       }
+       if (!created_session) {
+               ERR("Failed to fetch properties of created session");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if (opt_shm_path) {
+               char datetime_suffix[17] = {};
+
+               /*
+                * An auto-generated session name already includes the creation
+                * timestamp.
+                */
+               if (opt_session_name) {
+                       uint64_t creation_time;
+                       struct tm *timeinfo;
+                       time_t creation_time_t;
+                       size_t strftime_ret;
+
+                       ret_code = lttng_session_get_creation_time(
+                                       created_session,
+                                       &creation_time);
+                       if (ret_code != LTTNG_OK) {
+                               ERR("%s", lttng_strerror(-ret_code));
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+                       creation_time_t = (time_t) creation_time;
+                       timeinfo = localtime(&creation_time_t);
+                       if (!timeinfo) {
+                               PERROR("Failed to interpret session creation time");
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+                       strftime_ret = strftime(datetime_suffix,
+                                       sizeof(datetime_suffix),
+                                       "-%Y%m%d-%H%M%S", timeinfo);
+                       if (strftime_ret == 0) {
+                               ERR("Failed to format session creation time.");
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+
+               ret = snprintf(shm_path, sizeof(shm_path),
+                               "%s/%s%s", opt_shm_path, created_session_name,
+                               datetime_suffix);
+               if (ret < 0 || ret >= sizeof(shm_path)) {
+                       ERR("Failed to format the shared memory path.");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+               ret = lttng_set_session_shm_path(created_session_name,
+                               shm_path);
+               if (ret < 0) {
+                       lttng_destroy_session(created_session_name);
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       if (opt_snapshot) {
+               MSG("Snapshot session %s created.", created_session_name);
+       } else if (opt_live_timer) {
+               MSG("Live session %s created.", created_session_name);
+       } else {
+               MSG("Session %s created.", created_session_name);
+       }
+
+       if (*created_session->path && !opt_snapshot) {
+               MSG("Traces will be output to %s", created_session->path);
+
+               if (opt_live_timer) {
+                       MSG("Live timer interval set to %u %s", opt_live_timer,
+                                       USEC_UNIT);
+               }
+       } else if (opt_snapshot) {
+               struct lttng_snapshot_output_list *list;
+               struct lttng_snapshot_output *iter;
+               char snapshot_url[LTTNG_PATH_MAX] = {};
+
+               ret = lttng_snapshot_list_output(created_session_name, &list);
+               if (ret < 0) {
+                       ERR("Failed to list snapshot outputs.");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               while ((iter = lttng_snapshot_output_list_get_next(list))) {
+                       const char *url = NULL;
+
+                       url = lttng_snapshot_output_get_ctrl_url(
+                                       iter);
+                       ret = lttng_strncpy(snapshot_url, url,
+                                       sizeof(snapshot_url));
+                       if (ret) {
+                               snapshot_url[0] = '\0';
+                               ERR("Failed to retrieve snapshot output destination");
+                       }
+                       break;
+               }
+               lttng_snapshot_output_list_destroy(list);
+
+               if (*snapshot_url) {
+                       MSG("Default snapshot output set to %s",
+                                       snapshot_url);
+               }
+               MSG("Every channel enabled for this session will be set to mmap output and default to overwrite mode.");
+       }
+       if (opt_shm_path) {
+               MSG("Shared memory path set to %s", shm_path);
+       }
+
+       /* Mi output */
+       if (lttng_opt_mi) {
+               ret = mi_created_session(created_session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       /* Init lttng session config */
+       ret = config_init(created_session_name);
+       if (ret < 0) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       ret = CMD_SUCCESS;
+error:
+       lttng_session_descriptor_destroy(session_descriptor);
+       free(sessions);
+       return ret;
+}
+
+/*
+ *  spawn_sessiond
+ *
+ *  Spawn a session daemon by forking and execv.
+ */
+static int spawn_sessiond(const char *pathname)
+{
+       int ret = 0;
+       pid_t pid;
+
+       MSG("Spawning a session daemon");
+       pid = fork();
+       if (pid == 0) {
+               /*
+                * Spawn session daemon in daemon mode.
+                */
+               execlp(pathname, "lttng-sessiond",
+                               "--daemonize", NULL);
+               /* execlp only returns if error happened */
+               if (errno == ENOENT) {
+                       ERR("No session daemon found. Use --sessiond-path.");
+               } else {
+                       PERROR("execlp");
+               }
+               kill(getppid(), SIGTERM);       /* wake parent */
+               exit(EXIT_FAILURE);
+       } else if (pid > 0) {
+               /*
+                * In daemon mode (--daemonize), sessiond only exits when
+                * it's ready to accept commands.
+                */
+               for (;;) {
+                       int status;
+                       pid_t wait_pid_ret = waitpid(pid, &status, 0);
+
+                       if (wait_pid_ret < 0) {
+                               if (errno == EINTR) {
+                                       continue;
+                               }
+                               PERROR("waitpid");
+                               ret = -errno;
+                               goto end;
+                       }
+
+                       if (WIFSIGNALED(status)) {
+                               ERR("Session daemon was killed by signal %d",
+                                               WTERMSIG(status));
+                               ret = -1;
+                               goto end;
+                       } else if (WIFEXITED(status)) {
+                               DBG("Session daemon terminated normally (exit status: %d)",
+                                               WEXITSTATUS(status));
+
+                               if (WEXITSTATUS(status) != 0) {
+                                       ERR("Session daemon terminated with an error (exit status: %d)",
+                                                       WEXITSTATUS(status));
+                                       ret = -1;
+                                       goto end;
+                               }
+                               break;
+                       }
+               }
+
+               goto end;
+       } else {
+               PERROR("fork");
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ *  launch_sessiond
+ *
+ *  Check if the session daemon is available using
+ *  the liblttngctl API for the check. If not, try to
+ *  spawn a daemon.
+ */
+static int launch_sessiond(void)
+{
+       int ret;
+       const char *pathname = NULL;
+
+       ret = lttng_session_daemon_alive();
+       if (ret) {
+               /* Sessiond is alive, not an error */
+               ret = 0;
+               goto end;
+       }
+
+       /* Try command line option path */
+       pathname = opt_sessiond_path;
+
+       /* Try LTTNG_SESSIOND_PATH env variable */
+       if (pathname == NULL) {
+               pathname = getenv(DEFAULT_SESSIOND_PATH_ENV);
+       }
+
+       /* Try with configured path */
+       if (pathname == NULL) {
+               if (CONFIG_SESSIOND_BIN[0] != '\0') {
+                       pathname = CONFIG_SESSIOND_BIN;
+               }
+       }
+
+       /* Try the default path */
+       if (pathname == NULL) {
+               pathname = INSTALL_BIN_PATH "/lttng-sessiond";
+       }
+
+       DBG("Session daemon binary path: %s", pathname);
+
+       /* Check existence and permissions */
+       ret = access(pathname, F_OK | X_OK);
+       if (ret < 0) {
+               ERR("No such file or access denied: %s", pathname);
+               goto end;
+       }
+
+       ret = spawn_sessiond(pathname);
+end:
+       if (ret) {
+               ERR("Problem occurred while launching session daemon (%s)",
+                               pathname);
+       }
+       return ret;
+}
+
+static
+int validate_url_option_combination(void)
+{
+       int ret = 0;
+       int used_count = 0;
+
+       used_count += !!opt_url;
+       used_count += !!opt_output_path;
+       used_count += (opt_data_url || opt_ctrl_url);
+       if (used_count > 1) {
+               ERR("Only one of the --set-url, --ctrl-url/data-url, or --output options may be used at once.");
+               ret = -1;
+       }
+
+       return ret;
+}
+
+/*
+ *  The 'create <options>' first level command
+ *
+ *  Returns one of the CMD_* result constants.
+ */
+int cmd_create(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       char *opt_arg = NULL;
+       const char *leftover = NULL;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_LIVE_TIMER:
+               {
+                       uint64_t v;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+                       if (!opt_arg) {
+                               /* Set up default values. */
+                               opt_live_timer = (uint32_t) DEFAULT_LTTNG_LIVE_TIMER;
+                               DBG("Session live timer interval set to default value %d",
+                                               opt_live_timer);
+                               break;
+                       }
+
+                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
+                               ERR("Wrong value for --live parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (v != (uint32_t) v) {
+                               ERR("32-bit overflow in --live parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (v == 0) {
+                               ERR("Live timer interval must be greater than zero");
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       opt_live_timer = (uint32_t) v;
+                       DBG("Session live timer interval set to %d", opt_live_timer);
+                       break;
+               }
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (opt_no_consumer) {
+               MSG("The option --no-consumer is obsolete. Use --no-output now.");
+               ret = CMD_WARNING;
+               goto end;
+       }
+
+       ret = validate_url_option_combination();
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Spawn a session daemon if needed */
+       if (!opt_no_sessiond) {
+               ret = launch_sessiond();
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       /* MI initialization */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_create);
+               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;
+               }
+       }
+       opt_session_name = (char*) poptGetArg(pc);
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       command_ret = create_session();
+       if (command_ret) {
+               success = 0;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       /* Overwrite ret if an error occurred in create_session() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/destroy.c b/src/bin/lttng/commands/destroy.c
deleted file mode 100644 (file)
index 78bbbaa..0000000
+++ /dev/null
@@ -1,433 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <stdbool.h>
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-#include <common/mi-lttng.h>
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/utils.h>
-
-static char *opt_session_name;
-static int opt_destroy_all;
-static int opt_no_wait;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-destroy.1.h>
-;
-#endif
-
-/* Mi writer */
-static struct mi_writer *writer;
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"all",       'a', POPT_ARG_VAL, &opt_destroy_all, 1, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * destroy_session
- *
- * Unregister the provided session to the session daemon. On success, removes
- * the default configuration.
- */
-static int destroy_session(struct lttng_session *session)
-{
-       int ret;
-       char *session_name = NULL;
-       bool session_was_already_stopped;
-       enum lttng_error_code ret_code;
-       struct lttng_destruction_handle *handle = NULL;
-       enum lttng_destruction_handle_status status;
-       bool newline_needed = false, printed_destroy_msg = false;
-       enum lttng_rotation_state rotation_state;
-       char *stats_str = NULL;
-
-       ret = lttng_stop_tracing_no_wait(session->name);
-       if (ret < 0 && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
-               ERR("%s", lttng_strerror(ret));
-       }
-
-       session_was_already_stopped = ret == -LTTNG_ERR_TRACE_ALREADY_STOPPED;
-       if (!opt_no_wait) {
-               do {
-                       ret = lttng_data_pending(session->name);
-                       if (ret < 0) {
-                               /* Return the data available call error. */
-                               goto error;
-                       }
-
-                       /*
-                        * Data sleep time before retrying (in usec). Don't
-                        * sleep if the call returned value indicates
-                        * availability.
-                        */
-                       if (ret) {
-                               if (!printed_destroy_msg) {
-                                       _MSG("Destroying session %s",
-                                                       session->name);
-                                       newline_needed = true;
-                                       printed_destroy_msg = true;
-                                       fflush(stdout);
-                               }
-
-                               usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
-                               _MSG(".");
-                               fflush(stdout);
-                       }
-               } while (ret != 0);
-       }
-
-       if (!session_was_already_stopped) {
-               /*
-                * Don't print the event and packet loss warnings since the user
-                * already saw them when stopping the trace.
-                */
-               ret = get_session_stats_str(session->name, &stats_str);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       ret_code = lttng_destroy_session_ext(session->name, &handle);
-       if (ret_code != LTTNG_OK) {
-               ret = -ret_code;
-               goto error;
-       }
-
-       if (opt_no_wait) {
-               goto skip_wait_rotation;
-       }
-
-       do {
-               status = lttng_destruction_handle_wait_for_completion(
-                               handle, DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US /
-                                                       USEC_PER_MSEC);
-               switch (status) {
-               case LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT:
-                       if (!printed_destroy_msg) {
-                               _MSG("Destroying session %s", session->name);
-                               newline_needed = true;
-                               printed_destroy_msg = true;
-                       }
-                       _MSG(".");
-                       fflush(stdout);
-                       break;
-               case LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED:
-                       break;
-               default:
-                       ERR("%sFailed to wait for the completion of the destruction of session \"%s\"",
-                                       newline_needed ? "\n" : "",
-                                       session->name);
-                       newline_needed = false;
-                       ret = -1;
-                       goto error;
-               }
-       } while (status == LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT);
-
-       status = lttng_destruction_handle_get_result(handle, &ret_code);
-       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
-               ERR("%sFailed to get the result of session destruction",
-                               newline_needed ? "\n" : "");
-               ret = -1;
-               newline_needed = false;
-               goto error;
-       }
-       if (ret_code != LTTNG_OK) {
-               ret = -ret_code;
-               goto error;
-       }
-
-       status = lttng_destruction_handle_get_rotation_state(
-                       handle, &rotation_state);
-       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
-               ERR("%sFailed to get rotation state from destruction handle",
-                               newline_needed ? "\n" : "");
-               newline_needed = false;
-               goto skip_wait_rotation;
-       }
-
-       switch (rotation_state) {
-       case LTTNG_ROTATION_STATE_NO_ROTATION:
-               break;
-       case LTTNG_ROTATION_STATE_COMPLETED:
-       {
-               const struct lttng_trace_archive_location *location;
-
-               status = lttng_destruction_handle_get_archive_location(
-                               handle, &location);
-               if (status == LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
-                       ret = print_trace_archive_location(
-                                       location, session->name);
-                       if (ret) {
-                               ERR("%sFailed to print the location of trace archive",
-                                               newline_needed ? "\n" : "");
-                               newline_needed = false;
-                               goto skip_wait_rotation;
-                       }
-                       break;
-               }
-               /* fall-through. */
-       }
-       default:
-               ERR("%sFailed to get the location of the rotation performed during the session's destruction",
-                               newline_needed ? "\n" : "");
-               newline_needed = false;
-               goto skip_wait_rotation;
-       }
-skip_wait_rotation:
-       MSG("%sSession %s destroyed", newline_needed ? "\n" : "",
-                       session->name);
-       newline_needed = false;
-       if (stats_str) {
-               MSG("%s", stats_str);
-       }
-
-       session_name = get_session_name_quiet();
-       if (session_name && !strncmp(session->name, session_name, NAME_MAX)) {
-               config_destroy_default();
-       }
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_session(writer, session, 0);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       ret = CMD_SUCCESS;
-error:
-       if (newline_needed) {
-               MSG("");
-       }
-       lttng_destruction_handle_destroy(handle);
-       free(session_name);
-       free(stats_str);
-       return ret;
-}
-
-/*
- * destroy_all_sessions
- *
- * Call destroy_sessions for each registered sessions
- */
-static int destroy_all_sessions(struct lttng_session *sessions, int count)
-{
-       int i;
-       bool error_occurred = false;
-
-       LTTNG_ASSERT(count >= 0);
-       if (count == 0) {
-               MSG("No session found, nothing to do.");
-       }
-
-       for (i = 0; i < count; i++) {
-               int ret = destroy_session(&sessions[i]);
-
-               if (ret < 0) {
-                       ERR("%s during the destruction of session \"%s\"",
-                                       lttng_strerror(ret),
-                                       sessions[i].name);
-                       /* Continue to next session. */
-                       error_occurred = true;
-               }
-       }
-
-       return error_occurred ? CMD_ERROR : CMD_SUCCESS;
-}
-
-/*
- * The 'destroy <options>' first level command
- */
-int cmd_destroy(int argc, const char **argv)
-{
-       int opt;
-       int ret = CMD_SUCCESS , i, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-
-       struct lttng_session *sessions = NULL;
-       int count;
-       int found;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       break;
-               default:
-                       ret = CMD_UNDEFINED;
-                       break;
-               }
-               goto end;
-       }
-
-       /* Mi preparation */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_destroy);
-               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;
-               }
-
-               /* For validation and semantic purpose we open a sessions element */
-               ret = mi_lttng_sessions_open(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       /* Recuperate all sessions for further operation */
-       count = lttng_list_sessions(&sessions);
-       if (count < 0) {
-               ERR("%s", lttng_strerror(count));
-               command_ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-       /* Ignore session name in case all sessions are to be destroyed */
-       if (opt_destroy_all) {
-               command_ret = destroy_all_sessions(sessions, count);
-               if (command_ret) {
-                       success = 0;
-               }
-       } else {
-               opt_session_name = (char *) poptGetArg(pc);
-
-               if (!opt_session_name) {
-                       /* No session name specified, lookup default */
-                       session_name = get_session_name();
-                       if (session_name == NULL) {
-                               command_ret = CMD_ERROR;
-                               success = 0;
-                               goto mi_closing;
-                       }
-               } else {
-                       session_name = opt_session_name;
-               }
-
-               /* Find the corresponding lttng_session struct */
-               found = 0;
-               for (i = 0; i < count; i++) {
-                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
-                               found = 1;
-                               command_ret = destroy_session(&sessions[i]);
-                               if (command_ret) {
-                                       success = 0;
-                                       ERR("%s during the destruction of session \"%s\"",
-                                                       lttng_strerror(command_ret),
-                                                       sessions[i].name);
-                               }
-                       }
-               }
-
-               if (!found) {
-                       ERR("Session name %s not found", session_name);
-                       command_ret = LTTNG_ERR_SESS_NOT_FOUND;
-                       success = 0;
-                       goto mi_closing;
-               }
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-mi_closing:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close sessions and output element element */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       if (opt_session_name == NULL) {
-               free(session_name);
-       }
-
-       free(sessions);
-
-       /* Overwrite ret if an error occurred during destroy_session/all */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/destroy.cpp b/src/bin/lttng/commands/destroy.cpp
new file mode 100644 (file)
index 0000000..78bbbaa
--- /dev/null
@@ -0,0 +1,433 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+#include <common/mi-lttng.h>
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/utils.h>
+
+static char *opt_session_name;
+static int opt_destroy_all;
+static int opt_no_wait;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-destroy.1.h>
+;
+#endif
+
+/* Mi writer */
+static struct mi_writer *writer;
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"all",       'a', POPT_ARG_VAL, &opt_destroy_all, 1, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * destroy_session
+ *
+ * Unregister the provided session to the session daemon. On success, removes
+ * the default configuration.
+ */
+static int destroy_session(struct lttng_session *session)
+{
+       int ret;
+       char *session_name = NULL;
+       bool session_was_already_stopped;
+       enum lttng_error_code ret_code;
+       struct lttng_destruction_handle *handle = NULL;
+       enum lttng_destruction_handle_status status;
+       bool newline_needed = false, printed_destroy_msg = false;
+       enum lttng_rotation_state rotation_state;
+       char *stats_str = NULL;
+
+       ret = lttng_stop_tracing_no_wait(session->name);
+       if (ret < 0 && ret != -LTTNG_ERR_TRACE_ALREADY_STOPPED) {
+               ERR("%s", lttng_strerror(ret));
+       }
+
+       session_was_already_stopped = ret == -LTTNG_ERR_TRACE_ALREADY_STOPPED;
+       if (!opt_no_wait) {
+               do {
+                       ret = lttng_data_pending(session->name);
+                       if (ret < 0) {
+                               /* Return the data available call error. */
+                               goto error;
+                       }
+
+                       /*
+                        * Data sleep time before retrying (in usec). Don't
+                        * sleep if the call returned value indicates
+                        * availability.
+                        */
+                       if (ret) {
+                               if (!printed_destroy_msg) {
+                                       _MSG("Destroying session %s",
+                                                       session->name);
+                                       newline_needed = true;
+                                       printed_destroy_msg = true;
+                                       fflush(stdout);
+                               }
+
+                               usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
+                               _MSG(".");
+                               fflush(stdout);
+                       }
+               } while (ret != 0);
+       }
+
+       if (!session_was_already_stopped) {
+               /*
+                * Don't print the event and packet loss warnings since the user
+                * already saw them when stopping the trace.
+                */
+               ret = get_session_stats_str(session->name, &stats_str);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       ret_code = lttng_destroy_session_ext(session->name, &handle);
+       if (ret_code != LTTNG_OK) {
+               ret = -ret_code;
+               goto error;
+       }
+
+       if (opt_no_wait) {
+               goto skip_wait_rotation;
+       }
+
+       do {
+               status = lttng_destruction_handle_wait_for_completion(
+                               handle, DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US /
+                                                       USEC_PER_MSEC);
+               switch (status) {
+               case LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT:
+                       if (!printed_destroy_msg) {
+                               _MSG("Destroying session %s", session->name);
+                               newline_needed = true;
+                               printed_destroy_msg = true;
+                       }
+                       _MSG(".");
+                       fflush(stdout);
+                       break;
+               case LTTNG_DESTRUCTION_HANDLE_STATUS_COMPLETED:
+                       break;
+               default:
+                       ERR("%sFailed to wait for the completion of the destruction of session \"%s\"",
+                                       newline_needed ? "\n" : "",
+                                       session->name);
+                       newline_needed = false;
+                       ret = -1;
+                       goto error;
+               }
+       } while (status == LTTNG_DESTRUCTION_HANDLE_STATUS_TIMEOUT);
+
+       status = lttng_destruction_handle_get_result(handle, &ret_code);
+       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
+               ERR("%sFailed to get the result of session destruction",
+                               newline_needed ? "\n" : "");
+               ret = -1;
+               newline_needed = false;
+               goto error;
+       }
+       if (ret_code != LTTNG_OK) {
+               ret = -ret_code;
+               goto error;
+       }
+
+       status = lttng_destruction_handle_get_rotation_state(
+                       handle, &rotation_state);
+       if (status != LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
+               ERR("%sFailed to get rotation state from destruction handle",
+                               newline_needed ? "\n" : "");
+               newline_needed = false;
+               goto skip_wait_rotation;
+       }
+
+       switch (rotation_state) {
+       case LTTNG_ROTATION_STATE_NO_ROTATION:
+               break;
+       case LTTNG_ROTATION_STATE_COMPLETED:
+       {
+               const struct lttng_trace_archive_location *location;
+
+               status = lttng_destruction_handle_get_archive_location(
+                               handle, &location);
+               if (status == LTTNG_DESTRUCTION_HANDLE_STATUS_OK) {
+                       ret = print_trace_archive_location(
+                                       location, session->name);
+                       if (ret) {
+                               ERR("%sFailed to print the location of trace archive",
+                                               newline_needed ? "\n" : "");
+                               newline_needed = false;
+                               goto skip_wait_rotation;
+                       }
+                       break;
+               }
+               /* fall-through. */
+       }
+       default:
+               ERR("%sFailed to get the location of the rotation performed during the session's destruction",
+                               newline_needed ? "\n" : "");
+               newline_needed = false;
+               goto skip_wait_rotation;
+       }
+skip_wait_rotation:
+       MSG("%sSession %s destroyed", newline_needed ? "\n" : "",
+                       session->name);
+       newline_needed = false;
+       if (stats_str) {
+               MSG("%s", stats_str);
+       }
+
+       session_name = get_session_name_quiet();
+       if (session_name && !strncmp(session->name, session_name, NAME_MAX)) {
+               config_destroy_default();
+       }
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_session(writer, session, 0);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       ret = CMD_SUCCESS;
+error:
+       if (newline_needed) {
+               MSG("");
+       }
+       lttng_destruction_handle_destroy(handle);
+       free(session_name);
+       free(stats_str);
+       return ret;
+}
+
+/*
+ * destroy_all_sessions
+ *
+ * Call destroy_sessions for each registered sessions
+ */
+static int destroy_all_sessions(struct lttng_session *sessions, int count)
+{
+       int i;
+       bool error_occurred = false;
+
+       LTTNG_ASSERT(count >= 0);
+       if (count == 0) {
+               MSG("No session found, nothing to do.");
+       }
+
+       for (i = 0; i < count; i++) {
+               int ret = destroy_session(&sessions[i]);
+
+               if (ret < 0) {
+                       ERR("%s during the destruction of session \"%s\"",
+                                       lttng_strerror(ret),
+                                       sessions[i].name);
+                       /* Continue to next session. */
+                       error_occurred = true;
+               }
+       }
+
+       return error_occurred ? CMD_ERROR : CMD_SUCCESS;
+}
+
+/*
+ * The 'destroy <options>' first level command
+ */
+int cmd_destroy(int argc, const char **argv)
+{
+       int opt;
+       int ret = CMD_SUCCESS , i, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+
+       struct lttng_session *sessions = NULL;
+       int count;
+       int found;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       break;
+               default:
+                       ret = CMD_UNDEFINED;
+                       break;
+               }
+               goto end;
+       }
+
+       /* Mi preparation */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_destroy);
+               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;
+               }
+
+               /* For validation and semantic purpose we open a sessions element */
+               ret = mi_lttng_sessions_open(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       /* Recuperate all sessions for further operation */
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ERR("%s", lttng_strerror(count));
+               command_ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+       /* Ignore session name in case all sessions are to be destroyed */
+       if (opt_destroy_all) {
+               command_ret = destroy_all_sessions(sessions, count);
+               if (command_ret) {
+                       success = 0;
+               }
+       } else {
+               opt_session_name = (char *) poptGetArg(pc);
+
+               if (!opt_session_name) {
+                       /* No session name specified, lookup default */
+                       session_name = get_session_name();
+                       if (session_name == NULL) {
+                               command_ret = CMD_ERROR;
+                               success = 0;
+                               goto mi_closing;
+                       }
+               } else {
+                       session_name = opt_session_name;
+               }
+
+               /* Find the corresponding lttng_session struct */
+               found = 0;
+               for (i = 0; i < count; i++) {
+                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                               found = 1;
+                               command_ret = destroy_session(&sessions[i]);
+                               if (command_ret) {
+                                       success = 0;
+                                       ERR("%s during the destruction of session \"%s\"",
+                                                       lttng_strerror(command_ret),
+                                                       sessions[i].name);
+                               }
+                       }
+               }
+
+               if (!found) {
+                       ERR("Session name %s not found", session_name);
+                       command_ret = LTTNG_ERR_SESS_NOT_FOUND;
+                       success = 0;
+                       goto mi_closing;
+               }
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+mi_closing:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close sessions and output element element */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+
+       free(sessions);
+
+       /* Overwrite ret if an error occurred during destroy_session/all */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/disable_channels.c b/src/bin/lttng/commands/disable_channels.c
deleted file mode 100644 (file)
index cf9f20b..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-#include <lttng/domain-internal.h>
-
-#include "../command.h"
-
-static char *opt_channels;
-static int opt_kernel;
-static char *opt_session_name;
-static int opt_userspace;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-disable-channel.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_USERSPACE,
-       OPT_LIST_OPTIONS,
-};
-
-static struct lttng_handle *handle;
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int mi_partial_channel_print(char *channel_name, unsigned int enabled,
-               int success)
-{
-       int ret;
-
-       LTTNG_ASSERT(writer);
-       LTTNG_ASSERT(channel_name);
-
-       /* Open channel element */
-       ret = mi_lttng_writer_open_element(writer, config_element_channel);
-       if (ret) {
-               goto end;
-       }
-
-       /* Name */
-       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
-                       channel_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Enabled ? */
-       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
-                       enabled);
-       if (ret) {
-               goto end;
-       }
-
-       /* Success ? */
-       ret = mi_lttng_writer_write_element_bool(writer,
-                       mi_lttng_element_success, success);
-       if (ret) {
-               goto end;
-       }
-
-       /* Closing channel element */
-       ret = mi_lttng_writer_close_element(writer);
-
-end:
-       return ret;
-}
-
-/*
- * Disabling channel using the lttng API.
- */
-static int disable_channels(char *session_name)
-{
-       int ret = CMD_SUCCESS, warn = 0, success;
-
-       /* Normal case for disable channed is enabled = 0 */
-       unsigned int enabled = 0;
-       char *channel_name;
-       struct lttng_domain dom;
-
-       memset(&dom, 0, sizeof(dom));
-
-       /* Create lttng domain */
-       if (opt_kernel) {
-               dom.type = LTTNG_DOMAIN_KERNEL;
-       } else if (opt_userspace) {
-               dom.type = LTTNG_DOMAIN_UST;
-       } else {
-               /* Checked by the caller. */
-               abort();
-       }
-
-       handle = lttng_create_handle(session_name, &dom);
-       if (handle == NULL) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Prepare MI */
-       if (lttng_opt_mi) {
-               /* open a channels element */
-               ret = mi_lttng_writer_open_element(writer, config_element_channels);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-       }
-
-       /* Strip channel list */
-       channel_name = strtok(opt_channels, ",");
-       while (channel_name != NULL) {
-               DBG("Disabling channel %s", channel_name);
-
-               ret = lttng_disable_channel(handle, channel_name);
-               if (ret < 0) {
-                       ERR("Channel %s: %s (session %s)", channel_name,
-                                       lttng_strerror(ret), session_name);
-                       warn = 1;
-
-                       /*
-                        * Mi:
-                        * We assume that if an error occurred the channel is still active.
-                        * This might not be the case but is a good assumption.
-                        * The client should look at the stderr stream
-                        * for more informations.
-                        */
-                       enabled = 1;
-                       success = 0;
-
-               } else {
-                       MSG("%s channel %s disabled for session %s",
-                                       lttng_domain_type_str(dom.type),
-                                       channel_name, session_name);
-                       enabled = 0;
-                       success = 1;
-               }
-
-               /* Print the channel */
-               if (lttng_opt_mi) {
-                       ret = mi_partial_channel_print(channel_name, enabled, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-
-               /* Next channel */
-               channel_name = strtok(NULL, ",");
-       }
-
-       ret = CMD_SUCCESS;
-
-       /* Close Mi */
-       if (lttng_opt_mi) {
-               /* Close channels element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-error:
-       /* Bypass the warning if a more important error happened */
-       if (!ret && warn) {
-               ret = CMD_WARNING;
-       }
-
-       lttng_destroy_handle(handle);
-
-       return ret;
-}
-
-/*
- *  cmd_disable_channels
- *
- *  Disable channel to trace session
- */
-int cmd_disable_channels(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_USERSPACE:
-                       opt_userspace = 1;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace, false);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       opt_channels = (char*) poptGetArg(pc);
-       if (opt_channels == NULL) {
-               ERR("Missing channel name(s).\n");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_disable_channel);
-               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;
-               }
-       }
-
-       command_ret = disable_channels(session_name);
-       if (command_ret) {
-               success = 0;
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_success, success);
-               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;
-       }
-
-       if (!opt_session_name && session_name) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred in disable_channels */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/disable_channels.cpp b/src/bin/lttng/commands/disable_channels.cpp
new file mode 100644 (file)
index 0000000..cf9f20b
--- /dev/null
@@ -0,0 +1,334 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+#include <lttng/domain-internal.h>
+
+#include "../command.h"
+
+static char *opt_channels;
+static int opt_kernel;
+static char *opt_session_name;
+static int opt_userspace;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-disable-channel.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_USERSPACE,
+       OPT_LIST_OPTIONS,
+};
+
+static struct lttng_handle *handle;
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int mi_partial_channel_print(char *channel_name, unsigned int enabled,
+               int success)
+{
+       int ret;
+
+       LTTNG_ASSERT(writer);
+       LTTNG_ASSERT(channel_name);
+
+       /* Open channel element */
+       ret = mi_lttng_writer_open_element(writer, config_element_channel);
+       if (ret) {
+               goto end;
+       }
+
+       /* Name */
+       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
+                       channel_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Enabled ? */
+       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
+                       enabled);
+       if (ret) {
+               goto end;
+       }
+
+       /* Success ? */
+       ret = mi_lttng_writer_write_element_bool(writer,
+                       mi_lttng_element_success, success);
+       if (ret) {
+               goto end;
+       }
+
+       /* Closing channel element */
+       ret = mi_lttng_writer_close_element(writer);
+
+end:
+       return ret;
+}
+
+/*
+ * Disabling channel using the lttng API.
+ */
+static int disable_channels(char *session_name)
+{
+       int ret = CMD_SUCCESS, warn = 0, success;
+
+       /* Normal case for disable channed is enabled = 0 */
+       unsigned int enabled = 0;
+       char *channel_name;
+       struct lttng_domain dom;
+
+       memset(&dom, 0, sizeof(dom));
+
+       /* Create lttng domain */
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+       } else if (opt_userspace) {
+               dom.type = LTTNG_DOMAIN_UST;
+       } else {
+               /* Checked by the caller. */
+               abort();
+       }
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Prepare MI */
+       if (lttng_opt_mi) {
+               /* open a channels element */
+               ret = mi_lttng_writer_open_element(writer, config_element_channels);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+       }
+
+       /* Strip channel list */
+       channel_name = strtok(opt_channels, ",");
+       while (channel_name != NULL) {
+               DBG("Disabling channel %s", channel_name);
+
+               ret = lttng_disable_channel(handle, channel_name);
+               if (ret < 0) {
+                       ERR("Channel %s: %s (session %s)", channel_name,
+                                       lttng_strerror(ret), session_name);
+                       warn = 1;
+
+                       /*
+                        * Mi:
+                        * We assume that if an error occurred the channel is still active.
+                        * This might not be the case but is a good assumption.
+                        * The client should look at the stderr stream
+                        * for more informations.
+                        */
+                       enabled = 1;
+                       success = 0;
+
+               } else {
+                       MSG("%s channel %s disabled for session %s",
+                                       lttng_domain_type_str(dom.type),
+                                       channel_name, session_name);
+                       enabled = 0;
+                       success = 1;
+               }
+
+               /* Print the channel */
+               if (lttng_opt_mi) {
+                       ret = mi_partial_channel_print(channel_name, enabled, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+
+               /* Next channel */
+               channel_name = strtok(NULL, ",");
+       }
+
+       ret = CMD_SUCCESS;
+
+       /* Close Mi */
+       if (lttng_opt_mi) {
+               /* Close channels element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+error:
+       /* Bypass the warning if a more important error happened */
+       if (!ret && warn) {
+               ret = CMD_WARNING;
+       }
+
+       lttng_destroy_handle(handle);
+
+       return ret;
+}
+
+/*
+ *  cmd_disable_channels
+ *
+ *  Disable channel to trace session
+ */
+int cmd_disable_channels(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_USERSPACE:
+                       opt_userspace = 1;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       opt_channels = (char*) poptGetArg(pc);
+       if (opt_channels == NULL) {
+               ERR("Missing channel name(s).\n");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_disable_channel);
+               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;
+               }
+       }
+
+       command_ret = disable_channels(session_name);
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_success, success);
+               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;
+       }
+
+       if (!opt_session_name && session_name) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred in disable_channels */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/disable_events.c b/src/bin/lttng/commands/disable_events.c
deleted file mode 100644 (file)
index 687da1f..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-#include <lttng/domain-internal.h>
-
-#include "../command.h"
-
-static char *opt_event_list;
-static int opt_kernel;
-static char *opt_channel_name;
-static char *opt_session_name;
-static int opt_userspace;
-static int opt_disable_all;
-static int opt_jul;
-static int opt_log4j;
-static int opt_python;
-static int opt_event_type;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-disable-event.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_TYPE_SYSCALL,
-       OPT_TYPE_TRACEPOINT,
-       OPT_TYPE_PROBE,
-       OPT_TYPE_FUNCTION,
-       OPT_TYPE_ALL,
-       OPT_LIST_OPTIONS,
-};
-
-static struct lttng_handle *handle;
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"all-events",     'a', POPT_ARG_VAL, &opt_disable_all, 1, 0, 0},
-       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
-       {"jul",            'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
-       {"log4j",          'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
-       {"python",         'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
-       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"userspace",      'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0},
-       {"syscall",          0, POPT_ARG_NONE, 0, OPT_TYPE_SYSCALL, 0, 0},
-       {"probe",            0, POPT_ARG_NONE, 0, OPT_TYPE_PROBE, 0, 0},
-       {"tracepoint",       0, POPT_ARG_NONE, 0, OPT_TYPE_TRACEPOINT, 0, 0},
-       {"function",         0, POPT_ARG_NONE, 0, OPT_TYPE_FUNCTION, 0, 0},
-       {"all",              0, POPT_ARG_NONE, 0, OPT_TYPE_ALL, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static
-const char *print_channel_name(const char *name)
-{
-       return name ? : DEFAULT_CHANNEL_NAME;
-}
-
-static
-const char *print_raw_channel_name(const char *name)
-{
-       return name ? : "<default>";
-}
-
-static
-const char *print_event_type(const enum lttng_event_type ev_type)
-{
-       switch (ev_type) {
-       case LTTNG_EVENT_ALL:
-               return "any";
-       case LTTNG_EVENT_TRACEPOINT:
-               return "tracepoint";
-       case LTTNG_EVENT_PROBE:
-               return "probe";
-       case LTTNG_EVENT_FUNCTION:
-               return "function";
-       case LTTNG_EVENT_FUNCTION_ENTRY:
-               return "function entry";
-       case LTTNG_EVENT_SYSCALL:
-               return "syscall";
-       default:
-               return "";
-       }
-}
-
-/* Mi print a partial event.
- * enabled is 0 or 1
- * success is 0 or 1
- */
-static int mi_print_event(const char *event_name, int enabled, int success)
-{
-       int ret;
-
-       LTTNG_ASSERT(writer);
-       LTTNG_ASSERT(event_name);
-
-       /* Open event element */
-       ret = mi_lttng_writer_open_element(writer, config_element_event);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print the name of event */
-       ret = mi_lttng_writer_write_element_string(writer,
-                       config_element_name, event_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print enabled ? */
-       ret = mi_lttng_writer_write_element_bool(writer,
-                       config_element_enabled, enabled);
-       if (ret) {
-               goto end;
-       }
-
-       /* Success ? */
-       ret = mi_lttng_writer_write_element_bool(writer,
-                       mi_lttng_element_command_success, success);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close event element */
-       ret = mi_lttng_writer_close_element(writer);
-end:
-       return ret;
-}
-
-/*
- *  disable_events
- *
- *  Disabling event using the lttng API.
- */
-static int disable_events(char *session_name)
-{
-       int ret = CMD_SUCCESS, warn = 0, command_ret = CMD_SUCCESS;
-       int enabled = 1, success = 1;
-       char *event_name, *channel_name = NULL;
-       struct lttng_domain dom;
-       struct lttng_event event;
-
-       memset(&dom, 0, sizeof(dom));
-
-       /* Create lttng domain */
-       if (opt_kernel) {
-               dom.type = LTTNG_DOMAIN_KERNEL;
-       } else if (opt_userspace) {
-               dom.type = LTTNG_DOMAIN_UST;
-       } else if (opt_jul) {
-               dom.type = LTTNG_DOMAIN_JUL;
-       } else if (opt_log4j) {
-               dom.type = LTTNG_DOMAIN_LOG4J;
-       } else if (opt_python) {
-               dom.type = LTTNG_DOMAIN_PYTHON;
-       } else {
-               /* Checked by the caller. */
-               abort();
-       }
-
-       channel_name = opt_channel_name;
-
-       handle = lttng_create_handle(session_name, &dom);
-       if (handle == NULL) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Mi print the channel and open the events element */
-       if (lttng_opt_mi) {
-               ret = mi_lttng_writer_open_element(writer, config_element_channel);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               ret = mi_lttng_writer_write_element_string(writer,
-                               config_element_name, print_channel_name(channel_name));
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open events element */
-               ret = mi_lttng_writer_open_element(writer, config_element_events);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       memset(&event, 0, sizeof(event));
-       /* Set default loglevel to any/unknown */
-       event.loglevel = -1;
-
-       /* opt_event_type contain the event type to disable at this point */
-       event.type = opt_event_type;
-
-       if (opt_disable_all) {
-               command_ret = lttng_disable_event_ext(handle, &event, channel_name, NULL);
-               if (command_ret < 0) {
-                       ERR("%s", lttng_strerror(command_ret));
-                       enabled = 1;
-                       success = 0;
-
-               } else {
-                       enabled = 0;
-                       success = 1;
-                       MSG("All %s events of type %s are disabled in channel %s",
-                                       lttng_domain_type_str(dom.type),
-                                       print_event_type(opt_event_type),
-                                       print_channel_name(channel_name));
-               }
-
-               if (lttng_opt_mi) {
-                       ret = mi_print_event("*", enabled, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-       } else {
-               /* Strip event list */
-               event_name = strtok(opt_event_list, ",");
-               while (event_name != NULL) {
-                       DBG("Disabling event %s", event_name);
-
-                       strncpy(event.name, event_name, sizeof(event.name));
-                       event.name[sizeof(event.name) - 1] = '\0';
-                       command_ret = lttng_disable_event_ext(handle, &event, channel_name, NULL);
-                       if (command_ret < 0) {
-                               ERR("%s of type %s : %s (channel %s, session %s)",
-                                               event_name,
-                                               print_event_type(opt_event_type),
-                                               lttng_strerror(command_ret),
-                                               command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
-                                                       ? print_raw_channel_name(channel_name)
-                                                       : print_channel_name(channel_name),
-                                               session_name);
-                               warn = 1;
-                               success = 0;
-                               /*
-                                * If an error occurred we assume that the event is still
-                                * enabled.
-                                */
-                               enabled = 1;
-                       } else {
-                               MSG("%s %s of type %s disabled in channel %s for session %s",
-                                               lttng_domain_type_str(dom.type),
-                                               event_name,
-                                               print_event_type(opt_event_type),
-                                               print_channel_name(channel_name),
-                                               session_name);
-                               success = 1;
-                               enabled = 0;
-                       }
-
-                       if (lttng_opt_mi) {
-                               ret = mi_print_event(event_name, enabled, success);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-                       }
-
-                       /* Next event */
-                       event_name = strtok(NULL, ",");
-               }
-       }
-
-end:
-       if (lttng_opt_mi) {
-               /* Close events element and channel element */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       ret = CMD_ERROR;
-               }
-       }
-error:
-       /* if there is already an error preserve it */
-       if (warn && !ret) {
-               ret = CMD_WARNING;
-       }
-
-       /* Overwrite ret if an error occurred */
-       ret = command_ret ? command_ret : ret;
-
-       lttng_destroy_handle(handle);
-       return ret;
-}
-
-/*
- *  cmd_disable_events
- *
- *  Disable event to trace session
- */
-int cmd_disable_events(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-       int event_type = -1;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       /* Default event type */
-       opt_event_type = LTTNG_EVENT_ALL;
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_TYPE_SYSCALL:
-                       opt_event_type = LTTNG_EVENT_SYSCALL;
-                       break;
-               case OPT_TYPE_TRACEPOINT:
-                       opt_event_type = LTTNG_EVENT_TRACEPOINT;
-                       break;
-               case OPT_TYPE_PROBE:
-                       opt_event_type = LTTNG_EVENT_PROBE;
-                       break;
-               case OPT_TYPE_FUNCTION:
-                       opt_event_type = LTTNG_EVENT_FUNCTION;
-                       break;
-               case OPT_TYPE_ALL:
-                       opt_event_type = LTTNG_EVENT_ALL;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-
-               /* Validate event type. Multiple event type are not supported. */
-               if (event_type == -1) {
-                       event_type = opt_event_type;
-               } else {
-                       if (event_type != opt_event_type) {
-                               ERR("Multiple event type not supported.");
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace + opt_jul + opt_log4j +
-                                       opt_python,
-                       true);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Ust and agent only support ALL event type */
-       if ((opt_userspace || opt_jul || opt_log4j || opt_python)
-                       && opt_event_type != LTTNG_EVENT_ALL) {
-               ERR("Disabling userspace and agent (-j | -l | -p) event(s) based on instrumentation type is not supported.\n");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       opt_event_list = (char*) poptGetArg(pc);
-       if (opt_event_list == NULL && opt_disable_all == 0) {
-               ERR("Missing event name(s).\n");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_disable_event);
-               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;
-               }
-       }
-
-       command_ret = disable_events(session_name);
-       if (command_ret) {
-               success = 0;
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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:
-       if (!opt_session_name && session_name) {
-               free(session_name);
-       }
-
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
-       }
-
-       /* Overwrite ret if an error occurred in disable_events */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/disable_events.cpp b/src/bin/lttng/commands/disable_events.cpp
new file mode 100644 (file)
index 0000000..5ce36e5
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+#include <lttng/domain-internal.h>
+
+#include "../command.h"
+
+static char *opt_event_list;
+static int opt_kernel;
+static char *opt_channel_name;
+static char *opt_session_name;
+static int opt_userspace;
+static int opt_disable_all;
+static int opt_jul;
+static int opt_log4j;
+static int opt_python;
+static int opt_event_type;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-disable-event.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_TYPE_SYSCALL,
+       OPT_TYPE_TRACEPOINT,
+       OPT_TYPE_PROBE,
+       OPT_TYPE_FUNCTION,
+       OPT_TYPE_ALL,
+       OPT_LIST_OPTIONS,
+};
+
+static struct lttng_handle *handle;
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"all-events",     'a', POPT_ARG_VAL, &opt_disable_all, 1, 0, 0},
+       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
+       {"jul",            'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
+       {"log4j",          'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
+       {"python",         'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
+       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"userspace",      'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0},
+       {"syscall",          0, POPT_ARG_NONE, 0, OPT_TYPE_SYSCALL, 0, 0},
+       {"probe",            0, POPT_ARG_NONE, 0, OPT_TYPE_PROBE, 0, 0},
+       {"tracepoint",       0, POPT_ARG_NONE, 0, OPT_TYPE_TRACEPOINT, 0, 0},
+       {"function",         0, POPT_ARG_NONE, 0, OPT_TYPE_FUNCTION, 0, 0},
+       {"all",              0, POPT_ARG_NONE, 0, OPT_TYPE_ALL, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static
+const char *print_channel_name(const char *name)
+{
+       return name ? : DEFAULT_CHANNEL_NAME;
+}
+
+static
+const char *print_raw_channel_name(const char *name)
+{
+       return name ? : "<default>";
+}
+
+static
+const char *print_event_type(const enum lttng_event_type ev_type)
+{
+       switch (ev_type) {
+       case LTTNG_EVENT_ALL:
+               return "any";
+       case LTTNG_EVENT_TRACEPOINT:
+               return "tracepoint";
+       case LTTNG_EVENT_PROBE:
+               return "probe";
+       case LTTNG_EVENT_FUNCTION:
+               return "function";
+       case LTTNG_EVENT_FUNCTION_ENTRY:
+               return "function entry";
+       case LTTNG_EVENT_SYSCALL:
+               return "syscall";
+       default:
+               return "";
+       }
+}
+
+/* Mi print a partial event.
+ * enabled is 0 or 1
+ * success is 0 or 1
+ */
+static int mi_print_event(const char *event_name, int enabled, int success)
+{
+       int ret;
+
+       LTTNG_ASSERT(writer);
+       LTTNG_ASSERT(event_name);
+
+       /* Open event element */
+       ret = mi_lttng_writer_open_element(writer, config_element_event);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print the name of event */
+       ret = mi_lttng_writer_write_element_string(writer,
+                       config_element_name, event_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print enabled ? */
+       ret = mi_lttng_writer_write_element_bool(writer,
+                       config_element_enabled, enabled);
+       if (ret) {
+               goto end;
+       }
+
+       /* Success ? */
+       ret = mi_lttng_writer_write_element_bool(writer,
+                       mi_lttng_element_command_success, success);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close event element */
+       ret = mi_lttng_writer_close_element(writer);
+end:
+       return ret;
+}
+
+/*
+ *  disable_events
+ *
+ *  Disabling event using the lttng API.
+ */
+static int disable_events(char *session_name)
+{
+       int ret = CMD_SUCCESS, warn = 0, command_ret = CMD_SUCCESS;
+       int enabled = 1, success = 1;
+       char *event_name, *channel_name = NULL;
+       struct lttng_domain dom;
+       struct lttng_event event;
+
+       memset(&dom, 0, sizeof(dom));
+
+       /* Create lttng domain */
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+       } else if (opt_userspace) {
+               dom.type = LTTNG_DOMAIN_UST;
+       } else if (opt_jul) {
+               dom.type = LTTNG_DOMAIN_JUL;
+       } else if (opt_log4j) {
+               dom.type = LTTNG_DOMAIN_LOG4J;
+       } else if (opt_python) {
+               dom.type = LTTNG_DOMAIN_PYTHON;
+       } else {
+               /* Checked by the caller. */
+               abort();
+       }
+
+       channel_name = opt_channel_name;
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Mi print the channel and open the events element */
+       if (lttng_opt_mi) {
+               ret = mi_lttng_writer_open_element(writer, config_element_channel);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               ret = mi_lttng_writer_write_element_string(writer,
+                               config_element_name, print_channel_name(channel_name));
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open events element */
+               ret = mi_lttng_writer_open_element(writer, config_element_events);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       memset(&event, 0, sizeof(event));
+       /* Set default loglevel to any/unknown */
+       event.loglevel = -1;
+
+       /* opt_event_type contain the event type to disable at this point */
+       event.type = (lttng_event_type) opt_event_type;
+
+       if (opt_disable_all) {
+               command_ret = lttng_disable_event_ext(handle, &event, channel_name, NULL);
+               if (command_ret < 0) {
+                       ERR("%s", lttng_strerror(command_ret));
+                       enabled = 1;
+                       success = 0;
+
+               } else {
+                       enabled = 0;
+                       success = 1;
+                       MSG("All %s events of type %s are disabled in channel %s",
+                                       lttng_domain_type_str(dom.type),
+                                       print_event_type((lttng_event_type) opt_event_type),
+                                       print_channel_name(channel_name));
+               }
+
+               if (lttng_opt_mi) {
+                       ret = mi_print_event("*", enabled, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+       } else {
+               /* Strip event list */
+               event_name = strtok(opt_event_list, ",");
+               while (event_name != NULL) {
+                       DBG("Disabling event %s", event_name);
+
+                       strncpy(event.name, event_name, sizeof(event.name));
+                       event.name[sizeof(event.name) - 1] = '\0';
+                       command_ret = lttng_disable_event_ext(handle, &event, channel_name, NULL);
+                       if (command_ret < 0) {
+                               ERR("%s of type %s : %s (channel %s, session %s)",
+                                               event_name,
+                                               print_event_type((lttng_event_type) opt_event_type),
+                                               lttng_strerror(command_ret),
+                                               command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
+                                                       ? print_raw_channel_name(channel_name)
+                                                       : print_channel_name(channel_name),
+                                               session_name);
+                               warn = 1;
+                               success = 0;
+                               /*
+                                * If an error occurred we assume that the event is still
+                                * enabled.
+                                */
+                               enabled = 1;
+                       } else {
+                               MSG("%s %s of type %s disabled in channel %s for session %s",
+                                               lttng_domain_type_str(dom.type),
+                                               event_name,
+                                               print_event_type((lttng_event_type) opt_event_type),
+                                               print_channel_name(channel_name),
+                                               session_name);
+                               success = 1;
+                               enabled = 0;
+                       }
+
+                       if (lttng_opt_mi) {
+                               ret = mi_print_event(event_name, enabled, success);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                       }
+
+                       /* Next event */
+                       event_name = strtok(NULL, ",");
+               }
+       }
+
+end:
+       if (lttng_opt_mi) {
+               /* Close events element and channel element */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       ret = CMD_ERROR;
+               }
+       }
+error:
+       /* if there is already an error preserve it */
+       if (warn && !ret) {
+               ret = CMD_WARNING;
+       }
+
+       /* Overwrite ret if an error occurred */
+       ret = command_ret ? command_ret : ret;
+
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ *  cmd_disable_events
+ *
+ *  Disable event to trace session
+ */
+int cmd_disable_events(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+       int event_type = -1;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       /* Default event type */
+       opt_event_type = LTTNG_EVENT_ALL;
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_TYPE_SYSCALL:
+                       opt_event_type = LTTNG_EVENT_SYSCALL;
+                       break;
+               case OPT_TYPE_TRACEPOINT:
+                       opt_event_type = LTTNG_EVENT_TRACEPOINT;
+                       break;
+               case OPT_TYPE_PROBE:
+                       opt_event_type = LTTNG_EVENT_PROBE;
+                       break;
+               case OPT_TYPE_FUNCTION:
+                       opt_event_type = LTTNG_EVENT_FUNCTION;
+                       break;
+               case OPT_TYPE_ALL:
+                       opt_event_type = LTTNG_EVENT_ALL;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+
+               /* Validate event type. Multiple event type are not supported. */
+               if (event_type == -1) {
+                       event_type = opt_event_type;
+               } else {
+                       if (event_type != opt_event_type) {
+                               ERR("Multiple event type not supported.");
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace + opt_jul + opt_log4j +
+                                       opt_python,
+                       true);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Ust and agent only support ALL event type */
+       if ((opt_userspace || opt_jul || opt_log4j || opt_python)
+                       && opt_event_type != LTTNG_EVENT_ALL) {
+               ERR("Disabling userspace and agent (-j | -l | -p) event(s) based on instrumentation type is not supported.\n");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       opt_event_list = (char*) poptGetArg(pc);
+       if (opt_event_list == NULL && opt_disable_all == 0) {
+               ERR("Missing event name(s).\n");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_disable_event);
+               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;
+               }
+       }
+
+       command_ret = disable_events(session_name);
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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:
+       if (!opt_session_name && session_name) {
+               free(session_name);
+       }
+
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : LTTNG_ERR_MI_IO_FAIL;
+       }
+
+       /* Overwrite ret if an error occurred in disable_events */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/disable_rotation.c b/src/bin/lttng/commands/disable_rotation.c
deleted file mode 100644 (file)
index ff5749c..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-#include <lttng/lttng.h>
-
-static char *opt_session_name;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-disable-rotation.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_TIMER,
-       OPT_SIZE,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h',  POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0,   POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"session",     's',  POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"timer",        0,   POPT_ARG_NONE, 0, OPT_TIMER, 0, 0},
-       {"size",         0,   POPT_ARG_NONE, 0, OPT_SIZE, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static const char *schedule_type_str[] = {
-       [LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC] = "periodic",
-       [LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD] = "size-based",
-};
-
-static const struct lttng_rotation_schedule *get_schedule(
-               const char *session_name,
-               const struct lttng_rotation_schedules *schedules,
-               enum lttng_rotation_schedule_type schedule_type)
-{
-       unsigned int count, i;
-       enum lttng_rotation_status status;
-       const struct lttng_rotation_schedule *ret = NULL;
-
-       status = lttng_rotation_schedules_get_count(schedules, &count);
-       if (status != LTTNG_ROTATION_STATUS_OK) {
-               ERR("Unable to determine the number of rotation schedules of session %s",
-                               session_name);
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               const struct lttng_rotation_schedule *schedule = NULL;
-
-               schedule = lttng_rotation_schedules_get_at_index(schedules, i);
-               if (!schedule) {
-                       ERR("Unable to retrieve rotation schedule at index %u",
-                                       i);
-                       goto end;
-               }
-
-               if (lttng_rotation_schedule_get_type(schedule) ==
-                               schedule_type) {
-                       ret = schedule;
-                       break;
-               }
-       }
-
-       if (!ret) {
-               ERR("No %s rotation schedule active on session %s",
-                               schedule_type_str[schedule_type], session_name);
-       }
-end:
-       return ret;
-}
-
-static struct lttng_rotation_schedule *create_empty_schedule(
-               enum lttng_rotation_schedule_type type)
-{
-       struct lttng_rotation_schedule *schedule = NULL;
-
-       switch (type) {
-       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
-               schedule = lttng_rotation_schedule_periodic_create();
-               break;
-       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
-               schedule = lttng_rotation_schedule_size_threshold_create();
-               break;
-       default:
-               abort();
-       }
-       return schedule;
-}
-
-static enum cmd_error_code remove_schedule(const char *session_name,
-               enum lttng_rotation_schedule_type schedule_type)
-{
-       enum cmd_error_code cmd_ret;
-       int ret;
-       const struct lttng_rotation_schedule *schedule = NULL;
-       struct lttng_rotation_schedules *schedules = NULL;
-       enum lttng_rotation_status status;
-       const char *schedule_type_name;
-       struct lttng_rotation_schedule *empty_schedule = NULL;
-
-       switch (schedule_type) {
-       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
-       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
-               break;
-       default:
-               ERR("Unknown schedule type");
-               abort();
-       }
-
-       schedule_type_name = schedule_type_str[schedule_type];
-
-       ret = lttng_session_list_rotation_schedules(session_name, &schedules);
-       if (ret != LTTNG_OK) {
-               ERR("Failed to list rotation schedules of session %s",
-                               session_name);
-               goto error;
-       }
-
-       schedule = get_schedule(session_name, schedules, schedule_type);
-       if (!schedule) {
-               cmd_ret = CMD_ERROR;
-               /*
-                * get_schedule() logs its own errors.
-                * A temporaty schedule is created to serialize an MI rotation
-                * schedule descriptor of the appropriate type that has no
-                * attributes set.
-                */
-               empty_schedule = create_empty_schedule(schedule_type);
-               if (!empty_schedule) {
-                       goto error;
-               }
-               goto skip_removal;
-       }
-
-       status = lttng_session_remove_rotation_schedule(session_name, schedule);
-       switch (status) {
-       case LTTNG_ROTATION_STATUS_OK:
-               MSG("Disabled %s rotation on session %s",
-                               schedule_type_name, session_name);
-               cmd_ret = CMD_SUCCESS;
-               break;
-       case LTTNG_ROTATION_STATUS_SCHEDULE_NOT_SET:
-               ERR("No %s rotation schedule set on session %s",
-                               schedule_type_name,
-                               session_name);
-               cmd_ret = CMD_ERROR;
-               break;
-       case LTTNG_ROTATION_STATUS_ERROR:
-       case LTTNG_ROTATION_STATUS_INVALID:
-       default:
-               ERR("Failed to disable %s rotation schedule on session %s",
-                               schedule_type_name, session_name);
-               cmd_ret = CMD_ERROR;
-               break;
-       }
-
-skip_removal:
-       if (lttng_opt_mi) {
-               ret = mi_lttng_rotation_schedule_result(writer,
-                               schedule ? schedule : empty_schedule,
-                               cmd_ret == CMD_SUCCESS);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-end:
-       lttng_rotation_schedules_destroy(schedules);
-       lttng_rotation_schedule_destroy(empty_schedule);
-       return cmd_ret;
-error:
-       cmd_ret = CMD_ERROR;
-       goto end;
-}
-
-/*
- *  cmd_disable_rotation
- *
- *  The 'disable-rotation <options>' first level command
- */
-int cmd_disable_rotation(int argc, const char **argv)
-{
-       int popt_ret, opt, ret = 0;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       static poptContext pc;
-       char *session_name = NULL;
-       bool free_session_name = false;
-       bool periodic_rotation = false, size_rotation = false;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       popt_ret = poptReadDefaultConfig(pc, 0);
-       if (popt_ret) {
-               cmd_ret = CMD_ERROR;
-               ERR("poptReadDefaultConfig");
-               goto end;
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_TIMER:
-                       periodic_rotation = true;
-                       break;
-               case OPT_SIZE:
-                       size_rotation = true;
-                       break;
-               default:
-                       cmd_ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (opt_session_name == NULL) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       goto error;
-               }
-               free_session_name = true;
-       } else {
-               session_name = opt_session_name;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       goto error;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_disable_rotation);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (!periodic_rotation && !size_rotation) {
-               ERR("No session rotation schedule type provided.");
-               cmd_ret = CMD_ERROR;
-               goto close_command;
-       }
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_rotation_schedule_results);
-               if (ret) {
-                       goto error;
-               }
-
-               ret = mi_lttng_writer_write_element_string(writer,
-                               mi_lttng_element_session_name,
-                               session_name);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (periodic_rotation) {
-               /*
-                * Continue processing even on error as multiple schedules can
-                * be specified at once.
-                */
-               cmd_ret = remove_schedule(session_name,
-                               LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC);
-       }
-
-       if (size_rotation) {
-               enum cmd_error_code tmp_ret;
-
-               /* Don't overwrite cmd_ret if it already indicates an error. */
-               tmp_ret = remove_schedule(session_name,
-                               LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD);
-               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close rotation schedule results element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-close_command:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success,
-                               cmd_ret == CMD_SUCCESS);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-end:
-       (void) mi_lttng_writer_destroy(writer);
-       poptFreeContext(pc);
-       if (free_session_name) {
-               free(session_name);
-       }
-       return cmd_ret;
-error:
-       cmd_ret = CMD_ERROR;
-       goto end;
-}
diff --git a/src/bin/lttng/commands/disable_rotation.cpp b/src/bin/lttng/commands/disable_rotation.cpp
new file mode 100644 (file)
index 0000000..8229f63
--- /dev/null
@@ -0,0 +1,356 @@
+/*
+ * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include <lttng/lttng.h>
+
+static char *opt_session_name;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-disable-rotation.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_TIMER,
+       OPT_SIZE,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h',  POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0,   POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"session",     's',  POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"timer",        0,   POPT_ARG_NONE, 0, OPT_TIMER, 0, 0},
+       {"size",         0,   POPT_ARG_NONE, 0, OPT_SIZE, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static const char *schedule_type_str[] = {
+       "periodic",
+       "size-based",
+};
+
+static const struct lttng_rotation_schedule *get_schedule(
+               const char *session_name,
+               const struct lttng_rotation_schedules *schedules,
+               enum lttng_rotation_schedule_type schedule_type)
+{
+       unsigned int count, i;
+       enum lttng_rotation_status status;
+       const struct lttng_rotation_schedule *ret = NULL;
+
+       status = lttng_rotation_schedules_get_count(schedules, &count);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               ERR("Unable to determine the number of rotation schedules of session %s",
+                               session_name);
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_rotation_schedule *schedule = NULL;
+
+               schedule = lttng_rotation_schedules_get_at_index(schedules, i);
+               if (!schedule) {
+                       ERR("Unable to retrieve rotation schedule at index %u",
+                                       i);
+                       goto end;
+               }
+
+               if (lttng_rotation_schedule_get_type(schedule) ==
+                               schedule_type) {
+                       ret = schedule;
+                       break;
+               }
+       }
+
+       if (!ret) {
+               ERR("No %s rotation schedule active on session %s",
+                               schedule_type_str[schedule_type], session_name);
+       }
+end:
+       return ret;
+}
+
+static struct lttng_rotation_schedule *create_empty_schedule(
+               enum lttng_rotation_schedule_type type)
+{
+       struct lttng_rotation_schedule *schedule = NULL;
+
+       switch (type) {
+       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
+               schedule = lttng_rotation_schedule_periodic_create();
+               break;
+       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
+               schedule = lttng_rotation_schedule_size_threshold_create();
+               break;
+       default:
+               abort();
+       }
+       return schedule;
+}
+
+static enum cmd_error_code remove_schedule(const char *session_name,
+               enum lttng_rotation_schedule_type schedule_type)
+{
+       enum cmd_error_code cmd_ret;
+       int ret;
+       const struct lttng_rotation_schedule *schedule = NULL;
+       struct lttng_rotation_schedules *schedules = NULL;
+       enum lttng_rotation_status status;
+       const char *schedule_type_name;
+       struct lttng_rotation_schedule *empty_schedule = NULL;
+
+       switch (schedule_type) {
+       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
+       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
+               break;
+       default:
+               ERR("Unknown schedule type");
+               abort();
+       }
+
+       schedule_type_name = schedule_type_str[schedule_type];
+
+       ret = lttng_session_list_rotation_schedules(session_name, &schedules);
+       if (ret != LTTNG_OK) {
+               ERR("Failed to list rotation schedules of session %s",
+                               session_name);
+               goto error;
+       }
+
+       schedule = get_schedule(session_name, schedules, schedule_type);
+       if (!schedule) {
+               cmd_ret = CMD_ERROR;
+               /*
+                * get_schedule() logs its own errors.
+                * A temporaty schedule is created to serialize an MI rotation
+                * schedule descriptor of the appropriate type that has no
+                * attributes set.
+                */
+               empty_schedule = create_empty_schedule(schedule_type);
+               if (!empty_schedule) {
+                       goto error;
+               }
+               goto skip_removal;
+       }
+
+       status = lttng_session_remove_rotation_schedule(session_name, schedule);
+       switch (status) {
+       case LTTNG_ROTATION_STATUS_OK:
+               MSG("Disabled %s rotation on session %s",
+                               schedule_type_name, session_name);
+               cmd_ret = CMD_SUCCESS;
+               break;
+       case LTTNG_ROTATION_STATUS_SCHEDULE_NOT_SET:
+               ERR("No %s rotation schedule set on session %s",
+                               schedule_type_name,
+                               session_name);
+               cmd_ret = CMD_ERROR;
+               break;
+       case LTTNG_ROTATION_STATUS_ERROR:
+       case LTTNG_ROTATION_STATUS_INVALID:
+       default:
+               ERR("Failed to disable %s rotation schedule on session %s",
+                               schedule_type_name, session_name);
+               cmd_ret = CMD_ERROR;
+               break;
+       }
+
+skip_removal:
+       if (lttng_opt_mi) {
+               ret = mi_lttng_rotation_schedule_result(writer,
+                               schedule ? schedule : empty_schedule,
+                               cmd_ret == CMD_SUCCESS);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+end:
+       lttng_rotation_schedules_destroy(schedules);
+       lttng_rotation_schedule_destroy(empty_schedule);
+       return cmd_ret;
+error:
+       cmd_ret = CMD_ERROR;
+       goto end;
+}
+
+/*
+ *  cmd_disable_rotation
+ *
+ *  The 'disable-rotation <options>' first level command
+ */
+int cmd_disable_rotation(int argc, const char **argv)
+{
+       int popt_ret, opt, ret = 0;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       static poptContext pc;
+       char *session_name = NULL;
+       bool free_session_name = false;
+       bool periodic_rotation = false, size_rotation = false;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       popt_ret = poptReadDefaultConfig(pc, 0);
+       if (popt_ret) {
+               cmd_ret = CMD_ERROR;
+               ERR("poptReadDefaultConfig");
+               goto end;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_TIMER:
+                       periodic_rotation = true;
+                       break;
+               case OPT_SIZE:
+                       size_rotation = true;
+                       break;
+               default:
+                       cmd_ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+               free_session_name = true;
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       goto error;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_disable_rotation);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (!periodic_rotation && !size_rotation) {
+               ERR("No session rotation schedule type provided.");
+               cmd_ret = CMD_ERROR;
+               goto close_command;
+       }
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_rotation_schedule_results);
+               if (ret) {
+                       goto error;
+               }
+
+               ret = mi_lttng_writer_write_element_string(writer,
+                               mi_lttng_element_session_name,
+                               session_name);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (periodic_rotation) {
+               /*
+                * Continue processing even on error as multiple schedules can
+                * be specified at once.
+                */
+               cmd_ret = remove_schedule(session_name,
+                               LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC);
+       }
+
+       if (size_rotation) {
+               enum cmd_error_code tmp_ret;
+
+               /* Don't overwrite cmd_ret if it already indicates an error. */
+               tmp_ret = remove_schedule(session_name,
+                               LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD);
+               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close rotation schedule results element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+close_command:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success,
+                               cmd_ret == CMD_SUCCESS);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+end:
+       (void) mi_lttng_writer_destroy(writer);
+       poptFreeContext(pc);
+       if (free_session_name) {
+               free(session_name);
+       }
+       return cmd_ret;
+error:
+       cmd_ret = CMD_ERROR;
+       goto end;
+}
diff --git a/src/bin/lttng/commands/enable_channels.c b/src/bin/lttng/commands/enable_channels.c
deleted file mode 100644 (file)
index 194ec54..0000000
+++ /dev/null
@@ -1,759 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/utils.h>
-#include <common/mi-lttng.h>
-
-#include <lttng/domain-internal.h>
-
-#include "../command.h"
-#include "../utils.h"
-
-
-static struct lttng_channel chan_opts;
-static char *opt_channels;
-static int opt_kernel;
-static char *opt_session_name;
-static int opt_userspace;
-static char *opt_output;
-static int opt_buffer_uid;
-static int opt_buffer_pid;
-static int opt_buffer_global;
-static struct {
-       bool set;
-       uint64_t interval;
-} opt_monitor_timer;
-static struct {
-       bool set;
-       int64_t value;
-} opt_blocking_timeout;
-
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-enable-channel.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_DISCARD,
-       OPT_OVERWRITE,
-       OPT_SUBBUF_SIZE,
-       OPT_NUM_SUBBUF,
-       OPT_SWITCH_TIMER,
-       OPT_MONITOR_TIMER,
-       OPT_READ_TIMER,
-       OPT_USERSPACE,
-       OPT_LIST_OPTIONS,
-       OPT_TRACEFILE_SIZE,
-       OPT_TRACEFILE_COUNT,
-       OPT_BLOCKING_TIMEOUT,
-};
-
-static struct lttng_handle *handle;
-
-const char *output_mmap = "mmap";
-const char *output_splice = "splice";
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-       {"discard",        0,   POPT_ARG_NONE, 0, OPT_DISCARD, 0, 0},
-       {"overwrite",      0,   POPT_ARG_NONE, 0, OPT_OVERWRITE, 0, 0},
-       {"subbuf-size",    0,   POPT_ARG_STRING, 0, OPT_SUBBUF_SIZE, 0, 0},
-       {"num-subbuf",     0,   POPT_ARG_INT, 0, OPT_NUM_SUBBUF, 0, 0},
-       {"switch-timer",   0,   POPT_ARG_INT, 0, OPT_SWITCH_TIMER, 0, 0},
-       {"monitor-timer",  0,   POPT_ARG_INT, 0, OPT_MONITOR_TIMER, 0, 0},
-       {"read-timer",     0,   POPT_ARG_INT, 0, OPT_READ_TIMER, 0, 0},
-       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"output",         0,   POPT_ARG_STRING, &opt_output, 0, 0, 0},
-       {"buffers-uid",    0,   POPT_ARG_VAL, &opt_buffer_uid, 1, 0, 0},
-       {"buffers-pid",    0,   POPT_ARG_VAL, &opt_buffer_pid, 1, 0, 0},
-       {"buffers-global", 0,   POPT_ARG_VAL, &opt_buffer_global, 1, 0, 0},
-       {"tracefile-size", 'C',   POPT_ARG_INT, 0, OPT_TRACEFILE_SIZE, 0, 0},
-       {"tracefile-count", 'W',   POPT_ARG_INT, 0, OPT_TRACEFILE_COUNT, 0, 0},
-       {"blocking-timeout",     0,   POPT_ARG_INT, 0, OPT_BLOCKING_TIMEOUT, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Set default attributes depending on those already defined from the command
- * line.
- */
-static void set_default_attr(struct lttng_domain *dom)
-{
-       struct lttng_channel_attr default_attr;
-
-       memset(&default_attr, 0, sizeof(default_attr));
-
-       /* Set attributes */
-       lttng_channel_set_default_attr(dom, &default_attr);
-
-       if (chan_opts.attr.overwrite == -1) {
-               chan_opts.attr.overwrite = default_attr.overwrite;
-       }
-       if (chan_opts.attr.subbuf_size == -1) {
-               chan_opts.attr.subbuf_size = default_attr.subbuf_size;
-       }
-       if (chan_opts.attr.num_subbuf == -1) {
-               chan_opts.attr.num_subbuf = default_attr.num_subbuf;
-       }
-       if (chan_opts.attr.switch_timer_interval == -1) {
-               chan_opts.attr.switch_timer_interval = default_attr.switch_timer_interval;
-       }
-       if (chan_opts.attr.read_timer_interval == -1) {
-               chan_opts.attr.read_timer_interval = default_attr.read_timer_interval;
-       }
-       if ((int) chan_opts.attr.output == -1) {
-               chan_opts.attr.output = default_attr.output;
-       }
-       if (chan_opts.attr.tracefile_count == -1) {
-               chan_opts.attr.tracefile_count = default_attr.tracefile_count;
-       }
-       if (chan_opts.attr.tracefile_size == -1) {
-               chan_opts.attr.tracefile_size = default_attr.tracefile_size;
-       }
-}
-
-/*
- * Adding channel using the lttng API.
- */
-static int enable_channel(char *session_name)
-{
-       struct lttng_channel *channel = NULL;
-       int ret = CMD_SUCCESS, warn = 0, error = 0, success = 0;
-       char *channel_name;
-       struct lttng_domain dom;
-
-       memset(&dom, 0, sizeof(dom));
-
-       /* Validate options. */
-       if (opt_kernel) {
-               if (opt_blocking_timeout.set) {
-                       ERR("Retry timeout option not supported for kernel domain (-k)");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       /* Create lttng domain */
-       if (opt_kernel) {
-               dom.type = LTTNG_DOMAIN_KERNEL;
-               dom.buf_type = LTTNG_BUFFER_GLOBAL;
-               if (opt_buffer_uid || opt_buffer_pid) {
-                       ERR("Buffer type not supported for domain -k");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       } else if (opt_userspace) {
-               dom.type = LTTNG_DOMAIN_UST;
-               if (opt_buffer_pid) {
-                       dom.buf_type = LTTNG_BUFFER_PER_PID;
-               } else {
-                       if (opt_buffer_global) {
-                               ERR("Buffer type not supported for domain -u");
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-                       dom.buf_type = LTTNG_BUFFER_PER_UID;
-               }
-       } else {
-               /* Checked by the caller. */
-               abort();
-       }
-
-       set_default_attr(&dom);
-
-       if (chan_opts.attr.tracefile_size == 0 && chan_opts.attr.tracefile_count) {
-               ERR("Missing option --tracefile-size. "
-                               "A file count without a size won't do anything.");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if ((chan_opts.attr.tracefile_size > 0) &&
-                       (chan_opts.attr.tracefile_size < chan_opts.attr.subbuf_size)) {
-               WARN("Tracefile size rounded up from (%" PRIu64 ") to subbuffer size (%" PRIu64 ")",
-                               chan_opts.attr.tracefile_size, chan_opts.attr.subbuf_size);
-               chan_opts.attr.tracefile_size = chan_opts.attr.subbuf_size;
-       }
-
-       /* Setting channel output */
-       if (opt_output) {
-               if (!strncmp(output_mmap, opt_output, strlen(output_mmap))) {
-                       chan_opts.attr.output = LTTNG_EVENT_MMAP;
-               } else if (!strncmp(output_splice, opt_output, strlen(output_splice))) {
-                       chan_opts.attr.output = LTTNG_EVENT_SPLICE;
-               } else {
-                       ERR("Unknown output type %s. Possible values are: %s, %s\n",
-                                       opt_output, output_mmap, output_splice);
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       handle = lttng_create_handle(session_name, &dom);
-       if (handle == NULL) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Mi open channels element */
-       if (lttng_opt_mi) {
-               LTTNG_ASSERT(writer);
-               ret = mi_lttng_channels_open(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       /* Strip channel list (format: chan1,chan2,...) */
-       channel_name = strtok(opt_channels, ",");
-       while (channel_name != NULL) {
-               void *extended_ptr;
-
-               /* Validate channel name's length */
-               if (strlen(channel_name) >= sizeof(chan_opts.name)) {
-                       ERR("Channel name is too long (max. %zu characters)",
-                                       sizeof(chan_opts.name) - 1);
-                       error = 1;
-                       goto skip_enable;
-               }
-
-               /*
-                * A dynamically-allocated channel is used in order to allow
-                * the configuration of extended attributes (post-2.9).
-                */
-               channel = lttng_channel_create(&dom);
-               if (!channel) {
-                       ERR("Unable to create channel object");
-                       error = 1;
-                       goto error;
-               }
-
-               /* Copy channel name */
-               strcpy(channel->name, channel_name);
-               channel->enabled = 1;
-               extended_ptr = channel->attr.extended.ptr;
-               memcpy(&channel->attr, &chan_opts.attr, sizeof(chan_opts.attr));
-               channel->attr.extended.ptr = extended_ptr;
-               if (opt_monitor_timer.set) {
-                       ret = lttng_channel_set_monitor_timer_interval(channel,
-                                       opt_monitor_timer.interval);
-                       if (ret) {
-                               ERR("Failed to set the channel's monitor timer interval");
-                               error = 1;
-                               goto error;
-                       }
-               }
-               if (opt_blocking_timeout.set) {
-                       ret = lttng_channel_set_blocking_timeout(channel,
-                                       opt_blocking_timeout.value);
-                       if (ret) {
-                               ERR("Failed to set the channel's blocking timeout");
-                               error = 1;
-                               goto error;
-                       }
-               }
-
-               DBG("Enabling channel %s", channel_name);
-
-               ret = lttng_enable_channel(handle, channel);
-               if (ret < 0) {
-                       success = 0;
-                       switch (-ret) {
-                       case LTTNG_ERR_KERN_CHAN_EXIST:
-                       case LTTNG_ERR_UST_CHAN_EXIST:
-                       case LTTNG_ERR_CHAN_EXIST:
-                               WARN("Channel %s: %s (session %s)", channel_name,
-                                               lttng_strerror(ret), session_name);
-                               warn = 1;
-                               break;
-                       case LTTNG_ERR_INVALID_CHANNEL_NAME:
-                               ERR("Invalid channel name: \"%s\". "
-                                   "Channel names may not start with '.', and "
-                                   "may not contain '/'.", channel_name);
-                               error = 1;
-                               break;
-                       default:
-                               ERR("Channel %s: %s (session %s)", channel_name,
-                                               lttng_strerror(ret), session_name);
-                               error = 1;
-                               break;
-                       }
-               } else {
-                       MSG("%s channel %s enabled for session %s",
-                                       lttng_domain_type_str(dom.type),
-                                       channel_name, session_name);
-                       success = 1;
-               }
-
-skip_enable:
-               if (lttng_opt_mi) {
-                       /* Mi print the channel element and leave it open */
-                       ret = mi_lttng_channel(writer, channel, 1);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Individual Success ? */
-                       ret = mi_lttng_writer_write_element_bool(writer,
-                                       mi_lttng_element_command_success, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Close channel element */
-                       ret = mi_lttng_writer_close_element(writer);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-
-               /* Next channel */
-               channel_name = strtok(NULL, ",");
-               lttng_channel_destroy(channel);
-               channel = NULL;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close channels element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       ret = CMD_SUCCESS;
-
-error:
-       if (channel) {
-               lttng_channel_destroy(channel);
-       }
-       /* If more important error happen bypass the warning */
-       if (!ret && warn) {
-               ret = CMD_WARNING;
-       }
-       /* If more important error happen bypass the warning */
-       if (!ret && error) {
-               ret = CMD_ERROR;
-       }
-
-       lttng_destroy_handle(handle);
-
-       return ret;
-}
-
-/*
- * Default value for channel configuration.
- */
-static void init_channel_config(void)
-{
-       /*
-        * Put -1 everywhere so we can identify those set by the command line and
-        * those needed to be set by the default values.
-        */
-       memset(&chan_opts.attr, -1, sizeof(chan_opts.attr));
-       chan_opts.attr.extended.ptr = NULL;
-}
-
-/*
- * Add channel to trace session
- */
-int cmd_enable_channels(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       char *opt_arg = NULL;
-       const char *leftover = NULL;
-
-       init_channel_config();
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_DISCARD:
-                       chan_opts.attr.overwrite = 0;
-                       DBG("Channel set to discard");
-                       break;
-               case OPT_OVERWRITE:
-                       chan_opts.attr.overwrite = 1;
-                       DBG("Channel set to overwrite");
-                       break;
-               case OPT_SUBBUF_SIZE:
-               {
-                       uint64_t rounded_size;
-                       int order;
-
-                       /* Parse the size */
-                       opt_arg = poptGetOptArg(pc);
-                       if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.subbuf_size) < 0 || !chan_opts.attr.subbuf_size) {
-                               ERR("Wrong value in --subbuf-size parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       order = get_count_order_u64(chan_opts.attr.subbuf_size);
-                       LTTNG_ASSERT(order >= 0);
-                       rounded_size = 1ULL << order;
-                       if (rounded_size < chan_opts.attr.subbuf_size) {
-                               ERR("The subbuf size (%" PRIu64 ") is rounded and overflows!",
-                                               chan_opts.attr.subbuf_size);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (rounded_size != chan_opts.attr.subbuf_size) {
-                               WARN("The subbuf size (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
-                                               chan_opts.attr.subbuf_size, rounded_size);
-                               chan_opts.attr.subbuf_size = rounded_size;
-                       }
-
-                       /* Should now be power of 2 */
-                       LTTNG_ASSERT(!((chan_opts.attr.subbuf_size - 1) & chan_opts.attr.subbuf_size));
-
-                       DBG("Channel subbuf size set to %" PRIu64, chan_opts.attr.subbuf_size);
-                       break;
-               }
-               case OPT_NUM_SUBBUF:
-               {
-                       uint64_t rounded_size;
-                       int order;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-                       chan_opts.attr.num_subbuf = strtoull(opt_arg, NULL, 0);
-                       if (errno != 0 || !chan_opts.attr.num_subbuf || !isdigit(opt_arg[0])) {
-                               ERR("Wrong value in --num-subbuf parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       order = get_count_order_u64(chan_opts.attr.num_subbuf);
-                       LTTNG_ASSERT(order >= 0);
-                       rounded_size = 1ULL << order;
-                       if (rounded_size < chan_opts.attr.num_subbuf) {
-                               ERR("The number of subbuffers (%" PRIu64 ") is rounded and overflows!",
-                                               chan_opts.attr.num_subbuf);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (rounded_size != chan_opts.attr.num_subbuf) {
-                               WARN("The number of subbuffers (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
-                                               chan_opts.attr.num_subbuf, rounded_size);
-                               chan_opts.attr.num_subbuf = rounded_size;
-                       }
-
-                       /* Should now be power of 2 */
-                       LTTNG_ASSERT(!((chan_opts.attr.num_subbuf - 1) & chan_opts.attr.num_subbuf));
-
-                       DBG("Channel subbuf num set to %" PRIu64, chan_opts.attr.num_subbuf);
-                       break;
-               }
-               case OPT_SWITCH_TIMER:
-               {
-                       uint64_t v;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-
-                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
-                               ERR("Wrong value for --switch-timer parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (v != (uint32_t) v) {
-                               ERR("32-bit overflow in --switch-timer parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       chan_opts.attr.switch_timer_interval = (uint32_t) v;
-                       DBG("Channel switch timer interval set to %d %s",
-                                       chan_opts.attr.switch_timer_interval,
-                                       USEC_UNIT);
-                       break;
-               }
-               case OPT_READ_TIMER:
-               {
-                       uint64_t v;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-
-                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
-                               ERR("Wrong value for --read-timer parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       if (v != (uint32_t) v) {
-                               ERR("32-bit overflow in --read-timer parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       chan_opts.attr.read_timer_interval = (uint32_t) v;
-                       DBG("Channel read timer interval set to %d %s",
-                                       chan_opts.attr.read_timer_interval,
-                                       USEC_UNIT);
-                       break;
-               }
-               case OPT_MONITOR_TIMER:
-               {
-                       uint64_t v;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-
-                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
-                               ERR("Wrong value for --monitor-timer parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       opt_monitor_timer.interval = (uint64_t) v;
-                       opt_monitor_timer.set = true;
-                       DBG("Channel monitor timer interval set to %" PRIu64 " %s",
-                                       opt_monitor_timer.interval,
-                                       USEC_UNIT);
-                       break;
-               }
-               case OPT_BLOCKING_TIMEOUT:
-               {
-                       uint64_t v;
-                       long long v_msec;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-
-                       if (strcmp(opt_arg, "inf") == 0) {
-                               opt_blocking_timeout.value = (int64_t) -1;
-                               opt_blocking_timeout.set = true;
-                               DBG("Channel blocking timeout set to infinity");
-                               break;
-                       }
-
-                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
-                               ERR("Wrong value for --blocking-timeout parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       /*
-                        * While LTTng-UST and LTTng-tools will accept a
-                        * blocking timeout expressed in µs, the current
-                        * tracer implementation relies on poll() which
-                        * takes an "int timeout" parameter expressed in
-                        * msec.
-                        *
-                        * Since the error reporting from the tracer is
-                        * not precise, we perform this check here to
-                        * provide a helpful error message in case of
-                        * overflow.
-                        *
-                        * The setter (liblttng-ctl) also performs an
-                        * equivalent check.
-                        */
-                       v_msec = v / 1000;
-                       if (v_msec != (int32_t) v_msec) {
-                               ERR("32-bit milliseconds overflow in --blocking-timeout parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       opt_blocking_timeout.value = (int64_t) v;
-                       opt_blocking_timeout.set = true;
-                       DBG("Channel blocking timeout set to %" PRId64 " %s%s",
-                                       opt_blocking_timeout.value,
-                                       USEC_UNIT,
-                                       opt_blocking_timeout.value == 0 ?
-                                               " (non-blocking)" : "");
-                       break;
-               }
-               case OPT_USERSPACE:
-                       opt_userspace = 1;
-                       break;
-               case OPT_TRACEFILE_SIZE:
-                       opt_arg = poptGetOptArg(pc);
-                       if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.tracefile_size) < 0) {
-                               ERR("Wrong value in --tracefile-size parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       DBG("Maximum tracefile size set to %" PRIu64,
-                                       chan_opts.attr.tracefile_size);
-                       break;
-               case OPT_TRACEFILE_COUNT:
-               {
-                       unsigned long v;
-
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-                       v = strtoul(opt_arg, NULL, 0);
-                       if (errno != 0 || !isdigit(opt_arg[0])) {
-                               ERR("Wrong value in --tracefile-count parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       if (v != (uint32_t) v) {
-                               ERR("32-bit overflow in --tracefile-count parameter: %s", opt_arg);
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-                       chan_opts.attr.tracefile_count = (uint32_t) v;
-                       DBG("Maximum tracefile count set to %" PRIu64,
-                                       chan_opts.attr.tracefile_count);
-                       break;
-               }
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace, false);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (chan_opts.attr.overwrite == 1 && opt_blocking_timeout.set &&
-                       opt_blocking_timeout.value != 0) {
-               ERR("You cannot specify --overwrite and --blocking-timeout=N, "
-                       "where N is different than 0");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_enable_channels);
-               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;
-               }
-       }
-
-       opt_channels = (char*) poptGetArg(pc);
-       if (opt_channels == NULL) {
-               ERR("Missing channel name.\n");
-               ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               success = 0;
-               goto mi_closing;
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       command_ret = CMD_ERROR;
-                       success = 0;
-                       goto mi_closing;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       command_ret = enable_channel(session_name);
-       if (command_ret) {
-               success = 0;
-       }
-
-mi_closing:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               if (ret) {
-                       goto end;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       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;
-       }
-
-       if (!opt_session_name && session_name) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred when enable_channel */
-       ret = command_ret ? command_ret : ret;
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/enable_channels.cpp b/src/bin/lttng/commands/enable_channels.cpp
new file mode 100644 (file)
index 0000000..194ec54
--- /dev/null
@@ -0,0 +1,759 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/utils.h>
+#include <common/mi-lttng.h>
+
+#include <lttng/domain-internal.h>
+
+#include "../command.h"
+#include "../utils.h"
+
+
+static struct lttng_channel chan_opts;
+static char *opt_channels;
+static int opt_kernel;
+static char *opt_session_name;
+static int opt_userspace;
+static char *opt_output;
+static int opt_buffer_uid;
+static int opt_buffer_pid;
+static int opt_buffer_global;
+static struct {
+       bool set;
+       uint64_t interval;
+} opt_monitor_timer;
+static struct {
+       bool set;
+       int64_t value;
+} opt_blocking_timeout;
+
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-enable-channel.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_DISCARD,
+       OPT_OVERWRITE,
+       OPT_SUBBUF_SIZE,
+       OPT_NUM_SUBBUF,
+       OPT_SWITCH_TIMER,
+       OPT_MONITOR_TIMER,
+       OPT_READ_TIMER,
+       OPT_USERSPACE,
+       OPT_LIST_OPTIONS,
+       OPT_TRACEFILE_SIZE,
+       OPT_TRACEFILE_COUNT,
+       OPT_BLOCKING_TIMEOUT,
+};
+
+static struct lttng_handle *handle;
+
+const char *output_mmap = "mmap";
+const char *output_splice = "splice";
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
+       {"discard",        0,   POPT_ARG_NONE, 0, OPT_DISCARD, 0, 0},
+       {"overwrite",      0,   POPT_ARG_NONE, 0, OPT_OVERWRITE, 0, 0},
+       {"subbuf-size",    0,   POPT_ARG_STRING, 0, OPT_SUBBUF_SIZE, 0, 0},
+       {"num-subbuf",     0,   POPT_ARG_INT, 0, OPT_NUM_SUBBUF, 0, 0},
+       {"switch-timer",   0,   POPT_ARG_INT, 0, OPT_SWITCH_TIMER, 0, 0},
+       {"monitor-timer",  0,   POPT_ARG_INT, 0, OPT_MONITOR_TIMER, 0, 0},
+       {"read-timer",     0,   POPT_ARG_INT, 0, OPT_READ_TIMER, 0, 0},
+       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"output",         0,   POPT_ARG_STRING, &opt_output, 0, 0, 0},
+       {"buffers-uid",    0,   POPT_ARG_VAL, &opt_buffer_uid, 1, 0, 0},
+       {"buffers-pid",    0,   POPT_ARG_VAL, &opt_buffer_pid, 1, 0, 0},
+       {"buffers-global", 0,   POPT_ARG_VAL, &opt_buffer_global, 1, 0, 0},
+       {"tracefile-size", 'C',   POPT_ARG_INT, 0, OPT_TRACEFILE_SIZE, 0, 0},
+       {"tracefile-count", 'W',   POPT_ARG_INT, 0, OPT_TRACEFILE_COUNT, 0, 0},
+       {"blocking-timeout",     0,   POPT_ARG_INT, 0, OPT_BLOCKING_TIMEOUT, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Set default attributes depending on those already defined from the command
+ * line.
+ */
+static void set_default_attr(struct lttng_domain *dom)
+{
+       struct lttng_channel_attr default_attr;
+
+       memset(&default_attr, 0, sizeof(default_attr));
+
+       /* Set attributes */
+       lttng_channel_set_default_attr(dom, &default_attr);
+
+       if (chan_opts.attr.overwrite == -1) {
+               chan_opts.attr.overwrite = default_attr.overwrite;
+       }
+       if (chan_opts.attr.subbuf_size == -1) {
+               chan_opts.attr.subbuf_size = default_attr.subbuf_size;
+       }
+       if (chan_opts.attr.num_subbuf == -1) {
+               chan_opts.attr.num_subbuf = default_attr.num_subbuf;
+       }
+       if (chan_opts.attr.switch_timer_interval == -1) {
+               chan_opts.attr.switch_timer_interval = default_attr.switch_timer_interval;
+       }
+       if (chan_opts.attr.read_timer_interval == -1) {
+               chan_opts.attr.read_timer_interval = default_attr.read_timer_interval;
+       }
+       if ((int) chan_opts.attr.output == -1) {
+               chan_opts.attr.output = default_attr.output;
+       }
+       if (chan_opts.attr.tracefile_count == -1) {
+               chan_opts.attr.tracefile_count = default_attr.tracefile_count;
+       }
+       if (chan_opts.attr.tracefile_size == -1) {
+               chan_opts.attr.tracefile_size = default_attr.tracefile_size;
+       }
+}
+
+/*
+ * Adding channel using the lttng API.
+ */
+static int enable_channel(char *session_name)
+{
+       struct lttng_channel *channel = NULL;
+       int ret = CMD_SUCCESS, warn = 0, error = 0, success = 0;
+       char *channel_name;
+       struct lttng_domain dom;
+
+       memset(&dom, 0, sizeof(dom));
+
+       /* Validate options. */
+       if (opt_kernel) {
+               if (opt_blocking_timeout.set) {
+                       ERR("Retry timeout option not supported for kernel domain (-k)");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       /* Create lttng domain */
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
+               if (opt_buffer_uid || opt_buffer_pid) {
+                       ERR("Buffer type not supported for domain -k");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else if (opt_userspace) {
+               dom.type = LTTNG_DOMAIN_UST;
+               if (opt_buffer_pid) {
+                       dom.buf_type = LTTNG_BUFFER_PER_PID;
+               } else {
+                       if (opt_buffer_global) {
+                               ERR("Buffer type not supported for domain -u");
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+                       dom.buf_type = LTTNG_BUFFER_PER_UID;
+               }
+       } else {
+               /* Checked by the caller. */
+               abort();
+       }
+
+       set_default_attr(&dom);
+
+       if (chan_opts.attr.tracefile_size == 0 && chan_opts.attr.tracefile_count) {
+               ERR("Missing option --tracefile-size. "
+                               "A file count without a size won't do anything.");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if ((chan_opts.attr.tracefile_size > 0) &&
+                       (chan_opts.attr.tracefile_size < chan_opts.attr.subbuf_size)) {
+               WARN("Tracefile size rounded up from (%" PRIu64 ") to subbuffer size (%" PRIu64 ")",
+                               chan_opts.attr.tracefile_size, chan_opts.attr.subbuf_size);
+               chan_opts.attr.tracefile_size = chan_opts.attr.subbuf_size;
+       }
+
+       /* Setting channel output */
+       if (opt_output) {
+               if (!strncmp(output_mmap, opt_output, strlen(output_mmap))) {
+                       chan_opts.attr.output = LTTNG_EVENT_MMAP;
+               } else if (!strncmp(output_splice, opt_output, strlen(output_splice))) {
+                       chan_opts.attr.output = LTTNG_EVENT_SPLICE;
+               } else {
+                       ERR("Unknown output type %s. Possible values are: %s, %s\n",
+                                       opt_output, output_mmap, output_splice);
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Mi open channels element */
+       if (lttng_opt_mi) {
+               LTTNG_ASSERT(writer);
+               ret = mi_lttng_channels_open(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       /* Strip channel list (format: chan1,chan2,...) */
+       channel_name = strtok(opt_channels, ",");
+       while (channel_name != NULL) {
+               void *extended_ptr;
+
+               /* Validate channel name's length */
+               if (strlen(channel_name) >= sizeof(chan_opts.name)) {
+                       ERR("Channel name is too long (max. %zu characters)",
+                                       sizeof(chan_opts.name) - 1);
+                       error = 1;
+                       goto skip_enable;
+               }
+
+               /*
+                * A dynamically-allocated channel is used in order to allow
+                * the configuration of extended attributes (post-2.9).
+                */
+               channel = lttng_channel_create(&dom);
+               if (!channel) {
+                       ERR("Unable to create channel object");
+                       error = 1;
+                       goto error;
+               }
+
+               /* Copy channel name */
+               strcpy(channel->name, channel_name);
+               channel->enabled = 1;
+               extended_ptr = channel->attr.extended.ptr;
+               memcpy(&channel->attr, &chan_opts.attr, sizeof(chan_opts.attr));
+               channel->attr.extended.ptr = extended_ptr;
+               if (opt_monitor_timer.set) {
+                       ret = lttng_channel_set_monitor_timer_interval(channel,
+                                       opt_monitor_timer.interval);
+                       if (ret) {
+                               ERR("Failed to set the channel's monitor timer interval");
+                               error = 1;
+                               goto error;
+                       }
+               }
+               if (opt_blocking_timeout.set) {
+                       ret = lttng_channel_set_blocking_timeout(channel,
+                                       opt_blocking_timeout.value);
+                       if (ret) {
+                               ERR("Failed to set the channel's blocking timeout");
+                               error = 1;
+                               goto error;
+                       }
+               }
+
+               DBG("Enabling channel %s", channel_name);
+
+               ret = lttng_enable_channel(handle, channel);
+               if (ret < 0) {
+                       success = 0;
+                       switch (-ret) {
+                       case LTTNG_ERR_KERN_CHAN_EXIST:
+                       case LTTNG_ERR_UST_CHAN_EXIST:
+                       case LTTNG_ERR_CHAN_EXIST:
+                               WARN("Channel %s: %s (session %s)", channel_name,
+                                               lttng_strerror(ret), session_name);
+                               warn = 1;
+                               break;
+                       case LTTNG_ERR_INVALID_CHANNEL_NAME:
+                               ERR("Invalid channel name: \"%s\". "
+                                   "Channel names may not start with '.', and "
+                                   "may not contain '/'.", channel_name);
+                               error = 1;
+                               break;
+                       default:
+                               ERR("Channel %s: %s (session %s)", channel_name,
+                                               lttng_strerror(ret), session_name);
+                               error = 1;
+                               break;
+                       }
+               } else {
+                       MSG("%s channel %s enabled for session %s",
+                                       lttng_domain_type_str(dom.type),
+                                       channel_name, session_name);
+                       success = 1;
+               }
+
+skip_enable:
+               if (lttng_opt_mi) {
+                       /* Mi print the channel element and leave it open */
+                       ret = mi_lttng_channel(writer, channel, 1);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Individual Success ? */
+                       ret = mi_lttng_writer_write_element_bool(writer,
+                                       mi_lttng_element_command_success, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Close channel element */
+                       ret = mi_lttng_writer_close_element(writer);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+
+               /* Next channel */
+               channel_name = strtok(NULL, ",");
+               lttng_channel_destroy(channel);
+               channel = NULL;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close channels element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       ret = CMD_SUCCESS;
+
+error:
+       if (channel) {
+               lttng_channel_destroy(channel);
+       }
+       /* If more important error happen bypass the warning */
+       if (!ret && warn) {
+               ret = CMD_WARNING;
+       }
+       /* If more important error happen bypass the warning */
+       if (!ret && error) {
+               ret = CMD_ERROR;
+       }
+
+       lttng_destroy_handle(handle);
+
+       return ret;
+}
+
+/*
+ * Default value for channel configuration.
+ */
+static void init_channel_config(void)
+{
+       /*
+        * Put -1 everywhere so we can identify those set by the command line and
+        * those needed to be set by the default values.
+        */
+       memset(&chan_opts.attr, -1, sizeof(chan_opts.attr));
+       chan_opts.attr.extended.ptr = NULL;
+}
+
+/*
+ * Add channel to trace session
+ */
+int cmd_enable_channels(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       char *opt_arg = NULL;
+       const char *leftover = NULL;
+
+       init_channel_config();
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_DISCARD:
+                       chan_opts.attr.overwrite = 0;
+                       DBG("Channel set to discard");
+                       break;
+               case OPT_OVERWRITE:
+                       chan_opts.attr.overwrite = 1;
+                       DBG("Channel set to overwrite");
+                       break;
+               case OPT_SUBBUF_SIZE:
+               {
+                       uint64_t rounded_size;
+                       int order;
+
+                       /* Parse the size */
+                       opt_arg = poptGetOptArg(pc);
+                       if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.subbuf_size) < 0 || !chan_opts.attr.subbuf_size) {
+                               ERR("Wrong value in --subbuf-size parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       order = get_count_order_u64(chan_opts.attr.subbuf_size);
+                       LTTNG_ASSERT(order >= 0);
+                       rounded_size = 1ULL << order;
+                       if (rounded_size < chan_opts.attr.subbuf_size) {
+                               ERR("The subbuf size (%" PRIu64 ") is rounded and overflows!",
+                                               chan_opts.attr.subbuf_size);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (rounded_size != chan_opts.attr.subbuf_size) {
+                               WARN("The subbuf size (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
+                                               chan_opts.attr.subbuf_size, rounded_size);
+                               chan_opts.attr.subbuf_size = rounded_size;
+                       }
+
+                       /* Should now be power of 2 */
+                       LTTNG_ASSERT(!((chan_opts.attr.subbuf_size - 1) & chan_opts.attr.subbuf_size));
+
+                       DBG("Channel subbuf size set to %" PRIu64, chan_opts.attr.subbuf_size);
+                       break;
+               }
+               case OPT_NUM_SUBBUF:
+               {
+                       uint64_t rounded_size;
+                       int order;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+                       chan_opts.attr.num_subbuf = strtoull(opt_arg, NULL, 0);
+                       if (errno != 0 || !chan_opts.attr.num_subbuf || !isdigit(opt_arg[0])) {
+                               ERR("Wrong value in --num-subbuf parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       order = get_count_order_u64(chan_opts.attr.num_subbuf);
+                       LTTNG_ASSERT(order >= 0);
+                       rounded_size = 1ULL << order;
+                       if (rounded_size < chan_opts.attr.num_subbuf) {
+                               ERR("The number of subbuffers (%" PRIu64 ") is rounded and overflows!",
+                                               chan_opts.attr.num_subbuf);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (rounded_size != chan_opts.attr.num_subbuf) {
+                               WARN("The number of subbuffers (%" PRIu64 ") is rounded to the next power of 2 (%" PRIu64 ")",
+                                               chan_opts.attr.num_subbuf, rounded_size);
+                               chan_opts.attr.num_subbuf = rounded_size;
+                       }
+
+                       /* Should now be power of 2 */
+                       LTTNG_ASSERT(!((chan_opts.attr.num_subbuf - 1) & chan_opts.attr.num_subbuf));
+
+                       DBG("Channel subbuf num set to %" PRIu64, chan_opts.attr.num_subbuf);
+                       break;
+               }
+               case OPT_SWITCH_TIMER:
+               {
+                       uint64_t v;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+
+                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
+                               ERR("Wrong value for --switch-timer parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (v != (uint32_t) v) {
+                               ERR("32-bit overflow in --switch-timer parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       chan_opts.attr.switch_timer_interval = (uint32_t) v;
+                       DBG("Channel switch timer interval set to %d %s",
+                                       chan_opts.attr.switch_timer_interval,
+                                       USEC_UNIT);
+                       break;
+               }
+               case OPT_READ_TIMER:
+               {
+                       uint64_t v;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+
+                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
+                               ERR("Wrong value for --read-timer parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       if (v != (uint32_t) v) {
+                               ERR("32-bit overflow in --read-timer parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       chan_opts.attr.read_timer_interval = (uint32_t) v;
+                       DBG("Channel read timer interval set to %d %s",
+                                       chan_opts.attr.read_timer_interval,
+                                       USEC_UNIT);
+                       break;
+               }
+               case OPT_MONITOR_TIMER:
+               {
+                       uint64_t v;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+
+                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
+                               ERR("Wrong value for --monitor-timer parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       opt_monitor_timer.interval = (uint64_t) v;
+                       opt_monitor_timer.set = true;
+                       DBG("Channel monitor timer interval set to %" PRIu64 " %s",
+                                       opt_monitor_timer.interval,
+                                       USEC_UNIT);
+                       break;
+               }
+               case OPT_BLOCKING_TIMEOUT:
+               {
+                       uint64_t v;
+                       long long v_msec;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+
+                       if (strcmp(opt_arg, "inf") == 0) {
+                               opt_blocking_timeout.value = (int64_t) -1;
+                               opt_blocking_timeout.set = true;
+                               DBG("Channel blocking timeout set to infinity");
+                               break;
+                       }
+
+                       if (utils_parse_time_suffix(opt_arg, &v) < 0) {
+                               ERR("Wrong value for --blocking-timeout parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       /*
+                        * While LTTng-UST and LTTng-tools will accept a
+                        * blocking timeout expressed in µs, the current
+                        * tracer implementation relies on poll() which
+                        * takes an "int timeout" parameter expressed in
+                        * msec.
+                        *
+                        * Since the error reporting from the tracer is
+                        * not precise, we perform this check here to
+                        * provide a helpful error message in case of
+                        * overflow.
+                        *
+                        * The setter (liblttng-ctl) also performs an
+                        * equivalent check.
+                        */
+                       v_msec = v / 1000;
+                       if (v_msec != (int32_t) v_msec) {
+                               ERR("32-bit milliseconds overflow in --blocking-timeout parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       opt_blocking_timeout.value = (int64_t) v;
+                       opt_blocking_timeout.set = true;
+                       DBG("Channel blocking timeout set to %" PRId64 " %s%s",
+                                       opt_blocking_timeout.value,
+                                       USEC_UNIT,
+                                       opt_blocking_timeout.value == 0 ?
+                                               " (non-blocking)" : "");
+                       break;
+               }
+               case OPT_USERSPACE:
+                       opt_userspace = 1;
+                       break;
+               case OPT_TRACEFILE_SIZE:
+                       opt_arg = poptGetOptArg(pc);
+                       if (utils_parse_size_suffix(opt_arg, &chan_opts.attr.tracefile_size) < 0) {
+                               ERR("Wrong value in --tracefile-size parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       DBG("Maximum tracefile size set to %" PRIu64,
+                                       chan_opts.attr.tracefile_size);
+                       break;
+               case OPT_TRACEFILE_COUNT:
+               {
+                       unsigned long v;
+
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+                       v = strtoul(opt_arg, NULL, 0);
+                       if (errno != 0 || !isdigit(opt_arg[0])) {
+                               ERR("Wrong value in --tracefile-count parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       if (v != (uint32_t) v) {
+                               ERR("32-bit overflow in --tracefile-count parameter: %s", opt_arg);
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+                       chan_opts.attr.tracefile_count = (uint32_t) v;
+                       DBG("Maximum tracefile count set to %" PRIu64,
+                                       chan_opts.attr.tracefile_count);
+                       break;
+               }
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (chan_opts.attr.overwrite == 1 && opt_blocking_timeout.set &&
+                       opt_blocking_timeout.value != 0) {
+               ERR("You cannot specify --overwrite and --blocking-timeout=N, "
+                       "where N is different than 0");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_enable_channels);
+               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;
+               }
+       }
+
+       opt_channels = (char*) poptGetArg(pc);
+       if (opt_channels == NULL) {
+               ERR("Missing channel name.\n");
+               ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               success = 0;
+               goto mi_closing;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       command_ret = CMD_ERROR;
+                       success = 0;
+                       goto mi_closing;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       command_ret = enable_channel(session_name);
+       if (command_ret) {
+               success = 0;
+       }
+
+mi_closing:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       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;
+       }
+
+       if (!opt_session_name && session_name) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred when enable_channel */
+       ret = command_ret ? command_ret : ret;
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/enable_events.c b/src/bin/lttng/commands/enable_events.c
deleted file mode 100644 (file)
index bbf7c56..0000000
+++ /dev/null
@@ -1,1396 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/compat/string.h>
-#include <common/compat/getenv.h>
-#include <common/string-utils/string-utils.h>
-#include <common/utils.h>
-
-/* Mi dependancy */
-#include <common/mi-lttng.h>
-
-#include <lttng/domain-internal.h>
-#include <lttng/event-internal.h>
-
-#include "../command.h"
-#include "../loglevel.h"
-#include "../uprobe.h"
-
-#if (LTTNG_SYMBOL_NAME_LEN == 256)
-#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API    "255"
-#endif
-
-static char *opt_event_list;
-static int opt_event_type;
-static const char *opt_loglevel;
-static int opt_loglevel_type;
-static int opt_kernel;
-static char *opt_session_name;
-static int opt_userspace;
-static int opt_jul;
-static int opt_log4j;
-static int opt_python;
-static int opt_enable_all;
-static char *opt_probe;
-static char *opt_userspace_probe;
-static char *opt_function;
-static char *opt_channel_name;
-static char *opt_filter;
-static char *opt_exclude;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-enable-event.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_TRACEPOINT,
-       OPT_PROBE,
-       OPT_USERSPACE_PROBE,
-       OPT_FUNCTION,
-       OPT_SYSCALL,
-       OPT_USERSPACE,
-       OPT_LOGLEVEL,
-       OPT_LOGLEVEL_ONLY,
-       OPT_LIST_OPTIONS,
-       OPT_FILTER,
-       OPT_EXCLUDE,
-};
-
-static struct lttng_handle *handle;
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"all",            'a', POPT_ARG_VAL, &opt_enable_all, 1, 0, 0},
-       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
-       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-       {"jul",            'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
-       {"log4j",          'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
-       {"python",         'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
-       {"tracepoint",     0,   POPT_ARG_NONE, 0, OPT_TRACEPOINT, 0, 0},
-       {"probe",          0,   POPT_ARG_STRING, &opt_probe, OPT_PROBE, 0, 0},
-       {"userspace-probe",0,   POPT_ARG_STRING, &opt_userspace_probe, OPT_USERSPACE_PROBE, 0, 0},
-       {"function",       0,   POPT_ARG_STRING, &opt_function, OPT_FUNCTION, 0, 0},
-       {"syscall",        0,   POPT_ARG_NONE, 0, OPT_SYSCALL, 0, 0},
-       {"loglevel",       0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL, 0, 0},
-       {"loglevel-only",  0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL_ONLY, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"filter",         'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, 0, 0},
-       {"exclude",        'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Parse probe options.
- */
-static int parse_probe_opts(struct lttng_event *ev, char *opt)
-{
-       int ret = CMD_SUCCESS;
-       int match;
-       char s_hex[19];
-#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18"   /* 18 is (19 - 1) (\0 is extra) */
-       char name[LTTNG_SYMBOL_NAME_LEN];
-
-       if (opt == NULL) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Check for symbol+offset */
-       match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
-                       "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", name, s_hex);
-       if (match == 2) {
-               strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
-               ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-               DBG("probe symbol %s", ev->attr.probe.symbol_name);
-               if (*s_hex == '\0') {
-                       ERR("Invalid probe offset %s", s_hex);
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               ev->attr.probe.offset = strtoul(s_hex, NULL, 0);
-               DBG("probe offset %" PRIu64, ev->attr.probe.offset);
-               ev->attr.probe.addr = 0;
-               goto end;
-       }
-
-       /* Check for symbol */
-       if (isalpha(name[0]) || name[0] == '_') {
-               match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s",
-                       name);
-               if (match == 1) {
-                       strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
-                       ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-                       DBG("probe symbol %s", ev->attr.probe.symbol_name);
-                       ev->attr.probe.offset = 0;
-                       DBG("probe offset %" PRIu64, ev->attr.probe.offset);
-                       ev->attr.probe.addr = 0;
-                       goto end;
-               }
-       }
-
-       /* Check for address */
-       match = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex);
-       if (match > 0) {
-               /*
-                * Return an error if the first character of the tentative
-                * address is NULL or not a digit. It can be "0" if the address
-                * is in hexadecimal and can be 1 to 9 if it's in decimal.
-                */
-               if (*s_hex == '\0' || !isdigit(*s_hex)) {
-                       ERR("Invalid probe description %s", s_hex);
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               ev->attr.probe.addr = strtoul(s_hex, NULL, 0);
-               DBG("probe addr %" PRIu64, ev->attr.probe.addr);
-               ev->attr.probe.offset = 0;
-               memset(ev->attr.probe.symbol_name, 0, LTTNG_SYMBOL_NAME_LEN);
-               goto end;
-       }
-
-       /* No match */
-       ret = CMD_ERROR;
-
-end:
-       return ret;
-}
-
-static
-const char *print_channel_name(const char *name)
-{
-       return name ? : DEFAULT_CHANNEL_NAME;
-}
-
-static
-const char *print_raw_channel_name(const char *name)
-{
-       return name ? : "<default>";
-}
-
-/*
- * Mi print exlcusion list
- */
-static
-int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
-{
-       int ret;
-       size_t i;
-       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
-
-       LTTNG_ASSERT(writer);
-
-       if (count == 0) {
-               ret = 0;
-               goto end;
-       }
-
-       ret = mi_lttng_writer_open_element(writer, config_element_exclusions);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
-                               exclusions, i);
-
-               ret = mi_lttng_writer_write_element_string(writer,
-                               config_element_exclusion, exclusion);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close exclusions element */
-       ret = mi_lttng_writer_close_element(writer);
-
-end:
-       return ret;
-}
-
-/*
- * Return allocated string for pretty-printing exclusion names.
- */
-static
-char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
-{
-       int length = 0;
-       size_t i;
-       const char preamble[] = " excluding ";
-       char *ret;
-       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
-
-       if (count == 0) {
-               return strdup("");
-       }
-
-       /* Calculate total required length. */
-       for (i = 0; i < count; i++) {
-               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
-                               exclusions, i);
-
-               length += strlen(exclusion) + 4;
-       }
-
-       length += sizeof(preamble);
-       ret = zmalloc(length);
-       if (!ret) {
-               return NULL;
-       }
-
-       strncpy(ret, preamble, length);
-       for (i = 0; i < count; i++) {
-               const char *exclusion = lttng_dynamic_pointer_array_get_pointer(
-                               exclusions, i);
-
-               strcat(ret, "\"");
-               strcat(ret, exclusion);
-               strcat(ret, "\"");
-               if (i != count - 1) {
-                       strcat(ret, ", ");
-               }
-       }
-
-       return ret;
-}
-
-static
-int check_exclusion_subsets(const char *event_name, const char *exclusion)
-{
-       bool warn = false;
-       int ret = 0;
-       const char *e = event_name;
-       const char *x = exclusion;
-
-       /* Scan both the excluder and the event letter by letter */
-       while (true) {
-               if (*e == '\\') {
-                       if (*x != *e) {
-                               warn = true;
-                               goto end;
-                       }
-
-                       e++;
-                       x++;
-                       goto cmp_chars;
-               }
-
-               if (*x == '*') {
-                       /* Event is a subset of the excluder */
-                       ERR("Event %s: %s excludes all events from %s",
-                               event_name, exclusion, event_name);
-                       goto error;
-               }
-
-               if (*e == '*') {
-                       /*
-                        * Reached the end of the event name before the
-                        * end of the exclusion: this is valid.
-                        */
-                       goto end;
-               }
-
-cmp_chars:
-               if (*x != *e) {
-                       warn = true;
-                       break;
-               }
-
-               x++;
-               e++;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       if (warn) {
-               WARN("Event %s: %s does not exclude any events from %s",
-                       event_name, exclusion, event_name);
-       }
-
-       return ret;
-}
-
-int validate_exclusion_list(const char *event_name,
-               const struct lttng_dynamic_pointer_array *exclusions)
-{
-       int ret;
-
-       /* Event name must be a valid globbing pattern to allow exclusions. */
-       if (!strutils_is_star_glob_pattern(event_name)) {
-               ERR("Event %s: Exclusions can only be used with a globbing pattern",
-                       event_name);
-               goto error;
-       }
-
-       /*
-        * If the event name is a star-at-end only globbing pattern,
-        * then we can validate the individual exclusions. Otherwise
-        * all exclusions are passed to the session daemon.
-        */
-       if (strutils_is_star_at_the_end_only_glob_pattern(event_name)) {
-               size_t i, num_exclusions;
-
-               num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
-
-               for (i = 0; i < num_exclusions; i++) {
-                       const char *exclusion =
-                                       lttng_dynamic_pointer_array_get_pointer(
-                                                       exclusions, i);
-
-                       if (!strutils_is_star_glob_pattern(exclusion) ||
-                                       strutils_is_star_at_the_end_only_glob_pattern(exclusion)) {
-                               ret = check_exclusion_subsets(event_name, exclusion);
-                               if (ret) {
-                                       goto error;
-                               }
-                       }
-               }
-       }
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = -1;
-
-end:
-       return ret;
-}
-
-static int create_exclusion_list_and_validate(const char *event_name,
-               const char *exclusions_arg,
-               struct lttng_dynamic_pointer_array *exclusions)
-{
-       int ret = 0;
-
-       /* Split exclusions. */
-       ret = strutils_split(exclusions_arg, ',', true, exclusions);
-       if (ret < 0) {
-               goto error;
-       }
-
-       if (validate_exclusion_list(event_name, exclusions) !=
-                       0) {
-               goto error;
-       }
-
-       goto end;
-
-error:
-       ret = -1;
-       lttng_dynamic_pointer_array_reset(exclusions);
-
-end:
-       return ret;
-}
-
-static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions,
-       int *warn)
-{
-       size_t i;
-       const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
-
-       for (i = 0; i < num_exclusions; i++) {
-               const char * const exclusion = lttng_dynamic_pointer_array_get_pointer(exclusions, i);
-
-               if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
-                       WARN("Event exclusion \"%s\" will be truncated",
-                                       exclusion);
-                       *warn = 1;
-               }
-       }
-}
-
-/*
- * Enabling event using the lttng API.
- * Note: in case of error only the last error code will be return.
- */
-static int enable_events(char *session_name)
-{
-       int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
-       int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1;
-       char *event_name, *channel_name = NULL;
-       struct lttng_event *ev;
-       struct lttng_domain dom = {};
-       struct lttng_dynamic_pointer_array exclusions;
-       struct lttng_userspace_probe_location *uprobe_loc = NULL;
-
-       lttng_dynamic_pointer_array_init(&exclusions, NULL);
-
-       ev = lttng_event_create();
-       if (!ev) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if (opt_kernel) {
-               if (opt_loglevel) {
-                       WARN("Kernel loglevels are not supported.");
-               }
-       }
-
-       /* Create lttng domain */
-       if (opt_kernel) {
-               dom.type = LTTNG_DOMAIN_KERNEL;
-               dom.buf_type = LTTNG_BUFFER_GLOBAL;
-       } else if (opt_userspace) {
-               dom.type = LTTNG_DOMAIN_UST;
-               /* Default. */
-               dom.buf_type = LTTNG_BUFFER_PER_UID;
-       } else if (opt_jul) {
-               dom.type = LTTNG_DOMAIN_JUL;
-               /* Default. */
-               dom.buf_type = LTTNG_BUFFER_PER_UID;
-       } else if (opt_log4j) {
-               dom.type = LTTNG_DOMAIN_LOG4J;
-               /* Default. */
-               dom.buf_type = LTTNG_BUFFER_PER_UID;
-       } else if (opt_python) {
-               dom.type = LTTNG_DOMAIN_PYTHON;
-               /* Default. */
-               dom.buf_type = LTTNG_BUFFER_PER_UID;
-       } else {
-               /* Checked by the caller. */
-               abort();
-       }
-
-       if (opt_exclude) {
-               switch (dom.type) {
-               case LTTNG_DOMAIN_KERNEL:
-               case LTTNG_DOMAIN_JUL:
-               case LTTNG_DOMAIN_LOG4J:
-               case LTTNG_DOMAIN_PYTHON:
-                       ERR("Event name exclusions are not yet implemented for %s events",
-                                       lttng_domain_type_str(dom.type));
-                       ret = CMD_ERROR;
-                       goto error;
-               case LTTNG_DOMAIN_UST:
-                       /* Exclusions supported */
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-       /*
-        * Adding a filter to a probe, function or userspace-probe would be
-        * denied by the kernel tracer as it's not supported at the moment. We
-        * do an early check here to warn the user.
-        */
-       if (opt_filter && opt_kernel) {
-               switch (opt_event_type) {
-               case LTTNG_EVENT_ALL:
-               case LTTNG_EVENT_TRACEPOINT:
-               case LTTNG_EVENT_SYSCALL:
-                       break;
-               case LTTNG_EVENT_PROBE:
-               case LTTNG_EVENT_USERSPACE_PROBE:
-               case LTTNG_EVENT_FUNCTION:
-                       ERR("Filter expressions are not supported for %s events",
-                                       get_event_type_str(opt_event_type));
-                       ret = CMD_ERROR;
-                       goto error;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto error;
-               }
-       }
-
-       channel_name = opt_channel_name;
-
-       handle = lttng_create_handle(session_name, &dom);
-       if (handle == NULL) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Prepare Mi */
-       if (lttng_opt_mi) {
-               /* Open a events element */
-               ret = mi_lttng_writer_open_element(writer, config_element_events);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       if (opt_enable_all) {
-               /* Default setup for enable all */
-               if (opt_kernel) {
-                       ev->type = opt_event_type;
-                       strcpy(ev->name, "*");
-                       /* kernel loglevels not implemented */
-                       ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
-               } else {
-                       ev->type = LTTNG_EVENT_TRACEPOINT;
-                       strcpy(ev->name, "*");
-                       ev->loglevel_type = opt_loglevel_type;
-                       if (opt_loglevel) {
-                               int name_search_ret;
-
-                               LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
-
-                               if (opt_userspace) {
-                                       enum lttng_loglevel loglevel;
-
-                                       name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               } else if (opt_jul) {
-                                       enum lttng_loglevel_jul loglevel;
-
-                                       name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               } else if (opt_log4j) {
-                                       enum lttng_loglevel_log4j loglevel;
-
-                                       name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               } else {
-                                       /* python domain. */
-                                       enum lttng_loglevel_python loglevel;
-
-                                       name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               }
-
-                               if (name_search_ret == -1) {
-                                       ERR("Unknown loglevel %s", opt_loglevel);
-                                       ret = -LTTNG_ERR_INVALID;
-                                       goto error;
-                               }
-                       } else {
-                               LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
-                               if (opt_userspace) {
-                                       ev->loglevel = -1;
-                               } else if (opt_jul) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
-                               } else if (opt_log4j) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
-                               } else if (opt_python) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
-                               }
-                       }
-               }
-
-               if (opt_exclude) {
-                       ret = create_exclusion_list_and_validate("*",
-                               opt_exclude, &exclusions);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       ev->exclusion = 1;
-                       warn_on_truncated_exclusion_names(&exclusions,
-                               &warn);
-               }
-               if (!opt_filter) {
-                       ret = lttng_enable_event_with_exclusions(handle,
-                                       ev, channel_name,
-                                       NULL,
-                                       lttng_dynamic_pointer_array_get_count(&exclusions),
-                                       (char **) exclusions.array.buffer.data);
-                       if (ret < 0) {
-                               switch (-ret) {
-                               case LTTNG_ERR_KERN_EVENT_EXIST:
-                                       WARN("Kernel events already enabled (channel %s, session %s)",
-                                                       print_channel_name(channel_name), session_name);
-                                       warn = 1;
-                                       break;
-                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
-                               {
-                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
-                                       ERR("Events: %s (channel %s, session %s)",
-                                                       msg,
-                                                       print_channel_name(channel_name),
-                                                       session_name);
-                                       error = 1;
-                                       break;
-                               }
-                               default:
-                                       ERR("Events: %s (channel %s, session %s)",
-                                                       lttng_strerror(ret),
-                                                       ret == -LTTNG_ERR_NEED_CHANNEL_NAME
-                                                               ? print_raw_channel_name(channel_name)
-                                                               : print_channel_name(channel_name),
-                                                       session_name);
-                                       error = 1;
-                                       break;
-                               }
-                               goto end;
-                       }
-
-                       switch (opt_event_type) {
-                       case LTTNG_EVENT_TRACEPOINT:
-                               if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
-                                       char *exclusion_string = print_exclusions(&exclusions);
-
-                                       if (!exclusion_string) {
-                                               PERROR("Cannot allocate exclusion_string");
-                                               error = 1;
-                                               goto end;
-                                       }
-                                       MSG("All %s tracepoints%s are enabled in channel %s for loglevel %s",
-                                                       lttng_domain_type_str(dom.type),
-                                                       exclusion_string,
-                                                       print_channel_name(channel_name),
-                                                       opt_loglevel);
-                                       free(exclusion_string);
-                               } else {
-                                       char *exclusion_string = print_exclusions(&exclusions);
-
-                                       if (!exclusion_string) {
-                                               PERROR("Cannot allocate exclusion_string");
-                                               error = 1;
-                                               goto end;
-                                       }
-                                       MSG("All %s tracepoints%s are enabled in channel %s",
-                                                       lttng_domain_type_str(dom.type),
-                                                       exclusion_string,
-                                                       print_channel_name(channel_name));
-                                       free(exclusion_string);
-                               }
-                               break;
-                       case LTTNG_EVENT_SYSCALL:
-                               if (opt_kernel) {
-                                       MSG("All %s system calls are enabled in channel %s",
-                                                       lttng_domain_type_str(dom.type),
-                                                       print_channel_name(channel_name));
-                               }
-                               break;
-                       case LTTNG_EVENT_ALL:
-                               if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
-                                       char *exclusion_string = print_exclusions(&exclusions);
-
-                                       if (!exclusion_string) {
-                                               PERROR("Cannot allocate exclusion_string");
-                                               error = 1;
-                                               goto end;
-                                       }
-                                       MSG("All %s events%s are enabled in channel %s for loglevel %s",
-                                                       lttng_domain_type_str(dom.type),
-                                                       exclusion_string,
-                                                       print_channel_name(channel_name),
-                                                       opt_loglevel);
-                                       free(exclusion_string);
-                               } else {
-                                       char *exclusion_string = print_exclusions(&exclusions);
-
-                                       if (!exclusion_string) {
-                                               PERROR("Cannot allocate exclusion_string");
-                                               error = 1;
-                                               goto end;
-                                       }
-                                       MSG("All %s events%s are enabled in channel %s",
-                                                       lttng_domain_type_str(dom.type),
-                                                       exclusion_string,
-                                                       print_channel_name(channel_name));
-                                       free(exclusion_string);
-                               }
-                               break;
-                       default:
-                               /*
-                                * We should not be here since lttng_enable_event should have
-                                * failed on the event type.
-                                */
-                               goto error;
-                       }
-               }
-
-               if (opt_filter) {
-                       command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
-                                       opt_filter,
-                                       lttng_dynamic_pointer_array_get_count(&exclusions),
-                                       (char **) exclusions.array.buffer.data);
-                       if (command_ret < 0) {
-                               switch (-command_ret) {
-                               case LTTNG_ERR_FILTER_EXIST:
-                                       WARN("Filter on all events is already enabled"
-                                                       " (channel %s, session %s)",
-                                               print_channel_name(channel_name), session_name);
-                                       warn = 1;
-                                       break;
-                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
-                               {
-                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
-                                       ERR("All events: %s (channel %s, session %s, filter \'%s\')",
-                                                       msg,
-                                                       print_channel_name(channel_name),
-                                                       session_name, opt_filter);
-                                       error = 1;
-                                       break;
-                               }
-                               default:
-                                       ERR("All events: %s (channel %s, session %s, filter \'%s\')",
-                                                       lttng_strerror(command_ret),
-                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
-                                                               ? print_raw_channel_name(channel_name)
-                                                               : print_channel_name(channel_name),
-                                                       session_name, opt_filter);
-                                       error = 1;
-                                       break;
-                               }
-                               error_holder = command_ret;
-                       } else {
-                               ev->filter = 1;
-                               MSG("Filter '%s' successfully set", opt_filter);
-                       }
-               }
-
-               if (lttng_opt_mi) {
-                       /* The wildcard * is used for kernel and ust domain to
-                        * represent ALL. We copy * in event name to force the wildcard use
-                        * for kernel domain
-                        *
-                        * Note: this is strictly for semantic and printing while in
-                        * machine interface mode.
-                        */
-                       strcpy(ev->name, "*");
-
-                       /* If we reach here the events are enabled */
-                       if (!error && !warn) {
-                               ev->enabled = 1;
-                       } else {
-                               ev->enabled = 0;
-                               success = 0;
-                       }
-                       ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* print exclusion */
-                       ret = mi_print_exclusion(&exclusions);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Success ? */
-                       ret = mi_lttng_writer_write_element_bool(writer,
-                                       mi_lttng_element_command_success, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Close event element */
-                       ret = mi_lttng_writer_close_element(writer);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-               }
-
-               goto end;
-       }
-
-       /* Strip event list */
-       event_name = strtok(opt_event_list, ",");
-       while (event_name != NULL) {
-               /* Copy name and type of the event */
-               strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
-               ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-               ev->type = opt_event_type;
-
-               /* Kernel tracer action */
-               if (opt_kernel) {
-                       DBG("Enabling kernel event %s for channel %s",
-                                       event_name,
-                                       print_channel_name(channel_name));
-
-                       switch (opt_event_type) {
-                       case LTTNG_EVENT_ALL:   /* Enable tracepoints and syscalls */
-                               /* If event name differs from *, select tracepoint. */
-                               if (strcmp(ev->name, "*")) {
-                                       ev->type = LTTNG_EVENT_TRACEPOINT;
-                               }
-                               break;
-                       case LTTNG_EVENT_TRACEPOINT:
-                               break;
-                       case LTTNG_EVENT_PROBE:
-                               ret = parse_probe_opts(ev, opt_probe);
-                               if (ret) {
-                                       ERR("Unable to parse probe options");
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-                               break;
-                       case LTTNG_EVENT_USERSPACE_PROBE:
-                               LTTNG_ASSERT(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
-
-                               ret = parse_userspace_probe_opts(opt_userspace_probe, &uprobe_loc);
-                               if (ret) {
-                                       switch (ret) {
-                                       case CMD_UNSUPPORTED:
-                                               /*
-                                                * Error message describing
-                                                * what is not supported was
-                                                * printed in the function.
-                                                */
-                                               break;
-                                       case CMD_ERROR:
-                                       default:
-                                               ERR("Unable to parse userspace probe options");
-                                               break;
-                                       }
-                                       goto error;
-                               }
-
-                               ret = lttng_event_set_userspace_probe_location(ev, uprobe_loc);
-                               if (ret) {
-                                       WARN("Failed to set probe location on event");
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-
-                               /* Ownership of the uprobe location was transferred to the event. */
-                               uprobe_loc = NULL;
-                               break;
-                       case LTTNG_EVENT_FUNCTION:
-                               ret = parse_probe_opts(ev, opt_function);
-                               if (ret) {
-                                       ERR("Unable to parse function probe options");
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-                               break;
-                       case LTTNG_EVENT_SYSCALL:
-                               ev->type = LTTNG_EVENT_SYSCALL;
-                               break;
-                       default:
-                               ret = CMD_UNDEFINED;
-                               goto error;
-                       }
-
-                       /* kernel loglevels not implemented */
-                       ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
-               } else if (opt_userspace) {             /* User-space tracer action */
-                       DBG("Enabling UST event %s for channel %s, loglevel %s", event_name,
-                                       print_channel_name(channel_name), opt_loglevel ? : "<all>");
-
-                       switch (opt_event_type) {
-                       case LTTNG_EVENT_ALL:   /* Default behavior is tracepoint */
-                               /* Fall-through */
-                       case LTTNG_EVENT_TRACEPOINT:
-                               /* Copy name and type of the event */
-                               ev->type = LTTNG_EVENT_TRACEPOINT;
-                               strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
-                               ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-                               break;
-                       case LTTNG_EVENT_PROBE:
-                       case LTTNG_EVENT_FUNCTION:
-                       case LTTNG_EVENT_SYSCALL:
-                       case LTTNG_EVENT_USERSPACE_PROBE:
-                       default:
-                               ERR("Event type not available for user-space tracing");
-                               ret = CMD_UNSUPPORTED;
-                               goto error;
-                       }
-
-                       if (opt_exclude) {
-                               ev->exclusion = 1;
-                               if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) {
-                                       ERR("Exclusion option can only be used with tracepoint events");
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-                               /* Free previously allocated items. */
-                               lttng_dynamic_pointer_array_reset(&exclusions);
-                               ret = create_exclusion_list_and_validate(
-                                       event_name, opt_exclude,
-                                       &exclusions);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto error;
-                               }
-
-                               warn_on_truncated_exclusion_names(
-                                       &exclusions, &warn);
-                       }
-
-                       ev->loglevel_type = opt_loglevel_type;
-                       if (opt_loglevel) {
-                               enum lttng_loglevel loglevel;
-                               const int name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel);
-
-                               if (name_search_ret == -1) {
-                                       ERR("Unknown loglevel %s", opt_loglevel);
-                                       ret = -LTTNG_ERR_INVALID;
-                                       goto error;
-                               }
-
-                               ev->loglevel = (int) loglevel;
-                       } else {
-                               ev->loglevel = -1;
-                       }
-               } else if (opt_jul || opt_log4j || opt_python) {
-                       if (opt_event_type != LTTNG_EVENT_ALL &&
-                                       opt_event_type != LTTNG_EVENT_TRACEPOINT) {
-                               ERR("Event type not supported for domain.");
-                               ret = CMD_UNSUPPORTED;
-                               goto error;
-                       }
-
-                       ev->loglevel_type = opt_loglevel_type;
-                       if (opt_loglevel) {
-                               int name_search_ret;
-
-                               if (opt_jul) {
-                                       enum lttng_loglevel_jul loglevel;
-
-                                       name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               } else if (opt_log4j) {
-                                       enum lttng_loglevel_log4j loglevel;
-
-                                       name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               } else {
-                                       /* python domain. */
-                                       enum lttng_loglevel_python loglevel;
-
-                                       name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel);
-                                       ev->loglevel = (int) loglevel;
-                               }
-
-                               if (name_search_ret) {
-                                       ERR("Unknown loglevel %s", opt_loglevel);
-                                       ret = -LTTNG_ERR_INVALID;
-                                       goto error;
-                               }
-                       } else {
-                               if (opt_jul) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
-                               } else if (opt_log4j) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
-                               } else if (opt_python) {
-                                       ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
-                               }
-                       }
-                       ev->type = LTTNG_EVENT_TRACEPOINT;
-                       strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
-                       ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
-               } else {
-                       abort();
-               }
-
-               if (!opt_filter) {
-                       char *exclusion_string;
-
-                       command_ret = lttng_enable_event_with_exclusions(handle,
-                                       ev, channel_name,
-                                       NULL,
-                                       lttng_dynamic_pointer_array_get_count(&exclusions),
-                                       (char **) exclusions.array.buffer.data);
-                       exclusion_string = print_exclusions(&exclusions);
-                       if (!exclusion_string) {
-                               PERROR("Cannot allocate exclusion_string");
-                               error = 1;
-                               goto end;
-                       }
-                       if (command_ret < 0) {
-                               /* Turn ret to positive value to handle the positive error code */
-                               switch (-command_ret) {
-                               case LTTNG_ERR_KERN_EVENT_EXIST:
-                                       WARN("Kernel event %s%s already enabled (channel %s, session %s)",
-                                                       event_name,
-                                                       exclusion_string,
-                                                       print_channel_name(channel_name), session_name);
-                                       warn = 1;
-                                       break;
-                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
-                               {
-                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
-                                       ERR("Event %s%s: %s (channel %s, session %s)", event_name,
-                                                       exclusion_string,
-                                                       msg,
-                                                       print_channel_name(channel_name),
-                                                       session_name);
-                                       error = 1;
-                                       break;
-                               }
-                               case LTTNG_ERR_SDT_PROBE_SEMAPHORE:
-                                       ERR("SDT probes %s guarded by semaphores are not supported (channel %s, session %s)",
-                                                       event_name, print_channel_name(channel_name),
-                                                       session_name);
-                                       error = 1;
-                                       break;
-                               default:
-                                       ERR("Event %s%s: %s (channel %s, session %s)", event_name,
-                                                       exclusion_string,
-                                                       lttng_strerror(command_ret),
-                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
-                                                               ? print_raw_channel_name(channel_name)
-                                                               : print_channel_name(channel_name),
-                                                       session_name);
-                                       error = 1;
-                                       break;
-                               }
-                               error_holder = command_ret;
-                       } else {
-                               switch (dom.type) {
-                               case LTTNG_DOMAIN_KERNEL:
-                               case LTTNG_DOMAIN_UST:
-                                       MSG("%s event %s%s created in channel %s",
-                                               lttng_domain_type_str(dom.type),
-                                               event_name,
-                                               exclusion_string,
-                                               print_channel_name(channel_name));
-                                       break;
-                               case LTTNG_DOMAIN_JUL:
-                               case LTTNG_DOMAIN_LOG4J:
-                               case LTTNG_DOMAIN_PYTHON:
-                                       /*
-                                        * Don't print the default channel
-                                        * name for agent domains.
-                                        */
-                                       MSG("%s event %s%s enabled",
-                                               lttng_domain_type_str(dom.type),
-                                               event_name,
-                                               exclusion_string);
-                                       break;
-                               default:
-                                       abort();
-                               }
-                       }
-                       free(exclusion_string);
-               }
-
-               if (opt_filter) {
-                       char *exclusion_string;
-
-                       /* Filter present */
-                       ev->filter = 1;
-
-                       command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
-                                       opt_filter,
-                                       lttng_dynamic_pointer_array_get_count(&exclusions),
-                                       (char **) exclusions.array.buffer.data);
-                       exclusion_string = print_exclusions(&exclusions);
-                       if (!exclusion_string) {
-                               PERROR("Cannot allocate exclusion_string");
-                               error = 1;
-                               goto end;
-                       }
-                       if (command_ret < 0) {
-                               switch (-command_ret) {
-                               case LTTNG_ERR_FILTER_EXIST:
-                                       WARN("Filter on event %s%s is already enabled"
-                                                       " (channel %s, session %s)",
-                                               event_name,
-                                               exclusion_string,
-                                               print_channel_name(channel_name), session_name);
-                                       warn = 1;
-                                       break;
-                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
-                               {
-                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
-                                       ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name,
-                                                       exclusion_string,
-                                                       msg,
-                                                       print_channel_name(channel_name),
-                                                       session_name, opt_filter);
-                                       error = 1;
-                                       break;
-                               }
-                               default:
-                                       ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name,
-                                                       exclusion_string,
-                                                       lttng_strerror(command_ret),
-                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
-                                                               ? print_raw_channel_name(channel_name)
-                                                               : print_channel_name(channel_name),
-                                                       session_name, opt_filter);
-                                       error = 1;
-                                       break;
-                               }
-                               error_holder = command_ret;
-
-                       } else {
-                               MSG("Event %s%s: Filter '%s' successfully set",
-                                               event_name, exclusion_string,
-                                               opt_filter);
-                       }
-                       free(exclusion_string);
-               }
-
-               if (lttng_opt_mi) {
-                       if (command_ret) {
-                               success = 0;
-                               ev->enabled = 0;
-                       } else {
-                               ev->enabled = 1;
-                       }
-
-                       ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* print exclusion */
-                       ret = mi_print_exclusion(&exclusions);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto error;
-                       }
-
-                       /* Success ? */
-                       ret = mi_lttng_writer_write_element_bool(writer,
-                                       mi_lttng_element_command_success, success);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       /* Close event element */
-                       ret = mi_lttng_writer_close_element(writer);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-
-               /* Next event */
-               event_name = strtok(NULL, ",");
-               /* Reset warn, error and success */
-               success = 1;
-       }
-
-end:
-       /* Close Mi */
-       if (lttng_opt_mi) {
-               /* Close events element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-error:
-       if (warn) {
-               ret = CMD_WARNING;
-       }
-       if (error) {
-               ret = CMD_ERROR;
-       }
-       lttng_destroy_handle(handle);
-       lttng_dynamic_pointer_array_reset(&exclusions);
-       lttng_userspace_probe_location_destroy(uprobe_loc);
-
-       /* Overwrite ret with error_holder if there was an actual error with
-        * enabling an event.
-        */
-       ret = error_holder ? error_holder : ret;
-
-       lttng_event_destroy(ev);
-       return ret;
-}
-
-/*
- * Add event to trace session
- */
-int cmd_enable_events(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-       int event_type = -1;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       /* Default event type */
-       opt_event_type = LTTNG_EVENT_ALL;
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_TRACEPOINT:
-                       opt_event_type = LTTNG_EVENT_TRACEPOINT;
-                       break;
-               case OPT_PROBE:
-                       opt_event_type = LTTNG_EVENT_PROBE;
-                       break;
-               case OPT_USERSPACE_PROBE:
-                       opt_event_type = LTTNG_EVENT_USERSPACE_PROBE;
-                       break;
-               case OPT_FUNCTION:
-                       opt_event_type = LTTNG_EVENT_FUNCTION;
-                       break;
-               case OPT_SYSCALL:
-                       opt_event_type = LTTNG_EVENT_SYSCALL;
-                       break;
-               case OPT_USERSPACE:
-                       opt_userspace = 1;
-                       break;
-               case OPT_LOGLEVEL:
-                       opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
-                       opt_loglevel = poptGetOptArg(pc);
-                       break;
-               case OPT_LOGLEVEL_ONLY:
-                       opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
-                       opt_loglevel = poptGetOptArg(pc);
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_FILTER:
-                       break;
-               case OPT_EXCLUDE:
-                       break;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-
-               /* Validate event type. Multiple event type are not supported. */
-               if (event_type == -1) {
-                       event_type = opt_event_type;
-               } else {
-                       if (event_type != opt_event_type) {
-                               ERR("Multiple event type not supported.");
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace + opt_jul + opt_log4j +
-                                       opt_python,
-                       true);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_enable_event);
-               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;
-               }
-       }
-
-       opt_event_list = (char*) poptGetArg(pc);
-       if (opt_event_list == NULL && opt_enable_all == 0) {
-               ERR("Missing event name(s).\n");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       command_ret = CMD_ERROR;
-                       success = 0;
-                       goto mi_closing;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       command_ret = enable_events(session_name);
-       if (command_ret) {
-               success = 0;
-               goto mi_closing;
-       }
-
-mi_closing:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       if (opt_session_name == NULL) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred in enable_events */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
-
diff --git a/src/bin/lttng/commands/enable_events.cpp b/src/bin/lttng/commands/enable_events.cpp
new file mode 100644 (file)
index 0000000..50854fa
--- /dev/null
@@ -0,0 +1,1396 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/compat/string.h>
+#include <common/compat/getenv.h>
+#include <common/string-utils/string-utils.h>
+#include <common/utils.h>
+
+/* Mi dependancy */
+#include <common/mi-lttng.h>
+
+#include <lttng/domain-internal.h>
+#include <lttng/event-internal.h>
+
+#include "../command.h"
+#include "../loglevel.h"
+#include "../uprobe.h"
+
+#if (LTTNG_SYMBOL_NAME_LEN == 256)
+#define LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API    "255"
+#endif
+
+static char *opt_event_list;
+static int opt_event_type;
+static const char *opt_loglevel;
+static int opt_loglevel_type;
+static int opt_kernel;
+static char *opt_session_name;
+static int opt_userspace;
+static int opt_jul;
+static int opt_log4j;
+static int opt_python;
+static int opt_enable_all;
+static char *opt_probe;
+static char *opt_userspace_probe;
+static char *opt_function;
+static char *opt_channel_name;
+static char *opt_filter;
+static char *opt_exclude;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-enable-event.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_TRACEPOINT,
+       OPT_PROBE,
+       OPT_USERSPACE_PROBE,
+       OPT_FUNCTION,
+       OPT_SYSCALL,
+       OPT_USERSPACE,
+       OPT_LOGLEVEL,
+       OPT_LOGLEVEL_ONLY,
+       OPT_LIST_OPTIONS,
+       OPT_FILTER,
+       OPT_EXCLUDE,
+};
+
+static struct lttng_handle *handle;
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",        's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"all",            'a', POPT_ARG_VAL, &opt_enable_all, 1, 0, 0},
+       {"channel",        'c', POPT_ARG_STRING, &opt_channel_name, 0, 0, 0},
+       {"kernel",         'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"userspace",      'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
+       {"jul",            'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
+       {"log4j",          'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
+       {"python",         'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
+       {"tracepoint",     0,   POPT_ARG_NONE, 0, OPT_TRACEPOINT, 0, 0},
+       {"probe",          0,   POPT_ARG_STRING, &opt_probe, OPT_PROBE, 0, 0},
+       {"userspace-probe",0,   POPT_ARG_STRING, &opt_userspace_probe, OPT_USERSPACE_PROBE, 0, 0},
+       {"function",       0,   POPT_ARG_STRING, &opt_function, OPT_FUNCTION, 0, 0},
+       {"syscall",        0,   POPT_ARG_NONE, 0, OPT_SYSCALL, 0, 0},
+       {"loglevel",       0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL, 0, 0},
+       {"loglevel-only",  0,     POPT_ARG_STRING, 0, OPT_LOGLEVEL_ONLY, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"filter",         'f', POPT_ARG_STRING, &opt_filter, OPT_FILTER, 0, 0},
+       {"exclude",        'x', POPT_ARG_STRING, &opt_exclude, OPT_EXCLUDE, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Parse probe options.
+ */
+static int parse_probe_opts(struct lttng_event *ev, char *opt)
+{
+       int ret = CMD_SUCCESS;
+       int match;
+       char s_hex[19];
+#define S_HEX_LEN_SCANF_IS_A_BROKEN_API "18"   /* 18 is (19 - 1) (\0 is extra) */
+       char name[LTTNG_SYMBOL_NAME_LEN];
+
+       if (opt == NULL) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Check for symbol+offset */
+       match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API
+                       "[^'+']+%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", name, s_hex);
+       if (match == 2) {
+               strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
+               ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+               DBG("probe symbol %s", ev->attr.probe.symbol_name);
+               if (*s_hex == '\0') {
+                       ERR("Invalid probe offset %s", s_hex);
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               ev->attr.probe.offset = strtoul(s_hex, NULL, 0);
+               DBG("probe offset %" PRIu64, ev->attr.probe.offset);
+               ev->attr.probe.addr = 0;
+               goto end;
+       }
+
+       /* Check for symbol */
+       if (isalpha(name[0]) || name[0] == '_') {
+               match = sscanf(opt, "%" LTTNG_SYMBOL_NAME_LEN_SCANF_IS_A_BROKEN_API "s",
+                       name);
+               if (match == 1) {
+                       strncpy(ev->attr.probe.symbol_name, name, LTTNG_SYMBOL_NAME_LEN);
+                       ev->attr.probe.symbol_name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+                       DBG("probe symbol %s", ev->attr.probe.symbol_name);
+                       ev->attr.probe.offset = 0;
+                       DBG("probe offset %" PRIu64, ev->attr.probe.offset);
+                       ev->attr.probe.addr = 0;
+                       goto end;
+               }
+       }
+
+       /* Check for address */
+       match = sscanf(opt, "%" S_HEX_LEN_SCANF_IS_A_BROKEN_API "s", s_hex);
+       if (match > 0) {
+               /*
+                * Return an error if the first character of the tentative
+                * address is NULL or not a digit. It can be "0" if the address
+                * is in hexadecimal and can be 1 to 9 if it's in decimal.
+                */
+               if (*s_hex == '\0' || !isdigit(*s_hex)) {
+                       ERR("Invalid probe description %s", s_hex);
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               ev->attr.probe.addr = strtoul(s_hex, NULL, 0);
+               DBG("probe addr %" PRIu64, ev->attr.probe.addr);
+               ev->attr.probe.offset = 0;
+               memset(ev->attr.probe.symbol_name, 0, LTTNG_SYMBOL_NAME_LEN);
+               goto end;
+       }
+
+       /* No match */
+       ret = CMD_ERROR;
+
+end:
+       return ret;
+}
+
+static
+const char *print_channel_name(const char *name)
+{
+       return name ? : DEFAULT_CHANNEL_NAME;
+}
+
+static
+const char *print_raw_channel_name(const char *name)
+{
+       return name ? : "<default>";
+}
+
+/*
+ * Mi print exlcusion list
+ */
+static
+int mi_print_exclusion(const struct lttng_dynamic_pointer_array *exclusions)
+{
+       int ret;
+       size_t i;
+       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
+
+       LTTNG_ASSERT(writer);
+
+       if (count == 0) {
+               ret = 0;
+               goto end;
+       }
+
+       ret = mi_lttng_writer_open_element(writer, config_element_exclusions);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
+               ret = mi_lttng_writer_write_element_string(writer,
+                               config_element_exclusion, exclusion);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close exclusions element */
+       ret = mi_lttng_writer_close_element(writer);
+
+end:
+       return ret;
+}
+
+/*
+ * Return allocated string for pretty-printing exclusion names.
+ */
+static
+char *print_exclusions(const struct lttng_dynamic_pointer_array *exclusions)
+{
+       int length = 0;
+       size_t i;
+       const char preamble[] = " excluding ";
+       char *ret;
+       const size_t count = lttng_dynamic_pointer_array_get_count(exclusions);
+
+       if (count == 0) {
+               return strdup("");
+       }
+
+       /* Calculate total required length. */
+       for (i = 0; i < count; i++) {
+               const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
+               length += strlen(exclusion) + 4;
+       }
+
+       length += sizeof(preamble);
+       ret = (char *) zmalloc(length);
+       if (!ret) {
+               return NULL;
+       }
+
+       strncpy(ret, preamble, length);
+       for (i = 0; i < count; i++) {
+               const char *exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(
+                               exclusions, i);
+
+               strcat(ret, "\"");
+               strcat(ret, exclusion);
+               strcat(ret, "\"");
+               if (i != count - 1) {
+                       strcat(ret, ", ");
+               }
+       }
+
+       return ret;
+}
+
+static
+int check_exclusion_subsets(const char *event_name, const char *exclusion)
+{
+       bool warn = false;
+       int ret = 0;
+       const char *e = event_name;
+       const char *x = exclusion;
+
+       /* Scan both the excluder and the event letter by letter */
+       while (true) {
+               if (*e == '\\') {
+                       if (*x != *e) {
+                               warn = true;
+                               goto end;
+                       }
+
+                       e++;
+                       x++;
+                       goto cmp_chars;
+               }
+
+               if (*x == '*') {
+                       /* Event is a subset of the excluder */
+                       ERR("Event %s: %s excludes all events from %s",
+                               event_name, exclusion, event_name);
+                       goto error;
+               }
+
+               if (*e == '*') {
+                       /*
+                        * Reached the end of the event name before the
+                        * end of the exclusion: this is valid.
+                        */
+                       goto end;
+               }
+
+cmp_chars:
+               if (*x != *e) {
+                       warn = true;
+                       break;
+               }
+
+               x++;
+               e++;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       if (warn) {
+               WARN("Event %s: %s does not exclude any events from %s",
+                       event_name, exclusion, event_name);
+       }
+
+       return ret;
+}
+
+int validate_exclusion_list(const char *event_name,
+               const struct lttng_dynamic_pointer_array *exclusions)
+{
+       int ret;
+
+       /* Event name must be a valid globbing pattern to allow exclusions. */
+       if (!strutils_is_star_glob_pattern(event_name)) {
+               ERR("Event %s: Exclusions can only be used with a globbing pattern",
+                       event_name);
+               goto error;
+       }
+
+       /*
+        * If the event name is a star-at-end only globbing pattern,
+        * then we can validate the individual exclusions. Otherwise
+        * all exclusions are passed to the session daemon.
+        */
+       if (strutils_is_star_at_the_end_only_glob_pattern(event_name)) {
+               size_t i, num_exclusions;
+
+               num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
+
+               for (i = 0; i < num_exclusions; i++) {
+                       const char *exclusion =
+                                       (const char *) lttng_dynamic_pointer_array_get_pointer(
+                                                       exclusions, i);
+
+                       if (!strutils_is_star_glob_pattern(exclusion) ||
+                                       strutils_is_star_at_the_end_only_glob_pattern(exclusion)) {
+                               ret = check_exclusion_subsets(event_name, exclusion);
+                               if (ret) {
+                                       goto error;
+                               }
+                       }
+               }
+       }
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = -1;
+
+end:
+       return ret;
+}
+
+static int create_exclusion_list_and_validate(const char *event_name,
+               const char *exclusions_arg,
+               struct lttng_dynamic_pointer_array *exclusions)
+{
+       int ret = 0;
+
+       /* Split exclusions. */
+       ret = strutils_split(exclusions_arg, ',', true, exclusions);
+       if (ret < 0) {
+               goto error;
+       }
+
+       if (validate_exclusion_list(event_name, exclusions) !=
+                       0) {
+               goto error;
+       }
+
+       goto end;
+
+error:
+       ret = -1;
+       lttng_dynamic_pointer_array_reset(exclusions);
+
+end:
+       return ret;
+}
+
+static void warn_on_truncated_exclusion_names(const struct lttng_dynamic_pointer_array *exclusions,
+       int *warn)
+{
+       size_t i;
+       const size_t num_exclusions = lttng_dynamic_pointer_array_get_count(exclusions);
+
+       for (i = 0; i < num_exclusions; i++) {
+               const char * const exclusion = (const char *) lttng_dynamic_pointer_array_get_pointer(exclusions, i);
+
+               if (strlen(exclusion) >= LTTNG_SYMBOL_NAME_LEN) {
+                       WARN("Event exclusion \"%s\" will be truncated",
+                                       exclusion);
+                       *warn = 1;
+               }
+       }
+}
+
+/*
+ * Enabling event using the lttng API.
+ * Note: in case of error only the last error code will be return.
+ */
+static int enable_events(char *session_name)
+{
+       int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS;
+       int error_holder = CMD_SUCCESS, warn = 0, error = 0, success = 1;
+       char *event_name, *channel_name = NULL;
+       struct lttng_event *ev;
+       struct lttng_domain dom = {};
+       struct lttng_dynamic_pointer_array exclusions;
+       struct lttng_userspace_probe_location *uprobe_loc = NULL;
+
+       lttng_dynamic_pointer_array_init(&exclusions, NULL);
+
+       ev = lttng_event_create();
+       if (!ev) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if (opt_kernel) {
+               if (opt_loglevel) {
+                       WARN("Kernel loglevels are not supported.");
+               }
+       }
+
+       /* Create lttng domain */
+       if (opt_kernel) {
+               dom.type = LTTNG_DOMAIN_KERNEL;
+               dom.buf_type = LTTNG_BUFFER_GLOBAL;
+       } else if (opt_userspace) {
+               dom.type = LTTNG_DOMAIN_UST;
+               /* Default. */
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       } else if (opt_jul) {
+               dom.type = LTTNG_DOMAIN_JUL;
+               /* Default. */
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       } else if (opt_log4j) {
+               dom.type = LTTNG_DOMAIN_LOG4J;
+               /* Default. */
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       } else if (opt_python) {
+               dom.type = LTTNG_DOMAIN_PYTHON;
+               /* Default. */
+               dom.buf_type = LTTNG_BUFFER_PER_UID;
+       } else {
+               /* Checked by the caller. */
+               abort();
+       }
+
+       if (opt_exclude) {
+               switch (dom.type) {
+               case LTTNG_DOMAIN_KERNEL:
+               case LTTNG_DOMAIN_JUL:
+               case LTTNG_DOMAIN_LOG4J:
+               case LTTNG_DOMAIN_PYTHON:
+                       ERR("Event name exclusions are not yet implemented for %s events",
+                                       lttng_domain_type_str(dom.type));
+                       ret = CMD_ERROR;
+                       goto error;
+               case LTTNG_DOMAIN_UST:
+                       /* Exclusions supported */
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       /*
+        * Adding a filter to a probe, function or userspace-probe would be
+        * denied by the kernel tracer as it's not supported at the moment. We
+        * do an early check here to warn the user.
+        */
+       if (opt_filter && opt_kernel) {
+               switch (opt_event_type) {
+               case LTTNG_EVENT_ALL:
+               case LTTNG_EVENT_TRACEPOINT:
+               case LTTNG_EVENT_SYSCALL:
+                       break;
+               case LTTNG_EVENT_PROBE:
+               case LTTNG_EVENT_USERSPACE_PROBE:
+               case LTTNG_EVENT_FUNCTION:
+                       ERR("Filter expressions are not supported for %s events",
+                                       get_event_type_str((lttng_event_type) opt_event_type));
+                       ret = CMD_ERROR;
+                       goto error;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto error;
+               }
+       }
+
+       channel_name = opt_channel_name;
+
+       handle = lttng_create_handle(session_name, &dom);
+       if (handle == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Prepare Mi */
+       if (lttng_opt_mi) {
+               /* Open a events element */
+               ret = mi_lttng_writer_open_element(writer, config_element_events);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       if (opt_enable_all) {
+               /* Default setup for enable all */
+               if (opt_kernel) {
+                       ev->type = (lttng_event_type) opt_event_type;
+                       strcpy(ev->name, "*");
+                       /* kernel loglevels not implemented */
+                       ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               } else {
+                       ev->type = LTTNG_EVENT_TRACEPOINT;
+                       strcpy(ev->name, "*");
+                       ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
+                       if (opt_loglevel) {
+                               int name_search_ret;
+
+                               LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
+
+                               if (opt_userspace) {
+                                       enum lttng_loglevel loglevel;
+
+                                       name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               } else if (opt_jul) {
+                                       enum lttng_loglevel_jul loglevel;
+
+                                       name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               } else if (opt_log4j) {
+                                       enum lttng_loglevel_log4j loglevel;
+
+                                       name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               } else {
+                                       /* python domain. */
+                                       enum lttng_loglevel_python loglevel;
+
+                                       name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               }
+
+                               if (name_search_ret == -1) {
+                                       ERR("Unknown loglevel %s", opt_loglevel);
+                                       ret = -LTTNG_ERR_INVALID;
+                                       goto error;
+                               }
+                       } else {
+                               LTTNG_ASSERT(opt_userspace || opt_jul || opt_log4j || opt_python);
+                               if (opt_userspace) {
+                                       ev->loglevel = -1;
+                               } else if (opt_jul) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
+                               } else if (opt_log4j) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
+                               } else if (opt_python) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
+                               }
+                       }
+               }
+
+               if (opt_exclude) {
+                       ret = create_exclusion_list_and_validate("*",
+                               opt_exclude, &exclusions);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       ev->exclusion = 1;
+                       warn_on_truncated_exclusion_names(&exclusions,
+                               &warn);
+               }
+               if (!opt_filter) {
+                       ret = lttng_enable_event_with_exclusions(handle,
+                                       ev, channel_name,
+                                       NULL,
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       if (ret < 0) {
+                               switch (-ret) {
+                               case LTTNG_ERR_KERN_EVENT_EXIST:
+                                       WARN("Kernel events already enabled (channel %s, session %s)",
+                                                       print_channel_name(channel_name), session_name);
+                                       warn = 1;
+                                       break;
+                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                               {
+                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
+                                       ERR("Events: %s (channel %s, session %s)",
+                                                       msg,
+                                                       print_channel_name(channel_name),
+                                                       session_name);
+                                       error = 1;
+                                       break;
+                               }
+                               default:
+                                       ERR("Events: %s (channel %s, session %s)",
+                                                       lttng_strerror(ret),
+                                                       ret == -LTTNG_ERR_NEED_CHANNEL_NAME
+                                                               ? print_raw_channel_name(channel_name)
+                                                               : print_channel_name(channel_name),
+                                                       session_name);
+                                       error = 1;
+                                       break;
+                               }
+                               goto end;
+                       }
+
+                       switch (opt_event_type) {
+                       case LTTNG_EVENT_TRACEPOINT:
+                               if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
+                                       char *exclusion_string = print_exclusions(&exclusions);
+
+                                       if (!exclusion_string) {
+                                               PERROR("Cannot allocate exclusion_string");
+                                               error = 1;
+                                               goto end;
+                                       }
+                                       MSG("All %s tracepoints%s are enabled in channel %s for loglevel %s",
+                                                       lttng_domain_type_str(dom.type),
+                                                       exclusion_string,
+                                                       print_channel_name(channel_name),
+                                                       opt_loglevel);
+                                       free(exclusion_string);
+                               } else {
+                                       char *exclusion_string = print_exclusions(&exclusions);
+
+                                       if (!exclusion_string) {
+                                               PERROR("Cannot allocate exclusion_string");
+                                               error = 1;
+                                               goto end;
+                                       }
+                                       MSG("All %s tracepoints%s are enabled in channel %s",
+                                                       lttng_domain_type_str(dom.type),
+                                                       exclusion_string,
+                                                       print_channel_name(channel_name));
+                                       free(exclusion_string);
+                               }
+                               break;
+                       case LTTNG_EVENT_SYSCALL:
+                               if (opt_kernel) {
+                                       MSG("All %s system calls are enabled in channel %s",
+                                                       lttng_domain_type_str(dom.type),
+                                                       print_channel_name(channel_name));
+                               }
+                               break;
+                       case LTTNG_EVENT_ALL:
+                               if (opt_loglevel && dom.type != LTTNG_DOMAIN_KERNEL) {
+                                       char *exclusion_string = print_exclusions(&exclusions);
+
+                                       if (!exclusion_string) {
+                                               PERROR("Cannot allocate exclusion_string");
+                                               error = 1;
+                                               goto end;
+                                       }
+                                       MSG("All %s events%s are enabled in channel %s for loglevel %s",
+                                                       lttng_domain_type_str(dom.type),
+                                                       exclusion_string,
+                                                       print_channel_name(channel_name),
+                                                       opt_loglevel);
+                                       free(exclusion_string);
+                               } else {
+                                       char *exclusion_string = print_exclusions(&exclusions);
+
+                                       if (!exclusion_string) {
+                                               PERROR("Cannot allocate exclusion_string");
+                                               error = 1;
+                                               goto end;
+                                       }
+                                       MSG("All %s events%s are enabled in channel %s",
+                                                       lttng_domain_type_str(dom.type),
+                                                       exclusion_string,
+                                                       print_channel_name(channel_name));
+                                       free(exclusion_string);
+                               }
+                               break;
+                       default:
+                               /*
+                                * We should not be here since lttng_enable_event should have
+                                * failed on the event type.
+                                */
+                               goto error;
+                       }
+               }
+
+               if (opt_filter) {
+                       command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
+                                       opt_filter,
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       if (command_ret < 0) {
+                               switch (-command_ret) {
+                               case LTTNG_ERR_FILTER_EXIST:
+                                       WARN("Filter on all events is already enabled"
+                                                       " (channel %s, session %s)",
+                                               print_channel_name(channel_name), session_name);
+                                       warn = 1;
+                                       break;
+                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                               {
+                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
+                                       ERR("All events: %s (channel %s, session %s, filter \'%s\')",
+                                                       msg,
+                                                       print_channel_name(channel_name),
+                                                       session_name, opt_filter);
+                                       error = 1;
+                                       break;
+                               }
+                               default:
+                                       ERR("All events: %s (channel %s, session %s, filter \'%s\')",
+                                                       lttng_strerror(command_ret),
+                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
+                                                               ? print_raw_channel_name(channel_name)
+                                                               : print_channel_name(channel_name),
+                                                       session_name, opt_filter);
+                                       error = 1;
+                                       break;
+                               }
+                               error_holder = command_ret;
+                       } else {
+                               ev->filter = 1;
+                               MSG("Filter '%s' successfully set", opt_filter);
+                       }
+               }
+
+               if (lttng_opt_mi) {
+                       /* The wildcard * is used for kernel and ust domain to
+                        * represent ALL. We copy * in event name to force the wildcard use
+                        * for kernel domain
+                        *
+                        * Note: this is strictly for semantic and printing while in
+                        * machine interface mode.
+                        */
+                       strcpy(ev->name, "*");
+
+                       /* If we reach here the events are enabled */
+                       if (!error && !warn) {
+                               ev->enabled = 1;
+                       } else {
+                               ev->enabled = 0;
+                               success = 0;
+                       }
+                       ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* print exclusion */
+                       ret = mi_print_exclusion(&exclusions);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Success ? */
+                       ret = mi_lttng_writer_write_element_bool(writer,
+                                       mi_lttng_element_command_success, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Close event element */
+                       ret = mi_lttng_writer_close_element(writer);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+               }
+
+               goto end;
+       }
+
+       /* Strip event list */
+       event_name = strtok(opt_event_list, ",");
+       while (event_name != NULL) {
+               /* Copy name and type of the event */
+               strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
+               ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+               ev->type = (lttng_event_type) opt_event_type;
+
+               /* Kernel tracer action */
+               if (opt_kernel) {
+                       DBG("Enabling kernel event %s for channel %s",
+                                       event_name,
+                                       print_channel_name(channel_name));
+
+                       switch (opt_event_type) {
+                       case LTTNG_EVENT_ALL:   /* Enable tracepoints and syscalls */
+                               /* If event name differs from *, select tracepoint. */
+                               if (strcmp(ev->name, "*")) {
+                                       ev->type = LTTNG_EVENT_TRACEPOINT;
+                               }
+                               break;
+                       case LTTNG_EVENT_TRACEPOINT:
+                               break;
+                       case LTTNG_EVENT_PROBE:
+                               ret = parse_probe_opts(ev, opt_probe);
+                               if (ret) {
+                                       ERR("Unable to parse probe options");
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               break;
+                       case LTTNG_EVENT_USERSPACE_PROBE:
+                               LTTNG_ASSERT(ev->type == LTTNG_EVENT_USERSPACE_PROBE);
+
+                               ret = parse_userspace_probe_opts(opt_userspace_probe, &uprobe_loc);
+                               if (ret) {
+                                       switch (ret) {
+                                       case CMD_UNSUPPORTED:
+                                               /*
+                                                * Error message describing
+                                                * what is not supported was
+                                                * printed in the function.
+                                                */
+                                               break;
+                                       case CMD_ERROR:
+                                       default:
+                                               ERR("Unable to parse userspace probe options");
+                                               break;
+                                       }
+                                       goto error;
+                               }
+
+                               ret = lttng_event_set_userspace_probe_location(ev, uprobe_loc);
+                               if (ret) {
+                                       WARN("Failed to set probe location on event");
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+
+                               /* Ownership of the uprobe location was transferred to the event. */
+                               uprobe_loc = NULL;
+                               break;
+                       case LTTNG_EVENT_FUNCTION:
+                               ret = parse_probe_opts(ev, opt_function);
+                               if (ret) {
+                                       ERR("Unable to parse function probe options");
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               break;
+                       case LTTNG_EVENT_SYSCALL:
+                               ev->type = LTTNG_EVENT_SYSCALL;
+                               break;
+                       default:
+                               ret = CMD_UNDEFINED;
+                               goto error;
+                       }
+
+                       /* kernel loglevels not implemented */
+                       ev->loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+               } else if (opt_userspace) {             /* User-space tracer action */
+                       DBG("Enabling UST event %s for channel %s, loglevel %s", event_name,
+                                       print_channel_name(channel_name), opt_loglevel ? : "<all>");
+
+                       switch (opt_event_type) {
+                       case LTTNG_EVENT_ALL:   /* Default behavior is tracepoint */
+                               /* Fall-through */
+                       case LTTNG_EVENT_TRACEPOINT:
+                               /* Copy name and type of the event */
+                               ev->type = LTTNG_EVENT_TRACEPOINT;
+                               strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
+                               ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+                               break;
+                       case LTTNG_EVENT_PROBE:
+                       case LTTNG_EVENT_FUNCTION:
+                       case LTTNG_EVENT_SYSCALL:
+                       case LTTNG_EVENT_USERSPACE_PROBE:
+                       default:
+                               ERR("Event type not available for user-space tracing");
+                               ret = CMD_UNSUPPORTED;
+                               goto error;
+                       }
+
+                       if (opt_exclude) {
+                               ev->exclusion = 1;
+                               if (opt_event_type != LTTNG_EVENT_ALL && opt_event_type != LTTNG_EVENT_TRACEPOINT) {
+                                       ERR("Exclusion option can only be used with tracepoint events");
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+                               /* Free previously allocated items. */
+                               lttng_dynamic_pointer_array_reset(&exclusions);
+                               ret = create_exclusion_list_and_validate(
+                                       event_name, opt_exclude,
+                                       &exclusions);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto error;
+                               }
+
+                               warn_on_truncated_exclusion_names(
+                                       &exclusions, &warn);
+                       }
+
+                       ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
+                       if (opt_loglevel) {
+                               enum lttng_loglevel loglevel;
+                               const int name_search_ret = loglevel_name_to_value(opt_loglevel, &loglevel);
+
+                               if (name_search_ret == -1) {
+                                       ERR("Unknown loglevel %s", opt_loglevel);
+                                       ret = -LTTNG_ERR_INVALID;
+                                       goto error;
+                               }
+
+                               ev->loglevel = (int) loglevel;
+                       } else {
+                               ev->loglevel = -1;
+                       }
+               } else if (opt_jul || opt_log4j || opt_python) {
+                       if (opt_event_type != LTTNG_EVENT_ALL &&
+                                       opt_event_type != LTTNG_EVENT_TRACEPOINT) {
+                               ERR("Event type not supported for domain.");
+                               ret = CMD_UNSUPPORTED;
+                               goto error;
+                       }
+
+                       ev->loglevel_type = (lttng_loglevel_type) opt_loglevel_type;
+                       if (opt_loglevel) {
+                               int name_search_ret;
+
+                               if (opt_jul) {
+                                       enum lttng_loglevel_jul loglevel;
+
+                                       name_search_ret = loglevel_jul_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               } else if (opt_log4j) {
+                                       enum lttng_loglevel_log4j loglevel;
+
+                                       name_search_ret = loglevel_log4j_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               } else {
+                                       /* python domain. */
+                                       enum lttng_loglevel_python loglevel;
+
+                                       name_search_ret = loglevel_python_name_to_value(opt_loglevel, &loglevel);
+                                       ev->loglevel = (int) loglevel;
+                               }
+
+                               if (name_search_ret) {
+                                       ERR("Unknown loglevel %s", opt_loglevel);
+                                       ret = -LTTNG_ERR_INVALID;
+                                       goto error;
+                               }
+                       } else {
+                               if (opt_jul) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_JUL_ALL;
+                               } else if (opt_log4j) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_LOG4J_ALL;
+                               } else if (opt_python) {
+                                       ev->loglevel = LTTNG_LOGLEVEL_PYTHON_DEBUG;
+                               }
+                       }
+                       ev->type = LTTNG_EVENT_TRACEPOINT;
+                       strncpy(ev->name, event_name, LTTNG_SYMBOL_NAME_LEN);
+                       ev->name[LTTNG_SYMBOL_NAME_LEN - 1] = '\0';
+               } else {
+                       abort();
+               }
+
+               if (!opt_filter) {
+                       char *exclusion_string;
+
+                       command_ret = lttng_enable_event_with_exclusions(handle,
+                                       ev, channel_name,
+                                       NULL,
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       exclusion_string = print_exclusions(&exclusions);
+                       if (!exclusion_string) {
+                               PERROR("Cannot allocate exclusion_string");
+                               error = 1;
+                               goto end;
+                       }
+                       if (command_ret < 0) {
+                               /* Turn ret to positive value to handle the positive error code */
+                               switch (-command_ret) {
+                               case LTTNG_ERR_KERN_EVENT_EXIST:
+                                       WARN("Kernel event %s%s already enabled (channel %s, session %s)",
+                                                       event_name,
+                                                       exclusion_string,
+                                                       print_channel_name(channel_name), session_name);
+                                       warn = 1;
+                                       break;
+                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                               {
+                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
+                                       ERR("Event %s%s: %s (channel %s, session %s)", event_name,
+                                                       exclusion_string,
+                                                       msg,
+                                                       print_channel_name(channel_name),
+                                                       session_name);
+                                       error = 1;
+                                       break;
+                               }
+                               case LTTNG_ERR_SDT_PROBE_SEMAPHORE:
+                                       ERR("SDT probes %s guarded by semaphores are not supported (channel %s, session %s)",
+                                                       event_name, print_channel_name(channel_name),
+                                                       session_name);
+                                       error = 1;
+                                       break;
+                               default:
+                                       ERR("Event %s%s: %s (channel %s, session %s)", event_name,
+                                                       exclusion_string,
+                                                       lttng_strerror(command_ret),
+                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
+                                                               ? print_raw_channel_name(channel_name)
+                                                               : print_channel_name(channel_name),
+                                                       session_name);
+                                       error = 1;
+                                       break;
+                               }
+                               error_holder = command_ret;
+                       } else {
+                               switch (dom.type) {
+                               case LTTNG_DOMAIN_KERNEL:
+                               case LTTNG_DOMAIN_UST:
+                                       MSG("%s event %s%s created in channel %s",
+                                               lttng_domain_type_str(dom.type),
+                                               event_name,
+                                               exclusion_string,
+                                               print_channel_name(channel_name));
+                                       break;
+                               case LTTNG_DOMAIN_JUL:
+                               case LTTNG_DOMAIN_LOG4J:
+                               case LTTNG_DOMAIN_PYTHON:
+                                       /*
+                                        * Don't print the default channel
+                                        * name for agent domains.
+                                        */
+                                       MSG("%s event %s%s enabled",
+                                               lttng_domain_type_str(dom.type),
+                                               event_name,
+                                               exclusion_string);
+                                       break;
+                               default:
+                                       abort();
+                               }
+                       }
+                       free(exclusion_string);
+               }
+
+               if (opt_filter) {
+                       char *exclusion_string;
+
+                       /* Filter present */
+                       ev->filter = 1;
+
+                       command_ret = lttng_enable_event_with_exclusions(handle, ev, channel_name,
+                                       opt_filter,
+                                       lttng_dynamic_pointer_array_get_count(&exclusions),
+                                       (char **) exclusions.array.buffer.data);
+                       exclusion_string = print_exclusions(&exclusions);
+                       if (!exclusion_string) {
+                               PERROR("Cannot allocate exclusion_string");
+                               error = 1;
+                               goto end;
+                       }
+                       if (command_ret < 0) {
+                               switch (-command_ret) {
+                               case LTTNG_ERR_FILTER_EXIST:
+                                       WARN("Filter on event %s%s is already enabled"
+                                                       " (channel %s, session %s)",
+                                               event_name,
+                                               exclusion_string,
+                                               print_channel_name(channel_name), session_name);
+                                       warn = 1;
+                                       break;
+                               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                               {
+                                       const char *msg = "The command tried to enable an event in a new domain for a session that has already been started once.";
+                                       ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name,
+                                                       exclusion_string,
+                                                       msg,
+                                                       print_channel_name(channel_name),
+                                                       session_name, opt_filter);
+                                       error = 1;
+                                       break;
+                               }
+                               default:
+                                       ERR("Event %s%s: %s (channel %s, session %s, filter \'%s\')", ev->name,
+                                                       exclusion_string,
+                                                       lttng_strerror(command_ret),
+                                                       command_ret == -LTTNG_ERR_NEED_CHANNEL_NAME
+                                                               ? print_raw_channel_name(channel_name)
+                                                               : print_channel_name(channel_name),
+                                                       session_name, opt_filter);
+                                       error = 1;
+                                       break;
+                               }
+                               error_holder = command_ret;
+
+                       } else {
+                               MSG("Event %s%s: Filter '%s' successfully set",
+                                               event_name, exclusion_string,
+                                               opt_filter);
+                       }
+                       free(exclusion_string);
+               }
+
+               if (lttng_opt_mi) {
+                       if (command_ret) {
+                               success = 0;
+                               ev->enabled = 0;
+                       } else {
+                               ev->enabled = 1;
+                       }
+
+                       ret = mi_lttng_event(writer, ev, 1, handle->domain.type);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* print exclusion */
+                       ret = mi_print_exclusion(&exclusions);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto error;
+                       }
+
+                       /* Success ? */
+                       ret = mi_lttng_writer_write_element_bool(writer,
+                                       mi_lttng_element_command_success, success);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       /* Close event element */
+                       ret = mi_lttng_writer_close_element(writer);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+
+               /* Next event */
+               event_name = strtok(NULL, ",");
+               /* Reset warn, error and success */
+               success = 1;
+       }
+
+end:
+       /* Close Mi */
+       if (lttng_opt_mi) {
+               /* Close events element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+error:
+       if (warn) {
+               ret = CMD_WARNING;
+       }
+       if (error) {
+               ret = CMD_ERROR;
+       }
+       lttng_destroy_handle(handle);
+       lttng_dynamic_pointer_array_reset(&exclusions);
+       lttng_userspace_probe_location_destroy(uprobe_loc);
+
+       /* Overwrite ret with error_holder if there was an actual error with
+        * enabling an event.
+        */
+       ret = error_holder ? error_holder : ret;
+
+       lttng_event_destroy(ev);
+       return ret;
+}
+
+/*
+ * Add event to trace session
+ */
+int cmd_enable_events(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+       int event_type = -1;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       /* Default event type */
+       opt_event_type = LTTNG_EVENT_ALL;
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_TRACEPOINT:
+                       opt_event_type = LTTNG_EVENT_TRACEPOINT;
+                       break;
+               case OPT_PROBE:
+                       opt_event_type = LTTNG_EVENT_PROBE;
+                       break;
+               case OPT_USERSPACE_PROBE:
+                       opt_event_type = LTTNG_EVENT_USERSPACE_PROBE;
+                       break;
+               case OPT_FUNCTION:
+                       opt_event_type = LTTNG_EVENT_FUNCTION;
+                       break;
+               case OPT_SYSCALL:
+                       opt_event_type = LTTNG_EVENT_SYSCALL;
+                       break;
+               case OPT_USERSPACE:
+                       opt_userspace = 1;
+                       break;
+               case OPT_LOGLEVEL:
+                       opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_RANGE;
+                       opt_loglevel = poptGetOptArg(pc);
+                       break;
+               case OPT_LOGLEVEL_ONLY:
+                       opt_loglevel_type = LTTNG_EVENT_LOGLEVEL_SINGLE;
+                       opt_loglevel = poptGetOptArg(pc);
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_FILTER:
+                       break;
+               case OPT_EXCLUDE:
+                       break;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+
+               /* Validate event type. Multiple event type are not supported. */
+               if (event_type == -1) {
+                       event_type = opt_event_type;
+               } else {
+                       if (event_type != opt_event_type) {
+                               ERR("Multiple event type not supported.");
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace + opt_jul + opt_log4j +
+                                       opt_python,
+                       true);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_enable_event);
+               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;
+               }
+       }
+
+       opt_event_list = (char*) poptGetArg(pc);
+       if (opt_event_list == NULL && opt_enable_all == 0) {
+               ERR("Missing event name(s).\n");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       command_ret = CMD_ERROR;
+                       success = 0;
+                       goto mi_closing;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       command_ret = enable_events(session_name);
+       if (command_ret) {
+               success = 0;
+               goto mi_closing;
+       }
+
+mi_closing:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred in enable_events */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
+
diff --git a/src/bin/lttng/commands/enable_rotation.c b/src/bin/lttng/commands/enable_rotation.c
deleted file mode 100644 (file)
index c10c6a2..0000000
+++ /dev/null
@@ -1,341 +0,0 @@
-/*
- * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/mi-lttng.h>
-#include <common/utils.h>
-
-#include "../command.h"
-#include <lttng/lttng.h>
-
-static char *opt_session_name;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-enable-rotation.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_TIMER,
-       OPT_SIZE,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"session",     's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"timer",        0,   POPT_ARG_INT, 0, OPT_TIMER, 0, 0},
-       {"size",         0,   POPT_ARG_INT, 0, OPT_SIZE, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static const char *schedule_type_str[] = {
-       [LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC] = "periodic",
-       [LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD] = "size-based",
-};
-
-static enum cmd_error_code add_schedule(const char *session_name,
-               enum lttng_rotation_schedule_type schedule_type, uint64_t value)
-{
-       enum cmd_error_code ret = CMD_SUCCESS;
-       struct lttng_rotation_schedule *schedule = NULL;
-       enum lttng_rotation_status status;
-       const char *schedule_type_name;
-
-       switch (schedule_type) {
-       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
-               schedule = lttng_rotation_schedule_periodic_create();
-               if (!schedule) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               status = lttng_rotation_schedule_periodic_set_period(schedule,
-                               value);
-               break;
-       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
-               schedule = lttng_rotation_schedule_size_threshold_create();
-               if (!schedule) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               status = lttng_rotation_schedule_size_threshold_set_threshold(
-                               schedule, value);
-               break;
-       default:
-               ERR("Unknown schedule type");
-               abort();
-       }
-
-       schedule_type_name = schedule_type_str[schedule_type];
-
-       switch (status) {
-       case LTTNG_ROTATION_STATUS_OK:
-               break;
-       case LTTNG_ROTATION_STATUS_INVALID:
-               ERR("Invalid value for %s option", schedule_type_name);
-               ret = CMD_ERROR;
-               goto end;
-       default:
-               ERR("Unknown error occurred setting %s rotation schedule",
-                               schedule_type_name);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       status = lttng_session_add_rotation_schedule(session_name, schedule);
-       switch (status) {
-       case LTTNG_ROTATION_STATUS_OK:
-               ret = CMD_SUCCESS;
-               switch (schedule_type) {
-               case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
-                       MSG("Enabled %s rotations every %" PRIu64 " %s on session %s",
-                                       schedule_type_name, value, USEC_UNIT, session_name);
-                       break;
-               case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
-                       MSG("Enabled %s rotations every %" PRIu64 " bytes written on session %s",
-                                       schedule_type_name, value, session_name);
-                       break;
-               default:
-                       abort();
-               }
-               break;
-       case LTTNG_ROTATION_STATUS_INVALID:
-               ERR("Invalid parameter for %s rotation schedule",
-                               schedule_type_name);
-               ret = CMD_ERROR;
-               break;
-       case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET:
-               ERR("A %s rotation schedule is already set on session %s",
-                               schedule_type_name,
-                               session_name);
-               ret = CMD_ERROR;
-               break;
-       case LTTNG_ROTATION_STATUS_ERROR:
-       default:
-               ERR("Failed to enable %s rotation schedule on session %s",
-                               schedule_type_name,
-                               session_name);
-               ret = CMD_ERROR;
-               break;
-       }
-
-       if (lttng_opt_mi) {
-               int mi_ret;
-
-               mi_ret = mi_lttng_rotation_schedule_result(writer,
-                               schedule, ret == CMD_SUCCESS);
-               if (mi_ret < 0) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-end:
-       lttng_rotation_schedule_destroy(schedule);
-       return ret;
-}
-
-/*
- *  cmd_enable_rotation
- *
- *  The 'enable-rotation <options>' first level command
- */
-int cmd_enable_rotation(int argc, const char **argv)
-{
-       int popt_ret, opt, ret = 0;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       static poptContext pc;
-       char *session_name = NULL;
-       char *opt_arg = NULL;
-       bool free_session_name = false;
-       uint64_t timer_us = 0, size_bytes = 0;
-       bool periodic_rotation = false, size_rotation = false;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       popt_ret = poptReadDefaultConfig(pc, 0);
-       if (popt_ret) {
-               ERR("poptReadDefaultConfig");
-               goto error;
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_TIMER:
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-                       if (errno != 0 || !isdigit(opt_arg[0])) {
-                               ERR("Invalid value for --timer option: %s", opt_arg);
-                               goto error;
-                       }
-                       if (utils_parse_time_suffix(opt_arg, &timer_us) < 0) {
-                               ERR("Invalid value for --timer option: %s", opt_arg);
-                               goto error;
-                       }
-                       if (periodic_rotation) {
-                               ERR("Only one periodic rotation schedule may be set on a session.");
-                               goto error;
-                       }
-                       periodic_rotation = true;
-                       break;
-               case OPT_SIZE:
-                       errno = 0;
-                       opt_arg = poptGetOptArg(pc);
-                       if (utils_parse_size_suffix(opt_arg, &size_bytes) < 0) {
-                               ERR("Invalid value for --size option: %s", opt_arg);
-                               goto error;
-                       }
-                       if (size_rotation) {
-                               ERR("Only one size-based rotation schedule may be set on a session.");
-                               goto error;
-                       }
-                       size_rotation = true;
-                       break;
-               default:
-                       cmd_ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (opt_session_name == NULL) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       goto error;
-               }
-               free_session_name = true;
-       } else {
-               session_name = opt_session_name;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       goto error;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_enable_rotation);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (!periodic_rotation && !size_rotation) {
-               ERR("No session rotation schedule parameter provided.");
-               cmd_ret = CMD_ERROR;
-               goto close_command;
-       }
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_rotation_schedule_results);
-               if (ret) {
-                       goto error;
-               }
-
-               ret = mi_lttng_writer_write_element_string(writer,
-                               mi_lttng_element_session_name,
-                               session_name);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       if (periodic_rotation) {
-               /*
-                * Continue processing even on error as multiple schedules can
-                * be specified at once.
-                */
-               cmd_ret = add_schedule(session_name,
-                               LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC,
-                               timer_us);
-       }
-
-       if (size_rotation) {
-               enum cmd_error_code tmp_ret;
-
-               /* Don't overwrite cmd_ret if it already indicates an error. */
-               tmp_ret = add_schedule(session_name,
-                               LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD,
-                               size_bytes);
-               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close rotation schedule results element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-close_command:
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success,
-                               cmd_ret == CMD_SUCCESS);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-end:
-       (void) mi_lttng_writer_destroy(writer);
-       poptFreeContext(pc);
-       if (free_session_name) {
-               free(session_name);
-       }
-       return cmd_ret;
-
-error:
-       cmd_ret = CMD_ERROR;
-       goto end;
-}
diff --git a/src/bin/lttng/commands/enable_rotation.cpp b/src/bin/lttng/commands/enable_rotation.cpp
new file mode 100644 (file)
index 0000000..0210f9c
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+#include <common/utils.h>
+
+#include "../command.h"
+#include <lttng/lttng.h>
+
+static char *opt_session_name;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-enable-rotation.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_TIMER,
+       OPT_SIZE,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"session",     's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"timer",        0,   POPT_ARG_INT, 0, OPT_TIMER, 0, 0},
+       {"size",         0,   POPT_ARG_INT, 0, OPT_SIZE, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static const char *schedule_type_str[] = {
+       "periodic",
+       "size-based",
+};
+
+static enum cmd_error_code add_schedule(const char *session_name,
+               enum lttng_rotation_schedule_type schedule_type, uint64_t value)
+{
+       enum cmd_error_code ret = CMD_SUCCESS;
+       struct lttng_rotation_schedule *schedule = NULL;
+       enum lttng_rotation_status status;
+       const char *schedule_type_name;
+
+       switch (schedule_type) {
+       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
+               schedule = lttng_rotation_schedule_periodic_create();
+               if (!schedule) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               status = lttng_rotation_schedule_periodic_set_period(schedule,
+                               value);
+               break;
+       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
+               schedule = lttng_rotation_schedule_size_threshold_create();
+               if (!schedule) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               status = lttng_rotation_schedule_size_threshold_set_threshold(
+                               schedule, value);
+               break;
+       default:
+               ERR("Unknown schedule type");
+               abort();
+       }
+
+       schedule_type_name = schedule_type_str[schedule_type];
+
+       switch (status) {
+       case LTTNG_ROTATION_STATUS_OK:
+               break;
+       case LTTNG_ROTATION_STATUS_INVALID:
+               ERR("Invalid value for %s option", schedule_type_name);
+               ret = CMD_ERROR;
+               goto end;
+       default:
+               ERR("Unknown error occurred setting %s rotation schedule",
+                               schedule_type_name);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       status = lttng_session_add_rotation_schedule(session_name, schedule);
+       switch (status) {
+       case LTTNG_ROTATION_STATUS_OK:
+               ret = CMD_SUCCESS;
+               switch (schedule_type) {
+               case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
+                       MSG("Enabled %s rotations every %" PRIu64 " %s on session %s",
+                                       schedule_type_name, value, USEC_UNIT, session_name);
+                       break;
+               case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
+                       MSG("Enabled %s rotations every %" PRIu64 " bytes written on session %s",
+                                       schedule_type_name, value, session_name);
+                       break;
+               default:
+                       abort();
+               }
+               break;
+       case LTTNG_ROTATION_STATUS_INVALID:
+               ERR("Invalid parameter for %s rotation schedule",
+                               schedule_type_name);
+               ret = CMD_ERROR;
+               break;
+       case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET:
+               ERR("A %s rotation schedule is already set on session %s",
+                               schedule_type_name,
+                               session_name);
+               ret = CMD_ERROR;
+               break;
+       case LTTNG_ROTATION_STATUS_ERROR:
+       default:
+               ERR("Failed to enable %s rotation schedule on session %s",
+                               schedule_type_name,
+                               session_name);
+               ret = CMD_ERROR;
+               break;
+       }
+
+       if (lttng_opt_mi) {
+               int mi_ret;
+
+               mi_ret = mi_lttng_rotation_schedule_result(writer,
+                               schedule, ret == CMD_SUCCESS);
+               if (mi_ret < 0) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+end:
+       lttng_rotation_schedule_destroy(schedule);
+       return ret;
+}
+
+/*
+ *  cmd_enable_rotation
+ *
+ *  The 'enable-rotation <options>' first level command
+ */
+int cmd_enable_rotation(int argc, const char **argv)
+{
+       int popt_ret, opt, ret = 0;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       static poptContext pc;
+       char *session_name = NULL;
+       char *opt_arg = NULL;
+       bool free_session_name = false;
+       uint64_t timer_us = 0, size_bytes = 0;
+       bool periodic_rotation = false, size_rotation = false;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       popt_ret = poptReadDefaultConfig(pc, 0);
+       if (popt_ret) {
+               ERR("poptReadDefaultConfig");
+               goto error;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_TIMER:
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+                       if (errno != 0 || !isdigit(opt_arg[0])) {
+                               ERR("Invalid value for --timer option: %s", opt_arg);
+                               goto error;
+                       }
+                       if (utils_parse_time_suffix(opt_arg, &timer_us) < 0) {
+                               ERR("Invalid value for --timer option: %s", opt_arg);
+                               goto error;
+                       }
+                       if (periodic_rotation) {
+                               ERR("Only one periodic rotation schedule may be set on a session.");
+                               goto error;
+                       }
+                       periodic_rotation = true;
+                       break;
+               case OPT_SIZE:
+                       errno = 0;
+                       opt_arg = poptGetOptArg(pc);
+                       if (utils_parse_size_suffix(opt_arg, &size_bytes) < 0) {
+                               ERR("Invalid value for --size option: %s", opt_arg);
+                               goto error;
+                       }
+                       if (size_rotation) {
+                               ERR("Only one size-based rotation schedule may be set on a session.");
+                               goto error;
+                       }
+                       size_rotation = true;
+                       break;
+               default:
+                       cmd_ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       goto error;
+               }
+               free_session_name = true;
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       goto error;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_enable_rotation);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (!periodic_rotation && !size_rotation) {
+               ERR("No session rotation schedule parameter provided.");
+               cmd_ret = CMD_ERROR;
+               goto close_command;
+       }
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_rotation_schedule_results);
+               if (ret) {
+                       goto error;
+               }
+
+               ret = mi_lttng_writer_write_element_string(writer,
+                               mi_lttng_element_session_name,
+                               session_name);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       if (periodic_rotation) {
+               /*
+                * Continue processing even on error as multiple schedules can
+                * be specified at once.
+                */
+               cmd_ret = add_schedule(session_name,
+                               LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC,
+                               timer_us);
+       }
+
+       if (size_rotation) {
+               enum cmd_error_code tmp_ret;
+
+               /* Don't overwrite cmd_ret if it already indicates an error. */
+               tmp_ret = add_schedule(session_name,
+                               LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD,
+                               size_bytes);
+               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close rotation schedule results element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+close_command:
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success,
+                               cmd_ret == CMD_SUCCESS);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+end:
+       (void) mi_lttng_writer_destroy(writer);
+       poptFreeContext(pc);
+       if (free_session_name) {
+               free(session_name);
+       }
+       return cmd_ret;
+
+error:
+       cmd_ret = CMD_ERROR;
+       goto end;
+}
diff --git a/src/bin/lttng/commands/help.c b/src/bin/lttng/commands/help.c
deleted file mode 100644 (file)
index a9a01e7..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-/*
- * Copyright (C) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "../command.h"
-#include <common/utils.h>
-
-#ifdef LTTNG_EMBED_HELP
-static const char *help_msg =
-#include <lttng-help.1.h>
-;
-#endif
-
-static const char *lttng_help_msg =
-#ifdef LTTNG_EMBED_HELP
-#include <lttng.1.h>
-#else
-NULL
-#endif
-;
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- *  cmd_help
- */
-int cmd_help(int argc, const char **argv, const struct cmd_struct commands[])
-{
-       int opt, ret = CMD_SUCCESS;
-       char *cmd_name;
-       static poptContext pc;
-       const struct cmd_struct *cmd;
-       int found = 0;
-       const char *cmd_argv[2];
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       /* Get command name */
-       cmd_name = (char *) poptGetArg(pc);
-
-       if (cmd_name == NULL) {
-               /* Fall back to lttng(1) */
-               ret = utils_show_help(1, "lttng", lttng_help_msg);
-               if (ret) {
-                       ERR("Cannot show --help for `lttng`");
-                       perror("exec");
-                       ret = CMD_ERROR;
-               }
-
-               goto end;
-       }
-
-       /* Help about help? */
-       if (strcmp(cmd_name, "help") == 0) {
-               SHOW_HELP();
-               goto end;
-       }
-
-       /* Make sure command name exists */
-       cmd = &commands[0];
-
-       while (cmd->name != NULL) {
-               if (strcmp(cmd->name, cmd_name) == 0) {
-                       found = 1;
-                       break;
-               }
-
-               cmd++;
-       }
-
-       if (!found) {
-               ERR("Unknown command \"%s\"", cmd_name);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Show command's help */
-       cmd_argv[0] = cmd->name;
-       cmd_argv[1] = "--help";
-       LTTNG_ASSERT(cmd->func);
-       ret = cmd->func(2, cmd_argv);
-
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/help.cpp b/src/bin/lttng/commands/help.cpp
new file mode 100644 (file)
index 0000000..a9a01e7
--- /dev/null
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "../command.h"
+#include <common/utils.h>
+
+#ifdef LTTNG_EMBED_HELP
+static const char *help_msg =
+#include <lttng-help.1.h>
+;
+#endif
+
+static const char *lttng_help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng.1.h>
+#else
+NULL
+#endif
+;
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ *  cmd_help
+ */
+int cmd_help(int argc, const char **argv, const struct cmd_struct commands[])
+{
+       int opt, ret = CMD_SUCCESS;
+       char *cmd_name;
+       static poptContext pc;
+       const struct cmd_struct *cmd;
+       int found = 0;
+       const char *cmd_argv[2];
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       /* Get command name */
+       cmd_name = (char *) poptGetArg(pc);
+
+       if (cmd_name == NULL) {
+               /* Fall back to lttng(1) */
+               ret = utils_show_help(1, "lttng", lttng_help_msg);
+               if (ret) {
+                       ERR("Cannot show --help for `lttng`");
+                       perror("exec");
+                       ret = CMD_ERROR;
+               }
+
+               goto end;
+       }
+
+       /* Help about help? */
+       if (strcmp(cmd_name, "help") == 0) {
+               SHOW_HELP();
+               goto end;
+       }
+
+       /* Make sure command name exists */
+       cmd = &commands[0];
+
+       while (cmd->name != NULL) {
+               if (strcmp(cmd->name, cmd_name) == 0) {
+                       found = 1;
+                       break;
+               }
+
+               cmd++;
+       }
+
+       if (!found) {
+               ERR("Unknown command \"%s\"", cmd_name);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Show command's help */
+       cmd_argv[0] = cmd->name;
+       cmd_argv[1] = "--help";
+       LTTNG_ASSERT(cmd->func);
+       ret = cmd->func(2, cmd_argv);
+
+end:
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c
deleted file mode 100644 (file)
index f4c97cb..0000000
+++ /dev/null
@@ -1,2635 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdint.h>
-#define _LGPL_SOURCE
-#include <inttypes.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <common/mi-lttng.h>
-#include <common/time.h>
-#include <common/tracker.h>
-#include <lttng/domain-internal.h>
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-static int opt_userspace;
-static int opt_kernel;
-static int opt_jul;
-static int opt_log4j;
-static int opt_python;
-static char *opt_channel;
-static int opt_domain;
-static int opt_fields;
-static int opt_syscall;
-
-const char *indent4 = "    ";
-const char *indent6 = "      ";
-const char *indent8 = "        ";
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-list.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_USERSPACE,
-       OPT_LIST_OPTIONS,
-};
-
-static struct lttng_handle *the_handle;
-static struct mi_writer *the_writer;
-
-/* Only set when listing a single session. */
-static struct lttng_session the_listed_session;
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"kernel",      'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
-       {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
-       {"log4j",       'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
-       {"python",      'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
-       {"userspace",   'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
-       {"channel",     'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
-       {"domain",      'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
-       {"fields",      'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
-       {"syscall",     'S', POPT_ARG_VAL, &opt_syscall, 1, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Get command line from /proc for a specific pid.
- *
- * On success, return an allocated string pointer to the proc cmdline.
- * On error, return NULL.
- */
-static char *get_cmdline_by_pid(pid_t pid)
-{
-       int ret;
-       FILE *fp = NULL;
-       char *cmdline = NULL;
-       /* Can't go bigger than /proc/LTTNG_MAX_PID/cmdline */
-       char path[sizeof("/proc//cmdline") + sizeof(LTTNG_MAX_PID_STR) - 1];
-
-       snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
-       fp = fopen(path, "r");
-       if (fp == NULL) {
-               goto end;
-       }
-
-       /* Caller must free() *cmdline */
-       cmdline = zmalloc(PATH_MAX);
-       if (!cmdline) {
-               PERROR("malloc cmdline");
-               goto end;
-       }
-       ret = fread(cmdline, 1, PATH_MAX, fp);
-       if (ret < 0) {
-               PERROR("fread proc list");
-       }
-
-end:
-       if (fp) {
-               fclose(fp);
-       }
-       return cmdline;
-}
-
-static
-const char *active_string(int value)
-{
-       switch (value) {
-       case 0: return "inactive";
-       case 1: return "active";
-       case -1: return "";
-       default: return NULL;
-       }
-}
-
-static const char *snapshot_string(int value)
-{
-       switch (value) {
-       case 1:
-               return " snapshot";
-       default:
-               return "";
-       }
-}
-
-static
-const char *enabled_string(int value)
-{
-       switch (value) {
-       case 0: return " [disabled]";
-       case 1: return " [enabled]";
-       case -1: return "";
-       default: return NULL;
-       }
-}
-
-static
-const char *safe_string(const char *str)
-{
-       return str ? str : "";
-}
-
-static const char *logleveltype_string(enum lttng_loglevel_type value)
-{
-       switch (value) {
-       case LTTNG_EVENT_LOGLEVEL_ALL:
-               return ":";
-       case LTTNG_EVENT_LOGLEVEL_RANGE:
-               return " <=";
-       case LTTNG_EVENT_LOGLEVEL_SINGLE:
-               return " ==";
-       default:
-               return " <<TYPE UNKN>>";
-       }
-}
-
-static const char *bitness_event(enum lttng_event_flag flags)
-{
-       if (flags & LTTNG_EVENT_FLAG_SYSCALL_32) {
-               if (flags & LTTNG_EVENT_FLAG_SYSCALL_64) {
-                       return " [32/64-bit]";
-               } else {
-                       return " [32-bit]";
-               }
-       } else if (flags & LTTNG_EVENT_FLAG_SYSCALL_64) {
-               return " [64-bit]";
-       } else {
-               return "";
-       }
-}
-
-/*
- * Get exclusion names message for a single event.
- *
- * Returned pointer must be freed by caller. Returns NULL on error.
- */
-static char *get_exclusion_names_msg(struct lttng_event *event)
-{
-       int ret;
-       int exclusion_count;
-       char *exclusion_msg = NULL;
-       char *at;
-       size_t i;
-       const char * const exclusion_fmt = " [exclusions: ";
-       const size_t exclusion_fmt_len = strlen(exclusion_fmt);
-
-       exclusion_count = lttng_event_get_exclusion_name_count(event);
-       if (exclusion_count < 0) {
-               goto end;
-       } else if (exclusion_count == 0) {
-               /*
-                * No exclusions: return copy of empty string so that
-                * it can be freed by caller.
-                */
-               exclusion_msg = strdup("");
-               goto end;
-       }
-
-       /*
-        * exclusion_msg's size is bounded by the exclusion_fmt string,
-        * a comma per entry, the entry count (fixed-size), a closing
-        * bracket, and a trailing \0.
-        */
-       exclusion_msg = malloc(exclusion_count +
-                       exclusion_count * LTTNG_SYMBOL_NAME_LEN +
-                       exclusion_fmt_len + 1);
-       if (!exclusion_msg) {
-               goto end;
-       }
-
-       at = strcpy(exclusion_msg, exclusion_fmt) + exclusion_fmt_len;
-       for (i = 0; i < exclusion_count; ++i) {
-               const char *name;
-
-               /* Append comma between exclusion names */
-               if (i > 0) {
-                       *at = ',';
-                       at++;
-               }
-
-               ret = lttng_event_get_exclusion_name(event, i, &name);
-               if (ret) {
-                       /* Prints '?' on local error; should never happen */
-                       *at = '?';
-                       at++;
-                       continue;
-               }
-
-               /* Append exclusion name */
-               at += sprintf(at, "%s", name);
-       }
-
-       /* This also puts a final '\0' at the end of exclusion_msg */
-       strcpy(at, "]");
-
-end:
-       return exclusion_msg;
-}
-
-static void print_userspace_probe_location(struct lttng_event *event)
-{
-       const struct lttng_userspace_probe_location *location;
-       const struct lttng_userspace_probe_location_lookup_method *lookup_method;
-       enum lttng_userspace_probe_location_lookup_method_type lookup_type;
-
-       location = lttng_event_get_userspace_probe_location(event);
-       if (!location) {
-               MSG("Event has no userspace probe location");
-               return;
-       }
-
-       lookup_method = lttng_userspace_probe_location_get_lookup_method(location);
-       if (!lookup_method) {
-               MSG("Event has no userspace probe location lookup method");
-               return;
-       }
-
-       MSG("%s%s (type: userspace-probe)%s", indent6, event->name, enabled_string(event->enabled));
-
-       lookup_type = lttng_userspace_probe_location_lookup_method_get_type(lookup_method);
-
-       switch (lttng_userspace_probe_location_get_type(location)) {
-       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_UNKNOWN:
-               MSG("%sType: Unknown", indent8);
-               break;
-       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
-       {
-               const char *function_name;
-               char *binary_path;
-
-               MSG("%sType: Function", indent8);
-               function_name = lttng_userspace_probe_location_function_get_function_name(location);
-               binary_path = realpath(lttng_userspace_probe_location_function_get_binary_path(location), NULL);
-
-               MSG("%sBinary path:   %s", indent8, binary_path ? binary_path : "NULL");
-               MSG("%sFunction:      %s()", indent8, function_name ? function_name : "NULL");
-               switch (lookup_type) {
-               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
-                       MSG("%sLookup method: ELF", indent8);
-                       break;
-               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
-                       MSG("%sLookup method: default", indent8);
-                       break;
-               default:
-                       MSG("%sLookup method: INVALID LOOKUP TYPE ENCOUNTERED", indent8);
-                       break;
-               }
-
-               free(binary_path);
-               break;
-       }
-       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
-       {
-               const char *probe_name, *provider_name;
-               char *binary_path;
-
-               MSG("%sType: Tracepoint", indent8);
-               probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(location);
-               provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(location);
-               binary_path = realpath(lttng_userspace_probe_location_tracepoint_get_binary_path(location), NULL);
-               MSG("%sBinary path:   %s", indent8, binary_path ? binary_path : "NULL");
-               MSG("%sTracepoint:    %s:%s", indent8, provider_name ? provider_name : "NULL", probe_name ? probe_name : "NULL");
-               switch (lookup_type) {
-               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
-                       MSG("%sLookup method: SDT", indent8);
-                       break;
-               default:
-                       MSG("%sLookup method: INVALID LOOKUP TYPE ENCOUNTERED", indent8);
-                       break;
-               }
-
-               free(binary_path);
-               break;
-       }
-       default:
-               ERR("Invalid probe type encountered");
-       }
-}
-
-/*
- * Pretty print single event.
- */
-static void print_events(struct lttng_event *event)
-{
-       int ret;
-       const char *filter_str;
-       char *filter_msg = NULL;
-       char *exclusion_msg = NULL;
-
-       ret = lttng_event_get_filter_expression(event, &filter_str);
-
-       if (ret) {
-               filter_msg = strdup(" [failed to retrieve filter]");
-       } else if (filter_str) {
-               const char * const filter_fmt = " [filter: '%s']";
-
-               filter_msg = malloc(strlen(filter_str) +
-                               strlen(filter_fmt) + 1);
-               if (filter_msg) {
-                       sprintf(filter_msg, filter_fmt,
-                                       filter_str);
-               }
-       }
-
-       exclusion_msg = get_exclusion_names_msg(event);
-       if (!exclusion_msg) {
-               exclusion_msg = strdup(" [failed to retrieve exclusions]");
-       }
-
-       switch (event->type) {
-       case LTTNG_EVENT_TRACEPOINT:
-       {
-               if (event->loglevel != -1) {
-                       MSG("%s%s (loglevel%s %s (%d)) (type: tracepoint)%s%s%s",
-                                       indent6, event->name,
-                                       logleveltype_string(
-                                                       event->loglevel_type),
-                                       mi_lttng_loglevel_string(
-                                                       event->loglevel,
-                                                       the_handle->domain.type),
-                                       event->loglevel,
-                                       enabled_string(event->enabled),
-                                       safe_string(exclusion_msg),
-                                       safe_string(filter_msg));
-               } else {
-                       MSG("%s%s (type: tracepoint)%s%s%s",
-                               indent6,
-                               event->name,
-                               enabled_string(event->enabled),
-                               safe_string(exclusion_msg),
-                               safe_string(filter_msg));
-               }
-               break;
-       }
-       case LTTNG_EVENT_FUNCTION:
-               MSG("%s%s (type: function)%s%s", indent6,
-                               event->name, enabled_string(event->enabled),
-                               safe_string(filter_msg));
-               if (event->attr.probe.addr != 0) {
-                       MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
-               } else {
-                       MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
-                       MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
-               }
-               break;
-       case LTTNG_EVENT_PROBE:
-               MSG("%s%s (type: probe)%s%s", indent6,
-                               event->name, enabled_string(event->enabled),
-                               safe_string(filter_msg));
-               if (event->attr.probe.addr != 0) {
-                       MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
-               } else {
-                       MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
-                       MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
-               }
-               break;
-       case LTTNG_EVENT_USERSPACE_PROBE:
-               print_userspace_probe_location(event);
-               break;
-       case LTTNG_EVENT_FUNCTION_ENTRY:
-               MSG("%s%s (type: function)%s%s", indent6,
-                               event->name, enabled_string(event->enabled),
-                               safe_string(filter_msg));
-               MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name);
-               break;
-       case LTTNG_EVENT_SYSCALL:
-               MSG("%s%s%s%s%s%s", indent6, event->name,
-                               (opt_syscall ? "" : " (type:syscall)"),
-                               enabled_string(event->enabled),
-                               bitness_event(event->flags),
-                               safe_string(filter_msg));
-               break;
-       case LTTNG_EVENT_NOOP:
-               MSG("%s (type: noop)%s%s", indent6,
-                               enabled_string(event->enabled),
-                               safe_string(filter_msg));
-               break;
-       case LTTNG_EVENT_ALL:
-               /* Fall-through. */
-       default:
-               /* We should never have "all" events in list. */
-               abort();
-               break;
-       }
-
-       free(filter_msg);
-       free(exclusion_msg);
-}
-
-static const char *field_type(struct lttng_event_field *field)
-{
-       switch(field->type) {
-       case LTTNG_EVENT_FIELD_INTEGER:
-               return "integer";
-       case LTTNG_EVENT_FIELD_ENUM:
-               return "enum";
-       case LTTNG_EVENT_FIELD_FLOAT:
-               return "float";
-       case LTTNG_EVENT_FIELD_STRING:
-               return "string";
-       case LTTNG_EVENT_FIELD_OTHER:
-       default:        /* fall-through */
-               return "unknown";
-       }
-}
-
-/*
- * Pretty print single event fields.
- */
-static void print_event_field(struct lttng_event_field *field)
-{
-       if (!field->field_name[0]) {
-               return;
-       }
-       MSG("%sfield: %s (%s)%s", indent8, field->field_name,
-               field_type(field), field->nowrite ? " [no write]" : "");
-}
-
-/*
- * Machine interface
- * Jul and ust event listing
- */
-static int mi_list_agent_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(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Write domain */
-       ret = mi_lttng_domain(the_writer, domain, 1);
-       if (ret) {
-               goto end;
-       }
-
-       /* Open pids element element */
-       ret = mi_lttng_pids_open(the_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(
-                                               the_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(the_writer, cur_pid, cmdline,
-                                               1);
-                               if (ret) {
-                                       goto error;
-                               }
-
-                               /* Open events element */
-                               ret = mi_lttng_events_open(the_writer);
-                               if (ret) {
-                                       goto error;
-                               }
-
-                               pid_element_open = 1;
-                       }
-                       free(cmdline);
-               }
-
-               /* Write an event */
-               ret = mi_lttng_event(the_writer, &events[i], 0,
-                               the_handle->domain.type);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close pids */
-       ret = mi_lttng_writer_close_element(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close domain, domains */
-       ret = mi_lttng_close_multi_element(the_writer, 2);
-end:
-       return ret;
-error:
-       free(cmdline);
-       return ret;
-}
-
-static int list_agent_events(void)
-{
-       int i, size, ret = CMD_SUCCESS;
-       struct lttng_domain domain;
-       struct lttng_handle *handle = NULL;
-       struct lttng_event *event_list = NULL;
-       pid_t cur_pid = 0;
-       char *cmdline = NULL;
-       const char *agent_domain_str;
-
-       memset(&domain, 0, sizeof(domain));
-       if (opt_jul) {
-               domain.type = LTTNG_DOMAIN_JUL;
-       } else if (opt_log4j) {
-               domain.type = LTTNG_DOMAIN_LOG4J;
-       } else if (opt_python) {
-               domain.type = LTTNG_DOMAIN_PYTHON;
-       } else {
-               ERR("Invalid agent domain selected.");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       agent_domain_str = lttng_domain_type_str(domain.type);
-
-       DBG("Getting %s tracing events", agent_domain_str);
-
-       handle = lttng_create_handle(NULL, &domain);
-       if (handle == NULL) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       size = lttng_list_tracepoints(handle, &event_list);
-       if (size < 0) {
-               ERR("Unable to list %s events: %s", agent_domain_str,
-                               lttng_strerror(size));
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_list_agent_ust_events(event_list, size, &domain);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       } else {
-               /* Pretty print */
-               MSG("%s events (Logger name):\n-------------------------",
-                               agent_domain_str);
-
-               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);
-                       }
-                       MSG("%s- %s", indent6, event_list[i].name);
-               }
-
-               MSG("");
-       }
-
-error:
-       free(event_list);
-end:
-       lttng_destroy_handle(handle);
-       return ret;
-}
-
-/*
- * Ask session daemon for all user space tracepoints available.
- */
-static int list_ust_events(void)
-{
-       int i, size, ret = CMD_SUCCESS;
-       struct lttng_domain domain;
-       struct lttng_handle *handle;
-       struct lttng_event *event_list = NULL;
-       pid_t cur_pid = 0;
-       char *cmdline = NULL;
-
-       memset(&domain, 0, sizeof(domain));
-
-       DBG("Getting UST tracing events");
-
-       domain.type = LTTNG_DOMAIN_UST;
-
-       handle = lttng_create_handle(NULL, &domain);
-       if (handle == NULL) {
-               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));
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_list_agent_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]);
-               }
-
-               MSG("");
-       }
-
-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;
-
-       memset(&cur_event, 0, sizeof(cur_event));
-
-       /* Open domains element */
-       ret = mi_lttng_domains_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Write domain */
-       ret = mi_lttng_domain(the_writer, domain, 1);
-       if (ret) {
-               goto end;
-       }
-
-       /* Open pids element */
-       ret = mi_lttng_pids_open(the_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 field element and event. */
-                                       ret = mi_lttng_close_multi_element(
-                                                       the_writer, 2);
-                                       if (ret) {
-                                               goto end;
-                                       }
-                                       event_element_open = 0;
-                               }
-                               /* Close the previous events, pid element */
-                               ret = mi_lttng_close_multi_element(
-                                               the_writer, 2);
-                               if (ret) {
-                                       goto end;
-                               }
-                               pid_element_open = 0;
-                       }
-
-                       cur_pid = fields[i].event.pid;
-                       cmdline = get_cmdline_by_pid(cur_pid);
-                       if (!pid_element_open) {
-                               /* Open and write a pid element */
-                               ret = mi_lttng_pid(the_writer, cur_pid, cmdline,
-                                               1);
-                               if (ret) {
-                                       goto error;
-                               }
-
-                               /* Open events element */
-                               ret = mi_lttng_events_open(the_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));
-               }
-
-               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(
-                                               the_writer, 2);
-                               if (ret) {
-                                       goto end;
-                               }
-                               event_element_open = 0;
-                       }
-
-                       memcpy(&cur_event, &fields[i].event,
-                                       sizeof(cur_event));
-
-                       if (!event_element_open) {
-                               /* Open and write the event */
-                               ret = mi_lttng_event(the_writer, &cur_event, 1,
-                                               the_handle->domain.type);
-                               if (ret) {
-                                       goto end;
-                               }
-
-                               /* Open a fields element */
-                               ret = mi_lttng_event_fields_open(the_writer);
-                               if (ret) {
-                                       goto end;
-                               }
-                               event_element_open = 1;
-                       }
-               }
-
-               /* Print the event_field */
-               ret = mi_lttng_event_field(the_writer, &fields[i]);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close pids, domain, domains */
-       ret = mi_lttng_close_multi_element(the_writer, 3);
-end:
-       return ret;
-error:
-       free(cmdline);
-       return ret;
-}
-
-/*
- * Ask session daemon for all user space tracepoint fields available.
- */
-static int list_ust_event_fields(void)
-{
-       int i, size, ret = CMD_SUCCESS;
-       struct lttng_domain domain;
-       struct lttng_handle *handle;
-       struct lttng_event_field *event_field_list;
-       pid_t cur_pid = 0;
-       char *cmdline = NULL;
-
-       struct lttng_event cur_event;
-
-       memset(&domain, 0, sizeof(domain));
-       memset(&cur_event, 0, sizeof(cur_event));
-
-       DBG("Getting UST tracing event fields");
-
-       domain.type = LTTNG_DOMAIN_UST;
-
-       handle = lttng_create_handle(NULL, &domain);
-       if (handle == NULL) {
-               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));
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       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-------------");
-
-               if (size == 0) {
-                       MSG("None");
-               }
-
-               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]);
-               }
-
-               MSG("");
-       }
-
-error:
-       free(event_field_list);
-end:
-       lttng_destroy_handle(handle);
-       return ret;
-}
-
-/*
- * 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;
-
-       /* Open domains element */
-       ret = mi_lttng_domains_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Write domain */
-       ret = mi_lttng_domain(the_writer, domain, 1);
-       if (ret) {
-               goto end;
-       }
-
-       /* Open events */
-       ret = mi_lttng_events_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_event(the_writer, &events[i], 0,
-                               the_handle->domain.type);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* close events, domain and domains */
-       ret = mi_lttng_close_multi_element(the_writer, 3);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Ask for all trace events in the kernel
- */
-static int list_kernel_events(void)
-{
-       int i, size, ret = CMD_SUCCESS;
-       struct lttng_domain domain;
-       struct lttng_handle *handle;
-       struct lttng_event *event_list;
-
-       memset(&domain, 0, sizeof(domain));
-
-       DBG("Getting kernel tracing events");
-
-       domain.type = LTTNG_DOMAIN_KERNEL;
-
-       handle = lttng_create_handle(NULL, &domain);
-       if (handle == NULL) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       size = lttng_list_tracepoints(handle, &event_list);
-       if (size < 0) {
-               ERR("Unable to list kernel events: %s", lttng_strerror(size));
-               lttng_destroy_handle(handle);
-               return CMD_ERROR;
-       }
-
-       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]);
-               }
-
-               MSG("");
-       }
-
-end:
-       free(event_list);
-
-       lttng_destroy_handle(handle);
-       return ret;
-
-error:
-       lttng_destroy_handle(handle);
-       return ret;
-}
-
-/*
- * Machine interface
- * Print a list of system calls.
- */
-static int mi_list_syscalls(struct lttng_event *events, int count)
-{
-       int ret, i;
-
-       /* Open events */
-       ret = mi_lttng_events_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_event(the_writer, &events[i], 0,
-                               the_handle->domain.type);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close events. */
-       ret = mi_lttng_writer_close_element(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Ask for kernel system calls.
- */
-static int list_syscalls(void)
-{
-       int i, size, ret = CMD_SUCCESS;
-       struct lttng_event *event_list;
-
-       DBG("Getting kernel system call events");
-
-       size = lttng_list_syscalls(&event_list);
-       if (size < 0) {
-               ERR("Unable to list system calls: %s", lttng_strerror(size));
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_list_syscalls(event_list, size);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               MSG("System calls:\n-------------");
-
-               for (i = 0; i < size; i++) {
-                       print_events(&event_list[i]);
-               }
-
-               MSG("");
-       }
-
-end:
-       free(event_list);
-       return ret;
-
-error:
-       return ret;
-}
-
-/*
- * Machine Interface
- * Print a list of agent events
- */
-static int mi_list_session_agent_events(struct lttng_event *events, int count)
-{
-       int ret, i;
-
-       /* Open events element */
-       ret = mi_lttng_events_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_event(the_writer, &events[i], 0,
-                               the_handle->domain.type);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close events element */
-       ret = mi_lttng_writer_close_element(the_writer);
-
-end:
-       return ret;
-}
-
-/*
- * List agent events for a specific session using the handle.
- *
- * Return CMD_SUCCESS on success else a negative value.
- */
-static int list_session_agent_events(void)
-{
-       int ret = CMD_SUCCESS, count, i;
-       struct lttng_event *events = NULL;
-
-       count = lttng_list_events(the_handle, "", &events);
-       if (count < 0) {
-               ret = CMD_ERROR;
-               ERR("%s", lttng_strerror(count));
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_list_session_agent_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++) {
-                       const char *filter_str;
-                       char *filter_msg = NULL;
-                       struct lttng_event *event = &events[i];
-
-                       ret = lttng_event_get_filter_expression(event,
-                                       &filter_str);
-                       if (ret) {
-                               filter_msg = strdup(" [failed to retrieve filter]");
-                       } else if (filter_str) {
-                               const char * const filter_fmt =
-                                               " [filter: '%s']";
-
-                               filter_msg = malloc(strlen(filter_str) +
-                                               strlen(filter_fmt) + 1);
-                               if (filter_msg) {
-                                       sprintf(filter_msg, filter_fmt,
-                                                       filter_str);
-                               }
-                       }
-
-                       if (event->loglevel_type !=
-                                       LTTNG_EVENT_LOGLEVEL_ALL) {
-                               MSG("%s- %s%s (loglevel%s %s)%s", indent4,
-                                               event->name,
-                                               enabled_string(event->enabled),
-                                               logleveltype_string(
-                                                               event->loglevel_type),
-                                               mi_lttng_loglevel_string(
-                                                               event->loglevel,
-                                                               the_handle->domain
-                                                                               .type),
-                                               safe_string(filter_msg));
-                       } else {
-                               MSG("%s- %s%s%s", indent4, event->name,
-                                               enabled_string(event->enabled),
-                                               safe_string(filter_msg));
-                       }
-                       free(filter_msg);
-               }
-
-               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(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_event(the_writer, &events[i], 0,
-                               the_handle->domain.type);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close events element */
-       ret = mi_lttng_writer_close_element(the_writer);
-
-end:
-       return ret;
-}
-
-/*
- * List events of channel of session and domain.
- */
-static int list_events(const char *channel_name)
-{
-       int ret = CMD_SUCCESS, count, i;
-       struct lttng_event *events = NULL;
-
-       count = lttng_list_events(the_handle, channel_name, &events);
-       if (count < 0) {
-               ret = CMD_ERROR;
-               ERR("%s", lttng_strerror(count));
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_list_events(events, count);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               /* Pretty print */
-               MSG("\n%sRecording event rules:", indent4);
-               if (count == 0) {
-                       MSG("%sNone\n", indent6);
-                       goto end;
-               }
-
-               for (i = 0; i < count; i++) {
-                       print_events(&events[i]);
-               }
-
-               MSG("");
-       }
-end:
-       free(events);
-error:
-       return ret;
-}
-
-static
-void print_timer(const char *timer_name, uint32_t space_count, int64_t value)
-{
-       uint32_t i;
-
-       _MSG("%s%s:", indent6, timer_name);
-       for (i = 0; i < space_count; i++) {
-               _MSG(" ");
-       }
-
-       if (value) {
-               MSG("%" PRId64 " %s", value, USEC_UNIT);
-       } else {
-               MSG("inactive");
-       }
-}
-
-/*
- * Pretty print channel
- */
-static void print_channel(struct lttng_channel *channel)
-{
-       int ret;
-       uint64_t discarded_events, lost_packets, monitor_timer_interval;
-       int64_t blocking_timeout;
-
-       ret = lttng_channel_get_discarded_event_count(channel,
-                       &discarded_events);
-       if (ret) {
-               ERR("Failed to retrieve discarded event count of channel");
-               return;
-       }
-
-       ret = lttng_channel_get_lost_packet_count(channel,
-                       &lost_packets);
-       if (ret) {
-               ERR("Failed to retrieve lost packet count of channel");
-               return;
-       }
-
-       ret = lttng_channel_get_monitor_timer_interval(channel,
-                       &monitor_timer_interval);
-       if (ret) {
-               ERR("Failed to retrieve monitor interval of channel");
-               return;
-       }
-
-       ret = lttng_channel_get_blocking_timeout(channel,
-                       &blocking_timeout);
-       if (ret) {
-               ERR("Failed to retrieve blocking timeout of channel");
-               return;
-       }
-
-       MSG("- %s:%s\n", channel->name, enabled_string(channel->enabled));
-       MSG("%sAttributes:", indent4);
-       MSG("%sEvent-loss mode:  %s", indent6, channel->attr.overwrite ? "overwrite" : "discard");
-       MSG("%sSub-buffer size:  %" PRIu64 " bytes", indent6, channel->attr.subbuf_size);
-       MSG("%sSub-buffer count: %" PRIu64, indent6, channel->attr.num_subbuf);
-
-       print_timer("Switch timer", 5, channel->attr.switch_timer_interval);
-       print_timer("Read timer",  7, channel->attr.read_timer_interval);
-       print_timer("Monitor timer", 4, monitor_timer_interval);
-
-       if (!channel->attr.overwrite) {
-               if (blocking_timeout == -1) {
-                       MSG("%sBlocking timeout: infinite", indent6);
-               } else {
-                       MSG("%sBlocking timeout: %" PRId64 " %s", indent6,
-                                       blocking_timeout, USEC_UNIT);
-               }
-       }
-
-       MSG("%sTrace file count: %" PRIu64 " per stream", indent6,
-                       channel->attr.tracefile_count == 0 ?
-                               1 : channel->attr.tracefile_count);
-       if (channel->attr.tracefile_size != 0 ) {
-               MSG("%sTrace file size:  %" PRIu64 " bytes", indent6,
-                               channel->attr.tracefile_size);
-       } else {
-               MSG("%sTrace file size:  %s", indent6, "unlimited");
-       }
-       switch (channel->attr.output) {
-               case LTTNG_EVENT_SPLICE:
-                       MSG("%sOutput mode:      splice", indent6);
-                       break;
-               case LTTNG_EVENT_MMAP:
-                       MSG("%sOutput mode:      mmap", indent6);
-                       break;
-       }
-
-       MSG("\n%sStatistics:", indent4);
-       if (the_listed_session.snapshot_mode) {
-               /*
-                * The lost packet count is omitted for sessions in snapshot
-                * mode as it is misleading: it would indicate the number of
-                * packets that the consumer could not extract during the
-                * course of recording the snapshot. It does not have the
-                * same meaning as the "regular" lost packet count that
-                * would result from the consumer not keeping up with
-                * event production in an overwrite-mode channel.
-                *
-                * A more interesting statistic would be the number of
-                * packets lost between the first and last extracted
-                * packets of a given snapshot (which prevents most analyses).
-                */
-               MSG("%sNone", indent6);
-               goto skip_stats_printing;
-       }
-
-       if (!channel->attr.overwrite) {
-               MSG("%sDiscarded events: %" PRIu64, indent6, discarded_events);
-       } else {
-               MSG("%sLost packets:     %" PRIu64, indent6, lost_packets);
-       }
-skip_stats_printing:
-       return;
-}
-
-/*
- * 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(the_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(the_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(the_writer);
-               if (ret) {
-                       goto error;
-               }
-
-               if (chan_found) {
-                       break;
-               }
-       }
-
-       /* Close channels element */
-       ret = mi_lttng_writer_close_element(the_writer);
-       if (ret) {
-               goto error;
-       }
-
-error:
-       return ret;
-}
-
-/*
- * List channel(s) of session and domain.
- *
- * If channel_name is NULL, all channels are listed.
- */
-static int list_channels(const char *channel_name)
-{
-       int count, i, ret = CMD_SUCCESS;
-       unsigned int chan_found = 0;
-       struct lttng_channel *channels = NULL;
-
-       DBG("Listing channel(s) (%s)", channel_name ? : "<all>");
-
-       count = lttng_list_channels(the_handle, &channels);
-       if (count < 0) {
-               switch (-count) {
-               case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
-                       if (lttng_opt_mi) {
-                               /* When printing mi this is not an error
-                                * but an empty channels element */
-                               count = 0;
-                       } else {
-                               ret = CMD_SUCCESS;
-                               goto error_channels;
-                       }
-                       break;
-               default:
-                       /* We had a real error */
-                       ret = CMD_ERROR;
-                       ERR("%s", lttng_strerror(count));
-                       goto error_channels;
-                       break;
-               }
-       }
-
-       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 (count) {
-                       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;
-                               }
-                       }
-                       print_channel(&channels[i]);
-
-                       /* Listing events per channel */
-                       ret = list_events(channels[i].name);
-                       if (ret) {
-                               goto error;
-                       }
-
-                       if (chan_found) {
-                               break;
-                       }
-               }
-
-               if (!chan_found && channel_name != NULL) {
-                       ret = CMD_ERROR;
-                       ERR("Channel %s not found", channel_name);
-                       goto error;
-               }
-       }
-error:
-       free(channels);
-
-error_channels:
-       return ret;
-}
-
-static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
-{
-       switch (process_attr) {
-       case LTTNG_PROCESS_ATTR_PROCESS_ID:
-               return "Process ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
-               return "Virtual process ID";
-       case LTTNG_PROCESS_ATTR_USER_ID:
-               return "User ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
-               return "Virtual user ID";
-       case LTTNG_PROCESS_ATTR_GROUP_ID:
-               return "Group ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
-               return "Virtual group ID";
-       default:
-               return "Unknown";
-       }
-       return NULL;
-}
-
-static int handle_process_attr_status(enum lttng_process_attr process_attr,
-               enum lttng_process_attr_tracker_handle_status status)
-{
-       int ret = CMD_SUCCESS;
-
-       switch (status) {
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_INVALID_TRACKING_POLICY:
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
-               /* Carry on. */
-               break;
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_COMMUNICATION_ERROR:
-               ERR("Communication occurred while fetching %s tracker",
-                               lttng_process_attr_to_string(process_attr));
-               ret = CMD_ERROR;
-               break;
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
-               ERR("Failed to get the inclusion set of the %s tracker: session `%s` no longer exists",
-                               lttng_process_attr_to_string(process_attr),
-                               the_handle->session_name);
-               ret = CMD_ERROR;
-               break;
-       default:
-               ERR("Unknown error occurred while fetching the inclusion set of the %s tracker",
-                               lttng_process_attr_to_string(process_attr));
-               ret = CMD_ERROR;
-               break;
-       }
-
-       return ret;
-}
-
-static int mi_output_empty_tracker(enum lttng_process_attr process_attr)
-{
-       int ret;
-
-       ret = mi_lttng_process_attribute_tracker_open(the_writer, process_attr);
-       if (ret) {
-               goto end;
-       }
-
-       ret = mi_lttng_close_multi_element(the_writer, 2);
-end:
-       return ret;
-}
-
-static inline bool is_value_type_name(
-               enum lttng_process_attr_value_type value_type)
-{
-       return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
-              value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
-}
-
-/*
- * List a process attribute tracker for a session and domain tuple.
- */
-static int list_process_attr_tracker(enum lttng_process_attr process_attr)
-{
-       int ret = 0;
-       unsigned int count, i;
-       enum lttng_tracking_policy policy;
-       enum lttng_error_code ret_code;
-       enum lttng_process_attr_tracker_handle_status handle_status;
-       enum lttng_process_attr_values_status values_status;
-       const struct lttng_process_attr_values *values;
-       struct lttng_process_attr_tracker_handle *tracker_handle = NULL;
-
-       ret_code = lttng_session_get_tracker_handle(the_handle->session_name,
-                       the_handle->domain.type, process_attr, &tracker_handle);
-       if (ret_code != LTTNG_OK) {
-               ERR("Failed to get process attribute tracker handle: %s",
-                               lttng_strerror(ret_code));
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       handle_status = lttng_process_attr_tracker_handle_get_inclusion_set(
-                       tracker_handle, &values);
-       ret = handle_process_attr_status(process_attr, handle_status);
-       if (ret != CMD_SUCCESS) {
-               goto end;
-       }
-
-       handle_status = lttng_process_attr_tracker_handle_get_tracking_policy(
-                       tracker_handle, &policy);
-       ret = handle_process_attr_status(process_attr, handle_status);
-       if (ret != CMD_SUCCESS) {
-               goto end;
-       }
-
-       {
-               char *process_attr_name;
-               const int print_ret = asprintf(&process_attr_name, "%ss:",
-                               get_capitalized_process_attr_str(process_attr));
-
-               if (print_ret == -1) {
-                       ret = CMD_FATAL;
-                       goto end;
-               }
-               _MSG("  %-22s", process_attr_name);
-               free(process_attr_name);
-       }
-       switch (policy) {
-       case LTTNG_TRACKING_POLICY_INCLUDE_SET:
-               break;
-       case LTTNG_TRACKING_POLICY_EXCLUDE_ALL:
-               if (the_writer) {
-                       mi_output_empty_tracker(process_attr);
-               }
-               MSG("none");
-               ret = CMD_SUCCESS;
-               goto end;
-       case LTTNG_TRACKING_POLICY_INCLUDE_ALL:
-               MSG("all");
-               ret = CMD_SUCCESS;
-               goto end;
-       default:
-               ERR("Unknown tracking policy encoutered while listing the %s process attribute tracker of session `%s`",
-                               lttng_process_attr_to_string(process_attr),
-                               the_handle->session_name);
-               ret = CMD_FATAL;
-               goto end;
-       }
-
-       values_status = lttng_process_attr_values_get_count(values, &count);
-       if (values_status != LTTNG_PROCESS_ATTR_VALUES_STATUS_OK) {
-               ERR("Failed to get the count of values in the inclusion set of the %s process attribute tracker of session `%s`",
-                               lttng_process_attr_to_string(process_attr),
-                               the_handle->session_name);
-               ret = CMD_FATAL;
-               goto end;
-       }
-
-       if (count == 0) {
-               /* Functionally equivalent to the 'exclude all' policy. */
-               if (the_writer) {
-                       mi_output_empty_tracker(process_attr);
-               }
-               MSG("none");
-               ret = CMD_SUCCESS;
-               goto end;
-       }
-
-       /* Mi tracker_id element */
-       if (the_writer) {
-               /* Open tracker_id and targets elements */
-               ret = mi_lttng_process_attribute_tracker_open(
-                               the_writer, process_attr);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < count; i++) {
-               const enum lttng_process_attr_value_type value_type =
-                               lttng_process_attr_values_get_type_at_index(
-                                               values, i);
-               int64_t integral_value = INT64_MAX;
-               const char *name = "error";
-
-               if (i >= 1) {
-                       _MSG(", ");
-               }
-               switch (value_type) {
-               case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
-               {
-                       pid_t pid;
-
-                       values_status = lttng_process_attr_values_get_pid_at_index(
-                                       values, i, &pid);
-                       integral_value = (int64_t) pid;
-                       break;
-               }
-               case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
-               {
-                       uid_t uid;
-
-                       values_status = lttng_process_attr_values_get_uid_at_index(
-                                       values, i, &uid);
-                       integral_value = (int64_t) uid;
-                       break;
-               }
-               case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
-               {
-                       gid_t gid;
-
-                       values_status = lttng_process_attr_values_get_gid_at_index(
-                                       values, i, &gid);
-                       integral_value = (int64_t) gid;
-                       break;
-               }
-               case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
-                       values_status = lttng_process_attr_values_get_user_name_at_index(
-                                       values, i, &name);
-                       break;
-               case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
-                       values_status = lttng_process_attr_values_get_group_name_at_index(
-                                       values, i, &name);
-                       break;
-               default:
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               if (values_status != LTTNG_PROCESS_ATTR_VALUES_STATUS_OK) {
-                       /*
-                        * Not possible given the current liblttng-ctl
-                        * implementation.
-                        */
-                       ERR("Unknown error occurred while fetching process attribute value in inclusion list");
-                       ret = CMD_FATAL;
-                       goto end;
-               }
-
-               if (is_value_type_name(value_type)) {
-                       _MSG("`%s`", name);
-               } else {
-                       _MSG("%" PRIi64, integral_value);
-               }
-
-               /* Mi */
-               if (the_writer) {
-                       ret = is_value_type_name(value_type) ?
-                                             mi_lttng_string_process_attribute_value(
-                                                       the_writer,
-                                                       process_attr, name,
-                                                       false) :
-                                             mi_lttng_integral_process_attribute_value(
-                                                       the_writer,
-                                                       process_attr,
-                                                       integral_value, false);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-       }
-       MSG("");
-
-       /* Mi close tracker_id and targets */
-       if (the_writer) {
-               ret = mi_lttng_close_multi_element(the_writer, 2);
-               if (ret) {
-                       goto end;
-               }
-       }
-end:
-       lttng_process_attr_tracker_handle_destroy(tracker_handle);
-       return ret;
-}
-
-/*
- * List all trackers of a domain
- */
-static int list_trackers(const struct lttng_domain *domain)
-{
-       int ret = 0;
-
-       MSG("Tracked process attributes");
-       /* Trackers listing */
-       if (lttng_opt_mi) {
-               ret = mi_lttng_trackers_open(the_writer);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       switch (domain->type) {
-       case LTTNG_DOMAIN_KERNEL:
-               /* pid tracker */
-               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_PROCESS_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* vpid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* uid tracker */
-               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_USER_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* vuid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* gid tracker */
-               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_GROUP_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* vgid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID);
-               if (ret) {
-                       goto end;
-               }
-               break;
-       case LTTNG_DOMAIN_UST:
-               /* vpid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* vuid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID);
-               if (ret) {
-                       goto end;
-               }
-               /* vgid tracker */
-               ret = list_process_attr_tracker(
-                               LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID);
-               if (ret) {
-                       goto end;
-               }
-               break;
-       default:
-               break;
-       }
-       MSG();
-       if (lttng_opt_mi) {
-               /* Close trackers element */
-               ret = mi_lttng_writer_close_element(the_writer);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static enum cmd_error_code print_periodic_rotation_schedule(
-               const struct lttng_rotation_schedule *schedule)
-{
-       enum cmd_error_code ret;
-       enum lttng_rotation_status status;
-       uint64_t value;
-
-       status = lttng_rotation_schedule_periodic_get_period(schedule,
-                       &value);
-       if (status != LTTNG_ROTATION_STATUS_OK) {
-               ERR("Failed to retrieve period parameter from periodic rotation schedule.");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       MSG("    timer period: %" PRIu64" %s", value, USEC_UNIT);
-       ret = CMD_SUCCESS;
-end:
-       return ret;
-}
-
-static enum cmd_error_code print_size_threshold_rotation_schedule(
-               const struct lttng_rotation_schedule *schedule)
-{
-       enum cmd_error_code ret;
-       enum lttng_rotation_status status;
-       uint64_t value;
-
-       status = lttng_rotation_schedule_size_threshold_get_threshold(schedule,
-                       &value);
-       if (status != LTTNG_ROTATION_STATUS_OK) {
-               ERR("Failed to retrieve size parameter from size-based rotation schedule.");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       MSG("    size threshold: %" PRIu64" bytes", value);
-       ret = CMD_SUCCESS;
-end:
-       return ret;
-}
-
-static enum cmd_error_code print_rotation_schedule(
-               const struct lttng_rotation_schedule *schedule)
-{
-       enum cmd_error_code ret;
-
-       switch (lttng_rotation_schedule_get_type(schedule)) {
-       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
-               ret = print_size_threshold_rotation_schedule(schedule);
-               break;
-       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
-               ret = print_periodic_rotation_schedule(schedule);
-               break;
-       default:
-               ret = CMD_ERROR;
-       }
-       return ret;
-}
-
-/*
- * List the automatic rotation settings.
- */
-static enum cmd_error_code list_rotate_settings(const char *session_name)
-{
-       int ret;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       unsigned int count, i;
-       struct lttng_rotation_schedules *schedules = NULL;
-       enum lttng_rotation_status status;
-
-       ret = lttng_session_list_rotation_schedules(session_name, &schedules);
-       if (ret != LTTNG_OK) {
-               ERR("Failed to list session rotation schedules: %s", lttng_strerror(ret));
-               cmd_ret = CMD_ERROR;
-               goto end;
-       }
-
-       status = lttng_rotation_schedules_get_count(schedules, &count);
-       if (status != LTTNG_ROTATION_STATUS_OK) {
-               ERR("Failed to retrieve the number of session rotation schedules.");
-               cmd_ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (count == 0) {
-               cmd_ret = CMD_SUCCESS;
-               goto end;
-       }
-
-       MSG("Automatic rotation schedules:");
-       if (lttng_opt_mi) {
-               ret = mi_lttng_writer_open_element(the_writer,
-                               mi_lttng_element_rotation_schedules);
-               if (ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       for (i = 0; i < count; i++) {
-               enum cmd_error_code tmp_ret = CMD_SUCCESS;
-               const struct lttng_rotation_schedule *schedule;
-
-               schedule = lttng_rotation_schedules_get_at_index(schedules, i);
-               if (!schedule) {
-                       ERR("Failed to retrieve session rotation schedule.");
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               if (lttng_opt_mi) {
-                       ret = mi_lttng_rotation_schedule(the_writer, schedule);
-                       if (ret) {
-                               tmp_ret = CMD_ERROR;
-                       }
-               } else {
-                       tmp_ret = print_rotation_schedule(schedule);
-               }
-
-               /*
-                * Report an error if the serialization of any of the
-                * descriptors failed.
-                */
-               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
-       }
-
-       _MSG("\n");
-       if (lttng_opt_mi) {
-               /* Close the rotation_schedules element. */
-               ret = mi_lttng_writer_close_element(the_writer);
-               if (ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-end:
-       lttng_rotation_schedules_destroy(schedules);
-       return cmd_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(the_writer, &sessions[i], 1);
-                       if (ret) {
-                               goto end;
-                       }
-                       break;
-               }
-       }
-
-       if (!session_found) {
-               ERR("Session '%s' not found", session_name);
-               ret = -LTTNG_ERR_SESS_NOT_FOUND;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Machine interface
- * List all availables session
- */
-static int mi_list_sessions(struct lttng_session *sessions, int count)
-{
-       int ret, i;
-
-       /* Opening sessions element */
-       ret = mi_lttng_sessions_open(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Listing sessions */
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_session(the_writer, &sessions[i], 0);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Closing sessions element */
-       ret = mi_lttng_writer_close_element(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * List available tracing session. List only basic information.
- *
- * If session_name is NULL, all sessions are listed.
- */
-static int list_sessions(const char *session_name)
-{
-       int ret = CMD_SUCCESS;
-       int count, i;
-       unsigned int session_found = 0;
-       struct lttng_session *sessions = NULL;
-
-       count = lttng_list_sessions(&sessions);
-       DBG("Session count %d", count);
-       if (count < 0) {
-               ret = CMD_ERROR;
-               ERR("%s", lttng_strerror(count));
-               goto end;
-       }
-
-       if (lttng_opt_mi) {
-               /* Mi */
-               if (session_name == NULL) {
-                       /* List all sessions */
-                       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 end;
-               }
-       } else {
-               /* Pretty print */
-               if (count == 0) {
-                       MSG("Currently no available recording session");
-                       goto end;
-               }
-
-               if (session_name == NULL) {
-                       MSG("Available recording 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("Recording session %s: [%s%s]", session_name,
-                                                       active_string(sessions[i].enabled),
-                                                       snapshot_string(sessions[i].snapshot_mode));
-                                       if (*sessions[i].path) {
-                                               MSG("%sTrace output: %s\n", indent4, sessions[i].path);
-                                       }
-                                       memcpy(&the_listed_session,
-                                                       &sessions[i],
-                                                       sizeof(the_listed_session));
-                                       break;
-                               }
-                       } else {
-                               MSG("  %d) %s [%s%s]", i + 1,
-                                               sessions[i].name,
-                                               active_string(sessions[i].enabled),
-                                               snapshot_string(sessions[i].snapshot_mode));
-                               if (*sessions[i].path) {
-                                       MSG("%sTrace output: %s", indent4, sessions[i].path);
-                               }
-                               if (sessions[i].live_timer_interval != 0) {
-                                       MSG("%sLive timer interval: %u %s", indent4,
-                                                       sessions[i].live_timer_interval,
-                                                       USEC_UNIT);
-                               }
-                               MSG("");
-                       }
-               }
-
-               if (!session_found && session_name != NULL) {
-                       ERR("Session '%s' not found", session_name);
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               if (session_name == NULL) {
-                       MSG("\nUse lttng list <session_name> for more details");
-               }
-       }
-
-end:
-       free(sessions);
-       return ret;
-}
-
-
-/*
- * 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(the_writer);
-       if (ret) {
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               ret = mi_lttng_domain(the_writer, &domains[i], 0);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Closing domains element */
-       ret = mi_lttng_writer_close_element(the_writer);
-       if (ret) {
-               goto end;
-       }
-end:
-       return ret;
-}
-
-/*
- * List available domain(s) for a session.
- */
-static int list_domains(const char *session_name)
-{
-       int i, count, ret = CMD_SUCCESS;
-       struct lttng_domain *domains = NULL;
-
-
-       count = lttng_list_domains(session_name, &domains);
-       if (count < 0) {
-               ret = CMD_ERROR;
-               ERR("%s", lttng_strerror(count));
-               goto end;
-       }
-
-       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;
-                       case LTTNG_DOMAIN_LOG4J:
-                               MSG("  - LOG4j (Logging for Java)");
-                               break;
-                       case LTTNG_DOMAIN_PYTHON:
-                               MSG("  - Python (logging)");
-                               break;
-                       default:
-                               break;
-                       }
-               }
-       }
-
-error:
-       free(domains);
-
-end:
-       return ret;
-}
-
-/*
- * The 'list <options>' first level command
- */
-int cmd_list(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS;
-       const char *session_name, *leftover = NULL;
-       static poptContext pc;
-       struct lttng_domain domain;
-       struct lttng_domain *domains = NULL;
-
-       memset(&domain, 0, sizeof(domain));
-
-       if (argc < 1) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_USERSPACE:
-                       opt_userspace = 1;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               the_writer = mi_lttng_writer_create(
-                               fileno(stdout), lttng_opt_mi);
-               if (!the_writer) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(
-                               the_writer, mi_lttng_element_command_list);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(
-                               the_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);
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (opt_kernel) {
-               domain.type = LTTNG_DOMAIN_KERNEL;
-       } else if (opt_userspace) {
-               DBG2("Listing userspace global domain");
-               domain.type = LTTNG_DOMAIN_UST;
-       } else if (opt_jul) {
-               DBG2("Listing JUL domain");
-               domain.type = LTTNG_DOMAIN_JUL;
-       } else if (opt_log4j) {
-               domain.type = LTTNG_DOMAIN_LOG4J;
-       } else if (opt_python) {
-               domain.type = LTTNG_DOMAIN_PYTHON;
-       }
-
-       if (!opt_kernel && opt_syscall) {
-               WARN("--syscall will only work with the Kernel domain (-k)");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (opt_kernel || opt_userspace || opt_jul || opt_log4j || opt_python) {
-               the_handle = lttng_create_handle(session_name, &domain);
-               if (the_handle == NULL) {
-                       ret = CMD_FATAL;
-                       goto end;
-               }
-       }
-
-       if (session_name == NULL) {
-               if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j
-                               && !opt_python) {
-                       ret = list_sessions(NULL);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               if (opt_kernel) {
-                       if (opt_syscall) {
-                               ret = list_syscalls();
-                               if (ret) {
-                                       goto end;
-                               }
-                       } else {
-                               ret = list_kernel_events();
-                               if (ret) {
-                                       goto end;
-                               }
-                       }
-               }
-               if (opt_userspace) {
-                       if (opt_fields) {
-                               ret = list_ust_event_fields();
-                       } else {
-                               ret = list_ust_events();
-                       }
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               if (opt_jul || opt_log4j || opt_python) {
-                       ret = list_agent_events();
-                       if (ret) {
-                               goto end;
-                       }
-               }
-       } else {
-               /* List session attributes */
-               if (lttng_opt_mi) {
-                       /* Open element sessions
-                        * Present for xml consistency */
-                       ret = mi_lttng_sessions_open(the_writer);
-                       if (ret) {
-                               goto end;
-                       }
-               }
-               /* MI: the ouptut of list_sessions is an unclosed session element */
-               ret = list_sessions(session_name);
-               if (ret) {
-                       goto end;
-               }
-
-               ret = list_rotate_settings(session_name);
-               if (ret) {
-                       goto end;
-               }
-
-               /* Domain listing */
-               if (opt_domain) {
-                       ret = list_domains(session_name);
-                       goto end;
-               }
-
-               /* Channel listing */
-               if (opt_kernel || opt_userspace) {
-                       if (lttng_opt_mi) {
-                               /* Add of domains and domain element for xml
-                                * consistency and validation
-                                */
-                               ret = mi_lttng_domains_open(the_writer);
-                               if (ret) {
-                                       goto end;
-                               }
-
-                               /* Open domain and leave it open for
-                                * nested channels printing */
-                               ret = mi_lttng_domain(the_writer, &domain, 1);
-                               if (ret) {
-                                       goto end;
-                               }
-
-                       }
-
-
-                       /* Trackers */
-                       ret = list_trackers(&domain);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       /* Channels */
-                       ret = list_channels(opt_channel);
-                       if (ret) {
-                               goto end;
-                       }
-
-                       if (lttng_opt_mi) {
-                               /* Close domain and domain element */
-                               ret = mi_lttng_close_multi_element(
-                                               the_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 = CMD_ERROR;
-                               ERR("%s", lttng_strerror(nb_domain));
-                               goto end;
-                       }
-
-                       if (lttng_opt_mi) {
-                               ret = mi_lttng_domains_open(the_writer);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-
-                       for (i = 0; i < nb_domain; i++) {
-                               switch (domains[i].type) {
-                               case LTTNG_DOMAIN_KERNEL:
-                                       MSG("=== Domain: Linux kernel ===\n");
-                                       break;
-                               case LTTNG_DOMAIN_UST:
-                                       MSG("=== Domain: User space ===\n");
-                                       MSG("Buffering scheme: %s\n",
-                                                       domains[i].buf_type ==
-                                                       LTTNG_BUFFER_PER_PID ? "per-process" : "per-user");
-                                       break;
-                               case LTTNG_DOMAIN_JUL:
-                                       MSG("=== Domain: java.util.logging (JUL) ===\n");
-                                       break;
-                               case LTTNG_DOMAIN_LOG4J:
-                                       MSG("=== Domain: log4j ===\n");
-                                       break;
-                               case LTTNG_DOMAIN_PYTHON:
-                                       MSG("=== Domain: Python logging ===\n");
-                                       break;
-                               default:
-                                       MSG("=== Domain: Unimplemented ===\n");
-                                       break;
-                               }
-
-                               if (lttng_opt_mi) {
-                                       ret = mi_lttng_domain(the_writer,
-                                                       &domains[i], 1);
-                                       if (ret) {
-                                               ret = CMD_ERROR;
-                                               goto end;
-                                       }
-                               }
-
-                               /* Clean handle before creating a new one */
-                               if (the_handle) {
-                                       lttng_destroy_handle(the_handle);
-                               }
-
-                               the_handle = lttng_create_handle(
-                                               session_name, &domains[i]);
-                               if (the_handle == NULL) {
-                                       ret = CMD_FATAL;
-                                       goto end;
-                               }
-
-                               if (domains[i].type == LTTNG_DOMAIN_JUL ||
-                                               domains[i].type == LTTNG_DOMAIN_LOG4J ||
-                                               domains[i].type == LTTNG_DOMAIN_PYTHON) {
-                                       ret = list_session_agent_events();
-                                       if (ret) {
-                                               goto end;
-                                       }
-
-                                       goto next_domain;
-                               }
-
-                               switch (domains[i].type) {
-                               case LTTNG_DOMAIN_KERNEL:
-                               case LTTNG_DOMAIN_UST:
-                                       ret = list_trackers(&domains[i]);
-                                       if (ret) {
-                                               goto end;
-                                       }
-                                       break;
-                               default:
-                                       break;
-                               }
-
-                               ret = list_channels(opt_channel);
-                               if (ret) {
-                                       goto end;
-                               }
-
-next_domain:
-                               if (lttng_opt_mi) {
-                                       /* Close domain element */
-                                       ret = mi_lttng_writer_close_element(
-                                                       the_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(
-                                               the_writer, 3);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-               }
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(the_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(the_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-end:
-       /* Mi clean-up */
-       if (the_writer && mi_lttng_writer_destroy(the_writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
-       }
-
-       free(domains);
-       if (the_handle) {
-               lttng_destroy_handle(the_handle);
-       }
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/list.cpp b/src/bin/lttng/commands/list.cpp
new file mode 100644 (file)
index 0000000..4bb681e
--- /dev/null
@@ -0,0 +1,2635 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdint.h>
+#define _LGPL_SOURCE
+#include <inttypes.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/mi-lttng.h>
+#include <common/time.h>
+#include <common/tracker.h>
+#include <lttng/domain-internal.h>
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+static int opt_userspace;
+static int opt_kernel;
+static int opt_jul;
+static int opt_log4j;
+static int opt_python;
+static char *opt_channel;
+static int opt_domain;
+static int opt_fields;
+static int opt_syscall;
+
+const char *indent4 = "    ";
+const char *indent6 = "      ";
+const char *indent8 = "        ";
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-list.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_USERSPACE,
+       OPT_LIST_OPTIONS,
+};
+
+static struct lttng_handle *the_handle;
+static struct mi_writer *the_writer;
+
+/* Only set when listing a single session. */
+static struct lttng_session the_listed_session;
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"kernel",      'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0},
+       {"jul", 'j', POPT_ARG_VAL, &opt_jul, 1, 0, 0},
+       {"log4j",       'l', POPT_ARG_VAL, &opt_log4j, 1, 0, 0},
+       {"python",      'p', POPT_ARG_VAL, &opt_python, 1, 0, 0},
+       {"userspace",   'u', POPT_ARG_NONE, 0, OPT_USERSPACE, 0, 0},
+       {"channel",     'c', POPT_ARG_STRING, &opt_channel, 0, 0, 0},
+       {"domain",      'd', POPT_ARG_VAL, &opt_domain, 1, 0, 0},
+       {"fields",      'f', POPT_ARG_VAL, &opt_fields, 1, 0, 0},
+       {"syscall",     'S', POPT_ARG_VAL, &opt_syscall, 1, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Get command line from /proc for a specific pid.
+ *
+ * On success, return an allocated string pointer to the proc cmdline.
+ * On error, return NULL.
+ */
+static char *get_cmdline_by_pid(pid_t pid)
+{
+       int ret;
+       FILE *fp = NULL;
+       char *cmdline = NULL;
+       /* Can't go bigger than /proc/LTTNG_MAX_PID/cmdline */
+       char path[sizeof("/proc//cmdline") + sizeof(LTTNG_MAX_PID_STR) - 1];
+
+       snprintf(path, sizeof(path), "/proc/%d/cmdline", pid);
+       fp = fopen(path, "r");
+       if (fp == NULL) {
+               goto end;
+       }
+
+       /* Caller must free() *cmdline */
+       cmdline = (char *) zmalloc(PATH_MAX);
+       if (!cmdline) {
+               PERROR("malloc cmdline");
+               goto end;
+       }
+       ret = fread(cmdline, 1, PATH_MAX, fp);
+       if (ret < 0) {
+               PERROR("fread proc list");
+       }
+
+end:
+       if (fp) {
+               fclose(fp);
+       }
+       return cmdline;
+}
+
+static
+const char *active_string(int value)
+{
+       switch (value) {
+       case 0: return "inactive";
+       case 1: return "active";
+       case -1: return "";
+       default: return NULL;
+       }
+}
+
+static const char *snapshot_string(int value)
+{
+       switch (value) {
+       case 1:
+               return " snapshot";
+       default:
+               return "";
+       }
+}
+
+static
+const char *enabled_string(int value)
+{
+       switch (value) {
+       case 0: return " [disabled]";
+       case 1: return " [enabled]";
+       case -1: return "";
+       default: return NULL;
+       }
+}
+
+static
+const char *safe_string(const char *str)
+{
+       return str ? str : "";
+}
+
+static const char *logleveltype_string(enum lttng_loglevel_type value)
+{
+       switch (value) {
+       case LTTNG_EVENT_LOGLEVEL_ALL:
+               return ":";
+       case LTTNG_EVENT_LOGLEVEL_RANGE:
+               return " <=";
+       case LTTNG_EVENT_LOGLEVEL_SINGLE:
+               return " ==";
+       default:
+               return " <<TYPE UNKN>>";
+       }
+}
+
+static const char *bitness_event(enum lttng_event_flag flags)
+{
+       if (flags & LTTNG_EVENT_FLAG_SYSCALL_32) {
+               if (flags & LTTNG_EVENT_FLAG_SYSCALL_64) {
+                       return " [32/64-bit]";
+               } else {
+                       return " [32-bit]";
+               }
+       } else if (flags & LTTNG_EVENT_FLAG_SYSCALL_64) {
+               return " [64-bit]";
+       } else {
+               return "";
+       }
+}
+
+/*
+ * Get exclusion names message for a single event.
+ *
+ * Returned pointer must be freed by caller. Returns NULL on error.
+ */
+static char *get_exclusion_names_msg(struct lttng_event *event)
+{
+       int ret;
+       int exclusion_count;
+       char *exclusion_msg = NULL;
+       char *at;
+       size_t i;
+       const char * const exclusion_fmt = " [exclusions: ";
+       const size_t exclusion_fmt_len = strlen(exclusion_fmt);
+
+       exclusion_count = lttng_event_get_exclusion_name_count(event);
+       if (exclusion_count < 0) {
+               goto end;
+       } else if (exclusion_count == 0) {
+               /*
+                * No exclusions: return copy of empty string so that
+                * it can be freed by caller.
+                */
+               exclusion_msg = strdup("");
+               goto end;
+       }
+
+       /*
+        * exclusion_msg's size is bounded by the exclusion_fmt string,
+        * a comma per entry, the entry count (fixed-size), a closing
+        * bracket, and a trailing \0.
+        */
+       exclusion_msg = (char *) malloc(exclusion_count +
+                       exclusion_count * LTTNG_SYMBOL_NAME_LEN +
+                       exclusion_fmt_len + 1);
+       if (!exclusion_msg) {
+               goto end;
+       }
+
+       at = strcpy(exclusion_msg, exclusion_fmt) + exclusion_fmt_len;
+       for (i = 0; i < exclusion_count; ++i) {
+               const char *name;
+
+               /* Append comma between exclusion names */
+               if (i > 0) {
+                       *at = ',';
+                       at++;
+               }
+
+               ret = lttng_event_get_exclusion_name(event, i, &name);
+               if (ret) {
+                       /* Prints '?' on local error; should never happen */
+                       *at = '?';
+                       at++;
+                       continue;
+               }
+
+               /* Append exclusion name */
+               at += sprintf(at, "%s", name);
+       }
+
+       /* This also puts a final '\0' at the end of exclusion_msg */
+       strcpy(at, "]");
+
+end:
+       return exclusion_msg;
+}
+
+static void print_userspace_probe_location(struct lttng_event *event)
+{
+       const struct lttng_userspace_probe_location *location;
+       const struct lttng_userspace_probe_location_lookup_method *lookup_method;
+       enum lttng_userspace_probe_location_lookup_method_type lookup_type;
+
+       location = lttng_event_get_userspace_probe_location(event);
+       if (!location) {
+               MSG("Event has no userspace probe location");
+               return;
+       }
+
+       lookup_method = lttng_userspace_probe_location_get_lookup_method(location);
+       if (!lookup_method) {
+               MSG("Event has no userspace probe location lookup method");
+               return;
+       }
+
+       MSG("%s%s (type: userspace-probe)%s", indent6, event->name, enabled_string(event->enabled));
+
+       lookup_type = lttng_userspace_probe_location_lookup_method_get_type(lookup_method);
+
+       switch (lttng_userspace_probe_location_get_type(location)) {
+       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_UNKNOWN:
+               MSG("%sType: Unknown", indent8);
+               break;
+       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
+       {
+               const char *function_name;
+               char *binary_path;
+
+               MSG("%sType: Function", indent8);
+               function_name = lttng_userspace_probe_location_function_get_function_name(location);
+               binary_path = realpath(lttng_userspace_probe_location_function_get_binary_path(location), NULL);
+
+               MSG("%sBinary path:   %s", indent8, binary_path ? binary_path : "NULL");
+               MSG("%sFunction:      %s()", indent8, function_name ? function_name : "NULL");
+               switch (lookup_type) {
+               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+                       MSG("%sLookup method: ELF", indent8);
+                       break;
+               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_DEFAULT:
+                       MSG("%sLookup method: default", indent8);
+                       break;
+               default:
+                       MSG("%sLookup method: INVALID LOOKUP TYPE ENCOUNTERED", indent8);
+                       break;
+               }
+
+               free(binary_path);
+               break;
+       }
+       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
+       {
+               const char *probe_name, *provider_name;
+               char *binary_path;
+
+               MSG("%sType: Tracepoint", indent8);
+               probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(location);
+               provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(location);
+               binary_path = realpath(lttng_userspace_probe_location_tracepoint_get_binary_path(location), NULL);
+               MSG("%sBinary path:   %s", indent8, binary_path ? binary_path : "NULL");
+               MSG("%sTracepoint:    %s:%s", indent8, provider_name ? provider_name : "NULL", probe_name ? probe_name : "NULL");
+               switch (lookup_type) {
+               case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+                       MSG("%sLookup method: SDT", indent8);
+                       break;
+               default:
+                       MSG("%sLookup method: INVALID LOOKUP TYPE ENCOUNTERED", indent8);
+                       break;
+               }
+
+               free(binary_path);
+               break;
+       }
+       default:
+               ERR("Invalid probe type encountered");
+       }
+}
+
+/*
+ * Pretty print single event.
+ */
+static void print_events(struct lttng_event *event)
+{
+       int ret;
+       const char *filter_str;
+       char *filter_msg = NULL;
+       char *exclusion_msg = NULL;
+
+       ret = lttng_event_get_filter_expression(event, &filter_str);
+
+       if (ret) {
+               filter_msg = strdup(" [failed to retrieve filter]");
+       } else if (filter_str) {
+               const char * const filter_fmt = " [filter: '%s']";
+
+               filter_msg = (char *) malloc(strlen(filter_str) +
+                               strlen(filter_fmt) + 1);
+               if (filter_msg) {
+                       sprintf(filter_msg, filter_fmt,
+                                       filter_str);
+               }
+       }
+
+       exclusion_msg = get_exclusion_names_msg(event);
+       if (!exclusion_msg) {
+               exclusion_msg = strdup(" [failed to retrieve exclusions]");
+       }
+
+       switch (event->type) {
+       case LTTNG_EVENT_TRACEPOINT:
+       {
+               if (event->loglevel != -1) {
+                       MSG("%s%s (loglevel%s %s (%d)) (type: tracepoint)%s%s%s",
+                                       indent6, event->name,
+                                       logleveltype_string(
+                                                       event->loglevel_type),
+                                       mi_lttng_loglevel_string(
+                                                       event->loglevel,
+                                                       the_handle->domain.type),
+                                       event->loglevel,
+                                       enabled_string(event->enabled),
+                                       safe_string(exclusion_msg),
+                                       safe_string(filter_msg));
+               } else {
+                       MSG("%s%s (type: tracepoint)%s%s%s",
+                               indent6,
+                               event->name,
+                               enabled_string(event->enabled),
+                               safe_string(exclusion_msg),
+                               safe_string(filter_msg));
+               }
+               break;
+       }
+       case LTTNG_EVENT_FUNCTION:
+               MSG("%s%s (type: function)%s%s", indent6,
+                               event->name, enabled_string(event->enabled),
+                               safe_string(filter_msg));
+               if (event->attr.probe.addr != 0) {
+                       MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
+               } else {
+                       MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
+                       MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
+               }
+               break;
+       case LTTNG_EVENT_PROBE:
+               MSG("%s%s (type: probe)%s%s", indent6,
+                               event->name, enabled_string(event->enabled),
+                               safe_string(filter_msg));
+               if (event->attr.probe.addr != 0) {
+                       MSG("%saddr: 0x%" PRIx64, indent8, event->attr.probe.addr);
+               } else {
+                       MSG("%soffset: 0x%" PRIx64, indent8, event->attr.probe.offset);
+                       MSG("%ssymbol: %s", indent8, event->attr.probe.symbol_name);
+               }
+               break;
+       case LTTNG_EVENT_USERSPACE_PROBE:
+               print_userspace_probe_location(event);
+               break;
+       case LTTNG_EVENT_FUNCTION_ENTRY:
+               MSG("%s%s (type: function)%s%s", indent6,
+                               event->name, enabled_string(event->enabled),
+                               safe_string(filter_msg));
+               MSG("%ssymbol: \"%s\"", indent8, event->attr.ftrace.symbol_name);
+               break;
+       case LTTNG_EVENT_SYSCALL:
+               MSG("%s%s%s%s%s%s", indent6, event->name,
+                               (opt_syscall ? "" : " (type:syscall)"),
+                               enabled_string(event->enabled),
+                               bitness_event(event->flags),
+                               safe_string(filter_msg));
+               break;
+       case LTTNG_EVENT_NOOP:
+               MSG("%s (type: noop)%s%s", indent6,
+                               enabled_string(event->enabled),
+                               safe_string(filter_msg));
+               break;
+       case LTTNG_EVENT_ALL:
+               /* Fall-through. */
+       default:
+               /* We should never have "all" events in list. */
+               abort();
+               break;
+       }
+
+       free(filter_msg);
+       free(exclusion_msg);
+}
+
+static const char *field_type(struct lttng_event_field *field)
+{
+       switch(field->type) {
+       case LTTNG_EVENT_FIELD_INTEGER:
+               return "integer";
+       case LTTNG_EVENT_FIELD_ENUM:
+               return "enum";
+       case LTTNG_EVENT_FIELD_FLOAT:
+               return "float";
+       case LTTNG_EVENT_FIELD_STRING:
+               return "string";
+       case LTTNG_EVENT_FIELD_OTHER:
+       default:        /* fall-through */
+               return "unknown";
+       }
+}
+
+/*
+ * Pretty print single event fields.
+ */
+static void print_event_field(struct lttng_event_field *field)
+{
+       if (!field->field_name[0]) {
+               return;
+       }
+       MSG("%sfield: %s (%s)%s", indent8, field->field_name,
+               field_type(field), field->nowrite ? " [no write]" : "");
+}
+
+/*
+ * Machine interface
+ * Jul and ust event listing
+ */
+static int mi_list_agent_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(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(the_writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open pids element element */
+       ret = mi_lttng_pids_open(the_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(
+                                               the_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(the_writer, cur_pid, cmdline,
+                                               1);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               /* Open events element */
+                               ret = mi_lttng_events_open(the_writer);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               pid_element_open = 1;
+                       }
+                       free(cmdline);
+               }
+
+               /* Write an event */
+               ret = mi_lttng_event(the_writer, &events[i], 0,
+                               the_handle->domain.type);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close pids */
+       ret = mi_lttng_writer_close_element(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close domain, domains */
+       ret = mi_lttng_close_multi_element(the_writer, 2);
+end:
+       return ret;
+error:
+       free(cmdline);
+       return ret;
+}
+
+static int list_agent_events(void)
+{
+       int i, size, ret = CMD_SUCCESS;
+       struct lttng_domain domain;
+       struct lttng_handle *handle = NULL;
+       struct lttng_event *event_list = NULL;
+       pid_t cur_pid = 0;
+       char *cmdline = NULL;
+       const char *agent_domain_str;
+
+       memset(&domain, 0, sizeof(domain));
+       if (opt_jul) {
+               domain.type = LTTNG_DOMAIN_JUL;
+       } else if (opt_log4j) {
+               domain.type = LTTNG_DOMAIN_LOG4J;
+       } else if (opt_python) {
+               domain.type = LTTNG_DOMAIN_PYTHON;
+       } else {
+               ERR("Invalid agent domain selected.");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       agent_domain_str = lttng_domain_type_str(domain.type);
+
+       DBG("Getting %s tracing events", agent_domain_str);
+
+       handle = lttng_create_handle(NULL, &domain);
+       if (handle == NULL) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       size = lttng_list_tracepoints(handle, &event_list);
+       if (size < 0) {
+               ERR("Unable to list %s events: %s", agent_domain_str,
+                               lttng_strerror(size));
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_agent_ust_events(event_list, size, &domain);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               /* Pretty print */
+               MSG("%s events (Logger name):\n-------------------------",
+                               agent_domain_str);
+
+               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);
+                       }
+                       MSG("%s- %s", indent6, event_list[i].name);
+               }
+
+               MSG("");
+       }
+
+error:
+       free(event_list);
+end:
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ * Ask session daemon for all user space tracepoints available.
+ */
+static int list_ust_events(void)
+{
+       int i, size, ret = CMD_SUCCESS;
+       struct lttng_domain domain;
+       struct lttng_handle *handle;
+       struct lttng_event *event_list = NULL;
+       pid_t cur_pid = 0;
+       char *cmdline = NULL;
+
+       memset(&domain, 0, sizeof(domain));
+
+       DBG("Getting UST tracing events");
+
+       domain.type = LTTNG_DOMAIN_UST;
+
+       handle = lttng_create_handle(NULL, &domain);
+       if (handle == NULL) {
+               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));
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_agent_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]);
+               }
+
+               MSG("");
+       }
+
+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;
+
+       memset(&cur_event, 0, sizeof(cur_event));
+
+       /* Open domains element */
+       ret = mi_lttng_domains_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(the_writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open pids element */
+       ret = mi_lttng_pids_open(the_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 field element and event. */
+                                       ret = mi_lttng_close_multi_element(
+                                                       the_writer, 2);
+                                       if (ret) {
+                                               goto end;
+                                       }
+                                       event_element_open = 0;
+                               }
+                               /* Close the previous events, pid element */
+                               ret = mi_lttng_close_multi_element(
+                                               the_writer, 2);
+                               if (ret) {
+                                       goto end;
+                               }
+                               pid_element_open = 0;
+                       }
+
+                       cur_pid = fields[i].event.pid;
+                       cmdline = get_cmdline_by_pid(cur_pid);
+                       if (!pid_element_open) {
+                               /* Open and write a pid element */
+                               ret = mi_lttng_pid(the_writer, cur_pid, cmdline,
+                                               1);
+                               if (ret) {
+                                       goto error;
+                               }
+
+                               /* Open events element */
+                               ret = mi_lttng_events_open(the_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));
+               }
+
+               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(
+                                               the_writer, 2);
+                               if (ret) {
+                                       goto end;
+                               }
+                               event_element_open = 0;
+                       }
+
+                       memcpy(&cur_event, &fields[i].event,
+                                       sizeof(cur_event));
+
+                       if (!event_element_open) {
+                               /* Open and write the event */
+                               ret = mi_lttng_event(the_writer, &cur_event, 1,
+                                               the_handle->domain.type);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                               /* Open a fields element */
+                               ret = mi_lttng_event_fields_open(the_writer);
+                               if (ret) {
+                                       goto end;
+                               }
+                               event_element_open = 1;
+                       }
+               }
+
+               /* Print the event_field */
+               ret = mi_lttng_event_field(the_writer, &fields[i]);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close pids, domain, domains */
+       ret = mi_lttng_close_multi_element(the_writer, 3);
+end:
+       return ret;
+error:
+       free(cmdline);
+       return ret;
+}
+
+/*
+ * Ask session daemon for all user space tracepoint fields available.
+ */
+static int list_ust_event_fields(void)
+{
+       int i, size, ret = CMD_SUCCESS;
+       struct lttng_domain domain;
+       struct lttng_handle *handle;
+       struct lttng_event_field *event_field_list;
+       pid_t cur_pid = 0;
+       char *cmdline = NULL;
+
+       struct lttng_event cur_event;
+
+       memset(&domain, 0, sizeof(domain));
+       memset(&cur_event, 0, sizeof(cur_event));
+
+       DBG("Getting UST tracing event fields");
+
+       domain.type = LTTNG_DOMAIN_UST;
+
+       handle = lttng_create_handle(NULL, &domain);
+       if (handle == NULL) {
+               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));
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       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-------------");
+
+               if (size == 0) {
+                       MSG("None");
+               }
+
+               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]);
+               }
+
+               MSG("");
+       }
+
+error:
+       free(event_field_list);
+end:
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ * 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;
+
+       /* Open domains element */
+       ret = mi_lttng_domains_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Write domain */
+       ret = mi_lttng_domain(the_writer, domain, 1);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open events */
+       ret = mi_lttng_events_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_event(the_writer, &events[i], 0,
+                               the_handle->domain.type);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* close events, domain and domains */
+       ret = mi_lttng_close_multi_element(the_writer, 3);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Ask for all trace events in the kernel
+ */
+static int list_kernel_events(void)
+{
+       int i, size, ret = CMD_SUCCESS;
+       struct lttng_domain domain;
+       struct lttng_handle *handle;
+       struct lttng_event *event_list;
+
+       memset(&domain, 0, sizeof(domain));
+
+       DBG("Getting kernel tracing events");
+
+       domain.type = LTTNG_DOMAIN_KERNEL;
+
+       handle = lttng_create_handle(NULL, &domain);
+       if (handle == NULL) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       size = lttng_list_tracepoints(handle, &event_list);
+       if (size < 0) {
+               ERR("Unable to list kernel events: %s", lttng_strerror(size));
+               lttng_destroy_handle(handle);
+               return CMD_ERROR;
+       }
+
+       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]);
+               }
+
+               MSG("");
+       }
+
+end:
+       free(event_list);
+
+       lttng_destroy_handle(handle);
+       return ret;
+
+error:
+       lttng_destroy_handle(handle);
+       return ret;
+}
+
+/*
+ * Machine interface
+ * Print a list of system calls.
+ */
+static int mi_list_syscalls(struct lttng_event *events, int count)
+{
+       int ret, i;
+
+       /* Open events */
+       ret = mi_lttng_events_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_event(the_writer, &events[i], 0,
+                               the_handle->domain.type);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close events. */
+       ret = mi_lttng_writer_close_element(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Ask for kernel system calls.
+ */
+static int list_syscalls(void)
+{
+       int i, size, ret = CMD_SUCCESS;
+       struct lttng_event *event_list;
+
+       DBG("Getting kernel system call events");
+
+       size = lttng_list_syscalls(&event_list);
+       if (size < 0) {
+               ERR("Unable to list system calls: %s", lttng_strerror(size));
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_syscalls(event_list, size);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               MSG("System calls:\n-------------");
+
+               for (i = 0; i < size; i++) {
+                       print_events(&event_list[i]);
+               }
+
+               MSG("");
+       }
+
+end:
+       free(event_list);
+       return ret;
+
+error:
+       return ret;
+}
+
+/*
+ * Machine Interface
+ * Print a list of agent events
+ */
+static int mi_list_session_agent_events(struct lttng_event *events, int count)
+{
+       int ret, i;
+
+       /* Open events element */
+       ret = mi_lttng_events_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_event(the_writer, &events[i], 0,
+                               the_handle->domain.type);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close events element */
+       ret = mi_lttng_writer_close_element(the_writer);
+
+end:
+       return ret;
+}
+
+/*
+ * List agent events for a specific session using the handle.
+ *
+ * Return CMD_SUCCESS on success else a negative value.
+ */
+static int list_session_agent_events(void)
+{
+       int ret = CMD_SUCCESS, count, i;
+       struct lttng_event *events = NULL;
+
+       count = lttng_list_events(the_handle, "", &events);
+       if (count < 0) {
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_session_agent_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++) {
+                       const char *filter_str;
+                       char *filter_msg = NULL;
+                       struct lttng_event *event = &events[i];
+
+                       ret = lttng_event_get_filter_expression(event,
+                                       &filter_str);
+                       if (ret) {
+                               filter_msg = strdup(" [failed to retrieve filter]");
+                       } else if (filter_str) {
+                               const char * const filter_fmt =
+                                               " [filter: '%s']";
+
+                               filter_msg = (char *) malloc(strlen(filter_str) +
+                                               strlen(filter_fmt) + 1);
+                               if (filter_msg) {
+                                       sprintf(filter_msg, filter_fmt,
+                                                       filter_str);
+                               }
+                       }
+
+                       if (event->loglevel_type !=
+                                       LTTNG_EVENT_LOGLEVEL_ALL) {
+                               MSG("%s- %s%s (loglevel%s %s)%s", indent4,
+                                               event->name,
+                                               enabled_string(event->enabled),
+                                               logleveltype_string(
+                                                               event->loglevel_type),
+                                               mi_lttng_loglevel_string(
+                                                               event->loglevel,
+                                                               the_handle->domain
+                                                                               .type),
+                                               safe_string(filter_msg));
+                       } else {
+                               MSG("%s- %s%s%s", indent4, event->name,
+                                               enabled_string(event->enabled),
+                                               safe_string(filter_msg));
+                       }
+                       free(filter_msg);
+               }
+
+               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(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_event(the_writer, &events[i], 0,
+                               the_handle->domain.type);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close events element */
+       ret = mi_lttng_writer_close_element(the_writer);
+
+end:
+       return ret;
+}
+
+/*
+ * List events of channel of session and domain.
+ */
+static int list_events(const char *channel_name)
+{
+       int ret = CMD_SUCCESS, count, i;
+       struct lttng_event *events = NULL;
+
+       count = lttng_list_events(the_handle, channel_name, &events);
+       if (count < 0) {
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_list_events(events, count);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               /* Pretty print */
+               MSG("\n%sRecording event rules:", indent4);
+               if (count == 0) {
+                       MSG("%sNone\n", indent6);
+                       goto end;
+               }
+
+               for (i = 0; i < count; i++) {
+                       print_events(&events[i]);
+               }
+
+               MSG("");
+       }
+end:
+       free(events);
+error:
+       return ret;
+}
+
+static
+void print_timer(const char *timer_name, uint32_t space_count, int64_t value)
+{
+       uint32_t i;
+
+       _MSG("%s%s:", indent6, timer_name);
+       for (i = 0; i < space_count; i++) {
+               _MSG(" ");
+       }
+
+       if (value) {
+               MSG("%" PRId64 " %s", value, USEC_UNIT);
+       } else {
+               MSG("inactive");
+       }
+}
+
+/*
+ * Pretty print channel
+ */
+static void print_channel(struct lttng_channel *channel)
+{
+       int ret;
+       uint64_t discarded_events, lost_packets, monitor_timer_interval;
+       int64_t blocking_timeout;
+
+       ret = lttng_channel_get_discarded_event_count(channel,
+                       &discarded_events);
+       if (ret) {
+               ERR("Failed to retrieve discarded event count of channel");
+               return;
+       }
+
+       ret = lttng_channel_get_lost_packet_count(channel,
+                       &lost_packets);
+       if (ret) {
+               ERR("Failed to retrieve lost packet count of channel");
+               return;
+       }
+
+       ret = lttng_channel_get_monitor_timer_interval(channel,
+                       &monitor_timer_interval);
+       if (ret) {
+               ERR("Failed to retrieve monitor interval of channel");
+               return;
+       }
+
+       ret = lttng_channel_get_blocking_timeout(channel,
+                       &blocking_timeout);
+       if (ret) {
+               ERR("Failed to retrieve blocking timeout of channel");
+               return;
+       }
+
+       MSG("- %s:%s\n", channel->name, enabled_string(channel->enabled));
+       MSG("%sAttributes:", indent4);
+       MSG("%sEvent-loss mode:  %s", indent6, channel->attr.overwrite ? "overwrite" : "discard");
+       MSG("%sSub-buffer size:  %" PRIu64 " bytes", indent6, channel->attr.subbuf_size);
+       MSG("%sSub-buffer count: %" PRIu64, indent6, channel->attr.num_subbuf);
+
+       print_timer("Switch timer", 5, channel->attr.switch_timer_interval);
+       print_timer("Read timer",  7, channel->attr.read_timer_interval);
+       print_timer("Monitor timer", 4, monitor_timer_interval);
+
+       if (!channel->attr.overwrite) {
+               if (blocking_timeout == -1) {
+                       MSG("%sBlocking timeout: infinite", indent6);
+               } else {
+                       MSG("%sBlocking timeout: %" PRId64 " %s", indent6,
+                                       blocking_timeout, USEC_UNIT);
+               }
+       }
+
+       MSG("%sTrace file count: %" PRIu64 " per stream", indent6,
+                       channel->attr.tracefile_count == 0 ?
+                               1 : channel->attr.tracefile_count);
+       if (channel->attr.tracefile_size != 0 ) {
+               MSG("%sTrace file size:  %" PRIu64 " bytes", indent6,
+                               channel->attr.tracefile_size);
+       } else {
+               MSG("%sTrace file size:  %s", indent6, "unlimited");
+       }
+       switch (channel->attr.output) {
+               case LTTNG_EVENT_SPLICE:
+                       MSG("%sOutput mode:      splice", indent6);
+                       break;
+               case LTTNG_EVENT_MMAP:
+                       MSG("%sOutput mode:      mmap", indent6);
+                       break;
+       }
+
+       MSG("\n%sStatistics:", indent4);
+       if (the_listed_session.snapshot_mode) {
+               /*
+                * The lost packet count is omitted for sessions in snapshot
+                * mode as it is misleading: it would indicate the number of
+                * packets that the consumer could not extract during the
+                * course of recording the snapshot. It does not have the
+                * same meaning as the "regular" lost packet count that
+                * would result from the consumer not keeping up with
+                * event production in an overwrite-mode channel.
+                *
+                * A more interesting statistic would be the number of
+                * packets lost between the first and last extracted
+                * packets of a given snapshot (which prevents most analyses).
+                */
+               MSG("%sNone", indent6);
+               goto skip_stats_printing;
+       }
+
+       if (!channel->attr.overwrite) {
+               MSG("%sDiscarded events: %" PRIu64, indent6, discarded_events);
+       } else {
+               MSG("%sLost packets:     %" PRIu64, indent6, lost_packets);
+       }
+skip_stats_printing:
+       return;
+}
+
+/*
+ * 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(the_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(the_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(the_writer);
+               if (ret) {
+                       goto error;
+               }
+
+               if (chan_found) {
+                       break;
+               }
+       }
+
+       /* Close channels element */
+       ret = mi_lttng_writer_close_element(the_writer);
+       if (ret) {
+               goto error;
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * List channel(s) of session and domain.
+ *
+ * If channel_name is NULL, all channels are listed.
+ */
+static int list_channels(const char *channel_name)
+{
+       int count, i, ret = CMD_SUCCESS;
+       unsigned int chan_found = 0;
+       struct lttng_channel *channels = NULL;
+
+       DBG("Listing channel(s) (%s)", channel_name ? : "<all>");
+
+       count = lttng_list_channels(the_handle, &channels);
+       if (count < 0) {
+               switch (-count) {
+               case LTTNG_ERR_KERN_CHAN_NOT_FOUND:
+                       if (lttng_opt_mi) {
+                               /* When printing mi this is not an error
+                                * but an empty channels element */
+                               count = 0;
+                       } else {
+                               ret = CMD_SUCCESS;
+                               goto error_channels;
+                       }
+                       break;
+               default:
+                       /* We had a real error */
+                       ret = CMD_ERROR;
+                       ERR("%s", lttng_strerror(count));
+                       goto error_channels;
+                       break;
+               }
+       }
+
+       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 (count) {
+                       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;
+                               }
+                       }
+                       print_channel(&channels[i]);
+
+                       /* Listing events per channel */
+                       ret = list_events(channels[i].name);
+                       if (ret) {
+                               goto error;
+                       }
+
+                       if (chan_found) {
+                               break;
+                       }
+               }
+
+               if (!chan_found && channel_name != NULL) {
+                       ret = CMD_ERROR;
+                       ERR("Channel %s not found", channel_name);
+                       goto error;
+               }
+       }
+error:
+       free(channels);
+
+error_channels:
+       return ret;
+}
+
+static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
+{
+       switch (process_attr) {
+       case LTTNG_PROCESS_ATTR_PROCESS_ID:
+               return "Process ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+               return "Virtual process ID";
+       case LTTNG_PROCESS_ATTR_USER_ID:
+               return "User ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+               return "Virtual user ID";
+       case LTTNG_PROCESS_ATTR_GROUP_ID:
+               return "Group ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+               return "Virtual group ID";
+       default:
+               return "Unknown";
+       }
+       return NULL;
+}
+
+static int handle_process_attr_status(enum lttng_process_attr process_attr,
+               enum lttng_process_attr_tracker_handle_status status)
+{
+       int ret = CMD_SUCCESS;
+
+       switch (status) {
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_INVALID_TRACKING_POLICY:
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
+               /* Carry on. */
+               break;
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_COMMUNICATION_ERROR:
+               ERR("Communication occurred while fetching %s tracker",
+                               lttng_process_attr_to_string(process_attr));
+               ret = CMD_ERROR;
+               break;
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
+               ERR("Failed to get the inclusion set of the %s tracker: session `%s` no longer exists",
+                               lttng_process_attr_to_string(process_attr),
+                               the_handle->session_name);
+               ret = CMD_ERROR;
+               break;
+       default:
+               ERR("Unknown error occurred while fetching the inclusion set of the %s tracker",
+                               lttng_process_attr_to_string(process_attr));
+               ret = CMD_ERROR;
+               break;
+       }
+
+       return ret;
+}
+
+static int mi_output_empty_tracker(enum lttng_process_attr process_attr)
+{
+       int ret;
+
+       ret = mi_lttng_process_attribute_tracker_open(the_writer, process_attr);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_close_multi_element(the_writer, 2);
+end:
+       return ret;
+}
+
+static inline bool is_value_type_name(
+               enum lttng_process_attr_value_type value_type)
+{
+       return value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME ||
+              value_type == LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME;
+}
+
+/*
+ * List a process attribute tracker for a session and domain tuple.
+ */
+static int list_process_attr_tracker(enum lttng_process_attr process_attr)
+{
+       int ret = 0;
+       unsigned int count, i;
+       enum lttng_tracking_policy policy;
+       enum lttng_error_code ret_code;
+       enum lttng_process_attr_tracker_handle_status handle_status;
+       enum lttng_process_attr_values_status values_status;
+       const struct lttng_process_attr_values *values;
+       struct lttng_process_attr_tracker_handle *tracker_handle = NULL;
+
+       ret_code = lttng_session_get_tracker_handle(the_handle->session_name,
+                       the_handle->domain.type, process_attr, &tracker_handle);
+       if (ret_code != LTTNG_OK) {
+               ERR("Failed to get process attribute tracker handle: %s",
+                               lttng_strerror(ret_code));
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       handle_status = lttng_process_attr_tracker_handle_get_inclusion_set(
+                       tracker_handle, &values);
+       ret = handle_process_attr_status(process_attr, handle_status);
+       if (ret != CMD_SUCCESS) {
+               goto end;
+       }
+
+       handle_status = lttng_process_attr_tracker_handle_get_tracking_policy(
+                       tracker_handle, &policy);
+       ret = handle_process_attr_status(process_attr, handle_status);
+       if (ret != CMD_SUCCESS) {
+               goto end;
+       }
+
+       {
+               char *process_attr_name;
+               const int print_ret = asprintf(&process_attr_name, "%ss:",
+                               get_capitalized_process_attr_str(process_attr));
+
+               if (print_ret == -1) {
+                       ret = CMD_FATAL;
+                       goto end;
+               }
+               _MSG("  %-22s", process_attr_name);
+               free(process_attr_name);
+       }
+       switch (policy) {
+       case LTTNG_TRACKING_POLICY_INCLUDE_SET:
+               break;
+       case LTTNG_TRACKING_POLICY_EXCLUDE_ALL:
+               if (the_writer) {
+                       mi_output_empty_tracker(process_attr);
+               }
+               MSG("none");
+               ret = CMD_SUCCESS;
+               goto end;
+       case LTTNG_TRACKING_POLICY_INCLUDE_ALL:
+               MSG("all");
+               ret = CMD_SUCCESS;
+               goto end;
+       default:
+               ERR("Unknown tracking policy encoutered while listing the %s process attribute tracker of session `%s`",
+                               lttng_process_attr_to_string(process_attr),
+                               the_handle->session_name);
+               ret = CMD_FATAL;
+               goto end;
+       }
+
+       values_status = lttng_process_attr_values_get_count(values, &count);
+       if (values_status != LTTNG_PROCESS_ATTR_VALUES_STATUS_OK) {
+               ERR("Failed to get the count of values in the inclusion set of the %s process attribute tracker of session `%s`",
+                               lttng_process_attr_to_string(process_attr),
+                               the_handle->session_name);
+               ret = CMD_FATAL;
+               goto end;
+       }
+
+       if (count == 0) {
+               /* Functionally equivalent to the 'exclude all' policy. */
+               if (the_writer) {
+                       mi_output_empty_tracker(process_attr);
+               }
+               MSG("none");
+               ret = CMD_SUCCESS;
+               goto end;
+       }
+
+       /* Mi tracker_id element */
+       if (the_writer) {
+               /* Open tracker_id and targets elements */
+               ret = mi_lttng_process_attribute_tracker_open(
+                               the_writer, process_attr);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < count; i++) {
+               const enum lttng_process_attr_value_type value_type =
+                               lttng_process_attr_values_get_type_at_index(
+                                               values, i);
+               int64_t integral_value = INT64_MAX;
+               const char *name = "error";
+
+               if (i >= 1) {
+                       _MSG(", ");
+               }
+               switch (value_type) {
+               case LTTNG_PROCESS_ATTR_VALUE_TYPE_PID:
+               {
+                       pid_t pid;
+
+                       values_status = lttng_process_attr_values_get_pid_at_index(
+                                       values, i, &pid);
+                       integral_value = (int64_t) pid;
+                       break;
+               }
+               case LTTNG_PROCESS_ATTR_VALUE_TYPE_UID:
+               {
+                       uid_t uid;
+
+                       values_status = lttng_process_attr_values_get_uid_at_index(
+                                       values, i, &uid);
+                       integral_value = (int64_t) uid;
+                       break;
+               }
+               case LTTNG_PROCESS_ATTR_VALUE_TYPE_GID:
+               {
+                       gid_t gid;
+
+                       values_status = lttng_process_attr_values_get_gid_at_index(
+                                       values, i, &gid);
+                       integral_value = (int64_t) gid;
+                       break;
+               }
+               case LTTNG_PROCESS_ATTR_VALUE_TYPE_USER_NAME:
+                       values_status = lttng_process_attr_values_get_user_name_at_index(
+                                       values, i, &name);
+                       break;
+               case LTTNG_PROCESS_ATTR_VALUE_TYPE_GROUP_NAME:
+                       values_status = lttng_process_attr_values_get_group_name_at_index(
+                                       values, i, &name);
+                       break;
+               default:
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               if (values_status != LTTNG_PROCESS_ATTR_VALUES_STATUS_OK) {
+                       /*
+                        * Not possible given the current liblttng-ctl
+                        * implementation.
+                        */
+                       ERR("Unknown error occurred while fetching process attribute value in inclusion list");
+                       ret = CMD_FATAL;
+                       goto end;
+               }
+
+               if (is_value_type_name(value_type)) {
+                       _MSG("`%s`", name);
+               } else {
+                       _MSG("%" PRIi64, integral_value);
+               }
+
+               /* Mi */
+               if (the_writer) {
+                       ret = is_value_type_name(value_type) ?
+                                             mi_lttng_string_process_attribute_value(
+                                                       the_writer,
+                                                       process_attr, name,
+                                                       false) :
+                                             mi_lttng_integral_process_attribute_value(
+                                                       the_writer,
+                                                       process_attr,
+                                                       integral_value, false);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       }
+       MSG("");
+
+       /* Mi close tracker_id and targets */
+       if (the_writer) {
+               ret = mi_lttng_close_multi_element(the_writer, 2);
+               if (ret) {
+                       goto end;
+               }
+       }
+end:
+       lttng_process_attr_tracker_handle_destroy(tracker_handle);
+       return ret;
+}
+
+/*
+ * List all trackers of a domain
+ */
+static int list_trackers(const struct lttng_domain *domain)
+{
+       int ret = 0;
+
+       MSG("Tracked process attributes");
+       /* Trackers listing */
+       if (lttng_opt_mi) {
+               ret = mi_lttng_trackers_open(the_writer);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       switch (domain->type) {
+       case LTTNG_DOMAIN_KERNEL:
+               /* pid tracker */
+               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_PROCESS_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* vpid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* uid tracker */
+               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_USER_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* vuid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* gid tracker */
+               ret = list_process_attr_tracker(LTTNG_PROCESS_ATTR_GROUP_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* vgid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID);
+               if (ret) {
+                       goto end;
+               }
+               break;
+       case LTTNG_DOMAIN_UST:
+               /* vpid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* vuid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID);
+               if (ret) {
+                       goto end;
+               }
+               /* vgid tracker */
+               ret = list_process_attr_tracker(
+                               LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID);
+               if (ret) {
+                       goto end;
+               }
+               break;
+       default:
+               break;
+       }
+       MSG();
+       if (lttng_opt_mi) {
+               /* Close trackers element */
+               ret = mi_lttng_writer_close_element(the_writer);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static enum cmd_error_code print_periodic_rotation_schedule(
+               const struct lttng_rotation_schedule *schedule)
+{
+       enum cmd_error_code ret;
+       enum lttng_rotation_status status;
+       uint64_t value;
+
+       status = lttng_rotation_schedule_periodic_get_period(schedule,
+                       &value);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               ERR("Failed to retrieve period parameter from periodic rotation schedule.");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       MSG("    timer period: %" PRIu64" %s", value, USEC_UNIT);
+       ret = CMD_SUCCESS;
+end:
+       return ret;
+}
+
+static enum cmd_error_code print_size_threshold_rotation_schedule(
+               const struct lttng_rotation_schedule *schedule)
+{
+       enum cmd_error_code ret;
+       enum lttng_rotation_status status;
+       uint64_t value;
+
+       status = lttng_rotation_schedule_size_threshold_get_threshold(schedule,
+                       &value);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               ERR("Failed to retrieve size parameter from size-based rotation schedule.");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       MSG("    size threshold: %" PRIu64" bytes", value);
+       ret = CMD_SUCCESS;
+end:
+       return ret;
+}
+
+static enum cmd_error_code print_rotation_schedule(
+               const struct lttng_rotation_schedule *schedule)
+{
+       enum cmd_error_code ret;
+
+       switch (lttng_rotation_schedule_get_type(schedule)) {
+       case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD:
+               ret = print_size_threshold_rotation_schedule(schedule);
+               break;
+       case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC:
+               ret = print_periodic_rotation_schedule(schedule);
+               break;
+       default:
+               ret = CMD_ERROR;
+       }
+       return ret;
+}
+
+/*
+ * List the automatic rotation settings.
+ */
+static enum cmd_error_code list_rotate_settings(const char *session_name)
+{
+       int ret;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       unsigned int count, i;
+       struct lttng_rotation_schedules *schedules = NULL;
+       enum lttng_rotation_status status;
+
+       ret = lttng_session_list_rotation_schedules(session_name, &schedules);
+       if (ret != LTTNG_OK) {
+               ERR("Failed to list session rotation schedules: %s", lttng_strerror(ret));
+               cmd_ret = CMD_ERROR;
+               goto end;
+       }
+
+       status = lttng_rotation_schedules_get_count(schedules, &count);
+       if (status != LTTNG_ROTATION_STATUS_OK) {
+               ERR("Failed to retrieve the number of session rotation schedules.");
+               cmd_ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (count == 0) {
+               cmd_ret = CMD_SUCCESS;
+               goto end;
+       }
+
+       MSG("Automatic rotation schedules:");
+       if (lttng_opt_mi) {
+               ret = mi_lttng_writer_open_element(the_writer,
+                               mi_lttng_element_rotation_schedules);
+               if (ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       for (i = 0; i < count; i++) {
+               enum cmd_error_code tmp_ret = CMD_SUCCESS;
+               const struct lttng_rotation_schedule *schedule;
+
+               schedule = lttng_rotation_schedules_get_at_index(schedules, i);
+               if (!schedule) {
+                       ERR("Failed to retrieve session rotation schedule.");
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               if (lttng_opt_mi) {
+                       ret = mi_lttng_rotation_schedule(the_writer, schedule);
+                       if (ret) {
+                               tmp_ret = CMD_ERROR;
+                       }
+               } else {
+                       tmp_ret = print_rotation_schedule(schedule);
+               }
+
+               /*
+                * Report an error if the serialization of any of the
+                * descriptors failed.
+                */
+               cmd_ret = cmd_ret ? cmd_ret : tmp_ret;
+       }
+
+       _MSG("\n");
+       if (lttng_opt_mi) {
+               /* Close the rotation_schedules element. */
+               ret = mi_lttng_writer_close_element(the_writer);
+               if (ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+end:
+       lttng_rotation_schedules_destroy(schedules);
+       return cmd_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(the_writer, &sessions[i], 1);
+                       if (ret) {
+                               goto end;
+                       }
+                       break;
+               }
+       }
+
+       if (!session_found) {
+               ERR("Session '%s' not found", session_name);
+               ret = -LTTNG_ERR_SESS_NOT_FOUND;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Machine interface
+ * List all availables session
+ */
+static int mi_list_sessions(struct lttng_session *sessions, int count)
+{
+       int ret, i;
+
+       /* Opening sessions element */
+       ret = mi_lttng_sessions_open(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Listing sessions */
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_session(the_writer, &sessions[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Closing sessions element */
+       ret = mi_lttng_writer_close_element(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * List available tracing session. List only basic information.
+ *
+ * If session_name is NULL, all sessions are listed.
+ */
+static int list_sessions(const char *session_name)
+{
+       int ret = CMD_SUCCESS;
+       int count, i;
+       unsigned int session_found = 0;
+       struct lttng_session *sessions = NULL;
+
+       count = lttng_list_sessions(&sessions);
+       DBG("Session count %d", count);
+       if (count < 0) {
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
+               goto end;
+       }
+
+       if (lttng_opt_mi) {
+               /* Mi */
+               if (session_name == NULL) {
+                       /* List all sessions */
+                       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 end;
+               }
+       } else {
+               /* Pretty print */
+               if (count == 0) {
+                       MSG("Currently no available recording session");
+                       goto end;
+               }
+
+               if (session_name == NULL) {
+                       MSG("Available recording 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("Recording session %s: [%s%s]", session_name,
+                                                       active_string(sessions[i].enabled),
+                                                       snapshot_string(sessions[i].snapshot_mode));
+                                       if (*sessions[i].path) {
+                                               MSG("%sTrace output: %s\n", indent4, sessions[i].path);
+                                       }
+                                       memcpy(&the_listed_session,
+                                                       &sessions[i],
+                                                       sizeof(the_listed_session));
+                                       break;
+                               }
+                       } else {
+                               MSG("  %d) %s [%s%s]", i + 1,
+                                               sessions[i].name,
+                                               active_string(sessions[i].enabled),
+                                               snapshot_string(sessions[i].snapshot_mode));
+                               if (*sessions[i].path) {
+                                       MSG("%sTrace output: %s", indent4, sessions[i].path);
+                               }
+                               if (sessions[i].live_timer_interval != 0) {
+                                       MSG("%sLive timer interval: %u %s", indent4,
+                                                       sessions[i].live_timer_interval,
+                                                       USEC_UNIT);
+                               }
+                               MSG("");
+                       }
+               }
+
+               if (!session_found && session_name != NULL) {
+                       ERR("Session '%s' not found", session_name);
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               if (session_name == NULL) {
+                       MSG("\nUse lttng list <session_name> for more details");
+               }
+       }
+
+end:
+       free(sessions);
+       return ret;
+}
+
+
+/*
+ * 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(the_writer);
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               ret = mi_lttng_domain(the_writer, &domains[i], 0);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Closing domains element */
+       ret = mi_lttng_writer_close_element(the_writer);
+       if (ret) {
+               goto end;
+       }
+end:
+       return ret;
+}
+
+/*
+ * List available domain(s) for a session.
+ */
+static int list_domains(const char *session_name)
+{
+       int i, count, ret = CMD_SUCCESS;
+       struct lttng_domain *domains = NULL;
+
+
+       count = lttng_list_domains(session_name, &domains);
+       if (count < 0) {
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
+               goto end;
+       }
+
+       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;
+                       case LTTNG_DOMAIN_LOG4J:
+                               MSG("  - LOG4j (Logging for Java)");
+                               break;
+                       case LTTNG_DOMAIN_PYTHON:
+                               MSG("  - Python (logging)");
+                               break;
+                       default:
+                               break;
+                       }
+               }
+       }
+
+error:
+       free(domains);
+
+end:
+       return ret;
+}
+
+/*
+ * The 'list <options>' first level command
+ */
+int cmd_list(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS;
+       const char *session_name, *leftover = NULL;
+       static poptContext pc;
+       struct lttng_domain domain;
+       struct lttng_domain *domains = NULL;
+
+       memset(&domain, 0, sizeof(domain));
+
+       if (argc < 1) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_USERSPACE:
+                       opt_userspace = 1;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               the_writer = mi_lttng_writer_create(
+                               fileno(stdout), lttng_opt_mi);
+               if (!the_writer) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(
+                               the_writer, mi_lttng_element_command_list);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(
+                               the_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);
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (opt_kernel) {
+               domain.type = LTTNG_DOMAIN_KERNEL;
+       } else if (opt_userspace) {
+               DBG2("Listing userspace global domain");
+               domain.type = LTTNG_DOMAIN_UST;
+       } else if (opt_jul) {
+               DBG2("Listing JUL domain");
+               domain.type = LTTNG_DOMAIN_JUL;
+       } else if (opt_log4j) {
+               domain.type = LTTNG_DOMAIN_LOG4J;
+       } else if (opt_python) {
+               domain.type = LTTNG_DOMAIN_PYTHON;
+       }
+
+       if (!opt_kernel && opt_syscall) {
+               WARN("--syscall will only work with the Kernel domain (-k)");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (opt_kernel || opt_userspace || opt_jul || opt_log4j || opt_python) {
+               the_handle = lttng_create_handle(session_name, &domain);
+               if (the_handle == NULL) {
+                       ret = CMD_FATAL;
+                       goto end;
+               }
+       }
+
+       if (session_name == NULL) {
+               if (!opt_kernel && !opt_userspace && !opt_jul && !opt_log4j
+                               && !opt_python) {
+                       ret = list_sessions(NULL);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               if (opt_kernel) {
+                       if (opt_syscall) {
+                               ret = list_syscalls();
+                               if (ret) {
+                                       goto end;
+                               }
+                       } else {
+                               ret = list_kernel_events();
+                               if (ret) {
+                                       goto end;
+                               }
+                       }
+               }
+               if (opt_userspace) {
+                       if (opt_fields) {
+                               ret = list_ust_event_fields();
+                       } else {
+                               ret = list_ust_events();
+                       }
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               if (opt_jul || opt_log4j || opt_python) {
+                       ret = list_agent_events();
+                       if (ret) {
+                               goto end;
+                       }
+               }
+       } else {
+               /* List session attributes */
+               if (lttng_opt_mi) {
+                       /* Open element sessions
+                        * Present for xml consistency */
+                       ret = mi_lttng_sessions_open(the_writer);
+                       if (ret) {
+                               goto end;
+                       }
+               }
+               /* MI: the ouptut of list_sessions is an unclosed session element */
+               ret = list_sessions(session_name);
+               if (ret) {
+                       goto end;
+               }
+
+               ret = list_rotate_settings(session_name);
+               if (ret) {
+                       goto end;
+               }
+
+               /* Domain listing */
+               if (opt_domain) {
+                       ret = list_domains(session_name);
+                       goto end;
+               }
+
+               /* Channel listing */
+               if (opt_kernel || opt_userspace) {
+                       if (lttng_opt_mi) {
+                               /* Add of domains and domain element for xml
+                                * consistency and validation
+                                */
+                               ret = mi_lttng_domains_open(the_writer);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                               /* Open domain and leave it open for
+                                * nested channels printing */
+                               ret = mi_lttng_domain(the_writer, &domain, 1);
+                               if (ret) {
+                                       goto end;
+                               }
+
+                       }
+
+
+                       /* Trackers */
+                       ret = list_trackers(&domain);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       /* Channels */
+                       ret = list_channels(opt_channel);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       if (lttng_opt_mi) {
+                               /* Close domain and domain element */
+                               ret = mi_lttng_close_multi_element(
+                                               the_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 = CMD_ERROR;
+                               ERR("%s", lttng_strerror(nb_domain));
+                               goto end;
+                       }
+
+                       if (lttng_opt_mi) {
+                               ret = mi_lttng_domains_open(the_writer);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+
+                       for (i = 0; i < nb_domain; i++) {
+                               switch (domains[i].type) {
+                               case LTTNG_DOMAIN_KERNEL:
+                                       MSG("=== Domain: Linux kernel ===\n");
+                                       break;
+                               case LTTNG_DOMAIN_UST:
+                                       MSG("=== Domain: User space ===\n");
+                                       MSG("Buffering scheme: %s\n",
+                                                       domains[i].buf_type ==
+                                                       LTTNG_BUFFER_PER_PID ? "per-process" : "per-user");
+                                       break;
+                               case LTTNG_DOMAIN_JUL:
+                                       MSG("=== Domain: java.util.logging (JUL) ===\n");
+                                       break;
+                               case LTTNG_DOMAIN_LOG4J:
+                                       MSG("=== Domain: log4j ===\n");
+                                       break;
+                               case LTTNG_DOMAIN_PYTHON:
+                                       MSG("=== Domain: Python logging ===\n");
+                                       break;
+                               default:
+                                       MSG("=== Domain: Unimplemented ===\n");
+                                       break;
+                               }
+
+                               if (lttng_opt_mi) {
+                                       ret = mi_lttng_domain(the_writer,
+                                                       &domains[i], 1);
+                                       if (ret) {
+                                               ret = CMD_ERROR;
+                                               goto end;
+                                       }
+                               }
+
+                               /* Clean handle before creating a new one */
+                               if (the_handle) {
+                                       lttng_destroy_handle(the_handle);
+                               }
+
+                               the_handle = lttng_create_handle(
+                                               session_name, &domains[i]);
+                               if (the_handle == NULL) {
+                                       ret = CMD_FATAL;
+                                       goto end;
+                               }
+
+                               if (domains[i].type == LTTNG_DOMAIN_JUL ||
+                                               domains[i].type == LTTNG_DOMAIN_LOG4J ||
+                                               domains[i].type == LTTNG_DOMAIN_PYTHON) {
+                                       ret = list_session_agent_events();
+                                       if (ret) {
+                                               goto end;
+                                       }
+
+                                       goto next_domain;
+                               }
+
+                               switch (domains[i].type) {
+                               case LTTNG_DOMAIN_KERNEL:
+                               case LTTNG_DOMAIN_UST:
+                                       ret = list_trackers(&domains[i]);
+                                       if (ret) {
+                                               goto end;
+                                       }
+                                       break;
+                               default:
+                                       break;
+                               }
+
+                               ret = list_channels(opt_channel);
+                               if (ret) {
+                                       goto end;
+                               }
+
+next_domain:
+                               if (lttng_opt_mi) {
+                                       /* Close domain element */
+                                       ret = mi_lttng_writer_close_element(
+                                                       the_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(
+                                               the_writer, 3);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+               }
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(the_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(the_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+end:
+       /* Mi clean-up */
+       if (the_writer && mi_lttng_writer_destroy(the_writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
+       }
+
+       free(domains);
+       if (the_handle) {
+               lttng_destroy_handle(the_handle);
+       }
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/list_triggers.c b/src/bin/lttng/commands/list_triggers.c
deleted file mode 100644 (file)
index 50c5894..0000000
+++ /dev/null
@@ -1,1449 +0,0 @@
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include <stdio.h>
-
-#include "../command.h"
-
-#include "common/argpar/argpar.h"
-#include "common/dynamic-array.h"
-#include "common/mi-lttng.h"
-/* For lttng_condition_type_str(). */
-#include "lttng/condition/condition-internal.h"
-#include "lttng/condition/event-rule-matches.h"
-#include "lttng/condition/event-rule-matches-internal.h"
-/* For lttng_domain_type_str(). */
-#include "lttng/domain-internal.h"
-/* For lttng_event_rule_kernel_syscall_emission_site_str() */
-#include "lttng/event-rule/kernel-syscall-internal.h"
-#include "../loglevel.h"
-#include <lttng/lttng.h>
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-list-triggers.1.h>
-;
-#endif
-
-#define INDENTATION_LEVEL_STR "  "
-
-typedef enum lttng_event_rule_status (*event_rule_logging_get_name_pattern)(
-               const struct lttng_event_rule *rule, const char **pattern);
-typedef enum lttng_event_rule_status (*event_rule_logging_get_filter)(
-               const struct lttng_event_rule *rule, const char **expression);
-typedef enum lttng_event_rule_status (*event_rule_logging_get_log_level_rule)(
-               const struct lttng_event_rule *rule,
-               const struct lttng_log_level_rule **log_level_rule);
-
-enum {
-       OPT_HELP,
-       OPT_LIST_OPTIONS,
-};
-
-static const
-struct argpar_opt_descr list_trigger_options[] = {
-       { OPT_HELP, 'h', "help", false },
-       { OPT_LIST_OPTIONS, '\0', "list-options", false },
-       ARGPAR_OPT_DESCR_SENTINEL,
-};
-
-static void print_condition_session_consumed_size(
-               const struct lttng_condition *condition)
-{
-       enum lttng_condition_status condition_status;
-       const char *session_name;
-       uint64_t threshold;
-
-       condition_status =
-                       lttng_condition_session_consumed_size_get_session_name(
-                                       condition, &session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       lttng_condition_session_consumed_size_get_threshold(
-                       condition, &threshold);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       MSG("    session name: %s", session_name);
-       MSG("    threshold: %" PRIu64 " bytes", threshold);
-}
-
-static void print_condition_buffer_usage(
-               const struct lttng_condition *condition)
-{
-       enum lttng_condition_status condition_status;
-       const char *session_name, *channel_name;
-       enum lttng_domain_type domain_type;
-       uint64_t threshold;
-
-       condition_status = lttng_condition_buffer_usage_get_session_name(
-                       condition, &session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       condition_status = lttng_condition_buffer_usage_get_channel_name(
-                       condition, &channel_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       condition_status = lttng_condition_buffer_usage_get_domain_type(
-                       condition, &domain_type);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       MSG("    session name: %s", session_name);
-       MSG("    channel name: %s", channel_name);
-       MSG("    domain: %s", lttng_domain_type_str(domain_type));
-
-       condition_status = lttng_condition_buffer_usage_get_threshold(
-                       condition, &threshold);
-       if (condition_status == LTTNG_CONDITION_STATUS_OK) {
-               MSG("    threshold (bytes): %" PRIu64, threshold);
-       } else {
-               double threshold_ratio;
-
-               LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_UNSET);
-
-               condition_status =
-                               lttng_condition_buffer_usage_get_threshold_ratio(
-                                               condition, &threshold_ratio);
-               LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-               MSG("    threshold (ratio): %.2f", threshold_ratio);
-       }
-}
-
-static void print_condition_session_rotation(
-               const struct lttng_condition *condition)
-{
-       enum lttng_condition_status condition_status;
-       const char *session_name;
-
-       condition_status = lttng_condition_session_rotation_get_session_name(
-                       condition, &session_name);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       MSG("    session name: %s", session_name);
-}
-
-/*
- * Returns the human-readable log level name associated with a numerical value
- * if there is one. The Log4j and JUL event rule have discontinuous log level
- * values (a value can fall between two labels). In those cases, NULL is
- * returned.
- */
-static const char *get_pretty_loglevel_name(
-               enum lttng_event_rule_type event_rule_type, int loglevel)
-{
-       const char *name = NULL;
-
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-               name = loglevel_value_to_name(loglevel);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-               name = loglevel_log4j_value_to_name(loglevel);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-               name = loglevel_jul_value_to_name(loglevel);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-               name = loglevel_python_value_to_name(loglevel);
-               break;
-       default:
-               break;
-       }
-
-       return name;
-}
-
-static
-void print_event_rule_user_tracepoint(const struct lttng_event_rule *event_rule)
-{
-       enum lttng_event_rule_status event_rule_status;
-       const char *pattern;
-       const char *filter;
-       int log_level;
-       const struct lttng_log_level_rule *log_level_rule = NULL;
-       unsigned int exclusions_count;
-       int i;
-
-       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern(
-                       event_rule, &pattern);
-       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-       _MSG("    rule: %s (type: user tracepoint", pattern);
-
-       event_rule_status = lttng_event_rule_user_tracepoint_get_filter(
-                       event_rule, &filter);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               _MSG(", filter: %s", filter);
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       event_rule_status = lttng_event_rule_user_tracepoint_get_log_level_rule(
-                       event_rule, &log_level_rule);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               enum lttng_log_level_rule_status llr_status;
-               const char *log_level_op;
-               const char *pretty_loglevel_name;
-
-               switch (lttng_log_level_rule_get_type(log_level_rule)) {
-               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
-                       log_level_op = "is";
-                       llr_status = lttng_log_level_rule_exactly_get_level(
-                                       log_level_rule, &log_level);
-                       break;
-               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
-                       log_level_op = "at least";
-                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
-                                       log_level_rule, &log_level);
-                       break;
-               default:
-                       abort();
-               }
-
-               LTTNG_ASSERT(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
-
-               pretty_loglevel_name = get_pretty_loglevel_name(
-                               LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT, log_level);
-               if (pretty_loglevel_name) {
-                       _MSG(", log level %s %s", log_level_op,
-                                       pretty_loglevel_name);
-               } else {
-                       _MSG(", log level %s %d", log_level_op, log_level);
-               }
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(
-                       event_rule, &exclusions_count);
-       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-       if (exclusions_count > 0) {
-               _MSG(", exclusions: ");
-               for (i = 0; i < exclusions_count; i++) {
-                       const char *exclusion;
-
-                       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index(
-                                       event_rule, i, &exclusion);
-                       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-                       _MSG("%s%s", i > 0 ? "," : "", exclusion);
-               }
-       }
-
-       MSG(")");
-}
-
-static
-void print_event_rule_kernel_tracepoint(const struct lttng_event_rule *event_rule)
-{
-       enum lttng_event_rule_status event_rule_status;
-       const char *pattern;
-       const char *filter;
-
-       event_rule_status = lttng_event_rule_kernel_tracepoint_get_name_pattern(
-                       event_rule, &pattern);
-       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-       _MSG("    rule: %s (type: kernel tracepoint", pattern);
-
-       event_rule_status = lttng_event_rule_kernel_tracepoint_get_filter(
-                       event_rule, &filter);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               _MSG(", filter: %s", filter);
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       MSG(")");
-}
-
-static
-void print_event_rule_logging(const struct lttng_event_rule *event_rule)
-{
-       enum lttng_event_rule_status event_rule_status;
-       enum lttng_event_rule_type event_rule_type = lttng_event_rule_get_type(event_rule);
-       const char *pattern;
-       const char *filter;
-       int log_level;
-       const struct lttng_log_level_rule *log_level_rule = NULL;
-       const char *type_str = NULL;
-
-       event_rule_logging_get_name_pattern logging_get_name_pattern;
-       event_rule_logging_get_filter logging_get_filter;
-       event_rule_logging_get_log_level_rule logging_get_log_level_rule;
-
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-               logging_get_name_pattern =
-                               lttng_event_rule_jul_logging_get_name_pattern;
-               logging_get_filter = lttng_event_rule_jul_logging_get_filter;
-               logging_get_log_level_rule =
-                               lttng_event_rule_jul_logging_get_log_level_rule;
-               type_str = "jul";
-               break;
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-               logging_get_name_pattern =
-                               lttng_event_rule_log4j_logging_get_name_pattern;
-               logging_get_filter = lttng_event_rule_log4j_logging_get_filter;
-               logging_get_log_level_rule =
-                               lttng_event_rule_log4j_logging_get_log_level_rule;
-               type_str = "log4j";
-               break;
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-               logging_get_name_pattern =
-                               lttng_event_rule_python_logging_get_name_pattern;
-               logging_get_filter = lttng_event_rule_python_logging_get_filter;
-               logging_get_log_level_rule =
-                               lttng_event_rule_python_logging_get_log_level_rule;
-               type_str = "python";
-               break;
-       default:
-               abort();
-               break;
-       }
-
-       event_rule_status = logging_get_name_pattern(
-                       event_rule, &pattern);
-       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-       _MSG("    rule: %s (type: %s:logging", pattern, type_str);
-
-       event_rule_status = logging_get_filter(
-                       event_rule, &filter);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               _MSG(", filter: %s", filter);
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       event_rule_status = logging_get_log_level_rule(
-                       event_rule, &log_level_rule);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               enum lttng_log_level_rule_status llr_status;
-               const char *log_level_op;
-               const char *pretty_loglevel_name;
-
-               switch (lttng_log_level_rule_get_type(log_level_rule)) {
-               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
-                       log_level_op = "is";
-                       llr_status = lttng_log_level_rule_exactly_get_level(
-                                       log_level_rule, &log_level);
-                       break;
-               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
-                       log_level_op = "at least";
-                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
-                                       log_level_rule, &log_level);
-                       break;
-               default:
-                       abort();
-               }
-
-               LTTNG_ASSERT(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
-
-               pretty_loglevel_name = get_pretty_loglevel_name(
-                               event_rule_type, log_level);
-               if (pretty_loglevel_name) {
-                       _MSG(", log level %s %s", log_level_op,
-                                       pretty_loglevel_name);
-               } else {
-                       _MSG(", log level %s %d", log_level_op, log_level);
-               }
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       MSG(")");
-}
-
-static void print_kernel_probe_location(
-               const struct lttng_kernel_probe_location *location)
-{
-       enum lttng_kernel_probe_location_status status;
-       switch (lttng_kernel_probe_location_get_type(location)) {
-       case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
-       {
-               uint64_t address;
-
-               status = lttng_kernel_probe_location_address_get_address(
-                               location, &address);
-               if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
-                       ERR("Getting kernel probe location address failed.");
-                       goto end;
-               }
-
-               _MSG("0x%" PRIx64, address);
-
-               break;
-       }
-       case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
-       {
-               uint64_t offset;
-               const char *symbol_name;
-
-               symbol_name = lttng_kernel_probe_location_symbol_get_name(
-                               location);
-               if (!symbol_name) {
-                       ERR("Getting kernel probe location symbol name failed.");
-                       goto end;
-               }
-
-               status = lttng_kernel_probe_location_symbol_get_offset(
-                               location, &offset);
-               if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
-                       ERR("Getting kernel probe location address failed.");
-                       goto end;
-               }
-
-               if (offset == 0) {
-                       _MSG("%s", symbol_name);
-               } else {
-                       _MSG("%s+0x%" PRIx64, symbol_name, offset);
-               }
-
-               break;
-       }
-       default:
-               abort();
-       };
-end:
-       return;
-}
-
-static
-void print_event_rule_kernel_probe(const struct lttng_event_rule *event_rule)
-{
-       enum lttng_event_rule_status event_rule_status;
-       const char *name;
-       const struct lttng_kernel_probe_location *location;
-
-       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE);
-
-       event_rule_status = lttng_event_rule_kernel_kprobe_get_event_name(event_rule, &name);
-       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to get kprobe event rule's name.");
-               goto end;
-       }
-
-       event_rule_status = lttng_event_rule_kernel_kprobe_get_location(
-                       event_rule, &location);
-       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to get kprobe event rule's location.");
-               goto end;
-       }
-
-       _MSG("    rule: %s (type: kernel:kprobe, location: ", name);
-
-       print_kernel_probe_location(location);
-
-       MSG(")");
-
-end:
-       return;
-}
-
-static
-void print_event_rule_userspace_probe(const struct lttng_event_rule *event_rule)
-{
-       enum lttng_event_rule_status event_rule_status;
-       const char *name;
-       const struct lttng_userspace_probe_location *location;
-       enum lttng_userspace_probe_location_type userspace_probe_location_type;
-
-       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
-
-       event_rule_status = lttng_event_rule_kernel_uprobe_get_event_name(
-                       event_rule, &name);
-       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to get uprobe event rule's name.");
-               goto end;
-       }
-
-       event_rule_status = lttng_event_rule_kernel_uprobe_get_location(
-                       event_rule, &location);
-       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
-               ERR("Failed to get uprobe event rule's location.");
-               goto end;
-       }
-
-       _MSG("    rule: %s (type: kernel:uprobe, ", name);
-
-       userspace_probe_location_type =
-                       lttng_userspace_probe_location_get_type(location);
-
-       switch (userspace_probe_location_type) {
-       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
-       {
-               const char *binary_path, *function_name;
-
-               binary_path = lttng_userspace_probe_location_function_get_binary_path(
-                               location);
-               function_name = lttng_userspace_probe_location_function_get_function_name(
-                               location);
-
-               _MSG("location type: ELF, location: %s:%s", binary_path, function_name);
-               break;
-       }
-       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
-       {
-               const char *binary_path, *provider_name, *probe_name;
-
-               binary_path = lttng_userspace_probe_location_tracepoint_get_binary_path(
-                               location);
-               provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(
-                               location);
-               probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(
-                               location);
-               _MSG("location type: SDT, location: %s:%s:%s", binary_path, provider_name, probe_name);
-               break;
-       }
-       default:
-               abort();
-       }
-
-       MSG(")");
-
-end:
-       return;
-}
-
-static
-void print_event_rule_syscall(const struct lttng_event_rule *event_rule)
-{
-       const char *pattern, *filter;
-       enum lttng_event_rule_status event_rule_status;
-       enum lttng_event_rule_kernel_syscall_emission_site emission_site;
-
-       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL);
-
-       emission_site =
-               lttng_event_rule_kernel_syscall_get_emission_site(event_rule);
-
-       event_rule_status = lttng_event_rule_kernel_syscall_get_name_pattern(
-                       event_rule, &pattern);
-       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
-
-       _MSG("    rule: %s (type: kernel:syscall:%s", pattern,
-                       lttng_event_rule_kernel_syscall_emission_site_str(
-                                       emission_site));
-
-       event_rule_status = lttng_event_rule_kernel_syscall_get_filter(
-                       event_rule, &filter);
-       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
-               _MSG(", filter: %s", filter);
-       } else {
-               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
-       }
-
-       MSG(")");
-}
-
-static
-void print_event_rule(const struct lttng_event_rule *event_rule)
-{
-       const enum lttng_event_rule_type event_rule_type =
-                       lttng_event_rule_get_type(event_rule);
-
-       switch (event_rule_type) {
-       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
-               print_event_rule_user_tracepoint(event_rule);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
-               print_event_rule_kernel_tracepoint(event_rule);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
-       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
-       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
-               print_event_rule_logging(event_rule);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
-               print_event_rule_kernel_probe(event_rule);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
-               print_event_rule_userspace_probe(event_rule);
-               break;
-       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
-               print_event_rule_syscall(event_rule);
-               break;
-       default:
-               abort();
-       }
-}
-
-static
-void print_one_event_expr(const struct lttng_event_expr *event_expr)
-{
-       enum lttng_event_expr_type type;
-
-       type = lttng_event_expr_get_type(event_expr);
-
-       switch (type) {
-       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
-       {
-               const char *name;
-
-               name = lttng_event_expr_event_payload_field_get_name(
-                               event_expr);
-               _MSG("%s", name);
-
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
-       {
-               const char *name;
-
-               name = lttng_event_expr_channel_context_field_get_name(
-                               event_expr);
-               _MSG("$ctx.%s", name);
-
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
-       {
-               const char *provider_name;
-               const char *type_name;
-
-               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
-                               event_expr);
-               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
-                               event_expr);
-
-               _MSG("$app.%s:%s", provider_name, type_name);
-
-               break;
-       }
-       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
-       {
-               unsigned int index;
-               const struct lttng_event_expr *parent_expr;
-               enum lttng_event_expr_status status;
-
-               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
-                               event_expr);
-               LTTNG_ASSERT(parent_expr != NULL);
-
-               print_one_event_expr(parent_expr);
-
-               status = lttng_event_expr_array_field_element_get_index(
-                               event_expr, &index);
-               LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
-
-               _MSG("[%u]", index);
-
-               break;
-       }
-       default:
-               abort();
-       }
-}
-
-static
-void print_indentation(unsigned int indentation_level)
-{
-       unsigned int i;
-
-       for (i = 0; i < indentation_level; i++) {
-               _MSG(INDENTATION_LEVEL_STR);
-       }
-}
-
-static
-void print_error_query_results(struct lttng_error_query_results *results,
-               unsigned int base_indentation_level)
-{
-       unsigned int i, count, printed_errors_count = 0;
-       enum lttng_error_query_results_status results_status;
-
-       results_status = lttng_error_query_results_get_count(results, &count);
-       LTTNG_ASSERT(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
-
-       LTTNG_ASSERT(results);
-
-       print_indentation(base_indentation_level);
-       _MSG("errors:");
-
-       for (i = 0; i < count; i++) {
-               const struct lttng_error_query_result *result;
-               enum lttng_error_query_result_status result_status;
-               const char *result_name;
-               const char *result_description;
-               uint64_t result_value;
-
-               results_status = lttng_error_query_results_get_result(
-                               results, &result, i);
-               LTTNG_ASSERT(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
-
-               result_status = lttng_error_query_result_get_name(
-                               result, &result_name);
-               LTTNG_ASSERT(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
-               result_status = lttng_error_query_result_get_description(
-                               result, &result_description);
-               LTTNG_ASSERT(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
-
-
-               if (lttng_error_query_result_get_type(result) ==
-                               LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER) {
-                       result_status = lttng_error_query_result_counter_get_value(
-                                       result, &result_value);
-                       LTTNG_ASSERT(result_status ==
-                                       LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
-                       if (result_value == 0) {
-                               continue;
-                       }
-
-                       MSG("");
-                       print_indentation(base_indentation_level + 1);
-
-                       _MSG("%s: %" PRIu64, result_name, result_value);
-                       printed_errors_count++;
-               } else {
-                       MSG("");
-                       print_indentation(base_indentation_level + 1);
-                       _MSG("Unknown error query result type for result '%s' (%s)",
-                                       result_name, result_description);
-                       continue;
-               }
-       }
-
-       if (printed_errors_count == 0) {
-               _MSG(" none");
-       }
-}
-
-static void print_condition_event_rule_matches(
-               const struct lttng_condition *condition)
-{
-       const struct lttng_event_rule *event_rule;
-       enum lttng_condition_status condition_status;
-       unsigned int cap_desc_count, i;
-
-       condition_status = lttng_condition_event_rule_matches_get_rule(
-                       condition, &event_rule);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       print_event_rule(event_rule);
-
-       condition_status =
-                       lttng_condition_event_rule_matches_get_capture_descriptor_count(
-                                       condition, &cap_desc_count);
-       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
-
-       if (cap_desc_count > 0) {
-               MSG("    captures:");
-
-               for (i = 0; i < cap_desc_count; i++) {
-                       const struct lttng_event_expr *cap_desc =
-                                       lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
-                                                       condition, i);
-
-                       _MSG("      - ");
-                       print_one_event_expr(cap_desc);
-                       MSG("");
-               }
-       }
-}
-
-static void print_action_errors(const struct lttng_trigger *trigger,
-               const struct lttng_action *action,
-               const uint64_t *action_path_indexes,
-               size_t action_path_length)
-{
-       enum lttng_error_code error_query_ret;
-       struct lttng_error_query_results *results = NULL;
-       const char *trigger_name;
-       uid_t trigger_uid;
-       enum lttng_trigger_status trigger_status;
-       struct lttng_error_query *query;
-       struct lttng_action_path *action_path = lttng_action_path_create(
-                       action_path_indexes, action_path_length);
-
-       LTTNG_ASSERT(action_path);
-
-       query = lttng_error_query_action_create(trigger, action_path);
-       LTTNG_ASSERT(query);
-
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       /*
-        * Anonymous triggers are not listed; this would be an internal error.
-        */
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       error_query_ret = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, &results);
-       if (error_query_ret != LTTNG_OK) {
-               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-error_query_ret));
-               goto end;
-       }
-
-       print_error_query_results(results, 3);
-
-end:
-       MSG("");
-       lttng_error_query_destroy(query);
-       lttng_error_query_results_destroy(results);
-       lttng_action_path_destroy(action_path);
-}
-
-static
-void print_one_action(const struct lttng_trigger *trigger,
-               const struct lttng_action *action,
-               const uint64_t *action_path_indexes,
-               size_t action_path_length)
-{
-       enum lttng_action_type action_type;
-       enum lttng_action_status action_status;
-       const struct lttng_rate_policy *policy = NULL;
-       const char *value;
-
-       action_type = lttng_action_get_type(action);
-       LTTNG_ASSERT(action_type != LTTNG_ACTION_TYPE_LIST);
-
-       switch (action_type) {
-       case LTTNG_ACTION_TYPE_NOTIFY:
-               _MSG("notify");
-
-               action_status = lttng_action_notify_get_rate_policy(
-                               action, &policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to retrieve rate policy.");
-                       goto end;
-               }
-               break;
-       case LTTNG_ACTION_TYPE_START_SESSION:
-               action_status = lttng_action_start_session_get_session_name(
-                               action, &value);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-               _MSG("start session `%s`", value);
-
-               action_status = lttng_action_start_session_get_rate_policy(
-                               action, &policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to retrieve rate policy.");
-                       goto end;
-               }
-               break;
-       case LTTNG_ACTION_TYPE_STOP_SESSION:
-               action_status = lttng_action_stop_session_get_session_name(
-                               action, &value);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-               _MSG("stop session `%s`", value);
-
-               action_status = lttng_action_stop_session_get_rate_policy(
-                               action, &policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to retrieve rate policy.");
-                       goto end;
-               }
-               break;
-       case LTTNG_ACTION_TYPE_ROTATE_SESSION:
-               action_status = lttng_action_rotate_session_get_session_name(
-                               action, &value);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-               _MSG("rotate session `%s`", value);
-
-               action_status = lttng_action_rotate_session_get_rate_policy(
-                               action, &policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to retrieve rate policy.");
-                       goto end;
-               }
-               break;
-       case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
-       {
-               const struct lttng_snapshot_output *output;
-
-               action_status = lttng_action_snapshot_session_get_session_name(
-                               action, &value);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-               _MSG("snapshot session `%s`", value);
-
-               action_status = lttng_action_snapshot_session_get_output(
-                               action, &output);
-               if (action_status == LTTNG_ACTION_STATUS_OK) {
-                       const char *name;
-                       uint64_t max_size;
-                       const char *ctrl_url, *data_url;
-                       bool starts_with_file, starts_with_net, starts_with_net6;
-
-                       ctrl_url = lttng_snapshot_output_get_ctrl_url(output);
-                       LTTNG_ASSERT(ctrl_url && strlen(ctrl_url) > 0);
-
-                       data_url = lttng_snapshot_output_get_data_url(output);
-                       LTTNG_ASSERT(data_url);
-
-                       starts_with_file = strncmp(ctrl_url, "file://", strlen("file://")) == 0;
-                       starts_with_net = strncmp(ctrl_url, "net://", strlen("net://")) == 0;
-                       starts_with_net6 = strncmp(ctrl_url, "net6://", strlen("net6://")) == 0;
-
-                       if (ctrl_url[0] == '/' || starts_with_file) {
-                               if (starts_with_file) {
-                                       ctrl_url += strlen("file://");
-                               }
-
-                               _MSG(", path: %s", ctrl_url);
-                       } else if (starts_with_net || starts_with_net6) {
-                               _MSG(", url: %s", ctrl_url);
-                       } else {
-                               LTTNG_ASSERT(strlen(data_url) > 0);
-
-                               _MSG(", control url: %s, data url: %s", ctrl_url, data_url);
-                       }
-
-                       name = lttng_snapshot_output_get_name(output);
-                       LTTNG_ASSERT(name);
-                       if (strlen(name) > 0) {
-                               _MSG(", name: %s", name);
-                       }
-
-                       max_size = lttng_snapshot_output_get_maxsize(output);
-                       if (max_size != -1ULL) {
-                               _MSG(", max size: %" PRIu64, max_size);
-                       }
-               }
-
-               action_status = lttng_action_snapshot_session_get_rate_policy(
-                               action, &policy);
-               if (action_status != LTTNG_ACTION_STATUS_OK) {
-                       ERR("Failed to retrieve rate policy.");
-                       goto end;
-               }
-               break;
-       }
-       default:
-               abort();
-       }
-
-       if (policy) {
-               enum lttng_rate_policy_type policy_type;
-               enum lttng_rate_policy_status policy_status;
-               uint64_t policy_value = 0;
-
-               policy_type = lttng_rate_policy_get_type(policy);
-
-               switch (policy_type) {
-               case LTTNG_RATE_POLICY_TYPE_EVERY_N:
-                       policy_status = lttng_rate_policy_every_n_get_interval(
-                                       policy, &policy_value);
-                       if (policy_status != LTTNG_RATE_POLICY_STATUS_OK) {
-                               ERR("Failed to get action rate policy interval");
-                               goto end;
-                       }
-                       if (policy_value > 1) {
-                               /* The default is 1 so print only when it is a
-                                * special case.
-                                */
-                               _MSG(", rate policy: every %" PRIu64
-                                    " occurrences",
-                                               policy_value);
-                       }
-                       break;
-               case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
-                       policy_status = lttng_rate_policy_once_after_n_get_threshold(
-                                       policy, &policy_value);
-                       if (policy_status != LTTNG_RATE_POLICY_STATUS_OK) {
-                               ERR("Failed to get action rate policy interval");
-                               goto end;
-                       }
-                       _MSG(", rate policy: once after %" PRIu64
-                            " occurrences",
-                                       policy_value);
-                       break;
-               default:
-                       abort();
-               }
-       }
-
-       MSG("");
-       print_action_errors(trigger, action, action_path_indexes,
-                       action_path_length);
-
-end:
-       return;
-}
-
-static
-void print_trigger_errors(const struct lttng_trigger *trigger)
-{
-       enum lttng_error_code error_query_ret;
-       struct lttng_error_query_results *results = NULL;
-       enum lttng_trigger_status trigger_status;
-       const char *trigger_name;
-       uid_t trigger_uid;
-       struct lttng_error_query *query =
-                       lttng_error_query_trigger_create(trigger);
-
-       LTTNG_ASSERT(query);
-       /*
-        * Anonymous triggers are not listed; this would be an internal error.
-        */
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       error_query_ret = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, &results);
-       if (error_query_ret != LTTNG_OK) {
-               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-error_query_ret));
-               goto end;
-       }
-
-       print_error_query_results(results, 1);
-
-end:
-       MSG("");
-       lttng_error_query_destroy(query);
-       lttng_error_query_results_destroy(results);
-}
-
-static
-void print_condition_errors(const struct lttng_trigger *trigger)
-{
-       enum lttng_error_code error_query_ret;
-       struct lttng_error_query_results *results = NULL;
-       enum lttng_trigger_status trigger_status;
-       const char *trigger_name;
-       uid_t trigger_uid;
-       struct lttng_error_query *query =
-                       lttng_error_query_condition_create(trigger);
-
-       LTTNG_ASSERT(query);
-       /*
-        * Anonymous triggers are not listed; this would be an internal error.
-        */
-       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       error_query_ret = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, &results);
-       if (error_query_ret != LTTNG_OK) {
-               ERR("Failed to query errors of condition of trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-error_query_ret));
-               goto end;
-       }
-
-       print_error_query_results(results, 2);
-
-end:
-       MSG("");
-       lttng_error_query_destroy(query);
-       lttng_error_query_results_destroy(results);
-}
-
-static
-void print_one_trigger(const struct lttng_trigger *trigger)
-{
-       const struct lttng_condition *condition;
-       enum lttng_condition_type condition_type;
-       const struct lttng_action *action;
-       enum lttng_action_type action_type;
-       enum lttng_trigger_status trigger_status;
-       const char *name;
-       uid_t trigger_uid;
-
-       /*
-        * Anonymous triggers are not listed since they can't be specified nor
-        * referenced through the CLI.
-        */
-       trigger_status = lttng_trigger_get_name(trigger, &name);
-       if (trigger_status == LTTNG_TRIGGER_STATUS_UNSET) {
-               goto end;
-       }
-
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       MSG("- name: %s", name);
-       MSG("  owner uid: %d", trigger_uid);
-
-       condition = lttng_trigger_get_const_condition(trigger);
-       condition_type = lttng_condition_get_type(condition);
-       MSG("  condition: %s", lttng_condition_type_str(condition_type));
-       switch (condition_type) {
-       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
-               print_condition_session_consumed_size(condition);
-               break;
-       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
-       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
-               print_condition_buffer_usage(condition);
-               break;
-       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
-       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
-               print_condition_session_rotation(condition);
-               break;
-       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
-               print_condition_event_rule_matches(condition);
-               break;
-       default:
-               abort();
-       }
-
-       print_condition_errors(trigger);
-
-       action = lttng_trigger_get_const_action(trigger);
-       action_type = lttng_action_get_type(action);
-       if (action_type == LTTNG_ACTION_TYPE_LIST) {
-               unsigned int count, i;
-               enum lttng_action_status action_status;
-
-               MSG("  actions:");
-
-               action_status = lttng_action_list_get_count(action, &count);
-               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
-
-               for (i = 0; i < count; i++) {
-                       const uint64_t action_path_index = i;
-                       const struct lttng_action *subaction =
-                                       lttng_action_list_get_at_index(
-                                                       action, i);
-
-                       _MSG("    ");
-                       print_one_action(trigger, subaction, &action_path_index,
-                                       1);
-               }
-       } else {
-               _MSG(" action:");
-               print_one_action(trigger, action, NULL, 0);
-       }
-
-       print_trigger_errors(trigger);
-end:
-       return;
-}
-
-static
-int compare_triggers_by_name(const void *a, const void *b)
-{
-       const struct lttng_trigger *trigger_a = *((const struct lttng_trigger **) a);
-       const struct lttng_trigger *trigger_b = *((const struct lttng_trigger **) b);
-       const char *name_a, *name_b;
-       enum lttng_trigger_status trigger_status;
-
-       /* Anonymous triggers are not reachable here. */
-       trigger_status = lttng_trigger_get_name(trigger_a, &name_a);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       trigger_status = lttng_trigger_get_name(trigger_b, &name_b);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       return strcmp(name_a, name_b);
-}
-
-static int print_sorted_triggers(const struct lttng_triggers *triggers)
-{
-       int ret;
-       int i;
-       struct lttng_dynamic_pointer_array sorted_triggers;
-       enum lttng_trigger_status trigger_status;
-       unsigned int num_triggers;
-
-       lttng_dynamic_pointer_array_init(&sorted_triggers, NULL);
-
-       trigger_status = lttng_triggers_get_count(triggers, &num_triggers);
-       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
-               ERR("Failed to get trigger count.");
-               goto error;
-       }
-
-       for (i = 0; i < num_triggers; i++) {
-               int add_ret;
-               const char *unused_name;
-               const struct lttng_trigger *trigger =
-                               lttng_triggers_get_at_index(triggers, i);
-
-               trigger_status = lttng_trigger_get_name(trigger, &unused_name);
-               switch (trigger_status) {
-               case LTTNG_TRIGGER_STATUS_OK:
-                       break;
-               case LTTNG_TRIGGER_STATUS_UNSET:
-                       /* Don't list anonymous triggers. */
-                       continue;
-               default:
-                       abort();
-               }
-
-               add_ret = lttng_dynamic_pointer_array_add_pointer(
-                               &sorted_triggers, (void *) trigger);
-               if (add_ret) {
-                       ERR("Failed to allocate array of struct lttng_trigger *.");
-                       goto error;
-               }
-       }
-
-       qsort(sorted_triggers.array.buffer.data, num_triggers,
-                       sizeof(struct lttng_trigger *),
-                       compare_triggers_by_name);
-
-       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&sorted_triggers);
-                       i++) {
-               const struct lttng_trigger *trigger_to_print = (const struct lttng_trigger
-                                               *)
-                               lttng_dynamic_pointer_array_get_pointer(
-                                               &sorted_triggers, i);
-
-               print_one_trigger(trigger_to_print);
-       }
-
-       ret = 0;
-       goto end;
-error:
-       ret = 1;
-
-end:
-       lttng_dynamic_pointer_array_reset(&sorted_triggers);
-       return ret;
-}
-
-static enum lttng_error_code mi_error_query_trigger_callback(
-               const struct lttng_trigger *trigger,
-               struct lttng_error_query_results **results)
-{
-       enum lttng_error_code ret_code;
-       struct lttng_error_query *query =
-                       lttng_error_query_trigger_create(trigger);
-
-       LTTNG_ASSERT(results);
-       LTTNG_ASSERT(query);
-
-       ret_code = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, results);
-       if (ret_code != LTTNG_OK) {
-               enum lttng_trigger_status trigger_status;
-               const char *trigger_name;
-               uid_t trigger_uid;
-
-               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               trigger_status = lttng_trigger_get_owner_uid(
-                               trigger, &trigger_uid);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-ret_code));
-       }
-
-       lttng_error_query_destroy(query);
-       return ret_code;
-}
-
-static enum lttng_error_code mi_error_query_action_callback(
-               const struct lttng_trigger *trigger,
-               const struct lttng_action_path *action_path,
-               struct lttng_error_query_results **results)
-{
-       enum lttng_error_code ret_code;
-       struct lttng_error_query *query =
-                       lttng_error_query_action_create(trigger, action_path);
-
-       LTTNG_ASSERT(results);
-       LTTNG_ASSERT(query);
-
-       ret_code = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, results);
-       if (ret_code != LTTNG_OK) {
-               enum lttng_trigger_status trigger_status;
-               const char *trigger_name;
-               uid_t trigger_uid;
-
-               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               trigger_status = lttng_trigger_get_owner_uid(
-                               trigger, &trigger_uid);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               ERR("Failed to query errors of an action for trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-ret_code));
-       }
-
-       lttng_error_query_destroy(query);
-       return ret_code;
-}
-
-static enum lttng_error_code mi_error_query_condition_callback(
-               const struct lttng_trigger *trigger,
-               struct lttng_error_query_results **results)
-{
-       enum lttng_error_code ret_code;
-       struct lttng_error_query *query =
-                       lttng_error_query_condition_create(trigger);
-
-       LTTNG_ASSERT(results);
-       LTTNG_ASSERT(query);
-
-       ret_code = lttng_error_query_execute(
-                       query, lttng_session_daemon_command_endpoint, results);
-       if (ret_code != LTTNG_OK) {
-               enum lttng_trigger_status trigger_status;
-               const char *trigger_name;
-               uid_t trigger_uid;
-
-               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               trigger_status = lttng_trigger_get_owner_uid(
-                               trigger, &trigger_uid);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               ERR("Failed to query errors of of condition for condition of trigger '%s' (owner uid: %d): %s",
-                               trigger_name, (int) trigger_uid,
-                               lttng_strerror(-ret_code));
-       }
-
-       lttng_error_query_destroy(query);
-       return ret_code;
-}
-
-int cmd_list_triggers(int argc, const char **argv)
-{
-       int ret;
-       struct argpar_parse_ret argpar_parse_ret = {};
-       struct lttng_triggers *triggers = NULL;
-       int i;
-       struct mi_writer *mi_writer = NULL;
-
-       argpar_parse_ret = argpar_parse(
-                       argc - 1, argv + 1, list_trigger_options, true);
-       if (!argpar_parse_ret.items) {
-               ERR("%s", argpar_parse_ret.error);
-               goto error;
-       }
-
-       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
-               const struct argpar_item *item =
-                               argpar_parse_ret.items->items[i];
-
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_HELP:
-                               SHOW_HELP();
-                               ret = 0;
-                               goto end;
-
-                       case OPT_LIST_OPTIONS:
-                               list_cmd_options_argpar(
-                                               stdout, list_trigger_options);
-                               ret = 0;
-                               goto end;
-
-                       default:
-                               abort();
-                       }
-
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt =
-                               (const struct argpar_item_non_opt *) item;
-
-                       ERR("Unexpected argument: %s", item_non_opt->arg);
-               }
-       }
-
-       ret = lttng_list_triggers(&triggers);
-       if (ret != LTTNG_OK) {
-               ERR("Error listing triggers: %s.", lttng_strerror(-ret));
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               mi_writer = mi_lttng_writer_create(
-                               fileno(stdout), lttng_opt_mi);
-               if (!mi_writer) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open command element. */
-               ret = mi_lttng_writer_command_open(mi_writer,
-                               mi_lttng_element_command_list_trigger);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open output element. */
-               ret = mi_lttng_writer_open_element(
-                               mi_writer, mi_lttng_element_command_output);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       if (lttng_opt_mi) {
-               const struct mi_lttng_error_query_callbacks callbacks = {
-                       .trigger_cb = mi_error_query_trigger_callback,
-                       .action_cb = mi_error_query_action_callback,
-                       .condition_cb = mi_error_query_condition_callback,
-               };
-
-               ret = lttng_triggers_mi_serialize(
-                               triggers, mi_writer, &callbacks);
-               if (ret != LTTNG_OK) {
-                       ERR("Error printing MI triggers: %s.",
-                                       lttng_strerror(-ret));
-                       goto error;
-               }
-       } else {
-               ret = print_sorted_triggers(triggers);
-               if (ret) {
-                       ERR("Error printing triggers");
-                       goto error;
-               }
-       }
-
-       /* Mi closing. */
-       if (lttng_opt_mi) {
-               /* Close output element. */
-               ret = mi_lttng_writer_close_element(mi_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close. */
-               ret = mi_lttng_writer_command_close(mi_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = 1;
-
-end:
-       argpar_parse_ret_fini(&argpar_parse_ret);
-       lttng_triggers_destroy(triggers);
-       /* Mi clean-up. */
-       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
-               /* Preserve original error code. */
-               ret = ret ? ret : CMD_ERROR;
-       }
-       return ret;
-}
diff --git a/src/bin/lttng/commands/list_triggers.cpp b/src/bin/lttng/commands/list_triggers.cpp
new file mode 100644 (file)
index 0000000..9a57714
--- /dev/null
@@ -0,0 +1,1449 @@
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include <stdio.h>
+
+#include "../command.h"
+
+#include "common/argpar/argpar.h"
+#include "common/dynamic-array.h"
+#include "common/mi-lttng.h"
+/* For lttng_condition_type_str(). */
+#include "lttng/condition/condition-internal.h"
+#include "lttng/condition/event-rule-matches.h"
+#include "lttng/condition/event-rule-matches-internal.h"
+/* For lttng_domain_type_str(). */
+#include "lttng/domain-internal.h"
+/* For lttng_event_rule_kernel_syscall_emission_site_str() */
+#include "lttng/event-rule/kernel-syscall-internal.h"
+#include "../loglevel.h"
+#include <lttng/lttng.h>
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-list-triggers.1.h>
+;
+#endif
+
+#define INDENTATION_LEVEL_STR "  "
+
+typedef enum lttng_event_rule_status (*event_rule_logging_get_name_pattern)(
+               const struct lttng_event_rule *rule, const char **pattern);
+typedef enum lttng_event_rule_status (*event_rule_logging_get_filter)(
+               const struct lttng_event_rule *rule, const char **expression);
+typedef enum lttng_event_rule_status (*event_rule_logging_get_log_level_rule)(
+               const struct lttng_event_rule *rule,
+               const struct lttng_log_level_rule **log_level_rule);
+
+enum {
+       OPT_HELP,
+       OPT_LIST_OPTIONS,
+};
+
+static const
+struct argpar_opt_descr list_trigger_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_LIST_OPTIONS, '\0', "list-options", false },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static void print_condition_session_consumed_size(
+               const struct lttng_condition *condition)
+{
+       enum lttng_condition_status condition_status;
+       const char *session_name;
+       uint64_t threshold;
+
+       condition_status =
+                       lttng_condition_session_consumed_size_get_session_name(
+                                       condition, &session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       lttng_condition_session_consumed_size_get_threshold(
+                       condition, &threshold);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       MSG("    session name: %s", session_name);
+       MSG("    threshold: %" PRIu64 " bytes", threshold);
+}
+
+static void print_condition_buffer_usage(
+               const struct lttng_condition *condition)
+{
+       enum lttng_condition_status condition_status;
+       const char *session_name, *channel_name;
+       enum lttng_domain_type domain_type;
+       uint64_t threshold;
+
+       condition_status = lttng_condition_buffer_usage_get_session_name(
+                       condition, &session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       condition_status = lttng_condition_buffer_usage_get_channel_name(
+                       condition, &channel_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       condition_status = lttng_condition_buffer_usage_get_domain_type(
+                       condition, &domain_type);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       MSG("    session name: %s", session_name);
+       MSG("    channel name: %s", channel_name);
+       MSG("    domain: %s", lttng_domain_type_str(domain_type));
+
+       condition_status = lttng_condition_buffer_usage_get_threshold(
+                       condition, &threshold);
+       if (condition_status == LTTNG_CONDITION_STATUS_OK) {
+               MSG("    threshold (bytes): %" PRIu64, threshold);
+       } else {
+               double threshold_ratio;
+
+               LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_UNSET);
+
+               condition_status =
+                               lttng_condition_buffer_usage_get_threshold_ratio(
+                                               condition, &threshold_ratio);
+               LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+               MSG("    threshold (ratio): %.2f", threshold_ratio);
+       }
+}
+
+static void print_condition_session_rotation(
+               const struct lttng_condition *condition)
+{
+       enum lttng_condition_status condition_status;
+       const char *session_name;
+
+       condition_status = lttng_condition_session_rotation_get_session_name(
+                       condition, &session_name);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       MSG("    session name: %s", session_name);
+}
+
+/*
+ * Returns the human-readable log level name associated with a numerical value
+ * if there is one. The Log4j and JUL event rule have discontinuous log level
+ * values (a value can fall between two labels). In those cases, NULL is
+ * returned.
+ */
+static const char *get_pretty_loglevel_name(
+               enum lttng_event_rule_type event_rule_type, int loglevel)
+{
+       const char *name = NULL;
+
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+               name = loglevel_value_to_name(loglevel);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+               name = loglevel_log4j_value_to_name(loglevel);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+               name = loglevel_jul_value_to_name(loglevel);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               name = loglevel_python_value_to_name(loglevel);
+               break;
+       default:
+               break;
+       }
+
+       return name;
+}
+
+static
+void print_event_rule_user_tracepoint(const struct lttng_event_rule *event_rule)
+{
+       enum lttng_event_rule_status event_rule_status;
+       const char *pattern;
+       const char *filter;
+       int log_level;
+       const struct lttng_log_level_rule *log_level_rule = NULL;
+       unsigned int exclusions_count;
+       int i;
+
+       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern(
+                       event_rule, &pattern);
+       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       _MSG("    rule: %s (type: user tracepoint", pattern);
+
+       event_rule_status = lttng_event_rule_user_tracepoint_get_filter(
+                       event_rule, &filter);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               _MSG(", filter: %s", filter);
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       event_rule_status = lttng_event_rule_user_tracepoint_get_log_level_rule(
+                       event_rule, &log_level_rule);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               enum lttng_log_level_rule_status llr_status;
+               const char *log_level_op;
+               const char *pretty_loglevel_name;
+
+               switch (lttng_log_level_rule_get_type(log_level_rule)) {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       log_level_op = "is";
+                       llr_status = lttng_log_level_rule_exactly_get_level(
+                                       log_level_rule, &log_level);
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       log_level_op = "at least";
+                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                                       log_level_rule, &log_level);
+                       break;
+               default:
+                       abort();
+               }
+
+               LTTNG_ASSERT(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
+
+               pretty_loglevel_name = get_pretty_loglevel_name(
+                               LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT, log_level);
+               if (pretty_loglevel_name) {
+                       _MSG(", log level %s %s", log_level_op,
+                                       pretty_loglevel_name);
+               } else {
+                       _MSG(", log level %s %d", log_level_op, log_level);
+               }
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_count(
+                       event_rule, &exclusions_count);
+       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+       if (exclusions_count > 0) {
+               _MSG(", exclusions: ");
+               for (i = 0; i < exclusions_count; i++) {
+                       const char *exclusion;
+
+                       event_rule_status = lttng_event_rule_user_tracepoint_get_name_pattern_exclusion_at_index(
+                                       event_rule, i, &exclusion);
+                       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+                       _MSG("%s%s", i > 0 ? "," : "", exclusion);
+               }
+       }
+
+       MSG(")");
+}
+
+static
+void print_event_rule_kernel_tracepoint(const struct lttng_event_rule *event_rule)
+{
+       enum lttng_event_rule_status event_rule_status;
+       const char *pattern;
+       const char *filter;
+
+       event_rule_status = lttng_event_rule_kernel_tracepoint_get_name_pattern(
+                       event_rule, &pattern);
+       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       _MSG("    rule: %s (type: kernel tracepoint", pattern);
+
+       event_rule_status = lttng_event_rule_kernel_tracepoint_get_filter(
+                       event_rule, &filter);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               _MSG(", filter: %s", filter);
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       MSG(")");
+}
+
+static
+void print_event_rule_logging(const struct lttng_event_rule *event_rule)
+{
+       enum lttng_event_rule_status event_rule_status;
+       enum lttng_event_rule_type event_rule_type = lttng_event_rule_get_type(event_rule);
+       const char *pattern;
+       const char *filter;
+       int log_level;
+       const struct lttng_log_level_rule *log_level_rule = NULL;
+       const char *type_str = NULL;
+
+       event_rule_logging_get_name_pattern logging_get_name_pattern;
+       event_rule_logging_get_filter logging_get_filter;
+       event_rule_logging_get_log_level_rule logging_get_log_level_rule;
+
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+               logging_get_name_pattern =
+                               lttng_event_rule_jul_logging_get_name_pattern;
+               logging_get_filter = lttng_event_rule_jul_logging_get_filter;
+               logging_get_log_level_rule =
+                               lttng_event_rule_jul_logging_get_log_level_rule;
+               type_str = "jul";
+               break;
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+               logging_get_name_pattern =
+                               lttng_event_rule_log4j_logging_get_name_pattern;
+               logging_get_filter = lttng_event_rule_log4j_logging_get_filter;
+               logging_get_log_level_rule =
+                               lttng_event_rule_log4j_logging_get_log_level_rule;
+               type_str = "log4j";
+               break;
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               logging_get_name_pattern =
+                               lttng_event_rule_python_logging_get_name_pattern;
+               logging_get_filter = lttng_event_rule_python_logging_get_filter;
+               logging_get_log_level_rule =
+                               lttng_event_rule_python_logging_get_log_level_rule;
+               type_str = "python";
+               break;
+       default:
+               abort();
+               break;
+       }
+
+       event_rule_status = logging_get_name_pattern(
+                       event_rule, &pattern);
+       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       _MSG("    rule: %s (type: %s:logging", pattern, type_str);
+
+       event_rule_status = logging_get_filter(
+                       event_rule, &filter);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               _MSG(", filter: %s", filter);
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       event_rule_status = logging_get_log_level_rule(
+                       event_rule, &log_level_rule);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               enum lttng_log_level_rule_status llr_status;
+               const char *log_level_op;
+               const char *pretty_loglevel_name;
+
+               switch (lttng_log_level_rule_get_type(log_level_rule)) {
+               case LTTNG_LOG_LEVEL_RULE_TYPE_EXACTLY:
+                       log_level_op = "is";
+                       llr_status = lttng_log_level_rule_exactly_get_level(
+                                       log_level_rule, &log_level);
+                       break;
+               case LTTNG_LOG_LEVEL_RULE_TYPE_AT_LEAST_AS_SEVERE_AS:
+                       log_level_op = "at least";
+                       llr_status = lttng_log_level_rule_at_least_as_severe_as_get_level(
+                                       log_level_rule, &log_level);
+                       break;
+               default:
+                       abort();
+               }
+
+               LTTNG_ASSERT(llr_status == LTTNG_LOG_LEVEL_RULE_STATUS_OK);
+
+               pretty_loglevel_name = get_pretty_loglevel_name(
+                               event_rule_type, log_level);
+               if (pretty_loglevel_name) {
+                       _MSG(", log level %s %s", log_level_op,
+                                       pretty_loglevel_name);
+               } else {
+                       _MSG(", log level %s %d", log_level_op, log_level);
+               }
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       MSG(")");
+}
+
+static void print_kernel_probe_location(
+               const struct lttng_kernel_probe_location *location)
+{
+       enum lttng_kernel_probe_location_status status;
+       switch (lttng_kernel_probe_location_get_type(location)) {
+       case LTTNG_KERNEL_PROBE_LOCATION_TYPE_ADDRESS:
+       {
+               uint64_t address;
+
+               status = lttng_kernel_probe_location_address_get_address(
+                               location, &address);
+               if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
+                       ERR("Getting kernel probe location address failed.");
+                       goto end;
+               }
+
+               _MSG("0x%" PRIx64, address);
+
+               break;
+       }
+       case LTTNG_KERNEL_PROBE_LOCATION_TYPE_SYMBOL_OFFSET:
+       {
+               uint64_t offset;
+               const char *symbol_name;
+
+               symbol_name = lttng_kernel_probe_location_symbol_get_name(
+                               location);
+               if (!symbol_name) {
+                       ERR("Getting kernel probe location symbol name failed.");
+                       goto end;
+               }
+
+               status = lttng_kernel_probe_location_symbol_get_offset(
+                               location, &offset);
+               if (status != LTTNG_KERNEL_PROBE_LOCATION_STATUS_OK) {
+                       ERR("Getting kernel probe location address failed.");
+                       goto end;
+               }
+
+               if (offset == 0) {
+                       _MSG("%s", symbol_name);
+               } else {
+                       _MSG("%s+0x%" PRIx64, symbol_name, offset);
+               }
+
+               break;
+       }
+       default:
+               abort();
+       };
+end:
+       return;
+}
+
+static
+void print_event_rule_kernel_probe(const struct lttng_event_rule *event_rule)
+{
+       enum lttng_event_rule_status event_rule_status;
+       const char *name;
+       const struct lttng_kernel_probe_location *location;
+
+       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE);
+
+       event_rule_status = lttng_event_rule_kernel_kprobe_get_event_name(event_rule, &name);
+       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to get kprobe event rule's name.");
+               goto end;
+       }
+
+       event_rule_status = lttng_event_rule_kernel_kprobe_get_location(
+                       event_rule, &location);
+       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to get kprobe event rule's location.");
+               goto end;
+       }
+
+       _MSG("    rule: %s (type: kernel:kprobe, location: ", name);
+
+       print_kernel_probe_location(location);
+
+       MSG(")");
+
+end:
+       return;
+}
+
+static
+void print_event_rule_userspace_probe(const struct lttng_event_rule *event_rule)
+{
+       enum lttng_event_rule_status event_rule_status;
+       const char *name;
+       const struct lttng_userspace_probe_location *location;
+       enum lttng_userspace_probe_location_type userspace_probe_location_type;
+
+       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE);
+
+       event_rule_status = lttng_event_rule_kernel_uprobe_get_event_name(
+                       event_rule, &name);
+       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to get uprobe event rule's name.");
+               goto end;
+       }
+
+       event_rule_status = lttng_event_rule_kernel_uprobe_get_location(
+                       event_rule, &location);
+       if (event_rule_status != LTTNG_EVENT_RULE_STATUS_OK) {
+               ERR("Failed to get uprobe event rule's location.");
+               goto end;
+       }
+
+       _MSG("    rule: %s (type: kernel:uprobe, ", name);
+
+       userspace_probe_location_type =
+                       lttng_userspace_probe_location_get_type(location);
+
+       switch (userspace_probe_location_type) {
+       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_FUNCTION:
+       {
+               const char *binary_path, *function_name;
+
+               binary_path = lttng_userspace_probe_location_function_get_binary_path(
+                               location);
+               function_name = lttng_userspace_probe_location_function_get_function_name(
+                               location);
+
+               _MSG("location type: ELF, location: %s:%s", binary_path, function_name);
+               break;
+       }
+       case LTTNG_USERSPACE_PROBE_LOCATION_TYPE_TRACEPOINT:
+       {
+               const char *binary_path, *provider_name, *probe_name;
+
+               binary_path = lttng_userspace_probe_location_tracepoint_get_binary_path(
+                               location);
+               provider_name = lttng_userspace_probe_location_tracepoint_get_provider_name(
+                               location);
+               probe_name = lttng_userspace_probe_location_tracepoint_get_probe_name(
+                               location);
+               _MSG("location type: SDT, location: %s:%s:%s", binary_path, provider_name, probe_name);
+               break;
+       }
+       default:
+               abort();
+       }
+
+       MSG(")");
+
+end:
+       return;
+}
+
+static
+void print_event_rule_syscall(const struct lttng_event_rule *event_rule)
+{
+       const char *pattern, *filter;
+       enum lttng_event_rule_status event_rule_status;
+       enum lttng_event_rule_kernel_syscall_emission_site emission_site;
+
+       LTTNG_ASSERT(lttng_event_rule_get_type(event_rule) == LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL);
+
+       emission_site =
+               lttng_event_rule_kernel_syscall_get_emission_site(event_rule);
+
+       event_rule_status = lttng_event_rule_kernel_syscall_get_name_pattern(
+                       event_rule, &pattern);
+       LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_OK);
+
+       _MSG("    rule: %s (type: kernel:syscall:%s", pattern,
+                       lttng_event_rule_kernel_syscall_emission_site_str(
+                                       emission_site));
+
+       event_rule_status = lttng_event_rule_kernel_syscall_get_filter(
+                       event_rule, &filter);
+       if (event_rule_status == LTTNG_EVENT_RULE_STATUS_OK) {
+               _MSG(", filter: %s", filter);
+       } else {
+               LTTNG_ASSERT(event_rule_status == LTTNG_EVENT_RULE_STATUS_UNSET);
+       }
+
+       MSG(")");
+}
+
+static
+void print_event_rule(const struct lttng_event_rule *event_rule)
+{
+       const enum lttng_event_rule_type event_rule_type =
+                       lttng_event_rule_get_type(event_rule);
+
+       switch (event_rule_type) {
+       case LTTNG_EVENT_RULE_TYPE_USER_TRACEPOINT:
+               print_event_rule_user_tracepoint(event_rule);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_TRACEPOINT:
+               print_event_rule_kernel_tracepoint(event_rule);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_JUL_LOGGING:
+       case LTTNG_EVENT_RULE_TYPE_LOG4J_LOGGING:
+       case LTTNG_EVENT_RULE_TYPE_PYTHON_LOGGING:
+               print_event_rule_logging(event_rule);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_KPROBE:
+               print_event_rule_kernel_probe(event_rule);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_UPROBE:
+               print_event_rule_userspace_probe(event_rule);
+               break;
+       case LTTNG_EVENT_RULE_TYPE_KERNEL_SYSCALL:
+               print_event_rule_syscall(event_rule);
+               break;
+       default:
+               abort();
+       }
+}
+
+static
+void print_one_event_expr(const struct lttng_event_expr *event_expr)
+{
+       enum lttng_event_expr_type type;
+
+       type = lttng_event_expr_get_type(event_expr);
+
+       switch (type) {
+       case LTTNG_EVENT_EXPR_TYPE_EVENT_PAYLOAD_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_event_payload_field_get_name(
+                               event_expr);
+               _MSG("%s", name);
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_CHANNEL_CONTEXT_FIELD:
+       {
+               const char *name;
+
+               name = lttng_event_expr_channel_context_field_get_name(
+                               event_expr);
+               _MSG("$ctx.%s", name);
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_APP_SPECIFIC_CONTEXT_FIELD:
+       {
+               const char *provider_name;
+               const char *type_name;
+
+               provider_name = lttng_event_expr_app_specific_context_field_get_provider_name(
+                               event_expr);
+               type_name = lttng_event_expr_app_specific_context_field_get_type_name(
+                               event_expr);
+
+               _MSG("$app.%s:%s", provider_name, type_name);
+
+               break;
+       }
+       case LTTNG_EVENT_EXPR_TYPE_ARRAY_FIELD_ELEMENT:
+       {
+               unsigned int index;
+               const struct lttng_event_expr *parent_expr;
+               enum lttng_event_expr_status status;
+
+               parent_expr = lttng_event_expr_array_field_element_get_parent_expr(
+                               event_expr);
+               LTTNG_ASSERT(parent_expr != NULL);
+
+               print_one_event_expr(parent_expr);
+
+               status = lttng_event_expr_array_field_element_get_index(
+                               event_expr, &index);
+               LTTNG_ASSERT(status == LTTNG_EVENT_EXPR_STATUS_OK);
+
+               _MSG("[%u]", index);
+
+               break;
+       }
+       default:
+               abort();
+       }
+}
+
+static
+void print_indentation(unsigned int indentation_level)
+{
+       unsigned int i;
+
+       for (i = 0; i < indentation_level; i++) {
+               _MSG(INDENTATION_LEVEL_STR);
+       }
+}
+
+static
+void print_error_query_results(struct lttng_error_query_results *results,
+               unsigned int base_indentation_level)
+{
+       unsigned int i, count, printed_errors_count = 0;
+       enum lttng_error_query_results_status results_status;
+
+       results_status = lttng_error_query_results_get_count(results, &count);
+       LTTNG_ASSERT(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
+
+       LTTNG_ASSERT(results);
+
+       print_indentation(base_indentation_level);
+       _MSG("errors:");
+
+       for (i = 0; i < count; i++) {
+               const struct lttng_error_query_result *result;
+               enum lttng_error_query_result_status result_status;
+               const char *result_name;
+               const char *result_description;
+               uint64_t result_value;
+
+               results_status = lttng_error_query_results_get_result(
+                               results, &result, i);
+               LTTNG_ASSERT(results_status == LTTNG_ERROR_QUERY_RESULTS_STATUS_OK);
+
+               result_status = lttng_error_query_result_get_name(
+                               result, &result_name);
+               LTTNG_ASSERT(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+               result_status = lttng_error_query_result_get_description(
+                               result, &result_description);
+               LTTNG_ASSERT(result_status == LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+
+
+               if (lttng_error_query_result_get_type(result) ==
+                               LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER) {
+                       result_status = lttng_error_query_result_counter_get_value(
+                                       result, &result_value);
+                       LTTNG_ASSERT(result_status ==
+                                       LTTNG_ERROR_QUERY_RESULT_STATUS_OK);
+                       if (result_value == 0) {
+                               continue;
+                       }
+
+                       MSG("");
+                       print_indentation(base_indentation_level + 1);
+
+                       _MSG("%s: %" PRIu64, result_name, result_value);
+                       printed_errors_count++;
+               } else {
+                       MSG("");
+                       print_indentation(base_indentation_level + 1);
+                       _MSG("Unknown error query result type for result '%s' (%s)",
+                                       result_name, result_description);
+                       continue;
+               }
+       }
+
+       if (printed_errors_count == 0) {
+               _MSG(" none");
+       }
+}
+
+static void print_condition_event_rule_matches(
+               const struct lttng_condition *condition)
+{
+       const struct lttng_event_rule *event_rule;
+       enum lttng_condition_status condition_status;
+       unsigned int cap_desc_count, i;
+
+       condition_status = lttng_condition_event_rule_matches_get_rule(
+                       condition, &event_rule);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       print_event_rule(event_rule);
+
+       condition_status =
+                       lttng_condition_event_rule_matches_get_capture_descriptor_count(
+                                       condition, &cap_desc_count);
+       LTTNG_ASSERT(condition_status == LTTNG_CONDITION_STATUS_OK);
+
+       if (cap_desc_count > 0) {
+               MSG("    captures:");
+
+               for (i = 0; i < cap_desc_count; i++) {
+                       const struct lttng_event_expr *cap_desc =
+                                       lttng_condition_event_rule_matches_get_capture_descriptor_at_index(
+                                                       condition, i);
+
+                       _MSG("      - ");
+                       print_one_event_expr(cap_desc);
+                       MSG("");
+               }
+       }
+}
+
+static void print_action_errors(const struct lttng_trigger *trigger,
+               const struct lttng_action *action,
+               const uint64_t *action_path_indexes,
+               size_t action_path_length)
+{
+       enum lttng_error_code error_query_ret;
+       struct lttng_error_query_results *results = NULL;
+       const char *trigger_name;
+       uid_t trigger_uid;
+       enum lttng_trigger_status trigger_status;
+       struct lttng_error_query *query;
+       struct lttng_action_path *action_path = lttng_action_path_create(
+                       action_path_indexes, action_path_length);
+
+       LTTNG_ASSERT(action_path);
+
+       query = lttng_error_query_action_create(trigger, action_path);
+       LTTNG_ASSERT(query);
+
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       /*
+        * Anonymous triggers are not listed; this would be an internal error.
+        */
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       error_query_ret = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, &results);
+       if (error_query_ret != LTTNG_OK) {
+               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-error_query_ret));
+               goto end;
+       }
+
+       print_error_query_results(results, 3);
+
+end:
+       MSG("");
+       lttng_error_query_destroy(query);
+       lttng_error_query_results_destroy(results);
+       lttng_action_path_destroy(action_path);
+}
+
+static
+void print_one_action(const struct lttng_trigger *trigger,
+               const struct lttng_action *action,
+               const uint64_t *action_path_indexes,
+               size_t action_path_length)
+{
+       enum lttng_action_type action_type;
+       enum lttng_action_status action_status;
+       const struct lttng_rate_policy *policy = NULL;
+       const char *value;
+
+       action_type = lttng_action_get_type(action);
+       LTTNG_ASSERT(action_type != LTTNG_ACTION_TYPE_LIST);
+
+       switch (action_type) {
+       case LTTNG_ACTION_TYPE_NOTIFY:
+               _MSG("notify");
+
+               action_status = lttng_action_notify_get_rate_policy(
+                               action, &policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to retrieve rate policy.");
+                       goto end;
+               }
+               break;
+       case LTTNG_ACTION_TYPE_START_SESSION:
+               action_status = lttng_action_start_session_get_session_name(
+                               action, &value);
+               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+               _MSG("start session `%s`", value);
+
+               action_status = lttng_action_start_session_get_rate_policy(
+                               action, &policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to retrieve rate policy.");
+                       goto end;
+               }
+               break;
+       case LTTNG_ACTION_TYPE_STOP_SESSION:
+               action_status = lttng_action_stop_session_get_session_name(
+                               action, &value);
+               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+               _MSG("stop session `%s`", value);
+
+               action_status = lttng_action_stop_session_get_rate_policy(
+                               action, &policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to retrieve rate policy.");
+                       goto end;
+               }
+               break;
+       case LTTNG_ACTION_TYPE_ROTATE_SESSION:
+               action_status = lttng_action_rotate_session_get_session_name(
+                               action, &value);
+               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+               _MSG("rotate session `%s`", value);
+
+               action_status = lttng_action_rotate_session_get_rate_policy(
+                               action, &policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to retrieve rate policy.");
+                       goto end;
+               }
+               break;
+       case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
+       {
+               const struct lttng_snapshot_output *output;
+
+               action_status = lttng_action_snapshot_session_get_session_name(
+                               action, &value);
+               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+               _MSG("snapshot session `%s`", value);
+
+               action_status = lttng_action_snapshot_session_get_output(
+                               action, &output);
+               if (action_status == LTTNG_ACTION_STATUS_OK) {
+                       const char *name;
+                       uint64_t max_size;
+                       const char *ctrl_url, *data_url;
+                       bool starts_with_file, starts_with_net, starts_with_net6;
+
+                       ctrl_url = lttng_snapshot_output_get_ctrl_url(output);
+                       LTTNG_ASSERT(ctrl_url && strlen(ctrl_url) > 0);
+
+                       data_url = lttng_snapshot_output_get_data_url(output);
+                       LTTNG_ASSERT(data_url);
+
+                       starts_with_file = strncmp(ctrl_url, "file://", strlen("file://")) == 0;
+                       starts_with_net = strncmp(ctrl_url, "net://", strlen("net://")) == 0;
+                       starts_with_net6 = strncmp(ctrl_url, "net6://", strlen("net6://")) == 0;
+
+                       if (ctrl_url[0] == '/' || starts_with_file) {
+                               if (starts_with_file) {
+                                       ctrl_url += strlen("file://");
+                               }
+
+                               _MSG(", path: %s", ctrl_url);
+                       } else if (starts_with_net || starts_with_net6) {
+                               _MSG(", url: %s", ctrl_url);
+                       } else {
+                               LTTNG_ASSERT(strlen(data_url) > 0);
+
+                               _MSG(", control url: %s, data url: %s", ctrl_url, data_url);
+                       }
+
+                       name = lttng_snapshot_output_get_name(output);
+                       LTTNG_ASSERT(name);
+                       if (strlen(name) > 0) {
+                               _MSG(", name: %s", name);
+                       }
+
+                       max_size = lttng_snapshot_output_get_maxsize(output);
+                       if (max_size != -1ULL) {
+                               _MSG(", max size: %" PRIu64, max_size);
+                       }
+               }
+
+               action_status = lttng_action_snapshot_session_get_rate_policy(
+                               action, &policy);
+               if (action_status != LTTNG_ACTION_STATUS_OK) {
+                       ERR("Failed to retrieve rate policy.");
+                       goto end;
+               }
+               break;
+       }
+       default:
+               abort();
+       }
+
+       if (policy) {
+               enum lttng_rate_policy_type policy_type;
+               enum lttng_rate_policy_status policy_status;
+               uint64_t policy_value = 0;
+
+               policy_type = lttng_rate_policy_get_type(policy);
+
+               switch (policy_type) {
+               case LTTNG_RATE_POLICY_TYPE_EVERY_N:
+                       policy_status = lttng_rate_policy_every_n_get_interval(
+                                       policy, &policy_value);
+                       if (policy_status != LTTNG_RATE_POLICY_STATUS_OK) {
+                               ERR("Failed to get action rate policy interval");
+                               goto end;
+                       }
+                       if (policy_value > 1) {
+                               /* The default is 1 so print only when it is a
+                                * special case.
+                                */
+                               _MSG(", rate policy: every %" PRIu64
+                                    " occurrences",
+                                               policy_value);
+                       }
+                       break;
+               case LTTNG_RATE_POLICY_TYPE_ONCE_AFTER_N:
+                       policy_status = lttng_rate_policy_once_after_n_get_threshold(
+                                       policy, &policy_value);
+                       if (policy_status != LTTNG_RATE_POLICY_STATUS_OK) {
+                               ERR("Failed to get action rate policy interval");
+                               goto end;
+                       }
+                       _MSG(", rate policy: once after %" PRIu64
+                            " occurrences",
+                                       policy_value);
+                       break;
+               default:
+                       abort();
+               }
+       }
+
+       MSG("");
+       print_action_errors(trigger, action, action_path_indexes,
+                       action_path_length);
+
+end:
+       return;
+}
+
+static
+void print_trigger_errors(const struct lttng_trigger *trigger)
+{
+       enum lttng_error_code error_query_ret;
+       struct lttng_error_query_results *results = NULL;
+       enum lttng_trigger_status trigger_status;
+       const char *trigger_name;
+       uid_t trigger_uid;
+       struct lttng_error_query *query =
+                       lttng_error_query_trigger_create(trigger);
+
+       LTTNG_ASSERT(query);
+       /*
+        * Anonymous triggers are not listed; this would be an internal error.
+        */
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       error_query_ret = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, &results);
+       if (error_query_ret != LTTNG_OK) {
+               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-error_query_ret));
+               goto end;
+       }
+
+       print_error_query_results(results, 1);
+
+end:
+       MSG("");
+       lttng_error_query_destroy(query);
+       lttng_error_query_results_destroy(results);
+}
+
+static
+void print_condition_errors(const struct lttng_trigger *trigger)
+{
+       enum lttng_error_code error_query_ret;
+       struct lttng_error_query_results *results = NULL;
+       enum lttng_trigger_status trigger_status;
+       const char *trigger_name;
+       uid_t trigger_uid;
+       struct lttng_error_query *query =
+                       lttng_error_query_condition_create(trigger);
+
+       LTTNG_ASSERT(query);
+       /*
+        * Anonymous triggers are not listed; this would be an internal error.
+        */
+       trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       error_query_ret = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, &results);
+       if (error_query_ret != LTTNG_OK) {
+               ERR("Failed to query errors of condition of trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-error_query_ret));
+               goto end;
+       }
+
+       print_error_query_results(results, 2);
+
+end:
+       MSG("");
+       lttng_error_query_destroy(query);
+       lttng_error_query_results_destroy(results);
+}
+
+static
+void print_one_trigger(const struct lttng_trigger *trigger)
+{
+       const struct lttng_condition *condition;
+       enum lttng_condition_type condition_type;
+       const struct lttng_action *action;
+       enum lttng_action_type action_type;
+       enum lttng_trigger_status trigger_status;
+       const char *name;
+       uid_t trigger_uid;
+
+       /*
+        * Anonymous triggers are not listed since they can't be specified nor
+        * referenced through the CLI.
+        */
+       trigger_status = lttng_trigger_get_name(trigger, &name);
+       if (trigger_status == LTTNG_TRIGGER_STATUS_UNSET) {
+               goto end;
+       }
+
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       trigger_status = lttng_trigger_get_owner_uid(trigger, &trigger_uid);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       MSG("- name: %s", name);
+       MSG("  owner uid: %d", trigger_uid);
+
+       condition = lttng_trigger_get_const_condition(trigger);
+       condition_type = lttng_condition_get_type(condition);
+       MSG("  condition: %s", lttng_condition_type_str(condition_type));
+       switch (condition_type) {
+       case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
+               print_condition_session_consumed_size(condition);
+               break;
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
+       case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
+               print_condition_buffer_usage(condition);
+               break;
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
+       case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
+               print_condition_session_rotation(condition);
+               break;
+       case LTTNG_CONDITION_TYPE_EVENT_RULE_MATCHES:
+               print_condition_event_rule_matches(condition);
+               break;
+       default:
+               abort();
+       }
+
+       print_condition_errors(trigger);
+
+       action = lttng_trigger_get_const_action(trigger);
+       action_type = lttng_action_get_type(action);
+       if (action_type == LTTNG_ACTION_TYPE_LIST) {
+               unsigned int count, i;
+               enum lttng_action_status action_status;
+
+               MSG("  actions:");
+
+               action_status = lttng_action_list_get_count(action, &count);
+               LTTNG_ASSERT(action_status == LTTNG_ACTION_STATUS_OK);
+
+               for (i = 0; i < count; i++) {
+                       const uint64_t action_path_index = i;
+                       const struct lttng_action *subaction =
+                                       lttng_action_list_get_at_index(
+                                                       action, i);
+
+                       _MSG("    ");
+                       print_one_action(trigger, subaction, &action_path_index,
+                                       1);
+               }
+       } else {
+               _MSG(" action:");
+               print_one_action(trigger, action, NULL, 0);
+       }
+
+       print_trigger_errors(trigger);
+end:
+       return;
+}
+
+static
+int compare_triggers_by_name(const void *a, const void *b)
+{
+       const struct lttng_trigger *trigger_a = *((const struct lttng_trigger **) a);
+       const struct lttng_trigger *trigger_b = *((const struct lttng_trigger **) b);
+       const char *name_a, *name_b;
+       enum lttng_trigger_status trigger_status;
+
+       /* Anonymous triggers are not reachable here. */
+       trigger_status = lttng_trigger_get_name(trigger_a, &name_a);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       trigger_status = lttng_trigger_get_name(trigger_b, &name_b);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       return strcmp(name_a, name_b);
+}
+
+static int print_sorted_triggers(const struct lttng_triggers *triggers)
+{
+       int ret;
+       int i;
+       struct lttng_dynamic_pointer_array sorted_triggers;
+       enum lttng_trigger_status trigger_status;
+       unsigned int num_triggers;
+
+       lttng_dynamic_pointer_array_init(&sorted_triggers, NULL);
+
+       trigger_status = lttng_triggers_get_count(triggers, &num_triggers);
+       if (trigger_status != LTTNG_TRIGGER_STATUS_OK) {
+               ERR("Failed to get trigger count.");
+               goto error;
+       }
+
+       for (i = 0; i < num_triggers; i++) {
+               int add_ret;
+               const char *unused_name;
+               const struct lttng_trigger *trigger =
+                               lttng_triggers_get_at_index(triggers, i);
+
+               trigger_status = lttng_trigger_get_name(trigger, &unused_name);
+               switch (trigger_status) {
+               case LTTNG_TRIGGER_STATUS_OK:
+                       break;
+               case LTTNG_TRIGGER_STATUS_UNSET:
+                       /* Don't list anonymous triggers. */
+                       continue;
+               default:
+                       abort();
+               }
+
+               add_ret = lttng_dynamic_pointer_array_add_pointer(
+                               &sorted_triggers, (void *) trigger);
+               if (add_ret) {
+                       ERR("Failed to allocate array of struct lttng_trigger *.");
+                       goto error;
+               }
+       }
+
+       qsort(sorted_triggers.array.buffer.data, num_triggers,
+                       sizeof(struct lttng_trigger *),
+                       compare_triggers_by_name);
+
+       for (i = 0; i < lttng_dynamic_pointer_array_get_count(&sorted_triggers);
+                       i++) {
+               const struct lttng_trigger *trigger_to_print = (const struct lttng_trigger
+                                               *)
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               &sorted_triggers, i);
+
+               print_one_trigger(trigger_to_print);
+       }
+
+       ret = 0;
+       goto end;
+error:
+       ret = 1;
+
+end:
+       lttng_dynamic_pointer_array_reset(&sorted_triggers);
+       return ret;
+}
+
+static enum lttng_error_code mi_error_query_trigger_callback(
+               const struct lttng_trigger *trigger,
+               struct lttng_error_query_results **results)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_error_query *query =
+                       lttng_error_query_trigger_create(trigger);
+
+       LTTNG_ASSERT(results);
+       LTTNG_ASSERT(query);
+
+       ret_code = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, results);
+       if (ret_code != LTTNG_OK) {
+               enum lttng_trigger_status trigger_status;
+               const char *trigger_name;
+               uid_t trigger_uid;
+
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               trigger_status = lttng_trigger_get_owner_uid(
+                               trigger, &trigger_uid);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               ERR("Failed to query errors of trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-ret_code));
+       }
+
+       lttng_error_query_destroy(query);
+       return ret_code;
+}
+
+static enum lttng_error_code mi_error_query_action_callback(
+               const struct lttng_trigger *trigger,
+               const struct lttng_action_path *action_path,
+               struct lttng_error_query_results **results)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_error_query *query =
+                       lttng_error_query_action_create(trigger, action_path);
+
+       LTTNG_ASSERT(results);
+       LTTNG_ASSERT(query);
+
+       ret_code = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, results);
+       if (ret_code != LTTNG_OK) {
+               enum lttng_trigger_status trigger_status;
+               const char *trigger_name;
+               uid_t trigger_uid;
+
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               trigger_status = lttng_trigger_get_owner_uid(
+                               trigger, &trigger_uid);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               ERR("Failed to query errors of an action for trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-ret_code));
+       }
+
+       lttng_error_query_destroy(query);
+       return ret_code;
+}
+
+static enum lttng_error_code mi_error_query_condition_callback(
+               const struct lttng_trigger *trigger,
+               struct lttng_error_query_results **results)
+{
+       enum lttng_error_code ret_code;
+       struct lttng_error_query *query =
+                       lttng_error_query_condition_create(trigger);
+
+       LTTNG_ASSERT(results);
+       LTTNG_ASSERT(query);
+
+       ret_code = lttng_error_query_execute(
+                       query, lttng_session_daemon_command_endpoint, results);
+       if (ret_code != LTTNG_OK) {
+               enum lttng_trigger_status trigger_status;
+               const char *trigger_name;
+               uid_t trigger_uid;
+
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               trigger_status = lttng_trigger_get_owner_uid(
+                               trigger, &trigger_uid);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               ERR("Failed to query errors of of condition for condition of trigger '%s' (owner uid: %d): %s",
+                               trigger_name, (int) trigger_uid,
+                               lttng_strerror(-ret_code));
+       }
+
+       lttng_error_query_destroy(query);
+       return ret_code;
+}
+
+int cmd_list_triggers(int argc, const char **argv)
+{
+       int ret;
+       struct argpar_parse_ret argpar_parse_ret = {};
+       struct lttng_triggers *triggers = NULL;
+       int i;
+       struct mi_writer *mi_writer = NULL;
+
+       argpar_parse_ret = argpar_parse(
+                       argc - 1, argv + 1, list_trigger_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               const struct argpar_item *item =
+                               argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = 0;
+                               goto end;
+
+                       case OPT_LIST_OPTIONS:
+                               list_cmd_options_argpar(
+                                               stdout, list_trigger_options);
+                               ret = 0;
+                               goto end;
+
+                       default:
+                               abort();
+                       }
+
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt =
+                               (const struct argpar_item_non_opt *) item;
+
+                       ERR("Unexpected argument: %s", item_non_opt->arg);
+               }
+       }
+
+       ret = lttng_list_triggers(&triggers);
+       if (ret != LTTNG_OK) {
+               ERR("Error listing triggers: %s.", lttng_strerror(-ret));
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               mi_writer = mi_lttng_writer_create(
+                               fileno(stdout), lttng_opt_mi);
+               if (!mi_writer) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open command element. */
+               ret = mi_lttng_writer_command_open(mi_writer,
+                               mi_lttng_element_command_list_trigger);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element. */
+               ret = mi_lttng_writer_open_element(
+                               mi_writer, mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       if (lttng_opt_mi) {
+               const struct mi_lttng_error_query_callbacks callbacks = {
+                       .trigger_cb = mi_error_query_trigger_callback,
+                       .condition_cb = mi_error_query_condition_callback,
+                       .action_cb = mi_error_query_action_callback,
+               };
+
+               ret = lttng_triggers_mi_serialize(
+                               triggers, mi_writer, &callbacks);
+               if (ret != LTTNG_OK) {
+                       ERR("Error printing MI triggers: %s.",
+                                       lttng_strerror(-ret));
+                       goto error;
+               }
+       } else {
+               ret = print_sorted_triggers(triggers);
+               if (ret) {
+                       ERR("Error printing triggers");
+                       goto error;
+               }
+       }
+
+       /* Mi closing. */
+       if (lttng_opt_mi) {
+               /* Close output element. */
+               ret = mi_lttng_writer_close_element(mi_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close. */
+               ret = mi_lttng_writer_command_close(mi_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+       lttng_triggers_destroy(triggers);
+       /* Mi clean-up. */
+       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
+               /* Preserve original error code. */
+               ret = ret ? ret : CMD_ERROR;
+       }
+       return ret;
+}
diff --git a/src/bin/lttng/commands/load.c b/src/bin/lttng/commands/load.c
deleted file mode 100644 (file)
index cdc3905..0000000
+++ /dev/null
@@ -1,376 +0,0 @@
-/*
- * Copyright (C) 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <inttypes.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <common/mi-lttng.h>
-#include <common/config/session-config.h>
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-static char *the_opt_input_path;
-static char *the_opt_override_url;
-static char *the_opt_override_session_name;
-static int the_opt_force;
-static int the_opt_load_all;
-
-static const char *the_session_name;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-load.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_ALL,
-       OPT_FORCE,
-       OPT_LIST_OPTIONS,
-};
-
-static struct mi_writer *the_writer;
-
-static struct poptOption the_load_opts[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",          'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"all",           'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0},
-       {"input-path",    'i', POPT_ARG_STRING, &the_opt_input_path, 0, 0, 0},
-       {"force",         'f', POPT_ARG_NONE, 0, OPT_FORCE, 0, 0},
-       {"override-url",    0, POPT_ARG_STRING, &the_opt_override_url, 0, 0, 0},
-       {"override-name",   0, POPT_ARG_STRING, &the_opt_override_session_name, 0, 0, 0},
-       {"list-options",    0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int mi_partial_session(const char *session_name)
-{
-       int ret;
-       LTTNG_ASSERT(the_writer);
-       LTTNG_ASSERT(session_name);
-
-       /* Open session element */
-       ret = mi_lttng_writer_open_element(the_writer, config_element_session);
-       if (ret) {
-               goto end;
-       }
-
-       ret = mi_lttng_writer_write_element_string(the_writer, config_element_name,
-                       session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Closing session element */
-       ret = mi_lttng_writer_close_element(the_writer);
-end:
-       return ret;
-}
-
-/*
- * Mi print of load command
- */
-static int mi_load_print(const char *session_name)
-{
-       int ret;
-       LTTNG_ASSERT(the_writer);
-
-       if (the_opt_load_all) {
-               /* We use a wildcard to represent all sessions */
-               session_name = "*";
-       }
-
-       /* Print load element */
-       ret = mi_lttng_writer_open_element(the_writer, mi_lttng_element_load);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print session element */
-       ret = mi_partial_session(session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Path element */
-       if (the_opt_input_path) {
-               ret = mi_lttng_writer_write_element_string(the_writer, config_element_path,
-                               the_opt_input_path);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Print override elements */
-       ret = mi_lttng_writer_open_element(the_writer, mi_lttng_element_load_overrides);
-       if (ret) {
-               goto end;
-       }
-
-       /* Session name override element */
-       if (the_opt_override_session_name) {
-               ret = mi_lttng_writer_write_element_string(the_writer,
-                               config_element_name, the_opt_override_session_name);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Session url override element */
-       if (the_opt_override_url) {
-               ret = mi_lttng_writer_write_element_string(the_writer,
-                               mi_lttng_element_load_override_url,
-                               the_opt_override_url);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close override and load element */
-       ret = mi_lttng_close_multi_element(the_writer, 2);
-end:
-       return ret;
-}
-
-/*
- * The 'load <options>' first level command
- */
-int cmd_load(int argc, const char **argv)
-{
-       int ret, success;
-       int opt;
-       poptContext pc;
-       struct lttng_load_session_attr *session_attr = NULL;
-       char *input_path = NULL;
-       const char *leftover = NULL;
-
-       pc = poptGetContext(NULL, argc, argv, the_load_opts, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       ret = CMD_SUCCESS;
-                       goto end;
-               case OPT_ALL:
-                       the_opt_load_all = 1;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, the_load_opts);
-                       ret = CMD_SUCCESS;
-                       goto end;
-               case OPT_FORCE:
-                       the_opt_force = 1;
-                       break;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       ret = lttng_session_daemon_alive();
-       if (!ret) {
-               ERR("No session daemon is available");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (!the_opt_load_all) {
-               the_session_name = poptGetArg(pc);
-               if (the_session_name) {
-                       DBG2("Loading session name: %s", the_session_name);
-               } else {
-                       /* Default to load_all */
-                       the_opt_load_all = 1;
-               }
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               the_writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!the_writer) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(the_writer,
-                               mi_lttng_element_command_load);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(the_writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       /* Prepare load attributes */
-       session_attr = lttng_load_session_attr_create();
-       if (!session_attr) {
-               ERR("Failed to create load session attributes");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /*
-        * Set the input url
-        * lttng_load_session_attr_set_input_url only suppports absolute path.
-        * Use realpath to resolve any relative path.
-        * */
-       if (the_opt_input_path) {
-               input_path = realpath(the_opt_input_path, NULL);
-               if (!input_path) {
-                       PERROR("Invalid input path");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               input_path = NULL;
-       }
-
-       ret = lttng_load_session_attr_set_input_url(session_attr,
-                       input_path);
-       if (ret) {
-               ERR("Invalid input path");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Set the session name. NULL means all sessions should be loaded */
-       ret = lttng_load_session_attr_set_session_name(session_attr,
-                       the_session_name);
-       if (ret) {
-               ERR("Invalid session name");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Set the overwrite attribute */
-       ret = lttng_load_session_attr_set_overwrite(session_attr, the_opt_force);
-       if (ret) {
-               ERR("Force argument could not be applied");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Set the overrides attributes if any */
-       if (the_opt_override_url) {
-               ret = lttng_load_session_attr_set_override_url(session_attr,
-                               the_opt_override_url);
-               if (ret) {
-                       ERR("Url override is invalid");
-                       goto end;
-               }
-       }
-
-       if (the_opt_override_session_name) {
-               if (the_opt_load_all) {
-                       ERR("Options --all and --override-name cannot be used simultaneously");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               ret = lttng_load_session_attr_set_override_session_name(session_attr,
-                               the_opt_override_session_name);
-               if (ret) {
-                       ERR("Failed to set session name override");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       ret = lttng_load_session(session_attr);
-       if (ret) {
-               ERR("%s", lttng_strerror(ret));
-               success = 0;
-               ret = CMD_ERROR;
-       } else {
-               if (the_opt_load_all) {
-                       MSG("All sessions have been loaded successfully");
-               } else if (the_session_name) {
-                       ret = config_init((char *) the_session_name);
-                       if (ret < 0) {
-                               WARN("Could not set %s as the default session",
-                                               the_session_name);
-                       }
-                       MSG("Session %s has been loaded successfully", the_session_name);
-               } else {
-                       MSG("Session has been loaded successfully");
-               }
-
-               if (the_opt_override_session_name) {
-                       MSG("Session name overridden with %s",
-                                       the_opt_override_session_name);
-               }
-
-               if (the_opt_override_url) {
-                       MSG("Session output url overridden with %s", the_opt_override_url);
-               }
-               success = 1;
-               ret = CMD_SUCCESS;
-       }
-
-       /* Mi Printing and closing */
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_load_print(the_session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(the_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(the_writer,
-                               mi_lttng_element_command_success, success);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(the_writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-end:
-       if (the_writer && mi_lttng_writer_destroy(the_writer)) {
-               ERR("Failed to destroy mi lttng writer");
-       }
-
-       lttng_load_session_attr_destroy(session_attr);
-       free(input_path);
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/load.cpp b/src/bin/lttng/commands/load.cpp
new file mode 100644 (file)
index 0000000..cdc3905
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2014 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <inttypes.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/mi-lttng.h>
+#include <common/config/session-config.h>
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+static char *the_opt_input_path;
+static char *the_opt_override_url;
+static char *the_opt_override_session_name;
+static int the_opt_force;
+static int the_opt_load_all;
+
+static const char *the_session_name;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-load.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_ALL,
+       OPT_FORCE,
+       OPT_LIST_OPTIONS,
+};
+
+static struct mi_writer *the_writer;
+
+static struct poptOption the_load_opts[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",          'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"all",           'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0},
+       {"input-path",    'i', POPT_ARG_STRING, &the_opt_input_path, 0, 0, 0},
+       {"force",         'f', POPT_ARG_NONE, 0, OPT_FORCE, 0, 0},
+       {"override-url",    0, POPT_ARG_STRING, &the_opt_override_url, 0, 0, 0},
+       {"override-name",   0, POPT_ARG_STRING, &the_opt_override_session_name, 0, 0, 0},
+       {"list-options",    0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int mi_partial_session(const char *session_name)
+{
+       int ret;
+       LTTNG_ASSERT(the_writer);
+       LTTNG_ASSERT(session_name);
+
+       /* Open session element */
+       ret = mi_lttng_writer_open_element(the_writer, config_element_session);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_writer_write_element_string(the_writer, config_element_name,
+                       session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Closing session element */
+       ret = mi_lttng_writer_close_element(the_writer);
+end:
+       return ret;
+}
+
+/*
+ * Mi print of load command
+ */
+static int mi_load_print(const char *session_name)
+{
+       int ret;
+       LTTNG_ASSERT(the_writer);
+
+       if (the_opt_load_all) {
+               /* We use a wildcard to represent all sessions */
+               session_name = "*";
+       }
+
+       /* Print load element */
+       ret = mi_lttng_writer_open_element(the_writer, mi_lttng_element_load);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print session element */
+       ret = mi_partial_session(session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Path element */
+       if (the_opt_input_path) {
+               ret = mi_lttng_writer_write_element_string(the_writer, config_element_path,
+                               the_opt_input_path);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Print override elements */
+       ret = mi_lttng_writer_open_element(the_writer, mi_lttng_element_load_overrides);
+       if (ret) {
+               goto end;
+       }
+
+       /* Session name override element */
+       if (the_opt_override_session_name) {
+               ret = mi_lttng_writer_write_element_string(the_writer,
+                               config_element_name, the_opt_override_session_name);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Session url override element */
+       if (the_opt_override_url) {
+               ret = mi_lttng_writer_write_element_string(the_writer,
+                               mi_lttng_element_load_override_url,
+                               the_opt_override_url);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close override and load element */
+       ret = mi_lttng_close_multi_element(the_writer, 2);
+end:
+       return ret;
+}
+
+/*
+ * The 'load <options>' first level command
+ */
+int cmd_load(int argc, const char **argv)
+{
+       int ret, success;
+       int opt;
+       poptContext pc;
+       struct lttng_load_session_attr *session_attr = NULL;
+       char *input_path = NULL;
+       const char *leftover = NULL;
+
+       pc = poptGetContext(NULL, argc, argv, the_load_opts, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       ret = CMD_SUCCESS;
+                       goto end;
+               case OPT_ALL:
+                       the_opt_load_all = 1;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, the_load_opts);
+                       ret = CMD_SUCCESS;
+                       goto end;
+               case OPT_FORCE:
+                       the_opt_force = 1;
+                       break;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       ret = lttng_session_daemon_alive();
+       if (!ret) {
+               ERR("No session daemon is available");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (!the_opt_load_all) {
+               the_session_name = poptGetArg(pc);
+               if (the_session_name) {
+                       DBG2("Loading session name: %s", the_session_name);
+               } else {
+                       /* Default to load_all */
+                       the_opt_load_all = 1;
+               }
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               the_writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!the_writer) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(the_writer,
+                               mi_lttng_element_command_load);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(the_writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       /* Prepare load attributes */
+       session_attr = lttng_load_session_attr_create();
+       if (!session_attr) {
+               ERR("Failed to create load session attributes");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /*
+        * Set the input url
+        * lttng_load_session_attr_set_input_url only suppports absolute path.
+        * Use realpath to resolve any relative path.
+        * */
+       if (the_opt_input_path) {
+               input_path = realpath(the_opt_input_path, NULL);
+               if (!input_path) {
+                       PERROR("Invalid input path");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               input_path = NULL;
+       }
+
+       ret = lttng_load_session_attr_set_input_url(session_attr,
+                       input_path);
+       if (ret) {
+               ERR("Invalid input path");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Set the session name. NULL means all sessions should be loaded */
+       ret = lttng_load_session_attr_set_session_name(session_attr,
+                       the_session_name);
+       if (ret) {
+               ERR("Invalid session name");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Set the overwrite attribute */
+       ret = lttng_load_session_attr_set_overwrite(session_attr, the_opt_force);
+       if (ret) {
+               ERR("Force argument could not be applied");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Set the overrides attributes if any */
+       if (the_opt_override_url) {
+               ret = lttng_load_session_attr_set_override_url(session_attr,
+                               the_opt_override_url);
+               if (ret) {
+                       ERR("Url override is invalid");
+                       goto end;
+               }
+       }
+
+       if (the_opt_override_session_name) {
+               if (the_opt_load_all) {
+                       ERR("Options --all and --override-name cannot be used simultaneously");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               ret = lttng_load_session_attr_set_override_session_name(session_attr,
+                               the_opt_override_session_name);
+               if (ret) {
+                       ERR("Failed to set session name override");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       ret = lttng_load_session(session_attr);
+       if (ret) {
+               ERR("%s", lttng_strerror(ret));
+               success = 0;
+               ret = CMD_ERROR;
+       } else {
+               if (the_opt_load_all) {
+                       MSG("All sessions have been loaded successfully");
+               } else if (the_session_name) {
+                       ret = config_init((char *) the_session_name);
+                       if (ret < 0) {
+                               WARN("Could not set %s as the default session",
+                                               the_session_name);
+                       }
+                       MSG("Session %s has been loaded successfully", the_session_name);
+               } else {
+                       MSG("Session has been loaded successfully");
+               }
+
+               if (the_opt_override_session_name) {
+                       MSG("Session name overridden with %s",
+                                       the_opt_override_session_name);
+               }
+
+               if (the_opt_override_url) {
+                       MSG("Session output url overridden with %s", the_opt_override_url);
+               }
+               success = 1;
+               ret = CMD_SUCCESS;
+       }
+
+       /* Mi Printing and closing */
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_load_print(the_session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(the_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(the_writer,
+                               mi_lttng_element_command_success, success);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(the_writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+end:
+       if (the_writer && mi_lttng_writer_destroy(the_writer)) {
+               ERR("Failed to destroy mi lttng writer");
+       }
+
+       lttng_load_session_attr_destroy(session_attr);
+       free(input_path);
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/metadata.c b/src/bin/lttng/commands/metadata.c
deleted file mode 100644 (file)
index 35aea00..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * Copyright (C) 2015 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <ctype.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-static char *opt_session_name;
-static char *session_name = NULL;
-
-static int metadata_regenerate(int argc, const char **argv);
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-metadata.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_LIST_COMMANDS,
-};
-
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
-       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
-       { "session",            's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
-       { "list-commands",      0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
-       { 0, 0, 0, 0, 0, 0, 0, },
-};
-
-static struct cmd_struct actions[] = {
-       { "regenerate", metadata_regenerate },
-       { NULL, NULL }  /* Array closure */
-};
-
-/*
- * Count and return the number of arguments in argv.
- */
-static int count_arguments(const char **argv)
-{
-       int i = 0;
-
-       LTTNG_ASSERT(argv);
-
-       while (argv[i] != NULL) {
-               i++;
-       }
-
-       return i;
-}
-
-static int metadata_regenerate(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc > 1) {
-               ret = CMD_UNDEFINED;
-               goto end;
-       }
-       ret = lttng_regenerate_metadata(session_name);
-       if (ret == 0) {
-               MSG("Metadata successfully regenerated for session %s", session_name);
-       } else {
-               ERR("%s", lttng_strerror(ret));
-       }
-
-end:
-       return ret;
-}
-
-static int handle_command(const char **argv)
-{
-       struct cmd_struct *cmd;
-       int ret = CMD_SUCCESS, i = 0, argc, command_ret = CMD_SUCCESS;
-
-       if (argv == NULL) {
-               ERR("No action specified for metadata command.");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       argc = count_arguments(argv);
-       LTTNG_ASSERT(argc >= 1);
-
-       cmd = &actions[i];
-       while (cmd->func != NULL) {
-               /* Find command */
-               if (strcmp(argv[0], cmd->name) == 0) {
-                       if (lttng_opt_mi) {
-                               /* Action element */
-                               ret = mi_lttng_writer_open_element(writer,
-                                               mi_lttng_element_command_metadata_action);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               /* Name of the action */
-                               ret = mi_lttng_writer_write_element_string(writer,
-                                               config_element_name, argv[0]);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-                       command_ret = cmd->func(argc, argv);
-                       if (lttng_opt_mi) {
-                               /* Close output and action element */
-                               ret = mi_lttng_writer_close_element(writer);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-                       goto end;
-               }
-
-               cmd = &actions[i++];
-       }
-
-       ret = CMD_UNDEFINED;
-
-end:
-       /* Overwrite ret if an error occurred in cmd->func() */
-       ret = command_ret ? command_ret : ret;
-       return ret;
-}
-
-/*
- * Metadata command handling.
- */
-int cmd_metadata(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-
-       if (argc < 1) {
-               SHOW_HELP();
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_metadata);
-               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;
-               }
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_LIST_COMMANDS:
-                       list_commands(actions, stdout);
-                       goto end;
-               default:
-                       SHOW_HELP();
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       command_ret = handle_command(poptGetArgs(pc));
-       if (command_ret) {
-               success = 0;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       if (!opt_session_name) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred during handle_command() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/metadata.cpp b/src/bin/lttng/commands/metadata.cpp
new file mode 100644 (file)
index 0000000..35aea00
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * Copyright (C) 2015 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <ctype.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_session_name;
+static char *session_name = NULL;
+
+static int metadata_regenerate(int argc, const char **argv);
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-metadata.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_LIST_COMMANDS,
+};
+
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
+       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
+       { "session",            's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
+       { "list-commands",      0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
+       { 0, 0, 0, 0, 0, 0, 0, },
+};
+
+static struct cmd_struct actions[] = {
+       { "regenerate", metadata_regenerate },
+       { NULL, NULL }  /* Array closure */
+};
+
+/*
+ * Count and return the number of arguments in argv.
+ */
+static int count_arguments(const char **argv)
+{
+       int i = 0;
+
+       LTTNG_ASSERT(argv);
+
+       while (argv[i] != NULL) {
+               i++;
+       }
+
+       return i;
+}
+
+static int metadata_regenerate(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc > 1) {
+               ret = CMD_UNDEFINED;
+               goto end;
+       }
+       ret = lttng_regenerate_metadata(session_name);
+       if (ret == 0) {
+               MSG("Metadata successfully regenerated for session %s", session_name);
+       } else {
+               ERR("%s", lttng_strerror(ret));
+       }
+
+end:
+       return ret;
+}
+
+static int handle_command(const char **argv)
+{
+       struct cmd_struct *cmd;
+       int ret = CMD_SUCCESS, i = 0, argc, command_ret = CMD_SUCCESS;
+
+       if (argv == NULL) {
+               ERR("No action specified for metadata command.");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       argc = count_arguments(argv);
+       LTTNG_ASSERT(argc >= 1);
+
+       cmd = &actions[i];
+       while (cmd->func != NULL) {
+               /* Find command */
+               if (strcmp(argv[0], cmd->name) == 0) {
+                       if (lttng_opt_mi) {
+                               /* Action element */
+                               ret = mi_lttng_writer_open_element(writer,
+                                               mi_lttng_element_command_metadata_action);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               /* Name of the action */
+                               ret = mi_lttng_writer_write_element_string(writer,
+                                               config_element_name, argv[0]);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+                       command_ret = cmd->func(argc, argv);
+                       if (lttng_opt_mi) {
+                               /* Close output and action element */
+                               ret = mi_lttng_writer_close_element(writer);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+                       goto end;
+               }
+
+               cmd = &actions[i++];
+       }
+
+       ret = CMD_UNDEFINED;
+
+end:
+       /* Overwrite ret if an error occurred in cmd->func() */
+       ret = command_ret ? command_ret : ret;
+       return ret;
+}
+
+/*
+ * Metadata command handling.
+ */
+int cmd_metadata(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+
+       if (argc < 1) {
+               SHOW_HELP();
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_metadata);
+               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;
+               }
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_LIST_COMMANDS:
+                       list_commands(actions, stdout);
+                       goto end;
+               default:
+                       SHOW_HELP();
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       command_ret = handle_command(poptGetArgs(pc));
+       if (command_ret) {
+               success = 0;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       if (!opt_session_name) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred during handle_command() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/regenerate.c b/src/bin/lttng/commands/regenerate.c
deleted file mode 100644 (file)
index 0e904f8..0000000
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * Copyright (C) 2015 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <ctype.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-static char *opt_session_name;
-static char *session_name = NULL;
-
-static int regenerate_metadata(int argc, const char **argv);
-static int regenerate_statedump(int argc, const char **argv);
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-regenerate.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_LIST_COMMANDS,
-};
-
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
-       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
-       { "session",            's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
-       { "list-commands",      0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
-       { 0, 0, 0, 0, 0, 0, 0, },
-};
-
-static struct cmd_struct actions[] = {
-       { "metadata", regenerate_metadata },
-       { "statedump", regenerate_statedump },
-       { NULL, NULL }  /* Array closure */
-};
-
-/*
- * Count and return the number of arguments in argv.
- */
-static int count_arguments(const char **argv)
-{
-       int i = 0;
-
-       LTTNG_ASSERT(argv);
-
-       while (argv[i] != NULL) {
-               i++;
-       }
-
-       return i;
-}
-
-static int regenerate_metadata(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc > 1) {
-               ret = CMD_UNDEFINED;
-               goto end;
-       }
-       ret = lttng_regenerate_metadata(session_name);
-       if (ret == 0) {
-               MSG("Metadata successfully regenerated for session %s", session_name);
-       } else {
-               ERR("%s", lttng_strerror(ret));
-       }
-
-end:
-       return ret;
-}
-
-static int regenerate_statedump(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc > 1) {
-               ret = -LTTNG_ERR_INVALID;
-               goto end;
-       }
-       ret = lttng_regenerate_statedump(session_name);
-       if (ret == 0) {
-               MSG("State dump successfully regenerated for session %s", session_name);
-       }
-
-end:
-       return ret;
-}
-
-static int handle_command(const char **argv)
-{
-       struct cmd_struct *cmd;
-       int ret = CMD_SUCCESS, i = 0, argc, command_ret = CMD_SUCCESS;
-
-       if (argv == NULL) {
-               ERR("No object specified for regenerate command.");
-               command_ret = CMD_ERROR;
-               goto end;
-       }
-
-       argc = count_arguments(argv);
-       LTTNG_ASSERT(argc >= 1);
-
-       cmd = &actions[i];
-       while (cmd->func != NULL) {
-               /* Find command */
-               if (strcmp(argv[0], cmd->name) == 0) {
-                       if (lttng_opt_mi) {
-                               /* Action element */
-                               ret = mi_lttng_writer_open_element(writer,
-                                               mi_lttng_element_command_regenerate_action);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               /* Name of the action */
-                               ret = mi_lttng_writer_write_element_string(writer,
-                                               config_element_name, argv[0]);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-                       command_ret = cmd->func(argc, argv);
-                       if (lttng_opt_mi) {
-                               /* Close output and action element */
-                               ret = mi_lttng_writer_close_element(writer);
-                               if (ret) {
-                                       ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-                       goto end;
-               }
-
-               cmd = &actions[i++];
-       }
-
-       ret = CMD_UNDEFINED;
-
-end:
-       /* Overwrite ret if an error occurred in cmd->func() */
-       ret = command_ret ? command_ret : ret;
-       return ret;
-}
-
-/*
- * regenerate command handling.
- */
-int cmd_regenerate(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-
-       if (argc < 1) {
-               SHOW_HELP();
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_regenerate);
-               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;
-               }
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_LIST_COMMANDS:
-                       list_commands(actions, stdout);
-                       goto end;
-               default:
-                       SHOW_HELP();
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       command_ret = handle_command(poptGetArgs(pc));
-       if (command_ret) {
-               success = 0;
-       }
-
-       if (lttng_opt_mi) {
-               /* Close output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       if (!opt_session_name) {
-               free(session_name);
-       }
-
-       /* Overwrite ret if an error occurred during handle_command() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/regenerate.cpp b/src/bin/lttng/commands/regenerate.cpp
new file mode 100644 (file)
index 0000000..0e904f8
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2015 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <ctype.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_session_name;
+static char *session_name = NULL;
+
+static int regenerate_metadata(int argc, const char **argv);
+static int regenerate_statedump(int argc, const char **argv);
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-regenerate.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_LIST_COMMANDS,
+};
+
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
+       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
+       { "session",            's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
+       { "list-commands",      0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
+       { 0, 0, 0, 0, 0, 0, 0, },
+};
+
+static struct cmd_struct actions[] = {
+       { "metadata", regenerate_metadata },
+       { "statedump", regenerate_statedump },
+       { NULL, NULL }  /* Array closure */
+};
+
+/*
+ * Count and return the number of arguments in argv.
+ */
+static int count_arguments(const char **argv)
+{
+       int i = 0;
+
+       LTTNG_ASSERT(argv);
+
+       while (argv[i] != NULL) {
+               i++;
+       }
+
+       return i;
+}
+
+static int regenerate_metadata(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc > 1) {
+               ret = CMD_UNDEFINED;
+               goto end;
+       }
+       ret = lttng_regenerate_metadata(session_name);
+       if (ret == 0) {
+               MSG("Metadata successfully regenerated for session %s", session_name);
+       } else {
+               ERR("%s", lttng_strerror(ret));
+       }
+
+end:
+       return ret;
+}
+
+static int regenerate_statedump(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc > 1) {
+               ret = -LTTNG_ERR_INVALID;
+               goto end;
+       }
+       ret = lttng_regenerate_statedump(session_name);
+       if (ret == 0) {
+               MSG("State dump successfully regenerated for session %s", session_name);
+       }
+
+end:
+       return ret;
+}
+
+static int handle_command(const char **argv)
+{
+       struct cmd_struct *cmd;
+       int ret = CMD_SUCCESS, i = 0, argc, command_ret = CMD_SUCCESS;
+
+       if (argv == NULL) {
+               ERR("No object specified for regenerate command.");
+               command_ret = CMD_ERROR;
+               goto end;
+       }
+
+       argc = count_arguments(argv);
+       LTTNG_ASSERT(argc >= 1);
+
+       cmd = &actions[i];
+       while (cmd->func != NULL) {
+               /* Find command */
+               if (strcmp(argv[0], cmd->name) == 0) {
+                       if (lttng_opt_mi) {
+                               /* Action element */
+                               ret = mi_lttng_writer_open_element(writer,
+                                               mi_lttng_element_command_regenerate_action);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               /* Name of the action */
+                               ret = mi_lttng_writer_write_element_string(writer,
+                                               config_element_name, argv[0]);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+                       command_ret = cmd->func(argc, argv);
+                       if (lttng_opt_mi) {
+                               /* Close output and action element */
+                               ret = mi_lttng_writer_close_element(writer);
+                               if (ret) {
+                                       ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+                       goto end;
+               }
+
+               cmd = &actions[i++];
+       }
+
+       ret = CMD_UNDEFINED;
+
+end:
+       /* Overwrite ret if an error occurred in cmd->func() */
+       ret = command_ret ? command_ret : ret;
+       return ret;
+}
+
+/*
+ * regenerate command handling.
+ */
+int cmd_regenerate(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+
+       if (argc < 1) {
+               SHOW_HELP();
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_regenerate);
+               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;
+               }
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_LIST_COMMANDS:
+                       list_commands(actions, stdout);
+                       goto end;
+               default:
+                       SHOW_HELP();
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       command_ret = handle_command(poptGetArgs(pc));
+       if (command_ret) {
+               success = 0;
+       }
+
+       if (lttng_opt_mi) {
+               /* Close output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       if (!opt_session_name) {
+               free(session_name);
+       }
+
+       /* Overwrite ret if an error occurred during handle_command() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/remove_trigger.c b/src/bin/lttng/commands/remove_trigger.c
deleted file mode 100644 (file)
index 2ac237c..0000000
+++ /dev/null
@@ -1,263 +0,0 @@
-/*
- * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include "../command.h"
-#include "common/argpar/argpar.h"
-#include "common/mi-lttng.h"
-#include <lttng/lttng.h>
-#include <stdio.h>
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-remove-trigger.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP,
-       OPT_LIST_OPTIONS,
-       OPT_OWNER_UID,
-};
-
-static const
-struct argpar_opt_descr remove_trigger_options[] = {
-       { OPT_HELP, 'h', "help", false },
-       { OPT_LIST_OPTIONS, '\0', "list-options", false },
-       { OPT_OWNER_UID, '\0', "owner-uid", true },
-       ARGPAR_OPT_DESCR_SENTINEL,
-};
-
-static
-bool assign_string(char **dest, const char *src, const char *opt_name)
-{
-       bool ret;
-
-       if (*dest) {
-               ERR("Duplicate option '%s' given.", opt_name);
-               goto error;
-       }
-
-       *dest = strdup(src);
-       if (!*dest) {
-               ERR("Failed to allocate '%s' string.", opt_name);
-               goto error;
-       }
-
-       ret = true;
-       goto end;
-
-error:
-       ret = false;
-
-end:
-       return ret;
-}
-
-int cmd_remove_trigger(int argc, const char **argv)
-{
-       enum lttng_error_code ret_code;
-       int ret;
-       struct argpar_parse_ret argpar_parse_ret = {};
-       const char *name = NULL;
-       int i;
-       struct lttng_triggers *triggers = NULL;
-       unsigned int triggers_count;
-       enum lttng_trigger_status trigger_status;
-       const struct lttng_trigger *trigger_to_remove = NULL;
-       char *owner_uid = NULL;
-       long long uid;
-       struct mi_writer *mi_writer = NULL;
-
-       if (lttng_opt_mi) {
-               mi_writer = mi_lttng_writer_create(
-                               fileno(stdout), lttng_opt_mi);
-               if (!mi_writer) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               /* Open command element. */
-               ret = mi_lttng_writer_command_open(mi_writer,
-                               mi_lttng_element_command_remove_trigger);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-
-               /* Open output element. */
-               ret = mi_lttng_writer_open_element(
-                               mi_writer, mi_lttng_element_command_output);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
-               remove_trigger_options, true);
-       if (!argpar_parse_ret.items) {
-               ERR("%s", argpar_parse_ret.error);
-               goto error;
-       }
-
-       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
-               const struct argpar_item *item =
-                               argpar_parse_ret.items->items[i];
-
-               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
-                       const struct argpar_item_opt *item_opt =
-                                       (const struct argpar_item_opt *) item;
-
-                       switch (item_opt->descr->id) {
-                       case OPT_HELP:
-                               SHOW_HELP();
-                               ret = 0;
-                               goto end;
-                       case OPT_LIST_OPTIONS:
-                               list_cmd_options_argpar(stdout,
-                                       remove_trigger_options);
-                               ret = 0;
-                               goto end;
-                       case OPT_OWNER_UID:
-                       {
-                               if (!assign_string(&owner_uid, item_opt->arg,
-                                               "--owner-uid")) {
-                                       goto error;
-                               }
-                               break;
-                       }
-                       default:
-                               abort();
-                       }
-               } else {
-                       const struct argpar_item_non_opt *item_non_opt =
-                                       (const struct argpar_item_non_opt *) item;
-
-                       if (name) {
-                               ERR("Unexpected argument '%s'", item_non_opt->arg);
-                               goto error;
-                       }
-
-                       name = item_non_opt->arg;
-               }
-       }
-
-       if (!name) {
-               ERR("Missing `name` argument.");
-               goto error;
-       }
-
-       if (owner_uid) {
-               char *end;
-
-               errno = 0;
-               uid = strtol(owner_uid, &end, 10);
-               if (end == owner_uid || *end != '\0' || errno != 0) {
-                       ERR("Failed to parse `%s` as an integer.", owner_uid);
-               }
-       } else {
-               uid = geteuid();
-       }
-
-       ret = lttng_list_triggers(&triggers);
-       if (ret != LTTNG_OK) {
-               ERR("Failed to get the list of triggers.");
-               goto error;
-       }
-
-       trigger_status = lttng_triggers_get_count(triggers, &triggers_count);
-       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-       for (i = 0; i < triggers_count; i++) {
-               const struct lttng_trigger *trigger;
-               const char *trigger_name;
-               uid_t trigger_uid;
-
-               trigger = lttng_triggers_get_at_index(triggers, i);
-               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
-               switch (trigger_status) {
-               case LTTNG_TRIGGER_STATUS_OK:
-                       break;
-               case LTTNG_TRIGGER_STATUS_UNSET:
-                       /* Don't compare against anonymous triggers. */
-                       continue;
-               default:
-                       abort();
-               }
-
-               trigger_status = lttng_trigger_get_owner_uid(
-                               trigger, &trigger_uid);
-               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
-
-               if (trigger_uid == uid && strcmp(trigger_name, name) == 0) {
-                       trigger_to_remove = trigger;
-                       break;
-               }
-       }
-
-       if (!trigger_to_remove) {
-               ERR("Couldn't find trigger with name `%s`.", name);
-               goto error;
-       }
-
-       ret = lttng_unregister_trigger(trigger_to_remove);
-       if (ret != 0) {
-               ERR("Failed to unregister trigger `%s`.", name);
-               goto error;
-       }
-
-       if (lttng_opt_mi) {
-               ret_code = lttng_trigger_mi_serialize(
-                               trigger_to_remove, mi_writer, NULL);
-               if (ret_code != LTTNG_OK) {
-                       goto error;
-               }
-       }
-       MSG("Removed trigger `%s`.", name);
-
-       ret = 0;
-       goto end;
-
-error:
-       ret = 1;
-
-end:
-       /* Mi closing. */
-       if (lttng_opt_mi && mi_writer) {
-               /* Close output element. */
-               int mi_ret = mi_lttng_writer_close_element(mi_writer);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-
-               mi_ret = mi_lttng_writer_write_element_bool(mi_writer,
-                               mi_lttng_element_command_success, ret ? 0 : 1);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-
-               /* Command element close. */
-               mi_ret = mi_lttng_writer_command_close(mi_writer);
-               if (mi_ret) {
-                       ret = 1;
-                       goto cleanup;
-               }
-       }
-
-cleanup:
-       argpar_parse_ret_fini(&argpar_parse_ret);
-       lttng_triggers_destroy(triggers);
-       free(owner_uid);
-
-       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
-               /* Preserve original error code. */
-               ret = ret ? ret : CMD_ERROR;
-       }
-       return ret;
-}
diff --git a/src/bin/lttng/commands/remove_trigger.cpp b/src/bin/lttng/commands/remove_trigger.cpp
new file mode 100644 (file)
index 0000000..2ac237c
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Copyright (C) 2021 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "../command.h"
+#include "common/argpar/argpar.h"
+#include "common/mi-lttng.h"
+#include <lttng/lttng.h>
+#include <stdio.h>
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-remove-trigger.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP,
+       OPT_LIST_OPTIONS,
+       OPT_OWNER_UID,
+};
+
+static const
+struct argpar_opt_descr remove_trigger_options[] = {
+       { OPT_HELP, 'h', "help", false },
+       { OPT_LIST_OPTIONS, '\0', "list-options", false },
+       { OPT_OWNER_UID, '\0', "owner-uid", true },
+       ARGPAR_OPT_DESCR_SENTINEL,
+};
+
+static
+bool assign_string(char **dest, const char *src, const char *opt_name)
+{
+       bool ret;
+
+       if (*dest) {
+               ERR("Duplicate option '%s' given.", opt_name);
+               goto error;
+       }
+
+       *dest = strdup(src);
+       if (!*dest) {
+               ERR("Failed to allocate '%s' string.", opt_name);
+               goto error;
+       }
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int cmd_remove_trigger(int argc, const char **argv)
+{
+       enum lttng_error_code ret_code;
+       int ret;
+       struct argpar_parse_ret argpar_parse_ret = {};
+       const char *name = NULL;
+       int i;
+       struct lttng_triggers *triggers = NULL;
+       unsigned int triggers_count;
+       enum lttng_trigger_status trigger_status;
+       const struct lttng_trigger *trigger_to_remove = NULL;
+       char *owner_uid = NULL;
+       long long uid;
+       struct mi_writer *mi_writer = NULL;
+
+       if (lttng_opt_mi) {
+               mi_writer = mi_lttng_writer_create(
+                               fileno(stdout), lttng_opt_mi);
+               if (!mi_writer) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               /* Open command element. */
+               ret = mi_lttng_writer_command_open(mi_writer,
+                               mi_lttng_element_command_remove_trigger);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+
+               /* Open output element. */
+               ret = mi_lttng_writer_open_element(
+                               mi_writer, mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       argpar_parse_ret = argpar_parse(argc - 1, argv + 1,
+               remove_trigger_options, true);
+       if (!argpar_parse_ret.items) {
+               ERR("%s", argpar_parse_ret.error);
+               goto error;
+       }
+
+       for (i = 0; i < argpar_parse_ret.items->n_items; i++) {
+               const struct argpar_item *item =
+                               argpar_parse_ret.items->items[i];
+
+               if (item->type == ARGPAR_ITEM_TYPE_OPT) {
+                       const struct argpar_item_opt *item_opt =
+                                       (const struct argpar_item_opt *) item;
+
+                       switch (item_opt->descr->id) {
+                       case OPT_HELP:
+                               SHOW_HELP();
+                               ret = 0;
+                               goto end;
+                       case OPT_LIST_OPTIONS:
+                               list_cmd_options_argpar(stdout,
+                                       remove_trigger_options);
+                               ret = 0;
+                               goto end;
+                       case OPT_OWNER_UID:
+                       {
+                               if (!assign_string(&owner_uid, item_opt->arg,
+                                               "--owner-uid")) {
+                                       goto error;
+                               }
+                               break;
+                       }
+                       default:
+                               abort();
+                       }
+               } else {
+                       const struct argpar_item_non_opt *item_non_opt =
+                                       (const struct argpar_item_non_opt *) item;
+
+                       if (name) {
+                               ERR("Unexpected argument '%s'", item_non_opt->arg);
+                               goto error;
+                       }
+
+                       name = item_non_opt->arg;
+               }
+       }
+
+       if (!name) {
+               ERR("Missing `name` argument.");
+               goto error;
+       }
+
+       if (owner_uid) {
+               char *end;
+
+               errno = 0;
+               uid = strtol(owner_uid, &end, 10);
+               if (end == owner_uid || *end != '\0' || errno != 0) {
+                       ERR("Failed to parse `%s` as an integer.", owner_uid);
+               }
+       } else {
+               uid = geteuid();
+       }
+
+       ret = lttng_list_triggers(&triggers);
+       if (ret != LTTNG_OK) {
+               ERR("Failed to get the list of triggers.");
+               goto error;
+       }
+
+       trigger_status = lttng_triggers_get_count(triggers, &triggers_count);
+       LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+       for (i = 0; i < triggers_count; i++) {
+               const struct lttng_trigger *trigger;
+               const char *trigger_name;
+               uid_t trigger_uid;
+
+               trigger = lttng_triggers_get_at_index(triggers, i);
+               trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+               switch (trigger_status) {
+               case LTTNG_TRIGGER_STATUS_OK:
+                       break;
+               case LTTNG_TRIGGER_STATUS_UNSET:
+                       /* Don't compare against anonymous triggers. */
+                       continue;
+               default:
+                       abort();
+               }
+
+               trigger_status = lttng_trigger_get_owner_uid(
+                               trigger, &trigger_uid);
+               LTTNG_ASSERT(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+               if (trigger_uid == uid && strcmp(trigger_name, name) == 0) {
+                       trigger_to_remove = trigger;
+                       break;
+               }
+       }
+
+       if (!trigger_to_remove) {
+               ERR("Couldn't find trigger with name `%s`.", name);
+               goto error;
+       }
+
+       ret = lttng_unregister_trigger(trigger_to_remove);
+       if (ret != 0) {
+               ERR("Failed to unregister trigger `%s`.", name);
+               goto error;
+       }
+
+       if (lttng_opt_mi) {
+               ret_code = lttng_trigger_mi_serialize(
+                               trigger_to_remove, mi_writer, NULL);
+               if (ret_code != LTTNG_OK) {
+                       goto error;
+               }
+       }
+       MSG("Removed trigger `%s`.", name);
+
+       ret = 0;
+       goto end;
+
+error:
+       ret = 1;
+
+end:
+       /* Mi closing. */
+       if (lttng_opt_mi && mi_writer) {
+               /* Close output element. */
+               int mi_ret = mi_lttng_writer_close_element(mi_writer);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+
+               mi_ret = mi_lttng_writer_write_element_bool(mi_writer,
+                               mi_lttng_element_command_success, ret ? 0 : 1);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+
+               /* Command element close. */
+               mi_ret = mi_lttng_writer_command_close(mi_writer);
+               if (mi_ret) {
+                       ret = 1;
+                       goto cleanup;
+               }
+       }
+
+cleanup:
+       argpar_parse_ret_fini(&argpar_parse_ret);
+       lttng_triggers_destroy(triggers);
+       free(owner_uid);
+
+       if (mi_writer && mi_lttng_writer_destroy(mi_writer)) {
+               /* Preserve original error code. */
+               ret = ret ? ret : CMD_ERROR;
+       }
+       return ret;
+}
diff --git a/src/bin/lttng/commands/rotate.c b/src/bin/lttng/commands/rotate.c
deleted file mode 100644 (file)
index aa0923c..0000000
+++ /dev/null
@@ -1,262 +0,0 @@
-/*
- * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-#include <inttypes.h>
-#include <ctype.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-#include <lttng/lttng.h>
-
-static char *opt_session_name;
-static int opt_no_wait;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-rotate.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int rotate_tracing(char *session_name)
-{
-       int ret;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       struct lttng_rotation_handle *handle = NULL;
-       enum lttng_rotation_status rotation_status;
-       enum lttng_rotation_state rotation_state = LTTNG_ROTATION_STATE_ONGOING;
-       const struct lttng_trace_archive_location *location = NULL;
-       bool print_location = true;
-
-       DBG("Rotating the output files of session %s", session_name);
-
-       ret = lttng_rotate_session(session_name, NULL, &handle);
-       if (ret < 0) {
-               switch (-ret) {
-               case LTTNG_ERR_SESSION_NOT_STARTED:
-                       WARN("Tracing session %s not started yet", session_name);
-                       cmd_ret = CMD_WARNING;
-                       goto end;
-               default:
-                       ERR("%s", lttng_strerror(ret));
-                       goto error;
-               }
-       }
-
-       if (opt_no_wait) {
-               rotation_state = LTTNG_ROTATION_STATE_ONGOING;
-               goto skip_wait;
-       }
-
-       _MSG("Waiting for rotation to complete");
-       ret = fflush(stdout);
-       if (ret) {
-               PERROR("fflush");
-               goto error;
-       }
-
-       do {
-               rotation_status = lttng_rotation_handle_get_state(handle,
-                               &rotation_state);
-               if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
-                       MSG("");
-                       ERR("Failed to query the state of the rotation.");
-                       goto error;
-               }
-
-               if (rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
-                       ret = usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
-                       if (ret) {
-                               PERROR("\nusleep");
-                               goto error;
-                       }
-                       _MSG(".");
-
-                       ret = fflush(stdout);
-                       if (ret) {
-                               PERROR("\nfflush");
-                               goto error;
-                       }
-               }
-       } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING);
-       MSG("");
-
-skip_wait:
-       switch (rotation_state) {
-       case LTTNG_ROTATION_STATE_COMPLETED:
-               rotation_status = lttng_rotation_handle_get_archive_location(
-                               handle, &location);
-               if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
-                       ERR("Failed to retrieve the rotation's completed chunk archive location.");
-                       cmd_ret = CMD_ERROR;
-               }
-               break;
-       case LTTNG_ROTATION_STATE_EXPIRED:
-               break;
-       case LTTNG_ROTATION_STATE_ERROR:
-               ERR("Failed to retrieve rotation state.");
-               goto error;
-       case LTTNG_ROTATION_STATE_ONGOING:
-               MSG("Rotation ongoing for session %s", session_name);
-               print_location = false;
-               break;
-       default:
-               ERR("Unexpected rotation state encountered.");
-               goto error;
-       }
-
-       if (!lttng_opt_mi && print_location) {
-               ret = print_trace_archive_location(location,
-                               session_name);
-       } else if (lttng_opt_mi) {
-               ret = mi_lttng_rotate(writer, session_name, rotation_state,
-                               location);
-       }
-
-       if (ret < 0) {
-               cmd_ret = CMD_ERROR;
-       }
-
-end:
-       lttng_rotation_handle_destroy(handle);
-       return cmd_ret;
-error:
-       cmd_ret = CMD_ERROR;
-       goto end;
-}
-
-/*
- *  cmd_rotate
- *
- *  The 'rotate <options>' first level command
- */
-int cmd_rotate(int argc, const char **argv)
-{
-       int opt, ret;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       int popt_ret;
-       static poptContext pc;
-       char *session_name = NULL;
-       bool free_session_name = false;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       popt_ret = poptReadDefaultConfig(pc, 0);
-       if (popt_ret) {
-               ERR("poptReadDefaultConfig");
-               goto error;
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       cmd_ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       opt_session_name = (char*) poptGetArg(pc);
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (!session_name) {
-                       goto error;
-               }
-               free_session_name = true;
-       } else {
-               session_name = opt_session_name;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       goto error;
-               }
-
-               /* Open rotate command */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_rotate);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       cmd_ret = rotate_tracing(session_name);
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       goto error;
-               }
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success,
-                               cmd_ret == CMD_SUCCESS);
-               if (ret) {
-                       goto error;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       goto error;
-               }
-       }
-
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               goto error;
-       }
-end:
-       poptFreeContext(pc);
-       if (free_session_name) {
-               free(session_name);
-       }
-
-       return cmd_ret;
-error:
-       cmd_ret = CMD_ERROR;
-       goto end;
-}
diff --git a/src/bin/lttng/commands/rotate.cpp b/src/bin/lttng/commands/rotate.cpp
new file mode 100644 (file)
index 0000000..63cf388
--- /dev/null
@@ -0,0 +1,262 @@
+/*
+ * Copyright (C) 2017 Julien Desfossez <jdesfossez@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <ctype.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include <lttng/lttng.h>
+
+static char *opt_session_name;
+static int opt_no_wait;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-rotate.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int rotate_tracing(char *session_name)
+{
+       int ret;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       struct lttng_rotation_handle *handle = NULL;
+       enum lttng_rotation_status rotation_status;
+       enum lttng_rotation_state rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+       const struct lttng_trace_archive_location *location = NULL;
+       bool print_location = true;
+
+       DBG("Rotating the output files of session %s", session_name);
+
+       ret = lttng_rotate_session(session_name, NULL, &handle);
+       if (ret < 0) {
+               switch (-ret) {
+               case LTTNG_ERR_SESSION_NOT_STARTED:
+                       WARN("Tracing session %s not started yet", session_name);
+                       cmd_ret = CMD_WARNING;
+                       goto end;
+               default:
+                       ERR("%s", lttng_strerror(ret));
+                       goto error;
+               }
+       }
+
+       if (opt_no_wait) {
+               rotation_state = LTTNG_ROTATION_STATE_ONGOING;
+               goto skip_wait;
+       }
+
+       _MSG("Waiting for rotation to complete");
+       ret = fflush(stdout);
+       if (ret) {
+               PERROR("fflush");
+               goto error;
+       }
+
+       do {
+               rotation_status = lttng_rotation_handle_get_state(handle,
+                               &rotation_state);
+               if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+                       MSG("");
+                       ERR("Failed to query the state of the rotation.");
+                       goto error;
+               }
+
+               if (rotation_state == LTTNG_ROTATION_STATE_ONGOING) {
+                       ret = usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
+                       if (ret) {
+                               PERROR("\nusleep");
+                               goto error;
+                       }
+                       _MSG(".");
+
+                       ret = fflush(stdout);
+                       if (ret) {
+                               PERROR("\nfflush");
+                               goto error;
+                       }
+               }
+       } while (rotation_state == LTTNG_ROTATION_STATE_ONGOING);
+       MSG("");
+
+skip_wait:
+       switch (rotation_state) {
+       case LTTNG_ROTATION_STATE_COMPLETED:
+               rotation_status = lttng_rotation_handle_get_archive_location(
+                               handle, &location);
+               if (rotation_status != LTTNG_ROTATION_STATUS_OK) {
+                       ERR("Failed to retrieve the rotation's completed chunk archive location.");
+                       cmd_ret = CMD_ERROR;
+               }
+               break;
+       case LTTNG_ROTATION_STATE_EXPIRED:
+               break;
+       case LTTNG_ROTATION_STATE_ERROR:
+               ERR("Failed to retrieve rotation state.");
+               goto error;
+       case LTTNG_ROTATION_STATE_ONGOING:
+               MSG("Rotation ongoing for session %s", session_name);
+               print_location = false;
+               break;
+       default:
+               ERR("Unexpected rotation state encountered.");
+               goto error;
+       }
+
+       if (!lttng_opt_mi && print_location) {
+               ret = print_trace_archive_location(location,
+                               session_name);
+       } else if (lttng_opt_mi) {
+               ret = mi_lttng_rotate(writer, session_name, rotation_state,
+                               location);
+       }
+
+       if (ret < 0) {
+               cmd_ret = CMD_ERROR;
+       }
+
+end:
+       lttng_rotation_handle_destroy(handle);
+       return cmd_ret;
+error:
+       cmd_ret = CMD_ERROR;
+       goto end;
+}
+
+/*
+ *  cmd_rotate
+ *
+ *  The 'rotate <options>' first level command
+ */
+int cmd_rotate(int argc, const char **argv)
+{
+       int opt, ret;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       int popt_ret;
+       static poptContext pc;
+       char *session_name = NULL;
+       bool free_session_name = false;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       popt_ret = poptReadDefaultConfig(pc, 0);
+       if (popt_ret) {
+               ERR("poptReadDefaultConfig");
+               goto error;
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       cmd_ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (!session_name) {
+                       goto error;
+               }
+               free_session_name = true;
+       } else {
+               session_name = opt_session_name;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       goto error;
+               }
+
+               /* Open rotate command */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_rotate);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       cmd_ret = (cmd_error_code) rotate_tracing(session_name);
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       goto error;
+               }
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success,
+                               cmd_ret == CMD_SUCCESS);
+               if (ret) {
+                       goto error;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       goto error;
+               }
+       }
+
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               goto error;
+       }
+end:
+       poptFreeContext(pc);
+       if (free_session_name) {
+               free(session_name);
+       }
+
+       return cmd_ret;
+error:
+       cmd_ret = CMD_ERROR;
+       goto end;
+}
diff --git a/src/bin/lttng/commands/save.c b/src/bin/lttng/commands/save.c
deleted file mode 100644 (file)
index 4231922..0000000
+++ /dev/null
@@ -1,274 +0,0 @@
-/*
- * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <inttypes.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-#include <lttng/lttng.h>
-
-static char *opt_output_path;
-static bool opt_force;
-static bool opt_save_all;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-save.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_ALL,
-       OPT_FORCE,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption save_opts[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
-       {"all",         'a', POPT_ARG_NONE, NULL, OPT_ALL, NULL, NULL},
-       {"output-path", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL},
-       {"force",       'f', POPT_ARG_NONE, NULL, OPT_FORCE, NULL, NULL},
-       {"list-options",  0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int mi_partial_session(const char *session_name)
-{
-       int ret;
-       LTTNG_ASSERT(writer);
-       LTTNG_ASSERT(session_name);
-
-       /* Open session element */
-       ret = mi_lttng_writer_open_element(writer, config_element_session);
-       if (ret) {
-               goto end;
-       }
-
-       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
-                       session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Closing session element */
-       ret = mi_lttng_writer_close_element(writer);
-end:
-       return ret;
-}
-
-/*
- * Mi print of save command
- */
-static int mi_save_print(const char *session_name)
-{
-       int ret;
-       LTTNG_ASSERT(writer);
-
-       if (opt_save_all) {
-               /* We use a wildcard to represent all sessions */
-               session_name = "*";
-       }
-
-       /* Print save element */
-       ret = mi_lttng_writer_open_element(writer, mi_lttng_element_save);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print session element */
-       ret = mi_partial_session(session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Path element */
-       if (opt_output_path) {
-               ret = mi_lttng_writer_write_element_string(writer, config_element_path,
-                               opt_output_path);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Close save element */
-       ret = mi_lttng_writer_close_element(writer);
-end:
-       return ret;
-}
-
-/*
- * The 'save <options>' first level command
- */
-int cmd_save(int argc, const char **argv)
-{
-       int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success;
-       int opt;
-       const char *session_name = NULL, *leftover = NULL;
-       poptContext pc;
-       struct lttng_save_session_attr *attr;
-
-       pc = poptGetContext(NULL, argc, argv, save_opts, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_ALL:
-                       opt_save_all = true;
-                       break;
-               case OPT_FORCE:
-                       opt_force = true;
-                       break;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, save_opts);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (!opt_save_all) {
-               session_name = poptGetArg(pc);
-               if (session_name) {
-                       DBG2("Session name: %s", session_name);
-               } else {
-                       /* default to opt_save_all */
-                       opt_save_all = true;
-               }
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       attr = lttng_save_session_attr_create();
-       if (!attr) {
-               ret = CMD_FATAL;
-               goto end_destroy;
-       }
-
-       if (lttng_save_session_attr_set_session_name(attr, session_name)) {
-               ret = CMD_ERROR;
-               goto end_destroy;
-       }
-
-       if (lttng_save_session_attr_set_overwrite(attr, opt_force)) {
-               ret = CMD_ERROR;
-               goto end_destroy;
-       }
-
-       if (lttng_save_session_attr_set_output_url(attr, opt_output_path)) {
-               ret = CMD_ERROR;
-               goto end_destroy;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end_destroy;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_save);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-       }
-
-       command_ret = lttng_save_session(attr);
-       if (command_ret < 0) {
-               ERR("%s", lttng_strerror(command_ret));
-               success = 0;
-       } else {
-               /* Inform the user of what just happened on success. */
-               if (session_name && opt_output_path) {
-                       MSG("Session %s saved successfully in %s.", session_name,
-                                       opt_output_path);
-               } else if (session_name && !opt_output_path) {
-                       MSG("Session %s saved successfully.", session_name);
-               } else if (!session_name && opt_output_path) {
-                       MSG("All sessions have been saved successfully in %s.",
-                                       opt_output_path);
-               } else {
-                       MSG("All sessions have been saved successfully.");
-               }
-               success = 1;
-       }
-
-       /* Mi Printing and closing */
-       if (lttng_opt_mi) {
-               /* Mi print */
-               ret = mi_save_print(session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end_destroy;
-               }
-       }
-end_destroy:
-       lttng_save_session_attr_destroy(attr);
-end:
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
-       }
-
-       /* Overwrite ret if command failed */
-       ret = command_ret ? -command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/save.cpp b/src/bin/lttng/commands/save.cpp
new file mode 100644 (file)
index 0000000..4231922
--- /dev/null
@@ -0,0 +1,274 @@
+/*
+ * Copyright (C) 2013 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <inttypes.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include <lttng/lttng.h>
+
+static char *opt_output_path;
+static bool opt_force;
+static bool opt_save_all;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-save.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_ALL,
+       OPT_FORCE,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption save_opts[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
+       {"all",         'a', POPT_ARG_NONE, NULL, OPT_ALL, NULL, NULL},
+       {"output-path", 'o', POPT_ARG_STRING, &opt_output_path, 0, NULL, NULL},
+       {"force",       'f', POPT_ARG_NONE, NULL, OPT_FORCE, NULL, NULL},
+       {"list-options",  0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int mi_partial_session(const char *session_name)
+{
+       int ret;
+       LTTNG_ASSERT(writer);
+       LTTNG_ASSERT(session_name);
+
+       /* Open session element */
+       ret = mi_lttng_writer_open_element(writer, config_element_session);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
+                       session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Closing session element */
+       ret = mi_lttng_writer_close_element(writer);
+end:
+       return ret;
+}
+
+/*
+ * Mi print of save command
+ */
+static int mi_save_print(const char *session_name)
+{
+       int ret;
+       LTTNG_ASSERT(writer);
+
+       if (opt_save_all) {
+               /* We use a wildcard to represent all sessions */
+               session_name = "*";
+       }
+
+       /* Print save element */
+       ret = mi_lttng_writer_open_element(writer, mi_lttng_element_save);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print session element */
+       ret = mi_partial_session(session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Path element */
+       if (opt_output_path) {
+               ret = mi_lttng_writer_write_element_string(writer, config_element_path,
+                               opt_output_path);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Close save element */
+       ret = mi_lttng_writer_close_element(writer);
+end:
+       return ret;
+}
+
+/*
+ * The 'save <options>' first level command
+ */
+int cmd_save(int argc, const char **argv)
+{
+       int ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success;
+       int opt;
+       const char *session_name = NULL, *leftover = NULL;
+       poptContext pc;
+       struct lttng_save_session_attr *attr;
+
+       pc = poptGetContext(NULL, argc, argv, save_opts, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_ALL:
+                       opt_save_all = true;
+                       break;
+               case OPT_FORCE:
+                       opt_force = true;
+                       break;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, save_opts);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (!opt_save_all) {
+               session_name = poptGetArg(pc);
+               if (session_name) {
+                       DBG2("Session name: %s", session_name);
+               } else {
+                       /* default to opt_save_all */
+                       opt_save_all = true;
+               }
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       attr = lttng_save_session_attr_create();
+       if (!attr) {
+               ret = CMD_FATAL;
+               goto end_destroy;
+       }
+
+       if (lttng_save_session_attr_set_session_name(attr, session_name)) {
+               ret = CMD_ERROR;
+               goto end_destroy;
+       }
+
+       if (lttng_save_session_attr_set_overwrite(attr, opt_force)) {
+               ret = CMD_ERROR;
+               goto end_destroy;
+       }
+
+       if (lttng_save_session_attr_set_output_url(attr, opt_output_path)) {
+               ret = CMD_ERROR;
+               goto end_destroy;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end_destroy;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_save);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+       }
+
+       command_ret = lttng_save_session(attr);
+       if (command_ret < 0) {
+               ERR("%s", lttng_strerror(command_ret));
+               success = 0;
+       } else {
+               /* Inform the user of what just happened on success. */
+               if (session_name && opt_output_path) {
+                       MSG("Session %s saved successfully in %s.", session_name,
+                                       opt_output_path);
+               } else if (session_name && !opt_output_path) {
+                       MSG("Session %s saved successfully.", session_name);
+               } else if (!session_name && opt_output_path) {
+                       MSG("All sessions have been saved successfully in %s.",
+                                       opt_output_path);
+               } else {
+                       MSG("All sessions have been saved successfully.");
+               }
+               success = 1;
+       }
+
+       /* Mi Printing and closing */
+       if (lttng_opt_mi) {
+               /* Mi print */
+               ret = mi_save_print(session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end_destroy;
+               }
+       }
+end_destroy:
+       lttng_save_session_attr_destroy(attr);
+end:
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
+       }
+
+       /* Overwrite ret if command failed */
+       ret = command_ret ? -command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/set_session.c b/src/bin/lttng/commands/set_session.c
deleted file mode 100644 (file)
index fb42d14..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-static char *opt_session_name;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-set-session.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct mi_writer *writer;
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Print the necessary mi for a session and name.
- */
-static int mi_print(char *session_name)
-{
-       int ret;
-
-       LTTNG_ASSERT(writer);
-       LTTNG_ASSERT(session_name);
-
-       /*
-        * Open a sessions element
-        * This is purely for validation purpose
-        */
-       ret = mi_lttng_sessions_open(writer);
-       if (ret) {
-               goto end;
-       }
-
-       /* Open a session element */
-       ret = mi_lttng_writer_open_element(writer, config_element_session);
-       if (ret) {
-               goto end;
-       }
-
-       /* Session name */
-       ret = mi_lttng_writer_write_element_string(writer , config_element_name,
-                       session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close session and sessions element */
-       ret = mi_lttng_close_multi_element(writer, 2);
-       if (ret) {
-               goto end;
-       }
-end:
-       return ret;
-}
-
-/*
- *  set_session
- */
-static int set_session(void)
-{
-       int ret = CMD_SUCCESS;
-       int count, i;
-       unsigned int session_found = 0;
-       struct lttng_session *sessions;
-
-       if (opt_session_name && strlen(opt_session_name) > NAME_MAX) {
-               ERR("Session name too long. Length must be lower or equal to %d",
-                       NAME_MAX);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       count = lttng_list_sessions(&sessions);
-       if (count < 0) {
-               ret = CMD_ERROR;
-               ERR("%s", lttng_strerror(count));
-               goto end;
-       }
-
-       for (i = 0; i < count; i++) {
-               if (strncmp(sessions[i].name, opt_session_name, NAME_MAX) == 0) {
-                       session_found = 1;
-                       break;
-               }
-       }
-
-       if (!session_found) {
-               ERR("Session '%s' not found", opt_session_name);
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       ret = config_init(opt_session_name);
-       if (ret < 0) {
-               ERR("Unable to set session name");
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       MSG("Session set to %s", opt_session_name);
-       if (lttng_opt_mi) {
-               ret = mi_print(opt_session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       ret = CMD_SUCCESS;
-
-error:
-       free(sessions);
-end:
-       return ret;
-}
-
-/*
- *  cmd_set_session
- */
-int cmd_set_session(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       opt_session_name = (char *) poptGetArg(pc);
-       if (opt_session_name == NULL) {
-               ERR("Missing session name");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_set_session);
-               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;
-               }
-       }
-
-       command_ret = set_session();
-       if (command_ret) {
-               success = 0;
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  output element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       /* Overwrite ret if an error occurred during set_session() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/set_session.cpp b/src/bin/lttng/commands/set_session.cpp
new file mode 100644 (file)
index 0000000..fb42d14
--- /dev/null
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_session_name;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-set-session.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct mi_writer *writer;
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",           'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Print the necessary mi for a session and name.
+ */
+static int mi_print(char *session_name)
+{
+       int ret;
+
+       LTTNG_ASSERT(writer);
+       LTTNG_ASSERT(session_name);
+
+       /*
+        * Open a sessions element
+        * This is purely for validation purpose
+        */
+       ret = mi_lttng_sessions_open(writer);
+       if (ret) {
+               goto end;
+       }
+
+       /* Open a session element */
+       ret = mi_lttng_writer_open_element(writer, config_element_session);
+       if (ret) {
+               goto end;
+       }
+
+       /* Session name */
+       ret = mi_lttng_writer_write_element_string(writer , config_element_name,
+                       session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close session and sessions element */
+       ret = mi_lttng_close_multi_element(writer, 2);
+       if (ret) {
+               goto end;
+       }
+end:
+       return ret;
+}
+
+/*
+ *  set_session
+ */
+static int set_session(void)
+{
+       int ret = CMD_SUCCESS;
+       int count, i;
+       unsigned int session_found = 0;
+       struct lttng_session *sessions;
+
+       if (opt_session_name && strlen(opt_session_name) > NAME_MAX) {
+               ERR("Session name too long. Length must be lower or equal to %d",
+                       NAME_MAX);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       count = lttng_list_sessions(&sessions);
+       if (count < 0) {
+               ret = CMD_ERROR;
+               ERR("%s", lttng_strerror(count));
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (strncmp(sessions[i].name, opt_session_name, NAME_MAX) == 0) {
+                       session_found = 1;
+                       break;
+               }
+       }
+
+       if (!session_found) {
+               ERR("Session '%s' not found", opt_session_name);
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       ret = config_init(opt_session_name);
+       if (ret < 0) {
+               ERR("Unable to set session name");
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       MSG("Session set to %s", opt_session_name);
+       if (lttng_opt_mi) {
+               ret = mi_print(opt_session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       ret = CMD_SUCCESS;
+
+error:
+       free(sessions);
+end:
+       return ret;
+}
+
+/*
+ *  cmd_set_session
+ */
+int cmd_set_session(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char *) poptGetArg(pc);
+       if (opt_session_name == NULL) {
+               ERR("Missing session name");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_set_session);
+               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;
+               }
+       }
+
+       command_ret = set_session();
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  output element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       /* Overwrite ret if an error occurred during set_session() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/snapshot.c b/src/bin/lttng/commands/snapshot.c
deleted file mode 100644 (file)
index c37e09a..0000000
+++ /dev/null
@@ -1,694 +0,0 @@
-/*
- * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <inttypes.h>
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/utils.h>
-#include <common/mi-lttng.h>
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-static const char *opt_session_name;
-static const char *opt_output_name;
-static const char *opt_data_url;
-static const char *opt_ctrl_url;
-static const char *current_session_name;
-static uint64_t opt_max_size;
-
-/* Stub for the cmd struct actions. */
-static int cmd_add_output(int argc, const char **argv);
-static int cmd_del_output(int argc, const char **argv);
-static int cmd_list_output(int argc, const char **argv);
-static int cmd_record(int argc, const char **argv);
-
-static const char *indent4 = "    ";
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-snapshot.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-       OPT_MAX_SIZE,
-       OPT_LIST_COMMANDS,
-};
-
-static struct mi_writer *writer;
-
-static struct poptOption snapshot_opts[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"session",      's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
-       {"ctrl-url",     'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
-       {"data-url",     'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
-       {"name",         'n', POPT_ARG_STRING, &opt_output_name, 0, 0, 0},
-       {"max-size",     'm', POPT_ARG_STRING, 0, OPT_MAX_SIZE, 0, 0},
-       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"list-commands",  0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static struct cmd_struct actions[] = {
-       { "add-output", cmd_add_output },
-       { "del-output", cmd_del_output },
-       { "list-output", cmd_list_output },
-       { "record", cmd_record },
-       { NULL, NULL }  /* Array closure */
-};
-
-/*
- * Count and return the number of arguments in argv.
- */
-static int count_arguments(const char **argv)
-{
-       int i = 0;
-
-       LTTNG_ASSERT(argv);
-
-       while (argv[i] != NULL) {
-               i++;
-       }
-
-       return i;
-}
-
-/*
- * Create a snapshot output object from arguments using the given URL.
- *
- * Return a newly allocated object or NULL on error.
- */
-static struct lttng_snapshot_output *create_output_from_args(const char *url)
-{
-       int ret = 0;
-       struct lttng_snapshot_output *output = NULL;
-
-       output = lttng_snapshot_output_create();
-       if (!output) {
-               goto error_create;
-       }
-
-       if (url) {
-               ret = lttng_snapshot_output_set_ctrl_url(url, output);
-               if (ret < 0) {
-                       goto error;
-               }
-       } else if (opt_ctrl_url) {
-               ret = lttng_snapshot_output_set_ctrl_url(opt_ctrl_url, output);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       if (opt_data_url) {
-               ret = lttng_snapshot_output_set_data_url(opt_data_url, output);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       if (opt_max_size) {
-               ret = lttng_snapshot_output_set_size(opt_max_size, output);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       if (opt_output_name) {
-               ret = lttng_snapshot_output_set_name(opt_output_name, output);
-               if (ret < 0) {
-                       goto error;
-               }
-       }
-
-       return output;
-
-error:
-       lttng_snapshot_output_destroy(output);
-error_create:
-       return NULL;
-}
-
-static int list_output(void)
-{
-       int ret, output_seen = 0;
-       struct lttng_snapshot_output *s_iter;
-       struct lttng_snapshot_output_list *list;
-
-       ret = lttng_snapshot_list_output(current_session_name, &list);
-       if (ret < 0) {
-               goto error;
-       }
-
-       MSG("Snapshot output list for session %s", current_session_name);
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_snapshot_output_session_name(writer,
-                               current_session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       while ((s_iter = lttng_snapshot_output_list_get_next(list)) != NULL) {
-               if (lttng_snapshot_output_get_maxsize(s_iter)) {
-                       MSG("%s[%" PRIu32 "] %s: %s (max size: %" PRIu64 " bytes)", indent4,
-                                       lttng_snapshot_output_get_id(s_iter),
-                                       lttng_snapshot_output_get_name(s_iter),
-                                       lttng_snapshot_output_get_ctrl_url(s_iter),
-                                       lttng_snapshot_output_get_maxsize(s_iter));
-               } else {
-                       MSG("%s[%" PRIu32 "] %s: %s", indent4,
-                                       lttng_snapshot_output_get_id(s_iter),
-                                       lttng_snapshot_output_get_name(s_iter),
-                                       lttng_snapshot_output_get_ctrl_url(s_iter));
-               }
-               output_seen = 1;
-               if (lttng_opt_mi) {
-                       ret = mi_lttng_snapshot_list_output(writer, s_iter);
-                       if (ret) {
-                               ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-       }
-
-       if (lttng_opt_mi) {
-               /* Close snapshot snapshots element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Close snapshot session element */
-               ret = mi_lttng_writer_close_element(writer);
-               if (ret) {
-                       ret = CMD_ERROR;
-               }
-       }
-end:
-       lttng_snapshot_output_list_destroy(list);
-
-       if (!output_seen) {
-               MSG("%sNone", indent4);
-       }
-
-error:
-       return ret;
-}
-
-/*
- * Delete output by ID.
- */
-static int del_output(uint32_t id, const char *name)
-{
-       int ret;
-       struct lttng_snapshot_output *output = NULL;
-
-       output = lttng_snapshot_output_create();
-       if (!output) {
-               ret = CMD_FATAL;
-               goto error;
-       }
-
-       if (name) {
-               ret = lttng_snapshot_output_set_name(name, output);
-       } else if (id != UINT32_MAX) {
-               ret = lttng_snapshot_output_set_id(id, output);
-       } else {
-               ret = CMD_ERROR;
-               goto error;
-       }
-       if (ret < 0) {
-               ret = CMD_FATAL;
-               goto error;
-       }
-
-       ret = lttng_snapshot_del_output(current_session_name, output);
-       if (ret < 0) {
-               goto error;
-       }
-
-       if (id != UINT32_MAX) {
-               MSG("Snapshot output id %" PRIu32 " successfully deleted for session %s",
-                               id, current_session_name);
-       } else {
-               MSG("Snapshot output %s successfully deleted for session %s",
-                               name, current_session_name);
-       }
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_snapshot_del_output(writer, id, name,
-                               current_session_name);
-               if (ret) {
-                       ret = CMD_ERROR;
-               }
-       }
-
-error:
-       lttng_snapshot_output_destroy(output);
-       return ret;
-}
-
-/*
- * Add output from the user URL.
- */
-static int add_output(const char *url)
-{
-       int ret;
-       struct lttng_snapshot_output *output = NULL;
-       char name[NAME_MAX];
-       const char *n_ptr;
-
-       if (!url && (!opt_data_url || !opt_ctrl_url)) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       output = create_output_from_args(url);
-       if (!output) {
-               ret = CMD_FATAL;
-               goto error;
-       }
-
-       /* This call, if successful, populates the id of the output object. */
-       ret = lttng_snapshot_add_output(current_session_name, output);
-       if (ret < 0) {
-               goto error;
-       }
-
-       n_ptr = lttng_snapshot_output_get_name(output);
-       if (*n_ptr == '\0') {
-               int pret;
-               pret = snprintf(name, sizeof(name), DEFAULT_SNAPSHOT_NAME "-%" PRIu32,
-                               lttng_snapshot_output_get_id(output));
-               if (pret < 0) {
-                       PERROR("snprintf add output name");
-               }
-               n_ptr = name;
-       }
-
-       MSG("Snapshot output successfully added for session %s",
-                       current_session_name);
-       if (opt_max_size) {
-               MSG("  [%" PRIu32 "] %s: %s (max size: %" PRIu64 " bytes)",
-                               lttng_snapshot_output_get_id(output), n_ptr,
-                               lttng_snapshot_output_get_ctrl_url(output),
-                               lttng_snapshot_output_get_maxsize(output));
-       } else {
-               MSG("  [%" PRIu32 "] %s: %s",
-                               lttng_snapshot_output_get_id(output), n_ptr,
-                               lttng_snapshot_output_get_ctrl_url(output));
-       }
-       if (lttng_opt_mi) {
-               ret = mi_lttng_snapshot_add_output(writer, current_session_name,
-                               n_ptr, output);
-               if (ret) {
-                       ret = CMD_ERROR;
-               }
-       }
-error:
-       lttng_snapshot_output_destroy(output);
-       return ret;
-}
-
-static int cmd_add_output(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc < 2 && (!opt_data_url || !opt_ctrl_url)) {
-               ERR("An output destination must be specified to add a snapshot output.");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       ret = add_output(argv[1]);
-       if (ret < 0) {
-               switch (-ret) {
-               case LTTNG_ERR_SNAPSHOT_UNSUPPORTED:
-                       ERR("Session \"%s\" contains a channel that is incompatible with the snapshot functionality.\nMake sure all channels are configured in 'mmap' output mode.",
-                                       current_session_name);
-                       ret = CMD_ERROR;
-                       break;
-               default:
-                       break;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static int cmd_del_output(int argc, const char **argv)
-{
-       int ret;
-       char *name;
-       long id;
-
-       if (argc < 2) {
-               ERR("A snapshot output name or id must be provided to delete a snapshot output.");
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       errno = 0;
-       id = strtol(argv[1], &name, 10);
-       if (id == 0 && (errno == 0 || errno == EINVAL)) {
-               ret = del_output(UINT32_MAX, name);
-       } else if (errno == 0 && *name == '\0') {
-               ret = del_output(id, NULL);
-       } else {
-               ERR("Argument %s not recognized", argv[1]);
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-static int cmd_list_output(int argc, const char **argv)
-{
-       int ret;
-
-       ret = list_output();
-
-       return ret;
-}
-
-/*
- * Do a snapshot record with the URL if one is given.
- */
-static int record(const char *url)
-{
-       int ret;
-       struct lttng_snapshot_output *output = NULL;
-
-       output = create_output_from_args(url);
-       if (!output) {
-               ret = CMD_FATAL;
-               goto error;
-       }
-
-       ret = lttng_snapshot_record(current_session_name, output, 0);
-       if (ret < 0) {
-               if (ret == -LTTNG_ERR_MAX_SIZE_INVALID) {
-                       ERR("Invalid snapshot size. Cannot fit at least one packet per stream.");
-               }
-               goto error;
-       }
-
-       MSG("Snapshot recorded successfully for session %s", current_session_name);
-
-       if (url) {
-               MSG("Snapshot written at: %s", url);
-       } else if (opt_ctrl_url) {
-               MSG("Snapshot written to ctrl: %s, data: %s", opt_ctrl_url,
-                               opt_data_url);
-       }
-
-       if (lttng_opt_mi) {
-               ret = mi_lttng_snapshot_record(writer, current_session_name, url,
-                               opt_ctrl_url, opt_data_url);
-               if (ret) {
-                       ret = CMD_ERROR;
-               }
-       }
-
-error:
-       lttng_snapshot_output_destroy(output);
-       return ret;
-}
-
-static int cmd_record(int argc, const char **argv)
-{
-       int ret;
-
-       if (argc == 2) {
-               ret = record(argv[1]);
-       } else {
-               ret = record(NULL);
-       }
-
-       return ret;
-}
-
-static enum cmd_error_code handle_command(const char **argv)
-{
-       int mi_ret, i = 0, argc;
-       enum cmd_error_code cmd_ret;
-       struct cmd_struct *cmd;
-
-       if (!argv) {
-               ERR("No action specified for snapshot command.");
-               cmd_ret = CMD_ERROR;
-               goto end;
-       }
-
-       if ((!opt_ctrl_url && opt_data_url) ||
-                       (opt_ctrl_url && !opt_data_url)) {
-               ERR("URLs must be specified for both data and control");
-               cmd_ret = CMD_ERROR;
-               goto end;
-       }
-
-       argc = count_arguments(argv);
-       /* popt should have passed NULL if no arguments are present. */
-       LTTNG_ASSERT(argc > 0);
-
-       cmd = &actions[i];
-       while (cmd->func != NULL) {
-               /* Find command */
-               if (strcmp(argv[0], cmd->name) == 0) {
-                       int result;
-
-                       if (lttng_opt_mi) {
-                               /* Action element */
-                               mi_ret = mi_lttng_writer_open_element(writer,
-                                               mi_lttng_element_command_action);
-                               if (mi_ret) {
-                                       cmd_ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               /* Name of the action */
-                               mi_ret = mi_lttng_writer_write_element_string(writer,
-                                               config_element_name, argv[0]);
-                               if (mi_ret) {
-                                       cmd_ret = CMD_ERROR;
-                                       goto end;
-                               }
-
-                               /* Open output element */
-                               mi_ret = mi_lttng_writer_open_element(writer,
-                                               mi_lttng_element_command_output);
-                               if (mi_ret) {
-                                       cmd_ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-
-                       result = cmd->func(argc, argv);
-                       if (result) {
-                               switch (result) {
-                               case CMD_ERROR:
-                               case CMD_UNDEFINED:
-                               case CMD_FATAL:
-                               case CMD_WARNING:
-                               case CMD_UNSUPPORTED:
-                                       /*
-                                        * Sub-commands mix lttng_error_codes
-                                        * and cmd_error_codes. This should be
-                                        * cleaned-up, but in the meantime this
-                                        * hack works since the values of the
-                                        * two enums do not intersect.
-                                        */
-                                       cmd_ret = result;
-                                       break;
-                               case -LTTNG_ERR_SNAPSHOT_NODATA:
-                                       WARN("%s", lttng_strerror(result));
-
-                                       /*  A warning is fine since the user has no control on
-                                        *  whether or not applications (or the kernel) have
-                                        *  produced any event between the start of the tracing
-                                        *  session and the recording of the snapshot. MI wise
-                                        *  the command is not a success since nothing was
-                                        *  recorded.
-                                        */
-                                       cmd_ret = CMD_SUCCESS;
-                                       break;
-                               default:
-                                       ERR("%s", lttng_strerror(result));
-                                       cmd_ret = CMD_ERROR;
-                                       break;
-                               }
-                       } else {
-                               cmd_ret = CMD_SUCCESS;
-                       }
-
-
-                       if (lttng_opt_mi) {
-                               /* Close output and action element */
-                               mi_ret = mi_lttng_close_multi_element(writer, 2);
-                               if (mi_ret) {
-                                       cmd_ret = CMD_ERROR;
-                                       goto end;
-                               }
-                       }
-                       goto end;
-               }
-               i++;
-               cmd = &actions[i];
-       }
-
-       cmd_ret = CMD_UNDEFINED;
-
-end:
-       return cmd_ret;
-}
-/*
- * The 'snapshot <cmd> <options>' first level command
- */
-int cmd_snapshot(int argc, const char **argv)
-{
-       int opt;
-       int mi_ret;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       char *session_name = NULL;
-       static poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open command element */
-               mi_ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_snapshot);
-               if (mi_ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open output element */
-               mi_ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (mi_ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-               {
-                       int ret;
-
-                       /* SHOW_HELP assigns to ret. */
-                       SHOW_HELP();
-                       cmd_ret = ret;
-                       goto end;
-               }
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, snapshot_opts);
-                       goto end;
-               case OPT_LIST_COMMANDS:
-                       list_commands(actions, stdout);
-                       goto end;
-               case OPT_MAX_SIZE:
-               {
-                       uint64_t val;
-                       const char *max_size_arg = poptGetOptArg(pc);
-
-                       if (utils_parse_size_suffix((char *) max_size_arg, &val) < 0) {
-                               ERR("Unable to handle max-size value %s",
-                                               max_size_arg);
-                               cmd_ret = CMD_ERROR;
-                               goto end;
-                       }
-
-                       opt_max_size = val;
-
-                       break;
-               }
-               default:
-                       cmd_ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-               current_session_name = session_name;
-       } else {
-               current_session_name = opt_session_name;
-       }
-
-       cmd_ret = handle_command(poptGetArgs(pc));
-
-       if (lttng_opt_mi) {
-               /* Close output element */
-               mi_ret = mi_lttng_writer_close_element(writer);
-               if (mi_ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               mi_ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success,
-                               cmd_ret == CMD_SUCCESS);
-               if (mi_ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close */
-               mi_ret = mi_lttng_writer_command_close(writer);
-               if (mi_ret) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-end:
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               cmd_ret = CMD_ERROR;
-       }
-
-       if (!opt_session_name) {
-               free(session_name);
-       }
-
-       poptFreeContext(pc);
-       return cmd_ret;
-}
diff --git a/src/bin/lttng/commands/snapshot.cpp b/src/bin/lttng/commands/snapshot.cpp
new file mode 100644 (file)
index 0000000..8e19fa3
--- /dev/null
@@ -0,0 +1,694 @@
+/*
+ * Copyright (C) 2013 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <inttypes.h>
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/utils.h>
+#include <common/mi-lttng.h>
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+static const char *opt_session_name;
+static const char *opt_output_name;
+static const char *opt_data_url;
+static const char *opt_ctrl_url;
+static const char *current_session_name;
+static uint64_t opt_max_size;
+
+/* Stub for the cmd struct actions. */
+static int cmd_add_output(int argc, const char **argv);
+static int cmd_del_output(int argc, const char **argv);
+static int cmd_list_output(int argc, const char **argv);
+static int cmd_record(int argc, const char **argv);
+
+static const char *indent4 = "    ";
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-snapshot.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+       OPT_MAX_SIZE,
+       OPT_LIST_COMMANDS,
+};
+
+static struct mi_writer *writer;
+
+static struct poptOption snapshot_opts[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"session",      's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0},
+       {"ctrl-url",     'C', POPT_ARG_STRING, &opt_ctrl_url, 0, 0, 0},
+       {"data-url",     'D', POPT_ARG_STRING, &opt_data_url, 0, 0, 0},
+       {"name",         'n', POPT_ARG_STRING, &opt_output_name, 0, 0, 0},
+       {"max-size",     'm', POPT_ARG_STRING, 0, OPT_MAX_SIZE, 0, 0},
+       {"list-options",   0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"list-commands",  0, POPT_ARG_NONE, NULL, OPT_LIST_COMMANDS},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static struct cmd_struct actions[] = {
+       { "add-output", cmd_add_output },
+       { "del-output", cmd_del_output },
+       { "list-output", cmd_list_output },
+       { "record", cmd_record },
+       { NULL, NULL }  /* Array closure */
+};
+
+/*
+ * Count and return the number of arguments in argv.
+ */
+static int count_arguments(const char **argv)
+{
+       int i = 0;
+
+       LTTNG_ASSERT(argv);
+
+       while (argv[i] != NULL) {
+               i++;
+       }
+
+       return i;
+}
+
+/*
+ * Create a snapshot output object from arguments using the given URL.
+ *
+ * Return a newly allocated object or NULL on error.
+ */
+static struct lttng_snapshot_output *create_output_from_args(const char *url)
+{
+       int ret = 0;
+       struct lttng_snapshot_output *output = NULL;
+
+       output = lttng_snapshot_output_create();
+       if (!output) {
+               goto error_create;
+       }
+
+       if (url) {
+               ret = lttng_snapshot_output_set_ctrl_url(url, output);
+               if (ret < 0) {
+                       goto error;
+               }
+       } else if (opt_ctrl_url) {
+               ret = lttng_snapshot_output_set_ctrl_url(opt_ctrl_url, output);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       if (opt_data_url) {
+               ret = lttng_snapshot_output_set_data_url(opt_data_url, output);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       if (opt_max_size) {
+               ret = lttng_snapshot_output_set_size(opt_max_size, output);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       if (opt_output_name) {
+               ret = lttng_snapshot_output_set_name(opt_output_name, output);
+               if (ret < 0) {
+                       goto error;
+               }
+       }
+
+       return output;
+
+error:
+       lttng_snapshot_output_destroy(output);
+error_create:
+       return NULL;
+}
+
+static int list_output(void)
+{
+       int ret, output_seen = 0;
+       struct lttng_snapshot_output *s_iter;
+       struct lttng_snapshot_output_list *list;
+
+       ret = lttng_snapshot_list_output(current_session_name, &list);
+       if (ret < 0) {
+               goto error;
+       }
+
+       MSG("Snapshot output list for session %s", current_session_name);
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_snapshot_output_session_name(writer,
+                               current_session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       while ((s_iter = lttng_snapshot_output_list_get_next(list)) != NULL) {
+               if (lttng_snapshot_output_get_maxsize(s_iter)) {
+                       MSG("%s[%" PRIu32 "] %s: %s (max size: %" PRIu64 " bytes)", indent4,
+                                       lttng_snapshot_output_get_id(s_iter),
+                                       lttng_snapshot_output_get_name(s_iter),
+                                       lttng_snapshot_output_get_ctrl_url(s_iter),
+                                       lttng_snapshot_output_get_maxsize(s_iter));
+               } else {
+                       MSG("%s[%" PRIu32 "] %s: %s", indent4,
+                                       lttng_snapshot_output_get_id(s_iter),
+                                       lttng_snapshot_output_get_name(s_iter),
+                                       lttng_snapshot_output_get_ctrl_url(s_iter));
+               }
+               output_seen = 1;
+               if (lttng_opt_mi) {
+                       ret = mi_lttng_snapshot_list_output(writer, s_iter);
+                       if (ret) {
+                               ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+       }
+
+       if (lttng_opt_mi) {
+               /* Close snapshot snapshots element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Close snapshot session element */
+               ret = mi_lttng_writer_close_element(writer);
+               if (ret) {
+                       ret = CMD_ERROR;
+               }
+       }
+end:
+       lttng_snapshot_output_list_destroy(list);
+
+       if (!output_seen) {
+               MSG("%sNone", indent4);
+       }
+
+error:
+       return ret;
+}
+
+/*
+ * Delete output by ID.
+ */
+static int del_output(uint32_t id, const char *name)
+{
+       int ret;
+       struct lttng_snapshot_output *output = NULL;
+
+       output = lttng_snapshot_output_create();
+       if (!output) {
+               ret = CMD_FATAL;
+               goto error;
+       }
+
+       if (name) {
+               ret = lttng_snapshot_output_set_name(name, output);
+       } else if (id != UINT32_MAX) {
+               ret = lttng_snapshot_output_set_id(id, output);
+       } else {
+               ret = CMD_ERROR;
+               goto error;
+       }
+       if (ret < 0) {
+               ret = CMD_FATAL;
+               goto error;
+       }
+
+       ret = lttng_snapshot_del_output(current_session_name, output);
+       if (ret < 0) {
+               goto error;
+       }
+
+       if (id != UINT32_MAX) {
+               MSG("Snapshot output id %" PRIu32 " successfully deleted for session %s",
+                               id, current_session_name);
+       } else {
+               MSG("Snapshot output %s successfully deleted for session %s",
+                               name, current_session_name);
+       }
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_snapshot_del_output(writer, id, name,
+                               current_session_name);
+               if (ret) {
+                       ret = CMD_ERROR;
+               }
+       }
+
+error:
+       lttng_snapshot_output_destroy(output);
+       return ret;
+}
+
+/*
+ * Add output from the user URL.
+ */
+static int add_output(const char *url)
+{
+       int ret;
+       struct lttng_snapshot_output *output = NULL;
+       char name[NAME_MAX];
+       const char *n_ptr;
+
+       if (!url && (!opt_data_url || !opt_ctrl_url)) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       output = create_output_from_args(url);
+       if (!output) {
+               ret = CMD_FATAL;
+               goto error;
+       }
+
+       /* This call, if successful, populates the id of the output object. */
+       ret = lttng_snapshot_add_output(current_session_name, output);
+       if (ret < 0) {
+               goto error;
+       }
+
+       n_ptr = lttng_snapshot_output_get_name(output);
+       if (*n_ptr == '\0') {
+               int pret;
+               pret = snprintf(name, sizeof(name), DEFAULT_SNAPSHOT_NAME "-%" PRIu32,
+                               lttng_snapshot_output_get_id(output));
+               if (pret < 0) {
+                       PERROR("snprintf add output name");
+               }
+               n_ptr = name;
+       }
+
+       MSG("Snapshot output successfully added for session %s",
+                       current_session_name);
+       if (opt_max_size) {
+               MSG("  [%" PRIu32 "] %s: %s (max size: %" PRIu64 " bytes)",
+                               lttng_snapshot_output_get_id(output), n_ptr,
+                               lttng_snapshot_output_get_ctrl_url(output),
+                               lttng_snapshot_output_get_maxsize(output));
+       } else {
+               MSG("  [%" PRIu32 "] %s: %s",
+                               lttng_snapshot_output_get_id(output), n_ptr,
+                               lttng_snapshot_output_get_ctrl_url(output));
+       }
+       if (lttng_opt_mi) {
+               ret = mi_lttng_snapshot_add_output(writer, current_session_name,
+                               n_ptr, output);
+               if (ret) {
+                       ret = CMD_ERROR;
+               }
+       }
+error:
+       lttng_snapshot_output_destroy(output);
+       return ret;
+}
+
+static int cmd_add_output(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc < 2 && (!opt_data_url || !opt_ctrl_url)) {
+               ERR("An output destination must be specified to add a snapshot output.");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       ret = add_output(argv[1]);
+       if (ret < 0) {
+               switch (-ret) {
+               case LTTNG_ERR_SNAPSHOT_UNSUPPORTED:
+                       ERR("Session \"%s\" contains a channel that is incompatible with the snapshot functionality.\nMake sure all channels are configured in 'mmap' output mode.",
+                                       current_session_name);
+                       ret = CMD_ERROR;
+                       break;
+               default:
+                       break;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static int cmd_del_output(int argc, const char **argv)
+{
+       int ret;
+       char *name;
+       long id;
+
+       if (argc < 2) {
+               ERR("A snapshot output name or id must be provided to delete a snapshot output.");
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       errno = 0;
+       id = strtol(argv[1], &name, 10);
+       if (id == 0 && (errno == 0 || errno == EINVAL)) {
+               ret = del_output(UINT32_MAX, name);
+       } else if (errno == 0 && *name == '\0') {
+               ret = del_output(id, NULL);
+       } else {
+               ERR("Argument %s not recognized", argv[1]);
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+static int cmd_list_output(int argc, const char **argv)
+{
+       int ret;
+
+       ret = list_output();
+
+       return ret;
+}
+
+/*
+ * Do a snapshot record with the URL if one is given.
+ */
+static int record(const char *url)
+{
+       int ret;
+       struct lttng_snapshot_output *output = NULL;
+
+       output = create_output_from_args(url);
+       if (!output) {
+               ret = CMD_FATAL;
+               goto error;
+       }
+
+       ret = lttng_snapshot_record(current_session_name, output, 0);
+       if (ret < 0) {
+               if (ret == -LTTNG_ERR_MAX_SIZE_INVALID) {
+                       ERR("Invalid snapshot size. Cannot fit at least one packet per stream.");
+               }
+               goto error;
+       }
+
+       MSG("Snapshot recorded successfully for session %s", current_session_name);
+
+       if (url) {
+               MSG("Snapshot written at: %s", url);
+       } else if (opt_ctrl_url) {
+               MSG("Snapshot written to ctrl: %s, data: %s", opt_ctrl_url,
+                               opt_data_url);
+       }
+
+       if (lttng_opt_mi) {
+               ret = mi_lttng_snapshot_record(writer, current_session_name, url,
+                               opt_ctrl_url, opt_data_url);
+               if (ret) {
+                       ret = CMD_ERROR;
+               }
+       }
+
+error:
+       lttng_snapshot_output_destroy(output);
+       return ret;
+}
+
+static int cmd_record(int argc, const char **argv)
+{
+       int ret;
+
+       if (argc == 2) {
+               ret = record(argv[1]);
+       } else {
+               ret = record(NULL);
+       }
+
+       return ret;
+}
+
+static enum cmd_error_code handle_command(const char **argv)
+{
+       int mi_ret, i = 0, argc;
+       enum cmd_error_code cmd_ret;
+       struct cmd_struct *cmd;
+
+       if (!argv) {
+               ERR("No action specified for snapshot command.");
+               cmd_ret = CMD_ERROR;
+               goto end;
+       }
+
+       if ((!opt_ctrl_url && opt_data_url) ||
+                       (opt_ctrl_url && !opt_data_url)) {
+               ERR("URLs must be specified for both data and control");
+               cmd_ret = CMD_ERROR;
+               goto end;
+       }
+
+       argc = count_arguments(argv);
+       /* popt should have passed NULL if no arguments are present. */
+       LTTNG_ASSERT(argc > 0);
+
+       cmd = &actions[i];
+       while (cmd->func != NULL) {
+               /* Find command */
+               if (strcmp(argv[0], cmd->name) == 0) {
+                       int result;
+
+                       if (lttng_opt_mi) {
+                               /* Action element */
+                               mi_ret = mi_lttng_writer_open_element(writer,
+                                               mi_lttng_element_command_action);
+                               if (mi_ret) {
+                                       cmd_ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               /* Name of the action */
+                               mi_ret = mi_lttng_writer_write_element_string(writer,
+                                               config_element_name, argv[0]);
+                               if (mi_ret) {
+                                       cmd_ret = CMD_ERROR;
+                                       goto end;
+                               }
+
+                               /* Open output element */
+                               mi_ret = mi_lttng_writer_open_element(writer,
+                                               mi_lttng_element_command_output);
+                               if (mi_ret) {
+                                       cmd_ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+
+                       result = cmd->func(argc, argv);
+                       if (result) {
+                               switch (result) {
+                               case CMD_ERROR:
+                               case CMD_UNDEFINED:
+                               case CMD_FATAL:
+                               case CMD_WARNING:
+                               case CMD_UNSUPPORTED:
+                                       /*
+                                        * Sub-commands mix lttng_error_codes
+                                        * and cmd_error_codes. This should be
+                                        * cleaned-up, but in the meantime this
+                                        * hack works since the values of the
+                                        * two enums do not intersect.
+                                        */
+                                       cmd_ret = (cmd_error_code) result;
+                                       break;
+                               case -LTTNG_ERR_SNAPSHOT_NODATA:
+                                       WARN("%s", lttng_strerror(result));
+
+                                       /*  A warning is fine since the user has no control on
+                                        *  whether or not applications (or the kernel) have
+                                        *  produced any event between the start of the tracing
+                                        *  session and the recording of the snapshot. MI wise
+                                        *  the command is not a success since nothing was
+                                        *  recorded.
+                                        */
+                                       cmd_ret = CMD_SUCCESS;
+                                       break;
+                               default:
+                                       ERR("%s", lttng_strerror(result));
+                                       cmd_ret = CMD_ERROR;
+                                       break;
+                               }
+                       } else {
+                               cmd_ret = CMD_SUCCESS;
+                       }
+
+
+                       if (lttng_opt_mi) {
+                               /* Close output and action element */
+                               mi_ret = mi_lttng_close_multi_element(writer, 2);
+                               if (mi_ret) {
+                                       cmd_ret = CMD_ERROR;
+                                       goto end;
+                               }
+                       }
+                       goto end;
+               }
+               i++;
+               cmd = &actions[i];
+       }
+
+       cmd_ret = CMD_UNDEFINED;
+
+end:
+       return cmd_ret;
+}
+/*
+ * The 'snapshot <cmd> <options>' first level command
+ */
+int cmd_snapshot(int argc, const char **argv)
+{
+       int opt;
+       int mi_ret;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       char *session_name = NULL;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, snapshot_opts, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open command element */
+               mi_ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_snapshot);
+               if (mi_ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               mi_ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (mi_ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+               {
+                       int ret;
+
+                       /* SHOW_HELP assigns to ret. */
+                       SHOW_HELP();
+                       cmd_ret = (cmd_error_code) ret;
+                       goto end;
+               }
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, snapshot_opts);
+                       goto end;
+               case OPT_LIST_COMMANDS:
+                       list_commands(actions, stdout);
+                       goto end;
+               case OPT_MAX_SIZE:
+               {
+                       uint64_t val;
+                       const char *max_size_arg = poptGetOptArg(pc);
+
+                       if (utils_parse_size_suffix((char *) max_size_arg, &val) < 0) {
+                               ERR("Unable to handle max-size value %s",
+                                               max_size_arg);
+                               cmd_ret = CMD_ERROR;
+                               goto end;
+                       }
+
+                       opt_max_size = val;
+
+                       break;
+               }
+               default:
+                       cmd_ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+               current_session_name = session_name;
+       } else {
+               current_session_name = opt_session_name;
+       }
+
+       cmd_ret = handle_command(poptGetArgs(pc));
+
+       if (lttng_opt_mi) {
+               /* Close output element */
+               mi_ret = mi_lttng_writer_close_element(writer);
+               if (mi_ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               mi_ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success,
+                               cmd_ret == CMD_SUCCESS);
+               if (mi_ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               mi_ret = mi_lttng_writer_command_close(writer);
+               if (mi_ret) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+end:
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               cmd_ret = CMD_ERROR;
+       }
+
+       if (!opt_session_name) {
+               free(session_name);
+       }
+
+       poptFreeContext(pc);
+       return cmd_ret;
+}
diff --git a/src/bin/lttng/commands/start.c b/src/bin/lttng/commands/start.c
deleted file mode 100644 (file)
index 7082e09..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-
-static char *opt_session_name;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-start.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int mi_print_session(char *session_name, int enabled)
-{
-       int ret;
-
-       /* Open session element */
-       ret = mi_lttng_writer_open_element(writer, config_element_session);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print session name element */
-       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
-                       session_name);
-       if (ret) {
-               goto end;
-       }
-
-       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
-                       enabled);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close session element */
-       ret = mi_lttng_writer_close_element(writer);
-
-end:
-       return ret;
-}
-
-/*
- *  start_tracing
- *
- *  Start tracing for all trace of the session.
- */
-static int start_tracing(void)
-{
-       int ret;
-       char *session_name;
-
-       if (opt_session_name == NULL) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       DBG("Starting tracing for session %s", session_name);
-
-       ret = lttng_start_tracing(session_name);
-       if (ret < 0) {
-               switch (-ret) {
-               case LTTNG_ERR_TRACE_ALREADY_STARTED:
-                       WARN("Tracing already started for session %s", session_name);
-                       break;
-               default:
-                       ERR("%s", lttng_strerror(ret));
-                       break;
-               }
-               goto free_name;
-       }
-
-       ret = CMD_SUCCESS;
-
-       MSG("Tracing started for session %s", session_name);
-       if (lttng_opt_mi) {
-               ret = mi_print_session(session_name, 1);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto free_name;
-               }
-       }
-
-free_name:
-       if (opt_session_name == NULL) {
-               free(session_name);
-       }
-error:
-       return ret;
-}
-
-/*
- *  cmd_start
- *
- *  The 'start <options>' first level command
- */
-int cmd_start(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       const char *leftover = NULL;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       opt_session_name = (char*) poptGetArg(pc);
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_start);
-               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;
-               }
-
-               /*
-                * Open sessions element
-                * For validation purpose
-                */
-               ret = mi_lttng_writer_open_element(writer,
-                       config_element_sessions);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       command_ret = start_tracing();
-       if (command_ret) {
-               success = 0;
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close  sessions and output element */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       /* Overwrite ret if an error occurred with start_tracing */
-       ret = command_ret ? command_ret : ret;
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/start.cpp b/src/bin/lttng/commands/start.cpp
new file mode 100644 (file)
index 0000000..7082e09
--- /dev/null
@@ -0,0 +1,242 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+
+static char *opt_session_name;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-start.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int mi_print_session(char *session_name, int enabled)
+{
+       int ret;
+
+       /* Open session element */
+       ret = mi_lttng_writer_open_element(writer, config_element_session);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print session name element */
+       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
+                       session_name);
+       if (ret) {
+               goto end;
+       }
+
+       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
+                       enabled);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close session element */
+       ret = mi_lttng_writer_close_element(writer);
+
+end:
+       return ret;
+}
+
+/*
+ *  start_tracing
+ *
+ *  Start tracing for all trace of the session.
+ */
+static int start_tracing(void)
+{
+       int ret;
+       char *session_name;
+
+       if (opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       DBG("Starting tracing for session %s", session_name);
+
+       ret = lttng_start_tracing(session_name);
+       if (ret < 0) {
+               switch (-ret) {
+               case LTTNG_ERR_TRACE_ALREADY_STARTED:
+                       WARN("Tracing already started for session %s", session_name);
+                       break;
+               default:
+                       ERR("%s", lttng_strerror(ret));
+                       break;
+               }
+               goto free_name;
+       }
+
+       ret = CMD_SUCCESS;
+
+       MSG("Tracing started for session %s", session_name);
+       if (lttng_opt_mi) {
+               ret = mi_print_session(session_name, 1);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto free_name;
+               }
+       }
+
+free_name:
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+error:
+       return ret;
+}
+
+/*
+ *  cmd_start
+ *
+ *  The 'start <options>' first level command
+ */
+int cmd_start(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       const char *leftover = NULL;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_start);
+               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;
+               }
+
+               /*
+                * Open sessions element
+                * For validation purpose
+                */
+               ret = mi_lttng_writer_open_element(writer,
+                       config_element_sessions);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       command_ret = start_tracing();
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close  sessions and output element */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       /* Overwrite ret if an error occurred with start_tracing */
+       ret = command_ret ? command_ret : ret;
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/status.c b/src/bin/lttng/commands/status.c
deleted file mode 100644 (file)
index 23e8c03..0000000
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * Copyright (C) 2015 Philippe Proulx <pproulx@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include "../command.h"
-#include "../utils.h"
-#include <config.h>
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-status.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
-       {"list-options", 0,  POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-static int status(void)
-{
-       const char *argv[2];
-       int ret = CMD_SUCCESS;
-       char *session_name = NULL;
-
-       session_name = get_session_name();
-       if (!session_name) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       argv[0] = "list";
-       argv[1] = session_name;
-       ret = cmd_list(2, argv);
-end:
-       free(session_name);
-       return ret;
-}
-
-/*
- * The 'status <options>' first level command
- */
-int cmd_status(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS;
-       static poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (poptPeekArg(pc) != NULL) {
-               ERR("This command does not accept positional arguments.\n");
-               ret = CMD_UNDEFINED;
-               goto end;
-       }
-
-       ret = status();
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/status.cpp b/src/bin/lttng/commands/status.cpp
new file mode 100644 (file)
index 0000000..23e8c03
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2015 Philippe Proulx <pproulx@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "../command.h"
+#include "../utils.h"
+#include <config.h>
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-status.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, NULL, OPT_HELP, NULL, NULL},
+       {"list-options", 0,  POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+static int status(void)
+{
+       const char *argv[2];
+       int ret = CMD_SUCCESS;
+       char *session_name = NULL;
+
+       session_name = get_session_name();
+       if (!session_name) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       argv[0] = "list";
+       argv[1] = session_name;
+       ret = cmd_list(2, argv);
+end:
+       free(session_name);
+       return ret;
+}
+
+/*
+ * The 'status <options>' first level command
+ */
+int cmd_status(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (poptPeekArg(pc) != NULL) {
+               ERR("This command does not accept positional arguments.\n");
+               ret = CMD_UNDEFINED;
+               goto end;
+       }
+
+       ret = status();
+end:
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/stop.c b/src/bin/lttng/commands/stop.c
deleted file mode 100644 (file)
index d69da40..0000000
+++ /dev/null
@@ -1,270 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/sessiond-comm/sessiond-comm.h>
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-
-static char *opt_session_name;
-static int opt_no_wait;
-static struct mi_writer *writer;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-stop.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- * Mi print of partial session
- */
-static int mi_print_session(char *session_name, int enabled)
-{
-       int ret;
-       LTTNG_ASSERT(writer);
-       LTTNG_ASSERT(session_name);
-
-       /* Open session element */
-       ret = mi_lttng_writer_open_element(writer, config_element_session);
-       if (ret) {
-               goto end;
-       }
-
-       /* Print session name element */
-       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
-                       session_name);
-       if (ret) {
-               goto end;
-       }
-
-       /* Is enabled ? */
-       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
-                       enabled);
-       if (ret) {
-               goto end;
-       }
-
-       /* Close session element */
-       ret = mi_lttng_writer_close_element(writer);
-
-end:
-       return ret;
-}
-
-/*
- * Start tracing for all trace of the session.
- */
-static int stop_tracing(void)
-{
-       int ret;
-       char *session_name;
-
-       if (opt_session_name == NULL) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       ret = lttng_stop_tracing_no_wait(session_name);
-       if (ret < 0) {
-               switch (-ret) {
-               case LTTNG_ERR_TRACE_ALREADY_STOPPED:
-                       WARN("Tracing already stopped for session %s", session_name);
-                       break;
-               default:
-                       ERR("%s", lttng_strerror(ret));
-                       break;
-               }
-               goto free_name;
-       }
-
-       if (!opt_no_wait) {
-               _MSG("Waiting for data availability");
-               fflush(stdout);
-               do {
-                       ret = lttng_data_pending(session_name);
-                       if (ret < 0) {
-                               /* Return the data available call error. */
-                               goto free_name;
-                       }
-
-                       /*
-                        * Data sleep time before retrying (in usec). Don't sleep if the call
-                        * returned value indicates availability.
-                        */
-                       if (ret) {
-                               usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
-                               _MSG(".");
-                               fflush(stdout);
-                       }
-               } while (ret != 0);
-               MSG("");
-       }
-
-       ret = CMD_SUCCESS;
-
-       print_session_stats(session_name);
-       MSG("Tracing stopped for session %s", session_name);
-       if (lttng_opt_mi) {
-               ret = mi_print_session(session_name, 0);
-               if (ret) {
-                       goto free_name;
-               }
-       }
-
-free_name:
-       if (opt_session_name == NULL) {
-               free(session_name);
-       }
-
-error:
-       return ret;
-}
-
-/*
- *  cmd_stop
- *
- *  The 'stop <options>' first level command
- */
-int cmd_stop(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
-       static poptContext pc;
-       const char *leftover = NULL;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       ret = -LTTNG_ERR_NOMEM;
-                       goto end;
-               }
-
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               mi_lttng_element_command_stop);
-               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;
-               }
-
-               /*
-                * Open sessions element
-                * For validation
-                */
-               ret = mi_lttng_writer_open_element(writer,
-                               config_element_sessions);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       opt_session_name = (char*) poptGetArg(pc);
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       command_ret = stop_tracing();
-       if (command_ret) {
-               success = 0;
-       }
-
-       /* Mi closing */
-       if (lttng_opt_mi) {
-               /* Close sessions and  output element */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success, success);
-               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;
-       }
-
-       /* Overwrite ret if an error occurred in stop_tracing() */
-       ret = command_ret ? command_ret : ret;
-
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/stop.cpp b/src/bin/lttng/commands/stop.cpp
new file mode 100644 (file)
index 0000000..d69da40
--- /dev/null
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/sessiond-comm/sessiond-comm.h>
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+
+static char *opt_session_name;
+static int opt_no_wait;
+static struct mi_writer *writer;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-stop.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"no-wait",   'n', POPT_ARG_VAL, &opt_no_wait, 1, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ * Mi print of partial session
+ */
+static int mi_print_session(char *session_name, int enabled)
+{
+       int ret;
+       LTTNG_ASSERT(writer);
+       LTTNG_ASSERT(session_name);
+
+       /* Open session element */
+       ret = mi_lttng_writer_open_element(writer, config_element_session);
+       if (ret) {
+               goto end;
+       }
+
+       /* Print session name element */
+       ret = mi_lttng_writer_write_element_string(writer, config_element_name,
+                       session_name);
+       if (ret) {
+               goto end;
+       }
+
+       /* Is enabled ? */
+       ret = mi_lttng_writer_write_element_bool(writer, config_element_enabled,
+                       enabled);
+       if (ret) {
+               goto end;
+       }
+
+       /* Close session element */
+       ret = mi_lttng_writer_close_element(writer);
+
+end:
+       return ret;
+}
+
+/*
+ * Start tracing for all trace of the session.
+ */
+static int stop_tracing(void)
+{
+       int ret;
+       char *session_name;
+
+       if (opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       ret = lttng_stop_tracing_no_wait(session_name);
+       if (ret < 0) {
+               switch (-ret) {
+               case LTTNG_ERR_TRACE_ALREADY_STOPPED:
+                       WARN("Tracing already stopped for session %s", session_name);
+                       break;
+               default:
+                       ERR("%s", lttng_strerror(ret));
+                       break;
+               }
+               goto free_name;
+       }
+
+       if (!opt_no_wait) {
+               _MSG("Waiting for data availability");
+               fflush(stdout);
+               do {
+                       ret = lttng_data_pending(session_name);
+                       if (ret < 0) {
+                               /* Return the data available call error. */
+                               goto free_name;
+                       }
+
+                       /*
+                        * Data sleep time before retrying (in usec). Don't sleep if the call
+                        * returned value indicates availability.
+                        */
+                       if (ret) {
+                               usleep(DEFAULT_DATA_AVAILABILITY_WAIT_TIME_US);
+                               _MSG(".");
+                               fflush(stdout);
+                       }
+               } while (ret != 0);
+               MSG("");
+       }
+
+       ret = CMD_SUCCESS;
+
+       print_session_stats(session_name);
+       MSG("Tracing stopped for session %s", session_name);
+       if (lttng_opt_mi) {
+               ret = mi_print_session(session_name, 0);
+               if (ret) {
+                       goto free_name;
+               }
+       }
+
+free_name:
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+
+error:
+       return ret;
+}
+
+/*
+ *  cmd_stop
+ *
+ *  The 'stop <options>' first level command
+ */
+int cmd_stop(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1;
+       static poptContext pc;
+       const char *leftover = NULL;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       ret = -LTTNG_ERR_NOMEM;
+                       goto end;
+               }
+
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               mi_lttng_element_command_stop);
+               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;
+               }
+
+               /*
+                * Open sessions element
+                * For validation
+                */
+               ret = mi_lttng_writer_open_element(writer,
+                               config_element_sessions);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       command_ret = stop_tracing();
+       if (command_ret) {
+               success = 0;
+       }
+
+       /* Mi closing */
+       if (lttng_opt_mi) {
+               /* Close sessions and  output element */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success, success);
+               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;
+       }
+
+       /* Overwrite ret if an error occurred in stop_tracing() */
+       ret = command_ret ? command_ret : ret;
+
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/track-untrack.c b/src/bin/lttng/commands/track-untrack.c
deleted file mode 100644 (file)
index f175e2a..0000000
+++ /dev/null
@@ -1,819 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
- * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <ctype.h>
-#include <popt.h>
-#include <stdbool.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <urcu/list.h>
-
-#include <common/dynamic-array.h>
-#include <common/mi-lttng.h>
-#include <common/optional.h>
-#include <common/dynamic-buffer.h>
-#include <common/tracker.h>
-
-#include <lttng/lttng.h>
-
-#include "../command.h"
-
-struct process_attr_command_args {
-       enum lttng_process_attr process_attr;
-       /* Present in the user's command. */
-       bool requested;
-       bool all;
-       struct lttng_dynamic_pointer_array string_args;
-};
-
-enum cmd_type {
-       CMD_TRACK,
-       CMD_UNTRACK,
-};
-
-/* Offset OPT_ values by one since libpopt gives '0' a special meaning. */
-enum {
-       OPT_PID = LTTNG_PROCESS_ATTR_PROCESS_ID + 1,
-       OPT_VPID = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID + 1,
-       OPT_UID = LTTNG_PROCESS_ATTR_USER_ID + 1,
-       OPT_VUID = LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID + 1,
-       OPT_GID = LTTNG_PROCESS_ATTR_GROUP_ID + 1,
-       OPT_VGID = LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1,
-       OPT_HELP,
-       OPT_LIST_OPTIONS,
-       OPT_SESSION,
-       OPT_ALL,
-};
-
-static char *opt_session_name;
-static int opt_kernel;
-static int opt_userspace;
-static char *opt_str_arg;
-
-static struct poptOption long_options[] = {
-       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
-       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
-       { "session",            's', POPT_ARG_STRING, &opt_session_name, OPT_SESSION, 0, 0, },
-       { "kernel",             'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0, },
-       { "userspace",          'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0, },
-       { "pid",                'p', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_PID, 0, 0, },
-       { "vpid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VPID, 0, 0, },
-       { "uid",                0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_UID, 0, 0, },
-       { "vuid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VUID, 0, 0, },
-       { "gid",                0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_GID, 0, 0, },
-       { "vgid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VGID, 0, 0, },
-       { "all",                'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0, },
-       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
-       { 0, 0, 0, 0, 0, 0, 0, },
-};
-
-static struct process_attr_command_args
-               process_attr_commands[LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1];
-
-static void process_attr_command_init(struct process_attr_command_args *cmd,
-               enum lttng_process_attr process_attr)
-{
-       cmd->process_attr = process_attr;
-       cmd->all = false;
-       lttng_dynamic_pointer_array_init(&cmd->string_args, NULL);
-}
-
-static void process_attr_command_fini(struct process_attr_command_args *cmd)
-{
-       lttng_dynamic_pointer_array_reset(&cmd->string_args);
-}
-
-static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
-{
-       switch (process_attr) {
-       case LTTNG_PROCESS_ATTR_PROCESS_ID:
-               return "Process ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
-               return "Virtual process ID";
-       case LTTNG_PROCESS_ATTR_USER_ID:
-               return "User ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
-               return "Virtual user ID";
-       case LTTNG_PROCESS_ATTR_GROUP_ID:
-               return "Group ID";
-       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
-               return "Virtual group ID";
-       default:
-               return "Unknown";
-       }
-       return NULL;
-}
-
-static bool ust_process_attr_supported(enum lttng_process_attr *process_attr)
-{
-       bool supported;
-
-       switch (*process_attr) {
-       case LTTNG_PROCESS_ATTR_PROCESS_ID:
-               *process_attr = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID;
-               /* fall-through. */
-       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
-       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
-       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
-               supported = true;
-               break;
-       default:
-               ERR("The %s process attribute cannot be tracked in the user space domain.",
-                               lttng_process_attr_to_string(*process_attr));
-               supported = false;
-               break;
-       }
-       return supported;
-}
-
-static const char *get_mi_element_command(enum cmd_type cmd_type)
-{
-       switch (cmd_type) {
-       case CMD_TRACK:
-               return mi_lttng_element_command_track;
-       case CMD_UNTRACK:
-               return mi_lttng_element_command_untrack;
-       default:
-               abort();
-       }
-}
-
-static enum cmd_error_code run_command_all(enum cmd_type cmd_type,
-               const char *session_name,
-               enum lttng_domain_type domain_type,
-               enum lttng_process_attr process_attr,
-               struct mi_writer *writer)
-{
-       struct lttng_process_attr_tracker_handle *tracker_handle = NULL;
-       const enum lttng_error_code handle_ret_code =
-                       lttng_session_get_tracker_handle(session_name,
-                                       domain_type, process_attr,
-                                       &tracker_handle);
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       enum lttng_process_attr_tracker_handle_status status;
-
-       if (writer) {
-               const int ret = mi_lttng_all_process_attribute_value(
-                               writer, process_attr, true);
-               if (ret) {
-                       cmd_ret = CMD_FATAL;
-                       goto end;
-               }
-       }
-
-       if (handle_ret_code != LTTNG_OK) {
-               ERR("Session `%s` does not exist", session_name);
-               cmd_ret = CMD_FATAL;
-               goto end;
-       }
-
-       status = lttng_process_attr_tracker_handle_set_tracking_policy(
-                       tracker_handle,
-                       cmd_type == CMD_TRACK ?
-                                       LTTNG_TRACKING_POLICY_INCLUDE_ALL :
-                                       LTTNG_TRACKING_POLICY_EXCLUDE_ALL);
-       switch (status) {
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
-               if (cmd_type == CMD_TRACK) {
-                       MSG("%s tracking policy set to `include all`",
-                                       get_capitalized_process_attr_str(process_attr));
-               } else {
-                       MSG("%s tracking policy set to `exclude all`",
-                                       get_capitalized_process_attr_str(process_attr));
-               }
-               break;
-       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
-               ERR("%s", lttng_strerror(-LTTNG_ERR_SESS_NOT_FOUND));
-               break;
-       default:
-               ERR("Unknown error encountered while setting tracking policy of %s tracker to `%s`",
-                               lttng_process_attr_to_string(process_attr),
-                               cmd_type == CMD_TRACK ? "include all" :
-                                                       "exclude all");
-               cmd_ret = CMD_FATAL;
-               break;
-       }
-end:
-       if (writer) {
-               int ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_success,
-                               cmd_ret == CMD_SUCCESS);
-
-               if (ret) {
-                       cmd_ret = CMD_FATAL;
-               } else {
-                       ret = mi_lttng_writer_close_element(writer);
-                       cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
-               }
-       }
-       lttng_process_attr_tracker_handle_destroy(tracker_handle);
-       return cmd_ret;
-}
-
-static enum cmd_error_code run_command_string(enum cmd_type cmd_type,
-               const char *session_name,
-               enum lttng_domain_type domain_type,
-               enum lttng_process_attr process_attr,
-               const char *_args,
-               struct mi_writer *writer)
-{
-       struct lttng_process_attr_tracker_handle *tracker_handle;
-       const enum lttng_error_code handle_ret_code =
-                       lttng_session_get_tracker_handle(session_name,
-                                       domain_type, process_attr,
-                                       &tracker_handle);
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       const char *one_value_str;
-       char *args = strdup(_args);
-       char *iter = args;
-       bool policy_set = false;
-
-       if (!args) {
-               ERR("%s", lttng_strerror(-LTTNG_ERR_NOMEM));
-               cmd_ret = CMD_FATAL;
-               goto end;
-       }
-
-       if (handle_ret_code != LTTNG_OK) {
-               ERR("%s", lttng_strerror(-handle_ret_code));
-               cmd_ret = CMD_FATAL;
-               goto end;
-       }
-
-       while ((one_value_str = strtok_r(iter, ",", &iter)) != NULL) {
-               const bool is_numerical_argument = isdigit(one_value_str[0]);
-               enum lttng_process_attr_tracker_handle_status status;
-               enum lttng_tracking_policy policy;
-               int ret;
-               char *prettified_arg;
-
-               if (!policy_set) {
-                       status = lttng_process_attr_tracker_handle_get_tracking_policy(
-                                       tracker_handle, &policy);
-                       if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
-                               break;
-                       }
-
-                       if (policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
-                               status = lttng_process_attr_tracker_handle_set_tracking_policy(
-                                               tracker_handle,
-                                               LTTNG_TRACKING_POLICY_INCLUDE_SET);
-                               if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
-                                       break;
-                               }
-                       }
-                       policy_set = true;
-               }
-
-               if (is_numerical_argument) {
-                       const unsigned long one_value_int =
-                                       strtoul(one_value_str, NULL, 10);
-
-                       if (writer) {
-                               ret = mi_lttng_integral_process_attribute_value(
-                                               writer, process_attr,
-                                               (int64_t) one_value_int, true);
-                               if (ret) {
-                                       cmd_ret = CMD_FATAL;
-                                       goto end;
-                               }
-                       }
-
-                       switch (process_attr) {
-                       case LTTNG_PROCESS_ATTR_PROCESS_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_process_id_tracker_handle_add_pid(
-                                                                        tracker_handle,
-                                                                        (pid_t) one_value_int) :
-                                                        lttng_process_attr_process_id_tracker_handle_remove_pid(
-                                                                        tracker_handle,
-                                                                        (pid_t) one_value_int);
-                               break;
-                       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_virtual_process_id_tracker_handle_add_pid(
-                                                                        tracker_handle,
-                                                                        (pid_t) one_value_int) :
-                                                        lttng_process_attr_virtual_process_id_tracker_handle_remove_pid(
-                                                                        tracker_handle,
-                                                                        (pid_t) one_value_int);
-                               break;
-                       case LTTNG_PROCESS_ATTR_USER_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_user_id_tracker_handle_add_uid(
-                                                                        tracker_handle,
-                                                                        (uid_t) one_value_int) :
-                                                        lttng_process_attr_user_id_tracker_handle_remove_uid(
-                                                                        tracker_handle,
-                                                                        (uid_t) one_value_int);
-                               break;
-                       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_virtual_user_id_tracker_handle_add_uid(
-                                                                        tracker_handle,
-                                                                        (uid_t) one_value_int) :
-                                                        lttng_process_attr_virtual_user_id_tracker_handle_remove_uid(
-                                                                        tracker_handle,
-                                                                        (uid_t) one_value_int);
-                               break;
-                       case LTTNG_PROCESS_ATTR_GROUP_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_group_id_tracker_handle_add_gid(
-                                                                        tracker_handle,
-                                                                        (gid_t) one_value_int) :
-                                                        lttng_process_attr_group_id_tracker_handle_remove_gid(
-                                                                        tracker_handle,
-                                                                        (gid_t) one_value_int);
-                               break;
-                       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_virtual_group_id_tracker_handle_add_gid(
-                                                                        tracker_handle,
-                                                                        (gid_t) one_value_int) :
-                                                        lttng_process_attr_virtual_group_id_tracker_handle_remove_gid(
-                                                                        tracker_handle,
-                                                                        (gid_t) one_value_int);
-                               break;
-                       default:
-                               abort();
-                       }
-
-               } else {
-                       if (writer) {
-                               ret = mi_lttng_string_process_attribute_value(
-                                               writer, process_attr,
-                                               one_value_str, true);
-                               if (ret) {
-                                       cmd_ret = CMD_FATAL;
-                                       goto end;
-                               }
-                       }
-
-                       switch (process_attr) {
-                       case LTTNG_PROCESS_ATTR_USER_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_user_id_tracker_handle_add_user_name(
-                                                                        tracker_handle,
-                                                                        one_value_str) :
-                                                        lttng_process_attr_user_id_tracker_handle_remove_user_name(
-                                                                        tracker_handle,
-                                                                        one_value_str);
-                               break;
-                       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_virtual_user_id_tracker_handle_add_user_name(
-                                                                        tracker_handle,
-                                                                        one_value_str) :
-                                                        lttng_process_attr_virtual_user_id_tracker_handle_remove_user_name(
-                                                                        tracker_handle,
-                                                                        one_value_str);
-                               break;
-                       case LTTNG_PROCESS_ATTR_GROUP_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_group_id_tracker_handle_add_group_name(
-                                                                        tracker_handle,
-                                                                        one_value_str) :
-                                                        lttng_process_attr_group_id_tracker_handle_remove_group_name(
-                                                                        tracker_handle,
-                                                                        one_value_str);
-                               break;
-                       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
-                               status = cmd_type == CMD_TRACK ?
-                                                        lttng_process_attr_virtual_group_id_tracker_handle_add_group_name(
-                                                                        tracker_handle,
-                                                                        one_value_str) :
-                                                        lttng_process_attr_virtual_group_id_tracker_handle_remove_group_name(
-                                                                        tracker_handle,
-                                                                        one_value_str);
-                               break;
-                       default:
-                               ERR("%s is not a valid %s value; expected an integer",
-                                               one_value_str,
-                                               lttng_process_attr_to_string(
-                                                               process_attr));
-                               cmd_ret = CMD_FATAL;
-                               goto end;
-                       }
-               }
-
-               ret = asprintf(&prettified_arg,
-                               is_numerical_argument ? "%s" : "`%s`",
-                               one_value_str);
-               if (ret < 0) {
-                       PERROR("Failed to format argument `%s`", one_value_str);
-                       cmd_ret = CMD_FATAL;
-                       goto end;
-               }
-
-               switch (status) {
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
-                       if (cmd_type == CMD_TRACK) {
-                               MSG("Added %s to the %s tracker inclusion set",
-                                               one_value_str,
-                                               lttng_process_attr_to_string(
-                                                               process_attr));
-                       } else {
-                               MSG("Removed %s from the %s tracker inclusion set",
-                                               one_value_str,
-                                               lttng_process_attr_to_string(
-                                                               process_attr));
-                       }
-                       break;
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
-                       ERR("Session `%s` not found", session_name);
-                       break;
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_EXISTS:
-                       WARN("%s is already in the %s inclusion set",
-                                       prettified_arg,
-                                       lttng_process_attr_to_string(
-                                                       process_attr));
-                       break;
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_MISSING:
-                       WARN("%s is not in the %s the inclusion set",
-                                       prettified_arg,
-                                       lttng_process_attr_to_string(
-                                                       process_attr));
-                       break;
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_USER_NOT_FOUND:
-                       ERR("User %s was not found", prettified_arg);
-                       cmd_ret = CMD_ERROR;
-                       break;
-               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_GROUP_NOT_FOUND:
-                       ERR("Group %s was not found", prettified_arg);
-                       cmd_ret = CMD_ERROR;
-                       break;
-               default:
-                       ERR("Unknown error encountered while %s %s %s %s tracker's inclusion set",
-                                       cmd_type == CMD_TRACK ? "adding" :
-                                                               "removing",
-                                       lttng_process_attr_to_string(
-                                                       process_attr),
-                                       prettified_arg,
-                                       cmd_type == CMD_TRACK ? "to" : "from");
-                       cmd_ret = CMD_FATAL;
-                       break;
-               }
-               free(prettified_arg);
-
-               if (writer) {
-                       ret = mi_lttng_writer_write_element_bool(writer,
-                                       mi_lttng_element_success,
-                                       cmd_ret == CMD_SUCCESS);
-
-                       if (ret) {
-                               cmd_ret = CMD_FATAL;
-                       } else {
-                               ret = mi_lttng_writer_close_element(writer);
-                               cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
-                       }
-               }
-       }
-end:
-       free(args);
-       lttng_process_attr_tracker_handle_destroy(tracker_handle);
-       return cmd_ret;
-}
-
-static enum cmd_error_code run_command(enum cmd_type cmd_type,
-               const char *session_name,
-               const struct process_attr_command_args *command_args,
-               struct mi_writer *writer)
-{
-       const enum lttng_domain_type domain_type =
-                       opt_kernel ? LTTNG_DOMAIN_KERNEL : LTTNG_DOMAIN_UST;
-       enum cmd_error_code cmd_ret = CMD_SUCCESS;
-       unsigned int i;
-       const unsigned int string_arg_count =
-                       lttng_dynamic_pointer_array_get_count(
-                                       &command_args->string_args);
-       enum lttng_process_attr process_attr = command_args->process_attr;
-
-       if (opt_userspace) {
-               /*
-                * Check that this process attribute can be tracked
-                * in the user space domain. Backward-compatibility
-                * changes are be applied to process_attr as needed.
-                */
-               if (!ust_process_attr_supported(&process_attr)) {
-                       cmd_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       if (writer) {
-               /* Open tracker and trackers elements */
-               const int ret = mi_lttng_process_attribute_tracker_open(
-                               writer, process_attr);
-               if (ret) {
-                       cmd_ret = CMD_FATAL;
-                       goto end;
-               }
-       }
-
-       if (command_args->all) {
-               cmd_ret = run_command_all(cmd_type, session_name, domain_type,
-                               process_attr, writer);
-       } else {
-               bool error_occurred = false;
-
-               for (i = 0; i < string_arg_count; i++) {
-                       const char *arg = lttng_dynamic_pointer_array_get_pointer(
-                                       &command_args->string_args, i);
-
-                       cmd_ret = run_command_string(cmd_type, session_name,
-                                       domain_type, process_attr, arg, writer);
-                       if (cmd_ret != CMD_SUCCESS) {
-                               error_occurred = true;
-                               if (cmd_ret == CMD_FATAL) {
-                                       break;
-                               }
-                               goto end;
-                       }
-               }
-               if (error_occurred) {
-                       cmd_ret = CMD_ERROR;
-               }
-       }
-
-       if (writer) {
-               /* Close tracker and trackers elements */
-               const int ret = mi_lttng_close_multi_element(
-                               writer, 2);
-               if (ret) {
-                       cmd_ret = CMD_FATAL;
-                       goto end;
-               }
-       }
-end:
-       return cmd_ret;
-}
-
-/*
- * Add/remove tracker to/from session.
- */
-static int cmd_track_untrack(enum cmd_type cmd_type,
-               int argc,
-               const char **argv,
-               const char *help_msg)
-{
-       int opt, ret = 0;
-       bool sub_command_failed = false;
-       bool opt_all = false;
-       unsigned int selected_process_attr_tracker_count = 0;
-       const unsigned int command_count =
-                       sizeof(process_attr_commands) /
-                       sizeof(struct process_attr_command_args);
-       enum cmd_error_code command_ret = CMD_SUCCESS;
-       static poptContext pc;
-       char *session_name = NULL;
-       const char *leftover = NULL;
-       struct mi_writer *writer = NULL;
-       size_t i;
-
-       for (i = 0; i < command_count; i++) {
-               process_attr_command_init(&process_attr_commands[i], i);
-       }
-
-       if (argc < 1) {
-               command_ret = CMD_ERROR;
-               goto end;
-       }
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               case OPT_SESSION:
-                       break;
-               case OPT_PID:
-               case OPT_VPID:
-               case OPT_UID:
-               case OPT_VUID:
-               case OPT_GID:
-               case OPT_VGID:
-                       /* See OPT_ enum declaration comment.  */
-                       opt--;
-                       selected_process_attr_tracker_count++;
-                       process_attr_commands[opt].requested = true;
-                       if (!opt_str_arg) {
-                               continue;
-                       }
-                       ret = lttng_dynamic_pointer_array_add_pointer(
-                                       &process_attr_commands[opt].string_args,
-                                       opt_str_arg);
-                       if (ret) {
-                               ERR("Allocation failed while parsing command arguments");
-                               command_ret = CMD_ERROR;
-                               goto end;
-                       }
-                       break;
-               case OPT_ALL:
-                       opt_all = true;
-                       break;
-               default:
-                       command_ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       ret = print_missing_or_multiple_domains(
-                       opt_kernel + opt_userspace, false);
-       if (ret) {
-               command_ret = CMD_ERROR;
-               goto end;
-       }
-
-       if (selected_process_attr_tracker_count == 0) {
-               ERR("At least one process attribute must be specified");
-               command_ret = CMD_ERROR;
-               goto end;
-       }
-       if (opt_all) {
-               /*
-                * Only one process attribute tracker was specified; find it
-                * and set it in 'all' mode.
-                */
-               for (i = 0; i < command_count; i++) {
-                       if (!process_attr_commands[i].requested) {
-                               continue;
-                       }
-                       process_attr_commands[i].all = true;
-                       if (lttng_dynamic_pointer_array_get_count(
-                                           &process_attr_commands[i]
-                                                            .string_args)) {
-                               ERR("The --all option cannot be used with a list of process attribute values");
-                               command_ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-       } else {
-               for (i = 0; i < command_count; i++) {
-                       if (!process_attr_commands[i].requested) {
-                               continue;
-                       }
-                       if (lttng_dynamic_pointer_array_get_count(
-                                   &process_attr_commands[i]
-                                   .string_args) == 0) {
-                               ERR("No process attribute value specified for %s tracker",
-                                               get_capitalized_process_attr_str(
-                                                               process_attr_commands[i]
-                                                                               .process_attr));
-                               command_ret = CMD_ERROR;
-                               goto end;
-                       }
-               }
-       }
-
-       if (!opt_session_name) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               command_ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* Mi check */
-       if (lttng_opt_mi) {
-               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-               if (!writer) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       if (writer) {
-               /* Open command element */
-               ret = mi_lttng_writer_command_open(writer,
-                               get_mi_element_command(cmd_type));
-               if (ret) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Open output element */
-               ret = mi_lttng_writer_open_element(writer,
-                               mi_lttng_element_command_output);
-               if (ret) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               ret = mi_lttng_trackers_open(writer);
-               if (ret) {
-                       goto end;
-               }
-       }
-
-       /* Execute sub-commands. */
-       for (i = 0; i < command_count; i++) {
-               if (!process_attr_commands[i].requested) {
-                       continue;
-               }
-               command_ret = run_command(cmd_type, session_name,
-                               &process_attr_commands[i], writer);
-               if (command_ret != CMD_SUCCESS) {
-                       sub_command_failed = true;
-                       if (command_ret == CMD_FATAL) {
-                               break;
-                       }
-               }
-       }
-
-       /* Mi closing */
-       if (writer) {
-               /* Close trackers and output elements */
-               ret = mi_lttng_close_multi_element(writer, 2);
-               if (ret) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Success ? */
-               ret = mi_lttng_writer_write_element_bool(writer,
-                               mi_lttng_element_command_success,
-                               !sub_command_failed);
-               if (ret) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Command element close */
-               ret = mi_lttng_writer_command_close(writer);
-               if (ret) {
-                       command_ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-end:
-       if (!opt_session_name) {
-               free(session_name);
-       }
-
-       /* Mi clean-up */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               command_ret = CMD_ERROR;
-       }
-
-       for (i = 0; i < command_count; i++) {
-               process_attr_command_fini(&process_attr_commands[i]);
-       }
-
-       poptFreeContext(pc);
-       return (int) command_ret;
-}
-
-int cmd_track(int argc, const char **argv)
-{
-       static const char *help_msg =
-#ifdef LTTNG_EMBED_HELP
-#include <lttng-track.1.h>
-#else
-       NULL
-#endif
-       ;
-
-       return cmd_track_untrack(CMD_TRACK, argc, argv, help_msg);
-}
-
-int cmd_untrack(int argc, const char **argv)
-{
-       static const char *help_msg =
-#ifdef LTTNG_EMBED_HELP
-#include <lttng-untrack.1.h>
-#else
-       NULL
-#endif
-       ;
-
-       return cmd_track_untrack(CMD_UNTRACK, argc, argv, help_msg);
-}
diff --git a/src/bin/lttng/commands/track-untrack.cpp b/src/bin/lttng/commands/track-untrack.cpp
new file mode 100644 (file)
index 0000000..7db4488
--- /dev/null
@@ -0,0 +1,819 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ * Copyright (C) 2015 Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2020 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <ctype.h>
+#include <popt.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <urcu/list.h>
+
+#include <common/dynamic-array.h>
+#include <common/mi-lttng.h>
+#include <common/optional.h>
+#include <common/dynamic-buffer.h>
+#include <common/tracker.h>
+
+#include <lttng/lttng.h>
+
+#include "../command.h"
+
+struct process_attr_command_args {
+       enum lttng_process_attr process_attr;
+       /* Present in the user's command. */
+       bool requested;
+       bool all;
+       struct lttng_dynamic_pointer_array string_args;
+};
+
+enum cmd_type {
+       CMD_TRACK,
+       CMD_UNTRACK,
+};
+
+/* Offset OPT_ values by one since libpopt gives '0' a special meaning. */
+enum {
+       OPT_PID = LTTNG_PROCESS_ATTR_PROCESS_ID + 1,
+       OPT_VPID = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID + 1,
+       OPT_UID = LTTNG_PROCESS_ATTR_USER_ID + 1,
+       OPT_VUID = LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID + 1,
+       OPT_GID = LTTNG_PROCESS_ATTR_GROUP_ID + 1,
+       OPT_VGID = LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1,
+       OPT_HELP,
+       OPT_LIST_OPTIONS,
+       OPT_SESSION,
+       OPT_ALL,
+};
+
+static char *opt_session_name;
+static int opt_kernel;
+static int opt_userspace;
+static char *opt_str_arg;
+
+static struct poptOption long_options[] = {
+       /* { longName, shortName, argInfo, argPtr, value, descrip, argDesc, } */
+       { "help",               'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0, },
+       { "session",            's', POPT_ARG_STRING, &opt_session_name, OPT_SESSION, 0, 0, },
+       { "kernel",             'k', POPT_ARG_VAL, &opt_kernel, 1, 0, 0, },
+       { "userspace",          'u', POPT_ARG_VAL, &opt_userspace, 1, 0, 0, },
+       { "pid",                'p', POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_PID, 0, 0, },
+       { "vpid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VPID, 0, 0, },
+       { "uid",                0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_UID, 0, 0, },
+       { "vuid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VUID, 0, 0, },
+       { "gid",                0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_GID, 0, 0, },
+       { "vgid",               0, POPT_ARG_STRING | POPT_ARGFLAG_OPTIONAL, &opt_str_arg, OPT_VGID, 0, 0, },
+       { "all",                'a', POPT_ARG_NONE, 0, OPT_ALL, 0, 0, },
+       { "list-options",       0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, 0, 0, },
+       { 0, 0, 0, 0, 0, 0, 0, },
+};
+
+static struct process_attr_command_args
+               process_attr_commands[LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID + 1];
+
+static void process_attr_command_init(struct process_attr_command_args *cmd,
+               enum lttng_process_attr process_attr)
+{
+       cmd->process_attr = process_attr;
+       cmd->all = false;
+       lttng_dynamic_pointer_array_init(&cmd->string_args, NULL);
+}
+
+static void process_attr_command_fini(struct process_attr_command_args *cmd)
+{
+       lttng_dynamic_pointer_array_reset(&cmd->string_args);
+}
+
+static const char *get_capitalized_process_attr_str(enum lttng_process_attr process_attr)
+{
+       switch (process_attr) {
+       case LTTNG_PROCESS_ATTR_PROCESS_ID:
+               return "Process ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+               return "Virtual process ID";
+       case LTTNG_PROCESS_ATTR_USER_ID:
+               return "User ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+               return "Virtual user ID";
+       case LTTNG_PROCESS_ATTR_GROUP_ID:
+               return "Group ID";
+       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+               return "Virtual group ID";
+       default:
+               return "Unknown";
+       }
+       return NULL;
+}
+
+static bool ust_process_attr_supported(enum lttng_process_attr *process_attr)
+{
+       bool supported;
+
+       switch (*process_attr) {
+       case LTTNG_PROCESS_ATTR_PROCESS_ID:
+               *process_attr = LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID;
+               /* fall-through. */
+       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+               supported = true;
+               break;
+       default:
+               ERR("The %s process attribute cannot be tracked in the user space domain.",
+                               lttng_process_attr_to_string(*process_attr));
+               supported = false;
+               break;
+       }
+       return supported;
+}
+
+static const char *get_mi_element_command(enum cmd_type cmd_type)
+{
+       switch (cmd_type) {
+       case CMD_TRACK:
+               return mi_lttng_element_command_track;
+       case CMD_UNTRACK:
+               return mi_lttng_element_command_untrack;
+       default:
+               abort();
+       }
+}
+
+static enum cmd_error_code run_command_all(enum cmd_type cmd_type,
+               const char *session_name,
+               enum lttng_domain_type domain_type,
+               enum lttng_process_attr process_attr,
+               struct mi_writer *writer)
+{
+       struct lttng_process_attr_tracker_handle *tracker_handle = NULL;
+       const enum lttng_error_code handle_ret_code =
+                       lttng_session_get_tracker_handle(session_name,
+                                       domain_type, process_attr,
+                                       &tracker_handle);
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       enum lttng_process_attr_tracker_handle_status status;
+
+       if (writer) {
+               const int ret = mi_lttng_all_process_attribute_value(
+                               writer, process_attr, true);
+               if (ret) {
+                       cmd_ret = CMD_FATAL;
+                       goto end;
+               }
+       }
+
+       if (handle_ret_code != LTTNG_OK) {
+               ERR("Session `%s` does not exist", session_name);
+               cmd_ret = CMD_FATAL;
+               goto end;
+       }
+
+       status = lttng_process_attr_tracker_handle_set_tracking_policy(
+                       tracker_handle,
+                       cmd_type == CMD_TRACK ?
+                                       LTTNG_TRACKING_POLICY_INCLUDE_ALL :
+                                       LTTNG_TRACKING_POLICY_EXCLUDE_ALL);
+       switch (status) {
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
+               if (cmd_type == CMD_TRACK) {
+                       MSG("%s tracking policy set to `include all`",
+                                       get_capitalized_process_attr_str(process_attr));
+               } else {
+                       MSG("%s tracking policy set to `exclude all`",
+                                       get_capitalized_process_attr_str(process_attr));
+               }
+               break;
+       case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
+               ERR("%s", lttng_strerror(-LTTNG_ERR_SESS_NOT_FOUND));
+               break;
+       default:
+               ERR("Unknown error encountered while setting tracking policy of %s tracker to `%s`",
+                               lttng_process_attr_to_string(process_attr),
+                               cmd_type == CMD_TRACK ? "include all" :
+                                                       "exclude all");
+               cmd_ret = CMD_FATAL;
+               break;
+       }
+end:
+       if (writer) {
+               int ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_success,
+                               cmd_ret == CMD_SUCCESS);
+
+               if (ret) {
+                       cmd_ret = CMD_FATAL;
+               } else {
+                       ret = mi_lttng_writer_close_element(writer);
+                       cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
+               }
+       }
+       lttng_process_attr_tracker_handle_destroy(tracker_handle);
+       return cmd_ret;
+}
+
+static enum cmd_error_code run_command_string(enum cmd_type cmd_type,
+               const char *session_name,
+               enum lttng_domain_type domain_type,
+               enum lttng_process_attr process_attr,
+               const char *_args,
+               struct mi_writer *writer)
+{
+       struct lttng_process_attr_tracker_handle *tracker_handle;
+       const enum lttng_error_code handle_ret_code =
+                       lttng_session_get_tracker_handle(session_name,
+                                       domain_type, process_attr,
+                                       &tracker_handle);
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       const char *one_value_str;
+       char *args = strdup(_args);
+       char *iter = args;
+       bool policy_set = false;
+
+       if (!args) {
+               ERR("%s", lttng_strerror(-LTTNG_ERR_NOMEM));
+               cmd_ret = CMD_FATAL;
+               goto end;
+       }
+
+       if (handle_ret_code != LTTNG_OK) {
+               ERR("%s", lttng_strerror(-handle_ret_code));
+               cmd_ret = CMD_FATAL;
+               goto end;
+       }
+
+       while ((one_value_str = strtok_r(iter, ",", &iter)) != NULL) {
+               const bool is_numerical_argument = isdigit(one_value_str[0]);
+               enum lttng_process_attr_tracker_handle_status status;
+               enum lttng_tracking_policy policy;
+               int ret;
+               char *prettified_arg;
+
+               if (!policy_set) {
+                       status = lttng_process_attr_tracker_handle_get_tracking_policy(
+                                       tracker_handle, &policy);
+                       if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
+                               break;
+                       }
+
+                       if (policy != LTTNG_TRACKING_POLICY_INCLUDE_SET) {
+                               status = lttng_process_attr_tracker_handle_set_tracking_policy(
+                                               tracker_handle,
+                                               LTTNG_TRACKING_POLICY_INCLUDE_SET);
+                               if (status != LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK) {
+                                       break;
+                               }
+                       }
+                       policy_set = true;
+               }
+
+               if (is_numerical_argument) {
+                       const unsigned long one_value_int =
+                                       strtoul(one_value_str, NULL, 10);
+
+                       if (writer) {
+                               ret = mi_lttng_integral_process_attribute_value(
+                                               writer, process_attr,
+                                               (int64_t) one_value_int, true);
+                               if (ret) {
+                                       cmd_ret = CMD_FATAL;
+                                       goto end;
+                               }
+                       }
+
+                       switch (process_attr) {
+                       case LTTNG_PROCESS_ATTR_PROCESS_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_process_id_tracker_handle_add_pid(
+                                                                        tracker_handle,
+                                                                        (pid_t) one_value_int) :
+                                                        lttng_process_attr_process_id_tracker_handle_remove_pid(
+                                                                        tracker_handle,
+                                                                        (pid_t) one_value_int);
+                               break;
+                       case LTTNG_PROCESS_ATTR_VIRTUAL_PROCESS_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_virtual_process_id_tracker_handle_add_pid(
+                                                                        tracker_handle,
+                                                                        (pid_t) one_value_int) :
+                                                        lttng_process_attr_virtual_process_id_tracker_handle_remove_pid(
+                                                                        tracker_handle,
+                                                                        (pid_t) one_value_int);
+                               break;
+                       case LTTNG_PROCESS_ATTR_USER_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_user_id_tracker_handle_add_uid(
+                                                                        tracker_handle,
+                                                                        (uid_t) one_value_int) :
+                                                        lttng_process_attr_user_id_tracker_handle_remove_uid(
+                                                                        tracker_handle,
+                                                                        (uid_t) one_value_int);
+                               break;
+                       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_virtual_user_id_tracker_handle_add_uid(
+                                                                        tracker_handle,
+                                                                        (uid_t) one_value_int) :
+                                                        lttng_process_attr_virtual_user_id_tracker_handle_remove_uid(
+                                                                        tracker_handle,
+                                                                        (uid_t) one_value_int);
+                               break;
+                       case LTTNG_PROCESS_ATTR_GROUP_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_group_id_tracker_handle_add_gid(
+                                                                        tracker_handle,
+                                                                        (gid_t) one_value_int) :
+                                                        lttng_process_attr_group_id_tracker_handle_remove_gid(
+                                                                        tracker_handle,
+                                                                        (gid_t) one_value_int);
+                               break;
+                       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_virtual_group_id_tracker_handle_add_gid(
+                                                                        tracker_handle,
+                                                                        (gid_t) one_value_int) :
+                                                        lttng_process_attr_virtual_group_id_tracker_handle_remove_gid(
+                                                                        tracker_handle,
+                                                                        (gid_t) one_value_int);
+                               break;
+                       default:
+                               abort();
+                       }
+
+               } else {
+                       if (writer) {
+                               ret = mi_lttng_string_process_attribute_value(
+                                               writer, process_attr,
+                                               one_value_str, true);
+                               if (ret) {
+                                       cmd_ret = CMD_FATAL;
+                                       goto end;
+                               }
+                       }
+
+                       switch (process_attr) {
+                       case LTTNG_PROCESS_ATTR_USER_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_user_id_tracker_handle_add_user_name(
+                                                                        tracker_handle,
+                                                                        one_value_str) :
+                                                        lttng_process_attr_user_id_tracker_handle_remove_user_name(
+                                                                        tracker_handle,
+                                                                        one_value_str);
+                               break;
+                       case LTTNG_PROCESS_ATTR_VIRTUAL_USER_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_virtual_user_id_tracker_handle_add_user_name(
+                                                                        tracker_handle,
+                                                                        one_value_str) :
+                                                        lttng_process_attr_virtual_user_id_tracker_handle_remove_user_name(
+                                                                        tracker_handle,
+                                                                        one_value_str);
+                               break;
+                       case LTTNG_PROCESS_ATTR_GROUP_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_group_id_tracker_handle_add_group_name(
+                                                                        tracker_handle,
+                                                                        one_value_str) :
+                                                        lttng_process_attr_group_id_tracker_handle_remove_group_name(
+                                                                        tracker_handle,
+                                                                        one_value_str);
+                               break;
+                       case LTTNG_PROCESS_ATTR_VIRTUAL_GROUP_ID:
+                               status = cmd_type == CMD_TRACK ?
+                                                        lttng_process_attr_virtual_group_id_tracker_handle_add_group_name(
+                                                                        tracker_handle,
+                                                                        one_value_str) :
+                                                        lttng_process_attr_virtual_group_id_tracker_handle_remove_group_name(
+                                                                        tracker_handle,
+                                                                        one_value_str);
+                               break;
+                       default:
+                               ERR("%s is not a valid %s value; expected an integer",
+                                               one_value_str,
+                                               lttng_process_attr_to_string(
+                                                               process_attr));
+                               cmd_ret = CMD_FATAL;
+                               goto end;
+                       }
+               }
+
+               ret = asprintf(&prettified_arg,
+                               is_numerical_argument ? "%s" : "`%s`",
+                               one_value_str);
+               if (ret < 0) {
+                       PERROR("Failed to format argument `%s`", one_value_str);
+                       cmd_ret = CMD_FATAL;
+                       goto end;
+               }
+
+               switch (status) {
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_OK:
+                       if (cmd_type == CMD_TRACK) {
+                               MSG("Added %s to the %s tracker inclusion set",
+                                               one_value_str,
+                                               lttng_process_attr_to_string(
+                                                               process_attr));
+                       } else {
+                               MSG("Removed %s from the %s tracker inclusion set",
+                                               one_value_str,
+                                               lttng_process_attr_to_string(
+                                                               process_attr));
+                       }
+                       break;
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_SESSION_DOES_NOT_EXIST:
+                       ERR("Session `%s` not found", session_name);
+                       break;
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_EXISTS:
+                       WARN("%s is already in the %s inclusion set",
+                                       prettified_arg,
+                                       lttng_process_attr_to_string(
+                                                       process_attr));
+                       break;
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_MISSING:
+                       WARN("%s is not in the %s the inclusion set",
+                                       prettified_arg,
+                                       lttng_process_attr_to_string(
+                                                       process_attr));
+                       break;
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_USER_NOT_FOUND:
+                       ERR("User %s was not found", prettified_arg);
+                       cmd_ret = CMD_ERROR;
+                       break;
+               case LTTNG_PROCESS_ATTR_TRACKER_HANDLE_STATUS_GROUP_NOT_FOUND:
+                       ERR("Group %s was not found", prettified_arg);
+                       cmd_ret = CMD_ERROR;
+                       break;
+               default:
+                       ERR("Unknown error encountered while %s %s %s %s tracker's inclusion set",
+                                       cmd_type == CMD_TRACK ? "adding" :
+                                                               "removing",
+                                       lttng_process_attr_to_string(
+                                                       process_attr),
+                                       prettified_arg,
+                                       cmd_type == CMD_TRACK ? "to" : "from");
+                       cmd_ret = CMD_FATAL;
+                       break;
+               }
+               free(prettified_arg);
+
+               if (writer) {
+                       ret = mi_lttng_writer_write_element_bool(writer,
+                                       mi_lttng_element_success,
+                                       cmd_ret == CMD_SUCCESS);
+
+                       if (ret) {
+                               cmd_ret = CMD_FATAL;
+                       } else {
+                               ret = mi_lttng_writer_close_element(writer);
+                               cmd_ret = ret == 0 ? cmd_ret : CMD_FATAL;
+                       }
+               }
+       }
+end:
+       free(args);
+       lttng_process_attr_tracker_handle_destroy(tracker_handle);
+       return cmd_ret;
+}
+
+static enum cmd_error_code run_command(enum cmd_type cmd_type,
+               const char *session_name,
+               const struct process_attr_command_args *command_args,
+               struct mi_writer *writer)
+{
+       const enum lttng_domain_type domain_type =
+                       opt_kernel ? LTTNG_DOMAIN_KERNEL : LTTNG_DOMAIN_UST;
+       enum cmd_error_code cmd_ret = CMD_SUCCESS;
+       unsigned int i;
+       const unsigned int string_arg_count =
+                       lttng_dynamic_pointer_array_get_count(
+                                       &command_args->string_args);
+       enum lttng_process_attr process_attr = command_args->process_attr;
+
+       if (opt_userspace) {
+               /*
+                * Check that this process attribute can be tracked
+                * in the user space domain. Backward-compatibility
+                * changes are be applied to process_attr as needed.
+                */
+               if (!ust_process_attr_supported(&process_attr)) {
+                       cmd_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       if (writer) {
+               /* Open tracker and trackers elements */
+               const int ret = mi_lttng_process_attribute_tracker_open(
+                               writer, process_attr);
+               if (ret) {
+                       cmd_ret = CMD_FATAL;
+                       goto end;
+               }
+       }
+
+       if (command_args->all) {
+               cmd_ret = run_command_all(cmd_type, session_name, domain_type,
+                               process_attr, writer);
+       } else {
+               bool error_occurred = false;
+
+               for (i = 0; i < string_arg_count; i++) {
+                       const char *arg = (const char *) lttng_dynamic_pointer_array_get_pointer(
+                                       &command_args->string_args, i);
+
+                       cmd_ret = run_command_string(cmd_type, session_name,
+                                       domain_type, process_attr, arg, writer);
+                       if (cmd_ret != CMD_SUCCESS) {
+                               error_occurred = true;
+                               if (cmd_ret == CMD_FATAL) {
+                                       break;
+                               }
+                               goto end;
+                       }
+               }
+               if (error_occurred) {
+                       cmd_ret = CMD_ERROR;
+               }
+       }
+
+       if (writer) {
+               /* Close tracker and trackers elements */
+               const int ret = mi_lttng_close_multi_element(
+                               writer, 2);
+               if (ret) {
+                       cmd_ret = CMD_FATAL;
+                       goto end;
+               }
+       }
+end:
+       return cmd_ret;
+}
+
+/*
+ * Add/remove tracker to/from session.
+ */
+static int cmd_track_untrack(enum cmd_type cmd_type,
+               int argc,
+               const char **argv,
+               const char *help_msg)
+{
+       int opt, ret = 0;
+       bool sub_command_failed = false;
+       bool opt_all = false;
+       unsigned int selected_process_attr_tracker_count = 0;
+       const unsigned int command_count =
+                       sizeof(process_attr_commands) /
+                       sizeof(struct process_attr_command_args);
+       enum cmd_error_code command_ret = CMD_SUCCESS;
+       static poptContext pc;
+       char *session_name = NULL;
+       const char *leftover = NULL;
+       struct mi_writer *writer = NULL;
+       size_t i;
+
+       for (i = 0; i < command_count; i++) {
+               process_attr_command_init(&process_attr_commands[i], (lttng_process_attr) i);
+       }
+
+       if (argc < 1) {
+               command_ret = CMD_ERROR;
+               goto end;
+       }
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               case OPT_SESSION:
+                       break;
+               case OPT_PID:
+               case OPT_VPID:
+               case OPT_UID:
+               case OPT_VUID:
+               case OPT_GID:
+               case OPT_VGID:
+                       /* See OPT_ enum declaration comment.  */
+                       opt--;
+                       selected_process_attr_tracker_count++;
+                       process_attr_commands[opt].requested = true;
+                       if (!opt_str_arg) {
+                               continue;
+                       }
+                       ret = lttng_dynamic_pointer_array_add_pointer(
+                                       &process_attr_commands[opt].string_args,
+                                       opt_str_arg);
+                       if (ret) {
+                               ERR("Allocation failed while parsing command arguments");
+                               command_ret = CMD_ERROR;
+                               goto end;
+                       }
+                       break;
+               case OPT_ALL:
+                       opt_all = true;
+                       break;
+               default:
+                       command_ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       ret = print_missing_or_multiple_domains(
+                       opt_kernel + opt_userspace, false);
+       if (ret) {
+               command_ret = CMD_ERROR;
+               goto end;
+       }
+
+       if (selected_process_attr_tracker_count == 0) {
+               ERR("At least one process attribute must be specified");
+               command_ret = CMD_ERROR;
+               goto end;
+       }
+       if (opt_all) {
+               /*
+                * Only one process attribute tracker was specified; find it
+                * and set it in 'all' mode.
+                */
+               for (i = 0; i < command_count; i++) {
+                       if (!process_attr_commands[i].requested) {
+                               continue;
+                       }
+                       process_attr_commands[i].all = true;
+                       if (lttng_dynamic_pointer_array_get_count(
+                                           &process_attr_commands[i]
+                                                            .string_args)) {
+                               ERR("The --all option cannot be used with a list of process attribute values");
+                               command_ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+       } else {
+               for (i = 0; i < command_count; i++) {
+                       if (!process_attr_commands[i].requested) {
+                               continue;
+                       }
+                       if (lttng_dynamic_pointer_array_get_count(
+                                   &process_attr_commands[i]
+                                   .string_args) == 0) {
+                               ERR("No process attribute value specified for %s tracker",
+                                               get_capitalized_process_attr_str(
+                                                               process_attr_commands[i]
+                                                                               .process_attr));
+                               command_ret = CMD_ERROR;
+                               goto end;
+                       }
+               }
+       }
+
+       if (!opt_session_name) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               command_ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* Mi check */
+       if (lttng_opt_mi) {
+               writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+               if (!writer) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       if (writer) {
+               /* Open command element */
+               ret = mi_lttng_writer_command_open(writer,
+                               get_mi_element_command(cmd_type));
+               if (ret) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Open output element */
+               ret = mi_lttng_writer_open_element(writer,
+                               mi_lttng_element_command_output);
+               if (ret) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               ret = mi_lttng_trackers_open(writer);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       /* Execute sub-commands. */
+       for (i = 0; i < command_count; i++) {
+               if (!process_attr_commands[i].requested) {
+                       continue;
+               }
+               command_ret = run_command(cmd_type, session_name,
+                               &process_attr_commands[i], writer);
+               if (command_ret != CMD_SUCCESS) {
+                       sub_command_failed = true;
+                       if (command_ret == CMD_FATAL) {
+                               break;
+                       }
+               }
+       }
+
+       /* Mi closing */
+       if (writer) {
+               /* Close trackers and output elements */
+               ret = mi_lttng_close_multi_element(writer, 2);
+               if (ret) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Success ? */
+               ret = mi_lttng_writer_write_element_bool(writer,
+                               mi_lttng_element_command_success,
+                               !sub_command_failed);
+               if (ret) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Command element close */
+               ret = mi_lttng_writer_command_close(writer);
+               if (ret) {
+                       command_ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+end:
+       if (!opt_session_name) {
+               free(session_name);
+       }
+
+       /* Mi clean-up */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               command_ret = CMD_ERROR;
+       }
+
+       for (i = 0; i < command_count; i++) {
+               process_attr_command_fini(&process_attr_commands[i]);
+       }
+
+       poptFreeContext(pc);
+       return (int) command_ret;
+}
+
+int cmd_track(int argc, const char **argv)
+{
+       static const char *help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng-track.1.h>
+#else
+       NULL
+#endif
+       ;
+
+       return cmd_track_untrack(CMD_TRACK, argc, argv, help_msg);
+}
+
+int cmd_untrack(int argc, const char **argv)
+{
+       static const char *help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng-untrack.1.h>
+#else
+       NULL
+#endif
+       ;
+
+       return cmd_track_untrack(CMD_UNTRACK, argc, argv, help_msg);
+}
diff --git a/src/bin/lttng/commands/version.c b/src/bin/lttng/commands/version.c
deleted file mode 100644 (file)
index 9f606bf..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/mi-lttng.h>
-
-#include "../command.h"
-#include "version.h"
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-version.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static const char *lttng_license = "lttng is free software and under the GPL license and part LGPL";
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/*
- *  create_version
- */
-static void create_version(struct mi_lttng_version *version)
-{
-       strncpy(version->version, VERSION, NAME_MAX);
-       version->version_major = VERSION_MAJOR;
-       version->version_minor = VERSION_MINOR;
-       version->version_patchlevel = VERSION_PATCHLEVEL;
-       strncpy(version->version_commit, GIT_VERSION, NAME_MAX);
-       strncpy(version->version_name, VERSION_NAME, NAME_MAX);
-       strncpy(version->package_url, PACKAGE_URL, NAME_MAX);
-}
-
-/*
- * Print the machine interface output of this command.
- */
-static int print_mi(void)
-{
-       int ret = CMD_SUCCESS;
-       struct mi_writer *writer = NULL;
-       struct mi_lttng_version version;
-
-       create_version(&version);
-
-       writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
-       if (!writer) {
-               ret = -LTTNG_ERR_NOMEM;
-               goto end;
-       }
-
-       /* Open the command element */
-       ret = mi_lttng_writer_command_open(writer,
-                       mi_lttng_element_command_version);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       /* Beginning of output */
-       ret = mi_lttng_writer_open_element(writer,
-                       mi_lttng_element_command_output);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       /* Print the machine interface of version */
-       ret = mi_lttng_version(writer, &version,
-                       VERSION_DESCRIPTION, lttng_license);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       /* Close the output element */
-       ret = mi_lttng_writer_close_element(writer);
-       if (ret) {
-               ret = CMD_ERROR;
-               goto error;
-       }
-
-       /* Close the command  */
-       ret = mi_lttng_writer_command_close(writer);
-       if (ret) {
-               ret = CMD_ERROR;
-       }
-
-error:
-       /* Cleanup */
-       if (writer && mi_lttng_writer_destroy(writer)) {
-               /* Preserve original error code */
-               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
-       }
-
-end:
-       return ret;
-}
-
-/*
- *  cmd_version
- */
-int cmd_version(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS;
-       static poptContext pc;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       if (lttng_opt_mi) {
-               ret = print_mi();
-       } else {
-               MSG("lttng version " VERSION " - " VERSION_NAME "%s",
-                       GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
-               MSG("\n" VERSION_DESCRIPTION "\n");
-               MSG("Web site: https://lttng.org");
-               MSG("\n%s", lttng_license);
-               if (EXTRA_VERSION_NAME[0] != '\0') {
-                       MSG("\nExtra version name: " EXTRA_VERSION_NAME);
-               }
-               if (EXTRA_VERSION_DESCRIPTION[0] != '\0') {
-                       MSG("\nExtra version description:\n\t" EXTRA_VERSION_DESCRIPTION);
-               }
-               if (EXTRA_VERSION_PATCHES[0] != '\0') {
-                       MSG("\nExtra version patches:\n\t" EXTRA_VERSION_PATCHES);
-               }
-       }
-
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/version.cpp b/src/bin/lttng/commands/version.cpp
new file mode 100644 (file)
index 0000000..ccc7f66
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/mi-lttng.h>
+
+#include "../command.h"
+#include "version.h"
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-version.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static const char *lttng_license = "lttng is free software and under the GPL license and part LGPL";
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",      'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/*
+ *  create_version
+ */
+static void create_version(struct mi_lttng_version_data *version)
+{
+       strncpy(version->version, VERSION, NAME_MAX);
+       version->version_major = VERSION_MAJOR;
+       version->version_minor = VERSION_MINOR;
+       version->version_patchlevel = VERSION_PATCHLEVEL;
+       strncpy(version->version_commit, GIT_VERSION, NAME_MAX);
+       strncpy(version->version_name, VERSION_NAME, NAME_MAX);
+       strncpy(version->package_url, PACKAGE_URL, NAME_MAX);
+}
+
+/*
+ * Print the machine interface output of this command.
+ */
+static int print_mi(void)
+{
+       int ret = CMD_SUCCESS;
+       struct mi_writer *writer = NULL;
+       struct mi_lttng_version_data version;
+
+       create_version(&version);
+
+       writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi);
+       if (!writer) {
+               ret = -LTTNG_ERR_NOMEM;
+               goto end;
+       }
+
+       /* Open the command element */
+       ret = mi_lttng_writer_command_open(writer,
+                       mi_lttng_element_command_version);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       /* Beginning of output */
+       ret = mi_lttng_writer_open_element(writer,
+                       mi_lttng_element_command_output);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       /* Print the machine interface of version */
+       ret = mi_lttng_version(writer, &version,
+                       VERSION_DESCRIPTION, lttng_license);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       /* Close the output element */
+       ret = mi_lttng_writer_close_element(writer);
+       if (ret) {
+               ret = CMD_ERROR;
+               goto error;
+       }
+
+       /* Close the command  */
+       ret = mi_lttng_writer_command_close(writer);
+       if (ret) {
+               ret = CMD_ERROR;
+       }
+
+error:
+       /* Cleanup */
+       if (writer && mi_lttng_writer_destroy(writer)) {
+               /* Preserve original error code */
+               ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ *  cmd_version
+ */
+int cmd_version(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS;
+       static poptContext pc;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       if (lttng_opt_mi) {
+               ret = print_mi();
+       } else {
+               MSG("lttng version " VERSION " - " VERSION_NAME "%s",
+                       GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION);
+               MSG("\n" VERSION_DESCRIPTION "\n");
+               MSG("Web site: https://lttng.org");
+               MSG("\n%s", lttng_license);
+               if (EXTRA_VERSION_NAME[0] != '\0') {
+                       MSG("\nExtra version name: " EXTRA_VERSION_NAME);
+               }
+               if (EXTRA_VERSION_DESCRIPTION[0] != '\0') {
+                       MSG("\nExtra version description:\n\t" EXTRA_VERSION_DESCRIPTION);
+               }
+               if (EXTRA_VERSION_PATCHES[0] != '\0') {
+                       MSG("\nExtra version patches:\n\t" EXTRA_VERSION_PATCHES);
+               }
+       }
+
+end:
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/commands/view.c b/src/bin/lttng/commands/view.c
deleted file mode 100644 (file)
index a2623fe..0000000
+++ /dev/null
@@ -1,233 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <dgoulet@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <popt.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/spawn-viewer.h>
-#include "../command.h"
-
-static char *opt_session_name;
-static char *opt_viewer;
-static char *opt_trace_path;
-
-#ifdef LTTNG_EMBED_HELP
-static const char help_msg[] =
-#include <lttng-view.1.h>
-;
-#endif
-
-enum {
-       OPT_HELP = 1,
-       OPT_LIST_OPTIONS,
-};
-
-static struct poptOption long_options[] = {
-       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
-       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
-       {"list-options", 0,  POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
-       {"viewer",      'e', POPT_ARG_STRING, &opt_viewer, 0, 0, 0},
-       {"trace-path",  't', POPT_ARG_STRING, &opt_trace_path, 0, 0, 0},
-       {0, 0, 0, 0, 0, 0, 0}
-};
-
-/* Is the session we are trying to view is in live mode. */
-static int session_live_mode;
-
-/*
- * Build the live path we need for the lttng live view.
- */
-static char *build_live_path(char *session_name)
-{
-       int ret;
-       char *path = NULL;
-       char hostname[LTTNG_HOST_NAME_MAX];
-
-       ret = gethostname(hostname, sizeof(hostname));
-       if (ret < 0) {
-               PERROR("gethostname");
-               goto error;
-       }
-
-       ret = asprintf(&path, "net://localhost/host/%s/%s", hostname,
-                       session_name);
-       if (ret < 0) {
-               PERROR("asprintf live path");
-               goto error;
-       }
-
-error:
-       return path;
-}
-
-/*
- * Exec viewer if found and use session name path.
- */
-static int view_trace(void)
-{
-       int ret;
-       char *session_name, *trace_path = NULL;
-       struct lttng_session *sessions = NULL;
-       bool free_trace_path = false;
-
-       /*
-        * Safety net. If lttng is suid at some point for *any* useless reasons,
-        * this prevent any bad execution of binaries.
-        */
-       if (getuid() != 0) {
-               if (getuid() != geteuid()) {
-                       ERR("UID does not match effective UID.");
-                       ret = CMD_ERROR;
-                       goto error;
-               } else if (getgid() != getegid()) {
-                       ERR("GID does not match effective GID.");
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       }
-
-       /* User define trace path override the session name */
-       if (opt_trace_path) {
-               session_name = NULL;
-       } else if(opt_session_name == NULL) {
-               session_name = get_session_name();
-               if (session_name == NULL) {
-                       ret = CMD_ERROR;
-                       goto error;
-               }
-       } else {
-               session_name = opt_session_name;
-       }
-
-       DBG("Viewing trace for session %s", session_name);
-
-       if (session_name) {
-               int i, count, found = 0;
-
-               /* Getting all sessions */
-               count = lttng_list_sessions(&sessions);
-               if (count < 0) {
-                       ERR("Unable to list sessions. Session name %s not found.",
-                                       session_name);
-                       MSG("Is there a session daemon running?");
-                       ret = CMD_ERROR;
-                       goto free_error;
-               }
-
-               /* Find our session listed by the session daemon */
-               for (i = 0; i < count; i++) {
-                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
-                               found = 1;
-                               break;
-                       }
-               }
-
-               if (!found) {
-                       MSG("Session name %s not found", session_name);
-                       ret = CMD_ERROR;
-                       goto free_sessions;
-               }
-
-               session_live_mode = sessions[i].live_timer_interval;
-
-               DBG("Session live mode set to %d", session_live_mode);
-
-               if (sessions[i].enabled && !session_live_mode) {
-                       WARN("Session %s is running. Please stop it before reading it.",
-                                       session_name);
-                       ret = CMD_ERROR;
-                       goto free_sessions;
-               }
-
-               /* If the timer interval is set we are in live mode. */
-               if (session_live_mode) {
-                       trace_path = build_live_path(session_name);
-                       if (!trace_path) {
-                               ret = CMD_ERROR;
-                               goto free_sessions;
-                       }
-                       free_trace_path = true;
-               } else {
-                       /* Get file system session path. */
-                       trace_path = sessions[i].path;
-               }
-       } else {
-               trace_path = opt_trace_path;
-       }
-
-       MSG("Trace directory: %s\n", trace_path);
-
-       ret = spawn_viewer(trace_path, opt_viewer, session_live_mode);
-       if (ret < 0) {
-               /* Don't set ret so lttng can interpret the sessiond error. */
-               goto free_sessions;
-       }
-
-free_sessions:
-       if (session_live_mode && free_trace_path) {
-               free(trace_path);
-       }
-       free(sessions);
-free_error:
-       if (opt_session_name == NULL) {
-               free(session_name);
-       }
-error:
-       return ret;
-}
-
-/*
- * The 'view <options>' first level command
- */
-int cmd_view(int argc, const char **argv)
-{
-       int opt, ret = CMD_SUCCESS;
-       static poptContext pc;
-       const char *leftover = NULL;
-
-       pc = poptGetContext(NULL, argc, argv, long_options, 0);
-       poptReadDefaultConfig(pc, 0);
-
-       if (lttng_opt_mi) {
-               WARN("mi does not apply to view command");
-       }
-
-       while ((opt = poptGetNextOpt(pc)) != -1) {
-               switch (opt) {
-               case OPT_HELP:
-                       SHOW_HELP();
-                       goto end;
-               case OPT_LIST_OPTIONS:
-                       list_cmd_options(stdout, long_options);
-                       goto end;
-               default:
-                       ret = CMD_UNDEFINED;
-                       goto end;
-               }
-       }
-
-       opt_session_name = (char*) poptGetArg(pc);
-
-       leftover = poptGetArg(pc);
-       if (leftover) {
-               ERR("Unknown argument: %s", leftover);
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       ret = view_trace();
-
-end:
-       poptFreeContext(pc);
-       return ret;
-}
diff --git a/src/bin/lttng/commands/view.cpp b/src/bin/lttng/commands/view.cpp
new file mode 100644 (file)
index 0000000..a2623fe
--- /dev/null
@@ -0,0 +1,233 @@
+/*
+ * Copyright (C) 2011 David Goulet <dgoulet@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <popt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/spawn-viewer.h>
+#include "../command.h"
+
+static char *opt_session_name;
+static char *opt_viewer;
+static char *opt_trace_path;
+
+#ifdef LTTNG_EMBED_HELP
+static const char help_msg[] =
+#include <lttng-view.1.h>
+;
+#endif
+
+enum {
+       OPT_HELP = 1,
+       OPT_LIST_OPTIONS,
+};
+
+static struct poptOption long_options[] = {
+       /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */
+       {"help",        'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0},
+       {"list-options", 0,  POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL},
+       {"viewer",      'e', POPT_ARG_STRING, &opt_viewer, 0, 0, 0},
+       {"trace-path",  't', POPT_ARG_STRING, &opt_trace_path, 0, 0, 0},
+       {0, 0, 0, 0, 0, 0, 0}
+};
+
+/* Is the session we are trying to view is in live mode. */
+static int session_live_mode;
+
+/*
+ * Build the live path we need for the lttng live view.
+ */
+static char *build_live_path(char *session_name)
+{
+       int ret;
+       char *path = NULL;
+       char hostname[LTTNG_HOST_NAME_MAX];
+
+       ret = gethostname(hostname, sizeof(hostname));
+       if (ret < 0) {
+               PERROR("gethostname");
+               goto error;
+       }
+
+       ret = asprintf(&path, "net://localhost/host/%s/%s", hostname,
+                       session_name);
+       if (ret < 0) {
+               PERROR("asprintf live path");
+               goto error;
+       }
+
+error:
+       return path;
+}
+
+/*
+ * Exec viewer if found and use session name path.
+ */
+static int view_trace(void)
+{
+       int ret;
+       char *session_name, *trace_path = NULL;
+       struct lttng_session *sessions = NULL;
+       bool free_trace_path = false;
+
+       /*
+        * Safety net. If lttng is suid at some point for *any* useless reasons,
+        * this prevent any bad execution of binaries.
+        */
+       if (getuid() != 0) {
+               if (getuid() != geteuid()) {
+                       ERR("UID does not match effective UID.");
+                       ret = CMD_ERROR;
+                       goto error;
+               } else if (getgid() != getegid()) {
+                       ERR("GID does not match effective GID.");
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       }
+
+       /* User define trace path override the session name */
+       if (opt_trace_path) {
+               session_name = NULL;
+       } else if(opt_session_name == NULL) {
+               session_name = get_session_name();
+               if (session_name == NULL) {
+                       ret = CMD_ERROR;
+                       goto error;
+               }
+       } else {
+               session_name = opt_session_name;
+       }
+
+       DBG("Viewing trace for session %s", session_name);
+
+       if (session_name) {
+               int i, count, found = 0;
+
+               /* Getting all sessions */
+               count = lttng_list_sessions(&sessions);
+               if (count < 0) {
+                       ERR("Unable to list sessions. Session name %s not found.",
+                                       session_name);
+                       MSG("Is there a session daemon running?");
+                       ret = CMD_ERROR;
+                       goto free_error;
+               }
+
+               /* Find our session listed by the session daemon */
+               for (i = 0; i < count; i++) {
+                       if (strncmp(sessions[i].name, session_name, NAME_MAX) == 0) {
+                               found = 1;
+                               break;
+                       }
+               }
+
+               if (!found) {
+                       MSG("Session name %s not found", session_name);
+                       ret = CMD_ERROR;
+                       goto free_sessions;
+               }
+
+               session_live_mode = sessions[i].live_timer_interval;
+
+               DBG("Session live mode set to %d", session_live_mode);
+
+               if (sessions[i].enabled && !session_live_mode) {
+                       WARN("Session %s is running. Please stop it before reading it.",
+                                       session_name);
+                       ret = CMD_ERROR;
+                       goto free_sessions;
+               }
+
+               /* If the timer interval is set we are in live mode. */
+               if (session_live_mode) {
+                       trace_path = build_live_path(session_name);
+                       if (!trace_path) {
+                               ret = CMD_ERROR;
+                               goto free_sessions;
+                       }
+                       free_trace_path = true;
+               } else {
+                       /* Get file system session path. */
+                       trace_path = sessions[i].path;
+               }
+       } else {
+               trace_path = opt_trace_path;
+       }
+
+       MSG("Trace directory: %s\n", trace_path);
+
+       ret = spawn_viewer(trace_path, opt_viewer, session_live_mode);
+       if (ret < 0) {
+               /* Don't set ret so lttng can interpret the sessiond error. */
+               goto free_sessions;
+       }
+
+free_sessions:
+       if (session_live_mode && free_trace_path) {
+               free(trace_path);
+       }
+       free(sessions);
+free_error:
+       if (opt_session_name == NULL) {
+               free(session_name);
+       }
+error:
+       return ret;
+}
+
+/*
+ * The 'view <options>' first level command
+ */
+int cmd_view(int argc, const char **argv)
+{
+       int opt, ret = CMD_SUCCESS;
+       static poptContext pc;
+       const char *leftover = NULL;
+
+       pc = poptGetContext(NULL, argc, argv, long_options, 0);
+       poptReadDefaultConfig(pc, 0);
+
+       if (lttng_opt_mi) {
+               WARN("mi does not apply to view command");
+       }
+
+       while ((opt = poptGetNextOpt(pc)) != -1) {
+               switch (opt) {
+               case OPT_HELP:
+                       SHOW_HELP();
+                       goto end;
+               case OPT_LIST_OPTIONS:
+                       list_cmd_options(stdout, long_options);
+                       goto end;
+               default:
+                       ret = CMD_UNDEFINED;
+                       goto end;
+               }
+       }
+
+       opt_session_name = (char*) poptGetArg(pc);
+
+       leftover = poptGetArg(pc);
+       if (leftover) {
+               ERR("Unknown argument: %s", leftover);
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       ret = view_trace();
+
+end:
+       poptFreeContext(pc);
+       return ret;
+}
diff --git a/src/bin/lttng/conf.c b/src/bin/lttng/conf.c
deleted file mode 100644 (file)
index 4079d6e..0000000
+++ /dev/null
@@ -1,318 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <limits.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <unistd.h>
-
-#include <common/compat/errno.h>
-#include <common/common.h>
-#include <common/utils.h>
-
-#include "conf.h"
-
-/*
- * Returns the path with '/CONFIG_FILENAME' added to it;
- * path will be NULL if an error occurs.
- */
-char *config_get_file_path(const char *path)
-{
-       int ret;
-       char *file_path;
-
-       ret = asprintf(&file_path, "%s/%s", path, CONFIG_FILENAME);
-       if (ret < 0) {
-               ERR("Fail allocating config file path");
-               file_path = NULL;
-       }
-
-       return file_path;
-}
-
-/*
- * Returns an open FILE pointer to the config file;
- * on error, NULL is returned.
- */
-static FILE *open_config(const char *path, const char *mode)
-{
-       FILE *fp = NULL;
-       char *file_path;
-
-       file_path = config_get_file_path(path);
-       if (file_path == NULL) {
-               goto error;
-       }
-
-       fp = fopen(file_path, mode);
-       if (fp == NULL) {
-               goto error;
-       }
-
-error:
-       free(file_path);
-       return fp;
-}
-
-/*
- * Creates the empty config file at the path.
- * On success, returns 0;
- * on error, returns -1.
- */
-static int create_config_file(const char *path)
-{
-       int ret;
-       FILE *fp;
-
-       fp = open_config(path, "w+");
-       if (fp == NULL) {
-               ERR("Unable to create config file");
-               ret = -1;
-               goto error;
-       }
-
-       ret = fclose(fp);
-
-error:
-       return ret;
-}
-
-/*
- * Append data to the config file in file_path
- * On success, returns 0;
- * on error, returns -1.
- */
-static int write_config(const char *file_path, size_t size, char *data)
-{
-       FILE *fp;
-       size_t len;
-       int ret = 0;
-
-       fp = open_config(file_path, "a");
-       if (fp == NULL) {
-               ret = -1;
-               goto end;
-       }
-
-       /* Write session name into config file */
-       len = fwrite(data, size, 1, fp);
-       if (len != 1) {
-               ret = -1;
-       }
-       if (fclose(fp)) {
-               PERROR("close write_config");
-       }
-end:
-       return ret;
-}
-
-/*
- * Destroys directory config and file config.
- */
-void config_destroy(const char *path)
-{
-       int ret;
-       char *config_path;
-
-       config_path = config_get_file_path(path);
-       if (config_path == NULL) {
-               return;
-       }
-
-       if (!config_exists(config_path)) {
-               goto end;
-       }
-
-       DBG("Removing %s\n", config_path);
-       ret = remove(config_path);
-       if (ret < 0) {
-               PERROR("remove config file");
-       }
-end:
-       free(config_path);
-}
-
-/*
- * Destroys the default config
- */
-void config_destroy_default(void)
-{
-       const char *path = utils_get_home_dir();
-       if (path == NULL) {
-               return;
-       }
-       config_destroy(path);
-}
-
-/*
- * Returns 1 if config exists, 0 otherwise
- */
-int config_exists(const char *path)
-{
-       int ret;
-       struct stat info;
-
-       ret = stat(path, &info);
-       if (ret < 0) {
-               return 0;
-       }
-       return S_ISREG(info.st_mode) || S_ISDIR(info.st_mode);
-}
-
-static
-int _config_read_session_name(const char *path, char **name)
-{
-       int ret = 0;
-       FILE *fp;
-       char var[NAME_MAX], *session_name;
-
-#if (NAME_MAX == 255)
-#define NAME_MAX_SCANF_IS_A_BROKEN_API "254"
-#endif
-
-       session_name = zmalloc(NAME_MAX);
-       if (session_name == NULL) {
-               ret = -ENOMEM;
-               ERR("Out of memory");
-               goto error;
-       }
-
-       fp = open_config(path, "r");
-       if (fp == NULL) {
-               ret = -ENOENT;
-               goto error;
-       }
-
-       while (!feof(fp)) {
-               if ((ret = fscanf(fp, "%" NAME_MAX_SCANF_IS_A_BROKEN_API
-                               "[^'=']=%" NAME_MAX_SCANF_IS_A_BROKEN_API "s\n",
-                               var, session_name)) != 2) {
-                       if (ret == -1) {
-                               ERR("Missing session=NAME in config file.");
-                               goto error_close;
-                       }
-                       continue;
-               }
-
-               if (strcmp(var, "session") == 0) {
-                       goto found;
-               }
-       }
-
-error_close:
-       if (fclose(fp) < 0) {
-               PERROR("close config read session name");
-       }
-error:
-       free(session_name);
-       return ret;
-found:
-       *name = session_name;
-       if (fclose(fp) < 0) {
-               PERROR("close config read session name found");
-       }
-       return ret;
-}
-
-/*
- * Returns the session name from the config file.
- *
- * The caller is responsible for freeing the returned string.
- * On error, NULL is returned.
- */
-char *config_read_session_name(const char *path)
-{
-       int ret;
-       char *name = NULL;
-
-       ret = _config_read_session_name(path, &name);
-       if (ret == -ENOENT) {
-               const char *home_dir = utils_get_home_dir();
-
-               ERR("Can't find valid lttng config %s/.lttngrc", home_dir);
-               MSG("Did you create a session? (lttng create <my_session>)");
-       }
-
-       return name;
-}
-
-/*
- * Returns the session name from the config file. (no warnings/errors emitted)
- *
- * The caller is responsible for freeing the returned string.
- * On error, NULL is returned.
- */
-char *config_read_session_name_quiet(const char *path)
-{
-       char *name = NULL;
-
-       (void) _config_read_session_name(path, &name);
-       return name;
-}
-
-/*
- * Write session name option to the config file.
- * On success, returns 0;
- * on error, returns -1.
- */
-int config_add_session_name(const char *path, const char *name)
-{
-       int ret;
-       const char *attr = "session=";
-       /* Max name len accepted plus attribute's len and the NULL byte. */
-       char session_name[NAME_MAX + strlen(attr) + 1];
-
-       /*
-        * With GNU C <  2.1, snprintf returns -1 if the target buffer is too small;
-        * With GNU C >= 2.1, snprintf returns the required size (excluding closing null)
-        */
-       ret = snprintf(session_name, sizeof(session_name), "%s%s\n", attr, name);
-       if (ret < 0) {
-               ret = -1;
-               goto error;
-       }
-       ret = write_config(path, ret, session_name);
-error:
-       return ret;
-}
-
-/*
- * Init configuration directory and file.
- * On success, returns 0;
- * on error, returns -1.
- */
-int config_init(const char *session_name)
-{
-       int ret;
-       const char *path;
-
-       path = utils_get_home_dir();
-       if (path == NULL) {
-               ret = -1;
-               goto error;
-       }
-
-       /* Create default config file */
-       ret = create_config_file(path);
-       if (ret < 0) {
-               goto error;
-       }
-
-       ret = config_add_session_name(path, session_name);
-       if (ret < 0) {
-               goto error;
-       }
-
-       DBG("Init config session in %s", path);
-
-error:
-       return ret;
-}
diff --git a/src/bin/lttng/conf.cpp b/src/bin/lttng/conf.cpp
new file mode 100644 (file)
index 0000000..e347c4b
--- /dev/null
@@ -0,0 +1,318 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <unistd.h>
+
+#include <common/compat/errno.h>
+#include <common/common.h>
+#include <common/utils.h>
+
+#include "conf.h"
+
+/*
+ * Returns the path with '/CONFIG_FILENAME' added to it;
+ * path will be NULL if an error occurs.
+ */
+char *config_get_file_path(const char *path)
+{
+       int ret;
+       char *file_path;
+
+       ret = asprintf(&file_path, "%s/%s", path, CONFIG_FILENAME);
+       if (ret < 0) {
+               ERR("Fail allocating config file path");
+               file_path = NULL;
+       }
+
+       return file_path;
+}
+
+/*
+ * Returns an open FILE pointer to the config file;
+ * on error, NULL is returned.
+ */
+static FILE *open_config(const char *path, const char *mode)
+{
+       FILE *fp = NULL;
+       char *file_path;
+
+       file_path = config_get_file_path(path);
+       if (file_path == NULL) {
+               goto error;
+       }
+
+       fp = fopen(file_path, mode);
+       if (fp == NULL) {
+               goto error;
+       }
+
+error:
+       free(file_path);
+       return fp;
+}
+
+/*
+ * Creates the empty config file at the path.
+ * On success, returns 0;
+ * on error, returns -1.
+ */
+static int create_config_file(const char *path)
+{
+       int ret;
+       FILE *fp;
+
+       fp = open_config(path, "w+");
+       if (fp == NULL) {
+               ERR("Unable to create config file");
+               ret = -1;
+               goto error;
+       }
+
+       ret = fclose(fp);
+
+error:
+       return ret;
+}
+
+/*
+ * Append data to the config file in file_path
+ * On success, returns 0;
+ * on error, returns -1.
+ */
+static int write_config(const char *file_path, size_t size, char *data)
+{
+       FILE *fp;
+       size_t len;
+       int ret = 0;
+
+       fp = open_config(file_path, "a");
+       if (fp == NULL) {
+               ret = -1;
+               goto end;
+       }
+
+       /* Write session name into config file */
+       len = fwrite(data, size, 1, fp);
+       if (len != 1) {
+               ret = -1;
+       }
+       if (fclose(fp)) {
+               PERROR("close write_config");
+       }
+end:
+       return ret;
+}
+
+/*
+ * Destroys directory config and file config.
+ */
+void config_destroy(const char *path)
+{
+       int ret;
+       char *config_path;
+
+       config_path = config_get_file_path(path);
+       if (config_path == NULL) {
+               return;
+       }
+
+       if (!config_exists(config_path)) {
+               goto end;
+       }
+
+       DBG("Removing %s\n", config_path);
+       ret = remove(config_path);
+       if (ret < 0) {
+               PERROR("remove config file");
+       }
+end:
+       free(config_path);
+}
+
+/*
+ * Destroys the default config
+ */
+void config_destroy_default(void)
+{
+       const char *path = utils_get_home_dir();
+       if (path == NULL) {
+               return;
+       }
+       config_destroy(path);
+}
+
+/*
+ * Returns 1 if config exists, 0 otherwise
+ */
+int config_exists(const char *path)
+{
+       int ret;
+       struct stat info;
+
+       ret = stat(path, &info);
+       if (ret < 0) {
+               return 0;
+       }
+       return S_ISREG(info.st_mode) || S_ISDIR(info.st_mode);
+}
+
+static
+int _config_read_session_name(const char *path, char **name)
+{
+       int ret = 0;
+       FILE *fp;
+       char var[NAME_MAX], *session_name;
+
+#if (NAME_MAX == 255)
+#define NAME_MAX_SCANF_IS_A_BROKEN_API "254"
+#endif
+
+       session_name = (char *) zmalloc(NAME_MAX);
+       if (session_name == NULL) {
+               ret = -ENOMEM;
+               ERR("Out of memory");
+               goto error;
+       }
+
+       fp = open_config(path, "r");
+       if (fp == NULL) {
+               ret = -ENOENT;
+               goto error;
+       }
+
+       while (!feof(fp)) {
+               if ((ret = fscanf(fp, "%" NAME_MAX_SCANF_IS_A_BROKEN_API
+                               "[^'=']=%" NAME_MAX_SCANF_IS_A_BROKEN_API "s\n",
+                               var, session_name)) != 2) {
+                       if (ret == -1) {
+                               ERR("Missing session=NAME in config file.");
+                               goto error_close;
+                       }
+                       continue;
+               }
+
+               if (strcmp(var, "session") == 0) {
+                       goto found;
+               }
+       }
+
+error_close:
+       if (fclose(fp) < 0) {
+               PERROR("close config read session name");
+       }
+error:
+       free(session_name);
+       return ret;
+found:
+       *name = session_name;
+       if (fclose(fp) < 0) {
+               PERROR("close config read session name found");
+       }
+       return ret;
+}
+
+/*
+ * Returns the session name from the config file.
+ *
+ * The caller is responsible for freeing the returned string.
+ * On error, NULL is returned.
+ */
+char *config_read_session_name(const char *path)
+{
+       int ret;
+       char *name = NULL;
+
+       ret = _config_read_session_name(path, &name);
+       if (ret == -ENOENT) {
+               const char *home_dir = utils_get_home_dir();
+
+               ERR("Can't find valid lttng config %s/.lttngrc", home_dir);
+               MSG("Did you create a session? (lttng create <my_session>)");
+       }
+
+       return name;
+}
+
+/*
+ * Returns the session name from the config file. (no warnings/errors emitted)
+ *
+ * The caller is responsible for freeing the returned string.
+ * On error, NULL is returned.
+ */
+char *config_read_session_name_quiet(const char *path)
+{
+       char *name = NULL;
+
+       (void) _config_read_session_name(path, &name);
+       return name;
+}
+
+/*
+ * Write session name option to the config file.
+ * On success, returns 0;
+ * on error, returns -1.
+ */
+int config_add_session_name(const char *path, const char *name)
+{
+       int ret;
+       const char *attr = "session=";
+       /* Max name len accepted plus attribute's len and the NULL byte. */
+       char session_name[NAME_MAX + strlen(attr) + 1];
+
+       /*
+        * With GNU C <  2.1, snprintf returns -1 if the target buffer is too small;
+        * With GNU C >= 2.1, snprintf returns the required size (excluding closing null)
+        */
+       ret = snprintf(session_name, sizeof(session_name), "%s%s\n", attr, name);
+       if (ret < 0) {
+               ret = -1;
+               goto error;
+       }
+       ret = write_config(path, ret, session_name);
+error:
+       return ret;
+}
+
+/*
+ * Init configuration directory and file.
+ * On success, returns 0;
+ * on error, returns -1.
+ */
+int config_init(const char *session_name)
+{
+       int ret;
+       const char *path;
+
+       path = utils_get_home_dir();
+       if (path == NULL) {
+               ret = -1;
+               goto error;
+       }
+
+       /* Create default config file */
+       ret = create_config_file(path);
+       if (ret < 0) {
+               goto error;
+       }
+
+       ret = config_add_session_name(path, session_name);
+       if (ret < 0) {
+               goto error;
+       }
+
+       DBG("Init config session in %s", path);
+
+error:
+       return ret;
+}
diff --git a/src/bin/lttng/loglevel.c b/src/bin/lttng/loglevel.c
deleted file mode 100644 (file)
index 054510e..0000000
+++ /dev/null
@@ -1,370 +0,0 @@
-/*
- * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include "loglevel.h"
-#include <string.h>
-#include <strings.h>
-#include <ctype.h>
-
-struct loglevel_name_value {
-       const char *name;
-       int value;
-};
-
-static
-const struct loglevel_name_value loglevel_values[] = {
-       { .name = "EMERG", .value = LTTNG_LOGLEVEL_EMERG },
-       { .name = "TRACE_EMERG", .value = LTTNG_LOGLEVEL_EMERG },
-       { .name = "ALERT", .value = LTTNG_LOGLEVEL_ALERT },
-       { .name = "TRACE_ALERT", .value = LTTNG_LOGLEVEL_ALERT },
-       { .name = "CRIT", .value = LTTNG_LOGLEVEL_CRIT },
-       { .name = "TRACE_CRIT", .value = LTTNG_LOGLEVEL_CRIT },
-       { .name = "ERR", .value = LTTNG_LOGLEVEL_ERR },
-       { .name = "TRACE_ERR", .value = LTTNG_LOGLEVEL_ERR },
-       { .name = "WARNING", .value = LTTNG_LOGLEVEL_WARNING },
-       { .name = "TRACE_WARNING", .value = LTTNG_LOGLEVEL_WARNING },
-       { .name = "NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
-       { .name = "TRACE_NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
-       { .name = "INFO", .value = LTTNG_LOGLEVEL_INFO },
-       { .name = "TRACE_INFO", .value = LTTNG_LOGLEVEL_INFO },
-       { .name = "DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
-       { .name = "TRACE_DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
-       { .name = "SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
-       { .name = "DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
-       { .name = "TRACE_DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
-       { .name = "PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
-       { .name = "DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
-       { .name = "TRACE_DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
-       { .name = "PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
-       { .name = "DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
-       { .name = "TRACE_DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
-       { .name = "MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
-       { .name = "DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
-       { .name = "TRACE_DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
-       { .name = "UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
-       { .name = "DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
-       { .name = "TRACE_DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
-       { .name = "FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
-       { .name = "DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
-       { .name = "TRACE_DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
-       { .name = "LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
-       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
-       { .name = "TRACE_DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
-};
-
-static
-const struct loglevel_name_value loglevel_log4j_values[] = {
-       { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
-       { .name = "LOG4J_OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
-       { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
-       { .name = "LOG4J_FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
-       { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
-       { .name = "LOG4J_ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
-       { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
-       { .name = "LOG4J_WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
-       { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
-       { .name = "LOG4J_INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
-       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
-       { .name = "LOG4J_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
-       { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
-       { .name = "LOG4J_TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
-       { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
-       { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
-};
-
-static
-const struct loglevel_name_value loglevel_jul_values[] = {
-       { .name = "OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
-       { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
-       { .name = "SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
-       { .name = "JUL_SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
-       { .name = "WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
-       { .name = "JUL_WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
-       { .name = "INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
-       { .name = "JUL_INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
-       { .name = "CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
-       { .name = "JUL_CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
-       { .name = "FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
-       { .name = "JUL_FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
-       { .name = "FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
-       { .name = "JUL_FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
-       { .name = "FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
-       { .name = "JUL_FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
-       { .name = "ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
-       { .name = "JUL_ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
-};
-
-static
-const struct loglevel_name_value loglevel_python_values[] = {
-       { .name = "CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
-       { .name = "PYTHON_CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
-       { .name = "ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
-       { .name = "PYTHON_ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
-       { .name = "WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
-       { .name = "PYTHON_WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
-       { .name = "INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
-       { .name = "PYTHON_INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
-       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
-       { .name = "PYTNON_DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
-       { .name = "NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
-       { .name = "PYTHON_NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
-};
-
-static
-bool string_equal_insensitive(const char *a, const char *b)
-{
-       return strcasecmp(a, b) == 0;
-}
-
-static
-int lookup_value_from_name(const struct loglevel_name_value values[],
-               size_t values_count, const char *name)
-{
-       size_t i;
-       int ret = -1;
-
-       if (!name) {
-               goto end;
-       }
-
-       for (i = 0; i < values_count; i++) {
-               if (string_equal_insensitive(values[i].name, name)) {
-                       /* Match found. */
-                       ret = values[i].value;
-                       goto end;
-               }
-       }
-
-end:
-       return ret;
-}
-
-static bool loglevel_parse_range_string_common(const char *str,
-               const struct loglevel_name_value *nvs,
-               size_t nvs_count,
-               int *min,
-               int *max)
-{
-       bool ret;
-       int i;
-       const struct loglevel_name_value *nv;
-
-       for (i = 0; i < nvs_count; i++) {
-               nv = &nvs[i];
-
-               if (strncmp(str, nv->name, strlen(nv->name)) == 0) {
-                       break;
-               }
-       }
-
-       if (i == nvs_count) {
-               goto error;
-       }
-
-       *min = nv->value;
-       str += strlen(nv->name);
-
-       if (*str == '\0') {
-               *max = nv->value;
-               ret = true;
-               goto end;
-       }
-
-       if (strncmp(str, "..", strlen("..")) != 0) {
-               goto error;
-       }
-
-       str += strlen("..");
-
-       if (*str == '\0') {
-               *max = LTTNG_LOGLEVEL_EMERG;
-               ret = true;
-               goto end;
-       }
-
-       for (i = 0; i < nvs_count; i++) {
-               nv = &nvs[i];
-
-               if (strcmp(str, nv->name) == 0) {
-                       break;
-               }
-       }
-
-       if (i == nvs_count) {
-               goto error;
-       }
-
-       *max = nv->value;
-
-       ret = true;
-       goto end;
-
-error:
-       ret = false;
-
-end:
-       return ret;
-}
-
-int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel)
-{
-       int ret = lookup_value_from_name(loglevel_values,
-                       ARRAY_SIZE(loglevel_values), name);
-
-       if (ret >= 0) {
-               *loglevel = (typeof(*loglevel)) ret;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-bool loglevel_parse_range_string(const char *str,
-               enum lttng_loglevel *min,
-               enum lttng_loglevel *max)
-{
-       int min_int, max_int;
-       bool ret = loglevel_parse_range_string_common(str, loglevel_values,
-                       ARRAY_SIZE(loglevel_values), &min_int, &max_int);
-
-       *min = min_int;
-       *max = max_int;
-
-       return ret;
-}
-
-int loglevel_log4j_name_to_value(
-               const char *name, enum lttng_loglevel_log4j *loglevel)
-{
-       int ret = lookup_value_from_name(loglevel_log4j_values,
-                       ARRAY_SIZE(loglevel_log4j_values),
-                       name);
-
-       if (ret >= 0) {
-               *loglevel = (typeof(*loglevel)) ret;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-bool loglevel_log4j_parse_range_string(const char *str,
-               enum lttng_loglevel_log4j *min,
-               enum lttng_loglevel_log4j *max)
-{
-       int min_int, max_int;
-       bool ret = loglevel_parse_range_string_common(str,
-                       loglevel_log4j_values,
-                       ARRAY_SIZE(loglevel_log4j_values), &min_int, &max_int);
-
-       *min = min_int;
-       *max = max_int;
-
-       return ret;
-}
-
-int loglevel_jul_name_to_value(
-               const char *name, enum lttng_loglevel_jul *loglevel)
-{
-       int ret = lookup_value_from_name(loglevel_jul_values,
-                       ARRAY_SIZE(loglevel_jul_values),
-                       name);
-
-       if (ret >= 0) {
-               *loglevel = (typeof(*loglevel)) ret;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-bool loglevel_jul_parse_range_string(const char *str,
-               enum lttng_loglevel_jul *min,
-               enum lttng_loglevel_jul *max)
-{
-       int min_int, max_int;
-       bool ret = loglevel_parse_range_string_common(str, loglevel_jul_values,
-                       ARRAY_SIZE(loglevel_jul_values), &min_int, &max_int);
-
-       *min = min_int;
-       *max = max_int;
-
-       return ret;
-}
-
-int loglevel_python_name_to_value(
-               const char *name, enum lttng_loglevel_python *loglevel)
-{
-       int ret = lookup_value_from_name(loglevel_python_values,
-                       ARRAY_SIZE(loglevel_python_values),
-                       name);
-
-       if (ret >= 0) {
-               *loglevel = (typeof(*loglevel)) ret;
-               ret = 0;
-       }
-
-       return ret;
-}
-
-bool loglevel_python_parse_range_string(const char *str,
-               enum lttng_loglevel_python *min,
-               enum lttng_loglevel_python *max)
-{
-       int min_int, max_int;
-       bool ret = loglevel_parse_range_string_common(str,
-                       loglevel_python_values,
-                       ARRAY_SIZE(loglevel_python_values), &min_int, &max_int);
-
-       *min = min_int;
-       *max = max_int;
-
-       return ret;
-}
-
-static
-const char *lookup_name_from_value(const struct loglevel_name_value values[],
-               size_t values_count, int loglevel)
-{
-       size_t i;
-       const char *name = NULL;
-
-       for (i = 0; i < values_count; i++) {
-               if (values[i].value == loglevel) {
-                       /* Match found. */
-                       name = values[i].name;
-                       goto end;
-               }
-       }
-
-end:
-       return name;
-}
-
-const char *loglevel_value_to_name(int loglevel)
-{
-       return lookup_name_from_value(
-                       loglevel_values, ARRAY_SIZE(loglevel_values), loglevel);
-}
-
-const char *loglevel_log4j_value_to_name(int loglevel)
-{
-       return lookup_name_from_value(loglevel_log4j_values,
-                       ARRAY_SIZE(loglevel_log4j_values), loglevel);
-}
-
-const char *loglevel_jul_value_to_name(int loglevel)
-{
-       return lookup_name_from_value(loglevel_jul_values,
-                       ARRAY_SIZE(loglevel_jul_values), loglevel);
-}
-
-const char *loglevel_python_value_to_name(int loglevel)
-{
-       return lookup_name_from_value(loglevel_python_values,
-                       ARRAY_SIZE(loglevel_python_values), loglevel);
-}
diff --git a/src/bin/lttng/loglevel.cpp b/src/bin/lttng/loglevel.cpp
new file mode 100644 (file)
index 0000000..83c7b30
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "loglevel.h"
+#include <string.h>
+#include <strings.h>
+#include <ctype.h>
+
+struct loglevel_name_value {
+       const char *name;
+       int value;
+};
+
+static
+const struct loglevel_name_value loglevel_values[] = {
+       { .name = "EMERG", .value = LTTNG_LOGLEVEL_EMERG },
+       { .name = "TRACE_EMERG", .value = LTTNG_LOGLEVEL_EMERG },
+       { .name = "ALERT", .value = LTTNG_LOGLEVEL_ALERT },
+       { .name = "TRACE_ALERT", .value = LTTNG_LOGLEVEL_ALERT },
+       { .name = "CRIT", .value = LTTNG_LOGLEVEL_CRIT },
+       { .name = "TRACE_CRIT", .value = LTTNG_LOGLEVEL_CRIT },
+       { .name = "ERR", .value = LTTNG_LOGLEVEL_ERR },
+       { .name = "TRACE_ERR", .value = LTTNG_LOGLEVEL_ERR },
+       { .name = "WARNING", .value = LTTNG_LOGLEVEL_WARNING },
+       { .name = "TRACE_WARNING", .value = LTTNG_LOGLEVEL_WARNING },
+       { .name = "NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
+       { .name = "TRACE_NOTICE", .value = LTTNG_LOGLEVEL_NOTICE },
+       { .name = "INFO", .value = LTTNG_LOGLEVEL_INFO },
+       { .name = "TRACE_INFO", .value = LTTNG_LOGLEVEL_INFO },
+       { .name = "DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
+       { .name = "TRACE_DEBUG_SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
+       { .name = "SYSTEM", .value = LTTNG_LOGLEVEL_DEBUG_SYSTEM },
+       { .name = "DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
+       { .name = "TRACE_DEBUG_PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
+       { .name = "PROGRAM", .value = LTTNG_LOGLEVEL_DEBUG_PROGRAM },
+       { .name = "DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
+       { .name = "TRACE_DEBUG_PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
+       { .name = "PROCESS", .value = LTTNG_LOGLEVEL_DEBUG_PROCESS },
+       { .name = "DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
+       { .name = "TRACE_DEBUG_MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
+       { .name = "MODULE", .value = LTTNG_LOGLEVEL_DEBUG_MODULE },
+       { .name = "DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
+       { .name = "TRACE_DEBUG_UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
+       { .name = "UNIT", .value = LTTNG_LOGLEVEL_DEBUG_UNIT },
+       { .name = "DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
+       { .name = "TRACE_DEBUG_FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
+       { .name = "FUNCTION", .value = LTTNG_LOGLEVEL_DEBUG_FUNCTION },
+       { .name = "DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
+       { .name = "TRACE_DEBUG_LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
+       { .name = "LINE", .value = LTTNG_LOGLEVEL_DEBUG_LINE },
+       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
+       { .name = "TRACE_DEBUG", .value = LTTNG_LOGLEVEL_DEBUG },
+};
+
+static
+const struct loglevel_name_value loglevel_log4j_values[] = {
+       { .name = "OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
+       { .name = "LOG4J_OFF", .value = LTTNG_LOGLEVEL_LOG4J_OFF },
+       { .name = "FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
+       { .name = "LOG4J_FATAL", .value = LTTNG_LOGLEVEL_LOG4J_FATAL },
+       { .name = "ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
+       { .name = "LOG4J_ERROR", .value = LTTNG_LOGLEVEL_LOG4J_ERROR },
+       { .name = "WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
+       { .name = "LOG4J_WARN", .value = LTTNG_LOGLEVEL_LOG4J_WARN },
+       { .name = "INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
+       { .name = "LOG4J_INFO", .value = LTTNG_LOGLEVEL_LOG4J_INFO },
+       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
+       { .name = "LOG4J_DEBUG", .value = LTTNG_LOGLEVEL_LOG4J_DEBUG },
+       { .name = "TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
+       { .name = "LOG4J_TRACE", .value = LTTNG_LOGLEVEL_LOG4J_TRACE },
+       { .name = "ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
+       { .name = "LOG4J_ALL", .value = LTTNG_LOGLEVEL_LOG4J_ALL },
+};
+
+static
+const struct loglevel_name_value loglevel_jul_values[] = {
+       { .name = "OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
+       { .name = "JUL_OFF", .value = LTTNG_LOGLEVEL_JUL_OFF },
+       { .name = "SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
+       { .name = "JUL_SEVERE", .value = LTTNG_LOGLEVEL_JUL_SEVERE },
+       { .name = "WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
+       { .name = "JUL_WARNING", .value = LTTNG_LOGLEVEL_JUL_WARNING },
+       { .name = "INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
+       { .name = "JUL_INFO", .value = LTTNG_LOGLEVEL_JUL_INFO },
+       { .name = "CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
+       { .name = "JUL_CONFIG", .value = LTTNG_LOGLEVEL_JUL_CONFIG },
+       { .name = "FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
+       { .name = "JUL_FINE", .value = LTTNG_LOGLEVEL_JUL_FINE },
+       { .name = "FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
+       { .name = "JUL_FINER", .value = LTTNG_LOGLEVEL_JUL_FINER },
+       { .name = "FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
+       { .name = "JUL_FINEST", .value = LTTNG_LOGLEVEL_JUL_FINEST },
+       { .name = "ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
+       { .name = "JUL_ALL", .value = LTTNG_LOGLEVEL_JUL_ALL },
+};
+
+static
+const struct loglevel_name_value loglevel_python_values[] = {
+       { .name = "CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
+       { .name = "PYTHON_CRITICAL", .value = LTTNG_LOGLEVEL_PYTHON_CRITICAL },
+       { .name = "ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
+       { .name = "PYTHON_ERROR", .value = LTTNG_LOGLEVEL_PYTHON_ERROR },
+       { .name = "WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
+       { .name = "PYTHON_WARNING", .value = LTTNG_LOGLEVEL_PYTHON_WARNING },
+       { .name = "INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
+       { .name = "PYTHON_INFO", .value = LTTNG_LOGLEVEL_PYTHON_INFO },
+       { .name = "DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
+       { .name = "PYTNON_DEBUG", .value = LTTNG_LOGLEVEL_PYTHON_DEBUG },
+       { .name = "NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
+       { .name = "PYTHON_NOTSET", .value = LTTNG_LOGLEVEL_PYTHON_NOTSET },
+};
+
+static
+bool string_equal_insensitive(const char *a, const char *b)
+{
+       return strcasecmp(a, b) == 0;
+}
+
+static
+int lookup_value_from_name(const struct loglevel_name_value values[],
+               size_t values_count, const char *name)
+{
+       size_t i;
+       int ret = -1;
+
+       if (!name) {
+               goto end;
+       }
+
+       for (i = 0; i < values_count; i++) {
+               if (string_equal_insensitive(values[i].name, name)) {
+                       /* Match found. */
+                       ret = values[i].value;
+                       goto end;
+               }
+       }
+
+end:
+       return ret;
+}
+
+static bool loglevel_parse_range_string_common(const char *str,
+               const struct loglevel_name_value *nvs,
+               size_t nvs_count,
+               int *min,
+               int *max)
+{
+       bool ret;
+       int i;
+       const struct loglevel_name_value *nv;
+
+       for (i = 0; i < nvs_count; i++) {
+               nv = &nvs[i];
+
+               if (strncmp(str, nv->name, strlen(nv->name)) == 0) {
+                       break;
+               }
+       }
+
+       if (i == nvs_count) {
+               goto error;
+       }
+
+       *min = nv->value;
+       str += strlen(nv->name);
+
+       if (*str == '\0') {
+               *max = nv->value;
+               ret = true;
+               goto end;
+       }
+
+       if (strncmp(str, "..", strlen("..")) != 0) {
+               goto error;
+       }
+
+       str += strlen("..");
+
+       if (*str == '\0') {
+               *max = LTTNG_LOGLEVEL_EMERG;
+               ret = true;
+               goto end;
+       }
+
+       for (i = 0; i < nvs_count; i++) {
+               nv = &nvs[i];
+
+               if (strcmp(str, nv->name) == 0) {
+                       break;
+               }
+       }
+
+       if (i == nvs_count) {
+               goto error;
+       }
+
+       *max = nv->value;
+
+       ret = true;
+       goto end;
+
+error:
+       ret = false;
+
+end:
+       return ret;
+}
+
+int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel)
+{
+       int ret = lookup_value_from_name(loglevel_values,
+                       ARRAY_SIZE(loglevel_values), name);
+
+       if (ret >= 0) {
+               *loglevel = (typeof(*loglevel)) ret;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+bool loglevel_parse_range_string(const char *str,
+               enum lttng_loglevel *min,
+               enum lttng_loglevel *max)
+{
+       int min_int, max_int;
+       bool ret = loglevel_parse_range_string_common(str, loglevel_values,
+                       ARRAY_SIZE(loglevel_values), &min_int, &max_int);
+
+       *min = (lttng_loglevel) min_int;
+       *max = (lttng_loglevel) max_int;
+
+       return ret;
+}
+
+int loglevel_log4j_name_to_value(
+               const char *name, enum lttng_loglevel_log4j *loglevel)
+{
+       int ret = lookup_value_from_name(loglevel_log4j_values,
+                       ARRAY_SIZE(loglevel_log4j_values),
+                       name);
+
+       if (ret >= 0) {
+               *loglevel = (typeof(*loglevel)) ret;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+bool loglevel_log4j_parse_range_string(const char *str,
+               enum lttng_loglevel_log4j *min,
+               enum lttng_loglevel_log4j *max)
+{
+       int min_int, max_int;
+       bool ret = loglevel_parse_range_string_common(str,
+                       loglevel_log4j_values,
+                       ARRAY_SIZE(loglevel_log4j_values), &min_int, &max_int);
+
+       *min = (lttng_loglevel_log4j) min_int;
+       *max = (lttng_loglevel_log4j) max_int;
+
+       return ret;
+}
+
+int loglevel_jul_name_to_value(
+               const char *name, enum lttng_loglevel_jul *loglevel)
+{
+       int ret = lookup_value_from_name(loglevel_jul_values,
+                       ARRAY_SIZE(loglevel_jul_values),
+                       name);
+
+       if (ret >= 0) {
+               *loglevel = (typeof(*loglevel)) ret;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+bool loglevel_jul_parse_range_string(const char *str,
+               enum lttng_loglevel_jul *min,
+               enum lttng_loglevel_jul *max)
+{
+       int min_int, max_int;
+       bool ret = loglevel_parse_range_string_common(str, loglevel_jul_values,
+                       ARRAY_SIZE(loglevel_jul_values), &min_int, &max_int);
+
+       *min = (lttng_loglevel_jul) min_int;
+       *max = (lttng_loglevel_jul) max_int;
+
+       return ret;
+}
+
+int loglevel_python_name_to_value(
+               const char *name, enum lttng_loglevel_python *loglevel)
+{
+       int ret = lookup_value_from_name(loglevel_python_values,
+                       ARRAY_SIZE(loglevel_python_values),
+                       name);
+
+       if (ret >= 0) {
+               *loglevel = (typeof(*loglevel)) ret;
+               ret = 0;
+       }
+
+       return ret;
+}
+
+bool loglevel_python_parse_range_string(const char *str,
+               enum lttng_loglevel_python *min,
+               enum lttng_loglevel_python *max)
+{
+       int min_int, max_int;
+       bool ret = loglevel_parse_range_string_common(str,
+                       loglevel_python_values,
+                       ARRAY_SIZE(loglevel_python_values), &min_int, &max_int);
+
+       *min = (lttng_loglevel_python) min_int;
+       *max = (lttng_loglevel_python) max_int;
+
+       return ret;
+}
+
+static
+const char *lookup_name_from_value(const struct loglevel_name_value values[],
+               size_t values_count, int loglevel)
+{
+       size_t i;
+       const char *name = NULL;
+
+       for (i = 0; i < values_count; i++) {
+               if (values[i].value == loglevel) {
+                       /* Match found. */
+                       name = values[i].name;
+                       goto end;
+               }
+       }
+
+end:
+       return name;
+}
+
+const char *loglevel_value_to_name(int loglevel)
+{
+       return lookup_name_from_value(
+                       loglevel_values, ARRAY_SIZE(loglevel_values), loglevel);
+}
+
+const char *loglevel_log4j_value_to_name(int loglevel)
+{
+       return lookup_name_from_value(loglevel_log4j_values,
+                       ARRAY_SIZE(loglevel_log4j_values), loglevel);
+}
+
+const char *loglevel_jul_value_to_name(int loglevel)
+{
+       return lookup_name_from_value(loglevel_jul_values,
+                       ARRAY_SIZE(loglevel_jul_values), loglevel);
+}
+
+const char *loglevel_python_value_to_name(int loglevel)
+{
+       return lookup_name_from_value(loglevel_python_values,
+                       ARRAY_SIZE(loglevel_python_values), loglevel);
+}
index 43ae8e44858cdadd13308a630d7fe2846b5b928b..06dcbaa8647e03de2d46deda97c34e57ebbcdf87 100644 (file)
 #include <lttng/lttng.h>
 #include <common/macros.h>
 
+#ifdef __cplusplus
+extern "C" {
+#endif
+
 int loglevel_name_to_value(const char *name, enum lttng_loglevel *loglevel);
 
 bool loglevel_parse_range_string(const char *str,
@@ -46,4 +50,8 @@ const char *loglevel_jul_value_to_name(int loglevel);
 
 const char *loglevel_python_value_to_name(int loglevel);
 
+#ifdef __cplusplus
+}
+#endif
+
 #endif /* _LTTNG_LOGLEVEL_UTILS_H */
diff --git a/src/bin/lttng/lttng.c b/src/bin/lttng/lttng.c
deleted file mode 100644 (file)
index af1d3f4..0000000
+++ /dev/null
@@ -1,481 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <getopt.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/types.h>
-#include <sys/wait.h>
-#include <unistd.h>
-#include <ctype.h>
-
-#include <lttng/lttng.h>
-#include <common/error.h>
-#include <common/compat/getenv.h>
-#include <common/utils.h>
-
-#include "command.h"
-#include "version.h"
-
-static const char *help_msg =
-#ifdef LTTNG_EMBED_HELP
-#include <lttng.1.h>
-#else
-NULL
-#endif
-;
-
-/* Variables */
-static const char *progname;
-int opt_no_sessiond;
-char *opt_sessiond_path;
-
-char *opt_relayd_path;
-
-enum {
-       OPT_RELAYD_PATH,
-       OPT_SESSION_PATH,
-       OPT_DUMP_OPTIONS,
-       OPT_DUMP_COMMANDS,
-};
-
-/* Getopt options. No first level command. */
-static struct option long_options[] = {
-       {"version",          0, NULL, 'V'},
-       {"help",             0, NULL, 'h'},
-       {"group",            1, NULL, 'g'},
-       {"verbose",          0, NULL, 'v'},
-       {"quiet",            0, NULL, 'q'},
-       {"mi",               1, NULL, 'm'},
-       {"no-sessiond",      0, NULL, 'n'},
-       {"sessiond-path",    1, NULL, OPT_SESSION_PATH},
-       {"relayd-path",      1, NULL, OPT_RELAYD_PATH},
-       {"list-options",     0, NULL, OPT_DUMP_OPTIONS},
-       {"list-commands",    0, NULL, OPT_DUMP_COMMANDS},
-       {NULL, 0, NULL, 0}
-};
-
-/* First level command */
-static struct cmd_struct commands[] =  {
-       { "add-context", cmd_add_context},
-       { "add-trigger", cmd_add_trigger},
-       { "create", cmd_create},
-       { "clear", cmd_clear},
-       { "destroy", cmd_destroy},
-       { "disable-channel", cmd_disable_channels},
-       { "disable-event", cmd_disable_events},
-       { "enable-channel", cmd_enable_channels},
-       { "enable-event", cmd_enable_events},
-       { "help", NULL},
-       { "list", cmd_list},
-       { "list-triggers", cmd_list_triggers},
-       { "load", cmd_load},
-       { "metadata", cmd_metadata},
-       { "regenerate", cmd_regenerate},
-       { "remove-trigger", cmd_remove_trigger},
-       { "rotate", cmd_rotate},
-       { "enable-rotation", cmd_enable_rotation},
-       { "disable-rotation", cmd_disable_rotation},
-       { "save", cmd_save},
-       { "set-session", cmd_set_session},
-       { "snapshot", cmd_snapshot},
-       { "start", cmd_start},
-       { "status", cmd_status},
-       { "stop", cmd_stop},
-       { "track", cmd_track},
-       { "untrack", cmd_untrack},
-       { "version", cmd_version},
-       { "view", cmd_view},
-       { NULL, NULL}   /* Array closure */
-};
-
-static void version(FILE *ofp)
-{
-       fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME "%s%s\n",
-                       progname,
-                       GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION,
-                       EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME);
-}
-
-/*
- * Find the MI output type enum from a string. This function is for the support
- * of machine interface output.
- */
-static int mi_output_type(const char *output_type)
-{
-       int ret = 0;
-
-       if (!strncasecmp("xml", output_type, 3)) {
-               ret = LTTNG_MI_XML;
-       } else {
-               /* Invalid output format */
-               ERR("MI output format not supported");
-               ret = -LTTNG_ERR_MI_OUTPUT_TYPE;
-       }
-
-       return ret;
-}
-
-/*
- *  list_options
- *
- *  List options line by line. This is mostly for bash auto completion and to
- *  avoid difficult parsing.
- */
-static void list_options(FILE *ofp)
-{
-       int i = 0;
-       struct option *option = NULL;
-
-       option = &long_options[i];
-       while (option->name != NULL) {
-               fprintf(ofp, "--%s\n", option->name);
-
-               if (isprint(option->val)) {
-                       fprintf(ofp, "-%c\n", option->val);
-               }
-
-               i++;
-               option = &long_options[i];
-       }
-}
-
-/*
- * clean_exit
- */
-static void clean_exit(int code)
-{
-       DBG("Clean exit");
-       exit(code);
-}
-
-/*
- *  sighandler
- *
- *  Signal handler for the daemon
- */
-static void sighandler(int sig)
-{
-       switch (sig) {
-               case SIGTERM:
-                       DBG("SIGTERM caught");
-                       clean_exit(EXIT_FAILURE);
-                       break;
-               default:
-                       DBG("Unknown signal %d caught", sig);
-                       break;
-       }
-
-       return;
-}
-
-/*
- *  set_signal_handler
- *
- *  Setup signal handler for SIGCHLD and SIGTERM.
- */
-static int set_signal_handler(void)
-{
-       int ret = 0;
-       struct sigaction sa;
-       sigset_t sigset;
-
-       if ((ret = sigemptyset(&sigset)) < 0) {
-               PERROR("sigemptyset");
-               goto end;
-       }
-
-       sa.sa_handler = sighandler;
-       sa.sa_mask = sigset;
-       sa.sa_flags = 0;
-
-       if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
-               PERROR("sigaction");
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- *  handle_command
- *
- *  Handle the full argv list of a first level command. Will find the command
- *  in the global commands array and call the function callback associated.
- *
- *  If command not found, return -1
- *  else, return function command error code.
- */
-static int handle_command(int argc, char **argv)
-{
-       int i = 0, ret;
-       struct cmd_struct *cmd;
-
-       if (*argv == NULL) {
-               ret = CMD_SUCCESS;
-               goto end;
-       }
-
-       /* Special case for help command which needs the commands array */
-       if (strcmp(argv[0], "help") == 0) {
-               ret = cmd_help(argc, (const char**) argv, commands);
-               goto end;
-       }
-
-       cmd = &commands[i];
-       while (cmd->name != NULL) {
-               /* Find command */
-               if (strcmp(argv[0], cmd->name) == 0) {
-                       ret = cmd->func(argc, (const char**) argv);
-                       goto end;
-               }
-               i++;
-               cmd = &commands[i];
-       }
-
-       /* Command not found */
-       ret = CMD_UNDEFINED;
-
-end:
-       return ret;
-}
-
-static bool command_exists(const char *command)
-{
-       const struct cmd_struct *cmd = commands;
-       bool exists = false;
-
-       while (cmd->name != NULL) {
-               if (!strcmp(command, cmd->name)) {
-                       exists = true;
-                       goto end;
-               }
-               cmd++;
-       }
-
-end:
-       return exists;
-}
-
-static void show_basic_help(void)
-{
-       puts("Usage: lttng [--group=GROUP] [--mi=TYPE] [--no-sessiond | --sessiond-path=PATH]");
-       puts("             [--quiet | -v | -vv | -vvv] COMMAND [COMMAND OPTIONS]");
-       puts("");
-       puts("Available commands:");
-       puts("");
-       puts("Recording sessions:");
-       puts("  create            " CONFIG_CMD_DESCR_CREATE);
-       puts("  clear             " CONFIG_CMD_DESCR_CLEAR);
-       puts("  destroy           " CONFIG_CMD_DESCR_DESTROY);
-       puts("  load              " CONFIG_CMD_DESCR_LOAD);
-       puts("  regenerate        " CONFIG_CMD_DESCR_REGENERATE);
-       puts("  save              " CONFIG_CMD_DESCR_SAVE);
-       puts("  set-session       " CONFIG_CMD_DESCR_SET_SESSION);
-       puts("");
-       puts("Channels:");
-       puts("  add-context       " CONFIG_CMD_DESCR_ADD_CONTEXT);
-       puts("  disable-channel   " CONFIG_CMD_DESCR_DISABLE_CHANNEL);
-       puts("  enable-channel    " CONFIG_CMD_DESCR_ENABLE_CHANNEL);
-       puts("");
-       puts("Recording event rules:");
-       puts("  disable-event     " CONFIG_CMD_DESCR_DISABLE_EVENT);
-       puts("  enable-event      " CONFIG_CMD_DESCR_ENABLE_EVENT);
-       puts("");
-       puts("Status:");
-       puts("  list              " CONFIG_CMD_DESCR_LIST);
-       puts("  status            " CONFIG_CMD_DESCR_STATUS);
-       puts("");
-       puts("Control:");
-       puts("  snapshot          " CONFIG_CMD_DESCR_SNAPSHOT);
-       puts("  start             " CONFIG_CMD_DESCR_START);
-       puts("  stop              " CONFIG_CMD_DESCR_STOP);
-       puts("");
-       puts("Recording session rotation:");
-       puts("  disable-rotation  " CONFIG_CMD_DESCR_DISABLE_ROTATION);
-       puts("  enable-rotation   " CONFIG_CMD_DESCR_ENABLE_ROTATION);
-       puts("  rotate            " CONFIG_CMD_DESCR_ROTATE);
-       puts("");
-       puts("Resource tracking:");
-       puts("  track             " CONFIG_CMD_DESCR_TRACK);
-       puts("  untrack           " CONFIG_CMD_DESCR_UNTRACK);
-       puts("");
-       puts("Triggers:");
-       puts("  add-trigger       " CONFIG_CMD_DESCR_ADD_TRIGGER);
-       puts("  remove-trigger    " CONFIG_CMD_DESCR_REMOVE_TRIGGER);
-       puts("  list-triggers     " CONFIG_CMD_DESCR_LIST_TRIGGERS);
-       puts("");
-       puts("Miscellaneous:");
-       puts("  help              " CONFIG_CMD_DESCR_HELP);
-       puts("  version           " CONFIG_CMD_DESCR_VERSION);
-       puts("  view              " CONFIG_CMD_DESCR_VIEW);
-       puts("");
-       puts("Run `lttng help COMMAND` or `lttng COMMAND --help` to get help with");
-       puts("command COMMAND.");
-       puts("");
-       puts("See `man lttng` for more help with the lttng command.");
-}
-
-/*
- * Parse command line arguments.
- *
- * Return 0 if OK, else -1
- */
-static int parse_args(int argc, char **argv)
-{
-       int opt, ret;
-
-       if (lttng_is_setuid_setgid()) {
-               ERR("'%s' is not allowed to be executed as a setuid/setgid binary for security reasons. Aborting.", argv[0]);
-               clean_exit(EXIT_FAILURE);
-       }
-
-       if (argc < 2) {
-               show_basic_help();
-               clean_exit(EXIT_FAILURE);
-       }
-
-       while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) {
-               switch (opt) {
-               case 'V':
-                       version(stdout);
-                       ret = 0;
-                       goto end;
-               case 'h':
-                       ret = utils_show_help(1, "lttng", help_msg);
-                       if (ret) {
-                               ERR("Cannot show --help for `lttng`");
-                               perror("exec");
-                       }
-                       goto end;
-               case 'v':
-                       /* There is only 3 possible level of verbosity. (-vvv) */
-                       if (lttng_opt_verbose < 3) {
-                               lttng_opt_verbose += 1;
-                       }
-                       break;
-               case 'q':
-                       lttng_opt_quiet = 1;
-                       break;
-               case 'm':
-                       lttng_opt_mi = mi_output_type(optarg);
-                       if (lttng_opt_mi < 0) {
-                               ret = lttng_opt_mi;
-                               goto error;
-                       }
-                       break;
-               case 'g':
-                       lttng_set_tracing_group(optarg);
-                       break;
-               case 'n':
-                       opt_no_sessiond = 1;
-                       break;
-               case OPT_SESSION_PATH:
-                       free(opt_sessiond_path);
-                       opt_sessiond_path = strdup(optarg);
-                       if (!opt_sessiond_path) {
-                               ret = -1;
-                               goto error;
-                       }
-                       break;
-               case OPT_RELAYD_PATH:
-                       free(opt_relayd_path);
-                       opt_relayd_path = strdup(optarg);
-                       if (!opt_relayd_path) {
-                               ret = -1;
-                               goto error;
-                       }
-                       break;
-               case OPT_DUMP_OPTIONS:
-                       list_options(stdout);
-                       ret = 0;
-                       goto end;
-               case OPT_DUMP_COMMANDS:
-                       list_commands(commands, stdout);
-                       ret = 0;
-                       goto end;
-               default:
-                       ret = 1;
-                       goto error;
-               }
-       }
-
-       /* If both options are specified, quiet wins */
-       if (lttng_opt_verbose && lttng_opt_quiet) {
-               lttng_opt_verbose = 0;
-       }
-
-       /* No leftovers, quit */
-       if ((argc - optind) == 0) {
-               ret = 1;
-               goto error;
-       }
-
-       /*
-        * Handle leftovers which is a first level command with the trailing
-        * options.
-        */
-       ret = handle_command(argc - optind, argv + optind);
-       switch (ret) {
-       case CMD_WARNING:
-       case CMD_ERROR:
-               break;
-       case CMD_UNDEFINED:
-               if (!command_exists(*(argv + optind))) {
-                       MSG("lttng: %s is not an lttng command. See 'lttng --help'.",
-                                       *(argv + optind));
-               } else {
-                       ERR("Unrecognized argument used with \'%s\' command",
-                                       *(argv + optind));
-               }
-               break;
-       case CMD_FATAL:
-       case CMD_UNSUPPORTED:
-               break;
-       case -1:
-               ret = 1;
-               break;
-       case 0:
-               break;
-       default:
-               if (ret < 0) {
-                       ret = -ret;
-               }
-               break;
-       }
-
-end:
-error:
-       return ret;
-}
-
-
-/*
- *  main
- */
-int main(int argc, char *argv[])
-{
-       int ret;
-
-       progname = argv[0] ? argv[0] : "lttng";
-
-       ret = set_signal_handler();
-       if (ret < 0) {
-               clean_exit(ret);
-       }
-
-       ret = parse_args(argc, argv);
-       if (ret != 0) {
-               clean_exit(ret);
-       }
-
-       return 0;
-}
diff --git a/src/bin/lttng/lttng.cpp b/src/bin/lttng/lttng.cpp
new file mode 100644 (file)
index 0000000..af1d3f4
--- /dev/null
@@ -0,0 +1,481 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <getopt.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <ctype.h>
+
+#include <lttng/lttng.h>
+#include <common/error.h>
+#include <common/compat/getenv.h>
+#include <common/utils.h>
+
+#include "command.h"
+#include "version.h"
+
+static const char *help_msg =
+#ifdef LTTNG_EMBED_HELP
+#include <lttng.1.h>
+#else
+NULL
+#endif
+;
+
+/* Variables */
+static const char *progname;
+int opt_no_sessiond;
+char *opt_sessiond_path;
+
+char *opt_relayd_path;
+
+enum {
+       OPT_RELAYD_PATH,
+       OPT_SESSION_PATH,
+       OPT_DUMP_OPTIONS,
+       OPT_DUMP_COMMANDS,
+};
+
+/* Getopt options. No first level command. */
+static struct option long_options[] = {
+       {"version",          0, NULL, 'V'},
+       {"help",             0, NULL, 'h'},
+       {"group",            1, NULL, 'g'},
+       {"verbose",          0, NULL, 'v'},
+       {"quiet",            0, NULL, 'q'},
+       {"mi",               1, NULL, 'm'},
+       {"no-sessiond",      0, NULL, 'n'},
+       {"sessiond-path",    1, NULL, OPT_SESSION_PATH},
+       {"relayd-path",      1, NULL, OPT_RELAYD_PATH},
+       {"list-options",     0, NULL, OPT_DUMP_OPTIONS},
+       {"list-commands",    0, NULL, OPT_DUMP_COMMANDS},
+       {NULL, 0, NULL, 0}
+};
+
+/* First level command */
+static struct cmd_struct commands[] =  {
+       { "add-context", cmd_add_context},
+       { "add-trigger", cmd_add_trigger},
+       { "create", cmd_create},
+       { "clear", cmd_clear},
+       { "destroy", cmd_destroy},
+       { "disable-channel", cmd_disable_channels},
+       { "disable-event", cmd_disable_events},
+       { "enable-channel", cmd_enable_channels},
+       { "enable-event", cmd_enable_events},
+       { "help", NULL},
+       { "list", cmd_list},
+       { "list-triggers", cmd_list_triggers},
+       { "load", cmd_load},
+       { "metadata", cmd_metadata},
+       { "regenerate", cmd_regenerate},
+       { "remove-trigger", cmd_remove_trigger},
+       { "rotate", cmd_rotate},
+       { "enable-rotation", cmd_enable_rotation},
+       { "disable-rotation", cmd_disable_rotation},
+       { "save", cmd_save},
+       { "set-session", cmd_set_session},
+       { "snapshot", cmd_snapshot},
+       { "start", cmd_start},
+       { "status", cmd_status},
+       { "stop", cmd_stop},
+       { "track", cmd_track},
+       { "untrack", cmd_untrack},
+       { "version", cmd_version},
+       { "view", cmd_view},
+       { NULL, NULL}   /* Array closure */
+};
+
+static void version(FILE *ofp)
+{
+       fprintf(ofp, "%s (LTTng Trace Control) " VERSION" - " VERSION_NAME "%s%s\n",
+                       progname,
+                       GIT_VERSION[0] == '\0' ? "" : " - " GIT_VERSION,
+                       EXTRA_VERSION_NAME[0] == '\0' ? "" : " - " EXTRA_VERSION_NAME);
+}
+
+/*
+ * Find the MI output type enum from a string. This function is for the support
+ * of machine interface output.
+ */
+static int mi_output_type(const char *output_type)
+{
+       int ret = 0;
+
+       if (!strncasecmp("xml", output_type, 3)) {
+               ret = LTTNG_MI_XML;
+       } else {
+               /* Invalid output format */
+               ERR("MI output format not supported");
+               ret = -LTTNG_ERR_MI_OUTPUT_TYPE;
+       }
+
+       return ret;
+}
+
+/*
+ *  list_options
+ *
+ *  List options line by line. This is mostly for bash auto completion and to
+ *  avoid difficult parsing.
+ */
+static void list_options(FILE *ofp)
+{
+       int i = 0;
+       struct option *option = NULL;
+
+       option = &long_options[i];
+       while (option->name != NULL) {
+               fprintf(ofp, "--%s\n", option->name);
+
+               if (isprint(option->val)) {
+                       fprintf(ofp, "-%c\n", option->val);
+               }
+
+               i++;
+               option = &long_options[i];
+       }
+}
+
+/*
+ * clean_exit
+ */
+static void clean_exit(int code)
+{
+       DBG("Clean exit");
+       exit(code);
+}
+
+/*
+ *  sighandler
+ *
+ *  Signal handler for the daemon
+ */
+static void sighandler(int sig)
+{
+       switch (sig) {
+               case SIGTERM:
+                       DBG("SIGTERM caught");
+                       clean_exit(EXIT_FAILURE);
+                       break;
+               default:
+                       DBG("Unknown signal %d caught", sig);
+                       break;
+       }
+
+       return;
+}
+
+/*
+ *  set_signal_handler
+ *
+ *  Setup signal handler for SIGCHLD and SIGTERM.
+ */
+static int set_signal_handler(void)
+{
+       int ret = 0;
+       struct sigaction sa;
+       sigset_t sigset;
+
+       if ((ret = sigemptyset(&sigset)) < 0) {
+               PERROR("sigemptyset");
+               goto end;
+       }
+
+       sa.sa_handler = sighandler;
+       sa.sa_mask = sigset;
+       sa.sa_flags = 0;
+
+       if ((ret = sigaction(SIGTERM, &sa, NULL)) < 0) {
+               PERROR("sigaction");
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ *  handle_command
+ *
+ *  Handle the full argv list of a first level command. Will find the command
+ *  in the global commands array and call the function callback associated.
+ *
+ *  If command not found, return -1
+ *  else, return function command error code.
+ */
+static int handle_command(int argc, char **argv)
+{
+       int i = 0, ret;
+       struct cmd_struct *cmd;
+
+       if (*argv == NULL) {
+               ret = CMD_SUCCESS;
+               goto end;
+       }
+
+       /* Special case for help command which needs the commands array */
+       if (strcmp(argv[0], "help") == 0) {
+               ret = cmd_help(argc, (const char**) argv, commands);
+               goto end;
+       }
+
+       cmd = &commands[i];
+       while (cmd->name != NULL) {
+               /* Find command */
+               if (strcmp(argv[0], cmd->name) == 0) {
+                       ret = cmd->func(argc, (const char**) argv);
+                       goto end;
+               }
+               i++;
+               cmd = &commands[i];
+       }
+
+       /* Command not found */
+       ret = CMD_UNDEFINED;
+
+end:
+       return ret;
+}
+
+static bool command_exists(const char *command)
+{
+       const struct cmd_struct *cmd = commands;
+       bool exists = false;
+
+       while (cmd->name != NULL) {
+               if (!strcmp(command, cmd->name)) {
+                       exists = true;
+                       goto end;
+               }
+               cmd++;
+       }
+
+end:
+       return exists;
+}
+
+static void show_basic_help(void)
+{
+       puts("Usage: lttng [--group=GROUP] [--mi=TYPE] [--no-sessiond | --sessiond-path=PATH]");
+       puts("             [--quiet | -v | -vv | -vvv] COMMAND [COMMAND OPTIONS]");
+       puts("");
+       puts("Available commands:");
+       puts("");
+       puts("Recording sessions:");
+       puts("  create            " CONFIG_CMD_DESCR_CREATE);
+       puts("  clear             " CONFIG_CMD_DESCR_CLEAR);
+       puts("  destroy           " CONFIG_CMD_DESCR_DESTROY);
+       puts("  load              " CONFIG_CMD_DESCR_LOAD);
+       puts("  regenerate        " CONFIG_CMD_DESCR_REGENERATE);
+       puts("  save              " CONFIG_CMD_DESCR_SAVE);
+       puts("  set-session       " CONFIG_CMD_DESCR_SET_SESSION);
+       puts("");
+       puts("Channels:");
+       puts("  add-context       " CONFIG_CMD_DESCR_ADD_CONTEXT);
+       puts("  disable-channel   " CONFIG_CMD_DESCR_DISABLE_CHANNEL);
+       puts("  enable-channel    " CONFIG_CMD_DESCR_ENABLE_CHANNEL);
+       puts("");
+       puts("Recording event rules:");
+       puts("  disable-event     " CONFIG_CMD_DESCR_DISABLE_EVENT);
+       puts("  enable-event      " CONFIG_CMD_DESCR_ENABLE_EVENT);
+       puts("");
+       puts("Status:");
+       puts("  list              " CONFIG_CMD_DESCR_LIST);
+       puts("  status            " CONFIG_CMD_DESCR_STATUS);
+       puts("");
+       puts("Control:");
+       puts("  snapshot          " CONFIG_CMD_DESCR_SNAPSHOT);
+       puts("  start             " CONFIG_CMD_DESCR_START);
+       puts("  stop              " CONFIG_CMD_DESCR_STOP);
+       puts("");
+       puts("Recording session rotation:");
+       puts("  disable-rotation  " CONFIG_CMD_DESCR_DISABLE_ROTATION);
+       puts("  enable-rotation   " CONFIG_CMD_DESCR_ENABLE_ROTATION);
+       puts("  rotate            " CONFIG_CMD_DESCR_ROTATE);
+       puts("");
+       puts("Resource tracking:");
+       puts("  track             " CONFIG_CMD_DESCR_TRACK);
+       puts("  untrack           " CONFIG_CMD_DESCR_UNTRACK);
+       puts("");
+       puts("Triggers:");
+       puts("  add-trigger       " CONFIG_CMD_DESCR_ADD_TRIGGER);
+       puts("  remove-trigger    " CONFIG_CMD_DESCR_REMOVE_TRIGGER);
+       puts("  list-triggers     " CONFIG_CMD_DESCR_LIST_TRIGGERS);
+       puts("");
+       puts("Miscellaneous:");
+       puts("  help              " CONFIG_CMD_DESCR_HELP);
+       puts("  version           " CONFIG_CMD_DESCR_VERSION);
+       puts("  view              " CONFIG_CMD_DESCR_VIEW);
+       puts("");
+       puts("Run `lttng help COMMAND` or `lttng COMMAND --help` to get help with");
+       puts("command COMMAND.");
+       puts("");
+       puts("See `man lttng` for more help with the lttng command.");
+}
+
+/*
+ * Parse command line arguments.
+ *
+ * Return 0 if OK, else -1
+ */
+static int parse_args(int argc, char **argv)
+{
+       int opt, ret;
+
+       if (lttng_is_setuid_setgid()) {
+               ERR("'%s' is not allowed to be executed as a setuid/setgid binary for security reasons. Aborting.", argv[0]);
+               clean_exit(EXIT_FAILURE);
+       }
+
+       if (argc < 2) {
+               show_basic_help();
+               clean_exit(EXIT_FAILURE);
+       }
+
+       while ((opt = getopt_long(argc, argv, "+Vhnvqg:m:", long_options, NULL)) != -1) {
+               switch (opt) {
+               case 'V':
+                       version(stdout);
+                       ret = 0;
+                       goto end;
+               case 'h':
+                       ret = utils_show_help(1, "lttng", help_msg);
+                       if (ret) {
+                               ERR("Cannot show --help for `lttng`");
+                               perror("exec");
+                       }
+                       goto end;
+               case 'v':
+                       /* There is only 3 possible level of verbosity. (-vvv) */
+                       if (lttng_opt_verbose < 3) {
+                               lttng_opt_verbose += 1;
+                       }
+                       break;
+               case 'q':
+                       lttng_opt_quiet = 1;
+                       break;
+               case 'm':
+                       lttng_opt_mi = mi_output_type(optarg);
+                       if (lttng_opt_mi < 0) {
+                               ret = lttng_opt_mi;
+                               goto error;
+                       }
+                       break;
+               case 'g':
+                       lttng_set_tracing_group(optarg);
+                       break;
+               case 'n':
+                       opt_no_sessiond = 1;
+                       break;
+               case OPT_SESSION_PATH:
+                       free(opt_sessiond_path);
+                       opt_sessiond_path = strdup(optarg);
+                       if (!opt_sessiond_path) {
+                               ret = -1;
+                               goto error;
+                       }
+                       break;
+               case OPT_RELAYD_PATH:
+                       free(opt_relayd_path);
+                       opt_relayd_path = strdup(optarg);
+                       if (!opt_relayd_path) {
+                               ret = -1;
+                               goto error;
+                       }
+                       break;
+               case OPT_DUMP_OPTIONS:
+                       list_options(stdout);
+                       ret = 0;
+                       goto end;
+               case OPT_DUMP_COMMANDS:
+                       list_commands(commands, stdout);
+                       ret = 0;
+                       goto end;
+               default:
+                       ret = 1;
+                       goto error;
+               }
+       }
+
+       /* If both options are specified, quiet wins */
+       if (lttng_opt_verbose && lttng_opt_quiet) {
+               lttng_opt_verbose = 0;
+       }
+
+       /* No leftovers, quit */
+       if ((argc - optind) == 0) {
+               ret = 1;
+               goto error;
+       }
+
+       /*
+        * Handle leftovers which is a first level command with the trailing
+        * options.
+        */
+       ret = handle_command(argc - optind, argv + optind);
+       switch (ret) {
+       case CMD_WARNING:
+       case CMD_ERROR:
+               break;
+       case CMD_UNDEFINED:
+               if (!command_exists(*(argv + optind))) {
+                       MSG("lttng: %s is not an lttng command. See 'lttng --help'.",
+                                       *(argv + optind));
+               } else {
+                       ERR("Unrecognized argument used with \'%s\' command",
+                                       *(argv + optind));
+               }
+               break;
+       case CMD_FATAL:
+       case CMD_UNSUPPORTED:
+               break;
+       case -1:
+               ret = 1;
+               break;
+       case 0:
+               break;
+       default:
+               if (ret < 0) {
+                       ret = -ret;
+               }
+               break;
+       }
+
+end:
+error:
+       return ret;
+}
+
+
+/*
+ *  main
+ */
+int main(int argc, char *argv[])
+{
+       int ret;
+
+       progname = argv[0] ? argv[0] : "lttng";
+
+       ret = set_signal_handler();
+       if (ret < 0) {
+               clean_exit(ret);
+       }
+
+       ret = parse_args(argc, argv);
+       if (ret != 0) {
+               clean_exit(ret);
+       }
+
+       return 0;
+}
diff --git a/src/bin/lttng/uprobe.c b/src/bin/lttng/uprobe.c
deleted file mode 100644 (file)
index 2a28901..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * Copyright (C) 2020 EfficiOS, Inc.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#include "uprobe.h"
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <unistd.h>
-
-#include "common/compat/getenv.h"
-#include "common/string-utils/string-utils.h"
-#include "common/utils.h"
-#include "lttng/constant.h"
-
-#include "command.h"
-
-/*
- * Walk the directories in the PATH environment variable to find the target
- * binary passed as parameter.
- *
- * On success, the full path of the binary is copied in binary_full_path out
- * parameter. This buffer is allocated by the caller and must be at least
- * LTTNG_PATH_MAX bytes long.
- * On failure, returns -1;
- */
-static
-int walk_command_search_path(const char *binary, char *binary_full_path)
-{
-       char *tentative_binary_path = NULL;
-       char *command_search_path = NULL;
-       char *curr_search_dir_end = NULL;
-       char *curr_search_dir = NULL;
-       struct stat stat_output;
-       int ret = 0;
-
-       command_search_path = lttng_secure_getenv("PATH");
-       if (!command_search_path) {
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * Duplicate the $PATH string as the char pointer returned by getenv() should
-        * not be modified.
-        */
-       command_search_path = strdup(command_search_path);
-       if (!command_search_path) {
-               ret = -1;
-               goto end;
-       }
-
-       /*
-        * This char array is used to concatenate path to binary to look for
-        * the binary.
-        */
-       tentative_binary_path = zmalloc(LTTNG_PATH_MAX * sizeof(char));
-       if (!tentative_binary_path) {
-               ret = -1;
-               goto alloc_error;
-       }
-
-       curr_search_dir = command_search_path;
-       do {
-               /*
-                * Split on ':'. The return value of this call points to the
-                * matching character.
-                */
-               curr_search_dir_end = strchr(curr_search_dir, ':');
-               if (curr_search_dir_end != NULL) {
-                       /*
-                        * Add a NULL byte to the end of the first token so it
-                        * can be used as a string.
-                        */
-                       curr_search_dir_end[0] = '\0';
-               }
-
-               /* Empty the tentative path */
-               memset(tentative_binary_path, 0, LTTNG_PATH_MAX * sizeof(char));
-
-               /*
-                * Build the tentative path to the binary using the current
-                * search directory and the name of the binary.
-                */
-               ret = snprintf(tentative_binary_path, LTTNG_PATH_MAX, "%s/%s",
-                               curr_search_dir, binary);
-               if (ret < 0) {
-                       goto free_binary_path;
-               }
-               if (ret < LTTNG_PATH_MAX) {
-                        /*
-                         * Use STAT(2) to see if the file exists.
-                        */
-                       ret = stat(tentative_binary_path, &stat_output);
-                       if (ret == 0) {
-                               /*
-                                * Verify that it is a regular file or a
-                                * symlink and not a special file (e.g.
-                                * device).
-                                */
-                               if (S_ISREG(stat_output.st_mode)
-                                               || S_ISLNK(stat_output.st_mode)) {
-                                       /*
-                                        * Found a match, set the out parameter
-                                        * and return success.
-                                        */
-                                       ret = lttng_strncpy(binary_full_path,
-                                                       tentative_binary_path,
-                                                       LTTNG_PATH_MAX);
-                                       if (ret == -1) {
-                                               ERR("Source path does not fit "
-                                                       "in destination buffer.");
-                                       }
-                                       goto free_binary_path;
-                               }
-                       }
-               }
-               /* Go to the next entry in the $PATH variable. */
-               curr_search_dir = curr_search_dir_end + 1;
-       } while (curr_search_dir_end != NULL);
-
-free_binary_path:
-       free(tentative_binary_path);
-alloc_error:
-       free(command_search_path);
-end:
-       return ret;
-}
-
-/*
- * Check if the symbol field passed by the user is in fact an address or an
- * offset from a symbol. Those two instrumentation types are not supported yet.
- * It's expected to be a common mistake because of the existing --probe option
- * that does support these formats.
- *
- * Here are examples of these unsupported formats for the --userspace-probe
- * option:
- * elf:/path/to/binary:0x400430
- * elf:/path/to/binary:4194364
- * elf:/path/to/binary:my_symbol+0x323
- * elf:/path/to/binary:my_symbol+43
- */
-static
-int warn_userspace_probe_syntax(const char *symbol)
-{
-       int ret;
-
-       /* Check if the symbol field is an hex address. */
-       ret = sscanf(symbol, "0x%*x");
-       if (ret > 0) {
-               /* If there is a match, print a warning and return an error. */
-               ERR("Userspace probe on address not supported yet.");
-               ret = CMD_UNSUPPORTED;
-               goto error;
-       }
-
-       /* Check if the symbol field is an decimal address. */
-       ret = sscanf(symbol, "%*u");
-       if (ret > 0) {
-               /* If there is a match, print a warning and return an error. */
-               ERR("Userspace probe on address not supported yet.");
-               ret = CMD_UNSUPPORTED;
-               goto error;
-       }
-
-       /* Check if the symbol field is symbol+hex_offset. */
-       ret = sscanf(symbol, "%*[^+]+0x%*x");
-       if (ret > 0) {
-               /* If there is a match, print a warning and return an error. */
-               ERR("Userspace probe on symbol+offset not supported yet.");
-               ret = CMD_UNSUPPORTED;
-               goto error;
-       }
-
-       /* Check if the symbol field is symbol+decimal_offset. */
-       ret = sscanf(symbol, "%*[^+]+%*u");
-       if (ret > 0) {
-               /* If there is a match, print a warning and return an error. */
-               ERR("Userspace probe on symbol+offset not supported yet.");
-               ret = CMD_UNSUPPORTED;
-               goto error;
-       }
-
-       ret = 0;
-
-error:
-       return ret;
-}
-
-/*
- * Parse userspace probe options
- * Set the userspace probe fields in the lttng_event struct and set the
- * target_path to the path to the binary.
- */
-int parse_userspace_probe_opts(const char *opt,
-               struct lttng_userspace_probe_location **probe_location)
-{
-       int ret = CMD_SUCCESS;
-       size_t num_token = 0;
-       char *target_path = NULL;
-       char *unescaped_target_path = NULL;
-       char *real_target_path = NULL;
-       char *symbol_name = NULL, *probe_name = NULL, *provider_name = NULL;
-       struct lttng_userspace_probe_location *probe_location_local = NULL;
-       struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
-       struct lttng_dynamic_pointer_array tokens;
-
-       LTTNG_ASSERT(opt);
-
-       /*
-        * userspace probe fields are separated by ':'.
-        */
-       ret = strutils_split(opt, ':', true, &tokens);
-       if (ret == 0) {
-               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
-       }
-
-       /*
-        * Early sanity check that the number of parameter is between 2 and 4
-        * inclusively.
-        * elf:PATH:SYMBOL
-        * std:PATH:PROVIDER_NAME:PROBE_NAME
-        * PATH:SYMBOL (same behavior as ELF)
-        */
-       if (ret < 0 || num_token < 2 || num_token > 4) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /*
-        * Looking up the first parameter will tell the technique to use to
-        * interpret the userspace probe/function description.
-        */
-       switch (num_token) {
-       case 2:
-               /* When the probe type is omitted we assume ELF for now. */
-       case 3:
-               if (num_token == 3 && strcmp(lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "elf") == 0) {
-                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
-                       symbol_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
-               } else if (num_token == 2) {
-                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
-                       symbol_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
-               } else {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               lookup_method =
-                       lttng_userspace_probe_location_lookup_method_function_elf_create();
-               if (!lookup_method) {
-                       WARN("Failed to create ELF lookup method");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               break;
-       case 4:
-               if (strcmp(lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "sdt") == 0) {
-                       target_path = lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
-                       provider_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
-                       probe_name = lttng_dynamic_pointer_array_get_pointer(&tokens, 3);
-               } else {
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               lookup_method =
-                       lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
-               if (!lookup_method) {
-                       WARN("Failed to create SDT lookup method");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               break;
-       default:
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /* strutils_unescape_string allocates a new char *. */
-       unescaped_target_path = strutils_unescape_string(target_path, 0);
-       if (!unescaped_target_path) {
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /*
-        * If there is not forward slash in the path. Walk the $PATH else
-        * expand.
-        */
-       if (strchr(unescaped_target_path, '/') == NULL) {
-               /* Walk the $PATH variable to find the targeted binary. */
-               real_target_path = zmalloc(LTTNG_PATH_MAX * sizeof(char));
-               if (!real_target_path) {
-                       PERROR("Error allocating path buffer");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-               ret = walk_command_search_path(unescaped_target_path, real_target_path);
-               if (ret) {
-                       ERR("Binary not found.");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       } else {
-               /*
-                * Expand references to `/./` and `/../`. This function does not check
-                * if the file exists. This call returns an allocated buffer on
-                * success.
-                */
-               real_target_path = utils_expand_path_keep_symlink(unescaped_target_path);
-               if (!real_target_path) {
-                       ERR("Error expanding the path to binary.");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /*
-                * Check if the file exists using access(2), If it does not,
-                * return an error.
-                */
-               ret = access(real_target_path, F_OK);
-               if (ret) {
-                       ERR("Cannot find binary at path: %s.", real_target_path);
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-       }
-
-       switch (lttng_userspace_probe_location_lookup_method_get_type(lookup_method)) {
-       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
-               /*
-                * Check for common mistakes in userspace probe description syntax.
-                */
-               ret = warn_userspace_probe_syntax(symbol_name);
-               if (ret) {
-                       goto end;
-               }
-
-               probe_location_local = lttng_userspace_probe_location_function_create(
-                               real_target_path, symbol_name, lookup_method);
-               if (!probe_location_local) {
-                       WARN("Failed to create function probe location");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Ownership transferred to probe_location. */
-               lookup_method = NULL;
-               break;
-       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
-               probe_location_local = lttng_userspace_probe_location_tracepoint_create(
-                               real_target_path, provider_name, probe_name, lookup_method);
-               if (!probe_location_local) {
-                       WARN("Failed to create function probe location");
-                       ret = CMD_ERROR;
-                       goto end;
-               }
-
-               /* Ownership transferred to probe_location. */
-               lookup_method = NULL;
-               break;
-       default:
-               ret = CMD_ERROR;
-               goto end;
-       }
-
-       /*
-        * Everything went fine, transfer ownership of probe location to
-        * caller.
-        */
-       *probe_location = probe_location_local;
-       probe_location_local = NULL;
-
-end:
-       lttng_userspace_probe_location_destroy(probe_location_local);
-       lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
-       lttng_dynamic_pointer_array_reset(&tokens);
-       /*
-        * Freeing both char * here makes the error handling simplier. free()
-        * performs not action if the pointer is NULL.
-        */
-       free(real_target_path);
-       free(unescaped_target_path);
-
-       return ret;
-}
diff --git a/src/bin/lttng/uprobe.cpp b/src/bin/lttng/uprobe.cpp
new file mode 100644 (file)
index 0000000..7a119ae
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * Copyright (C) 2020 EfficiOS, Inc.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#include "uprobe.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "common/compat/getenv.h"
+#include "common/string-utils/string-utils.h"
+#include "common/utils.h"
+#include "lttng/constant.h"
+
+#include "command.h"
+
+/*
+ * Walk the directories in the PATH environment variable to find the target
+ * binary passed as parameter.
+ *
+ * On success, the full path of the binary is copied in binary_full_path out
+ * parameter. This buffer is allocated by the caller and must be at least
+ * LTTNG_PATH_MAX bytes long.
+ * On failure, returns -1;
+ */
+static
+int walk_command_search_path(const char *binary, char *binary_full_path)
+{
+       char *tentative_binary_path = NULL;
+       char *command_search_path = NULL;
+       char *curr_search_dir_end = NULL;
+       char *curr_search_dir = NULL;
+       struct stat stat_output;
+       int ret = 0;
+
+       command_search_path = lttng_secure_getenv("PATH");
+       if (!command_search_path) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * Duplicate the $PATH string as the char pointer returned by getenv() should
+        * not be modified.
+        */
+       command_search_path = strdup(command_search_path);
+       if (!command_search_path) {
+               ret = -1;
+               goto end;
+       }
+
+       /*
+        * This char array is used to concatenate path to binary to look for
+        * the binary.
+        */
+       tentative_binary_path = (char *) zmalloc(LTTNG_PATH_MAX * sizeof(char));
+       if (!tentative_binary_path) {
+               ret = -1;
+               goto alloc_error;
+       }
+
+       curr_search_dir = command_search_path;
+       do {
+               /*
+                * Split on ':'. The return value of this call points to the
+                * matching character.
+                */
+               curr_search_dir_end = strchr(curr_search_dir, ':');
+               if (curr_search_dir_end != NULL) {
+                       /*
+                        * Add a NULL byte to the end of the first token so it
+                        * can be used as a string.
+                        */
+                       curr_search_dir_end[0] = '\0';
+               }
+
+               /* Empty the tentative path */
+               memset(tentative_binary_path, 0, LTTNG_PATH_MAX * sizeof(char));
+
+               /*
+                * Build the tentative path to the binary using the current
+                * search directory and the name of the binary.
+                */
+               ret = snprintf(tentative_binary_path, LTTNG_PATH_MAX, "%s/%s",
+                               curr_search_dir, binary);
+               if (ret < 0) {
+                       goto free_binary_path;
+               }
+               if (ret < LTTNG_PATH_MAX) {
+                        /*
+                         * Use STAT(2) to see if the file exists.
+                        */
+                       ret = stat(tentative_binary_path, &stat_output);
+                       if (ret == 0) {
+                               /*
+                                * Verify that it is a regular file or a
+                                * symlink and not a special file (e.g.
+                                * device).
+                                */
+                               if (S_ISREG(stat_output.st_mode)
+                                               || S_ISLNK(stat_output.st_mode)) {
+                                       /*
+                                        * Found a match, set the out parameter
+                                        * and return success.
+                                        */
+                                       ret = lttng_strncpy(binary_full_path,
+                                                       tentative_binary_path,
+                                                       LTTNG_PATH_MAX);
+                                       if (ret == -1) {
+                                               ERR("Source path does not fit "
+                                                       "in destination buffer.");
+                                       }
+                                       goto free_binary_path;
+                               }
+                       }
+               }
+               /* Go to the next entry in the $PATH variable. */
+               curr_search_dir = curr_search_dir_end + 1;
+       } while (curr_search_dir_end != NULL);
+
+free_binary_path:
+       free(tentative_binary_path);
+alloc_error:
+       free(command_search_path);
+end:
+       return ret;
+}
+
+/*
+ * Check if the symbol field passed by the user is in fact an address or an
+ * offset from a symbol. Those two instrumentation types are not supported yet.
+ * It's expected to be a common mistake because of the existing --probe option
+ * that does support these formats.
+ *
+ * Here are examples of these unsupported formats for the --userspace-probe
+ * option:
+ * elf:/path/to/binary:0x400430
+ * elf:/path/to/binary:4194364
+ * elf:/path/to/binary:my_symbol+0x323
+ * elf:/path/to/binary:my_symbol+43
+ */
+static
+int warn_userspace_probe_syntax(const char *symbol)
+{
+       int ret;
+
+       /* Check if the symbol field is an hex address. */
+       ret = sscanf(symbol, "0x%*x");
+       if (ret > 0) {
+               /* If there is a match, print a warning and return an error. */
+               ERR("Userspace probe on address not supported yet.");
+               ret = CMD_UNSUPPORTED;
+               goto error;
+       }
+
+       /* Check if the symbol field is an decimal address. */
+       ret = sscanf(symbol, "%*u");
+       if (ret > 0) {
+               /* If there is a match, print a warning and return an error. */
+               ERR("Userspace probe on address not supported yet.");
+               ret = CMD_UNSUPPORTED;
+               goto error;
+       }
+
+       /* Check if the symbol field is symbol+hex_offset. */
+       ret = sscanf(symbol, "%*[^+]+0x%*x");
+       if (ret > 0) {
+               /* If there is a match, print a warning and return an error. */
+               ERR("Userspace probe on symbol+offset not supported yet.");
+               ret = CMD_UNSUPPORTED;
+               goto error;
+       }
+
+       /* Check if the symbol field is symbol+decimal_offset. */
+       ret = sscanf(symbol, "%*[^+]+%*u");
+       if (ret > 0) {
+               /* If there is a match, print a warning and return an error. */
+               ERR("Userspace probe on symbol+offset not supported yet.");
+               ret = CMD_UNSUPPORTED;
+               goto error;
+       }
+
+       ret = 0;
+
+error:
+       return ret;
+}
+
+/*
+ * Parse userspace probe options
+ * Set the userspace probe fields in the lttng_event struct and set the
+ * target_path to the path to the binary.
+ */
+int parse_userspace_probe_opts(const char *opt,
+               struct lttng_userspace_probe_location **probe_location)
+{
+       int ret = CMD_SUCCESS;
+       size_t num_token = 0;
+       char *target_path = NULL;
+       char *unescaped_target_path = NULL;
+       char *real_target_path = NULL;
+       char *symbol_name = NULL, *probe_name = NULL, *provider_name = NULL;
+       struct lttng_userspace_probe_location *probe_location_local = NULL;
+       struct lttng_userspace_probe_location_lookup_method *lookup_method = NULL;
+       struct lttng_dynamic_pointer_array tokens;
+
+       LTTNG_ASSERT(opt);
+
+       /*
+        * userspace probe fields are separated by ':'.
+        */
+       ret = strutils_split(opt, ':', true, &tokens);
+       if (ret == 0) {
+               num_token = lttng_dynamic_pointer_array_get_count(&tokens);
+       }
+
+       /*
+        * Early sanity check that the number of parameter is between 2 and 4
+        * inclusively.
+        * elf:PATH:SYMBOL
+        * std:PATH:PROVIDER_NAME:PROBE_NAME
+        * PATH:SYMBOL (same behavior as ELF)
+        */
+       if (ret < 0 || num_token < 2 || num_token > 4) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /*
+        * Looking up the first parameter will tell the technique to use to
+        * interpret the userspace probe/function description.
+        */
+       switch (num_token) {
+       case 2:
+               /* When the probe type is omitted we assume ELF for now. */
+       case 3:
+               if (num_token == 3 && strcmp((const char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "elf") == 0) {
+                       target_path = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+                       symbol_name = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
+               } else if (num_token == 2) {
+                       target_path = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 0);
+                       symbol_name = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+               } else {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               lookup_method =
+                       lttng_userspace_probe_location_lookup_method_function_elf_create();
+               if (!lookup_method) {
+                       WARN("Failed to create ELF lookup method");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               break;
+       case 4:
+               if (strcmp((const char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 0), "sdt") == 0) {
+                       target_path = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 1);
+                       provider_name = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 2);
+                       probe_name = (char *) lttng_dynamic_pointer_array_get_pointer(&tokens, 3);
+               } else {
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               lookup_method =
+                       lttng_userspace_probe_location_lookup_method_tracepoint_sdt_create();
+               if (!lookup_method) {
+                       WARN("Failed to create SDT lookup method");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               break;
+       default:
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /* strutils_unescape_string allocates a new char *. */
+       unescaped_target_path = strutils_unescape_string(target_path, 0);
+       if (!unescaped_target_path) {
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /*
+        * If there is not forward slash in the path. Walk the $PATH else
+        * expand.
+        */
+       if (strchr(unescaped_target_path, '/') == NULL) {
+               /* Walk the $PATH variable to find the targeted binary. */
+               real_target_path = (char *) zmalloc(LTTNG_PATH_MAX * sizeof(char));
+               if (!real_target_path) {
+                       PERROR("Error allocating path buffer");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+               ret = walk_command_search_path(unescaped_target_path, real_target_path);
+               if (ret) {
+                       ERR("Binary not found.");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       } else {
+               /*
+                * Expand references to `/./` and `/../`. This function does not check
+                * if the file exists. This call returns an allocated buffer on
+                * success.
+                */
+               real_target_path = utils_expand_path_keep_symlink(unescaped_target_path);
+               if (!real_target_path) {
+                       ERR("Error expanding the path to binary.");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /*
+                * Check if the file exists using access(2), If it does not,
+                * return an error.
+                */
+               ret = access(real_target_path, F_OK);
+               if (ret) {
+                       ERR("Cannot find binary at path: %s.", real_target_path);
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+       }
+
+       switch (lttng_userspace_probe_location_lookup_method_get_type(lookup_method)) {
+       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_FUNCTION_ELF:
+               /*
+                * Check for common mistakes in userspace probe description syntax.
+                */
+               ret = warn_userspace_probe_syntax(symbol_name);
+               if (ret) {
+                       goto end;
+               }
+
+               probe_location_local = lttng_userspace_probe_location_function_create(
+                               real_target_path, symbol_name, lookup_method);
+               if (!probe_location_local) {
+                       WARN("Failed to create function probe location");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Ownership transferred to probe_location. */
+               lookup_method = NULL;
+               break;
+       case LTTNG_USERSPACE_PROBE_LOCATION_LOOKUP_METHOD_TYPE_TRACEPOINT_SDT:
+               probe_location_local = lttng_userspace_probe_location_tracepoint_create(
+                               real_target_path, provider_name, probe_name, lookup_method);
+               if (!probe_location_local) {
+                       WARN("Failed to create function probe location");
+                       ret = CMD_ERROR;
+                       goto end;
+               }
+
+               /* Ownership transferred to probe_location. */
+               lookup_method = NULL;
+               break;
+       default:
+               ret = CMD_ERROR;
+               goto end;
+       }
+
+       /*
+        * Everything went fine, transfer ownership of probe location to
+        * caller.
+        */
+       *probe_location = probe_location_local;
+       probe_location_local = NULL;
+
+end:
+       lttng_userspace_probe_location_destroy(probe_location_local);
+       lttng_userspace_probe_location_lookup_method_destroy(lookup_method);
+       lttng_dynamic_pointer_array_reset(&tokens);
+       /*
+        * Freeing both char * here makes the error handling simplier. free()
+        * performs not action if the pointer is NULL.
+        */
+       free(real_target_path);
+       free(unescaped_target_path);
+
+       return ret;
+}
diff --git a/src/bin/lttng/utils.c b/src/bin/lttng/utils.c
deleted file mode 100644 (file)
index 6440ca7..0000000
+++ /dev/null
@@ -1,675 +0,0 @@
-/*
- * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
- *
- * SPDX-License-Identifier: GPL-2.0-only
- *
- */
-
-#define _LGPL_SOURCE
-#include <stdlib.h>
-#include <ctype.h>
-#include <limits.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <signal.h>
-#include <netinet/in.h>
-#include <arpa/inet.h>
-#include <inttypes.h>
-#include <unistd.h>
-
-#include <common/error.h>
-#include <common/utils.h>
-#include <common/defaults.h>
-
-#include "conf.h"
-#include "utils.h"
-#include "command.h"
-
-static const char *str_all = "ALL";
-static const char *str_tracepoint = "Tracepoint";
-static const char *str_syscall = "Syscall";
-static const char *str_probe = "Probe";
-static const char *str_userspace_probe = "Userspace Probe";
-static const char *str_function = "Function";
-
-static
-char *_get_session_name(int quiet)
-{
-       const char *path;
-       char *session_name = NULL;
-
-       /* Get path to config file */
-       path = utils_get_home_dir();
-       if (path == NULL) {
-               goto error;
-       }
-
-       /* Get session name from config */
-       session_name = quiet ? config_read_session_name_quiet(path) :
-               config_read_session_name(path);
-       if (session_name == NULL) {
-               goto error;
-       }
-
-       DBG2("Config file path found: %s", path);
-       DBG("Session name found: %s", session_name);
-       return session_name;
-
-error:
-       return NULL;
-}
-
-/*
- *  get_session_name
- *
- *  Return allocated string with the session name found in the config
- *  directory.
- */
-char *get_session_name(void)
-{
-       return _get_session_name(0);
-}
-
-/*
- *  get_session_name_quiet (no warnings/errors emitted)
- *
- *  Return allocated string with the session name found in the config
- *  directory.
- */
-char *get_session_name_quiet(void)
-{
-       return _get_session_name(1);
-}
-
-/*
- *  list_commands
- *
- *  List commands line by line. This is mostly for bash auto completion and to
- *  avoid difficult parsing.
- */
-void list_commands(struct cmd_struct *commands, FILE *ofp)
-{
-       int i = 0;
-       struct cmd_struct *cmd = NULL;
-
-       cmd = &commands[i];
-       while (cmd->name != NULL) {
-               fprintf(ofp, "%s\n", cmd->name);
-               i++;
-               cmd = &commands[i];
-       }
-}
-
-/*
- * list_cmd_options
- *
- * Prints a simple list of the options available to a command. This is intended
- * to be easily parsed for bash completion.
- */
-void list_cmd_options(FILE *ofp, struct poptOption *options)
-{
-       int i;
-       struct poptOption *option = NULL;
-
-       for (i = 0; options[i].longName != NULL; i++) {
-               option = &options[i];
-
-               fprintf(ofp, "--%s\n", option->longName);
-
-               if (isprint(option->shortName)) {
-                       fprintf(ofp, "-%c\n", option->shortName);
-               }
-       }
-}
-
-/*
- * Same as list_cmd_options, but for options specified for argpar.
- */
-void list_cmd_options_argpar(FILE *ofp, const struct argpar_opt_descr *options)
-{
-       int i;
-
-       for (i = 0; options[i].long_name != NULL; i++) {
-               const struct argpar_opt_descr *option = &options[i];
-
-               fprintf(ofp, "--%s\n", option->long_name);
-
-               if (isprint(option->short_name)) {
-                       fprintf(ofp, "-%c\n", option->short_name);
-               }
-       }
-}
-
-/*
- * fls: returns the position of the most significant bit.
- * Returns 0 if no bit is set, else returns the position of the most
- * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
- */
-#if defined(__i386) || defined(__x86_64)
-static inline
-unsigned int fls_u32(uint32_t x)
-{
-       int r;
-
-       asm("bsrl %1,%0\n\t"
-           "jnz 1f\n\t"
-           "movl $-1,%0\n\t"
-           "1:\n\t"
-           : "=r" (r) : "rm" (x));
-       return r + 1;
-}
-#define HAS_FLS_U32
-#endif
-
-#if defined(__x86_64) && defined(__LP64__)
-static inline
-unsigned int fls_u64(uint64_t x)
-{
-       long r;
-
-       asm("bsrq %1,%0\n\t"
-           "jnz 1f\n\t"
-           "movq $-1,%0\n\t"
-           "1:\n\t"
-           : "=r" (r) : "rm" (x));
-       return r + 1;
-}
-#define HAS_FLS_U64
-#endif
-
-#ifndef HAS_FLS_U64
-static __attribute__((unused))
-unsigned int fls_u64(uint64_t x)
-{
-       unsigned int r = 64;
-
-       if (!x)
-               return 0;
-
-       if (!(x & 0xFFFFFFFF00000000ULL)) {
-               x <<= 32;
-               r -= 32;
-       }
-       if (!(x & 0xFFFF000000000000ULL)) {
-               x <<= 16;
-               r -= 16;
-       }
-       if (!(x & 0xFF00000000000000ULL)) {
-               x <<= 8;
-               r -= 8;
-       }
-       if (!(x & 0xF000000000000000ULL)) {
-               x <<= 4;
-               r -= 4;
-       }
-       if (!(x & 0xC000000000000000ULL)) {
-               x <<= 2;
-               r -= 2;
-       }
-       if (!(x & 0x8000000000000000ULL)) {
-               x <<= 1;
-               r -= 1;
-       }
-       return r;
-}
-#endif
-
-#ifndef HAS_FLS_U32
-static __attribute__((unused))
-unsigned int fls_u32(uint32_t x)
-{
-       unsigned int r = 32;
-
-       if (!x)
-               return 0;
-       if (!(x & 0xFFFF0000U)) {
-               x <<= 16;
-               r -= 16;
-       }
-       if (!(x & 0xFF000000U)) {
-               x <<= 8;
-               r -= 8;
-       }
-       if (!(x & 0xF0000000U)) {
-               x <<= 4;
-               r -= 4;
-       }
-       if (!(x & 0xC0000000U)) {
-               x <<= 2;
-               r -= 2;
-       }
-       if (!(x & 0x80000000U)) {
-               x <<= 1;
-               r -= 1;
-       }
-       return r;
-}
-#endif
-
-static
-unsigned int fls_ulong(unsigned long x)
-{
-#if (CAA_BITS_PER_LONG == 32)
-       return fls_u32(x);
-#else
-       return fls_u64(x);
-#endif
-}
-
-/*
- * Return the minimum order for which x <= (1UL << order).
- * Return -1 if x is 0.
- */
-int get_count_order_u32(uint32_t x)
-{
-       if (!x)
-               return -1;
-
-       return fls_u32(x - 1);
-}
-
-/*
- * Return the minimum order for which x <= (1UL << order).
- * Return -1 if x is 0.
- */
-int get_count_order_u64(uint64_t x)
-{
-       if (!x)
-               return -1;
-
-       return fls_u64(x - 1);
-}
-
-/*
- * Return the minimum order for which x <= (1UL << order).
- * Return -1 if x is 0.
- */
-int get_count_order_ulong(unsigned long x)
-{
-       if (!x)
-               return -1;
-
-       return fls_ulong(x - 1);
-}
-
-const char *get_event_type_str(enum lttng_event_type type)
-{
-       const char *str_event_type;
-
-       switch (type) {
-       case LTTNG_EVENT_ALL:
-               str_event_type = str_all;
-               break;
-       case LTTNG_EVENT_TRACEPOINT:
-               str_event_type = str_tracepoint;
-               break;
-       case LTTNG_EVENT_SYSCALL:
-               str_event_type = str_syscall;
-               break;
-       case LTTNG_EVENT_PROBE:
-               str_event_type = str_probe;
-               break;
-       case LTTNG_EVENT_USERSPACE_PROBE:
-               str_event_type = str_userspace_probe;
-               break;
-       case LTTNG_EVENT_FUNCTION:
-               str_event_type = str_function;
-               break;
-       default:
-               /* Should not have an unknown event type or else define it. */
-               abort();
-       }
-
-       return str_event_type;
-}
-
-/*
- * Spawn a lttng relayd daemon by forking and execv.
- */
-int spawn_relayd(const char *pathname, int port)
-{
-       int ret = 0;
-       pid_t pid;
-       char url[255];
-
-       if (!port) {
-               port = DEFAULT_NETWORK_VIEWER_PORT;
-       }
-
-       ret = snprintf(url, sizeof(url), "tcp://localhost:%d", port);
-       if (ret < 0) {
-               goto end;
-       }
-
-       MSG("Spawning a relayd daemon");
-       pid = fork();
-       if (pid == 0) {
-               /*
-                * Spawn session daemon and tell
-                * it to signal us when ready.
-                */
-               execlp(pathname, "lttng-relayd", "-L", url, NULL);
-               /* execlp only returns if error happened */
-               if (errno == ENOENT) {
-                       ERR("No relayd found. Use --relayd-path.");
-               } else {
-                       PERROR("execlp");
-               }
-               kill(getppid(), SIGTERM);       /* wake parent */
-               exit(EXIT_FAILURE);
-       } else if (pid > 0) {
-               goto end;
-       } else {
-               PERROR("fork");
-               ret = -1;
-               goto end;
-       }
-
-end:
-       return ret;
-}
-
-/*
- * Check if relayd is alive.
- *
- * Return 1 if found else 0 if NOT found. Negative value on error.
- */
-int check_relayd(void)
-{
-       int ret, fd;
-       struct sockaddr_in sin;
-
-       fd = socket(AF_INET, SOCK_STREAM, 0);
-       if (fd < 0) {
-               PERROR("socket check relayd");
-               ret = -1;
-               goto error_socket;
-       }
-
-       sin.sin_family = AF_INET;
-       sin.sin_port = htons(DEFAULT_NETWORK_VIEWER_PORT);
-       ret = inet_pton(sin.sin_family, "127.0.0.1", &sin.sin_addr);
-       if (ret < 1) {
-               PERROR("inet_pton check relayd");
-               ret = -1;
-               goto error;
-       }
-
-       /*
-        * A successful connect means the relayd exists thus returning 0 else a
-        * negative value means it does NOT exists.
-        */
-       ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
-       if (ret < 0) {
-               /* Not found. */
-               ret = 0;
-       } else {
-               /* Already spawned. */
-               ret = 1;
-       }
-
-error:
-       if (close(fd) < 0) {
-               PERROR("close relayd fd");
-       }
-error_socket:
-       return ret;
-}
-
-int print_missing_or_multiple_domains(unsigned int domain_count,
-               bool include_agent_domains)
-{
-       int ret = 0;
-
-       if (domain_count == 0) {
-               ERR("Please specify a domain (--kernel/--userspace%s).",
-                               include_agent_domains ?
-                                               "/--jul/--log4j/--python" :
-                                               "");
-               ret = -1;
-       } else if (domain_count > 1) {
-               ERR("Only one domain must be specified.");
-               ret = -1;
-       }
-
-       return ret;
-}
-
-/*
- * Get the discarded events and lost packet counts.
- */
-void print_session_stats(const char *session_name)
-{
-       char *str;
-       const int ret = get_session_stats_str(session_name, &str);
-
-       if (ret >= 0 && str) {
-               MSG("%s", str);
-               free(str);
-       }
-}
-
-int get_session_stats_str(const char *session_name, char **out_str)
-{
-       int count, nb_domains, domain_idx, channel_idx, session_idx, ret;
-       struct lttng_domain *domains = NULL;
-       struct lttng_channel *channels = NULL;
-       uint64_t discarded_events_total = 0, lost_packets_total = 0;
-       struct lttng_session *sessions = NULL;
-       const struct lttng_session *selected_session = NULL;
-       char *stats_str = NULL;
-       bool print_discarded_events = false, print_lost_packets = false;
-
-       count = lttng_list_sessions(&sessions);
-       if (count < 1) {
-               ERR("Failed to retrieve session descriptions while printing session statistics.");
-               ret = -1;
-               goto end;
-       }
-
-       /* Identify the currently-selected sessions. */
-       for (session_idx = 0; session_idx < count; session_idx++) {
-               if (!strcmp(session_name, sessions[session_idx].name)) {
-                       selected_session = &sessions[session_idx];
-                       break;
-               }
-       }
-       if (!selected_session) {
-               ERR("Failed to retrieve session \"%s\" description while printing session statistics.", session_name);
-               ret = -1;
-               goto end;
-       }
-
-       nb_domains = lttng_list_domains(session_name, &domains);
-       if (nb_domains < 0) {
-               ret = -1;
-               goto end;
-       }
-       for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) {
-               struct lttng_handle *handle = lttng_create_handle(session_name,
-                               &domains[domain_idx]);
-
-               if (!handle) {
-                       ERR("Failed to create session handle while printing session statistics.");
-                       ret = -1;
-                       goto end;
-               }
-
-               free(channels);
-               channels = NULL;
-               count = lttng_list_channels(handle, &channels);
-               for (channel_idx = 0; channel_idx < count; channel_idx++) {
-                       uint64_t discarded_events = 0, lost_packets = 0;
-                       struct lttng_channel *channel = &channels[channel_idx];
-
-                       ret = lttng_channel_get_discarded_event_count(channel,
-                                       &discarded_events);
-                       if (ret) {
-                               ERR("Failed to retrieve discarded event count from channel %s",
-                                               channel->name);
-                       }
-
-                       ret = lttng_channel_get_lost_packet_count(channel,
-                                       &lost_packets);
-                       if (ret) {
-                               ERR("Failed to retrieve lost packet count from channel %s",
-                                               channel->name);
-                       }
-
-                       discarded_events_total += discarded_events;
-                       lost_packets_total += lost_packets;
-               }
-               lttng_destroy_handle(handle);
-       }
-
-       print_discarded_events = discarded_events_total > 0 &&
-                                !selected_session->snapshot_mode;
-       print_lost_packets = lost_packets_total > 0 &&
-                            !selected_session->snapshot_mode;
-
-       if (print_discarded_events && print_lost_packets) {
-               ret = asprintf(&stats_str,
-                               "Warning: %" PRIu64
-                               " events were discarded and %" PRIu64
-                               " packets were lost, please refer to "
-                               "the documentation on channel configuration.",
-                               discarded_events_total, lost_packets_total);
-       } else if (print_discarded_events) {
-               ret = asprintf(&stats_str,
-                               "Warning: %" PRIu64
-                               " events were discarded, please refer to "
-                               "the documentation on channel configuration.",
-                               discarded_events_total);
-       } else if (print_lost_packets) {
-               ret = asprintf(&stats_str,
-                               "Warning: %" PRIu64
-                               " packets were lost, please refer to "
-                               "the documentation on channel configuration.",
-                               lost_packets_total);
-       } else {
-               ret = 0;
-       }
-
-       if (ret < 0) {
-               ERR("Failed to format lost packet and discarded events statistics");
-       } else {
-               *out_str = stats_str;
-               ret = 0;
-       }
-end:
-       free(sessions);
-       free(channels);
-       free(domains);
-       return ret;
-}
-
-int show_cmd_help(const char *cmd_name, const char *help_msg)
-{
-       int ret;
-       char page_name[32];
-
-       ret = sprintf(page_name, "lttng-%s", cmd_name);
-       LTTNG_ASSERT(ret > 0 && ret < 32);
-       ret = utils_show_help(1, page_name, help_msg);
-       if (ret && !help_msg) {
-               ERR("Cannot view man page `lttng-%s(1)`", cmd_name);
-               perror("exec");
-       }
-
-       return ret;
-}
-
-int print_trace_archive_location(
-               const struct lttng_trace_archive_location *location,
-               const char *session_name)
-{
-       int ret = 0;
-       enum lttng_trace_archive_location_type location_type;
-       enum lttng_trace_archive_location_status status;
-       bool printed_location = false;
-
-       location_type = lttng_trace_archive_location_get_type(location);
-
-       _MSG("Trace chunk archive for session %s is now readable",
-                       session_name);
-       switch (location_type) {
-       case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
-       {
-               const char *absolute_path;
-
-               status = lttng_trace_archive_location_local_get_absolute_path(
-                               location, &absolute_path);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-               MSG(" at %s", absolute_path);
-               printed_location = true;
-               break;
-       }
-       case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
-       {
-               uint16_t control_port, data_port;
-               const char *host, *relative_path, *protocol_str;
-               enum lttng_trace_archive_location_relay_protocol_type protocol;
-
-               /* Fetch all relay location parameters. */
-               status = lttng_trace_archive_location_relay_get_protocol_type(
-                               location, &protocol);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-
-               status = lttng_trace_archive_location_relay_get_host(
-                               location, &host);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-
-               status = lttng_trace_archive_location_relay_get_control_port(
-                               location, &control_port);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-
-               status = lttng_trace_archive_location_relay_get_data_port(
-                               location, &data_port);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-
-               status = lttng_trace_archive_location_relay_get_relative_path(
-                               location, &relative_path);
-               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
-                       ret = -1;
-                       goto end;
-               }
-
-               switch (protocol) {
-               case LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP:
-                       protocol_str = "tcp";
-                       break;
-               default:
-                       protocol_str = "unknown";
-                       break;
-               }
-
-               MSG(" on relay %s://%s/%s [control port %" PRIu16 ", data port %"
-                               PRIu16 "]", protocol_str, host,
-                               relative_path, control_port, data_port);
-               printed_location = true;
-               break;
-       }
-       default:
-               break;
-       }
-end:
-       if (!printed_location) {
-               MSG(" at an unknown location");
-       }
-       return ret;
-}
diff --git a/src/bin/lttng/utils.cpp b/src/bin/lttng/utils.cpp
new file mode 100644 (file)
index 0000000..6440ca7
--- /dev/null
@@ -0,0 +1,675 @@
+/*
+ * Copyright (C) 2011 David Goulet <david.goulet@polymtl.ca>
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ *
+ */
+
+#define _LGPL_SOURCE
+#include <stdlib.h>
+#include <ctype.h>
+#include <limits.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <signal.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <inttypes.h>
+#include <unistd.h>
+
+#include <common/error.h>
+#include <common/utils.h>
+#include <common/defaults.h>
+
+#include "conf.h"
+#include "utils.h"
+#include "command.h"
+
+static const char *str_all = "ALL";
+static const char *str_tracepoint = "Tracepoint";
+static const char *str_syscall = "Syscall";
+static const char *str_probe = "Probe";
+static const char *str_userspace_probe = "Userspace Probe";
+static const char *str_function = "Function";
+
+static
+char *_get_session_name(int quiet)
+{
+       const char *path;
+       char *session_name = NULL;
+
+       /* Get path to config file */
+       path = utils_get_home_dir();
+       if (path == NULL) {
+               goto error;
+       }
+
+       /* Get session name from config */
+       session_name = quiet ? config_read_session_name_quiet(path) :
+               config_read_session_name(path);
+       if (session_name == NULL) {
+               goto error;
+       }
+
+       DBG2("Config file path found: %s", path);
+       DBG("Session name found: %s", session_name);
+       return session_name;
+
+error:
+       return NULL;
+}
+
+/*
+ *  get_session_name
+ *
+ *  Return allocated string with the session name found in the config
+ *  directory.
+ */
+char *get_session_name(void)
+{
+       return _get_session_name(0);
+}
+
+/*
+ *  get_session_name_quiet (no warnings/errors emitted)
+ *
+ *  Return allocated string with the session name found in the config
+ *  directory.
+ */
+char *get_session_name_quiet(void)
+{
+       return _get_session_name(1);
+}
+
+/*
+ *  list_commands
+ *
+ *  List commands line by line. This is mostly for bash auto completion and to
+ *  avoid difficult parsing.
+ */
+void list_commands(struct cmd_struct *commands, FILE *ofp)
+{
+       int i = 0;
+       struct cmd_struct *cmd = NULL;
+
+       cmd = &commands[i];
+       while (cmd->name != NULL) {
+               fprintf(ofp, "%s\n", cmd->name);
+               i++;
+               cmd = &commands[i];
+       }
+}
+
+/*
+ * list_cmd_options
+ *
+ * Prints a simple list of the options available to a command. This is intended
+ * to be easily parsed for bash completion.
+ */
+void list_cmd_options(FILE *ofp, struct poptOption *options)
+{
+       int i;
+       struct poptOption *option = NULL;
+
+       for (i = 0; options[i].longName != NULL; i++) {
+               option = &options[i];
+
+               fprintf(ofp, "--%s\n", option->longName);
+
+               if (isprint(option->shortName)) {
+                       fprintf(ofp, "-%c\n", option->shortName);
+               }
+       }
+}
+
+/*
+ * Same as list_cmd_options, but for options specified for argpar.
+ */
+void list_cmd_options_argpar(FILE *ofp, const struct argpar_opt_descr *options)
+{
+       int i;
+
+       for (i = 0; options[i].long_name != NULL; i++) {
+               const struct argpar_opt_descr *option = &options[i];
+
+               fprintf(ofp, "--%s\n", option->long_name);
+
+               if (isprint(option->short_name)) {
+                       fprintf(ofp, "-%c\n", option->short_name);
+               }
+       }
+}
+
+/*
+ * fls: returns the position of the most significant bit.
+ * Returns 0 if no bit is set, else returns the position of the most
+ * significant bit (from 1 to 32 on 32-bit, from 1 to 64 on 64-bit).
+ */
+#if defined(__i386) || defined(__x86_64)
+static inline
+unsigned int fls_u32(uint32_t x)
+{
+       int r;
+
+       asm("bsrl %1,%0\n\t"
+           "jnz 1f\n\t"
+           "movl $-1,%0\n\t"
+           "1:\n\t"
+           : "=r" (r) : "rm" (x));
+       return r + 1;
+}
+#define HAS_FLS_U32
+#endif
+
+#if defined(__x86_64) && defined(__LP64__)
+static inline
+unsigned int fls_u64(uint64_t x)
+{
+       long r;
+
+       asm("bsrq %1,%0\n\t"
+           "jnz 1f\n\t"
+           "movq $-1,%0\n\t"
+           "1:\n\t"
+           : "=r" (r) : "rm" (x));
+       return r + 1;
+}
+#define HAS_FLS_U64
+#endif
+
+#ifndef HAS_FLS_U64
+static __attribute__((unused))
+unsigned int fls_u64(uint64_t x)
+{
+       unsigned int r = 64;
+
+       if (!x)
+               return 0;
+
+       if (!(x & 0xFFFFFFFF00000000ULL)) {
+               x <<= 32;
+               r -= 32;
+       }
+       if (!(x & 0xFFFF000000000000ULL)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xFF00000000000000ULL)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xF000000000000000ULL)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xC000000000000000ULL)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x8000000000000000ULL)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+}
+#endif
+
+#ifndef HAS_FLS_U32
+static __attribute__((unused))
+unsigned int fls_u32(uint32_t x)
+{
+       unsigned int r = 32;
+
+       if (!x)
+               return 0;
+       if (!(x & 0xFFFF0000U)) {
+               x <<= 16;
+               r -= 16;
+       }
+       if (!(x & 0xFF000000U)) {
+               x <<= 8;
+               r -= 8;
+       }
+       if (!(x & 0xF0000000U)) {
+               x <<= 4;
+               r -= 4;
+       }
+       if (!(x & 0xC0000000U)) {
+               x <<= 2;
+               r -= 2;
+       }
+       if (!(x & 0x80000000U)) {
+               x <<= 1;
+               r -= 1;
+       }
+       return r;
+}
+#endif
+
+static
+unsigned int fls_ulong(unsigned long x)
+{
+#if (CAA_BITS_PER_LONG == 32)
+       return fls_u32(x);
+#else
+       return fls_u64(x);
+#endif
+}
+
+/*
+ * Return the minimum order for which x <= (1UL << order).
+ * Return -1 if x is 0.
+ */
+int get_count_order_u32(uint32_t x)
+{
+       if (!x)
+               return -1;
+
+       return fls_u32(x - 1);
+}
+
+/*
+ * Return the minimum order for which x <= (1UL << order).
+ * Return -1 if x is 0.
+ */
+int get_count_order_u64(uint64_t x)
+{
+       if (!x)
+               return -1;
+
+       return fls_u64(x - 1);
+}
+
+/*
+ * Return the minimum order for which x <= (1UL << order).
+ * Return -1 if x is 0.
+ */
+int get_count_order_ulong(unsigned long x)
+{
+       if (!x)
+               return -1;
+
+       return fls_ulong(x - 1);
+}
+
+const char *get_event_type_str(enum lttng_event_type type)
+{
+       const char *str_event_type;
+
+       switch (type) {
+       case LTTNG_EVENT_ALL:
+               str_event_type = str_all;
+               break;
+       case LTTNG_EVENT_TRACEPOINT:
+               str_event_type = str_tracepoint;
+               break;
+       case LTTNG_EVENT_SYSCALL:
+               str_event_type = str_syscall;
+               break;
+       case LTTNG_EVENT_PROBE:
+               str_event_type = str_probe;
+               break;
+       case LTTNG_EVENT_USERSPACE_PROBE:
+               str_event_type = str_userspace_probe;
+               break;
+       case LTTNG_EVENT_FUNCTION:
+               str_event_type = str_function;
+               break;
+       default:
+               /* Should not have an unknown event type or else define it. */
+               abort();
+       }
+
+       return str_event_type;
+}
+
+/*
+ * Spawn a lttng relayd daemon by forking and execv.
+ */
+int spawn_relayd(const char *pathname, int port)
+{
+       int ret = 0;
+       pid_t pid;
+       char url[255];
+
+       if (!port) {
+               port = DEFAULT_NETWORK_VIEWER_PORT;
+       }
+
+       ret = snprintf(url, sizeof(url), "tcp://localhost:%d", port);
+       if (ret < 0) {
+               goto end;
+       }
+
+       MSG("Spawning a relayd daemon");
+       pid = fork();
+       if (pid == 0) {
+               /*
+                * Spawn session daemon and tell
+                * it to signal us when ready.
+                */
+               execlp(pathname, "lttng-relayd", "-L", url, NULL);
+               /* execlp only returns if error happened */
+               if (errno == ENOENT) {
+                       ERR("No relayd found. Use --relayd-path.");
+               } else {
+                       PERROR("execlp");
+               }
+               kill(getppid(), SIGTERM);       /* wake parent */
+               exit(EXIT_FAILURE);
+       } else if (pid > 0) {
+               goto end;
+       } else {
+               PERROR("fork");
+               ret = -1;
+               goto end;
+       }
+
+end:
+       return ret;
+}
+
+/*
+ * Check if relayd is alive.
+ *
+ * Return 1 if found else 0 if NOT found. Negative value on error.
+ */
+int check_relayd(void)
+{
+       int ret, fd;
+       struct sockaddr_in sin;
+
+       fd = socket(AF_INET, SOCK_STREAM, 0);
+       if (fd < 0) {
+               PERROR("socket check relayd");
+               ret = -1;
+               goto error_socket;
+       }
+
+       sin.sin_family = AF_INET;
+       sin.sin_port = htons(DEFAULT_NETWORK_VIEWER_PORT);
+       ret = inet_pton(sin.sin_family, "127.0.0.1", &sin.sin_addr);
+       if (ret < 1) {
+               PERROR("inet_pton check relayd");
+               ret = -1;
+               goto error;
+       }
+
+       /*
+        * A successful connect means the relayd exists thus returning 0 else a
+        * negative value means it does NOT exists.
+        */
+       ret = connect(fd, (struct sockaddr *) &sin, sizeof(sin));
+       if (ret < 0) {
+               /* Not found. */
+               ret = 0;
+       } else {
+               /* Already spawned. */
+               ret = 1;
+       }
+
+error:
+       if (close(fd) < 0) {
+               PERROR("close relayd fd");
+       }
+error_socket:
+       return ret;
+}
+
+int print_missing_or_multiple_domains(unsigned int domain_count,
+               bool include_agent_domains)
+{
+       int ret = 0;
+
+       if (domain_count == 0) {
+               ERR("Please specify a domain (--kernel/--userspace%s).",
+                               include_agent_domains ?
+                                               "/--jul/--log4j/--python" :
+                                               "");
+               ret = -1;
+       } else if (domain_count > 1) {
+               ERR("Only one domain must be specified.");
+               ret = -1;
+       }
+
+       return ret;
+}
+
+/*
+ * Get the discarded events and lost packet counts.
+ */
+void print_session_stats(const char *session_name)
+{
+       char *str;
+       const int ret = get_session_stats_str(session_name, &str);
+
+       if (ret >= 0 && str) {
+               MSG("%s", str);
+               free(str);
+       }
+}
+
+int get_session_stats_str(const char *session_name, char **out_str)
+{
+       int count, nb_domains, domain_idx, channel_idx, session_idx, ret;
+       struct lttng_domain *domains = NULL;
+       struct lttng_channel *channels = NULL;
+       uint64_t discarded_events_total = 0, lost_packets_total = 0;
+       struct lttng_session *sessions = NULL;
+       const struct lttng_session *selected_session = NULL;
+       char *stats_str = NULL;
+       bool print_discarded_events = false, print_lost_packets = false;
+
+       count = lttng_list_sessions(&sessions);
+       if (count < 1) {
+               ERR("Failed to retrieve session descriptions while printing session statistics.");
+               ret = -1;
+               goto end;
+       }
+
+       /* Identify the currently-selected sessions. */
+       for (session_idx = 0; session_idx < count; session_idx++) {
+               if (!strcmp(session_name, sessions[session_idx].name)) {
+                       selected_session = &sessions[session_idx];
+                       break;
+               }
+       }
+       if (!selected_session) {
+               ERR("Failed to retrieve session \"%s\" description while printing session statistics.", session_name);
+               ret = -1;
+               goto end;
+       }
+
+       nb_domains = lttng_list_domains(session_name, &domains);
+       if (nb_domains < 0) {
+               ret = -1;
+               goto end;
+       }
+       for (domain_idx = 0; domain_idx < nb_domains; domain_idx++) {
+               struct lttng_handle *handle = lttng_create_handle(session_name,
+                               &domains[domain_idx]);
+
+               if (!handle) {
+                       ERR("Failed to create session handle while printing session statistics.");
+                       ret = -1;
+                       goto end;
+               }
+
+               free(channels);
+               channels = NULL;
+               count = lttng_list_channels(handle, &channels);
+               for (channel_idx = 0; channel_idx < count; channel_idx++) {
+                       uint64_t discarded_events = 0, lost_packets = 0;
+                       struct lttng_channel *channel = &channels[channel_idx];
+
+                       ret = lttng_channel_get_discarded_event_count(channel,
+                                       &discarded_events);
+                       if (ret) {
+                               ERR("Failed to retrieve discarded event count from channel %s",
+                                               channel->name);
+                       }
+
+                       ret = lttng_channel_get_lost_packet_count(channel,
+                                       &lost_packets);
+                       if (ret) {
+                               ERR("Failed to retrieve lost packet count from channel %s",
+                                               channel->name);
+                       }
+
+                       discarded_events_total += discarded_events;
+                       lost_packets_total += lost_packets;
+               }
+               lttng_destroy_handle(handle);
+       }
+
+       print_discarded_events = discarded_events_total > 0 &&
+                                !selected_session->snapshot_mode;
+       print_lost_packets = lost_packets_total > 0 &&
+                            !selected_session->snapshot_mode;
+
+       if (print_discarded_events && print_lost_packets) {
+               ret = asprintf(&stats_str,
+                               "Warning: %" PRIu64
+                               " events were discarded and %" PRIu64
+                               " packets were lost, please refer to "
+                               "the documentation on channel configuration.",
+                               discarded_events_total, lost_packets_total);
+       } else if (print_discarded_events) {
+               ret = asprintf(&stats_str,
+                               "Warning: %" PRIu64
+                               " events were discarded, please refer to "
+                               "the documentation on channel configuration.",
+                               discarded_events_total);
+       } else if (print_lost_packets) {
+               ret = asprintf(&stats_str,
+                               "Warning: %" PRIu64
+                               " packets were lost, please refer to "
+                               "the documentation on channel configuration.",
+                               lost_packets_total);
+       } else {
+               ret = 0;
+       }
+
+       if (ret < 0) {
+               ERR("Failed to format lost packet and discarded events statistics");
+       } else {
+               *out_str = stats_str;
+               ret = 0;
+       }
+end:
+       free(sessions);
+       free(channels);
+       free(domains);
+       return ret;
+}
+
+int show_cmd_help(const char *cmd_name, const char *help_msg)
+{
+       int ret;
+       char page_name[32];
+
+       ret = sprintf(page_name, "lttng-%s", cmd_name);
+       LTTNG_ASSERT(ret > 0 && ret < 32);
+       ret = utils_show_help(1, page_name, help_msg);
+       if (ret && !help_msg) {
+               ERR("Cannot view man page `lttng-%s(1)`", cmd_name);
+               perror("exec");
+       }
+
+       return ret;
+}
+
+int print_trace_archive_location(
+               const struct lttng_trace_archive_location *location,
+               const char *session_name)
+{
+       int ret = 0;
+       enum lttng_trace_archive_location_type location_type;
+       enum lttng_trace_archive_location_status status;
+       bool printed_location = false;
+
+       location_type = lttng_trace_archive_location_get_type(location);
+
+       _MSG("Trace chunk archive for session %s is now readable",
+                       session_name);
+       switch (location_type) {
+       case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_LOCAL:
+       {
+               const char *absolute_path;
+
+               status = lttng_trace_archive_location_local_get_absolute_path(
+                               location, &absolute_path);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+               MSG(" at %s", absolute_path);
+               printed_location = true;
+               break;
+       }
+       case LTTNG_TRACE_ARCHIVE_LOCATION_TYPE_RELAY:
+       {
+               uint16_t control_port, data_port;
+               const char *host, *relative_path, *protocol_str;
+               enum lttng_trace_archive_location_relay_protocol_type protocol;
+
+               /* Fetch all relay location parameters. */
+               status = lttng_trace_archive_location_relay_get_protocol_type(
+                               location, &protocol);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               status = lttng_trace_archive_location_relay_get_host(
+                               location, &host);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               status = lttng_trace_archive_location_relay_get_control_port(
+                               location, &control_port);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               status = lttng_trace_archive_location_relay_get_data_port(
+                               location, &data_port);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               status = lttng_trace_archive_location_relay_get_relative_path(
+                               location, &relative_path);
+               if (status != LTTNG_TRACE_ARCHIVE_LOCATION_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+
+               switch (protocol) {
+               case LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP:
+                       protocol_str = "tcp";
+                       break;
+               default:
+                       protocol_str = "unknown";
+                       break;
+               }
+
+               MSG(" on relay %s://%s/%s [control port %" PRIu16 ", data port %"
+                               PRIu16 "]", protocol_str, host,
+                               relative_path, control_port, data_port);
+               printed_location = true;
+               break;
+       }
+       default:
+               break;
+       }
+end:
+       if (!printed_location) {
+               MSG(" at an unknown location");
+       }
+       return ret;
+}
index 43dbd0d56fc1bad4be1f7a8f67c56d53c66c8f33..4bfc51d2b3b395b9968b3ae163d8dc9d05891915 100644 (file)
@@ -9,6 +9,10 @@
 
 #include <stdbool.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /*
  * argpar is a library that provides facilities for argument parsing.
  *
@@ -310,5 +314,8 @@ void argpar_item_destroy(struct argpar_item *item);
                _item = NULL;                   \
        }
 
+#if defined(__cplusplus)
+}
+#endif
 
 #endif /* BABELTRACE_ARGPAR_H */
index a18d9e7cab56c2434a67debccf45d05b82252734..c9aa7f7fa099e3575b9a565176768a6bf6c4b134 100644 (file)
@@ -113,7 +113,7 @@ static inline int lttng_fls(int val)
 static inline
 void *lttng_memrchr(const void *s, int c, size_t n)
 {
-       return memrchr(s, c, n);
+       return (void *) memrchr(s, c, n);
 }
 #else
 static inline
index 4ce2316f166ed04a91c835de01e116864922ad0f..a370774049bd680df09ccc2716b0ba38e401be8b 100644 (file)
 
 #include <common/dynamic-buffer.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 typedef void (*lttng_dynamic_array_element_destructor)(void *element);
 typedef void (*lttng_dynamic_pointer_array_destructor)(void *ptr);
 
@@ -127,7 +131,7 @@ static inline
 void *lttng_dynamic_pointer_array_get_pointer(
                const struct lttng_dynamic_pointer_array *array, size_t index)
 {
-       void **element = lttng_dynamic_array_get_element(&array->array, index);
+       void **element = (void **) lttng_dynamic_array_get_element(&array->array, index);
 
        return *element;
 }
@@ -141,7 +145,7 @@ static inline
 void *lttng_dynamic_pointer_array_steal_pointer(
                struct lttng_dynamic_pointer_array *array, size_t index)
 {
-       void **p_element = lttng_dynamic_array_get_element(&array->array, index);
+       void **p_element = (void **) lttng_dynamic_array_get_element(&array->array, index);
        void *element = *p_element;
 
        *p_element = NULL;
@@ -177,4 +181,8 @@ void lttng_dynamic_pointer_array_reset(
 void lttng_dynamic_pointer_array_clear(
                struct lttng_dynamic_pointer_array *array);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_DYNAMIC_ARRAY_H */
index f9b2ec2f9f0d63bda4a1a1cb90c90cab39117f84..6660cee6adec9f765d8802bacfe80db44e67f954 100644 (file)
 #include <lttng/lttng-error.h>
 #include <common/compat/tid.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Avoid conflict with Solaris <sys/regset.h> */
 #if defined(ERR) && defined(__sun__)
 #undef ERR
@@ -264,4 +268,8 @@ const char *log_add_time(void);
 /* Name must be a statically-allocated string. */
 void logger_set_thread_name(const char *name, bool set_pthread_name);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _ERROR_H */
index 93f9b9b25fd746673cc4689ff7ac7f5033779122..d7a5674451db2ee8f9872f9134784710b43aba78 100644 (file)
 #include <stdio.h>
 #include <stdint.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define printf_debug(fmt, args...)                                     \
        do {                                                            \
                if (filter_parser_debug)                                \
@@ -99,6 +103,8 @@ struct filter_node {
        enum node_type type;
        union {
                struct {
+                       /* Avoid -Wextern-c-compat warning with clang++. */
+                       char unused;
                } unknown;
                struct {
                        struct filter_node *child;
@@ -186,4 +192,8 @@ int filter_visitor_ir_validate_string(struct filter_parser_ctx *ctx);
 int filter_visitor_ir_normalize_glob_patterns(struct filter_parser_ctx *ctx);
 int filter_visitor_ir_validate_globbing(struct filter_parser_ctx *ctx);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _FILTER_AST_H */
index fc3706616ae11a2bb5db01e67e25e035d048f736..b790f793afba832272edc1461de6f6a1c78fcf60 100644 (file)
@@ -933,7 +933,7 @@ int mi_lttng_writer_write_element_double(struct mi_writer *writer,
                        writer->writer, element_name, value);
 }
 
-int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version,
+int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version_data *version,
        const char *lttng_description, const char *lttng_license)
 {
        int ret;
index 414c731d24eafe710ed1b9c10f82ea27cffe2bff..2f27bf6cd52a37e4c8c2fdf8cb08f2d02cd118e4 100644 (file)
 #include <common/config/session-config.h>
 #include <lttng/lttng.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Don't want to reference snapshot-internal.h here */
 struct lttng_snapshot_output;
 
@@ -29,7 +33,7 @@ struct mi_writer {
 /*
  * Version information for the machine interface.
  */
-struct mi_lttng_version {
+struct mi_lttng_version_data {
        char version[LTTNG_NAME_MAX]; /* Version number of package */
        uint32_t version_major; /* LTTng-Tools major version number */
        uint32_t version_minor; /* LTTng-Tools minor version number */
@@ -563,7 +567,7 @@ int mi_lttng_writer_write_element_double(struct mi_writer *writer,
  * Returns zero if the element's value could be written.
  * Negative values indicate an error.
  */
-int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version *version,
+int mi_lttng_version(struct mi_writer *writer, struct mi_lttng_version_data *version,
                const char *lttng_description, const char *lttng_license);
 
 /*
@@ -1117,4 +1121,8 @@ int mi_lttng_rotate(struct mi_writer *writer,
                enum lttng_rotation_state rotation_state,
                const struct lttng_trace_archive_location *location);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _MI_LTTNG_H */
index 58c376fe1a0b91b5627315d7872a35cfffa153e2..406dfca2219220f86a91d0cae26017ac82f3e9e1 100644 (file)
@@ -46,9 +46,9 @@ int run_as_rmdir(const char *path, uid_t uid, gid_t gid);
 int run_as_rmdir_recursive(const char *path, uid_t uid, gid_t gid, int flags);
 int run_as_rmdirat(int dirfd, const char *path, uid_t uid, gid_t gid);
 int run_as_rmdirat_recursive(int dirfd, const char *path, uid_t uid, gid_t gid, int flags);
-int run_as_rename(const char *old, const char *new, uid_t uid, gid_t gid);
-int run_as_renameat(int old_dirfd, const char *old,
-               int new_dirfd, const char *new, uid_t uid, gid_t gid);
+int run_as_rename(const char *old_name, const char *new_name, uid_t uid, gid_t gid);
+int run_as_renameat(int old_dirfd, const char *old_name,
+               int new_dirfd, const char *new_name, uid_t uid, gid_t gid);
 int run_as_extract_elf_symbol_offset(int fd, const char* function,
                uid_t uid, gid_t gid, uint64_t *offset);
 int run_as_extract_sdt_probe_offsets(int fd, const char *provider_name,
index 409c60ec86067fe023527c9c0942d314573fbb3a..316fe19982372e0d64e6fc33c7aedbe10fa77347 100644 (file)
 
 #include <stdbool.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /*
  * Read the trace by `exec()ing` the provided viewer program if any. If
  * `opt_viewer` is NULL, try to read the trace with the default trace reader.
@@ -22,4 +26,8 @@
  */
 int spawn_viewer(const char *trace_path, char *opt_viewer, bool opt_live_mode);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* ifndef LTTNG_SPAWN_VIEWER_H */
index 1cf31e9d4b97df486ec1b0a1a0ec1d107f8562ba..fb795b9ddf9a5bec07e63da880da75788995e2d1 100644 (file)
 #include <common/macros.h>
 #include <common/dynamic-array.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 void strutils_normalize_star_glob_pattern(char *pattern);
 
 bool strutils_is_star_glob_pattern(const char *pattern);
@@ -27,4 +31,8 @@ void strutils_free_null_terminated_array_of_strings(char **array);
 
 size_t strutils_array_of_strings_len(char * const *array);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _STRING_UTILS_H */
index 87adf17d75d40af2945ef392bb45129bb777d11b..dc3f7634223ed8c79810c7f3c98cd117864a8f27 100644 (file)
 #include <common/macros.h>
 #include <common/compat/time.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define MSEC_PER_SEC    1000ULL
 #define NSEC_PER_SEC    1000000000ULL
 #define NSEC_PER_MSEC   1000000ULL
@@ -62,4 +66,8 @@ int time_to_iso8601_str(time_t time, char *str, size_t len);
 
 int time_to_datetime_str(time_t time, char *str, size_t len);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_TIME_H */
index 8b37940493ea391784dc4bad6417578e3deb1b2b..e81ee309e7e91527861eb6090475ba645f814bbd 100644 (file)
 #include <common/macros.h>
 #include <common/sessiond-comm/sessiond-comm.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 struct process_attr_value {
        enum lttng_process_attr_value_type type;
        union value {
@@ -76,4 +80,8 @@ enum lttng_error_code process_attr_value_from_comm(
                const struct lttng_buffer_view *value_view,
                struct process_attr_value **value);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* LTTNG_COMMON_TRACKER_H */
index ac1de9e0cbc2450f2592f54c46beb499321734c3..a270db9d927c021a84b59723afc8920b2948c536 100644 (file)
 #include <lttng/lttng.h>
 #include <common/macros.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 /* Destination type of lttng URI */
 enum lttng_dst_type {
        LTTNG_DST_IPV4                        = 1,
@@ -72,4 +76,8 @@ ssize_t uri_parse_str_urls(const char *ctrl_url, const char *data_url,
                struct lttng_uri **uris);
 int uri_to_str_url(struct lttng_uri *uri, char *dst, size_t size);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _LTT_URI_H */
index a3250639becd448d38a10e61ef47287709256204..6e478b39eb3609f90aa3ad1ab3b5a4200754411c 100644 (file)
 
 #include <common/compat/directory-handle.h>
 
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
 #define KIBI_LOG2 10
 #define MEBI_LOG2 20
 #define GIBI_LOG2 30
@@ -68,4 +72,8 @@ enum lttng_error_code utils_group_id_from_name(
 int utils_parse_unsigned_long_long(const char *str,
                unsigned long long *value);
 
+#if defined(__cplusplus)
+}
+#endif
+
 #endif /* _COMMON_UTILS_H */
This page took 0.439696 seconds and 4 git commands to generate.