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/action/path-internal.h>
17 #include <lttng/error-query-internal.h>
18 #include <lttng/error-query.h>
19 #include <lttng/trigger/trigger-internal.h>
22 struct lttng_error_query
{
23 enum lttng_error_query_target_type target_type
;
26 struct lttng_error_query_comm
{
27 /* enum lttng_error_query_target_type */
29 /* Target-specific payload. */
33 struct lttng_error_query_trigger
{
34 struct lttng_error_query parent
;
35 /* Mutable only because of the reference count. */
36 struct lttng_trigger
*trigger
;
39 struct lttng_error_query_condition
{
40 struct lttng_error_query parent
;
41 /* Mutable only because of the reference count. */
42 struct lttng_trigger
*trigger
;
45 struct lttng_error_query_action
{
46 struct lttng_error_query parent
;
47 /* Mutable only because of the reference count. */
48 struct lttng_trigger
*trigger
;
49 struct lttng_action_path action_path
;
52 struct lttng_error_query_result
{
53 enum lttng_error_query_result_type type
;
58 struct lttng_error_query_result_comm
{
59 /* enum lttng_error_query_result_type */
61 /* Length of name (including null-terminator). */
63 /* Length of description (including null-terminator). */
64 uint32_t description_len
;
65 /* Name, description, and type-specific payload follow. */
69 struct lttng_error_query_result_counter_comm
{
73 struct lttng_error_query_result_counter
{
74 struct lttng_error_query_result parent
;
78 struct lttng_error_query_results_comm
{
80 /* `count` instances of `struct lttng_error_query_result` follow. */
84 struct lttng_error_query_results
{
85 struct lttng_dynamic_pointer_array results
;
89 struct lttng_error_query
*lttng_error_query_trigger_create(
90 const struct lttng_trigger
*trigger
)
92 struct lttng_error_query_trigger
*query
= NULL
;
93 struct lttng_trigger
*trigger_copy
= NULL
;
99 trigger_copy
= lttng_trigger_copy(trigger
);
104 query
= zmalloc(sizeof(*query
));
106 PERROR("Failed to allocate trigger error query");
110 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
;
111 query
->trigger
= trigger_copy
;
115 lttng_trigger_put(trigger_copy
);
117 return query
? &query
->parent
: NULL
;
120 struct lttng_error_query
*lttng_error_query_condition_create(
121 const struct lttng_trigger
*trigger
)
123 struct lttng_error_query_condition
*query
= NULL
;
124 struct lttng_trigger
*trigger_copy
= NULL
;
130 trigger_copy
= lttng_trigger_copy(trigger
);
135 query
= zmalloc(sizeof(*query
));
137 PERROR("Failed to allocate condition error query");
141 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION
;
142 query
->trigger
= trigger_copy
;
146 lttng_trigger_put(trigger_copy
);
148 return query
? &query
->parent
: NULL
;
152 struct lttng_action
*get_trigger_action_from_path(
153 struct lttng_trigger
*trigger
,
154 const struct lttng_action_path
*action_path
)
156 size_t index_count
, i
;
157 enum lttng_action_path_status path_status
;
158 struct lttng_action
*current_action
= NULL
;
160 path_status
= lttng_action_path_get_index_count(
161 action_path
, &index_count
);
162 if (path_status
!= LTTNG_ACTION_PATH_STATUS_OK
) {
166 current_action
= lttng_trigger_get_action(trigger
);
167 for (i
= 0; i
< index_count
; i
++) {
170 path_status
= lttng_action_path_get_index_at_index(
171 action_path
, i
, &path_index
);
172 current_action
= lttng_action_list_borrow_mutable_at_index(
173 current_action
, path_index
);
174 if (!current_action
) {
175 /* Invalid action path. */
181 return current_action
;
185 bool is_valid_action_path(const struct lttng_trigger
*trigger
,
186 const struct lttng_action_path
*action_path
)
189 * While 'trigger's constness is casted-away, the trigger and resulting
190 * action are not modified; we merely check for the action's existence.
192 return !!get_trigger_action_from_path(
193 (struct lttng_trigger
*) trigger
, action_path
);
196 struct lttng_error_query
*lttng_error_query_action_create(
197 const struct lttng_trigger
*trigger
,
198 const struct lttng_action_path
*action_path
)
200 struct lttng_error_query_action
*query
= NULL
;
201 struct lttng_trigger
*trigger_copy
= NULL
;
204 if (!trigger
|| !action_path
||
205 !is_valid_action_path(trigger
, action_path
)) {
209 trigger_copy
= lttng_trigger_copy(trigger
);
214 query
= zmalloc(sizeof(*query
));
216 PERROR("Failed to allocate action error query");
220 ret_copy
= lttng_action_path_copy(action_path
, &query
->action_path
);
225 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
;
226 query
->trigger
= trigger_copy
;
231 lttng_trigger_put(trigger_copy
);
232 lttng_error_query_destroy(query
? &query
->parent
: NULL
);
234 return query
? &query
->parent
: NULL
;
237 void lttng_error_query_destroy(struct lttng_error_query
*query
)
239 struct lttng_error_query_trigger
*trigger_query
;
245 trigger_query
= container_of(query
, typeof(*trigger_query
), parent
);
246 lttng_trigger_put(trigger_query
->trigger
);
251 int lttng_error_query_result_counter_serialize(
252 const struct lttng_error_query_result
*result
,
253 struct lttng_payload
*payload
)
255 const struct lttng_error_query_result_counter
*counter_result
;
257 assert(result
->type
== LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
);
258 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
260 return lttng_dynamic_buffer_append(&payload
->buffer
,
261 &(struct lttng_error_query_result_counter_comm
) {
262 .value
= counter_result
->value
264 sizeof(struct lttng_error_query_result_counter_comm
));
268 int lttng_error_query_result_serialize(
269 const struct lttng_error_query_result
*result
,
270 struct lttng_payload
*payload
)
273 struct lttng_error_query_result_comm header
= {
274 .type
= (uint8_t) result
->type
,
275 .name_len
= (typeof(header
.name_len
)) strlen(result
->name
) + 1,
276 .description_len
= (typeof(header
.name_len
)) strlen(result
->description
) + 1,
280 ret
= lttng_dynamic_buffer_append(
281 &payload
->buffer
, &header
, sizeof(header
));
283 ERR("Failed to append error query result communication header to payload");
288 ret
= lttng_dynamic_buffer_append(
289 &payload
->buffer
, result
->name
, header
.name_len
);
291 ERR("Failed to append error query result name to payload");
296 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, result
->description
,
297 header
.description_len
);
299 ERR("Failed to append error query result description to payload");
303 /* Type-specific payload. */
304 switch (result
->type
) {
305 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
306 ret
= lttng_error_query_result_counter_serialize(
309 ERR("Failed to serialize counter error query result");
322 int lttng_error_query_result_init(
323 struct lttng_error_query_result
*result
,
324 enum lttng_error_query_result_type result_type
,
326 const char *description
)
333 result
->type
= result_type
;
335 result
->name
= strdup(name
);
337 PERROR("Failed to copy error query result name");
342 result
->description
= strdup(description
);
343 if (!result
->description
) {
344 PERROR("Failed to copy error query result description");
355 void lttng_error_query_result_destroy(struct lttng_error_query_result
*counter
)
361 switch (counter
->type
) {
362 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
363 /* Nothing to tear down. */
370 free(counter
->description
);
375 struct lttng_error_query_result
*
376 lttng_error_query_result_counter_create(
377 const char *name
, const char *description
, uint64_t value
)
380 struct lttng_error_query_result_counter
*counter
;
382 counter
= zmalloc(sizeof(*counter
));
384 PERROR("Failed to allocate error query counter result");
388 init_ret
= lttng_error_query_result_init(&counter
->parent
,
389 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
, name
,
395 counter
->value
= value
;
398 lttng_error_query_result_destroy(&counter
->parent
);
400 return counter
? &counter
->parent
: NULL
;
404 void destroy_result(void *ptr
)
406 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
408 lttng_error_query_result_destroy(result
);
412 struct lttng_error_query_results
*lttng_error_query_results_create(void)
414 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
417 PERROR("Failed to allocate an error query result set");
421 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
427 int lttng_error_query_results_add_result(
428 struct lttng_error_query_results
*results
,
429 struct lttng_error_query_result
*result
)
431 return lttng_dynamic_pointer_array_add_pointer(
432 &results
->results
, result
);
436 ssize_t
lttng_error_query_result_create_from_payload(
437 struct lttng_payload_view
*view
,
438 struct lttng_error_query_result
**result
)
440 ssize_t used_size
= 0;
441 struct lttng_error_query_result_comm
*header
;
442 struct lttng_payload_view header_view
=
443 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
445 const char *description
;
447 if (!lttng_payload_view_is_valid(&header_view
)) {
452 header
= (typeof(header
)) header_view
.buffer
.data
;
453 used_size
+= sizeof(*header
);
456 struct lttng_payload_view name_view
=
457 lttng_payload_view_from_view(view
, used_size
,
460 if (!lttng_payload_view_is_valid(&name_view
) ||
461 !lttng_buffer_view_contains_string(
463 name_view
.buffer
.data
,
469 name
= name_view
.buffer
.data
;
470 used_size
+= header
->name_len
;
474 struct lttng_payload_view description_view
=
475 lttng_payload_view_from_view(view
, used_size
,
476 header
->description_len
);
478 if (!lttng_payload_view_is_valid(&description_view
) ||
479 !lttng_buffer_view_contains_string(
480 &description_view
.buffer
,
481 description_view
.buffer
.data
,
482 header
->description_len
)) {
487 description
= description_view
.buffer
.data
;
488 used_size
+= header
->description_len
;
491 switch (header
->type
) {
492 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
494 struct lttng_error_query_result_counter_comm
*counter
;
495 struct lttng_payload_view counter_payload_view
=
496 lttng_payload_view_from_view(view
, used_size
,
499 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
504 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
505 *result
= lttng_error_query_result_counter_create(
506 name
, description
, counter
->value
);
512 used_size
+= sizeof(*counter
);
525 int lttng_error_query_results_serialize(
526 const struct lttng_error_query_results
*results
,
527 struct lttng_payload
*payload
)
531 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
533 const struct lttng_error_query_results_comm header
= {
534 .count
= (typeof(header
.count
)) result_count
,
538 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
540 ERR("Failed to append error query result set header to payload");
545 for (result_index
= 0; result_index
< result_count
; result_index
++) {
546 const struct lttng_error_query_result
*result
= (typeof(result
))
547 lttng_dynamic_pointer_array_get_pointer(
551 ret
= lttng_error_query_result_serialize(result
, payload
);
553 ERR("Failed to append error query result to payload");
562 ssize_t
lttng_error_query_results_create_from_payload(
563 struct lttng_payload_view
*view
,
564 struct lttng_error_query_results
**_results
)
567 ssize_t total_used_size
= 0;
568 struct lttng_error_query_results_comm
*header
;
569 struct lttng_payload_view header_view
=
570 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
571 struct lttng_error_query_results
*results
= NULL
;
573 if (!lttng_payload_view_is_valid(&header_view
)) {
574 ERR("Failed to map view to error query result set header");
575 total_used_size
= -1;
579 header
= (typeof(header
)) header_view
.buffer
.data
;
580 total_used_size
+= sizeof(*header
);
581 results
= lttng_error_query_results_create();
583 total_used_size
= -1;
587 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
589 struct lttng_error_query_result
*result
;
590 struct lttng_payload_view result_view
=
591 lttng_payload_view_from_view(
592 view
, total_used_size
, -1);
594 if (!lttng_payload_view_is_valid(&result_view
)) {
595 total_used_size
= -1;
599 used_size
= lttng_error_query_result_create_from_payload(
600 &result_view
, &result
);
602 total_used_size
= -1;
606 total_used_size
+= used_size
;
608 if (lttng_dynamic_pointer_array_add_pointer(
609 &results
->results
, result
)) {
610 lttng_error_query_result_destroy(result
);
611 total_used_size
= -1;
619 lttng_error_query_results_destroy(results
);
620 return total_used_size
;
624 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
625 struct lttng_payload
*payload
)
628 const struct lttng_error_query_trigger
*query_trigger
=
629 container_of(query
, typeof(*query_trigger
), parent
);
631 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
636 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
646 int lttng_error_query_condition_serialize(const struct lttng_error_query
*query
,
647 struct lttng_payload
*payload
)
650 const struct lttng_error_query_condition
*query_trigger
=
651 container_of(query
, typeof(*query_trigger
), parent
);
653 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
658 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
668 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
669 struct lttng_payload
*payload
)
672 const struct lttng_error_query_action
*query_action
=
673 container_of(query
, typeof(*query_action
), parent
);
675 if (!lttng_trigger_validate(query_action
->trigger
)) {
680 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
685 ret
= lttng_action_path_serialize(&query_action
->action_path
, payload
);
695 enum lttng_error_query_target_type
lttng_error_query_get_target_type(
696 const struct lttng_error_query
*query
)
698 return query
->target_type
;
702 const struct lttng_trigger
*lttng_error_query_trigger_borrow_target(
703 const struct lttng_error_query
*query
)
705 const struct lttng_error_query_trigger
*query_trigger
=
706 container_of(query
, typeof(*query_trigger
), parent
);
708 return query_trigger
->trigger
;
712 const struct lttng_trigger
*lttng_error_query_condition_borrow_target(
713 const struct lttng_error_query
*query
)
715 const struct lttng_error_query_condition
*query_trigger
=
716 container_of(query
, typeof(*query_trigger
), parent
);
718 return query_trigger
->trigger
;
722 const struct lttng_trigger
*lttng_error_query_action_borrow_trigger_target(
723 const struct lttng_error_query
*query
)
725 const struct lttng_error_query_action
*query_action
=
726 container_of(query
, typeof(*query_action
), parent
);
728 return query_action
->trigger
;
732 struct lttng_action
*lttng_error_query_action_borrow_action_target(
733 const struct lttng_error_query
*query
,
734 struct lttng_trigger
*trigger
)
736 const struct lttng_error_query_action
*query_action
=
737 container_of(query
, typeof(*query_action
), parent
);
739 return get_trigger_action_from_path(
740 trigger
, &query_action
->action_path
);
744 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
745 struct lttng_payload
*payload
)
748 const struct lttng_error_query_comm header
= {
749 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
752 ret
= lttng_dynamic_buffer_append(
753 &payload
->buffer
, &header
, sizeof(header
));
755 ERR("Failed to append error query header to payload");
759 switch (query
->target_type
) {
760 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
761 ret
= lttng_error_query_trigger_serialize(query
, payload
);
767 case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION
:
768 ret
= lttng_error_query_condition_serialize(query
, payload
);
774 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
775 ret
= lttng_error_query_action_serialize(query
, payload
);
789 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
790 struct lttng_error_query
**query
)
792 ssize_t used_size
= 0;
793 struct lttng_error_query_comm
*header
;
794 struct lttng_trigger
*trigger
= NULL
;
795 struct lttng_payload_view header_view
=
796 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
798 if (!lttng_payload_view_is_valid(&header_view
)) {
799 ERR("Failed to map error query header");
804 used_size
= sizeof(*header
);
806 header
= (typeof(header
)) header_view
.buffer
.data
;
807 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
808 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
810 ssize_t trigger_used_size
;
811 struct lttng_payload_view trigger_view
=
812 lttng_payload_view_from_view(
813 view
, used_size
, -1);
815 if (!lttng_payload_view_is_valid(&trigger_view
)) {
820 trigger_used_size
= lttng_trigger_create_from_payload(
821 &trigger_view
, &trigger
);
822 if (trigger_used_size
< 0) {
827 used_size
+= trigger_used_size
;
829 *query
= lttng_error_query_trigger_create(trigger
);
837 case LTTNG_ERROR_QUERY_TARGET_TYPE_CONDITION
:
839 ssize_t trigger_used_size
;
840 struct lttng_payload_view trigger_view
=
841 lttng_payload_view_from_view(
842 view
, used_size
, -1);
844 if (!lttng_payload_view_is_valid(&trigger_view
)) {
849 trigger_used_size
= lttng_trigger_create_from_payload(
850 &trigger_view
, &trigger
);
851 if (trigger_used_size
< 0) {
856 used_size
+= trigger_used_size
;
858 *query
= lttng_error_query_condition_create(trigger
);
866 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
868 struct lttng_action_path
*action_path
= NULL
;
871 ssize_t trigger_used_size
;
872 struct lttng_payload_view trigger_view
=
873 lttng_payload_view_from_view(
874 view
, used_size
, -1);
876 if (!lttng_payload_view_is_valid(&trigger_view
)) {
881 trigger_used_size
= lttng_trigger_create_from_payload(
882 &trigger_view
, &trigger
);
883 if (trigger_used_size
< 0) {
888 used_size
+= trigger_used_size
;
892 ssize_t action_path_used_size
;
893 struct lttng_payload_view action_path_view
=
894 lttng_payload_view_from_view(
895 view
, used_size
, -1);
897 if (!lttng_payload_view_is_valid(&action_path_view
)) {
902 action_path_used_size
= lttng_action_path_create_from_payload(
903 &action_path_view
, &action_path
);
904 if (action_path_used_size
< 0) {
909 used_size
+= action_path_used_size
;
912 *query
= lttng_error_query_action_create(
913 trigger
, action_path
);
914 lttng_action_path_destroy(action_path
);
928 lttng_trigger_put(trigger
);
932 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
933 const struct lttng_error_query_results
*results
,
936 enum lttng_error_query_results_status status
;
938 if (!results
|| !count
) {
939 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
943 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
944 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
949 enum lttng_error_query_results_status
950 lttng_error_query_results_get_result(
951 const struct lttng_error_query_results
*results
,
952 const struct lttng_error_query_result
**result
,
955 unsigned int result_count
;
956 enum lttng_error_query_results_status status
;
958 if (!results
|| !result
) {
959 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
963 status
= lttng_error_query_results_get_count(results
, &result_count
);
964 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
968 if (index
>= result_count
) {
969 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
973 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
974 &results
->results
, index
);
976 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
981 void lttng_error_query_results_destroy(
982 struct lttng_error_query_results
*results
)
988 lttng_dynamic_pointer_array_reset(&results
->results
);
992 enum lttng_error_query_result_type
993 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
995 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
998 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
999 const struct lttng_error_query_result
*result
,
1002 enum lttng_error_query_result_status status
;
1004 if (!result
|| !name
) {
1005 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
1009 *name
= result
->name
;
1010 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
1015 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
1016 const struct lttng_error_query_result
*result
,
1017 const char **description
)
1019 enum lttng_error_query_result_status status
;
1021 if (!result
|| !description
) {
1022 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
1026 *description
= result
->description
;
1027 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
1032 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
1033 const struct lttng_error_query_result
*result
,
1036 enum lttng_error_query_result_status status
;
1037 const struct lttng_error_query_result_counter
*counter_result
;
1039 if (!result
|| !value
||
1040 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
1041 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
1045 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
1047 *value
= counter_result
->value
;
1048 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;