Add missing string declaration (without {})
[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
MD
23#include <inttypes.h>
24#include <uuid/uuid.h>
25#include <sys/mman.h>
bbefb8dd 26#include <errno.h>
bbefb8dd 27#include <sys/types.h>
65102a8c 28#include <sys/stat.h>
bbefb8dd 29#include <fcntl.h>
65102a8c 30#include <dirent.h>
bbefb8dd 31#include <glib.h>
65102a8c
MD
32#include <unistd.h>
33#include <stdlib.h>
34
65102a8c
MD
35#include "metadata/ctf-scanner.h"
36#include "metadata/ctf-parser.h"
37#include "metadata/ctf-ast.h"
38
0f980a35
MD
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.
42 */
43#define MAX_PACKET_HEADER_LEN getpagesize()
44#define UUID_LEN 16 /* uuid by value len */
45
65102a8c 46extern int yydebug;
bbefb8dd
MD
47
48struct trace_descriptor {
49 struct ctf_trace ctf_trace;
50};
51
52struct trace_descriptor *ctf_open_trace(const char *path, int flags);
53void ctf_close_trace(struct trace_descriptor *descriptor);
fc93b2bd 54
4c8bfb7e 55static struct format ctf_format = {
fc93b2bd
MD
56 .uint_read = ctf_uint_read,
57 .int_read = ctf_int_read,
58 .uint_write = ctf_uint_write,
59 .int_write = ctf_int_write,
0a46062b
MD
60 .double_read = ctf_double_read,
61 .double_write = ctf_double_write,
dc48ecad
MD
62 .ldouble_read = ctf_ldouble_read,
63 .ldouble_write = ctf_ldouble_write,
fc93b2bd
MD
64 .float_copy = ctf_float_copy,
65 .string_copy = ctf_string_copy,
a52d7f6a
MD
66 .string_read = ctf_string_read,
67 .string_write = ctf_string_write,
68 .string_free_temp = ctf_string_free_temp,
448d3cc7
MD
69 .enum_read = ctf_enum_read,
70 .enum_write = ctf_enum_write,
11796b96
MD
71 .struct_begin = ctf_struct_begin,
72 .struct_end = ctf_struct_end,
c054553d
MD
73 .variant_begin = ctf_variant_begin,
74 .variant_end = ctf_variant_end,
d06d03db
MD
75 .array_begin = ctf_array_begin,
76 .array_end = ctf_array_end,
77 .sequence_begin = ctf_sequence_begin,
78 .sequence_end = ctf_sequence_end,
bbefb8dd
MD
79 .open_trace = ctf_open_trace,
80 .close_trace = ctf_close_trace,
fc93b2bd
MD
81};
82
0f980a35
MD
83void move_pos_slow(struct stream_pos *pos, size_t offset)
84{
85 int ret;
86
87 /*
88 * The caller should never ask for move_pos across packets,
89 * except to get exactly at the beginning of the next packet.
90 */
91 assert(pos->offset + offset == pos->content_size);
92
93 if (pos->base) {
94 /* unmap old base */
95 ret = munmap(pos->base, pos->packet_size);
96 if (ret) {
97 fprintf(stdout, "Unable to unmap old base: %s.\n",
98 strerror(errno));
99 assert(0);
100 }
101 }
102
103 pos->mmap_offset += pos->packet_size / CHAR_BIT;
104 /* map new base. Need mapping length from header. */
105 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
106 MAP_PRIVATE, pos->fd, pos->mmap_offset);
107 pos->content_size = 0; /* Unknown at this point */
108 pos->packet_size = 0; /* Unknown at this point */
109
110}
111
65102a8c
MD
112/*
113 * TODO: for now, we treat the metadata file as a simple text file
114 * (without any header nor packets nor padding).
115 */
116static
117int ctf_open_trace_metadata_read(struct trace_descriptor *td)
118{
119 struct ctf_scanner *scanner;
120 FILE *fp;
121 int ret = 0;
122
0f980a35 123 td->ctf_trace.metadata.pos.fd = openat(td->ctf_trace.dirfd,
65102a8c 124 "metadata", O_RDONLY);
0f980a35 125 if (td->ctf_trace.metadata.pos.fd < 0) {
65102a8c 126 fprintf(stdout, "Unable to open metadata.\n");
0f980a35 127 return td->ctf_trace.metadata.pos.fd;
65102a8c
MD
128 }
129
130 if (babeltrace_debug)
131 yydebug = 1;
132
0f980a35 133 fp = fdopen(td->ctf_trace.metadata.pos.fd, "r");
65102a8c
MD
134 if (!fp) {
135 fprintf(stdout, "Unable to open metadata stream.\n");
136 ret = -errno;
137 goto end_stream;
138 }
139
140 scanner = ctf_scanner_alloc(fp);
141 if (!scanner) {
142 fprintf(stdout, "Error allocating scanner\n");
143 ret = -ENOMEM;
144 goto end_scanner_alloc;
145 }
146 ret = ctf_scanner_append_ast(scanner);
147 if (ret) {
148 fprintf(stdout, "Error creating AST\n");
149 goto end;
150 }
151
152 if (babeltrace_debug) {
153 ret = ctf_visitor_print_xml(stdout, 0, &scanner->ast->root);
154 if (ret) {
155 fprintf(stdout, "Error visiting AST for XML output\n");
156 goto end;
157 }
158 }
159
160 ret = ctf_visitor_semantic_check(stdout, 0, &scanner->ast->root);
161 if (ret) {
162 fprintf(stdout, "Error in CTF semantic validation %d\n", ret);
163 goto end;
164 }
165 ret = ctf_visitor_construct_metadata(stdout, 0, &scanner->ast->root,
166 &td->ctf_trace, BYTE_ORDER);
167 if (ret) {
168 fprintf(stdout, "Error in CTF metadata constructor %d\n", ret);
169 goto end;
170 }
171end:
172 ctf_scanner_free(scanner);
173end_scanner_alloc:
174 fclose(fp);
175end_stream:
0f980a35
MD
176 close(td->ctf_trace.metadata.pos.fd);
177 return ret;
178}
179
180
181static
182int create_stream_packet_index(struct trace_descriptor *td,
183 struct ctf_file_stream *file_stream)
184{
185 struct ctf_stream *stream;
186 int len_index;
187 struct stream_pos *pos;
188 struct stat filestats;
189 struct packet_index packet_index;
190 int first_packet = 1;
191 int ret;
192
193 pos = &file_stream->pos;
194
195 ret = fstat(pos->fd, &filestats);
196 if (ret < 0)
197 return ret;
198
199 for (pos->mmap_offset = 0; pos->mmap_offset < filestats.st_size; ) {
200 uint64_t stream_id = 0;
201
202 if (pos->base) {
203 /* unmap old base */
204 ret = munmap(pos->base, pos->packet_size);
205 if (ret) {
206 fprintf(stdout, "Unable to unmap old base: %s.\n",
207 strerror(errno));
208 return ret;
209 }
210 }
211 /* map new base. Need mapping length from header. */
212 pos->base = mmap(NULL, MAX_PACKET_HEADER_LEN, PROT_READ,
213 MAP_PRIVATE, pos->fd, pos->mmap_offset);
dc48ecad
MD
214 pos->content_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
215 pos->packet_size = MAX_PACKET_HEADER_LEN; /* Unknown at this point */
0f980a35
MD
216 pos->offset = 0; /* Position of the packet header */
217
218 /* read and check header, set stream id (and check) */
219 if (td->ctf_trace.packet_header) {
220 /* Read packet header */
221 td->ctf_trace.packet_header->p.declaration->copy(NULL, NULL,
222 pos, &ctf_format, &td->ctf_trace.packet_header->p);
223
224 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("magic"));
225 if (len_index >= 0) {
226 struct definition_integer *defint;
227 struct field *field;
228
229 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
230 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
231 defint = container_of(field->definition, struct definition_integer, p);
232 assert(defint->declaration->signedness == FALSE);
233 if (defint->value._unsigned != CTF_MAGIC) {
234 fprintf(stdout, "[error] Invalid magic number %" PRIX64 ".\n",
235 defint->value._unsigned);
236 return -EINVAL;
237 }
238 }
239
240 /* check uuid */
241 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("trace_uuid"));
242 if (len_index >= 0) {
243 struct definition_array *defarray;
244 struct field *field;
245 uint64_t i;
246 uint8_t uuidval[UUID_LEN];
247
248
249 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
250 assert(field->definition->declaration->id == CTF_TYPE_ARRAY);
251 defarray = container_of(field->definition, struct definition_array, p);
3838df27 252 assert(array_len(defarray) == UUID_LEN);
0f980a35
MD
253 assert(defarray->declaration->elem->id == CTF_TYPE_INTEGER);
254
255 for (i = 0; i < UUID_LEN; i++) {
256 struct definition *elem;
257 struct definition_integer *defint;
258
259 elem = array_index(defarray, i);
260 assert(elem);
261 defint = container_of(elem, struct definition_integer, p);
262 uuidval[i] = defint->value._unsigned;
263 }
264 ret = uuid_compare(td->ctf_trace.uuid, uuidval);
265 if (ret) {
266 fprintf(stdout, "[error] Unique Universal Identifiers do not match.\n");
267 return -EINVAL;
268 }
269 }
270
271
272 len_index = struct_declaration_lookup_field_index(td->ctf_trace.packet_header->declaration, g_quark_from_static_string("stream_id"));
273 if (len_index >= 0) {
274 struct definition_integer *defint;
275 struct field *field;
276
277 field = struct_definition_get_field_from_index(td->ctf_trace.packet_header, len_index);
278 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
279 defint = container_of(field->definition, struct definition_integer, p);
280 assert(defint->declaration->signedness == FALSE);
281 stream_id = defint->value._unsigned;
282 }
283 }
284
285 if (!first_packet && file_stream->stream_id != stream_id) {
286 fprintf(stdout, "[error] Stream ID is changing within a stream.\n");
287 return -EINVAL;
288 }
289 if (first_packet) {
290 file_stream->stream_id = stream_id;
291 if (stream_id >= td->ctf_trace.streams->len) {
292 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
293 return -EINVAL;
294 }
295 stream = g_ptr_array_index(td->ctf_trace.streams, stream_id);
296 if (!stream) {
297 fprintf(stdout, "[error] Stream %" PRIu64 " is not declared in metadata.\n", stream_id);
298 return -EINVAL;
299 }
300 file_stream->stream = stream;
301 }
302 first_packet = 0;
303
dc48ecad
MD
304 if (stream->packet_context) {
305 /* Read packet context */
306 stream->packet_context->p.declaration->copy(NULL, NULL,
307 pos, &ctf_format, &stream->packet_context->p);
308
309 /* read content size from header */
310 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("content_size"));
311 if (len_index >= 0) {
312 struct definition_integer *defint;
313 struct field *field;
314
315 field = struct_definition_get_field_from_index(stream->packet_context, 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 pos->content_size = defint->value._unsigned;
320 } else {
321 /* Use file size for packet size */
322 pos->content_size = filestats.st_size * CHAR_BIT;
323 }
324
325 /* read packet size from header */
326 len_index = struct_declaration_lookup_field_index(stream->packet_context->declaration, g_quark_from_static_string("packet_size"));
327 if (len_index >= 0) {
328 struct definition_integer *defint;
329 struct field *field;
330
331 field = struct_definition_get_field_from_index(stream->packet_context, len_index);
332 assert(field->definition->declaration->id == CTF_TYPE_INTEGER);
333 defint = container_of(field->definition, struct definition_integer, p);
334 assert(defint->declaration->signedness == FALSE);
335 pos->packet_size = defint->value._unsigned;
336 } else {
337 /* Use content size if non-zero, else file size */
338 pos->packet_size = pos->content_size ? : filestats.st_size * CHAR_BIT;
339 }
0f980a35
MD
340 } else {
341 /* Use file size for packet size */
342 pos->content_size = filestats.st_size * CHAR_BIT;
0f980a35
MD
343 /* Use content size if non-zero, else file size */
344 pos->packet_size = pos->content_size ? : filestats.st_size * CHAR_BIT;
345 }
346
347 packet_index.offset = pos->mmap_offset;
348 packet_index.content_size = pos->content_size;
349 packet_index.packet_size = pos->packet_size;
350 /* add index to packet array */
351 g_array_append_val(file_stream->pos.packet_index, packet_index);
352
353 pos->mmap_offset += pos->packet_size / CHAR_BIT;
354 }
355
356 return 0;
357}
358
359/*
360 * Note: many file streams can inherit from the same stream class
361 * description (metadata).
362 */
363static
364int ctf_open_file_stream_read(struct trace_descriptor *td, const char *path, int flags)
365{
366 int ret;
367 struct ctf_file_stream *file_stream;
368
369 ret = openat(td->ctf_trace.dirfd, path, flags);
370 if (ret < 0)
371 goto error;
372 file_stream = g_new0(struct ctf_file_stream, 1);
373 file_stream->pos.fd = ret;
374 file_stream->pos.packet_index = g_array_new(FALSE, TRUE,
375 sizeof(struct packet_index));
376 ret = create_stream_packet_index(td, file_stream);
377 if (ret)
378 goto error_index;
379 /* Add stream file to stream class */
380 g_ptr_array_add(file_stream->stream->files, file_stream);
381 return 0;
382
383error_index:
384 (void) g_array_free(file_stream->pos.packet_index, TRUE);
385 close(file_stream->pos.fd);
386 g_free(file_stream);
387error:
65102a8c
MD
388 return ret;
389}
390
bbefb8dd
MD
391static
392int ctf_open_trace_read(struct trace_descriptor *td, const char *path, int flags)
393{
394 int ret;
65102a8c
MD
395 struct dirent *dirent;
396 struct dirent *diriter;
397 size_t dirent_len;
bbefb8dd
MD
398
399 td->ctf_trace.flags = flags;
400
401 /* Open trace directory */
402 td->ctf_trace.dir = opendir(path);
403 if (!td->ctf_trace.dir) {
dc48ecad 404 fprintf(stdout, "[error] Unable to open trace directory.\n");
bbefb8dd
MD
405 ret = -ENOENT;
406 goto error;
407 }
408
65102a8c
MD
409 td->ctf_trace.dirfd = open(path, 0);
410 if (td->ctf_trace.dirfd < 0) {
dc48ecad 411 fprintf(stdout, "[error] Unable to open trace directory file descriptor.\n");
65102a8c
MD
412 ret = -ENOENT;
413 goto error_dirfd;
414 }
0f980a35
MD
415
416 td->ctf_trace.streams = g_ptr_array_new();
417
65102a8c
MD
418 /*
419 * Keep the metadata file separate.
420 */
bbefb8dd 421
65102a8c
MD
422 ret = ctf_open_trace_metadata_read(td);
423 if (ret) {
424 goto error_metadata;
425 }
bbefb8dd
MD
426
427 /*
428 * Open each stream: for each file, try to open, check magic
429 * number, and get the stream ID to add to the right location in
430 * the stream array.
bbefb8dd
MD
431 */
432
65102a8c
MD
433 dirent_len = offsetof(struct dirent, d_name) +
434 fpathconf(td->ctf_trace.dirfd, _PC_NAME_MAX) + 1;
bbefb8dd 435
65102a8c 436 dirent = malloc(dirent_len);
bbefb8dd 437
65102a8c
MD
438 for (;;) {
439 ret = readdir_r(td->ctf_trace.dir, dirent, &diriter);
440 if (ret) {
dc48ecad 441 fprintf(stdout, "[error] Readdir error.\n");
65102a8c 442 goto readdir_error;
65102a8c
MD
443 }
444 if (!diriter)
445 break;
446 if (!strcmp(diriter->d_name, ".")
447 || !strcmp(diriter->d_name, "..")
448 || !strcmp(diriter->d_name, "metadata"))
449 continue;
dc48ecad
MD
450 ret = ctf_open_file_stream_read(td, diriter->d_name, flags);
451 if (ret) {
452 fprintf(stdout, "[error] Open file stream error.\n");
453 goto readdir_error;
454 }
65102a8c 455 }
bbefb8dd 456
65102a8c 457 free(dirent);
bbefb8dd 458 return 0;
65102a8c
MD
459
460readdir_error:
461 free(dirent);
462error_metadata:
0f980a35 463 g_ptr_array_free(td->ctf_trace.streams, TRUE);
65102a8c
MD
464 close(td->ctf_trace.dirfd);
465error_dirfd:
466 closedir(td->ctf_trace.dir);
bbefb8dd
MD
467error:
468 return ret;
469}
470
471static
472int ctf_open_trace_write(struct trace_descriptor *td, const char *path, int flags)
473{
474 int ret;
475
476 ret = mkdir(path, S_IRWXU|S_IRWXG);
477 if (ret)
478 return ret;
479
65102a8c
MD
480 /* Open trace directory */
481 td->ctf_trace.dir = opendir(path);
482 if (!td->ctf_trace.dir) {
483 fprintf(stdout, "Unable to open trace directory.\n");
484 ret = -ENOENT;
485 goto error;
486 }
487
488
bbefb8dd 489 return 0;
65102a8c
MD
490
491error:
492 return ret;
bbefb8dd
MD
493}
494
495struct trace_descriptor *ctf_open_trace(const char *path, int flags)
496{
497 struct trace_descriptor *td;
498 int ret;
499
65102a8c 500 td = g_new0(struct trace_descriptor, 1);
bbefb8dd
MD
501
502 switch (flags) {
503 case O_RDONLY:
504 ret = ctf_open_trace_read(td, path, flags);
505 if (ret)
506 goto error;
507 break;
508 case O_WRONLY:
509 ret = ctf_open_trace_write(td, path, flags);
510 if (ret)
511 goto error;
512 break;
513 default:
514 fprintf(stdout, "Incorrect open flags.\n");
515 goto error;
516 }
517
518 return td;
519error:
520 g_free(td);
521 return NULL;
522}
523
0f980a35
MD
524static
525void ctf_close_file_stream(struct ctf_file_stream *file_stream)
526{
527 (void) g_array_free(file_stream->pos.packet_index, TRUE);
528 close(file_stream->pos.fd);
529}
530
bbefb8dd
MD
531void ctf_close_trace(struct trace_descriptor *td)
532{
0f980a35
MD
533 int i;
534
535 if (td->ctf_trace.streams) {
536 for (i = 0; i < td->ctf_trace.streams->len; i++) {
537 struct ctf_stream *stream;
538 int j;
539
540 stream = g_ptr_array_index(td->ctf_trace.streams, i);
541 for (j = 0; j < stream->files->len; j++) {
542 struct ctf_file_stream *file_stream;
543 file_stream = g_ptr_array_index(td->ctf_trace.streams, j);
544 ctf_close_file_stream(file_stream);
545 }
546
547 }
548 g_ptr_array_free(td->ctf_trace.streams, TRUE);
549 }
bbefb8dd
MD
550 closedir(td->ctf_trace.dir);
551 g_free(td);
552}
553
7fb21036 554void __attribute__((constructor)) ctf_init(void)
fc93b2bd
MD
555{
556 int ret;
557
4c8bfb7e 558 ctf_format.name = g_quark_from_static_string("ctf");
fc93b2bd
MD
559 ret = bt_register_format(&ctf_format);
560 assert(!ret);
561}
698f0fe4
MD
562
563/* TODO: finalize */
This page took 0.045781 seconds and 4 git commands to generate.