+ ret = lttng_ctl_ask_sessiond(&lsm, NULL);
+ if (ret < 0) {
+ goto end;
+ }
+
+ ret = 0;
+end:
+ return ret;
+}
+
+int lttng_register_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ struct lttcomm_session_msg lsm = {
+ .cmd_type = LTTNG_REGISTER_TRIGGER,
+ };
+ struct lttcomm_session_msg *message_lsm;
+ struct lttng_payload message;
+ struct lttng_payload reply;
+ struct lttng_trigger *reply_trigger = NULL;
+ enum lttng_domain_type domain_type;
+ struct lttng_credentials creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(geteuid()),
+ .gid = LTTNG_OPTIONAL_INIT_UNSET,
+ };
+
+
+ lttng_payload_init(&message);
+ lttng_payload_init(&reply);
+
+ if (!trigger) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!trigger->creds.uid.is_set) {
+ /* Use the client credentials as the trigger credentials */
+ lttng_trigger_set_credentials(trigger, &creds);
+ } else {
+ /*
+ * Validate that either the current trigger credentials and the
+ * client credentials are identical or that the current user is
+ * root. The root user can register, unregister triggers for
+ * himself and other users.
+ * This check is also present on the sessiond side, using the
+ * credentials passed on the socket. These check are all
+ * "safety" checks.
+ */
+ const struct lttng_credentials *trigger_creds =
+ lttng_trigger_get_credentials(trigger);
+ if (!lttng_credentials_is_equal_uid(trigger_creds, &creds)) {
+ if (lttng_credentials_get_uid(&creds) != 0) {
+ ret = -LTTNG_ERR_EPERM;
+ goto end;
+ }
+ }
+ }
+
+ if (!lttng_trigger_validate(trigger)) {
+ ret = -LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ domain_type = lttng_trigger_get_underlying_domain_type_restriction(
+ trigger);
+
+ lsm.domain.type = domain_type;
+
+ ret = lttng_dynamic_buffer_append(&message.buffer, &lsm, sizeof(lsm));
+ if (ret) {
+ ret = -LTTNG_ERR_NOMEM;
+ goto end;
+ }
+
+ /*
+ * This is needed to populate the trigger object size for the command
+ * header.
+ */
+ message_lsm = (struct lttcomm_session_msg *) message.buffer.data;
+
+ ret = lttng_trigger_serialize(trigger, &message);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ message_lsm->u.trigger.length = (uint32_t) message.buffer.size - sizeof(lsm);
+
+ if (getenv("LTTNG_REGISTER_TRIGGER_DRY_RUN")) {
+ /*
+ * Don't really send the request, just deserialize, validate
+ * that it is equal to the original trigger (to test
+ * serialization and deserialization), and return.
+ */
+ ssize_t sz;
+
+ struct lttng_payload_view pv = lttng_payload_view_from_payload(
+ &message, sizeof(lsm), -1);
+ sz = lttng_trigger_create_from_payload(&pv, &reply_trigger);
+ if (sz != pv.buffer.size - sizeof(lsm)) {
+ ret = -LTTNG_ERR_UNK;