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