#include <common/optional.h>
#include <lttng/action/action-internal.h>
#include <lttng/action/group.h>
+#include <lttng/action/notify-internal.h>
#include <lttng/action/notify.h>
#include <lttng/action/rotate-session.h>
#include <lttng/action/snapshot-session.h>
#include <lttng/action/start-session.h>
#include <lttng/action/stop-session.h>
#include <lttng/condition/evaluation.h>
+#include <lttng/condition/on-event-internal.h>
#include <lttng/lttng-error.h>
#include <lttng/trigger/trigger-internal.h>
#include <pthread.h>
uint64_t next_work_item_id;
};
+/*
+ * Only return non-zero on a fatal error that should shut down the action
+ * executor.
+ */
typedef int (*action_executor_handler)(struct action_executor *executor,
const struct action_work_item *,
const struct lttng_action *action);
static const char *get_action_name(const struct lttng_action *action)
{
- return action_type_names[lttng_action_get_type_const(action)];
+ const enum lttng_action_type action_type = lttng_action_get_type(action);
+
+ assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
+
+ return action_type_names[action_type];
+}
+
+/* Check if this trigger allowed to interect with a given session. */
+static bool is_trigger_allowed_for_session(const struct lttng_trigger *trigger,
+ struct ltt_session *session)
+{
+ bool is_allowed = false;
+ const struct lttng_credentials session_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(session->uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(session->gid),
+ };
+ /* Can never be NULL. */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(trigger);
+
+ is_allowed = (lttng_credentials_is_equal_uid(trigger_creds, &session_creds)) ||
+ (lttng_credentials_get_uid(trigger_creds) == 0);
+ if (!is_allowed) {
+ WARN("Trigger is not allowed to interact with session `%s`: session uid = %ld, session gid = %ld, trigger uid = %ld",
+ session->name,
+ (long int) session->uid,
+ (long int) session->gid,
+ (long int) lttng_credentials_get_uid(trigger_creds));
+ }
+
+ return is_allowed;
+}
+
+static const char *get_trigger_name(const struct lttng_trigger *trigger)
+{
+ const char *trigger_name;
+ enum lttng_trigger_status trigger_status;
+
+ trigger_status = lttng_trigger_get_name(trigger, &trigger_name);
+ assert(trigger_status == LTTNG_TRIGGER_STATUS_OK);
+
+ return trigger_name;
}
static int client_handle_transmission_status(
struct action_executor *executor = user_data;
bool update_communication = true;
- ASSERT_LOCKED(client->lock);
-
switch (status) {
case CLIENT_TRANSMISSION_STATUS_COMPLETE:
DBG("Successfully sent full notification to client, client_id = %" PRIu64,
case CLIENT_TRANSMISSION_STATUS_FAIL:
DBG("Communication error occurred while sending notification to client, client_id = %" PRIu64,
client->id);
- client->communication.active = false;
break;
default:
ERR("Fatal error encoutered while sending notification to client, client_id = %" PRIu64,
client->id);
- client->communication.active = false;
ret = -1;
goto end;
}
goto end;
}
+ /* Safe to read client's id without locking as it is immutable. */
ret = notification_thread_client_communication_update(
executor->notification_thread_handle, client->id,
status);
lttng_trigger_get_const_condition(work_item->trigger),
work_item->evaluation,
lttng_trigger_get_credentials(work_item->trigger),
- LTTNG_OPTIONAL_GET_PTR(work_item->object_creds),
- client_handle_transmission_status,
- executor);
+ work_item->object_creds.is_set ?
+ &(work_item->object_creds.value) :
+ NULL,
+ client_handle_transmission_status, executor);
}
static int action_executor_start_session_handler(struct action_executor *executor,
const char *session_name;
enum lttng_action_status action_status;
struct ltt_session *session;
+ enum lttng_error_code cmd_ret;
action_status = lttng_action_start_session_get_session_name(
action, &session_name);
if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to get session name from \"%s\" action",
+ ERR("Failed to get session name from `%s` action",
get_action_name(action));
ret = -1;
goto end;
session_lock_list();
session = session_find_by_name(session_name);
- if (session) {
- enum lttng_error_code cmd_ret;
-
- session_lock(session);
- cmd_ret = cmd_start_trace(session);
- session_unlock(session);
-
- switch (cmd_ret) {
- case LTTNG_OK:
- DBG("Successfully started session \"%s\" on behalf of trigger \"%p\"",
- session_name,
- work_item->trigger);
- break;
- case LTTNG_ERR_TRACE_ALREADY_STARTED:
- DBG("Attempted to start session \"%s\" on behalf of trigger \"%p\" but it was already started",
- session_name,
- work_item->trigger);
- break;
- default:
- WARN("Failed to start session \"%s\" on behalf of trigger \"%p\": %s",
- session_name,
- work_item->trigger,
- lttng_strerror(-cmd_ret));
- break;
- }
- session_put(session);
- } else {
- DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%p\"",
+ if (!session) {
+ DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
- work_item->trigger);
+ get_trigger_name(work_item->trigger));
+ goto error_unlock_list;
}
+
+ session_lock(session);
+ if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
+ goto error_dispose_session;
+ }
+
+ cmd_ret = cmd_start_trace(session);
+ switch (cmd_ret) {
+ case LTTNG_OK:
+ DBG("Successfully started session `%s` on behalf of trigger `%s`",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ case LTTNG_ERR_TRACE_ALREADY_STARTED:
+ DBG("Attempted to start session `%s` on behalf of trigger `%s` but it was already started",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ default:
+ WARN("Failed to start session `%s` on behalf of trigger `%s`: %s",
+ session_name, get_trigger_name(work_item->trigger),
+ lttng_strerror(-cmd_ret));
+ break;
+ }
+
+error_dispose_session:
+ session_unlock(session);
+ session_put(session);
+error_unlock_list:
session_unlock_list();
end:
return ret;
const char *session_name;
enum lttng_action_status action_status;
struct ltt_session *session;
+ enum lttng_error_code cmd_ret;
action_status = lttng_action_stop_session_get_session_name(
action, &session_name);
if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to get session name from \"%s\" action",
+ ERR("Failed to get session name from `%s` action",
get_action_name(action));
ret = -1;
goto end;
session_lock_list();
session = session_find_by_name(session_name);
- if (session) {
- enum lttng_error_code cmd_ret;
-
- session_lock(session);
- cmd_ret = cmd_stop_trace(session);
- session_unlock(session);
-
- switch (cmd_ret) {
- case LTTNG_OK:
- DBG("Successfully stopped session \"%s\" on behalf of trigger \"%p\"",
- session_name,
- work_item->trigger);
- break;
- case LTTNG_ERR_TRACE_ALREADY_STOPPED:
- DBG("Attempted to stop session \"%s\" on behalf of trigger \"%p\" but it was already stopped",
- session_name,
- work_item->trigger);
- break;
- default:
- WARN("Failed to stop session \"%s\" on behalf of trigger \"%p\": %s",
- session_name,
- work_item->trigger,
- lttng_strerror(-cmd_ret));
- break;
- }
- session_put(session);
- } else {
- DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%p\"",
+ if (!session) {
+ DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
- work_item->trigger);
+ get_trigger_name(work_item->trigger));
+ goto error_unlock_list;
+ }
+
+ session_lock(session);
+ if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
+ goto error_dispose_session;
+ }
+
+ cmd_ret = cmd_stop_trace(session);
+ switch (cmd_ret) {
+ case LTTNG_OK:
+ DBG("Successfully stopped session `%s` on behalf of trigger `%s`",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ case LTTNG_ERR_TRACE_ALREADY_STOPPED:
+ DBG("Attempted to stop session `%s` on behalf of trigger `%s` but it was already stopped",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ default:
+ WARN("Failed to stop session `%s` on behalf of trigger `%s`: %s",
+ session_name, get_trigger_name(work_item->trigger),
+ lttng_strerror(-cmd_ret));
+ break;
}
+
+error_dispose_session:
+ session_unlock(session);
+ session_put(session);
+error_unlock_list:
session_unlock_list();
end:
return ret;
const char *session_name;
enum lttng_action_status action_status;
struct ltt_session *session;
+ enum lttng_error_code cmd_ret;
action_status = lttng_action_rotate_session_get_session_name(
action, &session_name);
if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to get session name from \"%s\" action",
+ ERR("Failed to get session name from `%s` action",
get_action_name(action));
ret = -1;
goto end;
session_lock_list();
session = session_find_by_name(session_name);
- if (session) {
- enum lttng_error_code cmd_ret;
-
- session_lock(session);
- cmd_ret = cmd_rotate_session(session, NULL, false,
- LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
- session_unlock(session);
-
- switch (cmd_ret) {
- case LTTNG_OK:
- DBG("Successfully started rotation of session \"%s\" on behalf of trigger \"%p\"",
- session_name,
- work_item->trigger);
- break;
- case LTTNG_ERR_ROTATION_PENDING:
- DBG("Attempted to start a rotation of session \"%s\" on behalf of trigger \"%p\" but a rotation is already ongoing",
- session_name,
- work_item->trigger);
- break;
- case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
- case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
- DBG("Attempted to start a rotation of session \"%s\" on behalf of trigger \"%p\" but a rotation has already been completed since the last stop or clear",
- session_name,
- work_item->trigger);
- break;
- default:
- WARN("Failed to start a rotation of session \"%s\" on behalf of trigger \"%p\": %s",
- session_name,
- work_item->trigger,
- lttng_strerror(-cmd_ret));
- break;
- }
- session_put(session);
- } else {
- DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%p\"",
+ if (!session) {
+ DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
- work_item->trigger);
+ get_trigger_name(work_item->trigger));
+ goto error_unlock_list;
+ }
+
+ session_lock(session);
+ if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
+ goto error_dispose_session;
}
+
+ cmd_ret = cmd_rotate_session(session, NULL, false,
+ LTTNG_TRACE_CHUNK_COMMAND_TYPE_MOVE_TO_COMPLETED);
+ switch (cmd_ret) {
+ case LTTNG_OK:
+ DBG("Successfully started rotation of session `%s` on behalf of trigger `%s`",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ case LTTNG_ERR_ROTATION_PENDING:
+ DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation is already ongoing",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
+ case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
+ DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation has already been completed since the last stop or clear",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ default:
+ WARN("Failed to start a rotation of session `%s` on behalf of trigger `%s`: %s",
+ session_name, get_trigger_name(work_item->trigger),
+ lttng_strerror(-cmd_ret));
+ break;
+ }
+
+error_dispose_session:
+ session_unlock(session);
+ session_put(session);
+error_unlock_list:
session_unlock_list();
end:
return ret;
};
const struct lttng_snapshot_output *snapshot_output =
&default_snapshot_output;
+ enum lttng_error_code cmd_ret;
action_status = lttng_action_snapshot_session_get_session_name(
action, &session_name);
if (action_status != LTTNG_ACTION_STATUS_OK) {
- ERR("Failed to get session name from \"%s\" action",
+ ERR("Failed to get session name from `%s` action",
get_action_name(action));
ret = -1;
goto end;
action, &snapshot_output);
if (action_status != LTTNG_ACTION_STATUS_OK &&
action_status != LTTNG_ACTION_STATUS_UNSET) {
- ERR("Failed to get output from \"%s\" action",
+ ERR("Failed to get output from `%s` action",
get_action_name(action));
ret = -1;
goto end;
session_lock_list();
session = session_find_by_name(session_name);
- if (session) {
- enum lttng_error_code cmd_ret;
-
- session_lock(session);
- cmd_ret = cmd_snapshot_record(session, snapshot_output, 0);
- session_unlock(session);
-
- switch (cmd_ret) {
- case LTTNG_OK:
- DBG("Successfully recorded snapshot of session \"%s\" on behalf of trigger \"%p\"",
- session_name,
- work_item->trigger);
- break;
- default:
- WARN("Failed to record snapshot of session \"%s\" on behalf of trigger \"%p\": %s",
- session_name,
- work_item->trigger,
- lttng_strerror(-cmd_ret));
- break;
- }
- session_put(session);
- } else {
- DBG("Failed to find session \"%s\" by name while executing \"%s\" action of trigger \"%p\"",
+ if (!session) {
+ DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
- work_item->trigger);
+ get_trigger_name(work_item->trigger));
+ goto error_unlock_list;
+ }
+
+
+ session_lock(session);
+ if (!is_trigger_allowed_for_session(work_item->trigger, session)) {
+ goto error_dispose_session;
+ }
+
+ cmd_ret = cmd_snapshot_record(session, snapshot_output, 0);
+ switch (cmd_ret) {
+ case LTTNG_OK:
+ DBG("Successfully recorded snapshot of session `%s` on behalf of trigger `%s`",
+ session_name, get_trigger_name(work_item->trigger));
+ break;
+ default:
+ WARN("Failed to record snapshot of session `%s` on behalf of trigger `%s`: %s",
+ session_name, get_trigger_name(work_item->trigger),
+ lttng_strerror(-cmd_ret));
+ break;
}
+
+error_dispose_session:
+ session_unlock(session);
+ session_put(session);
+error_unlock_list:
session_unlock_list();
end:
return ret;
ret = action_executor_generic_handler(
executor, work_item, action);
if (ret) {
- ERR("Stopping the execution of the action group of trigger \"%p\" following a fatal error",
- work_item->trigger);
+ ERR("Stopping the execution of the action group of trigger `%s` following a fatal error",
+ get_trigger_name(work_item->trigger));
goto end;
}
}
const struct action_work_item *work_item,
const struct lttng_action *action)
{
- DBG("Executing action \"%s\" of trigger \"%p\" action work item %" PRIu64,
+ const enum lttng_action_type action_type = lttng_action_get_type(action);
+
+ assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
+
+ DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64,
get_action_name(action),
- work_item->trigger,
+ get_trigger_name(work_item->trigger),
work_item->id);
- return action_executors[lttng_action_get_type_const(action)](
+ return action_executors[action_type](
executor, work_item, action);
}
const struct lttng_action *action =
lttng_trigger_get_const_action(work_item->trigger);
- DBG("Starting execution of action work item %" PRIu64 " of trigger \"%p\"",
- work_item->id, work_item->trigger);
+ DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`",
+ work_item->id, get_trigger_name(work_item->trigger));
ret = action_executor_generic_handler(executor, work_item, action);
- DBG("Completed execution of action work item %" PRIu64 " of trigger \"%p\"",
- work_item->id, work_item->trigger);
+ DBG("Completed execution of action work item %" PRIu64 " of trigger `%s`",
+ work_item->id, get_trigger_name(work_item->trigger));
return ret;
}
continue;
}
- /* Pop item from front of the listwith work lock held. */
+ /* Pop item from front of the list with work lock held. */
work_item = cds_list_first_entry(&executor->work.list,
struct action_work_item, list_node);
cds_list_del(&work_item->list_node);
pthread_mutex_lock(&executor->work.lock);
}
- pthread_mutex_unlock(&executor->work.lock);
+ if (executor->should_quit) {
+ pthread_mutex_unlock(&executor->work.lock);
+ }
DBG("Left work execution loop");
health_code_update();
{
struct action_executor *executor = _data;
+ pthread_mutex_lock(&executor->work.lock);
executor->should_quit = true;
pthread_cond_signal(&executor->work.cond);
+ pthread_mutex_unlock(&executor->work.lock);
return true;
}
cds_list_for_each_entry_safe (
work_item, tmp, &executor->work.list, list_node) {
WARN("Discarding action work item %" PRIu64
- " associated to trigger \"%p\"",
- work_item->id, work_item->trigger);
+ " associated to trigger `%s`",
+ work_item->id, get_trigger_name(work_item->trigger));
cds_list_del(&work_item->list_node);
action_work_item_destroy(work_item);
}
/* Check for queue overflow. */
if (executor->work.pending_count >= MAX_QUEUED_WORK_COUNT) {
/* Most likely spammy, remove if it is the case. */
- DBG("Refusing to enqueue action for trigger \"%p\" as work item %" PRIu64
- " (overflow)",
- trigger, work_item_id);
+ DBG("Refusing to enqueue action for trigger `%s` as work item %" PRIu64
+ " (overflow)", get_trigger_name(trigger), work_item_id);
executor_status = ACTION_EXECUTOR_STATUS_OVERFLOW;
goto error_unlock;
}
work_item = zmalloc(sizeof(*work_item));
if (!work_item) {
- PERROR("Failed to allocate action executor work item on behalf of trigger \"%p\"",
- trigger);
+ PERROR("Failed to allocate action executor work item on behalf of trigger `%s`",
+ get_trigger_name(trigger));
executor_status = ACTION_EXECUTOR_STATUS_ERROR;
goto error_unlock;
}
evaluation = NULL;
cds_list_add_tail(&work_item->list_node, &executor->work.list);
executor->work.pending_count++;
- DBG("Enqueued action for trigger \"%p\" as work item %" PRIu64,
- trigger, work_item_id);
+ DBG("Enqueued action for trigger `%s` as work item #%" PRIu64,
+ get_trigger_name(trigger), work_item_id);
signal = true;
error_unlock:
- pthread_mutex_unlock(&executor->work.lock);
if (signal) {
pthread_cond_signal(&executor->work.cond);
}
+ pthread_mutex_unlock(&executor->work.lock);
lttng_evaluation_destroy(evaluation);
return executor_status;