SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / common / trigger.c
1 /*
2 * Copyright (C) 2017 Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <lttng/trigger/trigger-internal.h>
9 #include <lttng/condition/condition-internal.h>
10 #include <lttng/condition/on-event-internal.h>
11 #include <lttng/condition/on-event.h>
12 #include <lttng/condition/on-event-internal.h>
13 #include <lttng/condition/buffer-usage.h>
14 #include <lttng/event-rule/event-rule-internal.h>
15 #include <lttng/event-expr-internal.h>
16 #include <lttng/action/action-internal.h>
17 #include <lttng/action/group.h>
18 #include <common/credentials.h>
19 #include <common/payload.h>
20 #include <common/payload-view.h>
21 #include <lttng/domain.h>
22 #include <common/error.h>
23 #include <common/dynamic-array.h>
24 #include <common/optional.h>
25 #include <assert.h>
26 #include <inttypes.h>
27
28 LTTNG_HIDDEN
29 bool lttng_trigger_validate(const struct lttng_trigger *trigger)
30 {
31 bool valid;
32
33 if (!trigger) {
34 valid = false;
35 goto end;
36 }
37
38 if (!trigger->creds.uid.is_set) {
39 valid = false;
40 goto end;
41 }
42
43 valid = lttng_condition_validate(trigger->condition) &&
44 lttng_action_validate(trigger->action);
45 end:
46 return valid;
47 }
48
49 struct 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
64 urcu_ref_init(&trigger->ref);
65
66 trigger->firing_policy.type = LTTNG_TRIGGER_FIRING_POLICY_EVERY_N;
67 trigger->firing_policy.threshold = 1;
68
69 lttng_condition_get(condition);
70 trigger->condition = condition;
71
72 lttng_action_get(action);
73 trigger->action = action;
74
75 end:
76 return trigger;
77 }
78
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 */
84 struct lttng_condition *lttng_trigger_get_condition(
85 struct lttng_trigger *trigger)
86 {
87 return trigger ? trigger->condition : NULL;
88 }
89
90 const struct lttng_condition *lttng_trigger_get_const_condition(
91 const struct lttng_trigger *trigger)
92 {
93 return trigger ? trigger->condition : NULL;
94 }
95
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 */
101 struct lttng_action *lttng_trigger_get_action(
102 struct lttng_trigger *trigger)
103 {
104 return trigger ? trigger->action : NULL;
105 }
106
107 const struct lttng_action *lttng_trigger_get_const_action(
108 const struct lttng_trigger *trigger)
109 {
110 return trigger ? trigger->action : NULL;
111 }
112
113 static void trigger_destroy_ref(struct urcu_ref *ref)
114 {
115 struct lttng_trigger *trigger =
116 container_of(ref, struct lttng_trigger, ref);
117 struct lttng_action *action = lttng_trigger_get_action(trigger);
118 struct lttng_condition *condition =
119 lttng_trigger_get_condition(trigger);
120
121 assert(action);
122 assert(condition);
123
124 /* Release ownership. */
125 lttng_action_put(action);
126 lttng_condition_put(condition);
127
128 free(trigger->name);
129 free(trigger);
130 }
131
132 void lttng_trigger_destroy(struct lttng_trigger *trigger)
133 {
134 lttng_trigger_put(trigger);
135 }
136
137 static 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
154 LTTNG_HIDDEN
155 ssize_t lttng_trigger_create_from_payload(
156 struct lttng_payload_view *src_view,
157 struct lttng_trigger **_trigger)
158 {
159 ssize_t ret, offset = 0, condition_size, action_size, name_size = 0;
160 struct lttng_condition *condition = NULL;
161 struct lttng_action *action = NULL;
162 const struct lttng_trigger_comm *trigger_comm;
163 const char *name = NULL;
164 uint64_t firing_policy_threshold;
165 enum lttng_trigger_firing_policy firing_policy;
166 struct lttng_credentials creds = {
167 .uid = LTTNG_OPTIONAL_INIT_UNSET,
168 .gid = LTTNG_OPTIONAL_INIT_UNSET,
169 };
170 struct lttng_trigger *trigger = NULL;
171 const struct lttng_payload_view trigger_comm_view =
172 lttng_payload_view_from_view(
173 src_view, 0, sizeof(*trigger_comm));
174
175 if (!src_view || !_trigger) {
176 ret = -1;
177 goto end;
178 }
179
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
186 /* lttng_trigger_comm header */
187 trigger_comm = (typeof(trigger_comm)) trigger_comm_view.buffer.data;
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
198 offset += sizeof(*trigger_comm);
199
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;
207 if (trigger_comm->name_length != 0) {
208 /* Name. */
209 const struct lttng_payload_view name_view =
210 lttng_payload_view_from_view(
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 }
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
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 }
239
240 if (condition_size < 0) {
241 ret = condition_size;
242 goto end;
243 }
244
245 offset += condition_size;
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 }
254
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. */
262 if ((ssize_t) trigger_comm->length != condition_size + action_size + name_size) {
263 ret = -1;
264 goto error;
265 }
266
267 trigger = lttng_trigger_create(condition, action);
268 if (!trigger) {
269 ret = -1;
270 goto error;
271 }
272
273 lttng_trigger_set_credentials(trigger, &creds);
274
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
285 if (name) {
286 const enum lttng_trigger_status status =
287 lttng_trigger_set_name(trigger, name);
288
289 if (status != LTTNG_TRIGGER_STATUS_OK) {
290 ret = -1;
291 goto end;
292 }
293 }
294
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
308 ret = offset;
309
310 error:
311 lttng_condition_put(condition);
312 lttng_action_put(action);
313 end:
314 if (ret >= 0) {
315 *_trigger = trigger;
316 } else {
317 lttng_trigger_put(trigger);
318 }
319
320 return ret;
321 }
322
323 /*
324 * Both elements are stored contiguously, see their "*_comm" structure
325 * for the detailed format.
326 */
327 LTTNG_HIDDEN
328 int lttng_trigger_serialize(const struct lttng_trigger *trigger,
329 struct lttng_payload *payload)
330 {
331 int ret;
332 size_t header_offset, size_before_payload, size_name;
333 struct lttng_trigger_comm trigger_comm = {};
334 struct lttng_trigger_comm *header;
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);
341
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;
349 trigger_comm.firing_policy_type = (uint8_t) trigger->firing_policy.type;
350 trigger_comm.firing_policy_threshold = (uint64_t) trigger->firing_policy.threshold;
351
352 header_offset = payload->buffer.size;
353 ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
354 sizeof(trigger_comm));
355 if (ret) {
356 goto end;
357 }
358
359 size_before_payload = payload->buffer.size;
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
368 ret = lttng_condition_serialize(trigger->condition, payload);
369 if (ret) {
370 goto end;
371 }
372
373 ret = lttng_action_serialize(trigger->action, payload);
374 if (ret) {
375 goto end;
376 }
377
378 /* Update payload size. */
379 header = (typeof(header)) (payload->buffer.data + header_offset);
380 header->length = payload->buffer.size - size_before_payload;
381 end:
382 return ret;
383 }
384
385 LTTNG_HIDDEN
386 bool lttng_trigger_is_equal(
387 const struct lttng_trigger *a, const struct lttng_trigger *b)
388 {
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
397 /*
398 * FIXME: frdeso: this is a change of behavior.
399 * See internal tracker issue 1028.
400 */
401 if (strcmp(a->name, b->name) != 0) {
402 return false;
403 }
404
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
421 enum 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;
443 end:
444 return status;
445 }
446
447 enum 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;
462 end:
463 return status;
464 }
465
466 LTTNG_HIDDEN
467 int 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 }
479 end:
480 return ret;
481 }
482
483 LTTNG_HIDDEN
484 void 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
491 LTTNG_HIDDEN
492 uint64_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
499 LTTNG_HIDDEN
500 int 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;
516 end:
517 return ret;
518 }
519
520 LTTNG_HIDDEN
521 void lttng_trigger_get(struct lttng_trigger *trigger)
522 {
523 urcu_ref_get(&trigger->ref);
524 }
525
526 LTTNG_HIDDEN
527 void 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
536 static void delete_trigger_array_element(void *ptr)
537 {
538 struct lttng_trigger *trigger = ptr;
539
540 lttng_trigger_put(trigger);
541 }
542
543 LTTNG_HIDDEN
544 struct 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
555 end:
556 return triggers;
557 }
558
559 LTTNG_HIDDEN
560 struct 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);
573 end:
574 return trigger;
575 }
576
577 LTTNG_HIDDEN
578 int 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
596 const 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
602 enum 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);
612 end:
613 return status;
614 }
615
616 void 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
626 int 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;
669 end:
670 return ret;
671 }
672
673 LTTNG_HIDDEN
674 ssize_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;
734 error:
735
736 lttng_triggers_destroy(local_triggers);
737 return ret;
738 }
739
740 LTTNG_HIDDEN
741 const struct lttng_credentials *lttng_trigger_get_credentials(
742 const struct lttng_trigger *trigger)
743 {
744 return &trigger->creds;
745 }
746
747 LTTNG_HIDDEN
748 void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
749 const struct lttng_credentials *creds)
750 {
751 assert(creds);
752 trigger->creds = *creds;
753 }
754
755 enum 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
777 end:
778 return ret;
779 }
780
781 enum 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
800 end:
801 return ret;
802 }
803
804 enum 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
820 end:
821 return ret;
822 }
823
824 enum 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
839 end:
840 return status;
841 }
842
843 LTTNG_HIDDEN
844 bool 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
868 LTTNG_HIDDEN
869 void 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 }
894
895 LTTNG_HIDDEN
896 enum 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;
917 case LTTNG_CONDITION_TYPE_ON_EVENT:
918 /* Return the domain of the event rule. */
919 c_status = lttng_condition_on_event_get_rule(
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 }
937
938 /*
939 * Generate bytecode related to the trigger.
940 * On success LTTNG_OK. On error, returns lttng_error code.
941 */
942 LTTNG_HIDDEN
943 enum 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)) {
957 case LTTNG_CONDITION_TYPE_ON_EVENT:
958 {
959 struct lttng_event_rule *event_rule;
960 const enum lttng_condition_status condition_status =
961 lttng_condition_on_event_borrow_rule_mutable(
962 condition, &event_rule);
963
964 assert(condition_status == LTTNG_CONDITION_STATUS_OK);
965
966 /* Generate the filter bytecode. */
967 ret = lttng_event_rule_generate_filter_bytecode(
968 event_rule, creds);
969 if (ret != LTTNG_OK) {
970 goto end;
971 }
972
973 /* Generate the capture bytecode. */
974 ret = lttng_condition_on_event_generate_capture_descriptor_bytecode(
975 condition);
976 if (ret != LTTNG_OK) {
977 goto end;
978 }
979
980 ret = LTTNG_OK;
981 break;
982 }
983 default:
984 ret = LTTNG_OK;
985 break;
986 }
987 end:
988 return ret;
989 }
990
991 LTTNG_HIDDEN
992 struct 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
1017 end:
1018 lttng_payload_reset(&copy_buffer);
1019 return copy;
1020 }
1021
1022
1023 static
1024 bool 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
1042 static
1043 bool 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
1076 end:
1077 return needs_tracer_notifier;
1078 }
1079
1080 LTTNG_HIDDEN
1081 bool 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 }
1103 end:
1104 return needs_tracer_notifier;
1105 }
This page took 0.078493 seconds and 5 git commands to generate.