Add structure align() attribute, fix empty string support in definition paths
[babeltrace.git] / formats / ctf / ctf.c
1 /*
2 * BabelTrace - Common Trace Format (CTF)
3 *
4 * Format registration.
5 *
6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
7 *
8 * Permission is hereby granted, free of charge, to any person obtaining a copy
9 * of this software and associated documentation files (the "Software"), to deal
10 * in the Software without restriction, including without limitation the rights
11 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 * copies of the Software, and to permit persons to whom the Software is
13 * furnished to do so, subject to the following conditions:
14 *
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
17 */
18
19 #include <babeltrace/format.h>
20 #include <babeltrace/ctf/types.h>
21 #include <babeltrace/ctf/metadata.h>
22 #include <babeltrace/babeltrace.h>
23 #include <inttypes.h>
24 #include <uuid/uuid.h>
25 #include <sys/mman.h>
26 #include <errno.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
30 #include <dirent.h>
31 #include <glib.h>
32 #include <unistd.h>
33 #include <stdlib.h>
34
35 #include "metadata/ctf-scanner.h"
36 #include "metadata/ctf-parser.h"
37 #include "metadata/ctf-ast.h"
38
39 /*
40 * We currently simply map a page to read the packet header and packet
41 * context to get the packet length and content length. (in bits)
42 */
43 #define MAX_PACKET_HEADER_LEN (getpagesize() * CHAR_BIT)
44 #define WRITE_PACKET_LEN (getpagesize() * 8 * CHAR_BIT)
45 #define UUID_LEN 16 /* uuid by value len */
46
47 extern int yydebug;
48
49 struct trace_descriptor *ctf_open_trace(const char *path, int flags);
50 void ctf_close_trace(struct trace_descriptor *descriptor);
51
52 static
53 rw_dispatch read_dispatch_table[] = {
54 [ CTF_TYPE_INTEGER ] = ctf_integer_read,
55 [ CTF_TYPE_FLOAT ] = ctf_float_read,
56 [ CTF_TYPE_ENUM ] = ctf_enum_read,
57 [ CTF_TYPE_STRING ] = ctf_string_read,
58 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
59 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
60 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
61 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
62 };
63
64 static
65 rw_dispatch write_dispatch_table[] = {
66 [ CTF_TYPE_INTEGER ] = ctf_integer_write,
67 [ CTF_TYPE_FLOAT ] = ctf_float_write,
68 [ CTF_TYPE_ENUM ] = ctf_enum_write,
69 [ CTF_TYPE_STRING ] = ctf_string_write,
70 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
71 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
72 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
73 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
74 };
75
76 static
77 struct format ctf_format = {
78 .open_trace = ctf_open_trace,
79 .close_trace = ctf_close_trace,
80 };
81
82 static
83 int ctf_read_event(struct stream_pos *ppos, struct ctf_stream *stream)
84 {
85 struct ctf_stream_pos *pos =
86 container_of(ppos, struct ctf_stream_pos, parent);
87 struct ctf_stream_class *stream_class = stream->stream_class;
88 struct ctf_event *event_class;
89 uint64_t id = 0;
90 int len_index;
91 int ret;
92
93 if (pos->offset == EOF)
94 return EOF;
95
96 /* Read event header */
97 if (stream_class->event_header) {
98 ret = generic_rw(ppos, &stream_class->event_header->p);
99 if (ret)
100 goto error;
101 /* lookup event id */
102 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
103 g_quark_from_static_string("id"));
104 if (len_index >= 0) {
105 struct definition_integer *defint;
106 struct definition *field;
107
108 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
109 assert(field->declaration->id == CTF_TYPE_INTEGER);
110 defint = container_of(field, struct definition_integer, p);
111 assert(defint->declaration->signedness == FALSE);
112 id = defint->value._unsigned; /* set id */
113 }
114
115 /* lookup timestamp */
116 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
117 g_quark_from_static_string("timestamp"));
118 if (len_index >= 0) {
119 struct definition_integer *defint;
120 struct definition *field;
121
122 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
123 assert(field->declaration->id == CTF_TYPE_INTEGER);
124 defint = container_of(field, struct definition_integer, p);
125 assert(defint->declaration->signedness == FALSE);
126 /* update timestamp */
127 stream->timestamp = defint->value._unsigned;
128 }
129
130 }
131
132 /* Read stream-declared event context */
133 if (stream_class->event_context) {
134 ret = generic_rw(ppos, &stream_class->event_context->p);
135 if (ret)
136 goto error;
137 }
138
139 if (id >= stream_class->events_by_id->len) {
140 fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
141 return -EINVAL;
142 }
143 event_class = g_ptr_array_index(stream_class->events_by_id, id);
144 if (!event_class) {
145 fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
146 return -EINVAL;
147 }
148
149 /* Read event-declared event context */
150 if (event_class->context) {
151 ret = generic_rw(ppos, &event_class->context->p);
152 if (ret)
153 goto error;
154 }
155
156 /* Read event payload */
157 if (event_class->fields) {
158 ret = generic_rw(ppos, &event_class->fields->p);
159 if (ret)
160 goto error;
161 }
162
163 return 0;
164
165 error:
166 fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
167 return ret;
168 }
169
170 static
171 int ctf_write_event(struct stream_pos *pos, struct ctf_stream *stream)
172 {
173 struct ctf_stream_class *stream_class = stream->stream_class;
174 struct ctf_event *event_class;
175 uint64_t id = 0;
176 int len_index;
177 int ret;
178
179 /* print event header */
180 if (stream_class->event_header) {
181 /* lookup event id */
182 len_index = struct_declaration_lookup_field_index(stream_class->event_header_decl,
183 g_quark_from_static_string("id"));
184 if (len_index >= 0) {
185 struct definition_integer *defint;
186 struct definition *field;
187
188 field = struct_definition_get_field_from_index(stream_class->event_header, len_index);
189 assert(field->declaration->id == CTF_TYPE_INTEGER);
190 defint = container_of(field, struct definition_integer, p);
191 assert(defint->declaration->signedness == FALSE);
192 id = defint->value._unsigned; /* set id */
193 }
194
195 ret = generic_rw(pos, &stream_class->event_header->p);
196 if (ret)
197 goto error;
198 }
199
200 /* print stream-declared event context */
201 if (stream_class->event_context) {
202 ret = generic_rw(pos, &stream_class->event_context->p);
203 if (ret)
204 goto error;
205 }
206
207 if (id >= stream_class->events_by_id->len) {
208 fprintf(stdout, "[error] Event id %" PRIu64 " is outside range.\n", id);
209 return -EINVAL;
210 }
211 event_class = g_ptr_array_index(stream_class->events_by_id, id);
212 if (!event_class) {
213 fprintf(stdout, "[error] Event id %" PRIu64 " is unknown.\n", id);
214 return -EINVAL;
215 }
216
217 /* print event-declared event context */
218 if (event_class->context) {
219 ret = generic_rw(pos, &event_class->context->p);
220 if (ret)
221 goto error;
222 }
223
224 /* Read and print event payload */
225 if (event_class->fields) {
226 ret = generic_rw(pos, &event_class->fields->p);
227 if (ret)
228 goto error;
229 }
230
231 return 0;
232
233 error:
234 fprintf(stdout, "[error] Unexpected end of stream. Either the trace data stream is corrupted or metadata description does not match data layout.\n");
235 return ret;
236 }
237
238 void ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
239 {
240 pos->fd = fd;
241 pos->mmap_offset = 0;
242 pos->packet_size = 0;
243 pos->content_size = 0;
244 pos->content_size_loc = NULL;
245 pos->base = NULL;
246 pos->offset = 0;
247 pos->dummy = false;
248 pos->cur_index = 0;
249 if (fd >= 0)
250 pos->packet_index = g_array_new(FALSE, TRUE,
251 sizeof(struct packet_index));
252 else
253 pos->packet_index = NULL;
254 switch (open_flags & O_ACCMODE) {
255 case O_RDONLY:
256 pos->prot = PROT_READ;
257 pos->flags = MAP_PRIVATE;
258 pos->parent.rw_table = read_dispatch_table;
259 pos->parent.event_cb = ctf_read_event;
260 break;
261 case O_RDWR:
262 pos->prot = PROT_WRITE; /* Write has priority */
263 pos->flags = MAP_SHARED;
264 pos->parent.rw_table = write_dispatch_table;
265 pos->parent.event_cb = ctf_write_event;
266 if (fd >= 0)
267 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
268 break;
269 default:
270 assert(0);
271 }
272 }
273
274 void ctf_fini_pos(struct ctf_stream_pos *pos)
275 {
276 int ret;
277
278 if (pos->prot == PROT_WRITE && pos->content_size_loc)
279 *pos->content_size_loc = pos->offset;
280 if (pos->base) {
281 /* unmap old base */
282 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
283 if (ret) {
284 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
285 strerror(errno));
286 assert(0);
287 }
288 }
289 (void) g_array_free(pos->packet_index, TRUE);
290 }
291
292 void ctf_move_pos_slow(struct ctf_stream_pos *pos, size_t offset, int whence)
293 {
294 int ret;
295 off_t off;
296 struct packet_index *index;
297
298 if (pos->prot == PROT_WRITE && pos->content_size_loc)
299 *pos->content_size_loc = pos->offset;
300
301 if (pos->base) {
302 /* unmap old base */
303 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
304 if (ret) {
305 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
306 strerror(errno));
307 assert(0);
308 }
309 pos->base = NULL;
310 }
311
312 /*
313 * The caller should never ask for ctf_move_pos across packets,
314 * except to get exactly at the beginning of the next packet.
315 */
316 if (pos->prot == PROT_WRITE) {
317 switch (whence) {
318 case SEEK_CUR:
319 /* The writer will add padding */
320 assert(pos->offset + offset == pos->packet_size);
321 pos->mmap_offset += WRITE_PACKET_LEN / CHAR_BIT;
322 break;
323 case SEEK_SET:
324 assert(offset == 0); /* only seek supported for now */
325 pos->cur_index = 0;
326 break;
327 default:
328 assert(0);
329 }
330 pos->content_size = -1U; /* Unknown at this point */
331 pos->packet_size = WRITE_PACKET_LEN;
332 off = posix_fallocate(pos->fd, pos->mmap_offset,
333 pos->packet_size / CHAR_BIT);
334 assert(off >= 0);
335 pos->offset = 0;
336 } else {
337 switch (whence) {
338 case SEEK_CUR:
339 /* The reader will expect us to skip padding */
340 assert(pos->offset + offset == pos->content_size);
341 ++pos->cur_index;
342 break;
343 case SEEK_SET:
344 assert(offset == 0); /* only seek supported for now */
345 pos->cur_index = 0;
346 break;
347 default:
348 assert(0);
349 }
350 if (pos->cur_index >= pos->packet_index->len) {
351 pos->offset = EOF;
352 return;
353 }
354 index = &g_array_index(pos->packet_index, struct packet_index,
355 pos->cur_index);
356 pos->mmap_offset = index->offset;
357
358 /* Lookup context/packet size in index */
359 pos->content_size = index->content_size;
360 pos->packet_size = index->packet_size;
361 pos->offset = index->data_offset;
362 }
363 /* map new base. Need mapping length from header. */
364 pos->base = mmap(NULL, pos->packet_size / CHAR_BIT, pos->prot,
365 pos->flags, pos->fd, pos->mmap_offset);
366 if (pos->base == MAP_FAILED) {
367 fprintf(stdout, "[error] mmap error %s.\n",
368 strerror(errno));
369 assert(0);
370 }
371 }
372
373 /*
374 * TODO: for now, we treat the metadata file as a simple text file
375 * (without any header nor packets nor padding).
376 */
377 static
378 int ctf_open_trace_metadata_read(struct ctf_trace *td)
379 {
380 struct ctf_scanner *scanner;
381 FILE *fp;
382 int ret = 0;
383
384 td->metadata.pos.fd = openat(td->dirfd, "metadata", O_RDONLY);
385 if (td->metadata.pos.fd < 0) {
386 fprintf(stdout, "Unable to open metadata.\n");
387 return td->metadata.pos.fd;
388 }
389
390 if (babeltrace_debug)
391 yydebug = 1;
392
393 fp = fdopen(td->metadata.pos.fd, "r");
394 if (!fp) {
395 fprintf(stdout, "[error] Unable to open metadata stream.\n");
396 ret = -errno;
397 goto end_stream;
398 }
399
400 scanner = ctf_scanner_alloc(fp);
401 if (!scanner) {
402 fprintf(stdout, "[error] Error allocating scanner\n");
403 ret = -ENOMEM;
404 goto end_scanner_alloc;
405 }
406 ret = ctf_scanner_append_ast(scanner);
407 if (ret) {
408 fprintf(stdout, "[error] Error creating AST\n");
409 goto end;
410 }
411
412 if (babeltrace_debug) {
413 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
414 if (ret) {
415 fprintf(stdout, "[error] Error visiting AST for XML output\n");
416 goto end;
417 }
418 }
419
420 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
421 if (ret) {
422 fprintf(stdout, "[error] Error in CTF semantic validation %d\n", ret);
423 goto end;
424 }
425 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
426 td, BYTE_ORDER);
427 if (ret) {
428 fprintf(stdout, "[error] Error in CTF metadata constructor %d\n", ret);
429 goto end;
430 }
431 end:
432 ctf_scanner_free(scanner);
433 end_scanner_alloc:
434 fclose(fp);
435 end_stream:
436 close(td->metadata.pos.fd);
437 return ret;
438 }
439
440
441 static
442 int create_stream_packet_index(struct ctf_trace *td,
443 struct ctf_file_stream *file_stream)
444 {
445 struct ctf_stream_class *stream;
446 int len_index;
447 struct ctf_stream_pos *pos;
448 struct stat filestats;
449 struct packet_index packet_index;
450 int first_packet = 1;
451 int ret;
452
453 pos = &file_stream->pos;
454
455 ret = fstat(pos->fd, &filestats);
456 if (ret < 0)
457 return ret;
458
459 for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
460 uint64_t stream_id = 0;
461
462 if (pos->base) {
463 /* unmap old base */
464 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
465 if (ret) {
466 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
467 strerror(errno));
468 return ret;
469 }
470 pos->base = NULL;
471 }
472 /* map new base. Need mapping length from header. */
473 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN / CHAR_BIT, PROT_READ,
474 MAP_PRIVATE, pos->fd, pos->mmap_offset);
475 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
476 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
477 pos->offset = 0; /* Position of the packet header */
478
479 packet_index.offset = pos->mmap_offset;
480 packet_index.content_size = 0;
481 packet_index.packet_size = 0;
482
483 /* read and check header, set stream id (and check) */
484 if (td->packet_header) {
485 /* Read packet header */
486 ret = generic_rw(&pos->parent, &td->packet_header->p);
487 if (ret)
488 return ret;
489 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("magic"));
490 if (len_index >= 0) {
491 struct definition_integer *defint;
492 struct definition *field;
493
494 field = struct_definition_get_field_from_index(td->packet_header, len_index);
495 assert(field->declaration->id == CTF_TYPE_INTEGER);
496 defint = container_of(field, struct definition_integer, p);
497 assert(defint->declaration->signedness == FALSE);
498 if (defint->value._unsigned != CTF_MAGIC) {
499 fprintf(stdout, "[error] Invalid magic number 0x%" PRIX64 " at packet %u (file offset %zd).\n",
500 defint->value._unsigned,
501 file_stream->pos.packet_index->len,
502 (ssize_t) pos->mmap_offset);
503 return -EINVAL;
504 }
505 }
506
507 /* check uuid */
508 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("trace_uuid"));
509 if (len_index >= 0) {
510 struct definition_array *defarray;
511 struct definition *field;
512 uint64_t i;
513 uint8_t uuidval[UUID_LEN];
514
515 field = struct_definition_get_field_from_index(td->packet_header, len_index);
516 assert(field->declaration->id == CTF_TYPE_ARRAY);
517 defarray = container_of(field, struct definition_array, p);
518 assert(array_len(defarray) == UUID_LEN);
519 assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
520
521 for (i = 0; i < UUID_LEN; i++) {
522 struct definition *elem;
523 struct definition_integer *defint;
524
525 elem = array_index(defarray, i);
526 assert(elem);
527 defint = container_of(elem, struct definition_integer, p);
528 uuidval[i] = defint->value._unsigned;
529 }
530 ret = uuid_compare(td->uuid, uuidval);
531 if (ret) {
532 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
533 return -EINVAL;
534 }
535 }
536
537
538 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("stream_id"));
539 if (len_index >= 0) {
540 struct definition_integer *defint;
541 struct definition *field;
542
543 field = struct_definition_get_field_from_index(td->packet_header, len_index);
544 assert(field->declaration->id == CTF_TYPE_INTEGER);
545 defint = container_of(field, struct definition_integer, p);
546 assert(defint->declaration->signedness == FALSE);
547 stream_id = defint->value._unsigned;
548 }
549 }
550
551 if (!first_packet && file_stream->stream_id != stream_id) {
552 fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
553 return -EINVAL;
554 }
555 if (first_packet) {
556 file_stream->stream_id = stream_id;
557 if (stream_id >= td->streams->len) {
558 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
559 return -EINVAL;
560 }
561 stream = g_ptr_array_index(td->streams, stream_id);
562 if (!stream) {
563 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
564 return -EINVAL;
565 }
566 file_stream->stream.stream_class = stream;
567 }
568 first_packet = 0;
569
570 if (stream->packet_context) {
571 /* Read packet context */
572 ret = generic_rw(&pos->parent, &stream->packet_context->p);
573 if (ret)
574 return ret;
575 /* read content size from header */
576 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
577 if (len_index >= 0) {
578 struct definition_integer *defint;
579 struct definition *field;
580
581 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
582 assert(field->declaration->id == CTF_TYPE_INTEGER);
583 defint = container_of(field, struct definition_integer, p);
584 assert(defint->declaration->signedness == FALSE);
585 packet_index.content_size = defint->value._unsigned;
586 } else {
587 /* Use file size for packet size */
588 packet_index.content_size = filestats.st_size * CHAR_BIT;
589 }
590
591 /* read packet size from header */
592 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
593 if (len_index >= 0) {
594 struct definition_integer *defint;
595 struct definition *field;
596
597 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
598 assert(field->declaration->id == CTF_TYPE_INTEGER);
599 defint = container_of(field, struct definition_integer, p);
600 assert(defint->declaration->signedness == FALSE);
601 packet_index.packet_size = defint->value._unsigned;
602 } else {
603 /* Use content size if non-zero, else file size */
604 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
605 }
606 } else {
607 /* Use file size for packet size */
608 packet_index.content_size = filestats.st_size * CHAR_BIT;
609 /* Use content size if non-zero, else file size */
610 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
611 }
612
613 /* Validate content size and packet size values */
614 if (packet_index.content_size > packet_index.packet_size) {
615 fprintf(stdout, "[error] Content size (%zu bits) is larger than packet size (%zu bits).\n",
616 packet_index.content_size, packet_index.packet_size);
617 return -EINVAL;
618 }
619
620 if (packet_index.packet_size > (filestats.st_size - packet_index.offset) * CHAR_BIT) {
621 fprintf(stdout, "[error] Packet size (%zu bits) is larger than remaining file size (%zu bits).\n",
622 packet_index.content_size, (filestats.st_size - packet_index.offset) * CHAR_BIT);
623 return -EINVAL;
624 }
625
626 /* Save position after header and context */
627 packet_index.data_offset = pos->offset;
628
629 /* add index to packet array */
630 g_array_append_val(file_stream->pos.packet_index, packet_index);
631
632 pos->mmap_offset += packet_index.packet_size / CHAR_BIT;
633 }
634
635 /* Move pos back to beginning of file */
636 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
637
638 return 0;
639 }
640
641 /*
642 * Note: many file streams can inherit from the same stream class
643 * description (metadata).
644 */
645 static
646 int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags)
647 {
648 int ret;
649 struct ctf_file_stream *file_stream;
650
651 ret = openat(td->dirfd, path, flags);
652 if (ret < 0)
653 goto error;
654 file_stream = g_new0(struct ctf_file_stream, 1);
655 ctf_init_pos(&file_stream->pos, ret, flags);
656 ret = create_stream_packet_index(td, file_stream);
657 if (ret)
658 goto error_index;
659 /* Add stream file to stream class */
660 g_ptr_array_add(file_stream->stream.stream_class->files, file_stream);
661 return 0;
662
663 error_index:
664 ctf_fini_pos(&file_stream->pos);
665 close(file_stream->pos.fd);
666 g_free(file_stream);
667 error:
668 return ret;
669 }
670
671 static
672 int ctf_open_trace_read(struct ctf_trace *td, const char *path, int flags)
673 {
674 int ret;
675 struct dirent *dirent;
676 struct dirent *diriter;
677 size_t dirent_len;
678
679 td->flags = flags;
680
681 /* Open trace directory */
682 td->dir = opendir(path);
683 if (!td->dir) {
684 fprintf(stdout, "[error] Unable to open trace directory.\n");
685 ret = -ENOENT;
686 goto error;
687 }
688
689 td->dirfd = open(path, 0);
690 if (td->dirfd < 0) {
691 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
692 ret = -ENOENT;
693 goto error_dirfd;
694 }
695
696 /*
697 * Keep the metadata file separate.
698 */
699
700 ret = ctf_open_trace_metadata_read(td);
701 if (ret) {
702 goto error_metadata;
703 }
704
705 /*
706 * Open each stream: for each file, try to open, check magic
707 * number, and get the stream ID to add to the right location in
708 * the stream array.
709 */
710
711 dirent_len = offsetof(struct dirent, d_name) +
712 fpathconf(td->dirfd, _PC_NAME_MAX) + 1;
713
714 dirent = malloc(dirent_len);
715
716 for (;;) {
717 ret = readdir_r(td->dir, dirent, &diriter);
718 if (ret) {
719 fprintf(stdout, "[error] Readdir error.\n");
720 goto readdir_error;
721 }
722 if (!diriter)
723 break;
724 /* Ignore hidden files, ., .. and metadata. */
725 if (!strncmp(diriter->d_name, ".", 1)
726 || !strcmp(diriter->d_name, "..")
727 || !strcmp(diriter->d_name, "metadata"))
728 continue;
729 ret = ctf_open_file_stream_read(td, diriter->d_name, flags);
730 if (ret) {
731 fprintf(stdout, "[error] Open file stream error.\n");
732 goto readdir_error;
733 }
734 }
735
736 free(dirent);
737 return 0;
738
739 readdir_error:
740 free(dirent);
741 error_metadata:
742 g_ptr_array_free(td->streams, TRUE);
743 close(td->dirfd);
744 error_dirfd:
745 closedir(td->dir);
746 error:
747 return ret;
748 }
749
750 struct trace_descriptor *ctf_open_trace(const char *path, int flags)
751 {
752 struct ctf_trace *td;
753 int ret;
754
755 td = g_new0(struct ctf_trace, 1);
756
757 switch (flags & O_ACCMODE) {
758 case O_RDONLY:
759 if (!path) {
760 fprintf(stdout, "[error] Path missing for input CTF trace.\n");
761 goto error;
762 }
763 ret = ctf_open_trace_read(td, path, flags);
764 if (ret)
765 goto error;
766 break;
767 case O_RDWR:
768 fprintf(stdout, "[error] Opening CTF traces for output is not supported yet.\n");
769 goto error;
770 default:
771 fprintf(stdout, "[error] Incorrect open flags.\n");
772 goto error;
773 }
774
775 return &td->parent;
776 error:
777 g_free(td);
778 return NULL;
779 }
780
781 static
782 void ctf_close_file_stream(struct ctf_file_stream *file_stream)
783 {
784 ctf_fini_pos(&file_stream->pos);
785 close(file_stream->pos.fd);
786 }
787
788 void ctf_close_trace(struct trace_descriptor *tdp)
789 {
790 struct ctf_trace *td = container_of(tdp, struct ctf_trace, parent);
791 int i;
792
793 if (td->streams) {
794 for (i = 0; i < td->streams->len; i++) {
795 struct ctf_stream_class *stream;
796 int j;
797 stream = g_ptr_array_index(td->streams, i);
798 for (j = 0; j < stream->files->len; j++) {
799 struct ctf_file_stream *file_stream;
800 file_stream = g_ptr_array_index(stream->files, j);
801 ctf_close_file_stream(file_stream);
802 }
803
804 }
805 g_ptr_array_free(td->streams, TRUE);
806 }
807 closedir(td->dir);
808 g_free(td);
809 }
810
811 void __attribute__((constructor)) ctf_init(void)
812 {
813 int ret;
814
815 ctf_format.name = g_quark_from_static_string("ctf");
816 ret = bt_register_format(&ctf_format);
817 assert(!ret);
818 }
819
820 /* TODO: finalize */
This page took 0.04596 seconds and 5 git commands to generate.