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_action
{
40 struct lttng_error_query parent
;
41 /* Mutable only because of the reference count. */
42 struct lttng_trigger
*trigger
;
43 struct lttng_action_path action_path
;
46 struct lttng_error_query_result
{
47 enum lttng_error_query_result_type type
;
52 struct lttng_error_query_result_comm
{
53 /* enum lttng_error_query_result_type */
55 /* Length of name (including null-terminator). */
57 /* Length of description (including null-terminator). */
58 uint32_t description_len
;
59 /* Name, description, and type-specific payload follow. */
63 struct lttng_error_query_result_counter_comm
{
67 struct lttng_error_query_result_counter
{
68 struct lttng_error_query_result parent
;
72 struct lttng_error_query_results_comm
{
74 /* `count` instances of `struct lttng_error_query_result` follow. */
78 struct lttng_error_query_results
{
79 struct lttng_dynamic_pointer_array results
;
83 struct lttng_error_query
*lttng_error_query_trigger_create(
84 const struct lttng_trigger
*trigger
)
86 struct lttng_error_query_trigger
*query
= NULL
;
87 struct lttng_trigger
*trigger_copy
= NULL
;
93 trigger_copy
= lttng_trigger_copy(trigger
);
98 query
= zmalloc(sizeof(*query
));
100 PERROR("Failed to allocate trigger error query");
104 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
;
105 query
->trigger
= trigger_copy
;
109 lttng_trigger_put(trigger_copy
);
111 return query
? &query
->parent
: NULL
;
115 struct lttng_action
*get_trigger_action_from_path(
116 struct lttng_trigger
*trigger
,
117 const struct lttng_action_path
*action_path
)
119 size_t index_count
, i
;
120 enum lttng_action_path_status path_status
;
121 struct lttng_action
*current_action
= NULL
;
123 path_status
= lttng_action_path_get_index_count(
124 action_path
, &index_count
);
125 if (path_status
!= LTTNG_ACTION_PATH_STATUS_OK
) {
129 current_action
= lttng_trigger_get_action(trigger
);
130 for (i
= 0; i
< index_count
; i
++) {
133 path_status
= lttng_action_path_get_index_at_index(
134 action_path
, i
, &path_index
);
135 current_action
= lttng_action_list_borrow_mutable_at_index(
136 current_action
, path_index
);
137 if (!current_action
) {
138 /* Invalid action path. */
144 return current_action
;
148 bool is_valid_action_path(const struct lttng_trigger
*trigger
,
149 const struct lttng_action_path
*action_path
)
152 * While 'trigger's constness is casted-away, the trigger and resulting
153 * action are not modified; we merely check for the action's existence.
155 return !!get_trigger_action_from_path(
156 (struct lttng_trigger
*) trigger
, action_path
);
159 struct lttng_error_query
*lttng_error_query_action_create(
160 const struct lttng_trigger
*trigger
,
161 const struct lttng_action_path
*action_path
)
163 struct lttng_error_query_action
*query
= NULL
;
164 struct lttng_trigger
*trigger_copy
= NULL
;
167 if (!trigger
|| !action_path
||
168 !is_valid_action_path(trigger
, action_path
)) {
172 trigger_copy
= lttng_trigger_copy(trigger
);
177 query
= zmalloc(sizeof(*query
));
179 PERROR("Failed to allocate action error query");
183 ret_copy
= lttng_action_path_copy(action_path
, &query
->action_path
);
188 query
->parent
.target_type
= LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
;
189 query
->trigger
= trigger_copy
;
194 lttng_trigger_put(trigger_copy
);
195 lttng_error_query_destroy(query
? &query
->parent
: NULL
);
197 return query
? &query
->parent
: NULL
;
200 void lttng_error_query_destroy(struct lttng_error_query
*query
)
202 struct lttng_error_query_trigger
*trigger_query
;
208 trigger_query
= container_of(query
, typeof(*trigger_query
), parent
);
209 lttng_trigger_put(trigger_query
->trigger
);
214 int lttng_error_query_result_counter_serialize(
215 const struct lttng_error_query_result
*result
,
216 struct lttng_payload
*payload
)
218 const struct lttng_error_query_result_counter
*counter_result
;
220 assert(result
->type
== LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
);
221 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
223 return lttng_dynamic_buffer_append(&payload
->buffer
,
224 &(struct lttng_error_query_result_counter_comm
) {
225 .value
= counter_result
->value
227 sizeof(struct lttng_error_query_result_counter_comm
));
231 int lttng_error_query_result_serialize(
232 const struct lttng_error_query_result
*result
,
233 struct lttng_payload
*payload
)
236 struct lttng_error_query_result_comm header
= {
237 .type
= (uint8_t) result
->type
,
238 .name_len
= (typeof(header
.name_len
)) strlen(result
->name
) + 1,
239 .description_len
= (typeof(header
.name_len
)) strlen(result
->description
) + 1,
243 ret
= lttng_dynamic_buffer_append(
244 &payload
->buffer
, &header
, sizeof(header
));
246 ERR("Failed to append error query result communication header to payload");
251 ret
= lttng_dynamic_buffer_append(
252 &payload
->buffer
, result
->name
, header
.name_len
);
254 ERR("Failed to append error query result name to payload");
259 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, result
->description
,
260 header
.description_len
);
262 ERR("Failed to append error query result description to payload");
266 /* Type-specific payload. */
267 switch (result
->type
) {
268 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
269 ret
= lttng_error_query_result_counter_serialize(
272 ERR("Failed to serialize counter error query result");
285 int lttng_error_query_result_init(
286 struct lttng_error_query_result
*result
,
287 enum lttng_error_query_result_type result_type
,
289 const char *description
)
296 result
->type
= result_type
;
298 result
->name
= strdup(name
);
300 PERROR("Failed to copy error query result name");
305 result
->description
= strdup(description
);
306 if (!result
->description
) {
307 PERROR("Failed to copy error query result description");
318 void lttng_error_query_result_destroy(struct lttng_error_query_result
*counter
)
324 switch (counter
->type
) {
325 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
326 /* Nothing to tear down. */
333 free(counter
->description
);
338 struct lttng_error_query_result
*
339 lttng_error_query_result_counter_create(
340 const char *name
, const char *description
, uint64_t value
)
343 struct lttng_error_query_result_counter
*counter
;
345 counter
= zmalloc(sizeof(*counter
));
347 PERROR("Failed to allocate error query counter result");
351 init_ret
= lttng_error_query_result_init(&counter
->parent
,
352 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
, name
,
358 counter
->value
= value
;
361 lttng_error_query_result_destroy(&counter
->parent
);
363 return counter
? &counter
->parent
: NULL
;
367 void destroy_result(void *ptr
)
369 struct lttng_error_query_result
*result
= (typeof(result
)) ptr
;
371 lttng_error_query_result_destroy(result
);
375 struct lttng_error_query_results
*lttng_error_query_results_create(void)
377 struct lttng_error_query_results
*set
= zmalloc(sizeof(*set
));
380 PERROR("Failed to allocate an error query result set");
384 lttng_dynamic_pointer_array_init(&set
->results
, destroy_result
);
390 int lttng_error_query_results_add_result(
391 struct lttng_error_query_results
*results
,
392 struct lttng_error_query_result
*result
)
394 return lttng_dynamic_pointer_array_add_pointer(
395 &results
->results
, result
);
399 ssize_t
lttng_error_query_result_create_from_payload(
400 struct lttng_payload_view
*view
,
401 struct lttng_error_query_result
**result
)
403 ssize_t used_size
= 0;
404 struct lttng_error_query_result_comm
*header
;
405 struct lttng_payload_view header_view
=
406 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
408 const char *description
;
410 if (!lttng_payload_view_is_valid(&header_view
)) {
415 header
= (typeof(header
)) header_view
.buffer
.data
;
416 used_size
+= sizeof(*header
);
419 struct lttng_payload_view name_view
=
420 lttng_payload_view_from_view(view
, used_size
,
423 if (!lttng_payload_view_is_valid(&name_view
) ||
424 !lttng_buffer_view_contains_string(
426 name_view
.buffer
.data
,
432 name
= name_view
.buffer
.data
;
433 used_size
+= header
->name_len
;
437 struct lttng_payload_view description_view
=
438 lttng_payload_view_from_view(view
, used_size
,
439 header
->description_len
);
441 if (!lttng_payload_view_is_valid(&description_view
) ||
442 !lttng_buffer_view_contains_string(
443 &description_view
.buffer
,
444 description_view
.buffer
.data
,
445 header
->description_len
)) {
450 description
= description_view
.buffer
.data
;
451 used_size
+= header
->description_len
;
454 switch (header
->type
) {
455 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
:
457 struct lttng_error_query_result_counter_comm
*counter
;
458 struct lttng_payload_view counter_payload_view
=
459 lttng_payload_view_from_view(view
, used_size
,
462 if (!lttng_payload_view_is_valid(&counter_payload_view
)) {
467 counter
= (typeof(counter
)) counter_payload_view
.buffer
.data
;
468 *result
= lttng_error_query_result_counter_create(
469 name
, description
, counter
->value
);
475 used_size
+= sizeof(*counter
);
488 int lttng_error_query_results_serialize(
489 const struct lttng_error_query_results
*results
,
490 struct lttng_payload
*payload
)
494 const size_t result_count
= lttng_dynamic_pointer_array_get_count(
496 const struct lttng_error_query_results_comm header
= {
497 .count
= (typeof(header
.count
)) result_count
,
501 ret
= lttng_dynamic_buffer_append(&payload
->buffer
, &header
, sizeof(header
));
503 ERR("Failed to append error query result set header to payload");
508 for (result_index
= 0; result_index
< result_count
; result_index
++) {
509 const struct lttng_error_query_result
*result
= (typeof(result
))
510 lttng_dynamic_pointer_array_get_pointer(
514 ret
= lttng_error_query_result_serialize(result
, payload
);
516 ERR("Failed to append error query result to payload");
525 ssize_t
lttng_error_query_results_create_from_payload(
526 struct lttng_payload_view
*view
,
527 struct lttng_error_query_results
**_results
)
530 ssize_t total_used_size
= 0;
531 struct lttng_error_query_results_comm
*header
;
532 struct lttng_payload_view header_view
=
533 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
534 struct lttng_error_query_results
*results
= NULL
;
536 if (!lttng_payload_view_is_valid(&header_view
)) {
537 ERR("Failed to map view to error query result set header");
538 total_used_size
= -1;
542 header
= (typeof(header
)) header_view
.buffer
.data
;
543 total_used_size
+= sizeof(*header
);
544 results
= lttng_error_query_results_create();
546 total_used_size
= -1;
550 for (result_index
= 0; result_index
< header
->count
; result_index
++) {
552 struct lttng_error_query_result
*result
;
553 struct lttng_payload_view result_view
=
554 lttng_payload_view_from_view(
555 view
, total_used_size
, -1);
557 if (!lttng_payload_view_is_valid(&result_view
)) {
558 total_used_size
= -1;
562 used_size
= lttng_error_query_result_create_from_payload(
563 &result_view
, &result
);
565 total_used_size
= -1;
569 total_used_size
+= used_size
;
571 if (lttng_dynamic_pointer_array_add_pointer(
572 &results
->results
, result
)) {
573 lttng_error_query_result_destroy(result
);
574 total_used_size
= -1;
582 lttng_error_query_results_destroy(results
);
583 return total_used_size
;
587 int lttng_error_query_trigger_serialize(const struct lttng_error_query
*query
,
588 struct lttng_payload
*payload
)
591 const struct lttng_error_query_trigger
*query_trigger
=
592 container_of(query
, typeof(*query_trigger
), parent
);
594 if (!lttng_trigger_validate(query_trigger
->trigger
)) {
599 ret
= lttng_trigger_serialize(query_trigger
->trigger
, payload
);
609 int lttng_error_query_action_serialize(const struct lttng_error_query
*query
,
610 struct lttng_payload
*payload
)
613 const struct lttng_error_query_action
*query_action
=
614 container_of(query
, typeof(*query_action
), parent
);
616 if (!lttng_trigger_validate(query_action
->trigger
)) {
621 ret
= lttng_trigger_serialize(query_action
->trigger
, payload
);
626 ret
= lttng_action_path_serialize(&query_action
->action_path
, 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 const struct lttng_error_query_action
*query_action
=
668 container_of(query
, typeof(*query_action
), parent
);
670 return get_trigger_action_from_path(
671 trigger
, &query_action
->action_path
);
675 int lttng_error_query_serialize(const struct lttng_error_query
*query
,
676 struct lttng_payload
*payload
)
679 struct lttng_error_query_comm header
= {
680 .target_type
= (typeof(header
.target_type
)) query
->target_type
,
683 ret
= lttng_dynamic_buffer_append(
684 &payload
->buffer
, &header
, sizeof(header
));
686 ERR("Failed to append error query header to payload");
690 switch (query
->target_type
) {
691 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
692 ret
= lttng_error_query_trigger_serialize(query
, payload
);
698 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
699 ret
= lttng_error_query_action_serialize(query
, payload
);
713 ssize_t
lttng_error_query_create_from_payload(struct lttng_payload_view
*view
,
714 struct lttng_error_query
**query
)
716 ssize_t used_size
= 0;
717 struct lttng_error_query_comm
*header
;
718 struct lttng_trigger
*trigger
= NULL
;
719 struct lttng_payload_view header_view
=
720 lttng_payload_view_from_view(view
, 0, sizeof(*header
));
722 if (!lttng_payload_view_is_valid(&header_view
)) {
723 ERR("Failed to map error query header");
728 used_size
= sizeof(*header
);
730 header
= (typeof(header
)) header_view
.buffer
.data
;
731 switch ((enum lttng_error_query_target_type
) header
->target_type
) {
732 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER
:
734 ssize_t trigger_used_size
;
735 struct lttng_payload_view trigger_view
=
736 lttng_payload_view_from_view(
737 view
, used_size
, -1);
739 if (!lttng_payload_view_is_valid(&trigger_view
)) {
744 trigger_used_size
= lttng_trigger_create_from_payload(
745 &trigger_view
, &trigger
);
746 if (trigger_used_size
< 0) {
751 used_size
+= trigger_used_size
;
753 *query
= lttng_error_query_trigger_create(trigger
);
761 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION
:
763 struct lttng_action_path
*action_path
= NULL
;
766 ssize_t trigger_used_size
;
767 struct lttng_payload_view trigger_view
=
768 lttng_payload_view_from_view(
769 view
, used_size
, -1);
771 if (!lttng_payload_view_is_valid(&trigger_view
)) {
776 trigger_used_size
= lttng_trigger_create_from_payload(
777 &trigger_view
, &trigger
);
778 if (trigger_used_size
< 0) {
783 used_size
+= trigger_used_size
;
787 ssize_t action_path_used_size
;
788 struct lttng_payload_view action_path_view
=
789 lttng_payload_view_from_view(
790 view
, used_size
, -1);
792 if (!lttng_payload_view_is_valid(&action_path_view
)) {
797 action_path_used_size
= lttng_action_path_create_from_payload(
798 &action_path_view
, &action_path
);
799 if (action_path_used_size
< 0) {
804 used_size
+= action_path_used_size
;
807 *query
= lttng_error_query_action_create(
808 trigger
, action_path
);
809 lttng_action_path_destroy(action_path
);
823 lttng_trigger_put(trigger
);
827 enum lttng_error_query_results_status
lttng_error_query_results_get_count(
828 const struct lttng_error_query_results
*results
,
831 enum lttng_error_query_results_status status
;
833 if (!results
|| !count
) {
834 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
838 *count
= lttng_dynamic_pointer_array_get_count(&results
->results
);
839 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
844 enum lttng_error_query_results_status
845 lttng_error_query_results_get_result(
846 const struct lttng_error_query_results
*results
,
847 const struct lttng_error_query_result
**result
,
850 unsigned int result_count
;
851 enum lttng_error_query_results_status status
;
853 if (!results
|| !result
) {
854 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
858 status
= lttng_error_query_results_get_count(results
, &result_count
);
859 if (status
!= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
) {
863 if (index
>= result_count
) {
864 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER
;
868 *result
= (typeof(*result
)) lttng_dynamic_pointer_array_get_pointer(
869 &results
->results
, index
);
871 status
= LTTNG_ERROR_QUERY_RESULTS_STATUS_OK
;
876 void lttng_error_query_results_destroy(
877 struct lttng_error_query_results
*results
)
883 lttng_dynamic_pointer_array_reset(&results
->results
);
887 enum lttng_error_query_result_type
888 lttng_error_query_result_get_type(const struct lttng_error_query_result
*result
)
890 return result
? result
->type
: LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN
;
893 enum lttng_error_query_result_status
lttng_error_query_result_get_name(
894 const struct lttng_error_query_result
*result
,
897 enum lttng_error_query_result_status status
;
899 if (!result
|| !name
) {
900 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
904 *name
= result
->name
;
905 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
910 enum lttng_error_query_result_status
lttng_error_query_result_get_description(
911 const struct lttng_error_query_result
*result
,
912 const char **description
)
914 enum lttng_error_query_result_status status
;
916 if (!result
|| !description
) {
917 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
921 *description
= result
->description
;
922 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;
927 enum lttng_error_query_result_status
lttng_error_query_result_counter_get_value(
928 const struct lttng_error_query_result
*result
,
931 enum lttng_error_query_result_status status
;
932 const struct lttng_error_query_result_counter
*counter_result
;
934 if (!result
|| !value
||
935 result
->type
!= LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER
) {
936 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER
;
940 counter_result
= container_of(result
, typeof(*counter_result
), parent
);
942 *value
= counter_result
->value
;
943 status
= LTTNG_ERROR_QUERY_RESULT_STATUS_OK
;