6bcadd2ca3bf481d87bc1f705a444621c2ec7eca
[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/plugin/plugin-system.h>
30 #include <babeltrace/ctf-ir/packet.h>
31 #include <babeltrace/ctf-ir/clock.h>
32 #include <babeltrace/plugin/notification/iterator.h>
33 #include <babeltrace/plugin/notification/stream.h>
34 #include <babeltrace/plugin/notification/event.h>
35 #include <babeltrace/plugin/notification/packet.h>
36 #include <babeltrace/plugin/notification/heap.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
49 static bool ctf_fs_debug;
50
51 static
52 struct bt_notification *ctf_fs_iterator_get(
53 struct bt_notification_iterator *iterator)
54 {
55 struct ctf_fs_iterator *ctf_it =
56 bt_notification_iterator_get_private_data(iterator);
57
58 return bt_get(ctf_it->current_notification);
59 }
60
61 static
62 enum bt_notification_iterator_status ctf_fs_iterator_get_next_notification(
63 struct ctf_fs_iterator *it,
64 struct ctf_fs_stream *stream,
65 struct bt_notification **notification)
66 {
67 enum bt_ctf_notif_iter_status status;
68 enum bt_notification_iterator_status ret;
69
70 if (stream->end_reached) {
71 status = BT_CTF_NOTIF_ITER_STATUS_EOF;
72 goto end;
73 }
74
75 status = bt_ctf_notif_iter_get_next_notification(stream->notif_iter,
76 notification);
77 if (status != BT_CTF_NOTIF_ITER_STATUS_OK &&
78 status != BT_CTF_NOTIF_ITER_STATUS_EOF) {
79 goto end;
80 }
81
82 /* Should be handled in bt_ctf_notif_iter_get_next_notification. */
83 if (status == BT_CTF_NOTIF_ITER_STATUS_EOF) {
84 *notification = bt_notification_stream_end_create(
85 stream->stream);
86 if (!*notification) {
87 status = BT_CTF_NOTIF_ITER_STATUS_ERROR;
88 }
89 status = BT_CTF_NOTIF_ITER_STATUS_OK;
90 stream->end_reached = true;
91 }
92 end:
93 switch (status) {
94 case BT_CTF_NOTIF_ITER_STATUS_EOF:
95 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
96 break;
97 case BT_CTF_NOTIF_ITER_STATUS_OK:
98 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
99 break;
100 case BT_CTF_NOTIF_ITER_STATUS_AGAIN:
101 /*
102 * Should not make it this far as this is medium-specific;
103 * there is nothing for the user to do and it should have been
104 * handled upstream.
105 */
106 assert(0);
107 case BT_CTF_NOTIF_ITER_STATUS_INVAL:
108 /* No argument provided by the user, so don't return INVAL. */
109 case BT_CTF_NOTIF_ITER_STATUS_ERROR:
110 default:
111 ret = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
112 break;
113 }
114 return ret;
115 }
116
117 /*
118 * Remove me. This is a temporary work-around due to our inhability to use
119 * libbabeltrace-ctf from libbabeltrace-plugin.
120 */
121 static
122 struct bt_ctf_stream *internal_bt_notification_get_stream(
123 struct bt_notification *notification)
124 {
125 struct bt_ctf_stream *stream = NULL;
126
127 assert(notification);
128 switch (bt_notification_get_type(notification)) {
129 case BT_NOTIFICATION_TYPE_EVENT:
130 {
131 struct bt_ctf_event *event;
132
133 event = bt_notification_event_get_event(notification);
134 stream = bt_ctf_event_get_stream(event);
135 bt_put(event);
136 break;
137 }
138 case BT_NOTIFICATION_TYPE_PACKET_START:
139 {
140 struct bt_ctf_packet *packet;
141
142 packet = bt_notification_packet_start_get_packet(notification);
143 stream = bt_ctf_packet_get_stream(packet);
144 bt_put(packet);
145 break;
146 }
147 case BT_NOTIFICATION_TYPE_PACKET_END:
148 {
149 struct bt_ctf_packet *packet;
150
151 packet = bt_notification_packet_end_get_packet(notification);
152 stream = bt_ctf_packet_get_stream(packet);
153 bt_put(packet);
154 break;
155 }
156 case BT_NOTIFICATION_TYPE_STREAM_END:
157 stream = bt_notification_stream_end_get_stream(notification);
158 break;
159 default:
160 goto end;
161 }
162 end:
163 return stream;
164 }
165
166 static
167 enum bt_notification_iterator_status populate_heap(struct ctf_fs_iterator *it)
168 {
169 size_t i, pending_streams_count = it->pending_streams->len;
170 enum bt_notification_iterator_status ret =
171 BT_NOTIFICATION_ITERATOR_STATUS_OK;
172
173 /* Insert one stream-associated notification for each stream. */
174 for (i = 0; i < pending_streams_count; i++) {
175 struct bt_notification *notification;
176 struct ctf_fs_stream *fs_stream;
177 struct bt_ctf_stream *stream;
178 size_t pending_stream_index = pending_streams_count - 1 - i;
179
180 fs_stream = g_ptr_array_index(it->pending_streams,
181 pending_stream_index);
182
183 do {
184 int heap_ret;
185
186 ret = ctf_fs_iterator_get_next_notification(
187 it, fs_stream, &notification);
188 if (ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END) {
189 printf_debug("Failed to populate heap at stream %zu\n",
190 pending_stream_index);
191 goto end;
192 }
193
194 stream = internal_bt_notification_get_stream(
195 notification);
196 if (stream) {
197 gboolean inserted;
198
199 /*
200 * Associate pending ctf_fs_stream to
201 * bt_ctf_stream. Ownership of stream
202 * is passed to the stream ht.
203 */
204 inserted = g_hash_table_insert(it->stream_ht,
205 stream, fs_stream);
206 if (!inserted) {
207 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
208 printf_debug("Failed to associate fs stream to ctf stream\n");
209 goto end;
210 }
211 }
212
213 heap_ret = bt_notification_heap_insert(
214 it->pending_notifications,
215 notification);
216 bt_put(notification);
217 if (heap_ret) {
218 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
219 printf_debug("Failed to insert notification in heap\n");
220 goto end;
221 }
222 } while (!stream && ret != BT_NOTIFICATION_ITERATOR_STATUS_END);
223 /*
224 * Set NULL so the destruction callback registered with the
225 * array is not invoked on the stream (its ownership was
226 * transferred to the streams hashtable).
227 */
228 g_ptr_array_index(it->pending_streams,
229 pending_stream_index) = NULL;
230 g_ptr_array_remove_index(it->pending_streams,
231 pending_stream_index);
232 }
233
234 g_ptr_array_free(it->pending_streams, TRUE);
235 it->pending_streams = NULL;
236 end:
237 return ret;
238 }
239
240 static
241 enum bt_notification_iterator_status ctf_fs_iterator_next(
242 struct bt_notification_iterator *iterator)
243 {
244 int heap_ret;
245 struct bt_ctf_stream *stream = NULL;
246 struct ctf_fs_stream *fs_stream;
247 struct bt_notification *notification;
248 struct bt_notification *next_stream_notification;
249 enum bt_notification_iterator_status ret =
250 BT_NOTIFICATION_ITERATOR_STATUS_OK;
251 struct ctf_fs_iterator *ctf_it =
252 bt_notification_iterator_get_private_data(iterator);
253
254 notification = bt_notification_heap_pop(ctf_it->pending_notifications);
255 if (!notification && !ctf_it->pending_streams) {
256 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
257 goto end;
258 }
259
260 if (!notification && ctf_it->pending_streams) {
261 /*
262 * Insert at one notification per stream in the heap and pop
263 * one.
264 */
265 ret = populate_heap(ctf_it);
266 if (ret) {
267 goto end;
268 }
269
270 notification = bt_notification_heap_pop(
271 ctf_it->pending_notifications);
272 if (!notification) {
273 ret = BT_NOTIFICATION_ITERATOR_STATUS_END;
274 goto end;
275 }
276 }
277
278 /* notification is set from here. */
279
280 stream = internal_bt_notification_get_stream(notification);
281 if (!stream) {
282 /*
283 * The current notification is not associated to a particular
284 * stream, there is no need to insert a new notification from
285 * a stream in the heap.
286 */
287 goto end;
288 }
289
290 fs_stream = g_hash_table_lookup(ctf_it->stream_ht, stream);
291 if (!fs_stream) {
292 /* We have reached this stream's end. */
293 goto end;
294 }
295
296 ret = ctf_fs_iterator_get_next_notification(ctf_it, fs_stream,
297 &next_stream_notification);
298 if ((ret && ret != BT_NOTIFICATION_ITERATOR_STATUS_END)) {
299 heap_ret = bt_notification_heap_insert(
300 ctf_it->pending_notifications, notification);
301
302 assert(!next_stream_notification);
303 if (heap_ret) {
304 /*
305 * We're dropping the most recent notification, but at
306 * this point, something is seriously wrong...
307 */
308 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
309 }
310 BT_PUT(notification);
311 goto end;
312 }
313
314 if (ret == BT_NOTIFICATION_ITERATOR_STATUS_END) {
315 gboolean success;
316
317 /* Remove stream. */
318 success = g_hash_table_remove(ctf_it->stream_ht, stream);
319 assert(success);
320 ret = BT_NOTIFICATION_ITERATOR_STATUS_OK;
321 } else {
322 heap_ret = bt_notification_heap_insert(ctf_it->pending_notifications,
323 next_stream_notification);
324 BT_PUT(next_stream_notification);
325 if (heap_ret) {
326 /*
327 * We're dropping the most recent notification...
328 */
329 ret = BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
330 }
331 }
332
333 /*
334 * Ensure that the stream is removed from both pending_streams and
335 * the streams hashtable on reception of the "end of stream"
336 * notification.
337 */
338 end:
339 BT_MOVE(ctf_it->current_notification, notification);
340 bt_put(stream);
341 return ret;
342 }
343
344 static
345 void ctf_fs_iterator_destroy_data(struct ctf_fs_iterator *ctf_it)
346 {
347 bt_put(ctf_it->current_notification);
348 bt_put(ctf_it->pending_notifications);
349 if (ctf_it->pending_streams) {
350 g_ptr_array_free(ctf_it->pending_streams, TRUE);
351 }
352 if (ctf_it->stream_ht) {
353 g_hash_table_destroy(ctf_it->stream_ht);
354 }
355 g_free(ctf_it);
356 }
357
358 static
359 void ctf_fs_iterator_destroy(struct bt_notification_iterator *it)
360 {
361 void *data = bt_notification_iterator_get_private_data(it);
362
363 ctf_fs_iterator_destroy_data(data);
364 }
365
366 static
367 bool compare_event_notifications(struct bt_notification *a,
368 struct bt_notification *b)
369 {
370 int ret;
371 struct bt_ctf_clock *clock;
372 struct bt_ctf_clock_value *a_clock_value, *b_clock_value;
373 struct bt_ctf_stream_class *a_stream_class;
374 struct bt_ctf_stream *a_stream;
375 struct bt_ctf_event *a_event, *b_event;
376 struct bt_ctf_trace *trace;
377 int64_t a_ts, b_ts;
378
379 // FIXME - assumes only one clock
380 a_event = bt_notification_event_get_event(a);
381 b_event = bt_notification_event_get_event(b);
382 assert(a_event);
383 assert(b_event);
384
385 a_stream = bt_ctf_event_get_stream(a_event);
386 assert(a_stream);
387 a_stream_class = bt_ctf_stream_get_class(a_stream);
388 assert(a_stream_class);
389 trace = bt_ctf_stream_class_get_trace(a_stream_class);
390 assert(trace);
391
392 clock = bt_ctf_trace_get_clock(trace, 0);
393 a_clock_value = bt_ctf_event_get_clock_value(a_event, clock);
394 b_clock_value = bt_ctf_event_get_clock_value(b_event, clock);
395 assert(a_clock_value);
396 assert(b_clock_value);
397
398 ret = bt_ctf_clock_value_get_value_ns_from_epoch(a_clock_value, &a_ts);
399 assert(!ret);
400 ret = bt_ctf_clock_value_get_value_ns_from_epoch(b_clock_value, &b_ts);
401 assert(!ret);
402
403 bt_put(a_event);
404 bt_put(b_event);
405 bt_put(a_clock_value);
406 bt_put(b_clock_value);
407 bt_put(a_stream);
408 bt_put(a_stream_class);
409 bt_put(clock);
410 bt_put(trace);
411 return a_ts < b_ts;
412 }
413
414 static
415 bool compare_notifications(struct bt_notification *a, struct bt_notification *b,
416 void *unused)
417 {
418 static int notification_priorities[] = {
419 [BT_NOTIFICATION_TYPE_NEW_TRACE] = 0,
420 [BT_NOTIFICATION_TYPE_NEW_STREAM_CLASS] = 1,
421 [BT_NOTIFICATION_TYPE_NEW_EVENT_CLASS] = 2,
422 [BT_NOTIFICATION_TYPE_PACKET_START] = 3,
423 [BT_NOTIFICATION_TYPE_PACKET_END] = 4,
424 [BT_NOTIFICATION_TYPE_EVENT] = 5,
425 [BT_NOTIFICATION_TYPE_END_OF_TRACE] = 6,
426 };
427 int a_prio, b_prio;
428 enum bt_notification_type a_type, b_type;
429
430 assert(a && b);
431 a_type = bt_notification_get_type(a);
432 b_type = bt_notification_get_type(b);
433 assert(a_type > BT_NOTIFICATION_TYPE_ALL);
434 assert(a_type < BT_NOTIFICATION_TYPE_NR);
435 assert(b_type > BT_NOTIFICATION_TYPE_ALL);
436 assert(b_type < BT_NOTIFICATION_TYPE_NR);
437
438 a_prio = notification_priorities[a_type];
439 b_prio = notification_priorities[b_type];
440
441 if (likely((a_type == b_type) && a_type == BT_NOTIFICATION_TYPE_EVENT)) {
442 return compare_event_notifications(a, b);
443 }
444
445 if (unlikely(a_prio != b_prio)) {
446 return a_prio < b_prio;
447 }
448
449 /* Notification types are equal, but not of type "event". */
450 switch (a_type) {
451 case BT_NOTIFICATION_TYPE_PACKET_START:
452 case BT_NOTIFICATION_TYPE_PACKET_END:
453 case BT_NOTIFICATION_TYPE_STREAM_END:
454 {
455 int64_t a_sc_id, b_sc_id;
456 struct bt_ctf_stream *a_stream, *b_stream;
457 struct bt_ctf_stream_class *a_sc, *b_sc;
458
459 a_stream = internal_bt_notification_get_stream(a);
460 b_stream = internal_bt_notification_get_stream(b);
461 assert(a_stream && b_stream);
462
463 a_sc = bt_ctf_stream_get_class(a_stream);
464 b_sc = bt_ctf_stream_get_class(b_stream);
465 assert(a_sc && b_sc);
466
467 a_sc_id = bt_ctf_stream_class_get_id(a_sc);
468 b_sc_id = bt_ctf_stream_class_get_id(b_sc);
469 assert(a_sc_id >= 0 && b_sc_id >= 0);
470 bt_put(a_sc);
471 bt_put(a_stream);
472 bt_put(b_sc);
473 bt_put(b_stream);
474 return a_sc_id < b_sc_id;
475 }
476 case BT_NOTIFICATION_TYPE_NEW_TRACE:
477 case BT_NOTIFICATION_TYPE_END_OF_TRACE:
478 /* Impossible to have two separate traces. */
479 default:
480 assert(0);
481 }
482
483 assert(0);
484 return a < b;
485 }
486
487 static
488 void stream_destroy(void *stream)
489 {
490 ctf_fs_stream_destroy((struct ctf_fs_stream *) stream);
491 }
492
493 static
494 int open_trace_streams(struct ctf_fs_component *ctf_fs,
495 struct ctf_fs_iterator *ctf_it)
496 {
497 int ret = 0;
498 const char *name;
499 GError *error = NULL;
500 GDir *dir = g_dir_open(ctf_fs->trace_path->str, 0, &error);
501
502 if (!dir) {
503 PERR("Cannot open directory \"%s\": %s (code %d)\n",
504 ctf_fs->trace_path->str, error->message,
505 error->code);
506 goto error;
507 }
508
509 while ((name = g_dir_read_name(dir))) {
510 struct ctf_fs_file *file = NULL;
511 struct ctf_fs_stream *stream = NULL;
512
513 if (!strcmp(name, CTF_FS_METADATA_FILENAME)) {
514 /* Ignore the metadata stream. */
515 PDBG("Ignoring metadata file \"%s\"\n",
516 name);
517 continue;
518 }
519
520 if (name[0] == '.') {
521 PDBG("Ignoring hidden file \"%s\"\n",
522 name);
523 continue;
524 }
525
526 /* Create the file. */
527 file = ctf_fs_file_create(ctf_fs);
528 if (!file) {
529 PERR("Cannot create stream file object\n");
530 goto error;
531 }
532
533 /* Create full path string. */
534 g_string_append_printf(file->path, "%s/%s",
535 ctf_fs->trace_path->str, name);
536 if (!g_file_test(file->path->str, G_FILE_TEST_IS_REGULAR)) {
537 PDBG("Ignoring non-regular file \"%s\"\n", name);
538 ctf_fs_file_destroy(file);
539 continue;
540 }
541
542 /* Open the file. */
543 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
544 ctf_fs_file_destroy(file);
545 goto error;
546 }
547
548 /* Create a private stream; file ownership is passed to it. */
549 stream = ctf_fs_stream_create(ctf_fs, file);
550 if (!stream) {
551 ctf_fs_file_destroy(file);
552 goto error;
553 }
554
555 g_ptr_array_add(ctf_it->pending_streams, stream);
556 }
557
558 goto end;
559 error:
560 ret = -1;
561 end:
562 if (dir) {
563 g_dir_close(dir);
564 dir = NULL;
565 }
566 if (error) {
567 g_error_free(error);
568 }
569 return ret;
570 }
571
572 static
573 enum bt_component_status ctf_fs_iterator_init(struct bt_component *source,
574 struct bt_notification_iterator *it)
575 {
576 struct ctf_fs_iterator *ctf_it;
577 struct ctf_fs_component *ctf_fs;
578 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
579
580 assert(source && it);
581
582 ctf_fs = bt_component_get_private_data(source);
583 if (!ctf_fs) {
584 ret = BT_COMPONENT_STATUS_INVALID;
585 goto end;
586 }
587
588 ctf_it = g_new0(struct ctf_fs_iterator, 1);
589 if (!ctf_it) {
590 ret = BT_COMPONENT_STATUS_NOMEM;
591 goto end;
592 }
593
594 ctf_it->stream_ht = g_hash_table_new_full(g_direct_hash,
595 g_direct_equal, bt_put, stream_destroy);
596 if (!ctf_it->stream_ht) {
597 goto error;
598 }
599 ctf_it->pending_streams = g_ptr_array_new_with_free_func(
600 stream_destroy);
601 if (!ctf_it->pending_streams) {
602 goto error;
603 }
604 ctf_it->pending_notifications = bt_notification_heap_create(
605 compare_notifications, NULL);
606 if (!ctf_it->pending_notifications) {
607 goto error;
608 }
609
610 ret = open_trace_streams(ctf_fs, ctf_it);
611 if (ret) {
612 goto error;
613 }
614
615 ret = bt_notification_iterator_set_get_cb(it, ctf_fs_iterator_get);
616 if (ret) {
617 goto error;
618 }
619
620 ret = bt_notification_iterator_set_next_cb(it, ctf_fs_iterator_next);
621 if (ret) {
622 goto error;
623 }
624
625 ret = bt_notification_iterator_set_destroy_cb(it,
626 ctf_fs_iterator_destroy);
627 if (ret) {
628 goto error;
629 }
630
631 ret = bt_notification_iterator_set_private_data(it, ctf_it);
632 if (ret) {
633 goto error;
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->trace_path) {
647 g_string_free(ctf_fs->trace_path, TRUE);
648 }
649 if (ctf_fs->metadata) {
650 ctf_fs_metadata_fini(ctf_fs->metadata);
651 g_free(ctf_fs->metadata);
652 }
653 g_free(ctf_fs);
654 }
655
656 static
657 void ctf_fs_destroy(struct bt_component *component)
658 {
659 void *data = bt_component_get_private_data(component);
660
661 ctf_fs_destroy_data(data);
662 }
663
664 static
665 struct ctf_fs_component *ctf_fs_create(struct bt_value *params)
666 {
667 struct ctf_fs_component *ctf_fs;
668 struct bt_value *value = NULL;
669 const char *path;
670 enum bt_value_status ret;
671
672 ctf_fs = g_new0(struct ctf_fs_component, 1);
673 if (!ctf_fs) {
674 goto end;
675 }
676
677 /* FIXME: should probably look for a source URI */
678 value = bt_value_map_get(params, "path");
679 if (!value || bt_value_is_null(value) || !bt_value_is_string(value)) {
680 goto error;
681 }
682
683 ret = bt_value_string_get(value, &path);
684 if (ret != BT_VALUE_STATUS_OK) {
685 goto error;
686 }
687
688 ctf_fs->trace_path = g_string_new(path);
689 if (!ctf_fs->trace_path) {
690 goto error;
691 }
692 ctf_fs->error_fp = stderr;
693 ctf_fs->page_size = (size_t) getpagesize();
694
695 // FIXME: check error.
696 ctf_fs->metadata = g_new0(struct ctf_fs_metadata, 1);
697 if (!ctf_fs->metadata) {
698 goto error;
699 }
700 ctf_fs_metadata_set_trace(ctf_fs);
701 goto end;
702
703 error:
704 ctf_fs_destroy_data(ctf_fs);
705 ctf_fs = NULL;
706 end:
707 BT_PUT(value);
708 return ctf_fs;
709 }
710
711 BT_HIDDEN
712 enum bt_component_status ctf_fs_init(struct bt_component *source,
713 struct bt_value *params)
714 {
715 struct ctf_fs_component *ctf_fs;
716 enum bt_component_status ret = BT_COMPONENT_STATUS_OK;
717
718 assert(source);
719 ctf_fs_debug = g_strcmp0(getenv("CTF_FS_DEBUG"), "1") == 0;
720 ctf_fs = ctf_fs_create(params);
721 if (!ctf_fs) {
722 ret = BT_COMPONENT_STATUS_NOMEM;
723 goto end;
724 }
725
726 ret = bt_component_set_destroy_cb(source, ctf_fs_destroy);
727 if (ret != BT_COMPONENT_STATUS_OK) {
728 goto error;
729 }
730
731 ret = bt_component_set_private_data(source, ctf_fs);
732 if (ret != BT_COMPONENT_STATUS_OK) {
733 goto error;
734 }
735
736 ret = bt_component_source_set_iterator_init_cb(source,
737 ctf_fs_iterator_init);
738 if (ret != BT_COMPONENT_STATUS_OK) {
739 goto error;
740 }
741 end:
742 return ret;
743 error:
744 (void) bt_component_set_private_data(source, NULL);
745 ctf_fs_destroy_data(ctf_fs);
746 return ret;
747 }
This page took 0.04369 seconds and 3 git commands to generate.