init pos cleanup
[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 rw_dispatch read_dispatch_table[] = {
53 [ CTF_TYPE_INTEGER ] = ctf_integer_read,
54 [ CTF_TYPE_FLOAT ] = ctf_float_read,
55 [ CTF_TYPE_ENUM ] = ctf_enum_read,
56 [ CTF_TYPE_STRING ] = ctf_string_read,
57 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
58 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
59 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
60 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
61 };
62
63 static rw_dispatch write_dispatch_table[] = {
64 [ CTF_TYPE_INTEGER ] = ctf_integer_write,
65 [ CTF_TYPE_FLOAT ] = ctf_float_write,
66 [ CTF_TYPE_ENUM ] = ctf_enum_write,
67 [ CTF_TYPE_STRING ] = ctf_string_write,
68 [ CTF_TYPE_STRUCT ] = ctf_struct_rw,
69 [ CTF_TYPE_VARIANT ] = ctf_variant_rw,
70 [ CTF_TYPE_ARRAY ] = ctf_array_rw,
71 [ CTF_TYPE_SEQUENCE ] = ctf_sequence_rw,
72 };
73
74 struct format ctf_format = {
75 .open_trace = ctf_open_trace,
76 .close_trace = ctf_close_trace,
77 };
78
79 void ctf_init_pos(struct ctf_stream_pos *pos, int fd, int open_flags)
80 {
81 pos->fd = fd;
82 pos->mmap_offset = 0;
83 pos->packet_size = 0;
84 pos->content_size = 0;
85 pos->content_size_loc = NULL;
86 pos->base = NULL;
87 pos->offset = 0;
88 pos->dummy = false;
89 pos->cur_index = 0;
90 if (fd >= 0)
91 pos->packet_index = g_array_new(FALSE, TRUE,
92 sizeof(struct packet_index));
93 else
94 pos->packet_index = NULL;
95
96 switch (open_flags & O_ACCMODE) {
97 case O_RDONLY:
98 pos->prot = PROT_READ;
99 pos->flags = MAP_PRIVATE;
100 pos->parent.rw_table = read_dispatch_table;
101 break;
102 case O_WRONLY:
103 case O_RDWR:
104 pos->prot = PROT_WRITE; /* Write has priority */
105 pos->flags = MAP_SHARED;
106 pos->parent.rw_table = write_dispatch_table;
107 if (fd >= 0)
108 ctf_move_pos_slow(pos, 0); /* position for write */
109 break;
110 default:
111 assert(0);
112 }
113 }
114
115 void ctf_fini_pos(struct ctf_stream_pos *pos)
116 {
117 int ret;
118
119 if (pos->prot == PROT_WRITE && pos->content_size_loc)
120 *pos->content_size_loc = pos->offset;
121 if (pos->base) {
122 /* unmap old base */
123 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
124 if (ret) {
125 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
126 strerror(errno));
127 assert(0);
128 }
129 }
130 (void) g_array_free(pos->packet_index, TRUE);
131 }
132
133 void ctf_move_pos_slow(struct ctf_stream_pos *pos, size_t offset)
134 {
135 int ret;
136 off_t off;
137 struct packet_index *index;
138
139
140 if (pos->prot == PROT_WRITE && pos->content_size_loc)
141 *pos->content_size_loc = pos->offset;
142
143 if (pos->base) {
144 /* unmap old base */
145 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
146 if (ret) {
147 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
148 strerror(errno));
149 assert(0);
150 }
151 }
152
153 /*
154 * The caller should never ask for ctf_move_pos across packets,
155 * except to get exactly at the beginning of the next packet.
156 */
157 if (pos->prot == PROT_WRITE) {
158 /* The writer will add padding */
159 assert(pos->offset + offset == pos->packet_size);
160
161 /*
162 * Don't increment for initial stream move (only condition where
163 * pos->offset can be 0.
164 */
165 if (pos->offset)
166 pos->mmap_offset += WRITE_PACKET_LEN / CHAR_BIT;
167 pos->content_size = -1U; /* Unknown at this point */
168 pos->packet_size = WRITE_PACKET_LEN;
169 off = posix_fallocate(pos->fd, pos->mmap_offset, pos->packet_size / CHAR_BIT);
170 assert(off >= 0);
171 } else {
172 /* The reader will expect us to skip padding */
173 assert(pos->offset + offset == pos->content_size);
174
175 /*
176 * Don't increment for initial stream move (only condition where
177 * pos->offset can be 0).
178 */
179 if (pos->offset)
180 ++pos->cur_index;
181 index = &g_array_index(pos->packet_index, struct packet_index,
182 pos->cur_index);
183 pos->mmap_offset = index->offset;
184
185 /* Lookup context/packet size in index */
186 pos->content_size = index->content_size;
187 pos->packet_size = index->packet_size;
188 }
189 /* map new base. Need mapping length from header. */
190 pos->base = mmap(NULL, pos->packet_size / CHAR_BIT, pos->prot,
191 pos->flags, pos->fd, pos->mmap_offset);
192 pos->offset = 0;
193 }
194
195 /*
196 * TODO: for now, we treat the metadata file as a simple text file
197 * (without any header nor packets nor padding).
198 */
199 static
200 int ctf_open_trace_metadata_read(struct ctf_trace *td)
201 {
202 struct ctf_scanner *scanner;
203 FILE *fp;
204 int ret = 0;
205
206 td->metadata.pos.fd = openat(td->dirfd, "metadata", O_RDONLY);
207 if (td->metadata.pos.fd < 0) {
208 fprintf(stdout, "Unable to open metadata.\n");
209 return td->metadata.pos.fd;
210 }
211
212 if (babeltrace_debug)
213 yydebug = 1;
214
215 fp = fdopen(td->metadata.pos.fd, "r");
216 if (!fp) {
217 fprintf(stdout, "[error] Unable to open metadata stream.\n");
218 ret = -errno;
219 goto end_stream;
220 }
221
222 scanner = ctf_scanner_alloc(fp);
223 if (!scanner) {
224 fprintf(stdout, "[error] Error allocating scanner\n");
225 ret = -ENOMEM;
226 goto end_scanner_alloc;
227 }
228 ret = ctf_scanner_append_ast(scanner);
229 if (ret) {
230 fprintf(stdout, "[error] Error creating AST\n");
231 goto end;
232 }
233
234 if (babeltrace_debug) {
235 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
236 if (ret) {
237 fprintf(stdout, "[error] Error visiting AST for XML output\n");
238 goto end;
239 }
240 }
241
242 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
243 if (ret) {
244 fprintf(stdout, "[error] Error in CTF semantic validation %d\n", ret);
245 goto end;
246 }
247 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
248 td, BYTE_ORDER);
249 if (ret) {
250 fprintf(stdout, "[error] Error in CTF metadata constructor %d\n", ret);
251 goto end;
252 }
253 end:
254 ctf_scanner_free(scanner);
255 end_scanner_alloc:
256 fclose(fp);
257 end_stream:
258 close(td->metadata.pos.fd);
259 return ret;
260 }
261
262
263 static
264 int create_stream_packet_index(struct ctf_trace *td,
265 struct ctf_file_stream *file_stream)
266 {
267 struct ctf_stream *stream;
268 int len_index;
269 struct ctf_stream_pos *pos;
270 struct stat filestats;
271 struct packet_index packet_index;
272 int first_packet = 1;
273 int ret;
274
275 pos = &file_stream->pos;
276
277 ret = fstat(pos->fd, &filestats);
278 if (ret < 0)
279 return ret;
280
281 for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
282 uint64_t stream_id = 0;
283
284 if (pos->base) {
285 /* unmap old base */
286 ret = munmap(pos->base, pos->packet_size / CHAR_BIT);
287 if (ret) {
288 fprintf(stdout, "[error] Unable to unmap old base: %s.\n",
289 strerror(errno));
290 return ret;
291 }
292 pos->base = NULL;
293 }
294 /* map new base. Need mapping length from header. */
295 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN / CHAR_BIT, PROT_READ,
296 MAP_PRIVATE, pos->fd, pos->mmap_offset);
297 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
298 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
299 pos->offset = 0; /* Position of the packet header */
300
301 packet_index.offset = pos->mmap_offset;
302 packet_index.content_size = 0;
303 packet_index.packet_size = 0;
304
305 /* read and check header, set stream id (and check) */
306 if (td->packet_header) {
307 /* Read packet header */
308 generic_rw(&pos->parent, &td->packet_header->p);
309
310 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("magic"));
311 if (len_index >= 0) {
312 struct definition_integer *defint;
313 struct field *field;
314
315 field = struct_definition_get_field_from_index(td->packet_header, len_index);
316 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
317 defint = container_of(field->definition, struct definition_integer, p);
318 assert(defint->declaration->signedness == FALSE);
319 if (defint->value._unsigned != CTF_MAGIC) {
320 fprintf(stdout, "[error] Invalid magic number %" PRIX64 " at packet %u (file offset %zd).\n",
321 defint->value._unsigned,
322 file_stream->pos.packet_index->len,
323 (ssize_t) pos->mmap_offset);
324 return -EINVAL;
325 }
326 }
327
328 /* check uuid */
329 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("trace_uuid"));
330 if (len_index >= 0) {
331 struct definition_array *defarray;
332 struct field *field;
333 uint64_t i;
334 uint8_t uuidval[UUID_LEN];
335
336 field = struct_definition_get_field_from_index(td->packet_header, len_index);
337 assert(field->definition->declaration->id == CTF_TYPE_ARRAY);
338 defarray = container_of(field->definition, struct definition_array, p);
339 assert(array_len(defarray) == UUID_LEN);
340 assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
341
342 for (i = 0; i < UUID_LEN; i++) {
343 struct definition *elem;
344 struct definition_integer *defint;
345
346 elem = array_index(defarray, i);
347 assert(elem);
348 defint = container_of(elem, struct definition_integer, p);
349 uuidval[i] = defint->value._unsigned;
350 }
351 ret = uuid_compare(td->uuid, uuidval);
352 if (ret) {
353 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
354 return -EINVAL;
355 }
356 }
357
358
359 len_index = struct_declaration_lookup_field_index(td->packet_header->declaration, g_quark_from_static_string("stream_id"));
360 if (len_index >= 0) {
361 struct definition_integer *defint;
362 struct field *field;
363
364 field = struct_definition_get_field_from_index(td->packet_header, len_index);
365 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
366 defint = container_of(field->definition, struct definition_integer, p);
367 assert(defint->declaration->signedness == FALSE);
368 stream_id = defint->value._unsigned;
369 }
370 }
371
372 if (!first_packet && file_stream->stream_id != stream_id) {
373 fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
374 return -EINVAL;
375 }
376 if (first_packet) {
377 file_stream->stream_id = stream_id;
378 if (stream_id >= td->streams->len) {
379 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
380 return -EINVAL;
381 }
382 stream = g_ptr_array_index(td->streams, stream_id);
383 if (!stream) {
384 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
385 return -EINVAL;
386 }
387 file_stream->stream = stream;
388 }
389 first_packet = 0;
390
391 if (stream->packet_context) {
392 /* Read packet context */
393 generic_rw(&pos->parent, &stream->packet_context->p);
394
395 /* read content size from header */
396 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
397 if (len_index >= 0) {
398 struct definition_integer *defint;
399 struct field *field;
400
401 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
402 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
403 defint = container_of(field->definition, struct definition_integer, p);
404 assert(defint->declaration->signedness == FALSE);
405 packet_index.content_size = defint->value._unsigned;
406 } else {
407 /* Use file size for packet size */
408 packet_index.content_size = filestats.st_size * CHAR_BIT;
409 }
410
411 /* read packet size from header */
412 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
413 if (len_index >= 0) {
414 struct definition_integer *defint;
415 struct field *field;
416
417 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
418 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
419 defint = container_of(field->definition, struct definition_integer, p);
420 assert(defint->declaration->signedness == FALSE);
421 packet_index.packet_size = defint->value._unsigned;
422 } else {
423 /* Use content size if non-zero, else file size */
424 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
425 }
426 } else {
427 /* Use file size for packet size */
428 packet_index.content_size = filestats.st_size * CHAR_BIT;
429 /* Use content size if non-zero, else file size */
430 packet_index.packet_size = packet_index.content_size ? : filestats.st_size * CHAR_BIT;
431 }
432
433 /* add index to packet array */
434 g_array_append_val(file_stream->pos.packet_index, packet_index);
435
436 pos->mmap_offset += packet_index.packet_size / CHAR_BIT;
437 }
438
439 return 0;
440 }
441
442 /*
443 * Note: many file streams can inherit from the same stream class
444 * description (metadata).
445 */
446 static
447 int ctf_open_file_stream_read(struct ctf_trace *td, const char *path, int flags)
448 {
449 int ret;
450 struct ctf_file_stream *file_stream;
451
452 ret = openat(td->dirfd, path, flags);
453 if (ret < 0)
454 goto error;
455 file_stream = g_new0(struct ctf_file_stream, 1);
456 ctf_init_pos(&file_stream->pos, ret, flags);
457 ret = create_stream_packet_index(td, file_stream);
458 if (ret)
459 goto error_index;
460 /* Add stream file to stream class */
461 g_ptr_array_add(file_stream->stream->files, file_stream);
462 return 0;
463
464 error_index:
465 ctf_fini_pos(&file_stream->pos);
466 close(file_stream->pos.fd);
467 g_free(file_stream);
468 error:
469 return ret;
470 }
471
472 static
473 int ctf_open_trace_read(struct ctf_trace *td, const char *path, int flags)
474 {
475 int ret;
476 struct dirent *dirent;
477 struct dirent *diriter;
478 size_t dirent_len;
479
480 td->flags = flags;
481
482 /* Open trace directory */
483 td->dir = opendir(path);
484 if (!td->dir) {
485 fprintf(stdout, "[error] Unable to open trace directory.\n");
486 ret = -ENOENT;
487 goto error;
488 }
489
490 td->dirfd = open(path, 0);
491 if (td->dirfd < 0) {
492 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
493 ret = -ENOENT;
494 goto error_dirfd;
495 }
496
497 td->streams = g_ptr_array_new();
498
499 /*
500 * Keep the metadata file separate.
501 */
502
503 ret = ctf_open_trace_metadata_read(td);
504 if (ret) {
505 goto error_metadata;
506 }
507
508 /*
509 * Open each stream: for each file, try to open, check magic
510 * number, and get the stream ID to add to the right location in
511 * the stream array.
512 */
513
514 dirent_len = offsetof(struct dirent, d_name) +
515 fpathconf(td->dirfd, _PC_NAME_MAX) + 1;
516
517 dirent = malloc(dirent_len);
518
519 for (;;) {
520 ret = readdir_r(td->dir, dirent, &diriter);
521 if (ret) {
522 fprintf(stdout, "[error] Readdir error.\n");
523 goto readdir_error;
524 }
525 if (!diriter)
526 break;
527 if (!strcmp(diriter->d_name, ".")
528 || !strcmp(diriter->d_name, "..")
529 || !strcmp(diriter->d_name, "metadata"))
530 continue;
531 ret = ctf_open_file_stream_read(td, diriter->d_name, flags);
532 if (ret) {
533 fprintf(stdout, "[error] Open file stream error.\n");
534 goto readdir_error;
535 }
536 }
537
538 free(dirent);
539 return 0;
540
541 readdir_error:
542 free(dirent);
543 error_metadata:
544 g_ptr_array_free(td->streams, TRUE);
545 close(td->dirfd);
546 error_dirfd:
547 closedir(td->dir);
548 error:
549 return ret;
550 }
551
552 static
553 int ctf_open_trace_write(struct ctf_trace *td, const char *path, int flags)
554 {
555 int ret;
556
557 ret = mkdir(path, S_IRWXU|S_IRWXG);
558 if (ret)
559 return ret;
560
561 /* Open trace directory */
562 td->dir = opendir(path);
563 if (!td->dir) {
564 fprintf(stdout, "[error] Unable to open trace directory.\n");
565 ret = -ENOENT;
566 goto error;
567 }
568
569
570 return 0;
571
572 error:
573 return ret;
574 }
575
576 struct trace_descriptor *ctf_open_trace(const char *path, int flags)
577 {
578 struct ctf_trace *td;
579 int ret;
580
581 td = g_new0(struct ctf_trace, 1);
582
583 switch (flags & O_ACCMODE) {
584 case O_RDONLY:
585 ret = ctf_open_trace_read(td, path, flags);
586 if (ret)
587 goto error;
588 break;
589 case O_WRONLY:
590 fprintf(stdout, "[error] Opening CTF traces for output is not supported yet.\n");
591 goto error;
592 #if 0
593 ret = ctf_open_trace_write(td, path, flags);
594 if (ret)
595 goto error;
596 #endif //0
597 break;
598 default:
599 fprintf(stdout, "[error] Incorrect open flags.\n");
600 goto error;
601 }
602
603 return &td->parent;
604 error:
605 g_free(td);
606 return NULL;
607 }
608
609 static
610 void ctf_close_file_stream(struct ctf_file_stream *file_stream)
611 {
612 ctf_fini_pos(&file_stream->pos);
613 close(file_stream->pos.fd);
614 }
615
616 void ctf_close_trace(struct trace_descriptor *tdp)
617 {
618 struct ctf_trace *td = container_of(tdp, struct ctf_trace, parent);
619 int i;
620
621 if (td->streams) {
622 for (i = 0; i < td->streams->len; i++) {
623 struct ctf_stream *stream;
624 int j;
625
626 stream = g_ptr_array_index(td->streams, i);
627 for (j = 0; j < stream->files->len; j++) {
628 struct ctf_file_stream *file_stream;
629 file_stream = g_ptr_array_index(td->streams, j);
630 ctf_close_file_stream(file_stream);
631 }
632
633 }
634 g_ptr_array_free(td->streams, TRUE);
635 }
636 closedir(td->dir);
637 g_free(td);
638 }
639
640 void __attribute__((constructor)) ctf_init(void)
641 {
642 int ret;
643
644 ctf_format.name = g_quark_from_static_string("ctf");
645 ret = bt_register_format(&ctf_format);
646 assert(!ret);
647 }
648
649 /* TODO: finalize */
This page took 0.042344 seconds and 5 git commands to generate.