babeltrace(1): print value with colors
[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
46struct packet_header {
47 uint32_t magic;
48 uint8_t uuid[16];
49 uint32_t checksum;
50 uint32_t content_size;
51 uint32_t packet_size;
52 uint8_t compression_scheme;
53 uint8_t encryption_scheme;
54 uint8_t checksum_scheme;
55 uint8_t major;
56 uint8_t minor;
57} __attribute__((__packed__));
58
56a1cced 59static struct ctf_fs_file *get_file(struct ctf_fs_component *ctf_fs,
e98a2d6e
PP
60 const char *trace_path)
61{
62 struct ctf_fs_file *file = ctf_fs_file_create(ctf_fs);
63
64 if (!file) {
65 goto error;
66 }
67
68 g_string_append(file->path, trace_path);
69 g_string_append(file->path, "/" CTF_FS_METADATA_FILENAME);
70
71 if (ctf_fs_file_open(ctf_fs, file, "rb")) {
72 goto error;
73 }
74
75 goto end;
76
77error:
78 if (file) {
79 ctf_fs_file_destroy(file);
80 file = NULL;
81 }
82
83end:
84 return file;
85}
86
87static
56a1cced 88bool is_packetized(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file)
e98a2d6e
PP
89{
90 uint32_t magic;
91 size_t len;
92 int ret = 0;
93
94 len = fread(&magic, sizeof(magic), 1, file->fp);
95 if (len != 1) {
96 goto end;
97 }
98
99 if (magic == TSDL_MAGIC) {
100 ret = 1;
5b29e799 101 ctf_fs->metadata->bo = BYTE_ORDER;
e98a2d6e
PP
102 } else if (magic == GUINT32_SWAP_LE_BE(TSDL_MAGIC)) {
103 ret = 1;
5b29e799 104 ctf_fs->metadata->bo = BYTE_ORDER == BIG_ENDIAN ?
e98a2d6e
PP
105 LITTLE_ENDIAN : BIG_ENDIAN;
106 }
107
108end:
109 rewind(file->fp);
110
111 return ret;
112}
113
114static
115bool is_version_valid(unsigned int major, unsigned int minor)
116{
117 return major == 1 && minor == 8;
118}
119
120static
56a1cced 121int decode_packet(struct ctf_fs_component *ctf_fs, FILE *in_fp, FILE *out_fp)
e98a2d6e
PP
122{
123 struct packet_header header;
124 size_t readlen, writelen, toread;
125 uint8_t buf[512 + 1]; /* + 1 for debug-mode \0 */
126 int ret = 0;
127
128 readlen = fread(&header, sizeof(header), 1, in_fp);
129 if (feof(in_fp) != 0) {
130 goto end;
131 }
132 if (readlen < 1) {
133 goto error;
134 }
135
5b29e799 136 if (ctf_fs->metadata->bo != BYTE_ORDER) {
e98a2d6e
PP
137 header.magic = GUINT32_SWAP_LE_BE(header.magic);
138 header.checksum = GUINT32_SWAP_LE_BE(header.checksum);
139 header.content_size = GUINT32_SWAP_LE_BE(header.content_size);
140 header.packet_size = GUINT32_SWAP_LE_BE(header.packet_size);
141 }
142
143 if (header.compression_scheme) {
144 PERR("Metadata packet compression not supported yet\n");
145 goto error;
146 }
147
148 if (header.encryption_scheme) {
149 PERR("Metadata packet encryption not supported yet\n");
150 goto error;
151 }
152
153 if (header.checksum || header.checksum_scheme) {
154 PERR("Metadata packet checksum verification not supported yet\n");
155 goto error;
156 }
157
158 if (!is_version_valid(header.major, header.minor)) {
159 PERR("Invalid metadata version: %u.%u\n", header.major,
160 header.minor);
161 goto error;
162 }
163
164 /* Set expected trace UUID if not set; otherwise validate it */
5b29e799
JG
165 if (!ctf_fs->metadata->is_uuid_set) {
166 memcpy(ctf_fs->metadata->uuid, header.uuid, sizeof(header.uuid));
167 ctf_fs->metadata->is_uuid_set = true;
168 } else if (bt_uuid_compare(header.uuid, ctf_fs->metadata->uuid)) {
e98a2d6e
PP
169 PERR("Metadata UUID mismatch between packets of the same file\n");
170 goto error;
171 }
172
173 if ((header.content_size / CHAR_BIT) < sizeof(header)) {
174 PERR("Bad metadata packet content size: %u\n",
175 header.content_size);
176 goto error;
177 }
178
179 toread = header.content_size / CHAR_BIT - sizeof(header);
180
181 for (;;) {
182 readlen = fread(buf, sizeof(uint8_t),
183 MIN(sizeof(buf) - 1, toread), in_fp);
184 if (ferror(in_fp)) {
185 PERR("Cannot read metadata packet buffer (at position %ld)\n",
186 ftell(in_fp));
187 goto error;
188 }
189
190 writelen = fwrite(buf, sizeof(uint8_t), readlen, out_fp);
191 if (writelen < readlen || ferror(out_fp)) {
192 PERR("Cannot write decoded metadata text to buffer\n");
193 goto error;
194 }
195
196 toread -= readlen;
197 if (toread == 0) {
198 int fseek_ret;
199
200 /* Read leftover padding */
201 toread = (header.packet_size - header.content_size) /
202 CHAR_BIT;
203 fseek_ret = fseek(in_fp, toread, SEEK_CUR);
204 if (fseek_ret < 0) {
205 PWARN("Missing padding at the end of the metadata file\n");
206 }
207
208 break;
209 }
210 }
211
212 goto end;
213
214error:
215 ret = -1;
216
217end:
218 return ret;
219}
220
221static
56a1cced 222int packetized_file_to_buf(struct ctf_fs_component *ctf_fs, struct ctf_fs_file *file,
e98a2d6e
PP
223 uint8_t **buf)
224{
225 FILE *out_fp;
226 size_t size;
227 int ret = 0;
228 int tret;
229 size_t packet_index = 0;
230
231 out_fp = babeltrace_open_memstream((char **) buf, &size);
232 if (out_fp == NULL) {
233 PERR("Cannot open memory stream: %s\n", strerror(errno));
234 goto error;
235 }
236
237 for (;;) {
238 if (feof(file->fp) != 0) {
239 break;
240 }
241
242 tret = decode_packet(ctf_fs, file->fp, out_fp);
243 if (tret) {
244 PERR("Cannot decode packet #%zu\n", packet_index);
245 goto error;
246 }
247
248 packet_index++;
249 }
250
251 /* Make sure the whole string ends with a null character */
252 tret = fputc('\0', out_fp);
253 if (tret == EOF) {
254 PERR("Cannot append '\\0' to the decoded metadata buffer\n");
255 goto error;
256 }
257
258 /* Close stream, which also flushes the buffer */
259 ret = babeltrace_close_memstream((char **) buf, &size, out_fp);
260 if (ret < 0) {
261 PERR("Cannot close memory stream: %s\n", strerror(errno));
262 goto error;
263 }
264
265 goto end;
266
267error:
268 ret = -1;
269
270 if (out_fp) {
271 babeltrace_close_memstream((char **) buf, &size, out_fp);
272 }
273
274 if (*buf) {
275 free(*buf);
276 }
277
278end:
279 return ret;
280}
281
56a1cced 282void ctf_fs_metadata_set_trace(struct ctf_fs_component *ctf_fs)
e98a2d6e
PP
283{
284 int ret = 0;
285 struct ctf_fs_file *file = get_file(ctf_fs, ctf_fs->trace_path->str);
286 struct ctf_scanner *scanner = NULL;
287 uint8_t *buf = NULL;
288 char *cbuf;
289
290 if (!file) {
291 PERR("Cannot create metadata file object\n");
292 goto error;
293 }
294
295 if (babeltrace_debug) {
296 // yydebug = 1;
297 }
298
299 if (is_packetized(ctf_fs, file)) {
300 PDBG("Metadata file \"%s\" is packetized\n", file->path->str);
301 ret = packetized_file_to_buf(ctf_fs, file, &buf);
302 if (ret) {
303 // log: details
304 goto error;
305 }
306
307 cbuf = (char *) buf;
5b29e799 308 ctf_fs->metadata->text = (char *) cbuf;
e98a2d6e
PP
309
310 /* Convert the real file pointer to a memory file pointer */
311 ret = fclose(file->fp);
312 file->fp = NULL;
313 if (ret) {
314 PERR("Cannot close file \"%s\": %s\n", file->path->str,
315 strerror(errno));
316 goto error;
317 }
318
319 file->fp = babeltrace_fmemopen(cbuf, strlen(cbuf), "rb");
320 if (!file->fp) {
321 PERR("Cannot memory-open metadata buffer: %s\n",
322 strerror(errno));
323 goto error;
324 }
325 } else {
326 unsigned int major, minor;
327 ssize_t nr_items;
328
329 PDBG("Metadata file \"%s\" is plain text\n", file->path->str);
330
331 /* Check text-only metadata header and version */
332 nr_items = fscanf(file->fp, "/* CTF %10u.%10u", &major, &minor);
333 if (nr_items < 2) {
334 PWARN("Ill-shapen or missing \"/* CTF major.minor\" header in plain text metadata file\n");
335 }
336 PDBG("Metadata version: %u.%u\n", major, minor);
337
338 if (!is_version_valid(major, minor)) {
339 PERR("Invalid metadata version: %u.%u\n", major, minor);
340 goto error;
341 }
342
343 rewind(file->fp);
344 }
345
346 /* Allocate a scanner and append the metadata text content */
347 scanner = ctf_scanner_alloc();
348 if (!scanner) {
349 PERR("Cannot allocate a metadata lexical scanner\n");
350 goto error;
351 }
352
353 ret = ctf_scanner_append_ast(scanner, file->fp);
354 if (ret) {
355 PERR("Cannot create the metadata AST\n");
356 goto error;
357 }
358
359 ret = ctf_visitor_semantic_check(stderr, 0, &scanner->ast->root);
360 if (ret) {
361 PERR("Metadata semantic validation failed\n");
362 goto error;
363 }
364
365 ret = ctf_visitor_generate_ir(ctf_fs->error_fp, &scanner->ast->root,
5b29e799 366 &ctf_fs->metadata->trace);
e98a2d6e
PP
367 if (ret) {
368 PERR("Cannot create trace object from metadata AST\n");
369 goto error;
370 }
371
372 goto end;
373
374error:
5b29e799
JG
375 if (ctf_fs->metadata->text) {
376 free(ctf_fs->metadata->text);
377 ctf_fs->metadata->text = NULL;
e98a2d6e
PP
378 }
379
380end:
381 if (file) {
382 ctf_fs_file_destroy(file);
383 }
384
385 if (scanner) {
386 ctf_scanner_free(scanner);
387 }
388}
389
390int ctf_fs_metadata_init(struct ctf_fs_metadata *metadata)
391{
5b29e799 392 /* Nothing to initialize for the moment. */
e98a2d6e
PP
393 return 0;
394}
395
413bc2c4 396void ctf_fs_metadata_fini(struct ctf_fs_metadata *metadata)
e98a2d6e
PP
397{
398 if (metadata->text) {
399 free(metadata->text);
400 }
401
402 if (metadata->trace) {
403 BT_PUT(metadata->trace);
404 }
405}
This page took 0.041206 seconds and 4 git commands to generate.