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