From: Jonathan Rajotte Date: Thu, 23 Jan 2020 19:13:11 +0000 (-0500) Subject: trigger: implement listing of registered trigger X-Git-Tag: v2.13.0-rc1~415 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=fbc9f37df245d544a7705ba576297df791220b44;hp=f8522f5cc357c0d80257d5ace1cd556a88305c0c trigger: implement listing of registered trigger Each client have visibility over triggers matching its user id (uid). The root user have visibility over all registered triggers. Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau Change-Id: I3e5ae75939214ed85c376bea12f1e4b307d78976 --- diff --git a/include/lttng/trigger/trigger.h b/include/lttng/trigger/trigger.h index a0c312ddd..b36ee13a2 100644 --- a/include/lttng/trigger/trigger.h +++ b/include/lttng/trigger/trigger.h @@ -187,6 +187,19 @@ extern int lttng_register_trigger(struct lttng_trigger *trigger); */ extern int lttng_unregister_trigger(struct lttng_trigger *trigger); +/* + * List triggers for the current user. + * + * On success, a newly-allocated trigger set is returned. + * + * The trigger set must be destroyed by the caller (see + * lttng_triggers_destroy()). + * + * Returns LTTNG_OK on success, else a suitable LTTng error code. + */ +extern enum lttng_error_code lttng_list_triggers( + struct lttng_triggers **triggers); + /* * Get a trigger from the set at a given index. * diff --git a/src/bin/lttng-sessiond/client.c b/src/bin/lttng-sessiond/client.c index ecd31ea48..faf5d579f 100644 --- a/src/bin/lttng-sessiond/client.c +++ b/src/bin/lttng-sessiond/client.c @@ -801,6 +801,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_ROTATION_SET_SCHEDULE: case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: case LTTNG_CLEAR_SESSION: + case LTTNG_LIST_TRIGGERS: need_domain = 0; break; default: @@ -847,6 +848,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_DATA_PENDING: case LTTNG_ROTATE_SESSION: case LTTNG_ROTATION_GET_INFO: + case LTTNG_LIST_TRIGGERS: break; default: /* Setup lttng message with no payload */ @@ -867,6 +869,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int *sock, case LTTNG_SAVE_SESSION: case LTTNG_REGISTER_TRIGGER: case LTTNG_UNREGISTER_TRIGGER: + case LTTNG_LIST_TRIGGERS: need_tracing_session = 0; break; default: @@ -2185,6 +2188,44 @@ error_add_context: ret = cmd_clear_session(cmd_ctx->session, sock); break; } + case LTTNG_LIST_TRIGGERS: + { + struct lttng_triggers *return_triggers = NULL; + size_t original_payload_size; + size_t payload_size; + + ret = setup_empty_lttng_msg(cmd_ctx); + if (ret) { + ret = LTTNG_ERR_NOMEM; + goto setup_error; + } + + original_payload_size = cmd_ctx->reply_payload.buffer.size; + + ret = cmd_list_triggers(cmd_ctx, + notification_thread_handle, &return_triggers); + if (ret != LTTNG_OK) { + goto error; + } + + assert(return_triggers); + ret = lttng_triggers_serialize( + return_triggers, &cmd_ctx->reply_payload); + lttng_triggers_destroy(return_triggers); + if (ret) { + ERR("Failed to serialize triggers in reply to `list triggers` command"); + ret = LTTNG_ERR_NOMEM; + goto error; + } + + payload_size = cmd_ctx->reply_payload.buffer.size - + original_payload_size; + + update_lttng_msg(cmd_ctx, 0, payload_size); + + ret = LTTNG_OK; + break; + } default: ret = LTTNG_ERR_UND; break; diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 39e824bde..2f5a4e98c 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -4450,6 +4450,29 @@ end: return ret; } +int cmd_list_triggers(struct command_ctx *cmd_ctx, + struct notification_thread_handle *notification_thread, + struct lttng_triggers **return_triggers) +{ + int ret = 0; + enum lttng_error_code ret_code; + struct lttng_triggers *triggers = NULL; + + /* Get the set of triggers from the notification thread. */ + ret_code = notification_thread_command_list_triggers( + notification_thread, cmd_ctx->creds.uid, &triggers); + if (ret_code != LTTNG_OK) { + ret = ret_code; + goto end; + } + + *return_triggers = triggers; + triggers = NULL; + ret = LTTNG_OK; +end: + lttng_triggers_destroy(triggers); + return ret; +} /* * Send relayd sockets from snapshot output to consumer. Ignore request if the * snapshot output is *not* set with a remote destination. diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index eebb5a317..d376aee1e 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -147,6 +147,10 @@ int cmd_register_trigger(struct command_ctx *cmd_ctx, int sock, int cmd_unregister_trigger(struct command_ctx *cmd_ctx, int sock, struct notification_thread_handle *notification_thread_handle); +int cmd_list_triggers(struct command_ctx *cmd_ctx, + struct notification_thread_handle *notification_thread_handle, + struct lttng_triggers **return_triggers); + int cmd_rotate_session(struct ltt_session *session, struct lttng_rotate_session_return *rotate_return, bool quiet_rotation, diff --git a/src/bin/lttng-sessiond/notification-thread-commands.c b/src/bin/lttng-sessiond/notification-thread-commands.c index 28ed0b339..a434b08cf 100644 --- a/src/bin/lttng-sessiond/notification-thread-commands.c +++ b/src/bin/lttng-sessiond/notification-thread-commands.c @@ -270,6 +270,36 @@ end: return ret_code; } +enum lttng_error_code notification_thread_command_list_triggers( + struct notification_thread_handle *handle, + uid_t uid, + struct lttng_triggers **triggers) +{ + int ret; + enum lttng_error_code ret_code; + struct notification_thread_command cmd = {}; + + assert(handle); + assert(triggers); + + init_notification_thread_command(&cmd); + + cmd.type = NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS; + cmd.parameters.list_triggers.uid = uid; + + ret = run_command_wait(handle, &cmd); + if (ret) { + ret_code = LTTNG_ERR_UNK; + goto end; + } + + ret_code = cmd.reply_code; + *triggers = cmd.reply.list_triggers.triggers; + +end: + return ret_code; +} + void notification_thread_command_quit( struct notification_thread_handle *handle) { diff --git a/src/bin/lttng-sessiond/notification-thread-commands.h b/src/bin/lttng-sessiond/notification-thread-commands.h index c09ebea46..3f883bf20 100644 --- a/src/bin/lttng-sessiond/notification-thread-commands.h +++ b/src/bin/lttng-sessiond/notification-thread-commands.h @@ -27,6 +27,7 @@ enum notification_thread_command_type { NOTIFICATION_COMMAND_TYPE_REMOVE_CHANNEL, NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_ONGOING, NOTIFICATION_COMMAND_TYPE_SESSION_ROTATION_COMPLETED, + NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS, NOTIFICATION_COMMAND_TYPE_QUIT, NOTIFICATION_COMMAND_TYPE_CLIENT_COMMUNICATION_UPDATE, }; @@ -64,6 +65,11 @@ struct notification_thread_command { uint64_t trace_archive_chunk_id; struct lttng_trace_archive_location *location; } session_rotation; + /* List triggers. */ + struct { + /* Credentials of the requesting user. */ + uid_t uid; + } list_triggers; /* Client communication update. */ struct { notification_client_id id; @@ -72,6 +78,11 @@ struct notification_thread_command { } parameters; + union { + struct { + struct lttng_triggers *triggers; + } list_triggers; + } reply; /* lttng_waiter on which to wait for command reply (optional). */ struct lttng_waiter reply_waiter; enum lttng_error_code reply_code; @@ -108,6 +119,24 @@ enum lttng_error_code notification_thread_command_session_rotation_completed( uint64_t trace_archive_chunk_id, struct lttng_trace_archive_location *location); +/* + * Return the set of triggers visible to a given client. + * + * The trigger objects contained in the set are the actual trigger instances + * used by the notification subsystem (i.e. not a copy). Given that the command + * is only used to serialize the triggers, this is fine: the properties that + * are serialized are immutable over the lifetime of the triggers. + * + * Moreover, the lifetime of the trigger instances is protected through + * reference counting (references are held by the trigger set). + * + * The caller has the exclusive ownership of the returned trigger set. + */ +enum lttng_error_code notification_thread_command_list_triggers( + struct notification_thread_handle *handle, + uid_t client_uid, + struct lttng_triggers **triggers); + void notification_thread_command_quit( struct notification_thread_handle *handle); diff --git a/src/bin/lttng-sessiond/notification-thread-events.c b/src/bin/lttng-sessiond/notification-thread-events.c index 404503042..c318f833c 100644 --- a/src/bin/lttng-sessiond/notification-thread-events.c +++ b/src/bin/lttng-sessiond/notification-thread-events.c @@ -1984,6 +1984,61 @@ end: return ret; } +static int handle_notification_thread_command_list_triggers( + struct notification_thread_handle *handle, + struct notification_thread_state *state, + uid_t client_uid, + struct lttng_triggers **triggers, + enum lttng_error_code *_cmd_result) +{ + int ret = 0; + enum lttng_error_code cmd_result = LTTNG_OK; + struct cds_lfht_iter iter; + struct lttng_trigger_ht_element *trigger_ht_element; + struct lttng_triggers *local_triggers = NULL; + const struct lttng_credentials *creds; + + rcu_read_lock(); + + local_triggers = lttng_triggers_create(); + if (!local_triggers) { + /* Not a fatal error. */ + cmd_result = LTTNG_ERR_NOMEM; + goto end; + } + + cds_lfht_for_each_entry(state->triggers_ht, &iter, + trigger_ht_element, node) { + /* + * Only return the triggers to which the client has access. + * The root user has visibility over all triggers. + */ + creds = lttng_trigger_get_credentials(trigger_ht_element->trigger); + if (client_uid != lttng_credentials_get_uid(creds) && client_uid != 0) { + continue; + } + + ret = lttng_triggers_add(local_triggers, + trigger_ht_element->trigger); + if (ret < 0) { + /* Not a fatal error. */ + ret = 0; + cmd_result = LTTNG_ERR_NOMEM; + goto end; + } + } + + /* Transferring ownership to the caller. */ + *triggers = local_triggers; + local_triggers = NULL; + +end: + rcu_read_unlock(); + lttng_triggers_destroy(local_triggers); + *_cmd_result = cmd_result; + return ret; +} + static int condition_is_supported(struct lttng_condition *condition) { @@ -2658,6 +2713,20 @@ int handle_notification_thread_command( cmd->parameters.session_rotation.location, &cmd->reply_code); break; + case NOTIFICATION_COMMAND_TYPE_LIST_TRIGGERS: + { + struct lttng_triggers *triggers = NULL; + + ret = handle_notification_thread_command_list_triggers( + handle, + state, + cmd->parameters.list_triggers.uid, + &triggers, + &cmd->reply_code); + cmd->reply.list_triggers.triggers = triggers; + ret = 0; + break; + } case NOTIFICATION_COMMAND_TYPE_QUIT: DBG("[notification-thread] Received quit command"); cmd->reply_code = LTTNG_OK; diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index fca331fe7..d1a2bd97d 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -106,6 +106,7 @@ enum lttcomm_sessiond_command { LTTNG_SESSION_LIST_ROTATION_SCHEDULES = 48, LTTNG_CREATE_SESSION_EXT = 49, LTTNG_CLEAR_SESSION = 50, + LTTNG_LIST_TRIGGERS = 51, }; enum lttcomm_relayd_command { diff --git a/src/lib/lttng-ctl/lttng-ctl.c b/src/lib/lttng-ctl/lttng-ctl.c index 1c51eedc7..91d6109e5 100644 --- a/src/lib/lttng-ctl/lttng-ctl.c +++ b/src/lib/lttng-ctl/lttng-ctl.c @@ -3173,6 +3173,52 @@ end: return ret; } +/* + * Ask the session daemon for all registered triggers for the current user. + * + * Allocates and return an lttng_triggers set. + * On error, returns a suitable lttng_error_code. + */ +enum lttng_error_code lttng_list_triggers(struct lttng_triggers **triggers) +{ + int ret; + enum lttng_error_code ret_code = LTTNG_OK; + struct lttcomm_session_msg lsm = { .cmd_type = LTTNG_LIST_TRIGGERS }; + struct lttng_triggers *local_triggers = NULL; + struct lttng_payload reply; + struct lttng_payload_view lsm_view = + lttng_payload_view_init_from_buffer( + (const char *) &lsm, 0, sizeof(lsm)); + + lttng_payload_init(&reply); + + ret = lttng_ctl_ask_sessiond_payload(&lsm_view, &reply); + if (ret < 0) { + ret_code = (enum lttng_error_code) -ret; + goto end; + } + + { + struct lttng_payload_view reply_view = + lttng_payload_view_from_payload( + &reply, 0, reply.buffer.size); + + ret = lttng_triggers_create_from_payload( + &reply_view, &local_triggers); + if (ret < 0) { + ret_code = LTTNG_ERR_FATAL; + goto end; + } + } + + *triggers = local_triggers; + local_triggers = NULL; +end: + lttng_payload_reset(&reply); + lttng_triggers_destroy(local_triggers); + return ret_code; +} + /* * lib constructor. */