b406ee96deee4e494626c9ad4542a4c9383491b5
[babeltrace.git] / plugins / ctf / fs / fs.c
1 /*
2 * fs.c
3 *
4 * Babeltrace CTF file system Reader Component
5 *
6 * Copyright 2016 Jérémie Galarneau <jeremie.galarneau@efficios.com>
7 *
8 * Author: Jérémie Galarneau <jeremie.galarneau@efficios.com>
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this software and associated documentation files (the "Software"), to deal
12 * in the Software without restriction, including without limitation the rights
13 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 * copies of the Software, and to permit persons to whom the Software is
15 * furnished to do so, subject to the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
26 * SOFTWARE.
27 */
28
29 #include <babeltrace/ctf-ir/packet.h>
30 #include <babeltrace/ctf-ir/clock-class.h>
31 #include <babeltrace/component/notification/iterator.h>
32 #include <babeltrace/component/notification/stream.h>
33 #include <babeltrace/component/notification/event.h>
34 #include <babeltrace/component/notification/packet.h>
35 #include <babeltrace/component/notification/heap.h>
36 #include <plugins-common.h>
37 #include <glib.h>
38 #include <assert.h>
39 #include <unistd.h>
40 #include "fs.h"
41 #include "metadata.h"
42 #include "data-stream.h"
43 #include "file.h"
44
45 #define PRINT_ERR_STREAM ctf_fs->error_fp
46 #define PRINT_PREFIX "ctf-fs"
47 #include "print.h"
48 #define METADATA_TEXT_SIG "/* CTF 1.8"
49
50 BT_HIDDEN
51 bool ctf_fs_debug;
52
53 enum bt_notification_iterator_status ctf_fs_iterator_next(
54 struct bt_notification_iterator *iterator);
55
56 struct bt_notification *ctf_fs_iterator_get(
57 struct bt_notification_iterator *iterator)
58 {
59 struct ctf_fs_iterator *ctf_it =
60 bt_notification_iterator_get_private_data(iterator);
61
62 if (!ctf_it->current_notification) {
63 (void) ctf_fs_iterator_next(iterator);
64 }
65
66 return bt_get(ctf_it->current_notification);
67 }
68
69 static
70 enum bt_notification_iterator_status ctf_fs_iterator_get_next_notification(
71 struct ctf_fs_iterator *it,
72 struct ctf_fs_stream *stream,
73 struct bt_notification **notification)
74 {
75 enum bt_ctf_notif_iter_status status;
76 enum bt_notification_iterator_status ret;
77
78 if (stream->end_reached) {
79 status = BT_CTF_NOTIF_ITER_STATUS_EOF;
80 goto end;
81 }
82
83 status = bt_ctf_notif_iter_get_next_notification(stream->notif_iter,
84 notification);
85 if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
86 status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
87 goto end;
88 }
89
90 /* Should be handled in bt_ctf_notif_iter_get_next_notification. */
91 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
92 *notification = bt_notification_stream_end_create(
93 stream->stream);
94 if (!*notification) {
95 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
96 }
97 status = BT_CTF_NOTIF_ITER_STATUS_OK;
98 stream->end_reached = true;
99 }
100 end:
101 switch (status) {
102 case BT_CTF_NOTIF_ITER_STATUS_EOF:
103 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
104 break;
105 case BT_CTF_NOTIF_ITER_STATUS_OK:
106 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
107 break;
108 case BT_CTF_NOTIF_ITER_STATUS_AGAIN:
109 /*
110 * Should not make it this far as this is medium-specific;
111 * there is nothing for the user to do and it should have been
112 * handled upstream.
113 */
114 assert(0);
115 case BT_CTF_NOTIF_ITER_STATUS_INVAL:
116 /* No argument provided by the user, so don't return INVAL. */
117 case BT_CTF_NOTIF_ITER_STATUS_ERROR:
118 default:
119 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
120 break;
121 }
122 return ret;
123 }
124
125 /*
126 * Remove me. This is a temporary work-around due to our inhability to use
127 * libbabeltrace-ctf from libbabeltrace-plugin.
128 */
129 static
130 struct bt_ctf_stream *internal_bt_notification_get_stream(
131 struct bt_notification *notification)
132 {
133 struct bt_ctf_stream *stream = NULL;
134
135 assert(notification);
136 switch (bt_notification_get_type(notification)) {
137 case BT_NOTIFICATION_TYPE_EVENT:
138 {
139 struct bt_ctf_event *event;
140
141 event = bt_notification_event_get_event(notification);
142 stream = bt_ctf_event_get_stream(event);
143 bt_put(event);
144 break;
145 }
146 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
147 {
148 struct bt_ctf_packet *packet;
149
150 packet = bt_notification_packet_begin_get_packet(notification);
151 stream = bt_ctf_packet_get_stream(packet);
152 bt_put(packet);
153 break;
154 }
155 case BT_NOTIFICATION_TYPE_PACKET_END:
156 {
157 struct bt_ctf_packet *packet;
158
159 packet = bt_notification_packet_end_get_packet(notification);
160 stream = bt_ctf_packet_get_stream(packet);
161 bt_put(packet);
162 break;
163 }
164 case BT_NOTIFICATION_TYPE_STREAM_END:
165 stream = bt_notification_stream_end_get_stream(notification);
166 break;
167 default:
168 goto end;
169 }
170 end:
171 return stream;
172 }
173
174 static
175 enum bt_notification_iterator_status populate_heap(struct ctf_fs_iterator *it)
176 {
177 size_t i, pending_streams_count = it->pending_streams->len;
178 enum bt_notification_iterator_status ret =
179 BT_NOTIFICATION_ITERATOR_STATUS_OK;
180
181 /* Insert one stream-associated notification for each stream. */
182 for (i = 0; i < pending_streams_count; i++) {
183 struct bt_notification *notification;
184 struct ctf_fs_stream *fs_stream;
185 struct bt_ctf_stream *stream;
186 size_t pending_stream_index = pending_streams_count - 1 - i;
187
188 fs_stream = g_ptr_array_index(it->pending_streams,
189 pending_stream_index);
190
191 do {
192 int heap_ret;
193
194 ret = ctf_fs_iterator_get_next_notification(
195 it, fs_stream, &notification);
196 if (ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END) {
197 printf_debug("Failed to populate heap at stream %zu\n",
198 pending_stream_index);
199 goto end;
200 }
201
202 stream = internal_bt_notification_get_stream(
203 notification);
204 if (stream) {
205 gboolean inserted;
206
207 /*
208 * Associate pending ctf_fs_stream to
209 * bt_ctf_stream. Ownership of stream
210 * is passed to the stream ht.
211 */
212 inserted = g_hash_table_insert(it->stream_ht,
213 stream, fs_stream);
214 if (!inserted) {
215 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
216 printf_debug("Failed to associate fs stream to ctf stream\n");
217 goto end;
218 }
219 }
220
221 heap_ret = bt_notification_heap_insert(
222 it->pending_notifications,
223 notification);
224 bt_put(notification);
225 if (heap_ret) {
226 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
227 printf_debug("Failed to insert notification in heap\n");
228 goto end;
229 }
230 } while (!stream && ret != BT_NOTIFICATION_ITERATOR_STATUS_END);
231 /*
232 * Set NULL so the destruction callback registered with the
233 * array is not invoked on the stream (its ownership was
234 * transferred to the streams hashtable).
235 */
236 g_ptr_array_index(it->pending_streams,
237 pending_stream_index) = NULL;
238 g_ptr_array_remove_index(it->pending_streams,
239 pending_stream_index);
240 }
241
242 g_ptr_array_free(it->pending_streams, TRUE);
243 it->pending_streams = NULL;
244 end:
245 return ret;
246 }
247
248 enum bt_notification_iterator_status ctf_fs_iterator_next(
249 struct bt_notification_iterator *iterator)
250 {
251 int heap_ret;
252 struct bt_ctf_stream *stream = NULL;
253 struct ctf_fs_stream *fs_stream;
254 struct bt_notification *notification;
255 struct bt_notification *next_stream_notification;
256 enum bt_notification_iterator_status ret =
257 BT_NOTIFICATION_ITERATOR_STATUS_OK;
258 struct ctf_fs_iterator *ctf_it =
259 bt_notification_iterator_get_private_data(iterator);
260
261 notification = bt_notification_heap_pop(ctf_it->pending_notifications);
262 if (!notification && !ctf_it->pending_streams) {
263 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
264 goto end;
265 }
266
267 if (!notification && ctf_it->pending_streams) {
268 /*
269 * Insert at one notification per stream in the heap and pop
270 * one.
271 */
272 ret = populate_heap(ctf_it);
273 if (ret) {
274 goto end;
275 }
276
277 notification = bt_notification_heap_pop(
278 ctf_it->pending_notifications);
279 if (!notification) {
280 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
281 goto end;
282 }
283 }
284
285 /* notification is set from here. */
286
287 stream = internal_bt_notification_get_stream(notification);
288 if (!stream) {
289 /*
290 * The current notification is not associated to a particular
291 * stream, there is no need to insert a new notification from
292 * a stream in the heap.
293 */
294 goto end;
295 }
296
297 fs_stream = g_hash_table_lookup(ctf_it->stream_ht, stream);
298 if (!fs_stream) {
299 /* We have reached this stream's end. */
300 goto end;
301 }
302
303 ret = ctf_fs_iterator_get_next_notification(ctf_it, fs_stream,
304 &next_stream_notification);
305 if ((ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END)) {
306 heap_ret = bt_notification_heap_insert(
307 ctf_it->pending_notifications, notification);
308
309 assert(!next_stream_notification);
310 if (heap_ret) {
311 /*
312 * We're dropping the most recent notification, but at
313 * this point, something is seriously wrong...
314 */
315 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
316 }
317 BT_PUT(notification);
318 goto end;
319 }
320
321 if (ret == BT_NOTIFICATION_ITERATOR_STATUS_END) {
322 gboolean success;
323
324 /* Remove stream. */
325 success = g_hash_table_remove(ctf_it->stream_ht, stream);
326 assert(success);
327 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
328 } else {
329 heap_ret = bt_notification_heap_insert(ctf_it->pending_notifications,
330 next_stream_notification);
331 BT_PUT(next_stream_notification);
332 if (heap_ret) {
333 /*
334 * We're dropping the most recent notification...
335 */
336 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
337 }
338 }
339
340 /*
341 * Ensure that the stream is removed from both pending_streams and
342 * the streams hashtable on reception of the "end of stream"
343 * notification.
344 */
345 end:
346 BT_MOVE(ctf_it->current_notification, notification);
347 bt_put(stream);
348 return ret;
349 }
350
351 static
352 void ctf_fs_iterator_destroy_data(struct ctf_fs_iterator *ctf_it)
353 {
354 if (!ctf_it) {
355 return;
356 }
357 bt_put(ctf_it->current_notification);
358 bt_put(ctf_it->pending_notifications);
359 if (ctf_it->pending_streams) {
360 g_ptr_array_free(ctf_it->pending_streams, TRUE);
361 }
362 if (ctf_it->stream_ht) {
363 g_hash_table_destroy(ctf_it->stream_ht);
364 }
365 g_free(ctf_it);
366 }
367
368 void ctf_fs_iterator_destroy(struct bt_notification_iterator *it)
369 {
370 void *data = bt_notification_iterator_get_private_data(it);
371
372 ctf_fs_iterator_destroy_data(data);
373 }
374
375 static
376 bool compare_event_notifications(struct bt_notification *a,
377 struct bt_notification *b)
378 {
379 int ret;
380 struct bt_ctf_clock_class *clock_class;
381 struct bt_ctf_clock_value *a_clock_value, *b_clock_value;
382 struct bt_ctf_stream_class *a_stream_class;
383 struct bt_ctf_stream *a_stream;
384 struct bt_ctf_event *a_event, *b_event;
385 struct bt_ctf_trace *trace;
386 int64_t a_ts, b_ts;
387
388 // FIXME - assumes only one clock
389 a_event = bt_notification_event_get_event(a);
390 b_event = bt_notification_event_get_event(b);
391 assert(a_event);
392 assert(b_event);
393
394 a_stream = bt_ctf_event_get_stream(a_event);
395 assert(a_stream);
396 a_stream_class = bt_ctf_stream_get_class(a_stream);
397 assert(a_stream_class);
398 trace = bt_ctf_stream_class_get_trace(a_stream_class);
399 assert(trace);
400
401 clock_class = bt_ctf_trace_get_clock_class(trace, 0);
402 a_clock_value = bt_ctf_event_get_clock_value(a_event, clock_class);
403 b_clock_value = bt_ctf_event_get_clock_value(b_event, clock_class);
404 assert(a_clock_value);
405 assert(b_clock_value);
406
407 ret = bt_ctf_clock_value_get_value_ns_from_epoch(a_clock_value, &a_ts);
408 assert(!ret);
409 ret = bt_ctf_clock_value_get_value_ns_from_epoch(b_clock_value, &b_ts);
410 assert(!ret);
411
412 bt_put(a_event);
413 bt_put(b_event);
414 bt_put(a_clock_value);
415 bt_put(b_clock_value);
416 bt_put(a_stream);
417 bt_put(a_stream_class);
418 bt_put(clock_class);
419 bt_put(trace);
420 return a_ts < b_ts;
421 }
422
423 static
424 bool compare_notifications(struct bt_notification *a, struct bt_notification *b,
425 void *unused)
426 {
427 static int notification_priorities[] = {
428 [BT_NOTIFICATION_TYPE_NEW_TRACE] = 0,
429 [BT_NOTIFICATION_TYPE_NEW_STREAM_CLASS] = 1,
430 [BT_NOTIFICATION_TYPE_NEW_EVENT_CLASS] = 2,
431 [BT_NOTIFICATION_TYPE_PACKET_BEGIN] = 3,
432 [BT_NOTIFICATION_TYPE_PACKET_END] = 4,
433 [BT_NOTIFICATION_TYPE_EVENT] = 5,
434 [BT_NOTIFICATION_TYPE_END_OF_TRACE] = 6,
435 };
436 int a_prio, b_prio;
437 enum bt_notification_type a_type, b_type;
438
439 assert(a && b);
440 a_type = bt_notification_get_type(a);
441 b_type = bt_notification_get_type(b);
442 assert(a_type > BT_NOTIFICATION_TYPE_ALL);
443 assert(a_type < BT_NOTIFICATION_TYPE_NR);
444 assert(b_type > BT_NOTIFICATION_TYPE_ALL);
445 assert(b_type < BT_NOTIFICATION_TYPE_NR);
446
447 a_prio = notification_priorities[a_type];
448 b_prio = notification_priorities[b_type];
449
450 if (likely((a_type == b_type) && a_type == BT_NOTIFICATION_TYPE_EVENT)) {
451 return compare_event_notifications(a, b);
452 }
453
454 if (unlikely(a_prio != b_prio)) {
455 return a_prio < b_prio;
456 }
457
458 /* Notification types are equal, but not of type "event". */
459 switch (a_type) {
460 case BT_NOTIFICATION_TYPE_PACKET_BEGIN:
461 case BT_NOTIFICATION_TYPE_PACKET_END:
462 case BT_NOTIFICATION_TYPE_STREAM_END:
463 {
464 int64_t a_sc_id, b_sc_id;
465 struct bt_ctf_stream *a_stream, *b_stream;
466 struct bt_ctf_stream_class *a_sc, *b_sc;
467
468 a_stream = internal_bt_notification_get_stream(a);
469 b_stream = internal_bt_notification_get_stream(b);
470 assert(a_stream && b_stream);
471
472 a_sc = bt_ctf_stream_get_class(a_stream);
473 b_sc = bt_ctf_stream_get_class(b_stream);
474 assert(a_sc && b_sc);
475
476 a_sc_id = bt_ctf_stream_class_get_id(a_sc);
477 b_sc_id = bt_ctf_stream_class_get_id(b_sc);
478 assert(a_sc_id >= 0 && b_sc_id >= 0);
479 bt_put(a_sc);
480 bt_put(a_stream);
481 bt_put(b_sc);
482 bt_put(b_stream);
483 return a_sc_id < b_sc_id;
484 }
485 case BT_NOTIFICATION_TYPE_NEW_TRACE:
486 case BT_NOTIFICATION_TYPE_END_OF_TRACE:
487 /* Impossible to have two separate traces. */
488 default:
489 assert(0);
490 }
491
492 assert(0);
493 return a < b;
494 }
495
496 static
497 void stream_destroy(void *stream)
498 {
499 ctf_fs_stream_destroy((struct ctf_fs_stream *) stream);
500 }
501
502 static
503 int open_trace_streams(struct ctf_fs_component *ctf_fs,
504 struct ctf_fs_iterator *ctf_it)
505 {
506 int ret = 0;
507 const char *name;
508 GError *error = NULL;
509 GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
510
511 if (!dir) {
512 PERR("Cannot open directory \"%s\": %s (code %d)\n",
513 ctf_fs->trace_path->str, error->message,
514 error->code);
515 goto error;
516 }
517
518 while ((name = g_dir_read_name(dir))) {
519 struct ctf_fs_file *file = NULL;
520 struct ctf_fs_stream *stream = NULL;
521
522 if (!strcmp(name, CTF_FS_METADATA_FILENAME)) {
523 /* Ignore the metadata stream. */
524 PDBG("Ignoring metadata file \"%s\"\n",
525 name);
526 continue;
527 }
528
529 if (name[0] == '.') {
530 PDBG("Ignoring hidden file \"%s\"\n",
531 name);
532 continue;
533 }
534
535 /* Create the file. */
536 file = ctf_fs_file_create(ctf_fs);
537 if (!file) {
538 PERR("Cannot create stream file object\n");
539 goto error;
540 }
541
542 /* Create full path string. */
543 g_string_append_printf(file->path, "%s/%s",
544 ctf_fs->trace_path->str, name);
545 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
546 PDBG("Ignoring non-regular file \"%s\"\n", name);
547 ctf_fs_file_destroy(file);
548 continue;
549 }
550
551 /* Open the file. */
552 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
553 ctf_fs_file_destroy(file);
554 goto error;
555 }
556
557 if (file->size == 0) {
558 /* Skip empty stream. */
559 ctf_fs_file_destroy(file);
560 continue;
561 }
562
563 /* Create a private stream; file ownership is passed to it. */
564 stream = ctf_fs_stream_create(ctf_fs, file);
565 if (!stream) {
566 ctf_fs_file_destroy(file);
567 goto error;
568 }
569
570 g_ptr_array_add(ctf_it->pending_streams, stream);
571 }
572
573 goto end;
574 error:
575 ret = -1;
576 end:
577 if (dir) {
578 g_dir_close(dir);
579 dir = NULL;
580 }
581 if (error) {
582 g_error_free(error);
583 }
584 return ret;
585 }
586
587 enum bt_notification_iterator_status ctf_fs_iterator_init(struct bt_component *source,
588 struct bt_notification_iterator *it,
589 UNUSED_VAR void *init_method_data)
590 {
591 struct ctf_fs_iterator *ctf_it;
592 struct ctf_fs_component *ctf_fs;
593 enum bt_notification_iterator_status ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
594
595 assert(source && it);
596
597 ctf_fs = bt_component_get_private_data(source);
598 if (!ctf_fs) {
599 ret = BT_NOTIFICATION_ITERATOR_STATUS_INVAL;
600 goto end;
601 }
602
603 ctf_it = g_new0(struct ctf_fs_iterator, 1);
604 if (!ctf_it) {
605 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
606 goto end;
607 }
608
609 ctf_it->stream_ht = g_hash_table_new_full(g_direct_hash,
610 g_direct_equal, bt_put, stream_destroy);
611 if (!ctf_it->stream_ht) {
612 goto error;
613 }
614 ctf_it->pending_streams = g_ptr_array_new_with_free_func(
615 stream_destroy);
616 if (!ctf_it->pending_streams) {
617 goto error;
618 }
619 ctf_it->pending_notifications = bt_notification_heap_create(
620 compare_notifications, NULL);
621 if (!ctf_it->pending_notifications) {
622 goto error;
623 }
624
625 ret = open_trace_streams(ctf_fs, ctf_it);
626 if (ret) {
627 goto error;
628 }
629
630 ret = bt_notification_iterator_set_private_data(it, ctf_it);
631 if (ret) {
632 goto error;
633 }
634
635 end:
636 return ret;
637 error:
638 (void) bt_notification_iterator_set_private_data(it, NULL);
639 ctf_fs_iterator_destroy_data(ctf_it);
640 goto end;
641 }
642
643 static
644 void ctf_fs_destroy_data(struct ctf_fs_component *ctf_fs)
645 {
646 if (!ctf_fs) {
647 return;
648 }
649 if (ctf_fs->trace_path) {
650 g_string_free(ctf_fs->trace_path, TRUE);
651 }
652 if (ctf_fs->metadata) {
653 ctf_fs_metadata_fini(ctf_fs->metadata);
654 g_free(ctf_fs->metadata);
655 }
656 g_free(ctf_fs);
657 }
658
659 void ctf_fs_destroy(struct bt_component *component)
660 {
661 void *data = bt_component_get_private_data(component);
662
663 ctf_fs_destroy_data(data);
664 }
665
666 static
667 struct ctf_fs_component *ctf_fs_create(struct bt_value *params)
668 {
669 struct ctf_fs_component *ctf_fs;
670 struct bt_value *value = NULL;
671 const char *path;
672 enum bt_value_status ret;
673
674 ctf_fs = g_new0(struct ctf_fs_component, 1);
675 if (!ctf_fs) {
676 goto end;
677 }
678
679 /* FIXME: should probably look for a source URI */
680 value = bt_value_map_get(params, "path");
681 if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) {
682 goto error;
683 }
684
685 ret = bt_value_string_get(value, &path);
686 if (ret != BT_VALUE_STATUS_OK) {
687 goto error;
688 }
689
690 ctf_fs->trace_path = g_string_new(path);
691 if (!ctf_fs->trace_path) {
692 goto error;
693 }
694 ctf_fs->error_fp = stderr;
695 ctf_fs->page_size = (size_t) getpagesize();
696
697 // FIXME: check error.
698 ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1);
699 if (!ctf_fs->metadata) {
700 goto error;
701 }
702 ctf_fs_metadata_set_trace(ctf_fs);
703 goto end;
704
705 error:
706 ctf_fs_destroy_data(ctf_fs);
707 ctf_fs = NULL;
708 end:
709 BT_PUT(value);
710 return ctf_fs;
711 }
712
713 BT_HIDDEN
714 enum bt_component_status ctf_fs_init(struct bt_component *source,
715 struct bt_value *params, UNUSED_VAR void *init_method_data)
716 {
717 struct ctf_fs_component *ctf_fs;
718 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
719
720 assert(source);
721 ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
722 ctf_fs = ctf_fs_create(params);
723 if (!ctf_fs) {
724 ret = BT_COMPONENT_STATUS_NOMEM;
725 goto end;
726 }
727
728 ret = bt_component_set_private_data(source, ctf_fs);
729 if (ret != BT_COMPONENT_STATUS_OK) {
730 goto error;
731 }
732 end:
733 return ret;
734 error:
735 (void) bt_component_set_private_data(source, NULL);
736 ctf_fs_destroy_data(ctf_fs);
737 return ret;
738 }
739
740 BT_HIDDEN
741 struct bt_value *ctf_fs_query_info(struct bt_component_class *comp_class,
742 const char *action, struct bt_value *params)
743 {
744 struct bt_value *results = NULL;
745 struct bt_value *path_value = NULL;
746 char *metadata_text = NULL;
747 FILE *metadata_fp = NULL;
748 GString *g_metadata_text = NULL;
749
750 if (strcmp(action, "get-metadata-info") == 0) {
751 int ret;
752 int bo;
753 const char *path;
754 bool is_packetized;
755
756 results = bt_value_map_create();
757 if (!results) {
758 goto error;
759 }
760
761 if (!bt_value_is_map(params)) {
762 fprintf(stderr,
763 "Query info parameters is not a map value object\n");
764 goto error;
765 }
766
767 path_value = bt_value_map_get(params, "path");
768 ret = bt_value_string_get(path_value, &path);
769 if (ret) {
770 fprintf(stderr,
771 "Cannot get `path` string parameter\n");
772 goto error;
773 }
774
775 assert(path);
776 metadata_fp = ctf_fs_metadata_open_file(path);
777 if (!metadata_fp) {
778 fprintf(stderr,
779 "Cannot open trace at path `%s`\n", path);
780 goto error;
781 }
782
783 is_packetized = ctf_metadata_is_packetized(metadata_fp, &bo);
784
785 if (is_packetized) {
786 ret = ctf_metadata_packetized_file_to_buf(NULL,
787 metadata_fp, (uint8_t **) &metadata_text, bo);
788 if (ret) {
789 fprintf(stderr,
790 "Cannot decode packetized metadata file\n");
791 goto error;
792 }
793 } else {
794 long filesize;
795
796 fseek(metadata_fp, 0, SEEK_END);
797 filesize = ftell(metadata_fp);
798 rewind(metadata_fp);
799 metadata_text = malloc(filesize + 1);
800 if (!metadata_text) {
801 fprintf(stderr,
802 "Cannot allocate buffer for metadata text\n");
803 goto error;
804 }
805
806 if (fread(metadata_text, filesize, 1, metadata_fp) !=
807 1) {
808 fprintf(stderr,
809 "Cannot read metadata file\n");
810 goto error;
811 }
812
813 metadata_text[filesize] = '\0';
814 }
815
816 g_metadata_text = g_string_new(NULL);
817 if (!g_metadata_text) {
818 goto error;
819 }
820
821 if (strncmp(metadata_text, METADATA_TEXT_SIG,
822 sizeof(METADATA_TEXT_SIG) - 1) != 0) {
823 g_string_assign(g_metadata_text, METADATA_TEXT_SIG);
824 g_string_append(g_metadata_text, " */\n\n");
825 }
826
827 g_string_append(g_metadata_text, metadata_text);
828
829 ret = bt_value_map_insert_string(results, "text",
830 g_metadata_text->str);
831 if (ret) {
832 fprintf(stderr, "Cannot insert metadata text into results\n");
833 goto error;
834 }
835
836 ret = bt_value_map_insert_bool(results, "is-packetized",
837 is_packetized);
838 if (ret) {
839 fprintf(stderr, "Cannot insert is packetized into results\n");
840 goto error;
841 }
842 } else {
843 fprintf(stderr, "Unknown query info action `%s`\n", action);
844 goto error;
845 }
846
847 goto end;
848
849 error:
850 BT_PUT(results);
851
852 end:
853 bt_put(path_value);
854 free(metadata_text);
855
856 if (g_metadata_text) {
857 g_string_free(g_metadata_text, TRUE);
858 }
859
860 if (metadata_fp) {
861 fclose(metadata_fp);
862 }
863 return results;
864 }
This page took 0.044964 seconds and 3 git commands to generate.