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>
-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
#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;
const char *lttng_condition_type_str(enum lttng_condition_type type);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* LTTNG_CONDITION_INTERNAL_H */
#include <sys/types.h>
#include <urcu/ref.h>
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
struct lttng_payload;
struct lttng_payload_view;
struct mi_writer;
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 */
#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;
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 */
* 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.
#include <sys/types.h>
#include <urcu/ref.h>
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
struct lttng_payload;
struct lttng_payload_view;
struct mi_writer;
enum lttng_trigger_status lttng_trigger_set_name(
struct lttng_trigger *trigger, const char *name);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* LTTNG_TRIGGER_INTERNAL_H */
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 \
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
-
--- /dev/null
+/*
+ * 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;
+}
+
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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);
-}
--- /dev/null
+/*
+ * 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);
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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);
-}
--- /dev/null
+/*
+ * 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);
+}
#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,
const char *loglevel_python_value_to_name(int loglevel);
+#ifdef __cplusplus
+}
+#endif
+
#endif /* _LTTNG_LOGLEVEL_UTILS_H */
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
+++ /dev/null
-/*
- * 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;
-}
--- /dev/null
+/*
+ * 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;
+}
#include <stdbool.h>
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
/*
* argpar is a library that provides facilities for argument parsing.
*
_item = NULL; \
}
+#if defined(__cplusplus)
+}
+#endif
#endif /* BABELTRACE_ARGPAR_H */
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
#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);
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;
}
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;
void lttng_dynamic_pointer_array_clear(
struct lttng_dynamic_pointer_array *array);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* LTTNG_DYNAMIC_ARRAY_H */
#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
/* 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 */
#include <stdio.h>
#include <stdint.h>
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
#define printf_debug(fmt, args...) \
do { \
if (filter_parser_debug) \
enum node_type type;
union {
struct {
+ /* Avoid -Wextern-c-compat warning with clang++. */
+ char unused;
} unknown;
struct {
struct filter_node *child;
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 */
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;
#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;
/*
* 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 */
* 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);
/*
enum lttng_rotation_state rotation_state,
const struct lttng_trace_archive_location *location);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* _MI_LTTNG_H */
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,
#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.
*/
int spawn_viewer(const char *trace_path, char *opt_viewer, bool opt_live_mode);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* ifndef LTTNG_SPAWN_VIEWER_H */
#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);
size_t strutils_array_of_strings_len(char * const *array);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* _STRING_UTILS_H */
#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
int time_to_datetime_str(time_t time, char *str, size_t len);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* LTTNG_TIME_H */
#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 {
const struct lttng_buffer_view *value_view,
struct process_attr_value **value);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* LTTNG_COMMON_TRACKER_H */
#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,
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 */
#include <common/compat/directory-handle.h>
+#if defined(__cplusplus)
+extern "C" {
+#endif
+
#define KIBI_LOG2 10
#define MEBI_LOG2 20
#define GIBI_LOG2 30
int utils_parse_unsigned_long_long(const char *str,
unsigned long long *value);
+#if defined(__cplusplus)
+}
+#endif
+
#endif /* _COMMON_UTILS_H */