4 * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
6 * SPDX-License-Identifier: GPL-2.1-only
10 #include <common/dynamic-array.h>
11 #include <common/error.h>
12 #include <common/macros.h>
13 #include <common/sessiond-comm/sessiond-comm.h>
14 #include <lttng/action/action-internal.h>
15 #include <lttng/action/group-internal.h>
16 #include <lttng/error-query-internal.h>
17 #include <lttng/error-query.h>
18 #include <lttng/trigger/trigger-internal.h>
21 struct lttng_error_query
{
22 enum lttng_error_query_target_type target_type
;
25 struct lttng_error_query_comm
{
26 /* enum lttng_error_query_target_type */
28 /* Target-specific payload. */
32 struct lttng_error_query_trigger
{
33 struct lttng_error_query parent
;
34 /* Mutable only because of the reference count. */
35 struct lttng_trigger
*trigger
;
38 struct lttng_error_query_action_comm
{
39 LTTNG_OPTIONAL_COMM(uint32_t) action_index
;
40 /* Trigger payload. */
44 struct lttng_error_query_action
{
45 struct lttng_error_query parent
;
46 /* Mutable only because of the reference count. */
47 struct lttng_trigger
*trigger
;
49 * Index of the target action. Since action lists can't be nested,
50 * the targetted action is the top-level group if the action_index is
51 * unset. Otherwise, the index refers to the index within the top-level
54 LTTNG_OPTIONAL(unsigned int) action_index
;
57 struct lttng_error_query_result
{
58 enum lttng_error_query_result_type type
;
63 struct lttng_error_query_result_comm
{
64 /* enum lttng_error_query_result_type */
66 /* Length of name (including null-terminator). */
68 /* Length of description (including null-terminator). */
69 uint32_t description_len
;
70 /* Name, description, and type-specific payload follow. */
74 struct lttng_error_query_result_counter_comm
{
78 struct lttng_error_query_result_counter
{
79 struct lttng_error_query_result parent
;
83 struct lttng_error_query_results_comm
{
85 /* `count` instances of `struct lttng_error_query_result` follow. */
89 struct lttng_error_query_results
{
90 struct lttng_dynamic_pointer_array results
;
94 struct lttng_error_query
*lttng_error_query_trigger_create(
95 const struct lttng_trigger
*trigger
)
97 struct lttng_error_query_trigger
*query
= NULL
;
98 struct lttng_trigger
*trigger_copy
;
100 trigger_copy
= lttng_trigger_copy(trigger
);
109 query
= zmalloc(sizeof(*query
));
111 PERROR("Failed to allocate trigger error query");
115 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
;
116 query
->trigger
= trigger_copy
;
118 return query
? &query
->parent
: NULL
;
121 extern struct lttng_error_query
*lttng_error_query_action_create(
122 const struct lttng_trigger
*trigger
,
123 const struct lttng_action
*action
)
125 struct lttng_error_query_action
*query
= NULL
;
126 typeof(query
->action_index
) action_index
;
127 struct lttng_trigger
*trigger_copy
;
129 if (!trigger
|| !action
) {
133 trigger_copy
= lttng_trigger_copy(trigger
);
139 * If an action is not the top-level action of the trigger, our only
140 * hope of finding its position is if the top-level action is an
143 * Note that action comparisons are performed by pointer since multiple
144 * otherwise identical actions can be found in an action group (two
145 * notify actions, for example).
147 if (action
!= trigger
->action
&&
148 lttng_action_get_type(trigger
->action
) ==
149 LTTNG_ACTION_TYPE_GROUP
) {
150 unsigned int i
, action_group_count
;
151 enum lttng_action_status action_status
;
153 action_status
= lttng_action_group_get_count(
154 trigger
->action
, &action_group_count
);
155 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
159 for (i
= 0; i
< action_group_count
; i
++) {
160 const struct lttng_action
*candidate_action
=
161 lttng_action_group_get_at_index(
164 assert(candidate_action
);
165 if (candidate_action
== action
) {
166 LTTNG_OPTIONAL_SET(&action_index
, i
);
171 if (!action_index
.is_set
) {
172 /* Not found; invalid action. */
177 * Trigger action is not a group and not equal to the target
178 * action; invalid action provided.
183 query
= zmalloc(sizeof(*query
));
185 PERROR("Failed to allocate action error query");
189 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
;
190 query
->trigger
= trigger_copy
;
191 query
->action_index
= action_index
;
193 return query
? &query
->parent
: NULL
;
196 void lttng_error_query_destroy(struct lttng_error_query
*query
)
198 struct lttng_error_query_trigger
*trigger_query
;
204 trigger_query
= container_of(query
, typeof(*trigger_query
), parent
);
205 lttng_trigger_put(trigger_query
->trigger
);
210 int lttng_error_query_result_counter_serialize(
211 const struct lttng_error_query_result
*result
,
212 struct lttng_payload
*payload
)
214 const struct lttng_error_query_result_counter
*counter_result
;
216 assert(result
->type
== LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
);
217 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
219 return lttng_dynamic_buffer_append(&payload
->buffer
,
220 &(struct lttng_error_query_result_counter_comm
) {
221 .value
= counter_result
->value
223 sizeof(struct lttng_error_query_result_counter_comm
));
227 int lttng_error_query_result_serialize(
228 const struct lttng_error_query_result
*result
,
229 struct lttng_payload
*payload
)
232 struct lttng_error_query_result_comm header
= {
233 .type
= (uint8_t) result
->type
,
234 .name_len
= (typeof(header
.name_len
)) strlen(result
->name
) + 1,
235 .description_len
= (typeof(header
.name_len
)) strlen(result
->description
) + 1,
239 ret
= lttng_dynamic_buffer_append(
240 &payload
->buffer
, &header
, sizeof(header
));
242 ERR("Failed to append error query result communication header to payload");
247 ret
= lttng_dynamic_buffer_append(
248 &payload
->buffer
, result
->name
, header
.name_len
);
250 ERR("Failed to append error query result name to payload");
255 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, result
->description
,
256 header
.description_len
);
258 ERR("Failed to append error query result description to payload");
262 /* Type-specific payload. */
263 switch (result
->type
) {
264 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
265 ret
= lttng_error_query_result_counter_serialize(
268 ERR("Failed to serialize counter error query result");
281 int lttng_error_query_result_init(
282 struct lttng_error_query_result
*result
,
283 enum lttng_error_query_result_type result_type
,
285 const char *description
)
292 result
->type
= result_type
;
294 result
->name
= strdup(name
);
296 PERROR("Failed to copy error query result name");
301 result
->description
= strdup(description
);
302 if (!result
->description
) {
303 PERROR("Failed to copy error query result description");
314 void lttng_error_query_result_destroy(struct lttng_error_query_result
*counter
)
320 switch (counter
->type
) {
321 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
322 /* Nothing to tear down. */
329 free(counter
->description
);
334 struct lttng_error_query_result
*
335 lttng_error_query_result_counter_create(
336 const char *name
, const char *description
, uint64_t value
)
339 struct lttng_error_query_result_counter
*counter
;
341 counter
= zmalloc(sizeof(*counter
));
343 PERROR("Failed to allocate error query counter result");
347 init_ret
= lttng_error_query_result_init(&counter
->parent
,
348 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
, name
,
356 lttng_error_query_result_destroy(&counter
->parent
);
358 return counter
? &counter
->parent
: NULL
;
362 void destroy_result(void *ptr
)
364 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
366 lttng_error_query_result_destroy(result
);
370 struct lttng_error_query_results
*lttng_error_query_results_create(void)
372 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
375 PERROR("Failed to allocate an error query result set");
379 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
385 int lttng_error_query_results_add_result(
386 struct lttng_error_query_results
*results
,
387 struct lttng_error_query_result
*result
)
389 return lttng_dynamic_pointer_array_add_pointer(
390 &results
->results
, result
);
394 ssize_t
lttng_error_query_result_create_from_payload(
395 struct lttng_payload_view
*view
,
396 struct lttng_error_query_result
**result
)
398 ssize_t used_size
= 0;
399 struct lttng_error_query_result_comm
*header
;
400 struct lttng_payload_view header_view
=
401 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
403 const char *description
;
405 if (!lttng_payload_view_is_valid(&header_view
)) {
410 header
= (typeof(header
)) header_view
.buffer
.data
;
411 used_size
+= sizeof(*header
);
414 struct lttng_payload_view name_view
=
415 lttng_payload_view_from_view(view
, used_size
,
418 if (!lttng_payload_view_is_valid(&name_view
) ||
419 !lttng_buffer_view_contains_string(
421 name_view
.buffer
.data
,
427 name
= name_view
.buffer
.data
;
428 used_size
+= header
->name_len
;
432 struct lttng_payload_view description_view
=
433 lttng_payload_view_from_view(view
, used_size
,
434 header
->description_len
);
436 if (!lttng_payload_view_is_valid(&description_view
) ||
437 !lttng_buffer_view_contains_string(
438 &description_view
.buffer
,
439 description_view
.buffer
.data
,
440 header
->description_len
)) {
445 description
= description_view
.buffer
.data
;
446 used_size
+= header
->description_len
;
449 switch (header
->type
) {
450 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
452 struct lttng_error_query_result_counter_comm
*counter
;
453 struct lttng_payload_view counter_payload_view
=
454 lttng_payload_view_from_view(view
, used_size
,
457 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
462 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
463 *result
= lttng_error_query_result_counter_create(
464 name
, description
, counter
->value
);
470 used_size
+= sizeof(*counter
);
483 int lttng_error_query_results_serialize(
484 const struct lttng_error_query_results
*results
,
485 struct lttng_payload
*payload
)
489 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
491 const struct lttng_error_query_results_comm header
= {
492 .count
= (typeof(header
.count
)) result_count
,
496 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
498 ERR("Failed to append error query result set header to payload");
503 for (result_index
= 0; result_index
< result_count
; result_index
++) {
504 const struct lttng_error_query_result
*result
= (typeof(result
))
505 lttng_dynamic_pointer_array_get_pointer(
509 ret
= lttng_error_query_result_serialize(result
, payload
);
511 ERR("Failed to append error query result to payload");
520 ssize_t
lttng_error_query_results_create_from_payload(
521 struct lttng_payload_view
*view
,
522 struct lttng_error_query_results
**_results
)
525 ssize_t total_used_size
= 0;
526 struct lttng_error_query_results_comm
*header
;
527 struct lttng_payload_view header_view
=
528 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
529 struct lttng_error_query_results
*results
= NULL
;
531 if (!lttng_payload_view_is_valid(&header_view
)) {
532 ERR("Failed to map view to error query result set header");
533 total_used_size
= -1;
537 header
= (typeof(header
)) header_view
.buffer
.data
;
538 total_used_size
+= sizeof(*header
);
539 results
= lttng_error_query_results_create();
541 total_used_size
= -1;
545 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
547 struct lttng_error_query_result
*result
;
548 struct lttng_payload_view result_view
=
549 lttng_payload_view_from_view(
550 view
, total_used_size
, -1);
552 if (!lttng_payload_view_is_valid(&result_view
)) {
553 total_used_size
= -1;
557 used_size
= lttng_error_query_result_create_from_payload(
558 &result_view
, &result
);
560 total_used_size
= -1;
564 total_used_size
+= used_size
;
566 if (lttng_dynamic_pointer_array_add_pointer(
567 &results
->results
, result
)) {
568 lttng_error_query_result_destroy(result
);
569 total_used_size
= -1;
577 lttng_error_query_results_destroy(results
);
578 return total_used_size
;
582 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
583 struct lttng_payload
*payload
)
586 const struct lttng_error_query_trigger
*query_trigger
=
587 container_of(query
, typeof(*query_trigger
), parent
);
589 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
594 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
604 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
605 struct lttng_payload
*payload
)
608 const struct lttng_error_query_action
*query_action
=
609 container_of(query
, typeof(*query_action
), parent
);
610 struct lttng_error_query_action_comm header
= {
611 .action_index
.is_set
= query_action
->action_index
.is_set
,
612 .action_index
.value
= query_action
->action_index
.value
,
615 if (!lttng_trigger_validate(query_action
->trigger
)) {
620 ret
= lttng_dynamic_buffer_append(
621 &payload
->buffer
, &header
, sizeof(header
));
626 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
635 enum lttng_error_query_target_type
lttng_error_query_get_target_type(
636 const struct lttng_error_query
*query
)
638 return query
->target_type
;
642 const struct lttng_trigger
*lttng_error_query_trigger_borrow_target(
643 const struct lttng_error_query
*query
)
645 const struct lttng_error_query_trigger
*query_trigger
=
646 container_of(query
, typeof(*query_trigger
), parent
);
648 return query_trigger
->trigger
;
652 const struct lttng_trigger
*lttng_error_query_action_borrow_trigger_target(
653 const struct lttng_error_query
*query
)
655 const struct lttng_error_query_action
*query_action
=
656 container_of(query
, typeof(*query_action
), parent
);
658 return query_action
->trigger
;
662 const struct lttng_action
*lttng_error_query_action_borrow_action_target(
663 const struct lttng_error_query
*query
,
664 const struct lttng_trigger
*trigger
)
666 const struct lttng_action
*target_action
= NULL
;
667 const struct lttng_error_query_action
*query_action
=
668 container_of(query
, typeof(*query_action
), parent
);
669 const struct lttng_action
*trigger_action
=
670 lttng_trigger_get_const_action(trigger
);
672 if (!query_action
->action_index
.is_set
) {
673 target_action
= trigger_action
;
675 if (lttng_action_get_type(trigger_action
) !=
676 LTTNG_ACTION_TYPE_GROUP
) {
677 ERR("Invalid action error query target index: trigger action is not a group");
681 target_action
= lttng_action_group_get_at_index(trigger_action
,
682 LTTNG_OPTIONAL_GET(query_action
->action_index
));
686 return target_action
;
690 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
691 struct lttng_payload
*payload
)
694 struct lttng_error_query_comm header
= {
695 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
698 ret
= lttng_dynamic_buffer_append(
699 &payload
->buffer
, &header
, sizeof(header
));
701 ERR("Failed to append error query header to payload");
705 switch (query
->target_type
) {
706 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
707 ret
= lttng_error_query_trigger_serialize(query
, payload
);
713 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
714 ret
= lttng_error_query_action_serialize(query
, payload
);
728 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
729 struct lttng_error_query
**query
)
731 ssize_t used_size
= 0;
732 struct lttng_error_query_comm
*header
;
733 struct lttng_payload_view header_view
=
734 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
736 if (!lttng_payload_view_is_valid(&header_view
)) {
737 ERR("Failed to map error query header");
742 used_size
= sizeof(*header
);
744 header
= (typeof(header
)) header_view
.buffer
.data
;
745 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
746 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
748 struct lttng_trigger
*trigger
;
749 ssize_t trigger_used_size
;
750 struct lttng_payload_view trigger_view
=
751 lttng_payload_view_from_view(
752 view
, used_size
, -1);
754 if (!lttng_payload_view_is_valid(&trigger_view
)) {
759 trigger_used_size
= lttng_trigger_create_from_payload(
760 &trigger_view
, &trigger
);
761 if (trigger_used_size
< 0) {
766 used_size
+= trigger_used_size
;
768 *query
= lttng_error_query_trigger_create(trigger
);
769 lttng_trigger_put(trigger
);
777 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
779 struct lttng_trigger
*trigger
;
780 const struct lttng_action
*target_action
;
781 ssize_t trigger_used_size
;
782 struct lttng_error_query_action_comm
*action_header
;
785 struct lttng_payload_view action_header_view
=
786 lttng_payload_view_from_view(view
,
788 sizeof(*action_header
));
790 if (!lttng_payload_view_is_valid(&action_header_view
)) {
795 action_header
= (typeof(action_header
)) action_header_view
.buffer
.data
;
796 used_size
+= sizeof(*action_header
);
800 struct lttng_payload_view trigger_view
=
801 lttng_payload_view_from_view(
802 view
, used_size
, -1);
804 if (!lttng_payload_view_is_valid(&trigger_view
)) {
809 trigger_used_size
= lttng_trigger_create_from_payload(
810 &trigger_view
, &trigger
);
811 if (trigger_used_size
< 0) {
816 used_size
+= trigger_used_size
;
819 if (!action_header
->action_index
.is_set
) {
820 target_action
= trigger
->action
;
822 if (lttng_action_get_type(trigger
->action
) !=
823 LTTNG_ACTION_TYPE_GROUP
) {
828 target_action
= lttng_action_group_get_at_index(
830 action_header
->action_index
.value
);
833 *query
= lttng_error_query_action_create(
834 trigger
, target_action
);
835 lttng_trigger_put(trigger
);
852 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
853 const struct lttng_error_query_results
*results
,
856 enum lttng_error_query_results_status status
;
858 if (!results
|| !count
) {
859 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
863 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
864 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
869 enum lttng_error_query_results_status
870 lttng_error_query_results_get_result(
871 const struct lttng_error_query_results
*results
,
872 const struct lttng_error_query_result
**result
,
875 unsigned int result_count
;
876 enum lttng_error_query_results_status status
;
878 if (!results
|| !result
) {
879 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
883 status
= lttng_error_query_results_get_count(results
, &result_count
);
884 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
888 if (index
>= result_count
) {
889 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
893 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
894 &results
->results
, index
);
896 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
901 void lttng_error_query_results_destroy(
902 struct lttng_error_query_results
*results
)
908 lttng_dynamic_pointer_array_reset(&results
->results
);
912 enum lttng_error_query_result_type
913 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
915 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
918 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
919 const struct lttng_error_query_result
*result
,
922 enum lttng_error_query_result_status status
;
924 if (!result
|| !name
) {
925 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
929 *name
= result
->name
;
930 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
935 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
936 const struct lttng_error_query_result
*result
,
937 const char **description
)
939 enum lttng_error_query_result_status status
;
941 if (!result
|| !description
) {
942 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
946 *description
= result
->description
;
947 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
952 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
953 const struct lttng_error_query_result
*result
,
956 enum lttng_error_query_result_status status
;
957 const struct lttng_error_query_result_counter
*counter_result
;
959 if (!result
|| !value
||
960 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
961 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
965 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
967 *value
= counter_result
->value
;
968 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;