trace_uuid -> uuid and add packet metadata support
[babeltrace.git] / formats / ctf / ctf.c
CommitLineData
fc93b2bd
MD
1/*
2 * BabelTrace - Common Trace Format (CTF)
3 *
4 * Format registration.
5 *
c054553d 6 * Copyright 2010, 2011 - Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
fc93b2bd 7 *
ccd7e1c8
MD
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:
fc93b2bd 14 *
ccd7e1c8
MD
15 * The above copyright notice and this permission notice shall be included in
16 * all copies or substantial portions of the Software.
fc93b2bd
MD
17 */
18
19#include <babeltrace/format.h>
20#include <babeltrace/ctf/types.h>
bbefb8dd 21#include <babeltrace/ctf/metadata.h>
65102a8c 22#include <babeltrace/babeltrace.h>
0f980a35 23#include <inttypes.h>
b4c19c1e 24#include <stdio.h>
0f980a35
MD
25#include <uuid/uuid.h>
26#include <sys/mman.h>
bbefb8dd 27#include <errno.h>
b4c19c1e 28#include <endian.h>
bbefb8dd 29#include <sys/types.h>
65102a8c 30#include <sys/stat.h>
bbefb8dd 31#include <fcntl.h>
65102a8c 32#include <dirent.h>
bbefb8dd 33#include <glib.h>
65102a8c
MD
34#include <unistd.h>
35#include <stdlib.h>
36
65102a8c
MD
37#include "metadata/ctf-scanner.h"
38#include "metadata/ctf-parser.h"
39#include "metadata/ctf-ast.h"
40
0f980a35
MD
41/*
42 * We currently simply map a page to read the packet header and packet
8c572eba 43 * context to get the packet length and content length. (in bits)
0f980a35 44 */
8c572eba
MD
45#define MAX_PACKET_HEADER_LEN (getpagesize() * CHAR_BIT)
46#define WRITE_PACKET_LEN (getpagesize() * 8 * CHAR_BIT)
0f980a35
MD
47#define UUID_LEN 16 /* uuid by value len */
48
65102a8c 49extern int yydebug;
bbefb8dd 50
bbefb8dd
MD
51struct trace_descriptor *ctf_open_trace(const char *path, int flags);
52void ctf_close_trace(struct trace_descriptor *descriptor);
fc93b2bd 53
1ae19169
MD
54static
55rw_dispatch read_dispatch_table[] = {
d11e9c49
MD
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
1ae19169
MD
66static
67rw_dispatch write_dispatch_table[] = {
d11e9c49
MD
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
1ae19169 78static
d11e9c49 79struct format ctf_format = {
bbefb8dd
MD
80 .open_trace = ctf_open_trace,
81 .close_trace = ctf_close_trace,
fc93b2bd
MD
82};
83
31262354 84static
764af3f4 85int ctf_read_event(struct stream_pos *ppos, struct ctf_stream *stream)
31262354
MD
86{
87 struct ctf_stream_pos *pos =
88 container_of(ppos, struct ctf_stream_pos, parent);
764af3f4 89 struct ctf_stream_class *stream_class = stream->stream_class;
31262354
MD
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 }
764af3f4
MD
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
31262354
MD
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
167error:
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
172static
764af3f4 173int ctf_write_event(struct stream_pos *pos, struct ctf_stream *stream)
31262354 174{
764af3f4 175 struct ctf_stream_class *stream_class = stream->stream_class;
31262354
MD
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
235error:
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
8563e754 240void ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
8c572eba
MD
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;
8c572eba 250 pos->cur_index = 0;
8563e754
MD
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;
8563e754
MD
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;
31262354 261 pos->parent.event_cb = ctf_read_event;
8563e754 262 break;
8563e754
MD
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;
31262354 267 pos->parent.event_cb = ctf_write_event;
8563e754 268 if (fd >= 0)
847bf71a 269 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
8563e754
MD
270 break;
271 default:
272 assert(0);
8c572eba
MD
273 }
274}
275
46322b33 276void ctf_fini_pos(struct ctf_stream_pos *pos)
8c572eba
MD
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) {
46322b33 286 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
8c572eba
MD
287 strerror(errno));
288 assert(0);
289 }
290 }
291 (void) g_array_free(pos->packet_index, TRUE);
292}
293
847bf71a 294void ctf_move_pos_slow(struct ctf_stream_pos *pos, size_t offset, int whence)
0f980a35
MD
295{
296 int ret;
8c572eba
MD
297 off_t off;
298 struct packet_index *index;
0f980a35 299
8c572eba
MD
300 if (pos->prot == PROT_WRITE && pos->content_size_loc)
301 *pos->content_size_loc = pos->offset;
0f980a35
MD
302
303 if (pos->base) {
304 /* unmap old base */
8c572eba 305 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
0f980a35 306 if (ret) {
46322b33 307 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
0f980a35
MD
308 strerror(errno));
309 assert(0);
310 }
847bf71a 311 pos->base = NULL;
0f980a35
MD
312 }
313
8c572eba 314 /*
46322b33 315 * The caller should never ask for ctf_move_pos across packets,
8c572eba
MD
316 * except to get exactly at the beginning of the next packet.
317 */
318 if (pos->prot == PROT_WRITE) {
989c73bc
MD
319 switch (whence) {
320 case SEEK_CUR:
321 /* The writer will add padding */
322 assert(pos->offset + offset == pos->packet_size);
8c572eba 323 pos->mmap_offset += WRITE_PACKET_LEN / CHAR_BIT;
989c73bc
MD
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 }
8c572eba
MD
332 pos->content_size = -1U; /* Unknown at this point */
333 pos->packet_size = WRITE_PACKET_LEN;
989c73bc
MD
334 off = posix_fallocate(pos->fd, pos->mmap_offset,
335 pos->packet_size / CHAR_BIT);
8c572eba 336 assert(off >= 0);
847bf71a 337 pos->offset = 0;
8c572eba 338 } else {
847bf71a
MD
339 switch (whence) {
340 case SEEK_CUR:
341 /* The reader will expect us to skip padding */
342 assert(pos->offset + offset == pos->content_size);
8c572eba 343 ++pos->cur_index;
847bf71a
MD
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) {
670977d3 353 pos->offset = EOF;
847bf71a
MD
354 return;
355 }
8c572eba
MD
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;
847bf71a 363 pos->offset = index->data_offset;
8c572eba 364 }
0f980a35 365 /* map new base. Need mapping length from header. */
8c572eba
MD
366 pos->base = mmap(NULL, pos->packet_size / CHAR_BIT, pos->prot,
367 pos->flags, pos->fd, pos->mmap_offset);
847bf71a
MD
368 if (pos->base == MAP_FAILED) {
369 fprintf(stdout, "[error] mmap error %s.\n",
370 strerror(errno));
371 assert(0);
372 }
0f980a35
MD
373}
374
b4c19c1e
MD
375static
376int 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 }
394end:
395 rewind(fp);
396 return ret;
397}
398
399static
400int 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
462static
463int 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
65102a8c 491static
46322b33 492int ctf_open_trace_metadata_read(struct ctf_trace *td)
65102a8c
MD
493{
494 struct ctf_scanner *scanner;
495 FILE *fp;
b4c19c1e 496 char *buf = NULL;
65102a8c
MD
497 int ret = 0;
498
46322b33
MD
499 td->metadata.pos.fd = openat(td->dirfd, "metadata", O_RDONLY);
500 if (td->metadata.pos.fd < 0) {
65102a8c 501 fprintf(stdout, "Unable to open metadata.\n");
46322b33 502 return td->metadata.pos.fd;
65102a8c
MD
503 }
504
505 if (babeltrace_debug)
506 yydebug = 1;
507
46322b33 508 fp = fdopen(td->metadata.pos.fd, "r");
65102a8c 509 if (!fp) {
46322b33 510 fprintf(stdout, "[error] Unable to open metadata stream.\n");
65102a8c
MD
511 ret = -errno;
512 goto end_stream;
513 }
514
b4c19c1e
MD
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
65102a8c
MD
521 scanner = ctf_scanner_alloc(fp);
522 if (!scanner) {
46322b33 523 fprintf(stdout, "[error] Error allocating scanner\n");
65102a8c
MD
524 ret = -ENOMEM;
525 goto end_scanner_alloc;
526 }
527 ret = ctf_scanner_append_ast(scanner);
528 if (ret) {
46322b33 529 fprintf(stdout, "[error] Error creating AST\n");
65102a8c
MD
530 goto end;
531 }
532
533 if (babeltrace_debug) {
534 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
535 if (ret) {
46322b33 536 fprintf(stdout, "[error] Error visiting AST for XML output\n");
65102a8c
MD
537 goto end;
538 }
539 }
540
541 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
542 if (ret) {
46322b33 543 fprintf(stdout, "[error] Error in CTF semantic validation %d\n", ret);
65102a8c
MD
544 goto end;
545 }
546 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
46322b33 547 td, BYTE_ORDER);
65102a8c 548 if (ret) {
46322b33 549 fprintf(stdout, "[error] Error in CTF metadata constructor %d\n", ret);
65102a8c
MD
550 goto end;
551 }
552end:
553 ctf_scanner_free(scanner);
554end_scanner_alloc:
b4c19c1e 555end_packet_read:
65102a8c 556 fclose(fp);
b4c19c1e 557 free(buf);
65102a8c 558end_stream:
46322b33 559 close(td->metadata.pos.fd);
0f980a35
MD
560 return ret;
561}
562
563
564static
46322b33 565int create_stream_packet_index(struct ctf_trace *td,
0f980a35
MD
566 struct ctf_file_stream *file_stream)
567{
aa6bffae 568 struct ctf_stream_class *stream;
0f980a35 569 int len_index;
46322b33 570 struct ctf_stream_pos *pos;
0f980a35
MD
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 */
8c572eba 587 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
0f980a35 588 if (ret) {
46322b33 589 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
0f980a35
MD
590 strerror(errno));
591 return ret;
592 }
8c572eba 593 pos->base = NULL;
0f980a35
MD
594 }
595 /* map new base. Need mapping length from header. */
8c572eba 596 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN / CHAR_BIT, PROT_READ,
0f980a35 597 MAP_PRIVATE, pos->fd, pos->mmap_offset);
dc48ecad
MD
598 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
599 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
0f980a35
MD
600 pos->offset = 0; /* Position of the packet header */
601
8c572eba
MD
602 packet_index.offset = pos->mmap_offset;
603 packet_index.content_size = 0;
604 packet_index.packet_size = 0;
605
0f980a35 606 /* read and check header, set stream id (and check) */
46322b33 607 if (td->packet_header) {
0f980a35 608 /* Read packet header */
c5e74408
MD
609 ret = generic_rw(&pos->parent, &td->packet_header->p);
610 if (ret)
611 return ret;
46322b33 612 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("magic"));
0f980a35
MD
613 if (len_index >= 0) {
614 struct definition_integer *defint;
b1a2f580 615 struct definition *field;
0f980a35 616
46322b33 617 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
618 assert(field->declaration->id == CTF_TYPE_INTEGER);
619 defint = container_of(field, struct definition_integer, p);
0f980a35
MD
620 assert(defint->declaration->signedness == FALSE);
621 if (defint->value._unsigned != CTF_MAGIC) {
d8ea2d29 622 fprintf(stdout, "[error] Invalid magic number 0x%" PRIX64 " at packet %u (file offset %zd).\n",
8c572eba
MD
623 defint->value._unsigned,
624 file_stream->pos.packet_index->len,
625 (ssize_t) pos->mmap_offset);
0f980a35
MD
626 return -EINVAL;
627 }
628 }
629
630 /* check uuid */
b4c19c1e 631 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("uuid"));
0f980a35
MD
632 if (len_index >= 0) {
633 struct definition_array *defarray;
b1a2f580 634 struct definition *field;
0f980a35
MD
635 uint64_t i;
636 uint8_t uuidval[UUID_LEN];
637
46322b33 638 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
639 assert(field->declaration->id == CTF_TYPE_ARRAY);
640 defarray = container_of(field, struct definition_array, p);
3838df27 641 assert(array_len(defarray) == UUID_LEN);
0f980a35
MD
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 }
46322b33 653 ret = uuid_compare(td->uuid, uuidval);
0f980a35
MD
654 if (ret) {
655 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
656 return -EINVAL;
657 }
658 }
659
660
46322b33 661 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("stream_id"));
0f980a35
MD
662 if (len_index >= 0) {
663 struct definition_integer *defint;
b1a2f580 664 struct definition *field;
0f980a35 665
46322b33 666 field = struct_definition_get_field_from_index(td->packet_header, len_index);
b1a2f580
MD
667 assert(field->declaration->id == CTF_TYPE_INTEGER);
668 defint = container_of(field, struct definition_integer, p);
0f980a35
MD
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;
46322b33 680 if (stream_id >= td->streams->len) {
0f980a35
MD
681 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
682 return -EINVAL;
683 }
46322b33 684 stream = g_ptr_array_index(td->streams, stream_id);
0f980a35
MD
685 if (!stream) {
686 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
687 return -EINVAL;
688 }
764af3f4 689 file_stream->stream.stream_class = stream;
0f980a35
MD
690 }
691 first_packet = 0;
692
dc48ecad
MD
693 if (stream->packet_context) {
694 /* Read packet context */
c5e74408
MD
695 ret = generic_rw(&pos->parent, &stream->packet_context->p);
696 if (ret)
697 return ret;
dc48ecad
MD
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;
b1a2f580 702 struct definition *field;
dc48ecad
MD
703
704 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
b1a2f580
MD
705 assert(field->declaration->id == CTF_TYPE_INTEGER);
706 defint = container_of(field, struct definition_integer, p);
dc48ecad 707 assert(defint->declaration->signedness == FALSE);
8c572eba 708 packet_index.content_size = defint->value._unsigned;
dc48ecad
MD
709 } else {
710 /* Use file size for packet size */
8c572eba 711 packet_index.content_size = filestats.st_size * CHAR_BIT;
dc48ecad
MD
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;
b1a2f580 718 struct definition *field;
dc48ecad
MD
719
720 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
b1a2f580
MD
721 assert(field->declaration->id == CTF_TYPE_INTEGER);
722 defint = container_of(field, struct definition_integer, p);
dc48ecad 723 assert(defint->declaration->signedness == FALSE);
8c572eba 724 packet_index.packet_size = defint->value._unsigned;
dc48ecad
MD
725 } else {
726 /* Use content size if non-zero, else file size */
8c572eba 727 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
dc48ecad 728 }
0f980a35
MD
729 } else {
730 /* Use file size for packet size */
8c572eba 731 packet_index.content_size = filestats.st_size * CHAR_BIT;
0f980a35 732 /* Use content size if non-zero, else file size */
8c572eba 733 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
0f980a35 734 }
546293fa
MD
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
58b0b883
MD
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);
546293fa
MD
746 return -EINVAL;
747 }
748
847bf71a
MD
749 /* Save position after header and context */
750 packet_index.data_offset = pos->offset;
0f980a35 751
0f980a35
MD
752 /* add index to packet array */
753 g_array_append_val(file_stream->pos.packet_index, packet_index);
754
8c572eba 755 pos->mmap_offset += packet_index.packet_size / CHAR_BIT;
0f980a35
MD
756 }
757
847bf71a
MD
758 /* Move pos back to beginning of file */
759 ctf_move_pos_slow(pos, 0, SEEK_SET); /* position for write */
760
0f980a35
MD
761 return 0;
762}
763
764/*
765 * Note: many file streams can inherit from the same stream class
766 * description (metadata).
767 */
768static
46322b33 769int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags)
0f980a35
MD
770{
771 int ret;
772 struct ctf_file_stream *file_stream;
773
46322b33 774 ret = openat(td->dirfd, path, flags);
0f980a35
MD
775 if (ret < 0)
776 goto error;
777 file_stream = g_new0(struct ctf_file_stream, 1);
8563e754 778 ctf_init_pos(&file_stream->pos, ret, flags);
0f980a35
MD
779 ret = create_stream_packet_index(td, file_stream);
780 if (ret)
781 goto error_index;
782 /* Add stream file to stream class */
764af3f4 783 g_ptr_array_add(file_stream->stream.stream_class->files, file_stream);
0f980a35
MD
784 return 0;
785
786error_index:
46322b33 787 ctf_fini_pos(&file_stream->pos);
0f980a35
MD
788 close(file_stream->pos.fd);
789 g_free(file_stream);
790error:
65102a8c
MD
791 return ret;
792}
793
bbefb8dd 794static
46322b33 795int ctf_open_trace_read(struct ctf_trace *td, const char *path, int flags)
bbefb8dd
MD
796{
797 int ret;
65102a8c
MD
798 struct dirent *dirent;
799 struct dirent *diriter;
800 size_t dirent_len;
bbefb8dd 801
46322b33 802 td->flags = flags;
bbefb8dd
MD
803
804 /* Open trace directory */
46322b33
MD
805 td->dir = opendir(path);
806 if (!td->dir) {
dc48ecad 807 fprintf(stdout, "[error] Unable to open trace directory.\n");
bbefb8dd
MD
808 ret = -ENOENT;
809 goto error;
810 }
811
46322b33
MD
812 td->dirfd = open(path, 0);
813 if (td->dirfd < 0) {
dc48ecad 814 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
65102a8c
MD
815 ret = -ENOENT;
816 goto error_dirfd;
817 }
0f980a35 818
65102a8c
MD
819 /*
820 * Keep the metadata file separate.
821 */
bbefb8dd 822
65102a8c
MD
823 ret = ctf_open_trace_metadata_read(td);
824 if (ret) {
825 goto error_metadata;
826 }
bbefb8dd
MD
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.
bbefb8dd
MD
832 */
833
65102a8c 834 dirent_len = offsetof(struct dirent, d_name) +
46322b33 835 fpathconf(td->dirfd, _PC_NAME_MAX) + 1;
bbefb8dd 836
65102a8c 837 dirent = malloc(dirent_len);
bbefb8dd 838
65102a8c 839 for (;;) {
46322b33 840 ret = readdir_r(td->dir, dirent, &diriter);
65102a8c 841 if (ret) {
dc48ecad 842 fprintf(stdout, "[error] Readdir error.\n");
65102a8c 843 goto readdir_error;
65102a8c
MD
844 }
845 if (!diriter)
846 break;
d8ea2d29
MD
847 /* Ignore hidden files, ., .. and metadata. */
848 if (!strncmp(diriter->d_name, ".", 1)
65102a8c
MD
849 || !strcmp(diriter->d_name, "..")
850 || !strcmp(diriter->d_name, "metadata"))
851 continue;
dc48ecad
MD
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 }
65102a8c 857 }
bbefb8dd 858
65102a8c 859 free(dirent);
bbefb8dd 860 return 0;
65102a8c
MD
861
862readdir_error:
863 free(dirent);
864error_metadata:
46322b33
MD
865 g_ptr_array_free(td->streams, TRUE);
866 close(td->dirfd);
65102a8c 867error_dirfd:
46322b33 868 closedir(td->dir);
bbefb8dd
MD
869error:
870 return ret;
871}
872
bbefb8dd
MD
873struct trace_descriptor *ctf_open_trace(const char *path, int flags)
874{
46322b33 875 struct ctf_trace *td;
bbefb8dd
MD
876 int ret;
877
46322b33 878 td = g_new0(struct ctf_trace, 1);
bbefb8dd 879
8c572eba 880 switch (flags & O_ACCMODE) {
bbefb8dd 881 case O_RDONLY:
b61922b5
MD
882 if (!path) {
883 fprintf(stdout, "[error] Path missing for input CTF trace.\n");
884 goto error;
885 }
bbefb8dd
MD
886 ret = ctf_open_trace_read(td, path, flags);
887 if (ret)
888 goto error;
889 break;
989c73bc 890 case O_RDWR:
46322b33
MD
891 fprintf(stdout, "[error] Opening CTF traces for output is not supported yet.\n");
892 goto error;
bbefb8dd 893 default:
46322b33 894 fprintf(stdout, "[error] Incorrect open flags.\n");
bbefb8dd
MD
895 goto error;
896 }
897
46322b33 898 return &td->parent;
bbefb8dd
MD
899error:
900 g_free(td);
901 return NULL;
902}
903
0f980a35
MD
904static
905void ctf_close_file_stream(struct ctf_file_stream *file_stream)
906{
46322b33 907 ctf_fini_pos(&file_stream->pos);
0f980a35
MD
908 close(file_stream->pos.fd);
909}
910
46322b33 911void ctf_close_trace(struct trace_descriptor *tdp)
bbefb8dd 912{
46322b33 913 struct ctf_trace *td = container_of(tdp, struct ctf_trace, parent);
0f980a35
MD
914 int i;
915
46322b33
MD
916 if (td->streams) {
917 for (i = 0; i < td->streams->len; i++) {
aa6bffae 918 struct ctf_stream_class *stream;
0f980a35 919 int j;
46322b33 920 stream = g_ptr_array_index(td->streams, i);
0f980a35
MD
921 for (j = 0; j < stream->files->len; j++) {
922 struct ctf_file_stream *file_stream;
2c117823 923 file_stream = g_ptr_array_index(stream->files, j);
0f980a35
MD
924 ctf_close_file_stream(file_stream);
925 }
926
927 }
46322b33 928 g_ptr_array_free(td->streams, TRUE);
0f980a35 929 }
46322b33 930 closedir(td->dir);
bbefb8dd
MD
931 g_free(td);
932}
933
7fb21036 934void __attribute__((constructor)) ctf_init(void)
fc93b2bd
MD
935{
936 int ret;
937
4c8bfb7e 938 ctf_format.name = g_quark_from_static_string("ctf");
fc93b2bd
MD
939 ret = bt_register_format(&ctf_format);
940 assert(!ret);
941}
698f0fe4
MD
942
943/* TODO: finalize */
This page took 0.067407 seconds and 4 git commands to generate.