2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
4 * SPDX-License-Identifier: LGPL-2.1-only
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/action/action-internal.h>
11 #include <common/credentials.h>
12 #include <common/payload.h>
13 #include <common/payload-view.h>
14 #include <common/error.h>
15 #include <common/dynamic-array.h>
16 #include <common/optional.h>
21 bool lttng_trigger_validate(struct lttng_trigger
*trigger
)
30 if (!trigger
->creds
.uid
.is_set
) {
35 valid
= lttng_condition_validate(trigger
->condition
) &&
36 lttng_action_validate(trigger
->action
);
41 struct lttng_trigger
*lttng_trigger_create(
42 struct lttng_condition
*condition
,
43 struct lttng_action
*action
)
45 struct lttng_trigger
*trigger
= NULL
;
47 if (!condition
|| !action
) {
51 trigger
= zmalloc(sizeof(struct lttng_trigger
));
56 urcu_ref_init(&trigger
->ref
);
58 lttng_condition_get(condition
);
59 trigger
->condition
= condition
;
61 lttng_action_get(action
);
62 trigger
->action
= action
;
69 * Note: the lack of reference counting 'get' on the condition object is normal.
70 * This API was exposed as such in 2.11. The client is not expected to call
71 * lttng_condition_destroy on the returned object.
73 struct lttng_condition
*lttng_trigger_get_condition(
74 struct lttng_trigger
*trigger
)
76 return trigger
? trigger
->condition
: NULL
;
80 const struct lttng_condition
*lttng_trigger_get_const_condition(
81 const struct lttng_trigger
*trigger
)
83 return trigger
->condition
;
88 * Note: the lack of reference counting 'get' on the action object is normal.
89 * This API was exposed as such in 2.11. The client is not expected to call
90 * lttng_action_destroy on the returned object.
92 struct lttng_action
*lttng_trigger_get_action(
93 struct lttng_trigger
*trigger
)
95 return trigger
? trigger
->action
: NULL
;
99 const struct lttng_action
*lttng_trigger_get_const_action(
100 const struct lttng_trigger
*trigger
)
102 return trigger
->action
;
105 static void trigger_destroy_ref(struct urcu_ref
*ref
)
107 struct lttng_trigger
*trigger
=
108 container_of(ref
, struct lttng_trigger
, ref
);
109 struct lttng_action
*action
= lttng_trigger_get_action(trigger
);
110 struct lttng_condition
*condition
=
111 lttng_trigger_get_condition(trigger
);
116 /* Release ownership. */
117 lttng_action_put(action
);
118 lttng_condition_put(condition
);
124 void lttng_trigger_destroy(struct lttng_trigger
*trigger
)
126 lttng_trigger_put(trigger
);
130 ssize_t
lttng_trigger_create_from_payload(
131 struct lttng_payload_view
*src_view
,
132 struct lttng_trigger
**_trigger
)
134 ssize_t ret
, offset
= 0, condition_size
, action_size
, name_size
= 0;
135 struct lttng_condition
*condition
= NULL
;
136 struct lttng_action
*action
= NULL
;
137 const struct lttng_trigger_comm
*trigger_comm
;
138 const char *name
= NULL
;
139 struct lttng_credentials creds
= {
140 .uid
= LTTNG_OPTIONAL_INIT_UNSET
,
141 .gid
= LTTNG_OPTIONAL_INIT_UNSET
,
143 struct lttng_trigger
*trigger
= NULL
;
144 const struct lttng_payload_view trigger_comm_view
=
145 lttng_payload_view_from_view(
146 src_view
, 0, sizeof(*trigger_comm
));
148 if (!src_view
|| !_trigger
) {
153 if (!lttng_payload_view_is_valid(&trigger_comm_view
)) {
154 /* Payload not large enough to contain the header. */
159 /* lttng_trigger_comm header */
160 trigger_comm
= (typeof(trigger_comm
)) trigger_comm_view
.buffer
.data
;
162 /* Set the trigger's creds. */
163 if (trigger_comm
->uid
> (uint64_t) ((uid_t
) -1)) {
164 /* UID out of range for this platform. */
169 LTTNG_OPTIONAL_SET(&creds
.uid
, trigger_comm
->uid
);
171 offset
+= sizeof(*trigger_comm
);
173 if (trigger_comm
->name_length
!= 0) {
175 const struct lttng_payload_view name_view
=
176 lttng_payload_view_from_view(
178 trigger_comm
->name_length
);
180 if (!lttng_payload_view_is_valid(&name_view
)) {
185 name
= name_view
.buffer
.data
;
186 if (!lttng_buffer_view_contains_string(&name_view
.buffer
, name
,
187 trigger_comm
->name_length
)) {
192 offset
+= trigger_comm
->name_length
;
193 name_size
= trigger_comm
->name_length
;
197 /* struct lttng_condition */
198 struct lttng_payload_view condition_view
=
199 lttng_payload_view_from_view(
200 src_view
, offset
, -1);
202 condition_size
= lttng_condition_create_from_payload(&condition_view
,
206 if (condition_size
< 0) {
207 ret
= condition_size
;
211 offset
+= condition_size
;
213 /* struct lttng_action */
214 struct lttng_payload_view action_view
=
215 lttng_payload_view_from_view(
216 src_view
, offset
, -1);
218 action_size
= lttng_action_create_from_payload(&action_view
, &action
);
221 if (action_size
< 0) {
225 offset
+= action_size
;
227 /* Unexpected size of inner-elements; the buffer is corrupted. */
228 if ((ssize_t
) trigger_comm
->length
!= condition_size
+ action_size
+ name_size
) {
233 trigger
= lttng_trigger_create(condition
, action
);
239 lttng_trigger_set_credentials(trigger
, &creds
);
242 * The trigger object owns references to the action and condition
245 lttng_condition_put(condition
);
248 lttng_action_put(action
);
252 const enum lttng_trigger_status status
=
253 lttng_trigger_set_name(trigger
, name
);
255 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
264 lttng_condition_put(condition
);
265 lttng_action_put(action
);
270 lttng_trigger_put(trigger
);
277 * Both elements are stored contiguously, see their "*_comm" structure
278 * for the detailed format.
281 int lttng_trigger_serialize(const struct lttng_trigger
*trigger
,
282 struct lttng_payload
*payload
)
285 size_t header_offset
, size_before_payload
, size_name
;
286 struct lttng_trigger_comm trigger_comm
= {};
287 struct lttng_trigger_comm
*header
;
288 const struct lttng_credentials
*creds
= NULL
;
290 creds
= lttng_trigger_get_credentials(trigger
);
293 trigger_comm
.uid
= LTTNG_OPTIONAL_GET(creds
->uid
);
295 if (trigger
->name
!= NULL
) {
296 size_name
= strlen(trigger
->name
) + 1;
301 trigger_comm
.name_length
= size_name
;
303 header_offset
= payload
->buffer
.size
;
304 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &trigger_comm
,
305 sizeof(trigger_comm
));
310 size_before_payload
= payload
->buffer
.size
;
313 ret
= lttng_dynamic_buffer_append(
314 &payload
->buffer
, trigger
->name
, size_name
);
319 ret
= lttng_condition_serialize(trigger
->condition
, payload
);
324 ret
= lttng_action_serialize(trigger
->action
, payload
);
329 /* Update payload size. */
330 header
= (typeof(header
)) (payload
->buffer
.data
+ header_offset
);
331 header
->length
= payload
->buffer
.size
- size_before_payload
;
337 bool lttng_trigger_is_equal(
338 const struct lttng_trigger
*a
, const struct lttng_trigger
*b
)
341 * Name is not taken into account since it is cosmetic only.
343 if (!lttng_condition_is_equal(a
->condition
, b
->condition
)) {
347 if (!lttng_action_is_equal(a
->action
, b
->action
)) {
351 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a
),
352 lttng_trigger_get_credentials(b
))) {
359 enum lttng_trigger_status
lttng_trigger_set_name(struct lttng_trigger
*trigger
,
362 char *name_copy
= NULL
;
363 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
365 if (!trigger
|| !name
||
367 status
= LTTNG_TRIGGER_STATUS_INVALID
;
371 name_copy
= strdup(name
);
373 status
= LTTNG_TRIGGER_STATUS_ERROR
;
379 trigger
->name
= name_copy
;
385 enum lttng_trigger_status
lttng_trigger_get_name(
386 const struct lttng_trigger
*trigger
, const char **name
)
388 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
390 if (!trigger
|| !name
) {
391 status
= LTTNG_TRIGGER_STATUS_INVALID
;
395 if (!trigger
->name
) {
396 status
= LTTNG_TRIGGER_STATUS_UNSET
;
399 *name
= trigger
->name
;
405 int lttng_trigger_assign_name(struct lttng_trigger
*dst
,
406 const struct lttng_trigger
*src
)
409 enum lttng_trigger_status status
;
411 status
= lttng_trigger_set_name(dst
, src
->name
);
412 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
414 ERR("Failed to set name for trigger");
422 void lttng_trigger_set_tracer_token(struct lttng_trigger
*trigger
,
426 LTTNG_OPTIONAL_SET(&trigger
->tracer_token
, token
);
430 uint64_t lttng_trigger_get_tracer_token(const struct lttng_trigger
*trigger
)
434 return LTTNG_OPTIONAL_GET(trigger
->tracer_token
);
438 int lttng_trigger_generate_name(struct lttng_trigger
*trigger
,
442 char *generated_name
= NULL
;
444 ret
= asprintf(&generated_name
, "T%" PRIu64
"", unique_id
);
446 ERR("Failed to generate trigger name");
453 trigger
->name
= generated_name
;
459 void lttng_trigger_get(struct lttng_trigger
*trigger
)
461 urcu_ref_get(&trigger
->ref
);
465 void lttng_trigger_put(struct lttng_trigger
*trigger
)
471 urcu_ref_put(&trigger
->ref
, trigger_destroy_ref
);
474 static void delete_trigger_array_element(void *ptr
)
476 struct lttng_trigger
*trigger
= ptr
;
478 lttng_trigger_put(trigger
);
482 struct lttng_triggers
*lttng_triggers_create(void)
484 struct lttng_triggers
*triggers
= NULL
;
486 triggers
= zmalloc(sizeof(*triggers
));
491 lttng_dynamic_pointer_array_init(&triggers
->array
, delete_trigger_array_element
);
498 struct lttng_trigger
*lttng_triggers_borrow_mutable_at_index(
499 const struct lttng_triggers
*triggers
, unsigned int index
)
501 struct lttng_trigger
*trigger
= NULL
;
504 if (index
>= lttng_dynamic_pointer_array_get_count(&triggers
->array
)) {
508 trigger
= (struct lttng_trigger
*)
509 lttng_dynamic_pointer_array_get_pointer(
510 &triggers
->array
, index
);
516 int lttng_triggers_add(
517 struct lttng_triggers
*triggers
, struct lttng_trigger
*trigger
)
524 lttng_trigger_get(trigger
);
526 ret
= lttng_dynamic_pointer_array_add_pointer(&triggers
->array
, trigger
);
528 lttng_trigger_put(trigger
);
534 const struct lttng_trigger
*lttng_triggers_get_at_index(
535 const struct lttng_triggers
*triggers
, unsigned int index
)
537 return lttng_triggers_borrow_mutable_at_index(triggers
, index
);
540 enum lttng_trigger_status
lttng_triggers_get_count(const struct lttng_triggers
*triggers
, unsigned int *count
)
542 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
544 if (!triggers
|| !count
) {
545 status
= LTTNG_TRIGGER_STATUS_INVALID
;
549 *count
= lttng_dynamic_pointer_array_get_count(&triggers
->array
);
554 void lttng_triggers_destroy(struct lttng_triggers
*triggers
)
560 lttng_dynamic_pointer_array_reset(&triggers
->array
);
564 int lttng_triggers_serialize(const struct lttng_triggers
*triggers
,
565 struct lttng_payload
*payload
)
568 unsigned int i
, count
;
569 size_t size_before_payload
;
570 struct lttng_triggers_comm triggers_comm
= {};
571 struct lttng_triggers_comm
*header
;
572 enum lttng_trigger_status status
;
573 const size_t header_offset
= payload
->buffer
.size
;
575 status
= lttng_triggers_get_count(triggers
, &count
);
576 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
577 ret
= LTTNG_ERR_INVALID
;
581 triggers_comm
.count
= count
;
583 /* Placeholder header; updated at the end. */
584 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &triggers_comm
,
585 sizeof(triggers_comm
));
590 size_before_payload
= payload
->buffer
.size
;
592 for (i
= 0; i
< count
; i
++) {
593 const struct lttng_trigger
*trigger
=
594 lttng_triggers_get_at_index(triggers
, i
);
598 ret
= lttng_trigger_serialize(trigger
, payload
);
604 /* Update payload size. */
605 header
= (struct lttng_triggers_comm
*) ((char *) payload
->buffer
.data
+ header_offset
);
606 header
->length
= payload
->buffer
.size
- size_before_payload
;
612 ssize_t
lttng_triggers_create_from_payload(
613 struct lttng_payload_view
*src_view
,
614 struct lttng_triggers
**triggers
)
616 ssize_t ret
, offset
= 0, triggers_size
= 0;
618 const struct lttng_triggers_comm
*triggers_comm
;
619 struct lttng_triggers
*local_triggers
= NULL
;
621 if (!src_view
|| !triggers
) {
626 /* lttng_trigger_comms header */
627 triggers_comm
= (const struct lttng_triggers_comm
*) src_view
->buffer
.data
;
628 offset
+= sizeof(*triggers_comm
);
630 local_triggers
= lttng_triggers_create();
631 if (!local_triggers
) {
636 for (i
= 0; i
< triggers_comm
->count
; i
++) {
637 struct lttng_trigger
*trigger
= NULL
;
638 struct lttng_payload_view trigger_view
=
639 lttng_payload_view_from_view(src_view
, offset
, -1);
640 ssize_t trigger_size
;
642 trigger_size
= lttng_trigger_create_from_payload(
643 &trigger_view
, &trigger
);
644 if (trigger_size
< 0) {
649 /* Transfer ownership of the trigger to the collection. */
650 ret
= lttng_triggers_add(local_triggers
, trigger
);
651 lttng_trigger_put(trigger
);
657 offset
+= trigger_size
;
658 triggers_size
+= trigger_size
;
661 /* Unexpected size of inner-elements; the buffer is corrupted. */
662 if ((ssize_t
) triggers_comm
->length
!= triggers_size
) {
667 /* Pass ownership to caller. */
668 *triggers
= local_triggers
;
669 local_triggers
= NULL
;
674 lttng_triggers_destroy(local_triggers
);
679 const struct lttng_credentials
*lttng_trigger_get_credentials(
680 const struct lttng_trigger
*trigger
)
682 return &trigger
->creds
;
686 void lttng_trigger_set_credentials(struct lttng_trigger
*trigger
,
687 const struct lttng_credentials
*creds
)
690 trigger
->creds
= *creds
;
693 enum lttng_trigger_status
lttng_trigger_set_owner_uid(
694 struct lttng_trigger
*trigger
, uid_t uid
)
696 enum lttng_trigger_status ret
= LTTNG_TRIGGER_STATUS_OK
;
697 const struct lttng_credentials creds
= {
698 .uid
= LTTNG_OPTIONAL_INIT_VALUE(uid
),
699 .gid
= LTTNG_OPTIONAL_INIT_UNSET
,
703 ret
= LTTNG_TRIGGER_STATUS_INVALID
;
707 /* Client-side validation only to report a clearer error. */
708 if (geteuid() != 0) {
709 ret
= LTTNG_TRIGGER_STATUS_PERMISSION_DENIED
;
713 lttng_trigger_set_credentials(trigger
, &creds
);
719 enum lttng_trigger_status
lttng_trigger_get_owner_uid(
720 const struct lttng_trigger
*trigger
, uid_t
*uid
)
722 enum lttng_trigger_status ret
= LTTNG_TRIGGER_STATUS_OK
;
723 const struct lttng_credentials
*creds
= NULL
;
725 if (!trigger
|| !uid
) {
726 ret
= LTTNG_TRIGGER_STATUS_INVALID
;
730 if (!trigger
->creds
.uid
.is_set
) {
731 ret
= LTTNG_TRIGGER_STATUS_UNSET
;
735 creds
= lttng_trigger_get_credentials(trigger
);
736 *uid
= lttng_credentials_get_uid(creds
);