Add src.text.dmesg component class
[babeltrace.git] / plugins / text / dmesg / dmesg.c
1 /*
2 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
3 * Copyright 2017 Philippe Proulx <jeremie.galarneau@efficios.com>
4 *
5 * Permission is hereby granted, free of charge, to any person obtaining a copy
6 * of this software and associated documentation files (the "Software"), to deal
7 * in the Software without restriction, including without limitation the rights
8 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 * copies of the Software, and to permit persons to whom the Software is
10 * furnished to do so, subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 */
23
24 #define BT_LOG_TAG "PLUGIN-TEXT-DMESG-SRC"
25 #include "logging.h"
26
27 #include <stdbool.h>
28 #include <string.h>
29 #include <ctype.h>
30 #include <stdio.h>
31 #include <assert.h>
32 #include <babeltrace/babeltrace.h>
33 #include <babeltrace/values-internal.h>
34 #include <babeltrace/compat/utc-internal.h>
35 #include <babeltrace/compat/stdio-internal.h>
36 #include <glib.h>
37
38 #define NSEC_PER_USEC 1000UL
39 #define NSEC_PER_MSEC 1000000UL
40 #define NSEC_PER_SEC 1000000000ULL
41 #define USEC_PER_SEC 1000000UL
42
43 struct dmesg_component;
44
45 struct dmesg_notif_iter {
46 struct dmesg_component *dmesg_comp;
47 char *linebuf;
48 size_t linebuf_len;
49 FILE *fp;
50 };
51
52 struct dmesg_component {
53 struct {
54 GString *path;
55 bt_bool read_from_stdin;
56 } params;
57
58 struct bt_ctf_trace *trace;
59 struct bt_ctf_stream_class *stream_class;
60 struct bt_ctf_event_class *event_class;
61 struct bt_ctf_stream *stream;
62 struct bt_ctf_packet *packet;
63 struct bt_ctf_clock_class *clock_class;
64 struct bt_clock_class_priority_map *cc_prio_map;
65 };
66
67 static
68 struct bt_ctf_field_type *create_packet_header_ft(void)
69 {
70 struct bt_ctf_field_type *root_ft = NULL;
71 struct bt_ctf_field_type *ft = NULL;
72 int ret;
73
74 root_ft = bt_ctf_field_type_structure_create();
75 if (!root_ft) {
76 BT_LOGE_STR("Cannot create an empty structure field type object.");
77 goto error;
78 }
79
80 ft = bt_ctf_field_type_integer_create(32);
81 if (!ft) {
82 BT_LOGE_STR("Cannot create an integer field type object.");
83 goto error;
84 }
85
86 ret = bt_ctf_field_type_structure_add_field(root_ft, ft, "magic");
87 if (ret) {
88 BT_LOGE("Cannot add `magic` field type to structure field type: "
89 "ret=%d", ret);
90 goto error;
91 }
92
93 BT_PUT(ft);
94 ft = bt_ctf_field_type_integer_create(8);
95 if (!ft) {
96 BT_LOGE_STR("Cannot create an integer field type object.");
97 goto error;
98 }
99
100 goto end;
101
102 error:
103 BT_PUT(root_ft);
104
105 end:
106 bt_put(ft);
107 return root_ft;
108 }
109
110 static
111 struct bt_ctf_field_type *create_packet_context_ft(void)
112 {
113 struct bt_ctf_field_type *root_ft = NULL;
114 struct bt_ctf_field_type *ft = NULL;
115 int ret;
116
117 root_ft = bt_ctf_field_type_structure_create();
118 if (!root_ft) {
119 BT_LOGE_STR("Cannot create an empty structure field type object.");
120 goto error;
121 }
122
123 ft = bt_ctf_field_type_integer_create(64);
124 if (!ft) {
125 BT_LOGE_STR("Cannot create an integer field type object.");
126 goto error;
127 }
128
129 ret = bt_ctf_field_type_structure_add_field(root_ft,
130 ft, "content_size");
131 if (ret) {
132 BT_LOGE("Cannot add `content_size` field type to structure field type: "
133 "ret=%d", ret);
134 goto error;
135 }
136
137 BT_PUT(ft);
138 ft = bt_ctf_field_type_integer_create(64);
139 if (!ft) {
140 BT_LOGE_STR("Cannot create an integer field type object.");
141 goto error;
142 }
143
144 ret = bt_ctf_field_type_structure_add_field(root_ft,
145 ft, "packet_size");
146 if (ret) {
147 BT_LOGE("Cannot add `packet_size` field type to structure field type: "
148 "ret=%d", ret);
149 goto error;
150 }
151
152 goto end;
153
154 error:
155 BT_PUT(root_ft);
156
157 end:
158 bt_put(ft);
159 return root_ft;
160 }
161
162 static
163 struct bt_ctf_field_type *create_event_header_ft(
164 struct bt_ctf_clock_class *clock_class)
165 {
166 struct bt_ctf_field_type *root_ft = NULL;
167 struct bt_ctf_field_type *ft = NULL;
168 int ret;
169
170 root_ft = bt_ctf_field_type_structure_create();
171 if (!root_ft) {
172 BT_LOGE_STR("Cannot create an empty structure field type object.");
173 goto error;
174 }
175
176 ft = bt_ctf_field_type_integer_create(64);
177 if (!ft) {
178 BT_LOGE_STR("Cannot create an integer field type object.");
179 goto error;
180 }
181
182 ret = bt_ctf_field_type_integer_set_mapped_clock_class(ft, clock_class);
183 if (ret) {
184 BT_LOGE("Cannot map integer field type to clock class: "
185 "ret=%d", ret);
186 goto error;
187 }
188
189 ret = bt_ctf_field_type_structure_add_field(root_ft,
190 ft, "timestamp");
191 if (ret) {
192 BT_LOGE("Cannot add `timestamp` field type to structure field type: "
193 "ret=%d", ret);
194 goto error;
195 }
196
197 goto end;
198
199 error:
200 BT_PUT(root_ft);
201
202 end:
203 bt_put(ft);
204 return root_ft;
205 }
206
207 static
208 struct bt_ctf_field_type *create_event_payload_ft(void)
209 {
210 struct bt_ctf_field_type *root_ft = NULL;
211 struct bt_ctf_field_type *ft = NULL;
212 int ret;
213
214 root_ft = bt_ctf_field_type_structure_create();
215 if (!root_ft) {
216 BT_LOGE_STR("Cannot create an empty structure field type object.");
217 goto error;
218 }
219
220 ft = bt_ctf_field_type_string_create();
221 if (!ft) {
222 BT_LOGE_STR("Cannot create a string field type object.");
223 goto error;
224 }
225
226 ret = bt_ctf_field_type_structure_add_field(root_ft,
227 ft, "str");
228 if (ret) {
229 BT_LOGE("Cannot add `str` field type to structure field type: "
230 "ret=%d", ret);
231 goto error;
232 }
233
234 goto end;
235
236 error:
237 BT_PUT(root_ft);
238
239 end:
240 bt_put(ft);
241 return root_ft;
242 }
243
244 static
245 struct bt_ctf_clock_class *create_clock_class(void)
246 {
247 return bt_ctf_clock_class_create("the_clock", 1000000000);
248 }
249
250 static
251 int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
252 {
253 struct bt_ctf_field_type *ft = NULL;
254 const char *trace_name = NULL;
255 gchar *basename = NULL;
256 int ret = 0;
257
258 dmesg_comp->trace = bt_ctf_trace_create();
259 if (!dmesg_comp->trace) {
260 BT_LOGE_STR("Cannot create an empty trace object.");
261 goto error;
262 }
263
264 ft = create_packet_header_ft();
265 if (!ft) {
266 BT_LOGE_STR("Cannot create packet header field type.");
267 goto error;
268 }
269
270 ret = bt_ctf_trace_set_packet_header_type(dmesg_comp->trace, ft);
271 if (ret) {
272 BT_LOGE_STR("Cannot set trace's packet header field type.");
273 goto error;
274 }
275
276 if (dmesg_comp->params.read_from_stdin) {
277 trace_name = "STDIN";
278 } else {
279 basename = g_path_get_basename(dmesg_comp->params.path->str);
280 assert(basename);
281
282 if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
283 strcmp(basename, ".") != 0) {
284 trace_name = basename;
285 }
286 }
287
288 if (trace_name) {
289 ret = bt_ctf_trace_set_name(dmesg_comp->trace, trace_name);
290 if (ret) {
291 BT_LOGE("Cannot set trace's name: name=\"%s\"", trace_name);
292 goto error;
293 }
294 }
295
296 dmesg_comp->stream_class = bt_ctf_stream_class_create_empty(NULL);
297 if (!dmesg_comp->stream_class) {
298 BT_LOGE_STR("Cannot create an empty stream class object.");
299 goto error;
300 }
301
302 bt_put(ft);
303 ft = create_packet_context_ft();
304 if (!ft) {
305 BT_LOGE_STR("Cannot create packet context field type.");
306 goto error;
307 }
308
309 ret = bt_ctf_stream_class_set_packet_context_type(
310 dmesg_comp->stream_class, ft);
311 if (ret) {
312 BT_LOGE_STR("Cannot set stream class's packet context field type.");
313 goto error;
314 }
315
316 dmesg_comp->cc_prio_map = bt_clock_class_priority_map_create();
317 if (!dmesg_comp->cc_prio_map) {
318 BT_LOGE_STR("Cannot create empty clock class priority map.");
319 goto error;
320 }
321
322 if (has_ts) {
323 dmesg_comp->clock_class = create_clock_class();
324 if (!dmesg_comp->clock_class) {
325 BT_LOGE_STR("Cannot create clock class.");
326 goto error;
327 }
328
329 ret = bt_ctf_trace_add_clock_class(dmesg_comp->trace,
330 dmesg_comp->clock_class);
331 if (ret) {
332 BT_LOGE_STR("Cannot add clock class to trace.");
333 goto error;
334 }
335
336 ret = bt_clock_class_priority_map_add_clock_class(
337 dmesg_comp->cc_prio_map, dmesg_comp->clock_class, 0);
338 if (ret) {
339 BT_LOGE_STR("Cannot add clock class to clock class priority map.");
340 goto error;
341 }
342
343 bt_put(ft);
344 ft = create_event_header_ft(dmesg_comp->clock_class);
345 if (!ft) {
346 BT_LOGE_STR("Cannot create event header field type.");
347 goto error;
348 }
349
350 ret = bt_ctf_stream_class_set_event_header_type(
351 dmesg_comp->stream_class, ft);
352 if (ret) {
353 BT_LOGE_STR("Cannot set stream class's event header field type.");
354 goto error;
355 }
356 }
357
358 dmesg_comp->event_class = bt_ctf_event_class_create("string");
359 if (!dmesg_comp->event_class) {
360 BT_LOGE_STR("Cannot create an empty event class object.");
361 goto error;
362 }
363
364 bt_put(ft);
365 ft = create_event_payload_ft();
366 if (!ft) {
367 BT_LOGE_STR("Cannot create event payload field type.");
368 goto error;
369 }
370
371 ret = bt_ctf_event_class_set_payload_type(dmesg_comp->event_class, ft);
372 if (ret) {
373 BT_LOGE_STR("Cannot set event class's event payload field type.");
374 goto error;
375 }
376
377 ret = bt_ctf_stream_class_add_event_class(dmesg_comp->stream_class,
378 dmesg_comp->event_class);
379 if (ret) {
380 BT_LOGE("Cannot add event class to stream class: ret=%d", ret);
381 goto error;
382 }
383
384 ret = bt_ctf_trace_add_stream_class(dmesg_comp->trace,
385 dmesg_comp->stream_class);
386 if (ret) {
387 BT_LOGE("Cannot add event class to stream class: ret=%d", ret);
388 goto error;
389 }
390
391 goto end;
392
393 error:
394 ret = -1;
395
396 end:
397 bt_put(ft);
398
399 if (basename) {
400 g_free(basename);
401 }
402
403 return ret;
404 }
405
406 static
407 int handle_params(struct dmesg_component *dmesg_comp, struct bt_value *params)
408 {
409 struct bt_value *read_from_stdin = NULL;
410 struct bt_value *path = NULL;
411 const char *path_str;
412 int ret = 0;
413
414 read_from_stdin = bt_value_map_get(params, "read-from-stdin");
415 if (read_from_stdin) {
416 if (!bt_value_is_bool(read_from_stdin)) {
417 BT_LOGE("Expecting a boolean value for the `read-from-stdin` parameter: "
418 "type=%s",
419 bt_value_type_string(
420 bt_value_get_type(read_from_stdin)));
421 goto error;
422 }
423
424 ret = bt_value_bool_get(read_from_stdin,
425 &dmesg_comp->params.read_from_stdin);
426 assert(ret == 0);
427 }
428
429 path = bt_value_map_get(params, "path");
430 if (path) {
431 if (dmesg_comp->params.read_from_stdin) {
432 BT_LOGE_STR("Cannot specify both `read-from-stdin` and `path` parameters.");
433 goto error;
434 }
435
436 if (!bt_value_is_string(path)) {
437 BT_LOGE("Expecting a string value for the `path` parameter: "
438 "type=%s",
439 bt_value_type_string(
440 bt_value_get_type(path)));
441 goto error;
442 }
443
444 ret = bt_value_string_get(path, &path_str);
445 assert(ret == 0);
446 g_string_assign(dmesg_comp->params.path, path_str);
447 } else {
448 if (!dmesg_comp->params.read_from_stdin) {
449 BT_LOGE_STR("Expecting `path` parameter or true `read-from-stdin` parameter.");
450 goto error;
451 }
452 }
453
454 goto end;
455
456 error:
457 ret = -1;
458
459 end:
460 bt_put(read_from_stdin);
461 bt_put(path);
462 return ret;
463 }
464
465 static
466 struct bt_ctf_field *create_packet_header_field(struct bt_ctf_field_type *ft)
467 {
468 struct bt_ctf_field *ph = NULL;
469 struct bt_ctf_field *magic = NULL;
470 int ret;
471
472 ph = bt_ctf_field_create(ft);
473 if (!ph) {
474 BT_LOGE_STR("Cannot create field object.");
475 goto error;
476 }
477
478 magic = bt_ctf_field_structure_get_field_by_name(ph, "magic");
479 if (!magic) {
480 BT_LOGE_STR("Cannot get `magic` field from structure field.");
481 goto error;
482 }
483
484 ret = bt_ctf_field_unsigned_integer_set_value(magic, 0xc1fc1fc1);
485 if (ret) {
486 BT_LOGE_STR("Cannot set integer field's value.");
487 goto error;
488 }
489
490 goto end;
491
492 error:
493 BT_PUT(ph);
494
495 end:
496 bt_put(magic);
497 return ph;
498 }
499
500 static
501 struct bt_ctf_field *create_packet_context_field(struct bt_ctf_field_type *ft)
502 {
503 struct bt_ctf_field *pc = NULL;
504 struct bt_ctf_field *field = NULL;
505 int ret;
506
507 pc = bt_ctf_field_create(ft);
508 if (!pc) {
509 BT_LOGE_STR("Cannot create field object.");
510 goto error;
511 }
512
513 field = bt_ctf_field_structure_get_field_by_name(pc, "content_size");
514 if (!field) {
515 BT_LOGE_STR("Cannot get `content_size` field from structure field.");
516 goto error;
517 }
518
519 ret = bt_ctf_field_unsigned_integer_set_value(field, 0);
520 if (ret) {
521 BT_LOGE_STR("Cannot set integer field's value.");
522 goto error;
523 }
524
525 bt_put(field);
526 field = bt_ctf_field_structure_get_field_by_name(pc, "packet_size");
527 if (!field) {
528 BT_LOGE_STR("Cannot get `packet_size` field from structure field.");
529 goto error;
530 }
531
532 ret = bt_ctf_field_unsigned_integer_set_value(field, 0);
533 if (ret) {
534 BT_LOGE_STR("Cannot set integer field's value.");
535 goto error;
536 }
537
538 goto end;
539
540 error:
541 BT_PUT(pc);
542
543 end:
544 bt_put(field);
545 return pc;
546 }
547
548 static
549 int create_packet_and_stream(struct dmesg_component *dmesg_comp)
550 {
551 int ret = 0;
552 struct bt_ctf_field_type *ft = NULL;
553 struct bt_ctf_field *field = NULL;
554
555 dmesg_comp->stream = bt_ctf_stream_create(dmesg_comp->stream_class,
556 NULL);
557 if (!dmesg_comp->stream) {
558 BT_LOGE_STR("Cannot create stream object.");
559 goto error;
560 }
561
562 dmesg_comp->packet = bt_ctf_packet_create(dmesg_comp->stream);
563 if (!dmesg_comp->packet) {
564 BT_LOGE_STR("Cannot create packet object.");
565 goto error;
566 }
567
568 ft = bt_ctf_trace_get_packet_header_type(dmesg_comp->trace);
569 assert(ft);
570 field = create_packet_header_field(ft);
571 if (!field) {
572 BT_LOGE_STR("Cannot create packet header field.");
573 goto error;
574 }
575
576 ret = bt_ctf_packet_set_header(dmesg_comp->packet, field);
577 if (ret) {
578 BT_LOGE_STR("Cannot set packet's header field.");
579 goto error;
580 }
581
582 bt_put(ft);
583 bt_put(field);
584 ft = bt_ctf_stream_class_get_packet_context_type(
585 dmesg_comp->stream_class);
586 assert(ft);
587 field = create_packet_context_field(ft);
588 if (!field) {
589 BT_LOGE_STR("Cannot create packet context field.");
590 goto error;
591 }
592
593 ret = bt_ctf_packet_set_context(dmesg_comp->packet, field);
594 if (ret) {
595 BT_LOGE_STR("Cannot set packet's context field.");
596 goto error;
597 }
598
599 ret = bt_ctf_trace_set_is_static(dmesg_comp->trace);
600 if (ret) {
601 BT_LOGE_STR("Cannot make trace static.");
602 goto error;
603 }
604
605 goto end;
606
607 error:
608 ret = -1;
609
610 end:
611 bt_put(field);
612 bt_put(ft);
613 return ret;
614 }
615
616 static
617 int try_create_meta_stream_packet(struct dmesg_component *dmesg_comp,
618 bool has_ts)
619 {
620 int ret = 0;
621
622 if (dmesg_comp->trace) {
623 /* Already created */
624 goto end;
625 }
626
627 ret = create_meta(dmesg_comp, has_ts);
628 if (ret) {
629 BT_LOGE("Cannot create metadata objects: dmesg-comp-addr=%p",
630 dmesg_comp);
631 goto error;
632 }
633
634 ret = create_packet_and_stream(dmesg_comp);
635 if (ret) {
636 BT_LOGE("Cannot create packet and stream objects: "
637 "dmesg-comp-addr=%p", dmesg_comp);
638 goto error;
639 }
640
641 goto end;
642
643 error:
644 ret = -1;
645
646 end:
647 return ret;
648 }
649
650 static
651 void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
652 {
653 if (!dmesg_comp) {
654 return;
655 }
656
657 if (dmesg_comp->params.path) {
658 g_string_free(dmesg_comp->params.path, TRUE);
659 }
660
661 bt_put(dmesg_comp->packet);
662 bt_put(dmesg_comp->trace);
663 bt_put(dmesg_comp->stream_class);
664 bt_put(dmesg_comp->event_class);
665 bt_put(dmesg_comp->stream);
666 bt_put(dmesg_comp->clock_class);
667 bt_put(dmesg_comp->cc_prio_map);
668 g_free(dmesg_comp);
669 }
670
671 static
672 enum bt_component_status create_port(struct bt_private_component *priv_comp)
673 {
674 return bt_private_component_source_add_output_private_port(priv_comp,
675 "out", NULL, NULL);
676 }
677
678 BT_HIDDEN
679 enum bt_component_status dmesg_init(struct bt_private_component *priv_comp,
680 struct bt_value *params, void *init_method_data)
681 {
682 int ret = 0;
683 struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
684 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
685
686 if (!dmesg_comp) {
687 BT_LOGE_STR("Failed to allocate one dmesg component structure.");
688 goto error;
689 }
690
691 dmesg_comp->params.path = g_string_new(NULL);
692 if (!dmesg_comp->params.path) {
693 BT_LOGE_STR("Failed to allocate a GString.");
694 goto error;
695 }
696
697 ret = handle_params(dmesg_comp, params);
698 if (ret) {
699 BT_LOGE("Invalid parameters: comp-addr=%p", priv_comp);
700 goto error;
701 }
702
703 if (!dmesg_comp->params.read_from_stdin &&
704 !g_file_test(dmesg_comp->params.path->str,
705 G_FILE_TEST_IS_REGULAR)) {
706 BT_LOGE("Input path is not a regular file: "
707 "comp-addr=%p, path=\"%s\"", priv_comp,
708 dmesg_comp->params.path->str);
709 goto error;
710 }
711
712 status = create_port(priv_comp);
713 if (status != BT_COMPONENT_STATUS_OK) {
714 goto error;
715 }
716
717 (void) bt_private_component_set_user_data(priv_comp, dmesg_comp);
718 goto end;
719
720 error:
721 destroy_dmesg_component(dmesg_comp);
722 (void) bt_private_component_set_user_data(priv_comp, NULL);
723
724 if (status >= 0) {
725 status = BT_COMPONENT_STATUS_ERROR;
726 }
727
728 end:
729 return status;
730 }
731
732 BT_HIDDEN
733 void dmesg_finalize(struct bt_private_component *priv_comp)
734 {
735 void *data = bt_private_component_get_user_data(priv_comp);
736
737 destroy_dmesg_component(data);
738 }
739
740 static
741 int create_event_header_from_line(
742 struct dmesg_component *dmesg_comp,
743 const char *line, const char **new_start,
744 struct bt_ctf_field **user_field,
745 struct bt_ctf_clock_value **user_clock_value)
746 {
747 bool has_timestamp = false;
748 unsigned long sec, usec, msec;
749 unsigned int year, mon, mday, hour, min;
750 uint64_t ts = 0;
751 struct bt_ctf_clock_value *clock_value = NULL;
752 struct bt_ctf_field_type *ft = NULL;
753 struct bt_ctf_field *eh_field = NULL;
754 struct bt_ctf_field *ts_field = NULL;
755 int ret = 0;
756
757 assert(user_clock_value);
758 assert(user_field);
759 *new_start = line;
760
761 /* Extract time from input line */
762 if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
763 ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
764
765 /*
766 * The clock class we use has a 1 GHz frequency: convert
767 * from µs to ns.
768 */
769 ts *= NSEC_PER_USEC;
770 has_timestamp = true;
771 } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
772 &year, &mon, &mday, &hour, &min,
773 &sec, &msec) == 7) {
774 time_t ep_sec;
775 struct tm ti;
776
777 memset(&ti, 0, sizeof(ti));
778 ti.tm_year = year - 1900; /* From 1900 */
779 ti.tm_mon = mon - 1; /* 0 to 11 */
780 ti.tm_mday = mday;
781 ti.tm_hour = hour;
782 ti.tm_min = min;
783 ti.tm_sec = sec;
784
785 ep_sec = bt_timegm(&ti);
786 if (ep_sec != (time_t) -1) {
787 ts = (uint64_t) ep_sec * NSEC_PER_SEC
788 + (uint64_t) msec * NSEC_PER_MSEC;
789 }
790
791 has_timestamp = true;
792 }
793
794 if (has_timestamp) {
795 /* Set new start for the message portion of the line */
796 *new_start = strchr(line, ']');
797 assert(*new_start);
798 (*new_start)++;
799
800 if ((*new_start)[0] == ' ') {
801 (*new_start)++;
802 }
803 }
804
805 /*
806 * At this point, we know if the stream class's event header
807 * field type should have a timestamp or not, so we can lazily
808 * create the metadata, stream, and packet objects.
809 */
810 ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
811 if (ret) {
812 /* try_create_meta_stream_packet() logs errors */
813 goto error;
814 }
815
816 if (dmesg_comp->clock_class) {
817 clock_value = bt_ctf_clock_value_create(dmesg_comp->clock_class,
818 ts);
819 if (!clock_value) {
820 BT_LOGE_STR("Cannot create clock value object.");
821 goto error;
822 }
823
824 ft = bt_ctf_stream_class_get_event_header_type(
825 dmesg_comp->stream_class);
826 assert(ft);
827 eh_field = bt_ctf_field_create(ft);
828 if (!eh_field) {
829 BT_LOGE_STR("Cannot create event header field object.");
830 goto error;
831 }
832
833 ts_field = bt_ctf_field_structure_get_field_by_name(eh_field,
834 "timestamp");
835 if (!ts_field) {
836 BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
837 goto error;
838 }
839
840 ret = bt_ctf_field_unsigned_integer_set_value(ts_field, ts);
841 if (ret) {
842 BT_LOGE_STR("Cannot set integer field's value.");
843 goto error;
844 }
845
846 *user_clock_value = clock_value;
847 clock_value = NULL;
848 *user_field = eh_field;
849 eh_field = NULL;
850 }
851
852 goto end;
853
854 error:
855 ret = -1;
856
857 end:
858 bt_put(ft);
859 bt_put(ts_field);
860 bt_put(clock_value);
861 bt_put(eh_field);
862 return ret;
863 }
864
865 static
866 int create_event_payload_from_line(
867 struct dmesg_component *dmesg_comp,
868 const char *line, struct bt_ctf_field **user_field)
869 {
870 struct bt_ctf_field_type *ft = NULL;
871 struct bt_ctf_field *ep_field = NULL;
872 struct bt_ctf_field *str_field = NULL;
873 size_t len;
874 int ret;
875
876 assert(user_field);
877 ft = bt_ctf_event_class_get_payload_type(dmesg_comp->event_class);
878 assert(ft);
879 ep_field = bt_ctf_field_create(ft);
880 if (!ep_field) {
881 BT_LOGE_STR("Cannot create event payload field object.");
882 goto error;
883 }
884
885 str_field = bt_ctf_field_structure_get_field_by_name(ep_field, "str");
886 if (!str_field) {
887 BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
888 goto error;
889 }
890
891 len = strlen(line);
892 if (line[len - 1] == '\n') {
893 /* Do not include the newline character in the payload */
894 len--;
895 }
896
897 ret = bt_ctf_field_string_append_len(str_field, line, len);
898 if (ret) {
899 BT_LOGE("Cannot append value to string field object: "
900 "len=%zu", len);
901 goto error;
902 }
903
904 *user_field = ep_field;
905 ep_field = NULL;
906 goto end;
907
908 error:
909 ret = -1;
910
911 end:
912 bt_put(ft);
913 bt_put(ep_field);
914 bt_put(str_field);
915 return ret;
916 }
917
918 static
919 struct bt_notification *create_notif_from_line(
920 struct dmesg_component *dmesg_comp, const char *line)
921 {
922 struct bt_ctf_field *eh_field = NULL;
923 struct bt_ctf_field *ep_field = NULL;
924 struct bt_ctf_clock_value *clock_value = NULL;
925 struct bt_ctf_event *event = NULL;
926 struct bt_notification *notif = NULL;
927 const char *new_start;
928 int ret;
929
930 ret = create_event_header_from_line(dmesg_comp, line, &new_start,
931 &eh_field, &clock_value);
932 if (ret) {
933 BT_LOGE("Cannot create event header field from line: "
934 "ret=%d", ret);
935 goto error;
936 }
937
938 ret = create_event_payload_from_line(dmesg_comp, new_start,
939 &ep_field);
940 if (ret) {
941 BT_LOGE("Cannot create event payload field from line: "
942 "ret=%d", ret);
943 goto error;
944 }
945
946 assert(ep_field);
947 event = bt_ctf_event_create(dmesg_comp->event_class);
948 if (!event) {
949 BT_LOGE_STR("Cannot create event object.");
950 goto error;
951 }
952
953 ret = bt_ctf_event_set_packet(event, dmesg_comp->packet);
954 if (ret) {
955 BT_LOGE_STR("Cannot set event's packet.");
956 goto error;
957 }
958
959 if (eh_field) {
960 ret = bt_ctf_event_set_header(event, eh_field);
961 if (ret) {
962 BT_LOGE_STR("Cannot set event's header field.");
963 goto error;
964 }
965 }
966
967 ret = bt_ctf_event_set_event_payload(event, ep_field);
968 if (ret) {
969 BT_LOGE_STR("Cannot set event's payload field.");
970 goto error;
971 }
972
973 if (clock_value) {
974 ret = bt_ctf_event_set_clock_value(event, clock_value);
975 if (ret) {
976 BT_LOGE_STR("Cannot set event's clock value.");
977 goto error;
978 }
979 }
980
981 notif = bt_notification_event_create(event, dmesg_comp->cc_prio_map);
982 if (!notif) {
983 BT_LOGE_STR("Cannot create event notification.");
984 goto error;
985 }
986
987 goto end;
988
989 error:
990 BT_PUT(notif);
991
992 end:
993 bt_put(eh_field);
994 bt_put(ep_field);
995 bt_put(clock_value);
996 bt_put(event);
997 return notif;
998 }
999
1000 static
1001 void destroy_dmesg_notif_iter(struct dmesg_notif_iter *dmesg_notif_iter)
1002 {
1003 if (!dmesg_notif_iter) {
1004 return;
1005 }
1006
1007 if (dmesg_notif_iter->fp && dmesg_notif_iter->fp != stdin) {
1008 if (fclose(dmesg_notif_iter->fp)) {
1009 BT_LOGE_ERRNO("Cannot close input file", ".");
1010 }
1011 }
1012
1013 free(dmesg_notif_iter->linebuf);
1014 g_free(dmesg_notif_iter);
1015 }
1016
1017 BT_HIDDEN
1018 enum bt_notification_iterator_status dmesg_notif_iter_init(
1019 struct bt_private_notification_iterator *priv_notif_iter,
1020 struct bt_private_port *priv_port)
1021 {
1022 struct bt_private_component *priv_comp = NULL;
1023 struct dmesg_component *dmesg_comp;
1024 struct dmesg_notif_iter *dmesg_notif_iter =
1025 g_new0(struct dmesg_notif_iter, 1);
1026 enum bt_notification_iterator_status status =
1027 BT_NOTIFICATION_ITERATOR_STATUS_OK;
1028
1029 if (!dmesg_notif_iter) {
1030 BT_LOGE_STR("Failed to allocate on dmesg notification iterator structure.");
1031 goto error;
1032 }
1033
1034 priv_comp = bt_private_notification_iterator_get_private_component(
1035 priv_notif_iter);
1036 assert(priv_comp);
1037 dmesg_comp = bt_private_component_get_user_data(priv_comp);
1038 assert(dmesg_comp);
1039 dmesg_notif_iter->dmesg_comp = dmesg_comp;
1040
1041 if (dmesg_comp->params.read_from_stdin) {
1042 dmesg_notif_iter->fp = stdin;
1043 } else {
1044 dmesg_notif_iter->fp = fopen(dmesg_comp->params.path->str, "r");
1045 if (!dmesg_notif_iter->fp) {
1046 BT_LOGE_ERRNO("Cannot open input file in read mode", ": path=\"%s\"",
1047 dmesg_comp->params.path->str);
1048 goto error;
1049 }
1050 }
1051
1052 (void) bt_private_notification_iterator_set_user_data(priv_notif_iter,
1053 dmesg_notif_iter);
1054 goto end;
1055
1056 error:
1057 destroy_dmesg_notif_iter(dmesg_notif_iter);
1058 (void) bt_private_notification_iterator_set_user_data(priv_notif_iter,
1059 NULL);
1060 if (status >= 0) {
1061 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1062 }
1063
1064 end:
1065 bt_put(priv_comp);
1066 return status;
1067 }
1068
1069 BT_HIDDEN
1070 void dmesg_notif_iter_finalize(
1071 struct bt_private_notification_iterator *priv_notif_iter)
1072 {
1073 destroy_dmesg_notif_iter(bt_private_notification_iterator_get_user_data(
1074 priv_notif_iter));
1075 }
1076
1077 BT_HIDDEN
1078 struct bt_notification_iterator_next_return dmesg_notif_iter_next(
1079 struct bt_private_notification_iterator *priv_notif_iter)
1080 {
1081 ssize_t len;
1082 struct dmesg_notif_iter *dmesg_notif_iter =
1083 bt_private_notification_iterator_get_user_data(
1084 priv_notif_iter);
1085 struct dmesg_component *dmesg_comp;
1086 struct bt_notification_iterator_next_return next_ret = {
1087 .status = BT_NOTIFICATION_ITERATOR_STATUS_OK,
1088 .notification = NULL
1089 };
1090
1091 assert(dmesg_notif_iter);
1092 dmesg_comp = dmesg_notif_iter->dmesg_comp;
1093 assert(dmesg_comp);
1094
1095 while (true) {
1096 const char *ch;
1097 bool only_spaces = true;
1098
1099 len = bt_getline(&dmesg_notif_iter->linebuf,
1100 &dmesg_notif_iter->linebuf_len, dmesg_notif_iter->fp);
1101 if (len < 0) {
1102 if (errno == EINVAL) {
1103 next_ret.status =
1104 BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
1105 } else if (errno == ENOMEM) {
1106 next_ret.status =
1107 BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
1108 } else {
1109 next_ret.status =
1110 BT_NOTIFICATION_ITERATOR_STATUS_END;
1111 }
1112
1113 goto end;
1114 }
1115
1116 assert(dmesg_notif_iter->linebuf);
1117
1118 /* Ignore empty lines, once trimmed */
1119 for (ch = dmesg_notif_iter->linebuf; *ch != '\0'; ch++) {
1120 if (!isspace(*ch)) {
1121 only_spaces = false;
1122 break;
1123 }
1124 }
1125
1126 if (!only_spaces) {
1127 break;
1128 }
1129 }
1130
1131 next_ret.notification = create_notif_from_line(dmesg_comp,
1132 dmesg_notif_iter->linebuf);
1133 if (!next_ret.notification) {
1134 BT_LOGE("Cannot create event notification from line: "
1135 "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
1136 dmesg_notif_iter->linebuf);
1137 }
1138
1139 end:
1140 return next_ret;
1141 }
This page took 0.065134 seconds and 5 git commands to generate.