+ if (!name) {
+ ret = -1;
+ goto end;
+ }
+
+ /*
+ * Check name against all internal UST event component namespaces used
+ * by the agents.
+ */
+ if (name_starts_with(name, DEFAULT_JUL_EVENT_COMPONENT) ||
+ name_starts_with(name, DEFAULT_LOG4J_EVENT_COMPONENT) ||
+ name_starts_with(name, DEFAULT_PYTHON_EVENT_COMPONENT)) {
+ ret = -1;
+ }
+
+end:
+ return ret;
+}
+
+/*
+ * Internal version of cmd_enable_event() with a supplemental
+ * "internal_event" flag which is used to enable internal events which should
+ * be hidden from clients. Such events are used in the agent implementation to
+ * enable the events through which all "agent" events are funeled.
+ */
+static int _cmd_enable_event(struct ltt_session *session,
+ struct lttng_domain *domain,
+ char *channel_name, struct lttng_event *event,
+ char *filter_expression,
+ struct lttng_filter_bytecode *filter,
+ struct lttng_event_exclusion *exclusion,
+ int wpipe, bool internal_event)
+{
+ int ret, channel_created = 0;
+ struct lttng_channel *attr;
+
+ assert(session);
+ assert(event);
+ assert(channel_name);
+
+ DBG("Enable event command for event \'%s\'", event->name);
+
+ ret = validate_event_name(event->name);
+ if (ret) {
+ goto error;
+ }
+
+ rcu_read_lock();
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_KERNEL:
+ {
+ struct ltt_kernel_channel *kchan;
+
+ /*
+ * If a non-default channel has been created in the
+ * session, explicitely require that -c chan_name needs
+ * to be provided.
+ */
+ if (session->kernel_session->has_non_default_channel
+ && channel_name[0] == '\0') {
+ ret = LTTNG_ERR_NEED_CHANNEL_NAME;
+ goto error;
+ }
+
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ attr = channel_new_default_attr(LTTNG_DOMAIN_KERNEL,
+ LTTNG_BUFFER_GLOBAL);
+ if (attr == NULL) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ strncpy(attr->name, channel_name, sizeof(attr->name));
+
+ ret = cmd_enable_channel(session, domain, attr, wpipe);
+ if (ret != LTTNG_OK) {
+ free(attr);
+ goto error;
+ }
+ free(attr);
+
+ channel_created = 1;
+ }
+
+ /* Get the newly created kernel channel pointer */
+ kchan = trace_kernel_get_channel_by_name(channel_name,
+ session->kernel_session);
+ if (kchan == NULL) {
+ /* This sould not happen... */
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+
+ switch (event->type) {
+ case LTTNG_EVENT_ALL:
+ {
+ char *filter_expression_a = NULL;
+ struct lttng_filter_bytecode *filter_a = NULL;
+
+ /*
+ * We need to duplicate filter_expression and filter,
+ * because ownership is passed to first enable
+ * event.
+ */
+ if (filter_expression) {
+ filter_expression_a = strdup(filter_expression);
+ if (!filter_expression_a) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ }
+ if (filter) {
+ filter_a = zmalloc(sizeof(*filter_a) + filter->len);
+ if (!filter_a) {
+ free(filter_expression_a);
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ memcpy(filter_a, filter, sizeof(*filter_a) + filter->len);
+ }
+ event->type = LTTNG_EVENT_TRACEPOINT; /* Hack */
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
+ /* We have passed ownership */
+ filter_expression = NULL;
+ filter = NULL;
+ if (ret != LTTNG_OK) {
+ if (channel_created) {
+ /* Let's not leak a useless channel. */
+ kernel_destroy_channel(kchan);
+ }
+ free(filter_expression_a);
+ free(filter_a);
+ goto error;
+ }
+ event->type = LTTNG_EVENT_SYSCALL; /* Hack */
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression_a, filter_a);
+ if (ret != LTTNG_OK) {
+ free(filter_expression_a);
+ free(filter_a);
+ goto error;
+ }
+ break;
+ }
+ case LTTNG_EVENT_PROBE:
+ case LTTNG_EVENT_FUNCTION:
+ case LTTNG_EVENT_FUNCTION_ENTRY:
+ case LTTNG_EVENT_TRACEPOINT:
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
+ /* We have passed ownership */
+ filter_expression = NULL;
+ filter = NULL;
+ if (ret != LTTNG_OK) {
+ if (channel_created) {
+ /* Let's not leak a useless channel. */
+ kernel_destroy_channel(kchan);
+ }
+ goto error;
+ }
+ break;
+ case LTTNG_EVENT_SYSCALL:
+ ret = event_kernel_enable_event(kchan, event,
+ filter_expression, filter);
+ /* We have passed ownership */
+ filter_expression = NULL;
+ filter = NULL;
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+ break;
+ default:
+ ret = LTTNG_ERR_UNK;
+ goto error;
+ }
+
+ kernel_wait_quiescent(kernel_tracer_fd);
+ break;
+ }
+ case LTTNG_DOMAIN_UST:
+ {
+ struct ltt_ust_channel *uchan;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ assert(usess);
+
+ /*
+ * If a non-default channel has been created in the
+ * session, explicitely require that -c chan_name needs
+ * to be provided.
+ */
+ if (usess->has_non_default_channel && channel_name[0] == '\0') {
+ ret = LTTNG_ERR_NEED_CHANNEL_NAME;
+ goto error;
+ }
+
+ /* Get channel from global UST domain */
+ uchan = trace_ust_find_channel_by_name(usess->domain_global.channels,
+ channel_name);
+ if (uchan == NULL) {
+ /* Create default channel */
+ attr = channel_new_default_attr(LTTNG_DOMAIN_UST,
+ usess->buffer_type);
+ if (attr == NULL) {
+ ret = LTTNG_ERR_FATAL;
+ goto error;
+ }
+ strncpy(attr->name, channel_name, sizeof(attr->name));
+
+ ret = cmd_enable_channel(session, domain, attr, wpipe);
+ if (ret != LTTNG_OK) {
+ free(attr);
+ goto error;
+ }
+ free(attr);
+
+ /* Get the newly created channel reference back */
+ uchan = trace_ust_find_channel_by_name(
+ usess->domain_global.channels, channel_name);
+ assert(uchan);
+ }
+
+ if (!internal_event) {
+ /*
+ * Ensure the event name is not reserved for internal
+ * use.
+ */
+ ret = validate_ust_event_name(event->name);
+ if (ret) {
+ WARN("Userspace event name %s failed validation.",
+ event->name ?
+ event->name : "NULL");
+ ret = LTTNG_ERR_INVALID_EVENT_NAME;
+ goto error;
+ }
+ }
+
+ /* At this point, the session and channel exist on the tracer */
+ ret = event_ust_enable_tracepoint(usess, uchan, event,
+ filter_expression, filter, exclusion,
+ internal_event);
+ /* We have passed ownership */
+ filter_expression = NULL;
+ filter = NULL;
+ exclusion = NULL;
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+ break;
+ }
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
+ {
+ const char *default_event_name, *default_chan_name;
+ struct agent *agt;
+ struct lttng_event uevent;
+ struct lttng_domain tmp_dom;
+ struct ltt_ust_session *usess = session->ust_session;
+
+ assert(usess);
+
+ agt = trace_ust_find_agent(usess, domain->type);
+ if (!agt) {
+ agt = agent_create(domain->type);
+ if (!agt) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto error;
+ }
+ agent_add(agt, usess->agents);
+ }
+
+ /* Create the default tracepoint. */
+ memset(&uevent, 0, sizeof(uevent));
+ uevent.type = LTTNG_EVENT_TRACEPOINT;
+ uevent.loglevel_type = LTTNG_EVENT_LOGLEVEL_ALL;
+ default_event_name = event_get_default_agent_ust_name(domain->type);
+ if (!default_event_name) {
+ ret = -LTTNG_ERR_FATAL;
+ goto error;
+ }
+ strncpy(uevent.name, default_event_name, sizeof(uevent.name));
+ uevent.name[sizeof(uevent.name) - 1] = '\0';
+
+ /*
+ * The domain type is changed because we are about to enable the
+ * default channel and event for the JUL domain that are hardcoded.
+ * This happens in the UST domain.
+ */
+ memcpy(&tmp_dom, domain, sizeof(tmp_dom));
+ tmp_dom.type = LTTNG_DOMAIN_UST;
+
+ switch (domain->type) {
+ case LTTNG_DOMAIN_LOG4J:
+ default_chan_name = DEFAULT_LOG4J_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_JUL:
+ default_chan_name = DEFAULT_JUL_CHANNEL_NAME;
+ break;
+ case LTTNG_DOMAIN_PYTHON:
+ default_chan_name = DEFAULT_PYTHON_CHANNEL_NAME;
+ break;
+ default:
+ /* The switch/case we are in makes this impossible */
+ assert(0);
+ }
+
+ {
+ struct lttng_filter_bytecode *filter_copy = NULL;
+ char *filter_expression_copy = NULL;
+
+ if (filter) {
+ filter_copy = zmalloc(
+ sizeof(struct lttng_filter_bytecode)
+ + filter->len);
+ if (!filter_copy) {
+ goto error;
+ }
+
+ memcpy(filter_copy, filter,
+ sizeof(struct lttng_filter_bytecode)
+ + filter->len);
+ }
+
+ if (filter_expression) {
+ filter_expression_copy =
+ strdup(filter_expression);
+ if (!filter_expression) {
+ ret = LTTNG_ERR_NOMEM;
+ goto error_free_copy;
+ }
+ }
+
+ ret = cmd_enable_event_internal(session, &tmp_dom,
+ (char *) default_chan_name,
+ &uevent, filter_expression_copy,
+ filter_copy, NULL, wpipe);
+ filter_copy = NULL;
+ filter_expression_copy = NULL;
+error_free_copy:
+ free(filter_copy);
+ free(filter_expression_copy);
+ }
+
+ if (ret != LTTNG_OK && ret != LTTNG_ERR_UST_EVENT_ENABLED) {
+ goto error;
+ }
+
+ /* The wild card * means that everything should be enabled. */
+ if (strncmp(event->name, "*", 1) == 0 && strlen(event->name) == 1) {
+ ret = event_agent_enable_all(usess, agt, event, filter,
+ filter_expression);
+ filter = NULL;
+ } else {
+ ret = event_agent_enable(usess, agt, event, filter,
+ filter_expression);
+ filter = NULL;
+ }
+ if (ret != LTTNG_OK) {
+ goto error;
+ }
+
+ break;
+ }
+ default:
+ ret = LTTNG_ERR_UND;
+ goto error;
+ }
+
+ ret = LTTNG_OK;
+
+error:
+ free(filter_expression);
+ free(filter);
+ free(exclusion);
+ rcu_read_unlock();
+ return ret;
+}
+
+/*
+ * Command LTTNG_ENABLE_EVENT processed by the client thread.
+ * We own filter, exclusion, and filter_expression.
+ */
+int cmd_enable_event(struct ltt_session *session, struct lttng_domain *domain,
+ char *channel_name, struct lttng_event *event,
+ char *filter_expression,
+ struct lttng_filter_bytecode *filter,
+ struct lttng_event_exclusion *exclusion,
+ int wpipe)
+{
+ return _cmd_enable_event(session, domain, channel_name, event,
+ filter_expression, filter, exclusion, wpipe, false);
+}
+
+/*
+ * Enable an event which is internal to LTTng. An internal should
+ * never be made visible to clients and are immune to checks such as
+ * reserved names.
+ */
+static int cmd_enable_event_internal(struct ltt_session *session,
+ struct lttng_domain *domain,
+ char *channel_name, struct lttng_event *event,
+ char *filter_expression,
+ struct lttng_filter_bytecode *filter,
+ struct lttng_event_exclusion *exclusion,
+ int wpipe)
+{
+ return _cmd_enable_event(session, domain, channel_name, event,
+ filter_expression, filter, exclusion, wpipe, true);
+}
+
+/*
+ * Command LTTNG_LIST_TRACEPOINTS processed by the client thread.
+ */
+ssize_t cmd_list_tracepoints(enum lttng_domain_type domain,
+ struct lttng_event **events)
+{
+ int ret;
+ ssize_t nb_events = 0;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_KERNEL:
+ nb_events = kernel_list_events(kernel_tracer_fd, events);
+ if (nb_events < 0) {
+ ret = LTTNG_ERR_KERN_LIST_FAIL;
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_UST:
+ nb_events = ust_app_list_events(events);
+ if (nb_events < 0) {
+ ret = LTTNG_ERR_UST_LIST_FAIL;
+ goto error;
+ }
+ break;
+ case LTTNG_DOMAIN_LOG4J:
+ case LTTNG_DOMAIN_JUL:
+ case LTTNG_DOMAIN_PYTHON:
+ nb_events = agent_list_events(events, domain);
+ if (nb_events < 0) {
+ ret = LTTNG_ERR_UST_LIST_FAIL;
+ goto error;
+ }
+ break;
+ default:
+ ret = LTTNG_ERR_UND;
+ goto error;
+ }
+
+ return nb_events;
+
+error:
+ /* Return negative value to differentiate return code */
+ return -ret;
+}
+
+/*
+ * Command LTTNG_LIST_TRACEPOINT_FIELDS processed by the client thread.
+ */
+ssize_t cmd_list_tracepoint_fields(enum lttng_domain_type domain,
+ struct lttng_event_field **fields)
+{
+ int ret;
+ ssize_t nb_fields = 0;
+
+ switch (domain) {
+ case LTTNG_DOMAIN_UST:
+ nb_fields = ust_app_list_event_fields(fields);