+int lttng_register_trigger(struct lttng_trigger *trigger)
+{
+ int ret;
+ int reply_ret;
+ struct lttcomm_session_msg lsm;
+ struct lttng_dynamic_buffer buffer;
+ void *reply = NULL;
+ struct lttng_buffer_view reply_view;
+ struct lttng_trigger *reply_trigger = NULL;
+ bool send_fd = false;
+ int fd_to_send;
+ enum lttng_domain_type domain_type;
+
+ lttng_dynamic_buffer_init(&buffer);
+ if (!trigger) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!lttng_trigger_validate(trigger)) {
+ ret = -LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ domain_type = lttng_trigger_get_underlying_domain_type_restriction(
+ trigger);
+
+ ret = lttng_trigger_serialize(trigger, &buffer, &fd_to_send);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ 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.
+ */
+ struct lttng_buffer_view bv;
+ ssize_t sz;
+
+ bv = lttng_buffer_view_from_dynamic_buffer(&buffer, 0, -1);
+ sz = lttng_trigger_create_from_buffer(&bv, &reply_trigger);
+ if (sz != bv.size) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ if (!reply_trigger) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ if (!lttng_trigger_is_equal(trigger, reply_trigger)) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ /* Give it a dummy name. */
+ lttng_trigger_set_name(trigger, "yop");
+
+ ret = 0;
+ goto end;
+ }
+
+ send_fd = fd_to_send >= 0;
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_REGISTER_TRIGGER;
+ lsm.domain.type = domain_type;
+ lsm.u.trigger.length = (uint32_t) buffer.size;
+ reply_ret = lttng_ctl_ask_sessiond_fds_varlen_no_cmd_header(&lsm,
+ send_fd ? &fd_to_send : NULL,
+ send_fd ? 1 : 0,
+ buffer.data,
+ buffer.size,
+ &reply);
+ if (reply_ret < 0) {
+ ret = reply_ret;
+ goto end;
+ } else if (reply_ret == 0) {
+ /* Socket unexpectedly closed by the session daemon. */
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ reply_view = lttng_buffer_view_init(reply, 0, reply_ret);
+ ret = lttng_trigger_create_from_buffer(&reply_view, &reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ ret = lttng_trigger_assign(trigger, reply_trigger);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ ret = 0;
+end:
+ free(reply);
+ lttng_dynamic_buffer_reset(&buffer);
+ lttng_trigger_destroy(reply_trigger);
+ return ret;
+}
+
+int lttng_unregister_trigger(const struct lttng_trigger *trigger)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ struct lttng_dynamic_buffer buffer;
+
+ lttng_dynamic_buffer_init(&buffer);
+ if (!trigger) {
+ ret = -LTTNG_ERR_INVALID;
+ goto end;
+ }
+
+ if (!lttng_trigger_validate(trigger)) {
+ ret = -LTTNG_ERR_INVALID_TRIGGER;
+ goto end;
+ }
+
+ ret = lttng_trigger_serialize(trigger, &buffer, NULL);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_UNK;
+ goto end;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_UNREGISTER_TRIGGER;
+ lsm.u.trigger.length = (uint32_t) buffer.size;
+ ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(&lsm, buffer.data,
+ buffer.size, NULL);
+end:
+ lttng_dynamic_buffer_reset(&buffer);
+ return ret;
+}
+
+/*
+ * Ask the session daemon for all registered triggers.
+ * Allocate a lttng_triggers collection.
+ * On error, returns a negative value.
+ */
+int lttng_list_triggers(struct lttng_triggers **triggers)
+{
+ int ret;
+ int reply_ret;
+ struct lttcomm_session_msg lsm;
+ struct lttng_buffer_view reply_view;
+ struct lttng_triggers *local_triggers = NULL;
+ void *reply = NULL;
+
+ memset(&lsm, 0, sizeof(lsm));
+ lsm.cmd_type = LTTNG_LIST_TRIGGERS;
+
+ reply_ret = lttng_ctl_ask_sessiond(&lsm, &reply);
+ if (reply_ret < 0) {
+ ret = reply_ret;
+ goto end;
+ } else if (reply_ret == 0) {
+ /* Socket unexpectedly closed by the session daemon. */
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ reply_view = lttng_buffer_view_init(reply, 0, reply_ret);
+ ret = lttng_triggers_create_from_buffer(&reply_view, &local_triggers);
+ if (ret < 0) {
+ ret = -LTTNG_ERR_FATAL;
+ goto end;
+ }
+
+ *triggers = local_triggers;
+ local_triggers = NULL;
+ ret = 0;
+end:
+ free(reply);
+ free(local_triggers);
+ return ret;
+}
+
+static int lttng_track_untrack_id(struct lttng_handle *handle,
+ enum lttng_tracker_type tracker_type,
+ const struct lttng_tracker_id *id,
+ enum lttcomm_sessiond_command cmd)
+{
+ int ret;
+ struct lttcomm_session_msg lsm;
+ const char *var_data = NULL;
+ size_t var_data_len = 0;
+ int value;
+ enum lttng_tracker_id_status status;
+
+ /* NULL arguments are forbidden. No default values. */
+ if (handle == NULL) {
+ goto error;
+ }
+
+ memset(&lsm, 0, sizeof(lsm));
+
+ lsm.cmd_type = cmd;
+ lsm.u.id_tracker.tracker_type = tracker_type;
+ lsm.u.id_tracker.id_type = lttng_tracker_id_get_type(id);
+ switch (lsm.u.id_tracker.id_type) {
+ case LTTNG_ID_ALL:
+ break;
+ case LTTNG_ID_VALUE:
+ status = lttng_tracker_id_get_value(id, &value);
+ if (status != LTTNG_TRACKER_ID_STATUS_OK) {
+ goto error;
+ }
+ lsm.u.id_tracker.u.value = value;
+ break;
+ case LTTNG_ID_STRING:
+ status = lttng_tracker_id_get_string(id, &var_data);
+ if (status != LTTNG_TRACKER_ID_STATUS_OK) {
+ goto error;
+ }
+ var_data_len = strlen(var_data) + 1; /* Includes \0. */
+ lsm.u.id_tracker.u.var_len = var_data_len;
+ break;
+ default:
+ goto error;
+ }
+
+ COPY_DOMAIN_PACKED(lsm.domain, handle->domain);
+
+ lttng_ctl_copy_string(lsm.session.name, handle->session_name,
+ sizeof(lsm.session.name));
+
+ ret = lttng_ctl_ask_sessiond_varlen_no_cmd_header(
+ &lsm, (char *) var_data, var_data_len, NULL);
+ return ret;
+error:
+ return -LTTNG_ERR_INVALID;
+}
+
+/*
+ * Add ID to session tracker.
+ * Return 0 on success else a negative LTTng error code.
+ */
+int lttng_track_id(struct lttng_handle *handle,
+ enum lttng_tracker_type tracker_type,
+ const struct lttng_tracker_id *id)
+{
+ return lttng_track_untrack_id(handle, tracker_type, id, LTTNG_TRACK_ID);
+}
+
+/*
+ * Remove ID from session tracker.
+ * Return 0 on success else a negative LTTng error code.
+ */
+int lttng_untrack_id(struct lttng_handle *handle,
+ enum lttng_tracker_type tracker_type,
+ const struct lttng_tracker_id *id)
+{
+ return lttng_track_untrack_id(
+ handle, tracker_type, id, LTTNG_UNTRACK_ID);
+}
+
+/*
+ * Add PID to session tracker.
+ * Return 0 on success else a negative LTTng error code.
+ */
+int lttng_track_pid(struct lttng_handle *handle, int pid)
+{
+ int ret;
+ struct lttng_tracker_id *id = NULL;
+ enum lttng_tracker_id_status status;
+
+ id = lttng_tracker_id_create();
+ status = lttng_tracker_id_set_value(id, pid);
+ if (status == LTTNG_TRACKER_ID_STATUS_INVALID) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ ret = lttng_track_id(handle, LTTNG_TRACKER_PID, id);
+error:
+ lttng_tracker_id_destroy(id);
+ return ret;
+}
+
+/*
+ * Remove PID from session tracker.
+ * Return 0 on success else a negative LTTng error code.
+ */
+int lttng_untrack_pid(struct lttng_handle *handle, int pid)
+{
+ int ret;
+ struct lttng_tracker_id *id = NULL;
+ enum lttng_tracker_id_status status;
+
+ id = lttng_tracker_id_create();
+ status = lttng_tracker_id_set_value(id, pid);
+ if (status == LTTNG_TRACKER_ID_STATUS_INVALID) {
+ ret = -LTTNG_ERR_INVALID;
+ goto error;
+ }
+
+ ret = lttng_untrack_id(handle, LTTNG_TRACKER_PID, id);
+error:
+ lttng_tracker_id_destroy(id);
+ return ret;
+}
+