.gitignore: add some missing files
[babeltrace.git] / src / plugins / text / dmesg / dmesg.c
CommitLineData
d8866baa 1/*
0235b0db
MJ
2 * SPDX-License-Identifier: MIT
3 *
d8866baa 4 * Copyright 2010-2011 EfficiOS Inc. and Linux Foundation
d94d92ac 5 * Copyright 2017 Philippe Proulx <pproulx@efficios.com>
d8866baa
PP
6 */
7
9c8a5044 8#define BT_COMP_LOG_SELF_COMP (dmesg_comp->self_comp)
caedbbee 9#define BT_LOG_OUTPUT_LEVEL (dmesg_comp->log_level)
350ad6c1 10#define BT_LOG_TAG "PLUGIN/SRC.TEXT.DMESG"
d9c39b0a 11#include "logging/comp-logging.h"
33ec5dfa 12
7c7301d5
SM
13#include "dmesg.h"
14
d8866baa 15#include <stdbool.h>
33ec5dfa
PP
16#include <string.h>
17#include <ctype.h>
d8866baa 18#include <stdio.h>
578e048b 19#include "common/common.h"
caedbbee 20#include "common/assert.h"
3fadfbc0 21#include <babeltrace2/babeltrace.h>
578e048b
MJ
22#include "compat/utc.h"
23#include "compat/stdio.h"
d8866baa 24#include <glib.h>
430a5ccb 25#include "plugins/common/param-validation/param-validation.h"
d8866baa 26
33ec5dfa
PP
27#define NSEC_PER_USEC 1000UL
28#define NSEC_PER_MSEC 1000000UL
29#define NSEC_PER_SEC 1000000000ULL
30#define USEC_PER_SEC 1000000UL
31
d8866baa
PP
32struct dmesg_component;
33
d6e69534 34struct dmesg_msg_iter {
d8866baa 35 struct dmesg_component *dmesg_comp;
f30762e5
SM
36
37 /* Weak */
38 bt_self_message_iterator *self_msg_iter;
39
33ec5dfa
PP
40 char *linebuf;
41 size_t linebuf_len;
d8866baa 42 FILE *fp;
d6e69534 43 bt_message *tmp_event_msg;
a6d85d2f 44 uint64_t last_clock_value;
312c056a
PP
45
46 enum {
47 STATE_EMIT_STREAM_BEGINNING,
312c056a 48 STATE_EMIT_EVENT,
312c056a
PP
49 STATE_EMIT_STREAM_END,
50 STATE_DONE,
51 } state;
d8866baa
PP
52};
53
54struct dmesg_component {
caedbbee
PP
55 bt_logging_level log_level;
56
d8866baa
PP
57 struct {
58 GString *path;
33ec5dfa 59 bt_bool read_from_stdin;
707b323a 60 bt_bool no_timestamp;
d8866baa
PP
61 } params;
62
9c8a5044
PP
63 bt_self_component_source *self_comp_src;
64 bt_self_component *self_comp;
b19ff26f
PP
65 bt_trace_class *trace_class;
66 bt_stream_class *stream_class;
67 bt_event_class *event_class;
68 bt_trace *trace;
69 bt_stream *stream;
b19ff26f 70 bt_clock_class *clock_class;
d8866baa
PP
71};
72
497c1e20
SM
73bt_component_class_get_supported_mip_versions_method_status
74dmesg_supported_mip_versions(
75 bt_self_component_class_source *self_component_class __attribute__((unused)),
76 const bt_value *params __attribute__((unused)),
77 void *initialize_method_data __attribute__((unused)),
78 bt_logging_level logging_level __attribute__((unused)),
79 bt_integer_range_set_unsigned *supported_versions)
80{
81 return (int) bt_integer_range_set_unsigned_add_range(supported_versions, 0, 1);
82}
83
33ec5dfa 84static
caedbbee
PP
85bt_field_class *create_event_payload_fc(struct dmesg_component *dmesg_comp,
86 bt_trace_class *trace_class)
33ec5dfa 87{
b19ff26f
PP
88 bt_field_class *root_fc = NULL;
89 bt_field_class *fc = NULL;
5c72947e 90 bt_field_class_structure_append_member_status append_member_status;
33ec5dfa 91
1122a43a 92 root_fc = bt_field_class_structure_create(trace_class);
5cd6d0e5 93 if (!root_fc) {
5c72947e
SM
94 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
95 "Cannot create an empty structure field class object.");
33ec5dfa
PP
96 goto error;
97 }
98
1122a43a 99 fc = bt_field_class_string_create(trace_class);
5cd6d0e5 100 if (!fc) {
5c72947e
SM
101 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
102 "Cannot create a string field class object.");
33ec5dfa
PP
103 goto error;
104 }
105
5c72947e 106 append_member_status = bt_field_class_structure_append_member(root_fc,
e5be10ef 107 "str", fc);
5c72947e
SM
108 if (append_member_status != BT_FIELD_CLASS_STRUCTURE_APPEND_MEMBER_STATUS_OK) {
109 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
110 "Cannot add `str` member to structure field class: ret=%d",
111 append_member_status);
33ec5dfa
PP
112 goto error;
113 }
114
115 goto end;
116
117error:
c5b9b441 118 BT_FIELD_CLASS_PUT_REF_AND_RESET(root_fc);
33ec5dfa
PP
119
120end:
c5b9b441 121 bt_field_class_put_ref(fc);
5cd6d0e5 122 return root_fc;
33ec5dfa
PP
123}
124
33ec5dfa
PP
125static
126int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
127{
b19ff26f 128 bt_field_class *fc = NULL;
d8866baa
PP
129 int ret = 0;
130
9c8a5044 131 dmesg_comp->trace_class = bt_trace_class_create(dmesg_comp->self_comp);
862ca4ed 132 if (!dmesg_comp->trace_class) {
5c72947e
SM
133 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
134 "Cannot create an empty trace class object.");
33ec5dfa
PP
135 goto error;
136 }
137
40f4ba76 138 dmesg_comp->stream_class = bt_stream_class_create(
862ca4ed 139 dmesg_comp->trace_class);
33ec5dfa 140 if (!dmesg_comp->stream_class) {
5c72947e
SM
141 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
142 "Cannot create a stream class object.");
33ec5dfa
PP
143 goto error;
144 }
145
33ec5dfa 146 if (has_ts) {
0f2d58c9 147 dmesg_comp->clock_class = bt_clock_class_create(
9c8a5044 148 dmesg_comp->self_comp);
33ec5dfa 149 if (!dmesg_comp->clock_class) {
5c72947e
SM
150 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
151 "Cannot create clock class.");
33ec5dfa
PP
152 goto error;
153 }
154
21029722 155 /*
5552377a
PP
156 * The `dmesg` timestamp's origin is not the Unix epoch,
157 * it's the boot time.
21029722 158 */
5552377a 159 bt_clock_class_set_origin_is_unix_epoch(dmesg_comp->clock_class,
21029722
PP
160 BT_FALSE);
161
40f4ba76
PP
162 ret = bt_stream_class_set_default_clock_class(
163 dmesg_comp->stream_class, dmesg_comp->clock_class);
33ec5dfa 164 if (ret) {
5c72947e
SM
165 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
166 "Cannot set stream class's default clock class.");
33ec5dfa
PP
167 goto error;
168 }
169 }
170
40f4ba76 171 dmesg_comp->event_class = bt_event_class_create(
44c440bc 172 dmesg_comp->stream_class);
33ec5dfa 173 if (!dmesg_comp->event_class) {
5c72947e
SM
174 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
175 "Cannot create an event class object.");
44c440bc
PP
176 goto error;
177 }
178
40f4ba76 179 ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
44c440bc 180 if (ret) {
5c72947e
SM
181 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
182 "Cannot set event class's name.");
33ec5dfa
PP
183 goto error;
184 }
185
caedbbee 186 fc = create_event_payload_fc(dmesg_comp, dmesg_comp->trace_class);
5cd6d0e5 187 if (!fc) {
5c72947e
SM
188 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
189 "Cannot create event payload field class.");
d8866baa
PP
190 goto error;
191 }
192
40f4ba76 193 ret = bt_event_class_set_payload_field_class(dmesg_comp->event_class, fc);
33ec5dfa 194 if (ret) {
5c72947e
SM
195 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
196 "Cannot set event class's event payload field class.");
33ec5dfa
PP
197 goto error;
198 }
199
33ec5dfa
PP
200 goto end;
201
202error:
203 ret = -1;
204
205end:
c5b9b441 206 bt_field_class_put_ref(fc);
33ec5dfa
PP
207 return ret;
208}
209
d9120ccb 210static
430a5ccb
SM
211struct bt_param_validation_map_value_entry_descr dmesg_params[] = {
212 { "no-extract-timestamp", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_BOOL } },
213 { "path", BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_OPTIONAL, { .type = BT_VALUE_TYPE_STRING } },
214 BT_PARAM_VALIDATION_MAP_VALUE_ENTRY_END
215};
216
33ec5dfa 217static
430a5ccb
SM
218bt_component_class_initialize_method_status handle_params(
219 struct dmesg_component *dmesg_comp,
b19ff26f 220 const bt_value *params)
33ec5dfa 221{
b19ff26f
PP
222 const bt_value *no_timestamp = NULL;
223 const bt_value *path = NULL;
430a5ccb
SM
224 bt_component_class_initialize_method_status status;
225 enum bt_param_validation_status validation_status;
226 gchar *validate_error = NULL;
227
228 validation_status = bt_param_validation_validate(params,
229 dmesg_params, &validate_error);
230 if (validation_status == BT_PARAM_VALIDATION_STATUS_MEMORY_ERROR) {
231 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
232 goto end;
233 } else if (validation_status == BT_PARAM_VALIDATION_STATUS_VALIDATION_ERROR) {
234 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
235 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
236 "%s", validate_error);
237 goto end;
238 }
33ec5dfa 239
05e21286 240 no_timestamp = bt_value_map_borrow_entry_value_const(params,
07208d85 241 "no-extract-timestamp");
707b323a 242 if (no_timestamp) {
601b0d3c
PP
243 dmesg_comp->params.no_timestamp =
244 bt_value_bool_get(no_timestamp);
707b323a
PP
245 }
246
05e21286 247 path = bt_value_map_borrow_entry_value_const(params, "path");
d8866baa 248 if (path) {
430a5ccb 249 const char *path_str = bt_value_string_get(path);
d8866baa 250
d8866baa
PP
251 g_string_assign(dmesg_comp->params.path, path_str);
252 } else {
4da23e31 253 dmesg_comp->params.read_from_stdin = true;
d8866baa
PP
254 }
255
430a5ccb 256 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
d8866baa 257end:
430a5ccb
SM
258 g_free(validate_error);
259
260 return status;
d8866baa
PP
261}
262
33ec5dfa 263static
26fc5aed 264int create_stream_and_trace(struct dmesg_component *dmesg_comp)
33ec5dfa
PP
265{
266 int ret = 0;
e54986cf 267 const char *trace_name = NULL;
862ca4ed
PP
268 gchar *basename = NULL;
269
270 dmesg_comp->trace = bt_trace_create(dmesg_comp->trace_class);
271 if (!dmesg_comp->trace) {
5c72947e
SM
272 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
273 "Cannot create trace object.");
862ca4ed
PP
274 goto error;
275 }
33ec5dfa 276
862ca4ed
PP
277 if (dmesg_comp->params.read_from_stdin) {
278 trace_name = "STDIN";
279 } else {
280 basename = g_path_get_basename(dmesg_comp->params.path->str);
281 BT_ASSERT(basename);
282
283 if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
284 strcmp(basename, ".") != 0) {
285 trace_name = basename;
286 }
287 }
288
289 if (trace_name) {
290 ret = bt_trace_set_name(dmesg_comp->trace, trace_name);
291 if (ret) {
5c72947e
SM
292 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
293 "Cannot set trace's name: name=\"%s\"",
862ca4ed
PP
294 trace_name);
295 goto error;
296 }
297 }
298
299 dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class,
300 dmesg_comp->trace);
33ec5dfa 301 if (!dmesg_comp->stream) {
5c72947e
SM
302 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
303 "Cannot create stream object.");
33ec5dfa
PP
304 goto error;
305 }
306
33ec5dfa
PP
307 goto end;
308
309error:
310 ret = -1;
311
312end:
19bbdc9b 313 g_free(basename);
862ca4ed 314
33ec5dfa
PP
315 return ret;
316}
317
318static
26fc5aed 319int try_create_meta_stream(struct dmesg_component *dmesg_comp, bool has_ts)
33ec5dfa
PP
320{
321 int ret = 0;
322
323 if (dmesg_comp->trace) {
324 /* Already created */
325 goto end;
326 }
327
328 ret = create_meta(dmesg_comp, has_ts);
329 if (ret) {
5c72947e
SM
330 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
331 "Cannot create metadata objects: dmesg-comp-addr=%p",
33ec5dfa
PP
332 dmesg_comp);
333 goto error;
334 }
335
26fc5aed 336 ret = create_stream_and_trace(dmesg_comp);
33ec5dfa 337 if (ret) {
5c72947e
SM
338 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
339 "Cannot create stream object: dmesg-comp-addr=%p",
340 dmesg_comp);
33ec5dfa
PP
341 goto error;
342 }
343
344 goto end;
345
346error:
347 ret = -1;
348
349end:
350 return ret;
351}
d8866baa
PP
352
353static
354void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
355{
356 if (!dmesg_comp) {
357 return;
358 }
359
360 if (dmesg_comp->params.path) {
361 g_string_free(dmesg_comp->params.path, TRUE);
362 }
363
c5b9b441
PP
364 bt_trace_put_ref(dmesg_comp->trace);
365 bt_stream_class_put_ref(dmesg_comp->stream_class);
366 bt_event_class_put_ref(dmesg_comp->event_class);
367 bt_stream_put_ref(dmesg_comp->stream);
368 bt_clock_class_put_ref(dmesg_comp->clock_class);
8b5bd70c 369 bt_trace_class_put_ref(dmesg_comp->trace_class);
d8866baa
PP
370 g_free(dmesg_comp);
371}
372
21a9f056 373bt_component_class_initialize_method_status dmesg_init(
9c8a5044 374 bt_self_component_source *self_comp_src,
ecd7492f
MJ
375 bt_self_component_source_configuration *config __attribute__((unused)),
376 const bt_value *params,
377 void *init_method_data __attribute__((unused)))
d8866baa 378{
d8866baa 379 struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
430a5ccb 380 bt_component_class_initialize_method_status status;
9c8a5044
PP
381 bt_self_component *self_comp =
382 bt_self_component_source_as_self_component(self_comp_src);
383 const bt_component *comp = bt_self_component_as_component(self_comp);
caedbbee 384 bt_logging_level log_level = bt_component_get_logging_level(comp);
903b999e 385 bt_self_component_add_port_status add_port_status;
d8866baa
PP
386
387 if (!dmesg_comp) {
5c72947e
SM
388 /*
389 * Don't use BT_COMP_LOGE_APPEND_CAUSE, as `dmesg_comp` is not
390 * initialized.
391 */
9c8a5044 392 BT_COMP_LOG_CUR_LVL(BT_LOG_ERROR, log_level, self_comp,
caedbbee 393 "Failed to allocate one dmesg component structure.");
5c72947e
SM
394 BT_CURRENT_THREAD_ERROR_APPEND_CAUSE_FROM_COMPONENT(self_comp,
395 "Failed to allocate one dmesg component structure.");
396 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
d8866baa
PP
397 goto error;
398 }
399
caedbbee 400 dmesg_comp->log_level = log_level;
41693723 401 dmesg_comp->self_comp = self_comp;
9c8a5044 402 dmesg_comp->self_comp_src = self_comp_src;
d8866baa
PP
403 dmesg_comp->params.path = g_string_new(NULL);
404 if (!dmesg_comp->params.path) {
5c72947e
SM
405 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to allocate a GString.");
406 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
d8866baa
PP
407 goto error;
408 }
409
430a5ccb
SM
410 status = handle_params(dmesg_comp, params);
411 if (status != BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK) {
5c72947e
SM
412 BT_COMP_LOGE_APPEND_CAUSE(self_comp,
413 "Invalid parameters: comp-addr=%p", self_comp);
430a5ccb 414 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
d8866baa
PP
415 goto error;
416 }
417
33ec5dfa
PP
418 if (!dmesg_comp->params.read_from_stdin &&
419 !g_file_test(dmesg_comp->params.path->str,
420 G_FILE_TEST_IS_REGULAR)) {
5c72947e
SM
421 BT_COMP_LOGE_APPEND_CAUSE(self_comp,
422 "Input path is not a regular file: "
d94d92ac 423 "comp-addr=%p, path=\"%s\"", self_comp,
33ec5dfa 424 dmesg_comp->params.path->str);
430a5ccb 425 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
33ec5dfa
PP
426 goto error;
427 }
d8866baa 428
903b999e
SM
429 add_port_status = bt_self_component_source_add_output_port(
430 self_comp_src, "out", NULL, NULL);
431 if (add_port_status != BT_SELF_COMPONENT_ADD_PORT_STATUS_OK) {
5c72947e 432 BT_COMP_LOGE_APPEND_CAUSE(self_comp, "Failed to add output port.");
903b999e 433 status = (int) add_port_status;
33ec5dfa
PP
434 goto error;
435 }
d8866baa 436
9c8a5044
PP
437 bt_self_component_set_data(self_comp, dmesg_comp);
438 BT_COMP_LOGI_STR("Component initialized.");
430a5ccb
SM
439
440 status = BT_COMPONENT_CLASS_INITIALIZE_METHOD_STATUS_OK;
d8866baa
PP
441 goto end;
442
443error:
444 destroy_dmesg_component(dmesg_comp);
9c8a5044 445 bt_self_component_set_data(self_comp, NULL);
33ec5dfa 446
d8866baa
PP
447end:
448 return status;
449}
450
b19ff26f 451void dmesg_finalize(bt_self_component_source *self_comp)
d8866baa 452{
d94d92ac 453 destroy_dmesg_component(bt_self_component_get_data(
707b7d35 454 bt_self_component_source_as_self_component(self_comp)));
33ec5dfa
PP
455}
456
457static
d6e69534
PP
458bt_message *create_init_event_msg_from_line(
459 struct dmesg_msg_iter *msg_iter,
312c056a 460 const char *line, const char **new_start)
33ec5dfa 461{
b19ff26f 462 bt_event *event;
d6e69534 463 bt_message *msg = NULL;
33ec5dfa
PP
464 bool has_timestamp = false;
465 unsigned long sec, usec, msec;
466 unsigned int year, mon, mday, hour, min;
467 uint64_t ts = 0;
33ec5dfa 468 int ret = 0;
d6e69534 469 struct dmesg_component *dmesg_comp = msg_iter->dmesg_comp;
33ec5dfa 470
33ec5dfa
PP
471 *new_start = line;
472
707b323a
PP
473 if (dmesg_comp->params.no_timestamp) {
474 goto skip_ts;
475 }
476
33ec5dfa
PP
477 /* Extract time from input line */
478 if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
479 ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
480
481 /*
482 * The clock class we use has a 1 GHz frequency: convert
483 * from µs to ns.
484 */
485 ts *= NSEC_PER_USEC;
486 has_timestamp = true;
487 } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
488 &year, &mon, &mday, &hour, &min,
489 &sec, &msec) == 7) {
490 time_t ep_sec;
491 struct tm ti;
492
493 memset(&ti, 0, sizeof(ti));
494 ti.tm_year = year - 1900; /* From 1900 */
495 ti.tm_mon = mon - 1; /* 0 to 11 */
496 ti.tm_mday = mday;
497 ti.tm_hour = hour;
498 ti.tm_min = min;
499 ti.tm_sec = sec;
500
501 ep_sec = bt_timegm(&ti);
502 if (ep_sec != (time_t) -1) {
503 ts = (uint64_t) ep_sec * NSEC_PER_SEC
504 + (uint64_t) msec * NSEC_PER_MSEC;
505 }
506
507 has_timestamp = true;
508 }
509
510 if (has_timestamp) {
511 /* Set new start for the message portion of the line */
512 *new_start = strchr(line, ']');
98b15851 513 BT_ASSERT_DBG(*new_start);
33ec5dfa
PP
514 (*new_start)++;
515
516 if ((*new_start)[0] == ' ') {
517 (*new_start)++;
518 }
519 }
520
707b323a 521skip_ts:
33ec5dfa
PP
522 /*
523 * At this point, we know if the stream class's event header
5cd6d0e5 524 * field class should have a timestamp or not, so we can lazily
26fc5aed 525 * create the metadata and stream objects.
33ec5dfa 526 */
26fc5aed 527 ret = try_create_meta_stream(dmesg_comp, has_timestamp);
33ec5dfa 528 if (ret) {
26fc5aed 529 /* try_create_meta_stream() logs errors */
33ec5dfa
PP
530 goto error;
531 }
532
2c091c04
PP
533 if (dmesg_comp->clock_class) {
534 msg = bt_message_event_create_with_default_clock_snapshot(
f30762e5 535 msg_iter->self_msg_iter,
26fc5aed 536 dmesg_comp->event_class, dmesg_comp->stream, ts);
2c091c04
PP
537 msg_iter->last_clock_value = ts;
538 } else {
f30762e5 539 msg = bt_message_event_create(msg_iter->self_msg_iter,
26fc5aed 540 dmesg_comp->event_class, dmesg_comp->stream);
2c091c04
PP
541 }
542
d6e69534 543 if (!msg) {
5c72947e
SM
544 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
545 "Cannot create event message.");
312c056a
PP
546 goto error;
547 }
33ec5dfa 548
d6e69534 549 event = bt_message_event_borrow_event(msg);
98b15851 550 BT_ASSERT_DBG(event);
33ec5dfa
PP
551 goto end;
552
553error:
d6e69534 554 BT_MESSAGE_PUT_REF_AND_RESET(msg);
33ec5dfa
PP
555
556end:
d6e69534 557 return msg;
33ec5dfa
PP
558}
559
560static
caedbbee
PP
561int fill_event_payload_from_line(struct dmesg_component *dmesg_comp,
562 const char *line, bt_event *event)
33ec5dfa 563{
b19ff26f
PP
564 bt_field *ep_field = NULL;
565 bt_field *str_field = NULL;
33ec5dfa
PP
566 size_t len;
567 int ret;
568
40f4ba76 569 ep_field = bt_event_borrow_payload_field(event);
98b15851 570 BT_ASSERT_DBG(ep_field);
40f4ba76 571 str_field = bt_field_structure_borrow_member_field_by_index(
e5be10ef 572 ep_field, 0);
33ec5dfa 573 if (!str_field) {
5c72947e
SM
574 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
575 "Cannot borrow `timestamp` field from event payload structure field.");
33ec5dfa
PP
576 goto error;
577 }
578
579 len = strlen(line);
580 if (line[len - 1] == '\n') {
581 /* Do not include the newline character in the payload */
582 len--;
583 }
584
d24d5663 585 bt_field_string_clear(str_field);
40f4ba76 586 ret = bt_field_string_append_with_length(str_field, line, len);
33ec5dfa 587 if (ret) {
5c72947e
SM
588 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
589 "Cannot append value to string field object: len=%zu", len);
33ec5dfa
PP
590 goto error;
591 }
592
33ec5dfa
PP
593 goto end;
594
595error:
596 ret = -1;
597
598end:
33ec5dfa
PP
599 return ret;
600}
601
602static
d6e69534
PP
603bt_message *create_msg_from_line(
604 struct dmesg_msg_iter *dmesg_msg_iter, const char *line)
33ec5dfa 605{
caedbbee 606 struct dmesg_component *dmesg_comp = dmesg_msg_iter->dmesg_comp;
b19ff26f 607 bt_event *event = NULL;
d6e69534 608 bt_message *msg = NULL;
33ec5dfa
PP
609 const char *new_start;
610 int ret;
611
d6e69534 612 msg = create_init_event_msg_from_line(dmesg_msg_iter,
f0010051 613 line, &new_start);
d6e69534 614 if (!msg) {
5c72947e
SM
615 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
616 "Cannot create and initialize event message from line.");
33ec5dfa
PP
617 goto error;
618 }
619
d6e69534 620 event = bt_message_event_borrow_event(msg);
98b15851 621 BT_ASSERT_DBG(event);
caedbbee 622 ret = fill_event_payload_from_line(dmesg_comp, new_start, event);
33ec5dfa 623 if (ret) {
5c72947e
SM
624 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
625 "Cannot fill event payload field from line: ret=%d", ret);
33ec5dfa
PP
626 goto error;
627 }
628
33ec5dfa
PP
629 goto end;
630
631error:
d6e69534 632 BT_MESSAGE_PUT_REF_AND_RESET(msg);
33ec5dfa
PP
633
634end:
d6e69534 635 return msg;
33ec5dfa
PP
636}
637
638static
d6e69534 639void destroy_dmesg_msg_iter(struct dmesg_msg_iter *dmesg_msg_iter)
33ec5dfa 640{
53265bca 641 struct dmesg_component *dmesg_comp;
caedbbee 642
d6e69534 643 if (!dmesg_msg_iter) {
33ec5dfa
PP
644 return;
645 }
646
53265bca
PP
647 dmesg_comp = dmesg_msg_iter->dmesg_comp;
648
d6e69534
PP
649 if (dmesg_msg_iter->fp && dmesg_msg_iter->fp != stdin) {
650 if (fclose(dmesg_msg_iter->fp)) {
5c72947e
SM
651 BT_COMP_LOGE_APPEND_CAUSE_ERRNO(dmesg_comp->self_comp,
652 "Cannot close input file", ".");
33ec5dfa
PP
653 }
654 }
d8866baa 655
d6e69534
PP
656 bt_message_put_ref(dmesg_msg_iter->tmp_event_msg);
657 free(dmesg_msg_iter->linebuf);
658 g_free(dmesg_msg_iter);
d8866baa
PP
659}
660
2d6bab5c
PP
661
662
a3f0c7db 663bt_message_iterator_class_initialize_method_status dmesg_msg_iter_init(
d6e69534 664 bt_self_message_iterator *self_msg_iter,
ecd7492f
MJ
665 bt_self_message_iterator_configuration *config __attribute__((unused)),
666 bt_self_component_port_output *self_port __attribute__((unused)))
d8866baa 667{
f615b250
PP
668 bt_self_component *self_comp =
669 bt_self_message_iterator_borrow_component(self_msg_iter);
a3f0c7db 670 struct dmesg_component *dmesg_comp = bt_self_component_get_data(self_comp);
d6e69534
PP
671 struct dmesg_msg_iter *dmesg_msg_iter =
672 g_new0(struct dmesg_msg_iter, 1);
5c72947e 673 bt_message_iterator_class_initialize_method_status status;
33ec5dfa 674
d6e69534 675 if (!dmesg_msg_iter) {
5c72947e
SM
676 BT_COMP_LOGE_APPEND_CAUSE(self_comp,
677 "Failed to allocate on dmesg message iterator structure.");
678 status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_MEMORY_ERROR;
33ec5dfa
PP
679 goto error;
680 }
681
f6ccaed9 682 BT_ASSERT(dmesg_comp);
d6e69534 683 dmesg_msg_iter->dmesg_comp = dmesg_comp;
f30762e5 684 dmesg_msg_iter->self_msg_iter = self_msg_iter;
d8866baa 685
33ec5dfa 686 if (dmesg_comp->params.read_from_stdin) {
d6e69534 687 dmesg_msg_iter->fp = stdin;
33ec5dfa 688 } else {
d6e69534
PP
689 dmesg_msg_iter->fp = fopen(dmesg_comp->params.path->str, "r");
690 if (!dmesg_msg_iter->fp) {
5c72947e
SM
691 BT_COMP_LOGE_APPEND_CAUSE_ERRNO(self_comp,
692 "Cannot open input file in read mode", ": path=\"%s\"",
33ec5dfa 693 dmesg_comp->params.path->str);
5c72947e 694 status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_ERROR;
33ec5dfa
PP
695 goto error;
696 }
697 }
698
d6e69534
PP
699 bt_self_message_iterator_set_data(self_msg_iter,
700 dmesg_msg_iter);
5c72947e
SM
701
702 status = BT_MESSAGE_ITERATOR_CLASS_INITIALIZE_METHOD_STATUS_OK;
33ec5dfa
PP
703 goto end;
704
705error:
d6e69534
PP
706 destroy_dmesg_msg_iter(dmesg_msg_iter);
707 bt_self_message_iterator_set_data(self_msg_iter, NULL);
33ec5dfa
PP
708
709end:
33ec5dfa 710 return status;
d8866baa
PP
711}
712
d6e69534
PP
713void dmesg_msg_iter_finalize(
714 bt_self_message_iterator *priv_msg_iter)
d8866baa 715{
d6e69534
PP
716 destroy_dmesg_msg_iter(bt_self_message_iterator_get_data(
717 priv_msg_iter));
d8866baa
PP
718}
719
d4393e08 720static
a3f0c7db 721bt_message_iterator_class_next_method_status dmesg_msg_iter_next_one(
d6e69534
PP
722 struct dmesg_msg_iter *dmesg_msg_iter,
723 bt_message **msg)
d8866baa 724{
33ec5dfa 725 ssize_t len;
33ec5dfa 726 struct dmesg_component *dmesg_comp;
c16fb81a 727 bt_message_iterator_class_next_method_status status;
d8866baa 728
98b15851 729 BT_ASSERT_DBG(dmesg_msg_iter);
d6e69534 730 dmesg_comp = dmesg_msg_iter->dmesg_comp;
98b15851 731 BT_ASSERT_DBG(dmesg_comp);
33ec5dfa 732
d6e69534 733 if (dmesg_msg_iter->state == STATE_DONE) {
a3f0c7db 734 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
312c056a
PP
735 goto end;
736 }
737
d6e69534 738 if (dmesg_msg_iter->tmp_event_msg ||
d6e69534 739 dmesg_msg_iter->state == STATE_EMIT_STREAM_END) {
312c056a
PP
740 goto handle_state;
741 }
742
33ec5dfa
PP
743 while (true) {
744 const char *ch;
745 bool only_spaces = true;
746
d6e69534
PP
747 len = bt_getline(&dmesg_msg_iter->linebuf,
748 &dmesg_msg_iter->linebuf_len, dmesg_msg_iter->fp);
33ec5dfa
PP
749 if (len < 0) {
750 if (errno == EINVAL) {
a3f0c7db 751 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
c16fb81a 752 goto end;
33ec5dfa 753 } else if (errno == ENOMEM) {
a3f0c7db 754 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_MEMORY_ERROR;
c16fb81a 755 goto end;
33ec5dfa 756 } else {
d6e69534 757 if (dmesg_msg_iter->state == STATE_EMIT_STREAM_BEGINNING) {
312c056a 758 /* Stream did not even begin */
a3f0c7db 759 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_END;
312c056a
PP
760 goto end;
761 } else {
26fc5aed 762 /* End stream now */
d6e69534 763 dmesg_msg_iter->state =
26fc5aed 764 STATE_EMIT_STREAM_END;
312c056a
PP
765 goto handle_state;
766 }
33ec5dfa 767 }
33ec5dfa
PP
768 }
769
98b15851 770 BT_ASSERT_DBG(dmesg_msg_iter->linebuf);
33ec5dfa
PP
771
772 /* Ignore empty lines, once trimmed */
d6e69534 773 for (ch = dmesg_msg_iter->linebuf; *ch != '\0'; ch++) {
994cd345 774 if (!isspace((unsigned char) *ch)) {
33ec5dfa
PP
775 only_spaces = false;
776 break;
777 }
778 }
779
780 if (!only_spaces) {
781 break;
782 }
783 }
784
d6e69534
PP
785 dmesg_msg_iter->tmp_event_msg = create_msg_from_line(
786 dmesg_msg_iter, dmesg_msg_iter->linebuf);
787 if (!dmesg_msg_iter->tmp_event_msg) {
5c72947e
SM
788 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
789 "Cannot create event message from line: "
33ec5dfa 790 "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
d6e69534 791 dmesg_msg_iter->linebuf);
c16fb81a 792 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
312c056a
PP
793 goto end;
794 }
795
796handle_state:
98b15851 797 BT_ASSERT_DBG(dmesg_comp->trace);
312c056a 798
d6e69534 799 switch (dmesg_msg_iter->state) {
312c056a 800 case STATE_EMIT_STREAM_BEGINNING:
98b15851 801 BT_ASSERT_DBG(dmesg_msg_iter->tmp_event_msg);
d6e69534 802 *msg = bt_message_stream_beginning_create(
f30762e5 803 dmesg_msg_iter->self_msg_iter, dmesg_comp->stream);
d6e69534 804 dmesg_msg_iter->state = STATE_EMIT_EVENT;
312c056a
PP
805 break;
806 case STATE_EMIT_EVENT:
98b15851 807 BT_ASSERT_DBG(dmesg_msg_iter->tmp_event_msg);
d6e69534
PP
808 *msg = dmesg_msg_iter->tmp_event_msg;
809 dmesg_msg_iter->tmp_event_msg = NULL;
312c056a 810 break;
312c056a 811 case STATE_EMIT_STREAM_END:
d6e69534 812 *msg = bt_message_stream_end_create(
f30762e5 813 dmesg_msg_iter->self_msg_iter, dmesg_comp->stream);
d6e69534 814 dmesg_msg_iter->state = STATE_DONE;
312c056a
PP
815 break;
816 default:
817 break;
818 }
819
d6e69534 820 if (!*msg) {
5c72947e
SM
821 BT_COMP_LOGE_APPEND_CAUSE(dmesg_comp->self_comp,
822 "Cannot create message: dmesg-comp-addr=%p",
312c056a 823 dmesg_comp);
a3f0c7db 824 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_ERROR;
c16fb81a 825 goto end;
33ec5dfa
PP
826 }
827
c16fb81a 828 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
5c72947e 829
33ec5dfa 830end:
d4393e08
PP
831 return status;
832}
833
a3f0c7db 834bt_message_iterator_class_next_method_status dmesg_msg_iter_next(
d6e69534
PP
835 bt_self_message_iterator *self_msg_iter,
836 bt_message_array_const msgs, uint64_t capacity,
d4393e08
PP
837 uint64_t *count)
838{
d6e69534
PP
839 struct dmesg_msg_iter *dmesg_msg_iter =
840 bt_self_message_iterator_get_data(
841 self_msg_iter);
a3f0c7db
SM
842 bt_message_iterator_class_next_method_status status =
843 BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
d4393e08
PP
844 uint64_t i = 0;
845
d94d92ac 846 while (i < capacity &&
a3f0c7db 847 status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
d6e69534 848 bt_message *priv_msg = NULL;
e5be10ef 849
d6e69534
PP
850 status = dmesg_msg_iter_next_one(dmesg_msg_iter,
851 &priv_msg);
852 msgs[i] = priv_msg;
a3f0c7db 853 if (status == BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK) {
d4393e08
PP
854 i++;
855 }
856 }
857
858 if (i > 0) {
859 /*
d6e69534 860 * Even if dmesg_msg_iter_next_one() returned
d4393e08 861 * something else than
d6e69534
PP
862 * BT_SELF_MESSAGE_ITERATOR_STATUS_OK, we
863 * accumulated message objects in the output
864 * message array, so we need to return
865 * BT_SELF_MESSAGE_ITERATOR_STATUS_OK so that they
e7401568 866 * are transferred to downstream. This other status
d6e69534 867 * occurs again the next time muxer_msg_iter_do_next()
d94d92ac 868 * is called, possibly without any accumulated
d6e69534 869 * message, in which case we'll return it.
d4393e08
PP
870 */
871 *count = i;
a3f0c7db 872 status = BT_MESSAGE_ITERATOR_CLASS_NEXT_METHOD_STATUS_OK;
d4393e08
PP
873 }
874
875 return status;
d8866baa 876}
2d6bab5c 877
a3f0c7db 878bt_message_iterator_class_can_seek_beginning_method_status
f2fb1b32
SM
879dmesg_msg_iter_can_seek_beginning(
880 bt_self_message_iterator *self_msg_iter, bt_bool *can_seek)
2d6bab5c
PP
881{
882 struct dmesg_msg_iter *dmesg_msg_iter =
883 bt_self_message_iterator_get_data(self_msg_iter);
884
885 /* Can't seek the beginning of the standard input stream */
f2fb1b32
SM
886 *can_seek = !dmesg_msg_iter->dmesg_comp->params.read_from_stdin;
887
a3f0c7db 888 return BT_MESSAGE_ITERATOR_CLASS_CAN_SEEK_BEGINNING_METHOD_STATUS_OK;
2d6bab5c
PP
889}
890
a3f0c7db 891bt_message_iterator_class_seek_beginning_method_status
d24d5663 892dmesg_msg_iter_seek_beginning(
2d6bab5c
PP
893 bt_self_message_iterator *self_msg_iter)
894{
895 struct dmesg_msg_iter *dmesg_msg_iter =
896 bt_self_message_iterator_get_data(self_msg_iter);
897
898 BT_ASSERT(!dmesg_msg_iter->dmesg_comp->params.read_from_stdin);
899
900 BT_MESSAGE_PUT_REF_AND_RESET(dmesg_msg_iter->tmp_event_msg);
901 dmesg_msg_iter->last_clock_value = 0;
902 dmesg_msg_iter->state = STATE_EMIT_STREAM_BEGINNING;
a3f0c7db 903 return BT_MESSAGE_ITERATOR_CLASS_SEEK_BEGINNING_METHOD_STATUS_OK;
2d6bab5c 904}
This page took 0.154467 seconds and 5 git commands to generate.