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