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
,
354 counter
->value
= value
;
357 lttng_error_query_result_destroy(&counter
->parent
);
359 return counter
? &counter
->parent
: NULL
;
363 void destroy_result(void *ptr
)
365 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
367 lttng_error_query_result_destroy(result
);
371 struct lttng_error_query_results
*lttng_error_query_results_create(void)
373 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
376 PERROR("Failed to allocate an error query result set");
380 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
386 int lttng_error_query_results_add_result(
387 struct lttng_error_query_results
*results
,
388 struct lttng_error_query_result
*result
)
390 return lttng_dynamic_pointer_array_add_pointer(
391 &results
->results
, result
);
395 ssize_t
lttng_error_query_result_create_from_payload(
396 struct lttng_payload_view
*view
,
397 struct lttng_error_query_result
**result
)
399 ssize_t used_size
= 0;
400 struct lttng_error_query_result_comm
*header
;
401 struct lttng_payload_view header_view
=
402 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
404 const char *description
;
406 if (!lttng_payload_view_is_valid(&header_view
)) {
411 header
= (typeof(header
)) header_view
.buffer
.data
;
412 used_size
+= sizeof(*header
);
415 struct lttng_payload_view name_view
=
416 lttng_payload_view_from_view(view
, used_size
,
419 if (!lttng_payload_view_is_valid(&name_view
) ||
420 !lttng_buffer_view_contains_string(
422 name_view
.buffer
.data
,
428 name
= name_view
.buffer
.data
;
429 used_size
+= header
->name_len
;
433 struct lttng_payload_view description_view
=
434 lttng_payload_view_from_view(view
, used_size
,
435 header
->description_len
);
437 if (!lttng_payload_view_is_valid(&description_view
) ||
438 !lttng_buffer_view_contains_string(
439 &description_view
.buffer
,
440 description_view
.buffer
.data
,
441 header
->description_len
)) {
446 description
= description_view
.buffer
.data
;
447 used_size
+= header
->description_len
;
450 switch (header
->type
) {
451 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
453 struct lttng_error_query_result_counter_comm
*counter
;
454 struct lttng_payload_view counter_payload_view
=
455 lttng_payload_view_from_view(view
, used_size
,
458 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
463 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
464 *result
= lttng_error_query_result_counter_create(
465 name
, description
, counter
->value
);
471 used_size
+= sizeof(*counter
);
484 int lttng_error_query_results_serialize(
485 const struct lttng_error_query_results
*results
,
486 struct lttng_payload
*payload
)
490 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
492 const struct lttng_error_query_results_comm header
= {
493 .count
= (typeof(header
.count
)) result_count
,
497 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
499 ERR("Failed to append error query result set header to payload");
504 for (result_index
= 0; result_index
< result_count
; result_index
++) {
505 const struct lttng_error_query_result
*result
= (typeof(result
))
506 lttng_dynamic_pointer_array_get_pointer(
510 ret
= lttng_error_query_result_serialize(result
, payload
);
512 ERR("Failed to append error query result to payload");
521 ssize_t
lttng_error_query_results_create_from_payload(
522 struct lttng_payload_view
*view
,
523 struct lttng_error_query_results
**_results
)
526 ssize_t total_used_size
= 0;
527 struct lttng_error_query_results_comm
*header
;
528 struct lttng_payload_view header_view
=
529 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
530 struct lttng_error_query_results
*results
= NULL
;
532 if (!lttng_payload_view_is_valid(&header_view
)) {
533 ERR("Failed to map view to error query result set header");
534 total_used_size
= -1;
538 header
= (typeof(header
)) header_view
.buffer
.data
;
539 total_used_size
+= sizeof(*header
);
540 results
= lttng_error_query_results_create();
542 total_used_size
= -1;
546 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
548 struct lttng_error_query_result
*result
;
549 struct lttng_payload_view result_view
=
550 lttng_payload_view_from_view(
551 view
, total_used_size
, -1);
553 if (!lttng_payload_view_is_valid(&result_view
)) {
554 total_used_size
= -1;
558 used_size
= lttng_error_query_result_create_from_payload(
559 &result_view
, &result
);
561 total_used_size
= -1;
565 total_used_size
+= used_size
;
567 if (lttng_dynamic_pointer_array_add_pointer(
568 &results
->results
, result
)) {
569 lttng_error_query_result_destroy(result
);
570 total_used_size
= -1;
578 lttng_error_query_results_destroy(results
);
579 return total_used_size
;
583 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
584 struct lttng_payload
*payload
)
587 const struct lttng_error_query_trigger
*query_trigger
=
588 container_of(query
, typeof(*query_trigger
), parent
);
590 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
595 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
605 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
606 struct lttng_payload
*payload
)
609 const struct lttng_error_query_action
*query_action
=
610 container_of(query
, typeof(*query_action
), parent
);
611 struct lttng_error_query_action_comm header
= {
612 .action_index
.is_set
= query_action
->action_index
.is_set
,
613 .action_index
.value
= query_action
->action_index
.value
,
616 if (!lttng_trigger_validate(query_action
->trigger
)) {
621 ret
= lttng_dynamic_buffer_append(
622 &payload
->buffer
, &header
, sizeof(header
));
627 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
636 enum lttng_error_query_target_type
lttng_error_query_get_target_type(
637 const struct lttng_error_query
*query
)
639 return query
->target_type
;
643 const struct lttng_trigger
*lttng_error_query_trigger_borrow_target(
644 const struct lttng_error_query
*query
)
646 const struct lttng_error_query_trigger
*query_trigger
=
647 container_of(query
, typeof(*query_trigger
), parent
);
649 return query_trigger
->trigger
;
653 const struct lttng_trigger
*lttng_error_query_action_borrow_trigger_target(
654 const struct lttng_error_query
*query
)
656 const struct lttng_error_query_action
*query_action
=
657 container_of(query
, typeof(*query_action
), parent
);
659 return query_action
->trigger
;
663 struct lttng_action
*lttng_error_query_action_borrow_action_target(
664 const struct lttng_error_query
*query
,
665 struct lttng_trigger
*trigger
)
667 struct lttng_action
*target_action
= NULL
;
668 const struct lttng_error_query_action
*query_action
=
669 container_of(query
, typeof(*query_action
), parent
);
670 struct lttng_action
*trigger_action
=
671 lttng_trigger_get_action(trigger
);
673 if (!query_action
->action_index
.is_set
) {
674 target_action
= trigger_action
;
676 if (lttng_action_get_type(trigger_action
) !=
677 LTTNG_ACTION_TYPE_GROUP
) {
678 ERR("Invalid action error query target index: trigger action is not a group");
682 target_action
= lttng_action_group_borrow_mutable_at_index(
684 LTTNG_OPTIONAL_GET(query_action
->action_index
));
688 return target_action
;
692 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
693 struct lttng_payload
*payload
)
696 struct lttng_error_query_comm header
= {
697 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
700 ret
= lttng_dynamic_buffer_append(
701 &payload
->buffer
, &header
, sizeof(header
));
703 ERR("Failed to append error query header to payload");
707 switch (query
->target_type
) {
708 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
709 ret
= lttng_error_query_trigger_serialize(query
, payload
);
715 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
716 ret
= lttng_error_query_action_serialize(query
, payload
);
730 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
731 struct lttng_error_query
**query
)
733 ssize_t used_size
= 0;
734 struct lttng_error_query_comm
*header
;
735 struct lttng_payload_view header_view
=
736 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
738 if (!lttng_payload_view_is_valid(&header_view
)) {
739 ERR("Failed to map error query header");
744 used_size
= sizeof(*header
);
746 header
= (typeof(header
)) header_view
.buffer
.data
;
747 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
748 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
750 struct lttng_trigger
*trigger
;
751 ssize_t trigger_used_size
;
752 struct lttng_payload_view trigger_view
=
753 lttng_payload_view_from_view(
754 view
, used_size
, -1);
756 if (!lttng_payload_view_is_valid(&trigger_view
)) {
761 trigger_used_size
= lttng_trigger_create_from_payload(
762 &trigger_view
, &trigger
);
763 if (trigger_used_size
< 0) {
768 used_size
+= trigger_used_size
;
770 *query
= lttng_error_query_trigger_create(trigger
);
771 lttng_trigger_put(trigger
);
779 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
781 struct lttng_trigger
*trigger
;
782 const struct lttng_action
*target_action
;
783 ssize_t trigger_used_size
;
784 struct lttng_error_query_action_comm
*action_header
;
787 struct lttng_payload_view action_header_view
=
788 lttng_payload_view_from_view(view
,
790 sizeof(*action_header
));
792 if (!lttng_payload_view_is_valid(&action_header_view
)) {
797 action_header
= (typeof(action_header
)) action_header_view
.buffer
.data
;
798 used_size
+= sizeof(*action_header
);
802 struct lttng_payload_view trigger_view
=
803 lttng_payload_view_from_view(
804 view
, used_size
, -1);
806 if (!lttng_payload_view_is_valid(&trigger_view
)) {
811 trigger_used_size
= lttng_trigger_create_from_payload(
812 &trigger_view
, &trigger
);
813 if (trigger_used_size
< 0) {
818 used_size
+= trigger_used_size
;
821 if (!action_header
->action_index
.is_set
) {
822 target_action
= trigger
->action
;
824 if (lttng_action_get_type(trigger
->action
) !=
825 LTTNG_ACTION_TYPE_GROUP
) {
830 target_action
= lttng_action_group_get_at_index(
832 action_header
->action_index
.value
);
835 *query
= lttng_error_query_action_create(
836 trigger
, target_action
);
837 lttng_trigger_put(trigger
);
854 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
855 const struct lttng_error_query_results
*results
,
858 enum lttng_error_query_results_status status
;
860 if (!results
|| !count
) {
861 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
865 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
866 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
871 enum lttng_error_query_results_status
872 lttng_error_query_results_get_result(
873 const struct lttng_error_query_results
*results
,
874 const struct lttng_error_query_result
**result
,
877 unsigned int result_count
;
878 enum lttng_error_query_results_status status
;
880 if (!results
|| !result
) {
881 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
885 status
= lttng_error_query_results_get_count(results
, &result_count
);
886 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
890 if (index
>= result_count
) {
891 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
895 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
896 &results
->results
, index
);
898 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
903 void lttng_error_query_results_destroy(
904 struct lttng_error_query_results
*results
)
910 lttng_dynamic_pointer_array_reset(&results
->results
);
914 enum lttng_error_query_result_type
915 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
917 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
920 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
921 const struct lttng_error_query_result
*result
,
924 enum lttng_error_query_result_status status
;
926 if (!result
|| !name
) {
927 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
931 *name
= result
->name
;
932 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
937 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
938 const struct lttng_error_query_result
*result
,
939 const char **description
)
941 enum lttng_error_query_result_status status
;
943 if (!result
|| !description
) {
944 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
948 *description
= result
->description
;
949 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
954 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
955 const struct lttng_error_query_result
*result
,
958 enum lttng_error_query_result_status status
;
959 const struct lttng_error_query_result_counter
*counter_result
;
961 if (!result
|| !value
||
962 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
963 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
967 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
969 *value
= counter_result
->value
;
970 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;