Support for --clock-offset and --clock-offset-ns
[babeltrace.git] / plugins / ctf / fs / metadata.c
CommitLineData
e98a2d6e
PP
1/*
2 * Copyright 2016 - Philippe Proulx <pproulx@efficios.com>
3 * Copyright 2010-2011 - EfficiOS Inc. and Linux Foundation
4 *
5 * Some functions are based on older functions written by Mathieu Desnoyers.
6 *
7 * Permission is hereby granted, free of charge, to any person obtaining a copy
8 * of this software and associated documentation files (the "Software"), to deal
9 * in the Software without restriction, including without limitation the rights
10 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11 * copies of the Software, and to permit persons to whom the Software is
12 * furnished to do so, subject to the following conditions:
13 *
14 * The above copyright notice and this permission notice shall be included in
15 * all copies or substantial portions of the Software.
16 *
17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
20 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
23 * SOFTWARE.
24 */
25
26#include <stdio.h>
27#include <stdint.h>
28#include <stdlib.h>
29#include <stdbool.h>
30#include <glib.h>
31#include <babeltrace/compat/uuid.h>
32#include <babeltrace/compat/memstream.h>
33
34#define PRINT_ERR_STREAM ctf_fs->error_fp
35#define PRINT_PREFIX "ctf-fs-metadata"
36#include "print.h"
37
56a1cced
JG
38#include "fs.h"
39#include "file.h"
40#include "metadata.h"
41#include "../common/metadata/ast.h"
42#include "../common/metadata/scanner.h"
e98a2d6e
PP
43
44#define TSDL_MAGIC 0x75d11d57
45
92540773
JD
46#define NSEC_PER_SEC 1000000000LL
47
e98a2d6e
PP
48struct packet_header {
49 uint32_t magic;
50 uint8_t uuid[16];
51 uint32_t checksum;
52 uint32_t content_size;
53 uint32_t packet_size;
54 uint8_t compression_scheme;
55 uint8_t encryption_scheme;
56 uint8_t checksum_scheme;
57 uint8_t major;
58 uint8_t minor;
59} __attribute__((__packed__));
60
33f93973
PP
61BT_HIDDEN
62FILE *ctf_fs_metadata_open_file(const char *trace_path)
63{
64 GString *metadata_path = g_string_new(trace_path);
65 FILE *fp = NULL;
66
67 if (!metadata_path) {
68 goto error;
69 }
70
71 g_string_append(metadata_path, "/" CTF_FS_METADATA_FILENAME);
72 fp = fopen(metadata_path->str, "rb");
73 if (!fp) {
74 goto error;
75 }
76
77 goto end;
78
79error:
80 if (fp) {
81 fclose(fp);
82 fp = NULL;
83 }
84
85end:
86 g_string_free(metadata_path, TRUE);
87 return fp;
88}
89
56a1cced 90static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs,
e98a2d6e
PP
91 const char *trace_path)
92{
93 struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs);
94
95 if (!file) {
96 goto error;
97 }
98
99 g_string_append(file->path, trace_path);
100 g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME);
101
102 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
103 goto error;
104 }
105
106 goto end;
107
108error:
109 if (file) {
110 ctf_fs_file_destroy(file);
111 file = NULL;
112 }
113
114end:
115 return file;
116}
117
33f93973
PP
118BT_HIDDEN
119bool ctf_metadata_is_packetized(FILE *fp, int *byte_order)
e98a2d6e
PP
120{
121 uint32_t magic;
122 size_t len;
123 int ret = 0;
124
33f93973 125 len = fread(&magic, sizeof(magic), 1, fp);
e98a2d6e
PP
126 if (len != 1) {
127 goto end;
128 }
129
33f93973
PP
130 if (byte_order) {
131 if (magic == TSDL_MAGIC) {
132 ret = 1;
133 *byte_order = BYTE_ORDER;
134 } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
135 ret = 1;
136 *byte_order = BYTE_ORDER == BIG_ENDIAN ?
137 LITTLE_ENDIAN : BIG_ENDIAN;
138 }
e98a2d6e
PP
139 }
140
141end:
33f93973 142 rewind(fp);
e98a2d6e
PP
143
144 return ret;
145}
146
147static
148bool is_version_valid(unsigned int major, unsigned int minor)
149{
150 return major == 1 && minor == 8;
151}
152
153static
33f93973
PP
154int decode_packet(struct ctf_fs_component *ctf_fs, FILE *in_fp, FILE *out_fp,
155 int byte_order)
e98a2d6e
PP
156{
157 struct packet_header header;
158 size_t readlen, writelen, toread;
159 uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */
160 int ret = 0;
161
162 readlen = fread(&header, sizeof(header), 1, in_fp);
163 if (feof(in_fp) != 0) {
164 goto end;
165 }
166 if (readlen < 1) {
167 goto error;
168 }
169
33f93973 170 if (byte_order != BYTE_ORDER) {
e98a2d6e
PP
171 header.magic = GUINT32_SWAP_LE_BE(header.magic);
172 header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
173 header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
174 header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
175 }
176
177 if (header.compression_scheme) {
178 PERR("Metadata packet compression not supported yet\n");
179 goto error;
180 }
181
182 if (header.encryption_scheme) {
183 PERR("Metadata packet encryption not supported yet\n");
184 goto error;
185 }
186
187 if (header.checksum || header.checksum_scheme) {
188 PERR("Metadata packet checksum verification not supported yet\n");
189 goto error;
190 }
191
192 if (!is_version_valid(header.major, header.minor)) {
193 PERR("Invalid metadata version: %u.%u\n", header.major,
194 header.minor);
195 goto error;
196 }
197
198 /* Set expected trace UUID if not set; otherwise validate it */
33f93973
PP
199 if (ctf_fs) {
200 if (!ctf_fs->metadata->is_uuid_set) {
201 memcpy(ctf_fs->metadata->uuid, header.uuid, sizeof(header.uuid));
202 ctf_fs->metadata->is_uuid_set = true;
203 } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata->uuid)) {
204 PERR("Metadata UUID mismatch between packets of the same file\n");
205 goto error;
206 }
e98a2d6e
PP
207 }
208
209 if ((header.content_size / CHAR_BIT) < sizeof(header)) {
210 PERR("Bad metadata packet content size: %u\n",
211 header.content_size);
212 goto error;
213 }
214
215 toread = header.content_size / CHAR_BIT - sizeof(header);
216
217 for (;;) {
218 readlen = fread(buf, sizeof(uint8_t),
219 MIN(sizeof(buf) - 1, toread), in_fp);
220 if (ferror(in_fp)) {
221 PERR("Cannot read metadata packet buffer (at position %ld)\n",
222 ftell(in_fp));
223 goto error;
224 }
225
226 writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
227 if (writelen < readlen || ferror(out_fp)) {
228 PERR("Cannot write decoded metadata text to buffer\n");
229 goto error;
230 }
231
232 toread -= readlen;
233 if (toread == 0) {
234 int fseek_ret;
235
236 /* Read leftover padding */
237 toread = (header.packet_size - header.content_size) /
238 CHAR_BIT;
239 fseek_ret = fseek(in_fp, toread, SEEK_CUR);
240 if (fseek_ret < 0) {
241 PWARN("Missing padding at the end of the metadata file\n");
242 }
243
244 break;
245 }
246 }
247
248 goto end;
249
250error:
251 ret = -1;
252
253end:
254 return ret;
255}
256
33f93973
PP
257BT_HIDDEN
258int ctf_metadata_packetized_file_to_buf(struct ctf_fs_component *ctf_fs,
259 FILE *fp, uint8_t **buf, int byte_order)
e98a2d6e
PP
260{
261 FILE *out_fp;
262 size_t size;
263 int ret = 0;
264 int tret;
265 size_t packet_index = 0;
266
267 out_fp = babeltrace_open_memstream((char **) buf, &size);
268 if (out_fp == NULL) {
269 PERR("Cannot open memory stream: %s\n", strerror(errno));
270 goto error;
271 }
272
273 for (;;) {
33f93973 274 if (feof(fp) != 0) {
e98a2d6e
PP
275 break;
276 }
277
33f93973 278 tret = decode_packet(ctf_fs, fp, out_fp, byte_order);
e98a2d6e
PP
279 if (tret) {
280 PERR("Cannot decode packet #%zu\n", packet_index);
281 goto error;
282 }
283
284 packet_index++;
285 }
286
287 /* Make sure the whole string ends with a null character */
288 tret = fputc('\0', out_fp);
289 if (tret == EOF) {
290 PERR("Cannot append '\\0' to the decoded metadata buffer\n");
291 goto error;
292 }
293
294 /* Close stream, which also flushes the buffer */
295 ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
296 if (ret < 0) {
297 PERR("Cannot close memory stream: %s\n", strerror(errno));
298 goto error;
299 }
300
301 goto end;
302
303error:
304 ret = -1;
305
306 if (out_fp) {
307 babeltrace_close_memstream((char **) buf, &size, out_fp);
308 }
309
310 if (*buf) {
311 free(*buf);
312 }
313
314end:
315 return ret;
316}
317
4f1f88a6 318int ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
e98a2d6e
PP
319{
320 int ret = 0;
321 struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
322 struct ctf_scanner *scanner = NULL;
323 uint8_t *buf = NULL;
324 char *cbuf;
325
326 if (!file) {
327 PERR("Cannot create metadata file object\n");
328 goto error;
329 }
330
331 if (babeltrace_debug) {
332 // yydebug = 1;
333 }
334
33f93973 335 if (ctf_metadata_is_packetized(file->fp, &ctf_fs->metadata->bo)) {
e98a2d6e 336 PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
33f93973
PP
337 ret = ctf_metadata_packetized_file_to_buf(ctf_fs, file->fp,
338 &buf, ctf_fs->metadata->bo);
e98a2d6e
PP
339 if (ret) {
340 // log: details
341 goto error;
342 }
343
344 cbuf = (char *) buf;
5b29e799 345 ctf_fs->metadata->text = (char *) cbuf;
e98a2d6e
PP
346
347 /* Convert the real file pointer to a memory file pointer */
348 ret = fclose(file->fp);
349 file->fp = NULL;
350 if (ret) {
351 PERR("Cannot close file \"%s\": %s\n", file->path->str,
352 strerror(errno));
353 goto error;
354 }
355
356 file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
357 if (!file->fp) {
358 PERR("Cannot memory-open metadata buffer: %s\n",
359 strerror(errno));
360 goto error;
361 }
362 } else {
363 unsigned int major, minor;
364 ssize_t nr_items;
365
366 PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
367
368 /* Check text-only metadata header and version */
369 nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
370 if (nr_items < 2) {
371 PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
372 }
373 PDBG("Metadata version: %u.%u\n", major, minor);
374
375 if (!is_version_valid(major, minor)) {
376 PERR("Invalid metadata version: %u.%u\n", major, minor);
377 goto error;
378 }
379
380 rewind(file->fp);
381 }
382
383 /* Allocate a scanner and append the metadata text content */
384 scanner = ctf_scanner_alloc();
385 if (!scanner) {
386 PERR("Cannot allocate a metadata lexical scanner\n");
387 goto error;
388 }
389
390 ret = ctf_scanner_append_ast(scanner, file->fp);
391 if (ret) {
392 PERR("Cannot create the metadata AST\n");
393 goto error;
394 }
395
396 ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
397 if (ret) {
398 PERR("Metadata semantic validation failed\n");
399 goto error;
400 }
401
402 ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
92540773
JD
403 &ctf_fs->metadata->trace,
404 ctf_fs->options.clock_offset * NSEC_PER_SEC +
405 ctf_fs->options.clock_offset_ns);
e98a2d6e
PP
406 if (ret) {
407 PERR("Cannot create trace object from metadata AST\n");
408 goto error;
409 }
410
411 goto end;
412
413error:
5b29e799
JG
414 if (ctf_fs->metadata->text) {
415 free(ctf_fs->metadata->text);
416 ctf_fs->metadata->text = NULL;
e98a2d6e
PP
417 }
418
4f1f88a6
PP
419 ret = -1;
420
e98a2d6e
PP
421end:
422 if (file) {
423 ctf_fs_file_destroy(file);
424 }
425
426 if (scanner) {
427 ctf_scanner_free(scanner);
428 }
4f1f88a6
PP
429
430 return ret;
e98a2d6e
PP
431}
432
433int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
434{
5b29e799 435 /* Nothing to initialize for the moment. */
e98a2d6e
PP
436 return 0;
437}
438
413bc2c4 439void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
e98a2d6e
PP
440{
441 if (metadata->text) {
442 free(metadata->text);
443 }
444
445 if (metadata->trace) {
446 BT_PUT(metadata->trace);
447 }
448}
This page took 0.048894 seconds and 4 git commands to generate.