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/optional.h>
20 bool lttng_trigger_validate(struct lttng_trigger
*trigger
)
29 if (!trigger
->creds
.uid
.is_set
) {
34 valid
= lttng_condition_validate(trigger
->condition
) &&
35 lttng_action_validate(trigger
->action
);
40 struct lttng_trigger
*lttng_trigger_create(
41 struct lttng_condition
*condition
,
42 struct lttng_action
*action
)
44 struct lttng_trigger
*trigger
= NULL
;
46 if (!condition
|| !action
) {
50 trigger
= zmalloc(sizeof(struct lttng_trigger
));
55 urcu_ref_init(&trigger
->ref
);
57 lttng_condition_get(condition
);
58 trigger
->condition
= condition
;
60 lttng_action_get(action
);
61 trigger
->action
= action
;
68 * Note: the lack of reference counting 'get' on the condition object is normal.
69 * This API was exposed as such in 2.11. The client is not expected to call
70 * lttng_condition_destroy on the returned object.
72 struct lttng_condition
*lttng_trigger_get_condition(
73 struct lttng_trigger
*trigger
)
75 return trigger
? trigger
->condition
: NULL
;
79 const struct lttng_condition
*lttng_trigger_get_const_condition(
80 const struct lttng_trigger
*trigger
)
82 return trigger
->condition
;
87 * Note: the lack of reference counting 'get' on the action object is normal.
88 * This API was exposed as such in 2.11. The client is not expected to call
89 * lttng_action_destroy on the returned object.
91 struct lttng_action
*lttng_trigger_get_action(
92 struct lttng_trigger
*trigger
)
94 return trigger
? trigger
->action
: NULL
;
98 const struct lttng_action
*lttng_trigger_get_const_action(
99 const struct lttng_trigger
*trigger
)
101 return trigger
->action
;
104 static void trigger_destroy_ref(struct urcu_ref
*ref
)
106 struct lttng_trigger
*trigger
=
107 container_of(ref
, struct lttng_trigger
, ref
);
108 struct lttng_action
*action
= lttng_trigger_get_action(trigger
);
109 struct lttng_condition
*condition
=
110 lttng_trigger_get_condition(trigger
);
115 /* Release ownership. */
116 lttng_action_put(action
);
117 lttng_condition_put(condition
);
123 void lttng_trigger_destroy(struct lttng_trigger
*trigger
)
125 lttng_trigger_put(trigger
);
129 ssize_t
lttng_trigger_create_from_payload(
130 struct lttng_payload_view
*src_view
,
131 struct lttng_trigger
**trigger
)
133 ssize_t ret
, offset
= 0, condition_size
, action_size
, name_size
= 0;
134 struct lttng_condition
*condition
= NULL
;
135 struct lttng_action
*action
= NULL
;
136 const struct lttng_trigger_comm
*trigger_comm
;
137 const char *name
= NULL
;
138 struct lttng_credentials creds
= {
139 .uid
= LTTNG_OPTIONAL_INIT_UNSET
,
140 .gid
= LTTNG_OPTIONAL_INIT_UNSET
,
143 if (!src_view
|| !trigger
) {
148 /* lttng_trigger_comm header */
149 trigger_comm
= (typeof(trigger_comm
)) src_view
->buffer
.data
;
151 /* Set the trigger's creds. */
152 if (trigger_comm
->uid
> (uint64_t) ((uid_t
) -1)) {
153 /* UID out of range for this platform. */
158 LTTNG_OPTIONAL_SET(&creds
.uid
, trigger_comm
->uid
);
160 offset
+= sizeof(*trigger_comm
);
162 if (trigger_comm
->name_length
!= 0) {
164 const struct lttng_payload_view name_view
=
165 lttng_payload_view_from_view(
166 src_view
, offset
, trigger_comm
->name_length
);
168 name
= name_view
.buffer
.data
;
169 if (!lttng_buffer_view_contains_string(&name_view
.buffer
, name
,
170 trigger_comm
->name_length
)) {
175 offset
+= trigger_comm
->name_length
;
176 name_size
= trigger_comm
->name_length
;
180 /* struct lttng_condition */
181 struct lttng_payload_view condition_view
=
182 lttng_payload_view_from_view(
183 src_view
, offset
, -1);
185 condition_size
= lttng_condition_create_from_payload(&condition_view
,
189 if (condition_size
< 0) {
190 ret
= condition_size
;
194 offset
+= condition_size
;
196 /* struct lttng_action */
197 struct lttng_payload_view action_view
=
198 lttng_payload_view_from_view(
199 src_view
, offset
, -1);
201 action_size
= lttng_action_create_from_payload(&action_view
, &action
);
204 if (action_size
< 0) {
208 offset
+= action_size
;
210 /* Unexpected size of inner-elements; the buffer is corrupted. */
211 if ((ssize_t
) trigger_comm
->length
!= condition_size
+ action_size
+ name_size
) {
216 *trigger
= lttng_trigger_create(condition
, action
);
222 lttng_trigger_set_credentials(*trigger
, &creds
);
225 * The trigger object owns references to the action and condition
228 lttng_condition_put(condition
);
231 lttng_action_put(action
);
235 const enum lttng_trigger_status status
=
236 lttng_trigger_set_name(*trigger
, name
);
238 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
247 lttng_condition_destroy(condition
);
248 lttng_action_destroy(action
);
254 * Both elements are stored contiguously, see their "*_comm" structure
255 * for the detailed format.
258 int lttng_trigger_serialize(struct lttng_trigger
*trigger
,
259 struct lttng_payload
*payload
)
262 size_t header_offset
, size_before_payload
, size_name
;
263 struct lttng_trigger_comm trigger_comm
= {};
264 struct lttng_trigger_comm
*header
;
265 const struct lttng_credentials
*creds
= NULL
;
267 creds
= lttng_trigger_get_credentials(trigger
);
270 trigger_comm
.uid
= LTTNG_OPTIONAL_GET(creds
->uid
);
272 if (trigger
->name
!= NULL
) {
273 size_name
= strlen(trigger
->name
) + 1;
278 trigger_comm
.name_length
= size_name
;
280 header_offset
= payload
->buffer
.size
;
281 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &trigger_comm
,
282 sizeof(trigger_comm
));
287 size_before_payload
= payload
->buffer
.size
;
290 ret
= lttng_dynamic_buffer_append(
291 &payload
->buffer
, trigger
->name
, size_name
);
296 ret
= lttng_condition_serialize(trigger
->condition
, payload
);
301 ret
= lttng_action_serialize(trigger
->action
, payload
);
306 /* Update payload size. */
307 header
= (typeof(header
)) (payload
->buffer
.data
+ header_offset
);
308 header
->length
= payload
->buffer
.size
- size_before_payload
;
314 bool lttng_trigger_is_equal(
315 const struct lttng_trigger
*a
, const struct lttng_trigger
*b
)
318 * Name is not taken into account since it is cosmetic only.
320 if (!lttng_condition_is_equal(a
->condition
, b
->condition
)) {
324 if (!lttng_action_is_equal(a
->action
, b
->action
)) {
328 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a
),
329 lttng_trigger_get_credentials(b
))) {
336 enum lttng_trigger_status
lttng_trigger_set_name(struct lttng_trigger
*trigger
,
339 char *name_copy
= NULL
;
340 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
342 if (!trigger
|| !name
||
344 status
= LTTNG_TRIGGER_STATUS_INVALID
;
348 name_copy
= strdup(name
);
350 status
= LTTNG_TRIGGER_STATUS_ERROR
;
356 trigger
->name
= name_copy
;
362 enum lttng_trigger_status
lttng_trigger_get_name(
363 const struct lttng_trigger
*trigger
, const char **name
)
365 enum lttng_trigger_status status
= LTTNG_TRIGGER_STATUS_OK
;
367 if (!trigger
|| !name
) {
368 status
= LTTNG_TRIGGER_STATUS_INVALID
;
372 if (!trigger
->name
) {
373 status
= LTTNG_TRIGGER_STATUS_UNSET
;
376 *name
= trigger
->name
;
382 int lttng_trigger_assign_name(struct lttng_trigger
*dst
,
383 const struct lttng_trigger
*src
)
386 enum lttng_trigger_status status
;
388 status
= lttng_trigger_set_name(dst
, src
->name
);
389 if (status
!= LTTNG_TRIGGER_STATUS_OK
) {
391 ERR("Failed to set name for trigger");
399 int lttng_trigger_generate_name(struct lttng_trigger
*trigger
,
403 char *generated_name
= NULL
;
405 ret
= asprintf(&generated_name
, "T%" PRIu64
"", unique_id
);
407 ERR("Failed to generate trigger name");
414 trigger
->name
= generated_name
;
420 void lttng_trigger_get(struct lttng_trigger
*trigger
)
422 urcu_ref_get(&trigger
->ref
);
426 void lttng_trigger_put(struct lttng_trigger
*trigger
)
432 urcu_ref_put(&trigger
->ref
, trigger_destroy_ref
);
436 const struct lttng_credentials
*lttng_trigger_get_credentials(
437 const struct lttng_trigger
*trigger
)
439 return &trigger
->creds
;
443 void lttng_trigger_set_credentials(struct lttng_trigger
*trigger
,
444 const struct lttng_credentials
*creds
)
447 trigger
->creds
= *creds
;
450 enum lttng_trigger_status
lttng_trigger_set_owner_uid(
451 struct lttng_trigger
*trigger
, uid_t uid
)
453 enum lttng_trigger_status ret
= LTTNG_TRIGGER_STATUS_OK
;
454 const struct lttng_credentials creds
= {
455 .uid
= LTTNG_OPTIONAL_INIT_VALUE(uid
),
456 .gid
= LTTNG_OPTIONAL_INIT_UNSET
,
460 ret
= LTTNG_TRIGGER_STATUS_INVALID
;
464 /* Client-side validation only to report a clearer error. */
465 if (geteuid() != 0) {
466 ret
= LTTNG_TRIGGER_STATUS_PERMISSION_DENIED
;
470 lttng_trigger_set_credentials(trigger
, &creds
);
476 enum lttng_trigger_status
lttng_trigger_get_owner_uid(
477 const struct lttng_trigger
*trigger
, uid_t
*uid
)
479 enum lttng_trigger_status ret
= LTTNG_TRIGGER_STATUS_OK
;
480 const struct lttng_credentials
*creds
= NULL
;
482 if (!trigger
|| !uid
) {
483 ret
= LTTNG_TRIGGER_STATUS_INVALID
;
487 if (!trigger
->creds
.uid
.is_set
) {
488 ret
= LTTNG_TRIGGER_STATUS_UNSET
;
492 creds
= lttng_trigger_get_credentials(trigger
);
493 *uid
= lttng_credentials_get_uid(creds
);