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/list-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 list 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
= NULL
;
104 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
;
120 lttng_trigger_put(trigger_copy
);
122 return query
? &query
->parent
: NULL
;
125 extern struct lttng_error_query
*lttng_error_query_action_create(
126 const struct lttng_trigger
*trigger
,
127 const struct lttng_action
*action
)
129 struct lttng_error_query_action
*query
= NULL
;
130 typeof(query
->action_index
) action_index
= {};
131 struct lttng_trigger
*trigger_copy
= NULL
;
133 if (!trigger
|| !action
) {
137 trigger_copy
= lttng_trigger_copy(trigger
);
143 * If an action is not the top-level action of the trigger, our only
144 * hope of finding its position is if the top-level action is an
147 * Note that action comparisons are performed by pointer since multiple
148 * otherwise identical actions can be found in an action list (two
149 * notify actions, for example).
151 if (action
!= trigger
->action
&&
152 lttng_action_get_type(trigger
->action
) ==
153 LTTNG_ACTION_TYPE_LIST
) {
154 unsigned int i
, action_list_count
;
155 enum lttng_action_status action_status
;
157 action_status
= lttng_action_list_get_count(
158 trigger
->action
, &action_list_count
);
159 if (action_status
!= LTTNG_ACTION_STATUS_OK
) {
163 for (i
= 0; i
< action_list_count
; i
++) {
164 const struct lttng_action
*candidate_action
=
165 lttng_action_list_get_at_index(
168 assert(candidate_action
);
169 if (candidate_action
== action
) {
170 LTTNG_OPTIONAL_SET(&action_index
, i
);
175 if (!action_index
.is_set
) {
176 /* Not found; invalid action. */
181 * Trigger action is not a list and not equal to the target
182 * action; invalid action provided.
187 query
= zmalloc(sizeof(*query
));
189 PERROR("Failed to allocate action error query");
193 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
;
194 query
->trigger
= trigger_copy
;
196 query
->action_index
= action_index
;
198 lttng_trigger_put(trigger_copy
);
200 return query
? &query
->parent
: NULL
;
203 void lttng_error_query_destroy(struct lttng_error_query
*query
)
205 struct lttng_error_query_trigger
*trigger_query
;
211 trigger_query
= container_of(query
, typeof(*trigger_query
), parent
);
212 lttng_trigger_put(trigger_query
->trigger
);
217 int lttng_error_query_result_counter_serialize(
218 const struct lttng_error_query_result
*result
,
219 struct lttng_payload
*payload
)
221 const struct lttng_error_query_result_counter
*counter_result
;
223 assert(result
->type
== LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
);
224 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
226 return lttng_dynamic_buffer_append(&payload
->buffer
,
227 &(struct lttng_error_query_result_counter_comm
) {
228 .value
= counter_result
->value
230 sizeof(struct lttng_error_query_result_counter_comm
));
234 int lttng_error_query_result_serialize(
235 const struct lttng_error_query_result
*result
,
236 struct lttng_payload
*payload
)
239 struct lttng_error_query_result_comm header
= {
240 .type
= (uint8_t) result
->type
,
241 .name_len
= (typeof(header
.name_len
)) strlen(result
->name
) + 1,
242 .description_len
= (typeof(header
.name_len
)) strlen(result
->description
) + 1,
246 ret
= lttng_dynamic_buffer_append(
247 &payload
->buffer
, &header
, sizeof(header
));
249 ERR("Failed to append error query result communication header to payload");
254 ret
= lttng_dynamic_buffer_append(
255 &payload
->buffer
, result
->name
, header
.name_len
);
257 ERR("Failed to append error query result name to payload");
262 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, result
->description
,
263 header
.description_len
);
265 ERR("Failed to append error query result description to payload");
269 /* Type-specific payload. */
270 switch (result
->type
) {
271 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
272 ret
= lttng_error_query_result_counter_serialize(
275 ERR("Failed to serialize counter error query result");
288 int lttng_error_query_result_init(
289 struct lttng_error_query_result
*result
,
290 enum lttng_error_query_result_type result_type
,
292 const char *description
)
299 result
->type
= result_type
;
301 result
->name
= strdup(name
);
303 PERROR("Failed to copy error query result name");
308 result
->description
= strdup(description
);
309 if (!result
->description
) {
310 PERROR("Failed to copy error query result description");
321 void lttng_error_query_result_destroy(struct lttng_error_query_result
*counter
)
327 switch (counter
->type
) {
328 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
329 /* Nothing to tear down. */
336 free(counter
->description
);
341 struct lttng_error_query_result
*
342 lttng_error_query_result_counter_create(
343 const char *name
, const char *description
, uint64_t value
)
346 struct lttng_error_query_result_counter
*counter
;
348 counter
= zmalloc(sizeof(*counter
));
350 PERROR("Failed to allocate error query counter result");
354 init_ret
= lttng_error_query_result_init(&counter
->parent
,
355 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
, name
,
361 counter
->value
= value
;
364 lttng_error_query_result_destroy(&counter
->parent
);
366 return counter
? &counter
->parent
: NULL
;
370 void destroy_result(void *ptr
)
372 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
374 lttng_error_query_result_destroy(result
);
378 struct lttng_error_query_results
*lttng_error_query_results_create(void)
380 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
383 PERROR("Failed to allocate an error query result set");
387 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
393 int lttng_error_query_results_add_result(
394 struct lttng_error_query_results
*results
,
395 struct lttng_error_query_result
*result
)
397 return lttng_dynamic_pointer_array_add_pointer(
398 &results
->results
, result
);
402 ssize_t
lttng_error_query_result_create_from_payload(
403 struct lttng_payload_view
*view
,
404 struct lttng_error_query_result
**result
)
406 ssize_t used_size
= 0;
407 struct lttng_error_query_result_comm
*header
;
408 struct lttng_payload_view header_view
=
409 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
411 const char *description
;
413 if (!lttng_payload_view_is_valid(&header_view
)) {
418 header
= (typeof(header
)) header_view
.buffer
.data
;
419 used_size
+= sizeof(*header
);
422 struct lttng_payload_view name_view
=
423 lttng_payload_view_from_view(view
, used_size
,
426 if (!lttng_payload_view_is_valid(&name_view
) ||
427 !lttng_buffer_view_contains_string(
429 name_view
.buffer
.data
,
435 name
= name_view
.buffer
.data
;
436 used_size
+= header
->name_len
;
440 struct lttng_payload_view description_view
=
441 lttng_payload_view_from_view(view
, used_size
,
442 header
->description_len
);
444 if (!lttng_payload_view_is_valid(&description_view
) ||
445 !lttng_buffer_view_contains_string(
446 &description_view
.buffer
,
447 description_view
.buffer
.data
,
448 header
->description_len
)) {
453 description
= description_view
.buffer
.data
;
454 used_size
+= header
->description_len
;
457 switch (header
->type
) {
458 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
460 struct lttng_error_query_result_counter_comm
*counter
;
461 struct lttng_payload_view counter_payload_view
=
462 lttng_payload_view_from_view(view
, used_size
,
465 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
470 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
471 *result
= lttng_error_query_result_counter_create(
472 name
, description
, counter
->value
);
478 used_size
+= sizeof(*counter
);
491 int lttng_error_query_results_serialize(
492 const struct lttng_error_query_results
*results
,
493 struct lttng_payload
*payload
)
497 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
499 const struct lttng_error_query_results_comm header
= {
500 .count
= (typeof(header
.count
)) result_count
,
504 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
506 ERR("Failed to append error query result set header to payload");
511 for (result_index
= 0; result_index
< result_count
; result_index
++) {
512 const struct lttng_error_query_result
*result
= (typeof(result
))
513 lttng_dynamic_pointer_array_get_pointer(
517 ret
= lttng_error_query_result_serialize(result
, payload
);
519 ERR("Failed to append error query result to payload");
528 ssize_t
lttng_error_query_results_create_from_payload(
529 struct lttng_payload_view
*view
,
530 struct lttng_error_query_results
**_results
)
533 ssize_t total_used_size
= 0;
534 struct lttng_error_query_results_comm
*header
;
535 struct lttng_payload_view header_view
=
536 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
537 struct lttng_error_query_results
*results
= NULL
;
539 if (!lttng_payload_view_is_valid(&header_view
)) {
540 ERR("Failed to map view to error query result set header");
541 total_used_size
= -1;
545 header
= (typeof(header
)) header_view
.buffer
.data
;
546 total_used_size
+= sizeof(*header
);
547 results
= lttng_error_query_results_create();
549 total_used_size
= -1;
553 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
555 struct lttng_error_query_result
*result
;
556 struct lttng_payload_view result_view
=
557 lttng_payload_view_from_view(
558 view
, total_used_size
, -1);
560 if (!lttng_payload_view_is_valid(&result_view
)) {
561 total_used_size
= -1;
565 used_size
= lttng_error_query_result_create_from_payload(
566 &result_view
, &result
);
568 total_used_size
= -1;
572 total_used_size
+= used_size
;
574 if (lttng_dynamic_pointer_array_add_pointer(
575 &results
->results
, result
)) {
576 lttng_error_query_result_destroy(result
);
577 total_used_size
= -1;
585 lttng_error_query_results_destroy(results
);
586 return total_used_size
;
590 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
591 struct lttng_payload
*payload
)
594 const struct lttng_error_query_trigger
*query_trigger
=
595 container_of(query
, typeof(*query_trigger
), parent
);
597 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
602 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
612 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
613 struct lttng_payload
*payload
)
616 const struct lttng_error_query_action
*query_action
=
617 container_of(query
, typeof(*query_action
), parent
);
618 struct lttng_error_query_action_comm header
= {
619 .action_index
.is_set
= query_action
->action_index
.is_set
,
620 .action_index
.value
= query_action
->action_index
.value
,
623 if (!lttng_trigger_validate(query_action
->trigger
)) {
628 ret
= lttng_dynamic_buffer_append(
629 &payload
->buffer
, &header
, sizeof(header
));
634 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
643 enum lttng_error_query_target_type
lttng_error_query_get_target_type(
644 const struct lttng_error_query
*query
)
646 return query
->target_type
;
650 const struct lttng_trigger
*lttng_error_query_trigger_borrow_target(
651 const struct lttng_error_query
*query
)
653 const struct lttng_error_query_trigger
*query_trigger
=
654 container_of(query
, typeof(*query_trigger
), parent
);
656 return query_trigger
->trigger
;
660 const struct lttng_trigger
*lttng_error_query_action_borrow_trigger_target(
661 const struct lttng_error_query
*query
)
663 const struct lttng_error_query_action
*query_action
=
664 container_of(query
, typeof(*query_action
), parent
);
666 return query_action
->trigger
;
670 struct lttng_action
*lttng_error_query_action_borrow_action_target(
671 const struct lttng_error_query
*query
,
672 struct lttng_trigger
*trigger
)
674 struct lttng_action
*target_action
= NULL
;
675 const struct lttng_error_query_action
*query_action
=
676 container_of(query
, typeof(*query_action
), parent
);
677 struct lttng_action
*trigger_action
=
678 lttng_trigger_get_action(trigger
);
680 if (!query_action
->action_index
.is_set
) {
681 target_action
= trigger_action
;
683 if (lttng_action_get_type(trigger_action
) !=
684 LTTNG_ACTION_TYPE_LIST
) {
685 ERR("Invalid action error query target index: trigger action is not a list");
689 target_action
= lttng_action_list_borrow_mutable_at_index(
691 LTTNG_OPTIONAL_GET(query_action
->action_index
));
695 return target_action
;
699 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
700 struct lttng_payload
*payload
)
703 struct lttng_error_query_comm header
= {
704 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
707 ret
= lttng_dynamic_buffer_append(
708 &payload
->buffer
, &header
, sizeof(header
));
710 ERR("Failed to append error query header to payload");
714 switch (query
->target_type
) {
715 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
716 ret
= lttng_error_query_trigger_serialize(query
, payload
);
722 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
723 ret
= lttng_error_query_action_serialize(query
, payload
);
737 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
738 struct lttng_error_query
**query
)
740 ssize_t used_size
= 0;
741 struct lttng_error_query_comm
*header
;
742 struct lttng_trigger
*trigger
= NULL
;
743 struct lttng_payload_view header_view
=
744 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
746 if (!lttng_payload_view_is_valid(&header_view
)) {
747 ERR("Failed to map error query header");
752 used_size
= sizeof(*header
);
754 header
= (typeof(header
)) header_view
.buffer
.data
;
755 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
756 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
758 ssize_t trigger_used_size
;
759 struct lttng_payload_view trigger_view
=
760 lttng_payload_view_from_view(
761 view
, used_size
, -1);
763 if (!lttng_payload_view_is_valid(&trigger_view
)) {
768 trigger_used_size
= lttng_trigger_create_from_payload(
769 &trigger_view
, &trigger
);
770 if (trigger_used_size
< 0) {
775 used_size
+= trigger_used_size
;
777 *query
= lttng_error_query_trigger_create(trigger
);
785 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
787 const struct lttng_action
*target_action
;
788 ssize_t trigger_used_size
;
789 struct lttng_error_query_action_comm
*action_header
;
792 struct lttng_payload_view action_header_view
=
793 lttng_payload_view_from_view(view
,
795 sizeof(*action_header
));
797 if (!lttng_payload_view_is_valid(&action_header_view
)) {
802 action_header
= (typeof(action_header
)) action_header_view
.buffer
.data
;
803 used_size
+= sizeof(*action_header
);
807 struct lttng_payload_view trigger_view
=
808 lttng_payload_view_from_view(
809 view
, used_size
, -1);
811 if (!lttng_payload_view_is_valid(&trigger_view
)) {
816 trigger_used_size
= lttng_trigger_create_from_payload(
817 &trigger_view
, &trigger
);
818 if (trigger_used_size
< 0) {
823 used_size
+= trigger_used_size
;
826 if (!action_header
->action_index
.is_set
) {
827 target_action
= trigger
->action
;
829 if (lttng_action_get_type(trigger
->action
) !=
830 LTTNG_ACTION_TYPE_LIST
) {
835 target_action
= lttng_action_list_get_at_index(
837 action_header
->action_index
.value
);
840 *query
= lttng_error_query_action_create(
841 trigger
, target_action
);
855 lttng_trigger_put(trigger
);
859 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
860 const struct lttng_error_query_results
*results
,
863 enum lttng_error_query_results_status status
;
865 if (!results
|| !count
) {
866 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
870 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
871 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
876 enum lttng_error_query_results_status
877 lttng_error_query_results_get_result(
878 const struct lttng_error_query_results
*results
,
879 const struct lttng_error_query_result
**result
,
882 unsigned int result_count
;
883 enum lttng_error_query_results_status status
;
885 if (!results
|| !result
) {
886 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
890 status
= lttng_error_query_results_get_count(results
, &result_count
);
891 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
895 if (index
>= result_count
) {
896 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
900 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
901 &results
->results
, index
);
903 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
908 void lttng_error_query_results_destroy(
909 struct lttng_error_query_results
*results
)
915 lttng_dynamic_pointer_array_reset(&results
->results
);
919 enum lttng_error_query_result_type
920 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
922 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
925 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
926 const struct lttng_error_query_result
*result
,
929 enum lttng_error_query_result_status status
;
931 if (!result
|| !name
) {
932 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
936 *name
= result
->name
;
937 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
942 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
943 const struct lttng_error_query_result
*result
,
944 const char **description
)
946 enum lttng_error_query_result_status status
;
948 if (!result
|| !description
) {
949 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
953 *description
= result
->description
;
954 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
959 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
960 const struct lttng_error_query_result
*result
,
963 enum lttng_error_query_result_status status
;
964 const struct lttng_error_query_result_counter
*counter_result
;
966 if (!result
|| !value
||
967 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
968 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
972 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
974 *value
= counter_result
->value
;
975 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;