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