error-query: add lttng_action_path to express the location of an action
[lttng-tools.git] / src / common / error-query.c
1 /*
2 * error-query.c
3 *
4 * Copyright (C) 2021 Jérémie Galarneau <jeremie.galarneau@efficios.com>
5 *
6 * SPDX-License-Identifier: GPL-2.1-only
7 *
8 */
9
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>
20 #include <stddef.h>
21
22 struct lttng_error_query {
23 enum lttng_error_query_target_type target_type;
24 };
25
26 struct lttng_error_query_comm {
27 /* enum lttng_error_query_target_type */
28 int8_t target_type;
29 /* Target-specific payload. */
30 char payload[];
31 };
32
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;
37 };
38
39 struct lttng_error_query_action_comm {
40 LTTNG_OPTIONAL_COMM(uint32_t) action_index;
41 /* Trigger payload. */
42 char payload[];
43 };
44
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 /*
50 * Index of the target action. Since action lists can't be nested,
51 * the targetted action is the top-level list if the action_index is
52 * unset. Otherwise, the index refers to the index within the top-level
53 * list.
54 */
55 LTTNG_OPTIONAL(unsigned int) action_index;
56 };
57
58 struct lttng_error_query_result {
59 enum lttng_error_query_result_type type;
60 char *name;
61 char *description;
62 };
63
64 struct lttng_error_query_result_comm {
65 /* enum lttng_error_query_result_type */
66 uint8_t type;
67 /* Length of name (including null-terminator). */
68 uint32_t name_len;
69 /* Length of description (including null-terminator). */
70 uint32_t description_len;
71 /* Name, description, and type-specific payload follow. */
72 char payload[];
73 } LTTNG_PACKED;
74
75 struct lttng_error_query_result_counter_comm {
76 uint64_t value;
77 } LTTNG_PACKED;
78
79 struct lttng_error_query_result_counter {
80 struct lttng_error_query_result parent;
81 uint64_t value;
82 };
83
84 struct lttng_error_query_results_comm {
85 uint32_t count;
86 /* `count` instances of `struct lttng_error_query_result` follow. */
87 char payload[];
88 } LTTNG_PACKED;
89
90 struct lttng_error_query_results {
91 struct lttng_dynamic_pointer_array results;
92 };
93
94
95 struct lttng_error_query *lttng_error_query_trigger_create(
96 const struct lttng_trigger *trigger)
97 {
98 struct lttng_error_query_trigger *query = NULL;
99 struct lttng_trigger *trigger_copy = NULL;
100
101 if (!trigger) {
102 goto end;
103 }
104
105 trigger_copy = lttng_trigger_copy(trigger);
106 if (!trigger_copy) {
107 goto end;
108 }
109
110 query = zmalloc(sizeof(*query));
111 if (!query) {
112 PERROR("Failed to allocate trigger error query");
113 goto error;
114 }
115
116 query->parent.target_type = LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER;
117 query->trigger = trigger_copy;
118 trigger_copy = NULL;
119
120 error:
121 lttng_trigger_put(trigger_copy);
122 end:
123 return query ? &query->parent : NULL;
124 }
125
126 extern struct lttng_error_query *lttng_error_query_action_create(
127 const struct lttng_trigger *trigger,
128 const struct lttng_action *action)
129 {
130 struct lttng_error_query_action *query = NULL;
131 typeof(query->action_index) action_index = {};
132 struct lttng_trigger *trigger_copy = NULL;
133
134 if (!trigger || !action) {
135 goto end;
136 }
137
138 trigger_copy = lttng_trigger_copy(trigger);
139 if (!trigger_copy) {
140 goto end;
141 }
142
143 /*
144 * If an action is not the top-level action of the trigger, our only
145 * hope of finding its position is if the top-level action is an
146 * action list.
147 *
148 * Note that action comparisons are performed by pointer since multiple
149 * otherwise identical actions can be found in an action list (two
150 * notify actions, for example).
151 */
152 if (action != trigger->action &&
153 lttng_action_get_type(trigger->action) ==
154 LTTNG_ACTION_TYPE_LIST) {
155 unsigned int i, action_list_count;
156 enum lttng_action_status action_status;
157
158 action_status = lttng_action_list_get_count(
159 trigger->action, &action_list_count);
160 if (action_status != LTTNG_ACTION_STATUS_OK) {
161 goto error;
162 }
163
164 for (i = 0; i < action_list_count; i++) {
165 const struct lttng_action *candidate_action =
166 lttng_action_list_get_at_index(
167 trigger->action, i);
168
169 assert(candidate_action);
170 if (candidate_action == action) {
171 LTTNG_OPTIONAL_SET(&action_index, i);
172 break;
173 }
174 }
175
176 if (!action_index.is_set) {
177 /* Not found; invalid action. */
178 goto error;
179 }
180 } else {
181 /*
182 * Trigger action is not a list and not equal to the target
183 * action; invalid action provided.
184 */
185 goto error;
186 }
187
188 query = zmalloc(sizeof(*query));
189 if (!query) {
190 PERROR("Failed to allocate action error query");
191 goto error;
192 }
193
194 query->parent.target_type = LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION;
195 query->trigger = trigger_copy;
196 trigger_copy = NULL;
197 query->action_index = action_index;
198 error:
199 lttng_trigger_put(trigger_copy);
200 end:
201 return query ? &query->parent : NULL;
202 }
203
204 void lttng_error_query_destroy(struct lttng_error_query *query)
205 {
206 struct lttng_error_query_trigger *trigger_query;
207
208 if (!query) {
209 return;
210 }
211
212 trigger_query = container_of(query, typeof(*trigger_query), parent);
213 lttng_trigger_put(trigger_query->trigger);
214 free(trigger_query);
215 }
216
217 static
218 int lttng_error_query_result_counter_serialize(
219 const struct lttng_error_query_result *result,
220 struct lttng_payload *payload)
221 {
222 const struct lttng_error_query_result_counter *counter_result;
223
224 assert(result->type == LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER);
225 counter_result = container_of(result, typeof(*counter_result), parent);
226
227 return lttng_dynamic_buffer_append(&payload->buffer,
228 &(struct lttng_error_query_result_counter_comm) {
229 .value = counter_result->value
230 },
231 sizeof(struct lttng_error_query_result_counter_comm));
232 }
233
234 LTTNG_HIDDEN
235 int lttng_error_query_result_serialize(
236 const struct lttng_error_query_result *result,
237 struct lttng_payload *payload)
238 {
239 int ret;
240 struct lttng_error_query_result_comm header = {
241 .type = (uint8_t) result->type,
242 .name_len = (typeof(header.name_len)) strlen(result->name) + 1,
243 .description_len = (typeof(header.name_len)) strlen(result->description) + 1,
244 };
245
246 /* Header. */
247 ret = lttng_dynamic_buffer_append(
248 &payload->buffer, &header, sizeof(header));
249 if (ret) {
250 ERR("Failed to append error query result communication header to payload");
251 goto end;
252 }
253
254 /* Name. */
255 ret = lttng_dynamic_buffer_append(
256 &payload->buffer, result->name, header.name_len);
257 if (ret) {
258 ERR("Failed to append error query result name to payload");
259 goto end;
260 }
261
262 /* Description. */
263 ret = lttng_dynamic_buffer_append(&payload->buffer, result->description,
264 header.description_len);
265 if (ret) {
266 ERR("Failed to append error query result description to payload");
267 goto end;
268 }
269
270 /* Type-specific payload. */
271 switch (result->type) {
272 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER:
273 ret = lttng_error_query_result_counter_serialize(
274 result, payload);
275 if (ret) {
276 ERR("Failed to serialize counter error query result");
277 goto end;
278 }
279 break;
280 default:
281 abort();
282 }
283
284 end:
285 return ret;
286 }
287
288 static
289 int lttng_error_query_result_init(
290 struct lttng_error_query_result *result,
291 enum lttng_error_query_result_type result_type,
292 const char *name,
293 const char *description)
294 {
295 int ret;
296
297 assert(name);
298 assert(description);
299
300 result->type = result_type;
301
302 result->name = strdup(name);
303 if (!result->name) {
304 PERROR("Failed to copy error query result name");
305 ret = -1;
306 goto end;
307 }
308
309 result->description = strdup(description);
310 if (!result->description) {
311 PERROR("Failed to copy error query result description");
312 ret = -1;
313 goto end;
314 }
315
316 ret = 0;
317 end:
318 return ret;
319 }
320
321 LTTNG_HIDDEN
322 void lttng_error_query_result_destroy(struct lttng_error_query_result *counter)
323 {
324 if (!counter) {
325 return;
326 }
327
328 switch (counter->type) {
329 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER:
330 /* Nothing to tear down. */
331 break;
332 default:
333 abort();
334 }
335
336 free(counter->name);
337 free(counter->description);
338 free(counter);
339 }
340
341 LTTNG_HIDDEN
342 struct lttng_error_query_result *
343 lttng_error_query_result_counter_create(
344 const char *name, const char *description, uint64_t value)
345 {
346 int init_ret;
347 struct lttng_error_query_result_counter *counter;
348
349 counter = zmalloc(sizeof(*counter));
350 if (!counter) {
351 PERROR("Failed to allocate error query counter result");
352 goto end;
353 }
354
355 init_ret = lttng_error_query_result_init(&counter->parent,
356 LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER, name,
357 description);
358 if (init_ret) {
359 goto error;
360 }
361
362 counter->value = value;
363 goto end;
364 error:
365 lttng_error_query_result_destroy(&counter->parent);
366 end:
367 return counter ? &counter->parent : NULL;
368 }
369
370 static
371 void destroy_result(void *ptr)
372 {
373 struct lttng_error_query_result *result = (typeof(result)) ptr;
374
375 lttng_error_query_result_destroy(result);
376 }
377
378 LTTNG_HIDDEN
379 struct lttng_error_query_results *lttng_error_query_results_create(void)
380 {
381 struct lttng_error_query_results *set = zmalloc(sizeof(*set));
382
383 if (!set) {
384 PERROR("Failed to allocate an error query result set");
385 goto end;
386 }
387
388 lttng_dynamic_pointer_array_init(&set->results, destroy_result);
389 end:
390 return set;
391 }
392
393 LTTNG_HIDDEN
394 int lttng_error_query_results_add_result(
395 struct lttng_error_query_results *results,
396 struct lttng_error_query_result *result)
397 {
398 return lttng_dynamic_pointer_array_add_pointer(
399 &results->results, result);
400 }
401
402 LTTNG_HIDDEN
403 ssize_t lttng_error_query_result_create_from_payload(
404 struct lttng_payload_view *view,
405 struct lttng_error_query_result **result)
406 {
407 ssize_t used_size = 0;
408 struct lttng_error_query_result_comm *header;
409 struct lttng_payload_view header_view =
410 lttng_payload_view_from_view(view, 0, sizeof(*header));
411 const char *name;
412 const char *description;
413
414 if (!lttng_payload_view_is_valid(&header_view)) {
415 used_size = -1;
416 goto end;
417 }
418
419 header = (typeof(header)) header_view.buffer.data;
420 used_size += sizeof(*header);
421
422 {
423 struct lttng_payload_view name_view =
424 lttng_payload_view_from_view(view, used_size,
425 header->name_len);
426
427 if (!lttng_payload_view_is_valid(&name_view) ||
428 !lttng_buffer_view_contains_string(
429 &name_view.buffer,
430 name_view.buffer.data,
431 header->name_len)) {
432 used_size = -1;
433 goto end;
434 }
435
436 name = name_view.buffer.data;
437 used_size += header->name_len;
438 }
439
440 {
441 struct lttng_payload_view description_view =
442 lttng_payload_view_from_view(view, used_size,
443 header->description_len);
444
445 if (!lttng_payload_view_is_valid(&description_view) ||
446 !lttng_buffer_view_contains_string(
447 &description_view.buffer,
448 description_view.buffer.data,
449 header->description_len)) {
450 used_size = -1;
451 goto end;
452 }
453
454 description = description_view.buffer.data;
455 used_size += header->description_len;
456 }
457
458 switch (header->type) {
459 case LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER:
460 {
461 struct lttng_error_query_result_counter_comm *counter;
462 struct lttng_payload_view counter_payload_view =
463 lttng_payload_view_from_view(view, used_size,
464 sizeof(*counter));
465
466 if (!lttng_payload_view_is_valid(&counter_payload_view)) {
467 used_size = -1;
468 goto end;
469 }
470
471 counter = (typeof(counter)) counter_payload_view.buffer.data;
472 *result = lttng_error_query_result_counter_create(
473 name, description, counter->value);
474 if (!*result) {
475 used_size = -1;
476 goto end;
477 }
478
479 used_size += sizeof(*counter);
480 break;
481 }
482 default:
483 used_size = -1;
484 goto end;
485 }
486
487 end:
488 return used_size;
489 }
490
491 LTTNG_HIDDEN
492 int lttng_error_query_results_serialize(
493 const struct lttng_error_query_results *results,
494 struct lttng_payload *payload)
495 {
496 int ret;
497 size_t result_index;
498 const size_t result_count = lttng_dynamic_pointer_array_get_count(
499 &results->results);
500 const struct lttng_error_query_results_comm header = {
501 .count = (typeof(header.count)) result_count,
502 };
503
504 /* Header. */
505 ret = lttng_dynamic_buffer_append(&payload->buffer, &header, sizeof(header));
506 if (ret) {
507 ERR("Failed to append error query result set header to payload");
508 goto end;
509 }
510
511 /* Results. */
512 for (result_index = 0; result_index < result_count; result_index++) {
513 const struct lttng_error_query_result *result = (typeof(result))
514 lttng_dynamic_pointer_array_get_pointer(
515 &results->results,
516 result_index);
517
518 ret = lttng_error_query_result_serialize(result, payload);
519 if (ret) {
520 ERR("Failed to append error query result to payload");
521 goto end;
522 }
523 }
524 end:
525 return ret;
526 }
527
528 LTTNG_HIDDEN
529 ssize_t lttng_error_query_results_create_from_payload(
530 struct lttng_payload_view *view,
531 struct lttng_error_query_results **_results)
532 {
533 size_t result_index;
534 ssize_t total_used_size = 0;
535 struct lttng_error_query_results_comm *header;
536 struct lttng_payload_view header_view =
537 lttng_payload_view_from_view(view, 0, sizeof(*header));
538 struct lttng_error_query_results *results = NULL;
539
540 if (!lttng_payload_view_is_valid(&header_view)) {
541 ERR("Failed to map view to error query result set header");
542 total_used_size = -1;
543 goto end;
544 }
545
546 header = (typeof(header)) header_view.buffer.data;
547 total_used_size += sizeof(*header);
548 results = lttng_error_query_results_create();
549 if (!results) {
550 total_used_size = -1;
551 goto end;
552 }
553
554 for (result_index = 0; result_index < header->count; result_index++) {
555 ssize_t used_size;
556 struct lttng_error_query_result *result;
557 struct lttng_payload_view result_view =
558 lttng_payload_view_from_view(
559 view, total_used_size, -1);
560
561 if (!lttng_payload_view_is_valid(&result_view)) {
562 total_used_size = -1;
563 goto end;
564 }
565
566 used_size = lttng_error_query_result_create_from_payload(
567 &result_view, &result);
568 if (used_size < 0) {
569 total_used_size = -1;
570 goto end;
571 }
572
573 total_used_size += used_size;
574
575 if (lttng_dynamic_pointer_array_add_pointer(
576 &results->results, result)) {
577 lttng_error_query_result_destroy(result);
578 total_used_size = -1;
579 goto end;
580 }
581 }
582
583 *_results = results;
584 results = NULL;
585 end:
586 lttng_error_query_results_destroy(results);
587 return total_used_size;
588 }
589
590 static
591 int lttng_error_query_trigger_serialize(const struct lttng_error_query *query,
592 struct lttng_payload *payload)
593 {
594 int ret;
595 const struct lttng_error_query_trigger *query_trigger =
596 container_of(query, typeof(*query_trigger), parent);
597
598 if (!lttng_trigger_validate(query_trigger->trigger)) {
599 ret = -1;
600 goto end;
601 }
602
603 ret = lttng_trigger_serialize(query_trigger->trigger, payload);
604 if (ret) {
605 goto end;
606 }
607
608 end:
609 return ret;
610 }
611
612 static
613 int lttng_error_query_action_serialize(const struct lttng_error_query *query,
614 struct lttng_payload *payload)
615 {
616 int ret;
617 const struct lttng_error_query_action *query_action =
618 container_of(query, typeof(*query_action), parent);
619 struct lttng_error_query_action_comm header = {
620 .action_index.is_set = query_action->action_index.is_set,
621 .action_index.value = query_action->action_index.value,
622 };
623
624 if (!lttng_trigger_validate(query_action->trigger)) {
625 ret = -1;
626 goto end;
627 }
628
629 ret = lttng_dynamic_buffer_append(
630 &payload->buffer, &header, sizeof(header));
631 if (ret) {
632 goto end;
633 }
634
635 ret = lttng_trigger_serialize(query_action->trigger, payload);
636 if (ret) {
637 goto end;
638 }
639 end:
640 return ret;
641 }
642
643 LTTNG_HIDDEN
644 enum lttng_error_query_target_type lttng_error_query_get_target_type(
645 const struct lttng_error_query *query)
646 {
647 return query->target_type;
648 }
649
650 LTTNG_HIDDEN
651 const struct lttng_trigger *lttng_error_query_trigger_borrow_target(
652 const struct lttng_error_query *query)
653 {
654 const struct lttng_error_query_trigger *query_trigger =
655 container_of(query, typeof(*query_trigger), parent);
656
657 return query_trigger->trigger;
658 }
659
660 LTTNG_HIDDEN
661 const struct lttng_trigger *lttng_error_query_action_borrow_trigger_target(
662 const struct lttng_error_query *query)
663 {
664 const struct lttng_error_query_action *query_action =
665 container_of(query, typeof(*query_action), parent);
666
667 return query_action->trigger;
668 }
669
670 LTTNG_HIDDEN
671 struct lttng_action *lttng_error_query_action_borrow_action_target(
672 const struct lttng_error_query *query,
673 struct lttng_trigger *trigger)
674 {
675 struct lttng_action *target_action = NULL;
676 const struct lttng_error_query_action *query_action =
677 container_of(query, typeof(*query_action), parent);
678 struct lttng_action *trigger_action =
679 lttng_trigger_get_action(trigger);
680
681 if (!query_action->action_index.is_set) {
682 target_action = trigger_action;
683 } else {
684 if (lttng_action_get_type(trigger_action) !=
685 LTTNG_ACTION_TYPE_LIST) {
686 ERR("Invalid action error query target index: trigger action is not a list");
687 goto end;
688 }
689
690 target_action = lttng_action_list_borrow_mutable_at_index(
691 trigger_action,
692 LTTNG_OPTIONAL_GET(query_action->action_index));
693 }
694
695 end:
696 return target_action;
697 }
698
699 LTTNG_HIDDEN
700 int lttng_error_query_serialize(const struct lttng_error_query *query,
701 struct lttng_payload *payload)
702 {
703 int ret;
704 struct lttng_error_query_comm header = {
705 .target_type = (typeof(header.target_type)) query->target_type,
706 };
707
708 ret = lttng_dynamic_buffer_append(
709 &payload->buffer, &header, sizeof(header));
710 if (ret) {
711 ERR("Failed to append error query header to payload");
712 goto end;
713 }
714
715 switch (query->target_type) {
716 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER:
717 ret = lttng_error_query_trigger_serialize(query, payload);
718 if (ret) {
719 goto end;
720 }
721
722 break;
723 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION:
724 ret = lttng_error_query_action_serialize(query, payload);
725 if (ret) {
726 goto end;
727 }
728
729 break;
730 default:
731 abort();
732 }
733 end:
734 return ret;
735 }
736
737 LTTNG_HIDDEN
738 ssize_t lttng_error_query_create_from_payload(struct lttng_payload_view *view,
739 struct lttng_error_query **query)
740 {
741 ssize_t used_size = 0;
742 struct lttng_error_query_comm *header;
743 struct lttng_trigger *trigger = NULL;
744 struct lttng_payload_view header_view =
745 lttng_payload_view_from_view(view, 0, sizeof(*header));
746
747 if (!lttng_payload_view_is_valid(&header_view)) {
748 ERR("Failed to map error query header");
749 used_size = -1;
750 goto end;
751 }
752
753 used_size = sizeof(*header);
754
755 header = (typeof(header)) header_view.buffer.data;
756 switch ((enum lttng_error_query_target_type) header->target_type) {
757 case LTTNG_ERROR_QUERY_TARGET_TYPE_TRIGGER:
758 {
759 ssize_t trigger_used_size;
760 struct lttng_payload_view trigger_view =
761 lttng_payload_view_from_view(
762 view, used_size, -1);
763
764 if (!lttng_payload_view_is_valid(&trigger_view)) {
765 used_size = -1;
766 goto end;
767 }
768
769 trigger_used_size = lttng_trigger_create_from_payload(
770 &trigger_view, &trigger);
771 if (trigger_used_size < 0) {
772 used_size = -1;
773 goto end;
774 }
775
776 used_size += trigger_used_size;
777
778 *query = lttng_error_query_trigger_create(trigger);
779 if (!*query) {
780 used_size = -1;
781 goto end;
782 }
783
784 break;
785 }
786 case LTTNG_ERROR_QUERY_TARGET_TYPE_ACTION:
787 {
788 const struct lttng_action *target_action;
789 ssize_t trigger_used_size;
790 struct lttng_error_query_action_comm *action_header;
791
792 {
793 struct lttng_payload_view action_header_view =
794 lttng_payload_view_from_view(view,
795 used_size,
796 sizeof(*action_header));
797
798 if (!lttng_payload_view_is_valid(&action_header_view)) {
799 used_size = -1;
800 goto end;
801 }
802
803 action_header = (typeof(action_header)) action_header_view.buffer.data;
804 used_size += sizeof(*action_header);
805 }
806
807 {
808 struct lttng_payload_view trigger_view =
809 lttng_payload_view_from_view(
810 view, used_size, -1);
811
812 if (!lttng_payload_view_is_valid(&trigger_view)) {
813 used_size = -1;
814 goto end;
815 }
816
817 trigger_used_size = lttng_trigger_create_from_payload(
818 &trigger_view, &trigger);
819 if (trigger_used_size < 0) {
820 used_size = -1;
821 goto end;
822 }
823
824 used_size += trigger_used_size;
825 }
826
827 if (!action_header->action_index.is_set) {
828 target_action = trigger->action;
829 } else {
830 if (lttng_action_get_type(trigger->action) !=
831 LTTNG_ACTION_TYPE_LIST) {
832 used_size = -1;
833 goto end;
834 }
835
836 target_action = lttng_action_list_get_at_index(
837 trigger->action,
838 action_header->action_index.value);
839 }
840
841 *query = lttng_error_query_action_create(
842 trigger, target_action);
843 if (!*query) {
844 used_size = -1;
845 goto end;
846 }
847
848 break;
849 }
850 default:
851 used_size = -1;
852 goto end;
853 }
854
855 end:
856 lttng_trigger_put(trigger);
857 return used_size;
858 }
859
860 enum lttng_error_query_results_status lttng_error_query_results_get_count(
861 const struct lttng_error_query_results *results,
862 unsigned int *count)
863 {
864 enum lttng_error_query_results_status status;
865
866 if (!results || !count) {
867 status = LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER;
868 goto end;
869 }
870
871 *count = lttng_dynamic_pointer_array_get_count(&results->results);
872 status = LTTNG_ERROR_QUERY_RESULTS_STATUS_OK;
873 end:
874 return status;
875 }
876
877 enum lttng_error_query_results_status
878 lttng_error_query_results_get_result(
879 const struct lttng_error_query_results *results,
880 const struct lttng_error_query_result **result,
881 unsigned int index)
882 {
883 unsigned int result_count;
884 enum lttng_error_query_results_status status;
885
886 if (!results || !result) {
887 status = LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER;
888 goto end;
889 }
890
891 status = lttng_error_query_results_get_count(results, &result_count);
892 if (status != LTTNG_ERROR_QUERY_RESULTS_STATUS_OK) {
893 goto end;
894 }
895
896 if (index >= result_count) {
897 status = LTTNG_ERROR_QUERY_RESULTS_STATUS_INVALID_PARAMETER;
898 goto end;
899 }
900
901 *result = (typeof(*result)) lttng_dynamic_pointer_array_get_pointer(
902 &results->results, index);
903 assert(*result);
904 status = LTTNG_ERROR_QUERY_RESULTS_STATUS_OK;
905 end:
906 return status;
907 }
908
909 void lttng_error_query_results_destroy(
910 struct lttng_error_query_results *results)
911 {
912 if (!results) {
913 return;
914 }
915
916 lttng_dynamic_pointer_array_reset(&results->results);
917 free(results);
918 }
919
920 enum lttng_error_query_result_type
921 lttng_error_query_result_get_type(const struct lttng_error_query_result *result)
922 {
923 return result ? result->type : LTTNG_ERROR_QUERY_RESULT_TYPE_UNKNOWN;
924 }
925
926 enum lttng_error_query_result_status lttng_error_query_result_get_name(
927 const struct lttng_error_query_result *result,
928 const char **name)
929 {
930 enum lttng_error_query_result_status status;
931
932 if (!result || !name) {
933 status = LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER;
934 goto end;
935 }
936
937 *name = result->name;
938 status = LTTNG_ERROR_QUERY_RESULT_STATUS_OK;
939 end:
940 return status;
941 }
942
943 enum lttng_error_query_result_status lttng_error_query_result_get_description(
944 const struct lttng_error_query_result *result,
945 const char **description)
946 {
947 enum lttng_error_query_result_status status;
948
949 if (!result || !description) {
950 status = LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER;
951 goto end;
952 }
953
954 *description = result->description;
955 status = LTTNG_ERROR_QUERY_RESULT_STATUS_OK;
956 end:
957 return status;
958 }
959
960 enum lttng_error_query_result_status lttng_error_query_result_counter_get_value(
961 const struct lttng_error_query_result *result,
962 uint64_t *value)
963 {
964 enum lttng_error_query_result_status status;
965 const struct lttng_error_query_result_counter *counter_result;
966
967 if (!result || !value ||
968 result->type != LTTNG_ERROR_QUERY_RESULT_TYPE_COUNTER) {
969 status = LTTNG_ERROR_QUERY_RESULT_STATUS_INVALID_PARAMETER;
970 goto end;
971 }
972
973 counter_result = container_of(result, typeof(*counter_result), parent);
974
975 *value = counter_result->value;
976 status = LTTNG_ERROR_QUERY_RESULT_STATUS_OK;
977 end:
978 return status;
979 }
This page took 0.049234 seconds and 4 git commands to generate.