SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / common / trigger.c
CommitLineData
a58c490f 1/*
ab5be9fa 2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
a58c490f 3 *
ab5be9fa 4 * SPDX-License-Identifier: LGPL-2.1-only
a58c490f 5 *
a58c490f
JG
6 */
7
8#include <lttng/trigger/trigger-internal.h>
9#include <lttng/condition/condition-internal.h>
ebdb334b
JR
10#include <lttng/condition/on-event-internal.h>
11#include <lttng/condition/on-event.h>
12#include <lttng/condition/on-event-internal.h>
91c96f62
JR
13#include <lttng/condition/buffer-usage.h>
14#include <lttng/event-rule/event-rule-internal.h>
f2e97f59 15#include <lttng/event-expr-internal.h>
a58c490f 16#include <lttng/action/action-internal.h>
ebdb334b 17#include <lttng/action/group.h>
3da864a9 18#include <common/credentials.h>
9e620ea7
JG
19#include <common/payload.h>
20#include <common/payload-view.h>
91c96f62 21#include <lttng/domain.h>
a58c490f 22#include <common/error.h>
a02903c0 23#include <common/dynamic-array.h>
3da864a9 24#include <common/optional.h>
a58c490f 25#include <assert.h>
242388e4 26#include <inttypes.h>
a58c490f
JG
27
28LTTNG_HIDDEN
b61776fb 29bool lttng_trigger_validate(const struct lttng_trigger *trigger)
a58c490f
JG
30{
31 bool valid;
32
33 if (!trigger) {
34 valid = false;
35 goto end;
36 }
37
64eafdf6
JR
38 if (!trigger->creds.uid.is_set) {
39 valid = false;
40 goto end;
41 }
42
a58c490f
JG
43 valid = lttng_condition_validate(trigger->condition) &&
44 lttng_action_validate(trigger->action);
45end:
46 return valid;
47}
48
49struct lttng_trigger *lttng_trigger_create(
50 struct lttng_condition *condition,
51 struct lttng_action *action)
52{
53 struct lttng_trigger *trigger = NULL;
54
55 if (!condition || !action) {
56 goto end;
57 }
58
59 trigger = zmalloc(sizeof(struct lttng_trigger));
60 if (!trigger) {
61 goto end;
62 }
63
f01d28b4
JR
64 urcu_ref_init(&trigger->ref);
65
5c504c41
JR
66 trigger->firing_policy.type = LTTNG_TRIGGER_FIRING_POLICY_EVERY_N;
67 trigger->firing_policy.threshold = 1;
68
7ca172c1 69 lttng_condition_get(condition);
a58c490f 70 trigger->condition = condition;
7ca172c1
JR
71
72 lttng_action_get(action);
a58c490f 73 trigger->action = action;
3da864a9 74
a58c490f
JG
75end:
76 return trigger;
77}
78
7ca172c1
JR
79/*
80 * Note: the lack of reference counting 'get' on the condition object is normal.
81 * This API was exposed as such in 2.11. The client is not expected to call
82 * lttng_condition_destroy on the returned object.
83 */
a58c490f
JG
84struct lttng_condition *lttng_trigger_get_condition(
85 struct lttng_trigger *trigger)
86{
87 return trigger ? trigger->condition : NULL;
88}
89
9b63a4aa
JG
90const struct lttng_condition *lttng_trigger_get_const_condition(
91 const struct lttng_trigger *trigger)
92{
0de2479d 93 return trigger ? trigger->condition : NULL;
9b63a4aa
JG
94}
95
7ca172c1
JR
96/*
97 * Note: the lack of reference counting 'get' on the action object is normal.
98 * This API was exposed as such in 2.11. The client is not expected to call
99 * lttng_action_destroy on the returned object.
100 */
e2ba1c78 101struct lttng_action *lttng_trigger_get_action(
a58c490f
JG
102 struct lttng_trigger *trigger)
103{
104 return trigger ? trigger->action : NULL;
105}
106
9b63a4aa
JG
107const struct lttng_action *lttng_trigger_get_const_action(
108 const struct lttng_trigger *trigger)
109{
0de2479d 110 return trigger ? trigger->action : NULL;
9b63a4aa
JG
111}
112
f01d28b4 113static void trigger_destroy_ref(struct urcu_ref *ref)
a58c490f 114{
f01d28b4
JR
115 struct lttng_trigger *trigger =
116 container_of(ref, struct lttng_trigger, ref);
7ca172c1
JR
117 struct lttng_action *action = lttng_trigger_get_action(trigger);
118 struct lttng_condition *condition =
119 lttng_trigger_get_condition(trigger);
120
7ca172c1
JR
121 assert(action);
122 assert(condition);
123
124 /* Release ownership. */
125 lttng_action_put(action);
126 lttng_condition_put(condition);
127
242388e4 128 free(trigger->name);
a58c490f
JG
129 free(trigger);
130}
131
f01d28b4
JR
132void lttng_trigger_destroy(struct lttng_trigger *trigger)
133{
134 lttng_trigger_put(trigger);
135}
136
5c504c41
JR
137static bool is_firing_policy_valid(enum lttng_trigger_firing_policy policy)
138{
139 bool valid = false;
140
141 switch (policy) {
142 case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
143 case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
144 valid = true;
145 break;
146 default:
147 valid = false;
148 break;
149 }
150
151 return valid;
152}
153
a58c490f 154LTTNG_HIDDEN
c0a66c84
JG
155ssize_t lttng_trigger_create_from_payload(
156 struct lttng_payload_view *src_view,
6808ef55 157 struct lttng_trigger **_trigger)
a58c490f 158{
242388e4 159 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
a58c490f
JG
160 struct lttng_condition *condition = NULL;
161 struct lttng_action *action = NULL;
162 const struct lttng_trigger_comm *trigger_comm;
242388e4 163 const char *name = NULL;
5c504c41
JR
164 uint64_t firing_policy_threshold;
165 enum lttng_trigger_firing_policy firing_policy;
64eafdf6
JR
166 struct lttng_credentials creds = {
167 .uid = LTTNG_OPTIONAL_INIT_UNSET,
168 .gid = LTTNG_OPTIONAL_INIT_UNSET,
169 };
6808ef55 170 struct lttng_trigger *trigger = NULL;
3e6e0df2
JG
171 const struct lttng_payload_view trigger_comm_view =
172 lttng_payload_view_from_view(
173 src_view, 0, sizeof(*trigger_comm));
a58c490f 174
6808ef55 175 if (!src_view || !_trigger) {
a58c490f
JG
176 ret = -1;
177 goto end;
178 }
179
3e6e0df2
JG
180 if (!lttng_payload_view_is_valid(&trigger_comm_view)) {
181 /* Payload not large enough to contain the header. */
182 ret = -1;
183 goto end;
184 }
185
a58c490f 186 /* lttng_trigger_comm header */
3e6e0df2 187 trigger_comm = (typeof(trigger_comm)) trigger_comm_view.buffer.data;
64eafdf6
JR
188
189 /* Set the trigger's creds. */
190 if (trigger_comm->uid > (uint64_t) ((uid_t) -1)) {
191 /* UID out of range for this platform. */
192 ret = -1;
193 goto end;
194 }
195
196 LTTNG_OPTIONAL_SET(&creds.uid, trigger_comm->uid);
197
a58c490f 198 offset += sizeof(*trigger_comm);
242388e4 199
5c504c41
JR
200 firing_policy = trigger_comm->firing_policy_type;
201 if (!is_firing_policy_valid(firing_policy)) {
202 ret =-1;
203 goto end;
204 }
205
206 firing_policy_threshold = trigger_comm->firing_policy_threshold;
242388e4
JR
207 if (trigger_comm->name_length != 0) {
208 /* Name. */
209 const struct lttng_payload_view name_view =
210 lttng_payload_view_from_view(
3e6e0df2
JG
211 src_view, offset,
212 trigger_comm->name_length);
213
214 if (!lttng_payload_view_is_valid(&name_view)) {
215 ret = -1;
216 goto end;
217 }
242388e4
JR
218
219 name = name_view.buffer.data;
220 if (!lttng_buffer_view_contains_string(&name_view.buffer, name,
221 trigger_comm->name_length)) {
222 ret = -1;
223 goto end;
224 }
225
226 offset += trigger_comm->name_length;
227 name_size = trigger_comm->name_length;
228 }
229
c0a66c84
JG
230 {
231 /* struct lttng_condition */
232 struct lttng_payload_view condition_view =
233 lttng_payload_view_from_view(
234 src_view, offset, -1);
235
236 condition_size = lttng_condition_create_from_payload(&condition_view,
237 &condition);
238 }
a58c490f 239
a58c490f
JG
240 if (condition_size < 0) {
241 ret = condition_size;
242 goto end;
243 }
c0a66c84 244
a58c490f 245 offset += condition_size;
c0a66c84
JG
246 {
247 /* struct lttng_action */
248 struct lttng_payload_view action_view =
249 lttng_payload_view_from_view(
250 src_view, offset, -1);
251
252 action_size = lttng_action_create_from_payload(&action_view, &action);
253 }
a58c490f 254
a58c490f
JG
255 if (action_size < 0) {
256 ret = action_size;
257 goto end;
258 }
259 offset += action_size;
260
261 /* Unexpected size of inner-elements; the buffer is corrupted. */
242388e4 262 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
a58c490f
JG
263 ret = -1;
264 goto error;
265 }
266
6808ef55
JG
267 trigger = lttng_trigger_create(condition, action);
268 if (!trigger) {
a58c490f
JG
269 ret = -1;
270 goto error;
271 }
c0a66c84 272
6808ef55 273 lttng_trigger_set_credentials(trigger, &creds);
64eafdf6 274
7ca172c1
JR
275 /*
276 * The trigger object owns references to the action and condition
277 * objects.
278 */
279 lttng_condition_put(condition);
280 condition = NULL;
281
282 lttng_action_put(action);
283 action = NULL;
284
242388e4
JR
285 if (name) {
286 const enum lttng_trigger_status status =
6808ef55 287 lttng_trigger_set_name(trigger, name);
242388e4
JR
288
289 if (status != LTTNG_TRIGGER_STATUS_OK) {
290 ret = -1;
291 goto end;
292 }
293 }
294
5c504c41
JR
295 /* Set the policy. */
296 {
297 const enum lttng_trigger_status status =
298 lttng_trigger_set_firing_policy(trigger,
299 firing_policy,
300 firing_policy_threshold);
301
302 if (status != LTTNG_TRIGGER_STATUS_OK) {
303 ret = -1;
304 goto end;
305 }
306 }
307
a58c490f 308 ret = offset;
7ca172c1 309
a58c490f 310error:
1065801b
JG
311 lttng_condition_put(condition);
312 lttng_action_put(action);
7ca172c1 313end:
f5d98ed9 314 if (ret >= 0) {
6808ef55
JG
315 *_trigger = trigger;
316 } else {
317 lttng_trigger_put(trigger);
318 }
319
a58c490f
JG
320 return ret;
321}
322
323/*
a58c490f
JG
324 * Both elements are stored contiguously, see their "*_comm" structure
325 * for the detailed format.
326 */
327LTTNG_HIDDEN
a02903c0 328int lttng_trigger_serialize(const struct lttng_trigger *trigger,
c0a66c84 329 struct lttng_payload *payload)
a58c490f 330{
3647288f 331 int ret;
242388e4 332 size_t header_offset, size_before_payload, size_name;
c0a66c84 333 struct lttng_trigger_comm trigger_comm = {};
3647288f 334 struct lttng_trigger_comm *header;
64eafdf6
JR
335 const struct lttng_credentials *creds = NULL;
336
337 creds = lttng_trigger_get_credentials(trigger);
338 assert(creds);
339
340 trigger_comm.uid = LTTNG_OPTIONAL_GET(creds->uid);
a58c490f 341
242388e4
JR
342 if (trigger->name != NULL) {
343 size_name = strlen(trigger->name) + 1;
344 } else {
345 size_name = 0;
346 }
347
348 trigger_comm.name_length = size_name;
5c504c41
JR
349 trigger_comm.firing_policy_type = (uint8_t) trigger->firing_policy.type;
350 trigger_comm.firing_policy_threshold = (uint64_t) trigger->firing_policy.threshold;
242388e4 351
c0a66c84
JG
352 header_offset = payload->buffer.size;
353 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
3647288f
JG
354 sizeof(trigger_comm));
355 if (ret) {
a58c490f
JG
356 goto end;
357 }
358
c0a66c84 359 size_before_payload = payload->buffer.size;
242388e4
JR
360
361 /* Trigger name. */
362 ret = lttng_dynamic_buffer_append(
363 &payload->buffer, trigger->name, size_name);
364 if (ret) {
365 goto end;
366 }
367
c0a66c84 368 ret = lttng_condition_serialize(trigger->condition, payload);
3647288f 369 if (ret) {
a58c490f
JG
370 goto end;
371 }
a58c490f 372
c0a66c84 373 ret = lttng_action_serialize(trigger->action, payload);
3647288f 374 if (ret) {
a58c490f
JG
375 goto end;
376 }
a58c490f 377
3647288f 378 /* Update payload size. */
c0a66c84
JG
379 header = (typeof(header)) (payload->buffer.data + header_offset);
380 header->length = payload->buffer.size - size_before_payload;
a58c490f
JG
381end:
382 return ret;
383}
3da864a9 384
85c06c44
JR
385LTTNG_HIDDEN
386bool lttng_trigger_is_equal(
387 const struct lttng_trigger *a, const struct lttng_trigger *b)
388{
5c504c41
JR
389 if (a->firing_policy.type != b->firing_policy.type) {
390 return false;
391 }
392
393 if (a->firing_policy.threshold != b->firing_policy.threshold) {
394 return false;
395 }
396
85c06c44 397 /*
ebdb334b
JR
398 * FIXME: frdeso: this is a change of behavior.
399 * See internal tracker issue 1028.
85c06c44 400 */
ebdb334b
JR
401 if (strcmp(a->name, b->name) != 0) {
402 return false;
403 }
404
85c06c44
JR
405 if (!lttng_condition_is_equal(a->condition, b->condition)) {
406 return false;
407 }
408
409 if (!lttng_action_is_equal(a->action, b->action)) {
410 return false;
411 }
412
413 if (!lttng_credentials_is_equal(lttng_trigger_get_credentials(a),
414 lttng_trigger_get_credentials(b))) {
415 return false;
416 }
417
418 return true;
419}
420
242388e4
JR
421enum lttng_trigger_status lttng_trigger_set_name(struct lttng_trigger *trigger,
422 const char* name)
423{
424 char *name_copy = NULL;
425 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
426
427 if (!trigger || !name ||
428 strlen(name) == 0) {
429 status = LTTNG_TRIGGER_STATUS_INVALID;
430 goto end;
431 }
432
433 name_copy = strdup(name);
434 if (!name_copy) {
435 status = LTTNG_TRIGGER_STATUS_ERROR;
436 goto end;
437 }
438
439 free(trigger->name);
440
441 trigger->name = name_copy;
442 name_copy = NULL;
443end:
444 return status;
445}
446
447enum lttng_trigger_status lttng_trigger_get_name(
448 const struct lttng_trigger *trigger, const char **name)
449{
450 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
451
452 if (!trigger || !name) {
453 status = LTTNG_TRIGGER_STATUS_INVALID;
454 goto end;
455 }
456
457 if (!trigger->name) {
458 status = LTTNG_TRIGGER_STATUS_UNSET;
459 }
460
461 *name = trigger->name;
462end:
463 return status;
464}
465
466LTTNG_HIDDEN
467int lttng_trigger_assign_name(struct lttng_trigger *dst,
468 const struct lttng_trigger *src)
469{
470 int ret = 0;
471 enum lttng_trigger_status status;
472
473 status = lttng_trigger_set_name(dst, src->name);
474 if (status != LTTNG_TRIGGER_STATUS_OK) {
475 ret = -1;
476 ERR("Failed to set name for trigger");
477 goto end;
478 }
479end:
480 return ret;
481}
482
e6887944
JR
483LTTNG_HIDDEN
484void lttng_trigger_set_tracer_token(struct lttng_trigger *trigger,
485 uint64_t token)
486{
487 assert(trigger);
488 LTTNG_OPTIONAL_SET(&trigger->tracer_token, token);
489}
490
491LTTNG_HIDDEN
492uint64_t lttng_trigger_get_tracer_token(const struct lttng_trigger *trigger)
493{
494 assert(trigger);
495
496 return LTTNG_OPTIONAL_GET(trigger->tracer_token);
497}
498
242388e4
JR
499LTTNG_HIDDEN
500int lttng_trigger_generate_name(struct lttng_trigger *trigger,
501 uint64_t unique_id)
502{
503 int ret = 0;
504 char *generated_name = NULL;
505
506 ret = asprintf(&generated_name, "T%" PRIu64 "", unique_id);
507 if (ret < 0) {
508 ERR("Failed to generate trigger name");
509 ret = -1;
510 goto end;
511 }
512
513 ret = 0;
514 free(trigger->name);
515 trigger->name = generated_name;
516end:
517 return ret;
518}
519
f01d28b4
JR
520LTTNG_HIDDEN
521void lttng_trigger_get(struct lttng_trigger *trigger)
522{
523 urcu_ref_get(&trigger->ref);
524}
525
526LTTNG_HIDDEN
527void lttng_trigger_put(struct lttng_trigger *trigger)
528{
529 if (!trigger) {
530 return;
531 }
532
533 urcu_ref_put(&trigger->ref , trigger_destroy_ref);
534}
535
a02903c0
JR
536static void delete_trigger_array_element(void *ptr)
537{
538 struct lttng_trigger *trigger = ptr;
539
540 lttng_trigger_put(trigger);
541}
542
543LTTNG_HIDDEN
544struct lttng_triggers *lttng_triggers_create(void)
545{
546 struct lttng_triggers *triggers = NULL;
547
548 triggers = zmalloc(sizeof(*triggers));
549 if (!triggers) {
550 goto end;
551 }
552
553 lttng_dynamic_pointer_array_init(&triggers->array, delete_trigger_array_element);
554
555end:
556 return triggers;
557}
558
559LTTNG_HIDDEN
560struct lttng_trigger *lttng_triggers_borrow_mutable_at_index(
561 const struct lttng_triggers *triggers, unsigned int index)
562{
563 struct lttng_trigger *trigger = NULL;
564
565 assert(triggers);
566 if (index >= lttng_dynamic_pointer_array_get_count(&triggers->array)) {
567 goto end;
568 }
569
570 trigger = (struct lttng_trigger *)
571 lttng_dynamic_pointer_array_get_pointer(
572 &triggers->array, index);
573end:
574 return trigger;
575}
576
577LTTNG_HIDDEN
578int lttng_triggers_add(
579 struct lttng_triggers *triggers, struct lttng_trigger *trigger)
580{
581 int ret;
582
583 assert(triggers);
584 assert(trigger);
585
586 lttng_trigger_get(trigger);
587
588 ret = lttng_dynamic_pointer_array_add_pointer(&triggers->array, trigger);
589 if (ret) {
590 lttng_trigger_put(trigger);
591 }
592
593 return ret;
594}
595
596const struct lttng_trigger *lttng_triggers_get_at_index(
597 const struct lttng_triggers *triggers, unsigned int index)
598{
599 return lttng_triggers_borrow_mutable_at_index(triggers, index);
600}
601
602enum lttng_trigger_status lttng_triggers_get_count(const struct lttng_triggers *triggers, unsigned int *count)
603{
604 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
605
606 if (!triggers || !count) {
607 status = LTTNG_TRIGGER_STATUS_INVALID;
608 goto end;
609 }
610
611 *count = lttng_dynamic_pointer_array_get_count(&triggers->array);
612end:
613 return status;
614}
615
616void lttng_triggers_destroy(struct lttng_triggers *triggers)
617{
618 if (!triggers) {
619 return;
620 }
621
622 lttng_dynamic_pointer_array_reset(&triggers->array);
623 free(triggers);
624}
625
626int lttng_triggers_serialize(const struct lttng_triggers *triggers,
627 struct lttng_payload *payload)
628{
629 int ret;
630 unsigned int i, count;
631 size_t size_before_payload;
632 struct lttng_triggers_comm triggers_comm = {};
633 struct lttng_triggers_comm *header;
634 enum lttng_trigger_status status;
635 const size_t header_offset = payload->buffer.size;
636
637 status = lttng_triggers_get_count(triggers, &count);
638 if (status != LTTNG_TRIGGER_STATUS_OK) {
639 ret = LTTNG_ERR_INVALID;
640 goto end;
641 }
642
643 triggers_comm.count = count;
644
645 /* Placeholder header; updated at the end. */
646 ret = lttng_dynamic_buffer_append(&payload->buffer, &triggers_comm,
647 sizeof(triggers_comm));
648 if (ret) {
649 goto end;
650 }
651
652 size_before_payload = payload->buffer.size;
653
654 for (i = 0; i < count; i++) {
655 const struct lttng_trigger *trigger =
656 lttng_triggers_get_at_index(triggers, i);
657
658 assert(trigger);
659
660 ret = lttng_trigger_serialize(trigger, payload);
661 if (ret) {
662 goto end;
663 }
664 }
665
666 /* Update payload size. */
667 header = (struct lttng_triggers_comm *) ((char *) payload->buffer.data + header_offset);
668 header->length = payload->buffer.size - size_before_payload;
669end:
670 return ret;
671}
672
673LTTNG_HIDDEN
674ssize_t lttng_triggers_create_from_payload(
675 struct lttng_payload_view *src_view,
676 struct lttng_triggers **triggers)
677{
678 ssize_t ret, offset = 0, triggers_size = 0;
679 unsigned int i;
680 const struct lttng_triggers_comm *triggers_comm;
681 struct lttng_triggers *local_triggers = NULL;
682
683 if (!src_view || !triggers) {
684 ret = -1;
685 goto error;
686 }
687
688 /* lttng_trigger_comms header */
689 triggers_comm = (const struct lttng_triggers_comm *) src_view->buffer.data;
690 offset += sizeof(*triggers_comm);
691
692 local_triggers = lttng_triggers_create();
693 if (!local_triggers) {
694 ret = -1;
695 goto error;
696 }
697
698 for (i = 0; i < triggers_comm->count; i++) {
699 struct lttng_trigger *trigger = NULL;
700 struct lttng_payload_view trigger_view =
701 lttng_payload_view_from_view(src_view, offset, -1);
702 ssize_t trigger_size;
703
704 trigger_size = lttng_trigger_create_from_payload(
705 &trigger_view, &trigger);
706 if (trigger_size < 0) {
707 ret = trigger_size;
708 goto error;
709 }
710
711 /* Transfer ownership of the trigger to the collection. */
712 ret = lttng_triggers_add(local_triggers, trigger);
713 lttng_trigger_put(trigger);
714 if (ret < 0) {
715 ret = -1;
716 goto error;
717 }
718
719 offset += trigger_size;
720 triggers_size += trigger_size;
721 }
722
723 /* Unexpected size of inner-elements; the buffer is corrupted. */
724 if ((ssize_t) triggers_comm->length != triggers_size) {
725 ret = -1;
726 goto error;
727 }
728
729 /* Pass ownership to caller. */
730 *triggers = local_triggers;
731 local_triggers = NULL;
732
733 ret = offset;
734error:
735
736 lttng_triggers_destroy(local_triggers);
737 return ret;
738}
739
3da864a9
JR
740LTTNG_HIDDEN
741const struct lttng_credentials *lttng_trigger_get_credentials(
742 const struct lttng_trigger *trigger)
743{
64eafdf6 744 return &trigger->creds;
3da864a9
JR
745}
746
747LTTNG_HIDDEN
64eafdf6 748void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
3da864a9
JR
749 const struct lttng_credentials *creds)
750{
751 assert(creds);
64eafdf6
JR
752 trigger->creds = *creds;
753}
754
755enum lttng_trigger_status lttng_trigger_set_owner_uid(
756 struct lttng_trigger *trigger, uid_t uid)
757{
758 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
759 const struct lttng_credentials creds = {
760 .uid = LTTNG_OPTIONAL_INIT_VALUE(uid),
761 .gid = LTTNG_OPTIONAL_INIT_UNSET,
762 };
763
764 if (!trigger) {
765 ret = LTTNG_TRIGGER_STATUS_INVALID;
766 goto end;
767 }
768
769 /* Client-side validation only to report a clearer error. */
770 if (geteuid() != 0) {
771 ret = LTTNG_TRIGGER_STATUS_PERMISSION_DENIED;
772 goto end;
773 }
774
775 lttng_trigger_set_credentials(trigger, &creds);
776
777end:
778 return ret;
779}
780
781enum lttng_trigger_status lttng_trigger_get_owner_uid(
782 const struct lttng_trigger *trigger, uid_t *uid)
783{
784 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
785 const struct lttng_credentials *creds = NULL;
786
787 if (!trigger || !uid ) {
788 ret = LTTNG_TRIGGER_STATUS_INVALID;
789 goto end;
790 }
791
792 if (!trigger->creds.uid.is_set ) {
793 ret = LTTNG_TRIGGER_STATUS_UNSET;
794 goto end;
795 }
796
797 creds = lttng_trigger_get_credentials(trigger);
798 *uid = lttng_credentials_get_uid(creds);
799
800end:
801 return ret;
3da864a9 802}
5c504c41
JR
803
804enum lttng_trigger_status lttng_trigger_set_firing_policy(
805 struct lttng_trigger *trigger,
806 enum lttng_trigger_firing_policy policy_type,
807 uint64_t threshold)
808{
809 enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
810 assert(trigger);
811
812 if (threshold < 1) {
813 ret = LTTNG_TRIGGER_STATUS_INVALID;
814 goto end;
815 }
816
817 trigger->firing_policy.type = policy_type;
818 trigger->firing_policy.threshold = threshold;
819
820end:
821 return ret;
822}
823
824enum lttng_trigger_status lttng_trigger_get_firing_policy(
825 const struct lttng_trigger *trigger,
826 enum lttng_trigger_firing_policy *policy_type,
827 uint64_t *threshold)
828{
829 enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
830
831 if (!trigger || !policy_type || !threshold) {
832 status = LTTNG_TRIGGER_STATUS_INVALID;
833 goto end;
834 }
835
836 *policy_type = trigger->firing_policy.type;
837 *threshold = trigger->firing_policy.threshold;
838
839end:
840 return status;
841}
842
843LTTNG_HIDDEN
844bool lttng_trigger_should_fire(const struct lttng_trigger *trigger)
845{
846 bool ready_to_fire = false;
847
848 assert(trigger);
849
850 switch (trigger->firing_policy.type) {
851 case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
852 if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
853 ready_to_fire = true;
854 }
855 break;
856 case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
857 if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
858 ready_to_fire = true;
859 }
860 break;
861 default:
862 abort();
863 };
864
865 return ready_to_fire;
866}
867
868LTTNG_HIDDEN
869void lttng_trigger_fire(struct lttng_trigger *trigger)
870{
871 assert(trigger);
872
873 trigger->firing_policy.current_count++;
874
875 switch (trigger->firing_policy.type) {
876 case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
877 if (trigger->firing_policy.current_count == trigger->firing_policy.threshold) {
878 trigger->firing_policy.current_count = 0;
879 }
880
881 break;
882 case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
883 /*
884 * TODO:
885 * As an optimisation, deactivate the trigger condition and
886 * remove any checks in the traced application or kernel since
887 * the trigger will never fire again.
888 */
889 break;
890 default:
891 abort();
892 };
893}
91c96f62
JR
894
895LTTNG_HIDDEN
896enum lttng_domain_type lttng_trigger_get_underlying_domain_type_restriction(
897 const struct lttng_trigger *trigger)
898{
899 enum lttng_domain_type type = LTTNG_DOMAIN_NONE;
900 const struct lttng_event_rule *event_rule;
901 enum lttng_condition_status c_status;
902 enum lttng_condition_type c_type;
903
904 assert(trigger);
905 assert(trigger->condition);
906
907 c_type = lttng_condition_get_type(trigger->condition);
908 assert (c_type != LTTNG_CONDITION_TYPE_UNKNOWN);
909
910 switch (c_type) {
911 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
912 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
913 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
914 /* Apply to any domain. */
915 type = LTTNG_DOMAIN_NONE;
916 break;
ebdb334b 917 case LTTNG_CONDITION_TYPE_ON_EVENT:
91c96f62 918 /* Return the domain of the event rule. */
ebdb334b 919 c_status = lttng_condition_on_event_get_rule(
91c96f62
JR
920 trigger->condition, &event_rule);
921 assert(c_status == LTTNG_CONDITION_STATUS_OK);
922 type = lttng_event_rule_get_domain_type(event_rule);
923 break;
924 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
925 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
926 /* Return the domain of the channel being monitored. */
927 c_status = lttng_condition_buffer_usage_get_domain_type(
928 trigger->condition, &type);
929 assert(c_status == LTTNG_CONDITION_STATUS_OK);
930 break;
931 default:
932 abort();
933 }
934
935 return type;
936}
58daac01
JR
937
938/*
939 * Generate bytecode related to the trigger.
940 * On success LTTNG_OK. On error, returns lttng_error code.
941 */
942LTTNG_HIDDEN
943enum lttng_error_code lttng_trigger_generate_bytecode(
944 struct lttng_trigger *trigger,
945 const struct lttng_credentials *creds)
946{
947 enum lttng_error_code ret;
948 struct lttng_condition *condition = NULL;
949
950 condition = lttng_trigger_get_condition(trigger);
951 if (!condition) {
952 ret = LTTNG_ERR_INVALID_TRIGGER;
953 goto end;
954 }
955
956 switch (lttng_condition_get_type(condition)) {
ebdb334b 957 case LTTNG_CONDITION_TYPE_ON_EVENT:
58daac01
JR
958 {
959 struct lttng_event_rule *event_rule;
960 const enum lttng_condition_status condition_status =
ebdb334b 961 lttng_condition_on_event_borrow_rule_mutable(
58daac01
JR
962 condition, &event_rule);
963
964 assert(condition_status == LTTNG_CONDITION_STATUS_OK);
f2e97f59
JR
965
966 /* Generate the filter bytecode. */
58daac01
JR
967 ret = lttng_event_rule_generate_filter_bytecode(
968 event_rule, creds);
969 if (ret != LTTNG_OK) {
970 goto end;
971 }
972
f2e97f59 973 /* Generate the capture bytecode. */
ebdb334b 974 ret = lttng_condition_on_event_generate_capture_descriptor_bytecode(
f2e97f59
JR
975 condition);
976 if (ret != LTTNG_OK) {
977 goto end;
978 }
979
58daac01
JR
980 ret = LTTNG_OK;
981 break;
982 }
983 default:
984 ret = LTTNG_OK;
985 break;
986 }
987end:
988 return ret;
989}
b61776fb
SM
990
991LTTNG_HIDDEN
992struct lttng_trigger *lttng_trigger_copy(const struct lttng_trigger *trigger)
993{
994 int ret;
995 struct lttng_payload copy_buffer;
996 struct lttng_trigger *copy = NULL;
997
998 lttng_payload_init(&copy_buffer);
999
1000 ret = lttng_trigger_serialize(trigger, &copy_buffer);
1001 if (ret < 0) {
1002 goto end;
1003 }
1004
1005 {
1006 struct lttng_payload_view view =
1007 lttng_payload_view_from_payload(
1008 &copy_buffer, 0, -1);
1009 ret = lttng_trigger_create_from_payload(
1010 &view, &copy);
1011 if (ret < 0) {
1012 copy = NULL;
1013 goto end;
1014 }
1015 }
1016
1017end:
1018 lttng_payload_reset(&copy_buffer);
1019 return copy;
1020}
ebdb334b
JR
1021
1022
1023static
1024bool action_type_needs_tracer_notifier(enum lttng_action_type action_type)
1025{
1026 switch (action_type) {
1027 case LTTNG_ACTION_TYPE_NOTIFY:
1028 case LTTNG_ACTION_TYPE_START_SESSION:
1029 case LTTNG_ACTION_TYPE_STOP_SESSION:
1030 case LTTNG_ACTION_TYPE_SNAPSHOT_SESSION:
1031 case LTTNG_ACTION_TYPE_ROTATE_SESSION:
1032 return true;
1033 case LTTNG_ACTION_TYPE_INCREMENT_VALUE:
1034 return false;
1035 case LTTNG_ACTION_TYPE_GROUP:
1036 case LTTNG_ACTION_TYPE_UNKNOWN:
1037 default:
1038 abort();
1039 }
1040}
1041
1042static
1043bool action_needs_tracer_notifier(const struct lttng_action *action)
1044{
1045 bool needs_tracer_notifier = false;
1046 unsigned int i, count;
1047 enum lttng_action_status action_status;
1048 enum lttng_action_type action_type;
1049
1050 assert(action);
1051 /* If there is only one action. Check if it needs a tracer notifier. */
1052 action_type = lttng_action_get_type(action);
1053 if (action_type != LTTNG_ACTION_TYPE_GROUP) {
1054 needs_tracer_notifier = action_type_needs_tracer_notifier(
1055 action_type);
1056 goto end;
1057 }
1058
1059 /*
1060 * Iterate over all the actions of the action group and check if any of
1061 * them needs a tracer notifier.
1062 */
1063 action_status = lttng_action_group_get_count(action, &count);
1064 assert(action_status == LTTNG_ACTION_STATUS_OK);
1065 for (i = 0; i < count; i++) {
1066 const struct lttng_action *inner_action =
1067 lttng_action_group_get_at_index(action, i);
1068
1069 action_type = lttng_action_get_type(inner_action);
1070 if (action_type_needs_tracer_notifier(action_type)) {
1071 needs_tracer_notifier = true;
1072 goto end;
1073 }
1074 }
1075
1076end:
1077 return needs_tracer_notifier;
1078}
1079
1080LTTNG_HIDDEN
1081bool lttng_trigger_needs_tracer_notifier(const struct lttng_trigger *trigger)
1082{
1083 bool needs_tracer_notifier = false;
1084 const struct lttng_condition *condition =
1085 lttng_trigger_get_const_condition(trigger);
1086 const struct lttng_action *action =
1087 lttng_trigger_get_const_action(trigger);
1088
1089 switch (lttng_condition_get_type(condition)) {
1090 case LTTNG_CONDITION_TYPE_ON_EVENT:
1091 needs_tracer_notifier = action_needs_tracer_notifier(action);
1092 goto end;
1093 case LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE:
1094 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH:
1095 case LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW:
1096 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_ONGOING:
1097 case LTTNG_CONDITION_TYPE_SESSION_ROTATION_COMPLETED:
1098 goto end;
1099 case LTTNG_CONDITION_TYPE_UNKNOWN:
1100 default:
1101 abort();
1102 }
1103end:
1104 return needs_tracer_notifier;
1105}
This page took 0.094599 seconds and 5 git commands to generate.