Values API: split into private and public APIs
[babeltrace.git] / plugins / text / dmesg / dmesg.c
CommitLineData
d8866baa
PP
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
33ec5dfa
PP
24#define BT_LOG_TAG "PLUGIN-TEXT-DMESG-SRC"
25#include "logging.h"
26
d8866baa 27#include <stdbool.h>
33ec5dfa
PP
28#include <string.h>
29#include <ctype.h>
d8866baa 30#include <stdio.h>
f6ccaed9 31#include <babeltrace/assert-internal.h>
da91b29a 32#include <babeltrace/common-internal.h>
33ec5dfa
PP
33#include <babeltrace/babeltrace.h>
34#include <babeltrace/values-internal.h>
35#include <babeltrace/compat/utc-internal.h>
36#include <babeltrace/compat/stdio-internal.h>
d8866baa
PP
37#include <glib.h>
38
33ec5dfa
PP
39#define NSEC_PER_USEC 1000UL
40#define NSEC_PER_MSEC 1000000UL
41#define NSEC_PER_SEC 1000000000ULL
42#define USEC_PER_SEC 1000000UL
43
d8866baa
PP
44struct dmesg_component;
45
46struct dmesg_notif_iter {
47 struct dmesg_component *dmesg_comp;
f0010051 48 struct bt_private_connection_private_notification_iterator *pc_notif_iter; /* Weak */
33ec5dfa
PP
49 char *linebuf;
50 size_t linebuf_len;
d8866baa 51 FILE *fp;
312c056a
PP
52 struct bt_notification *tmp_event_notif;
53
54 enum {
55 STATE_EMIT_STREAM_BEGINNING,
56 STATE_EMIT_PACKET_BEGINNING,
57 STATE_EMIT_EVENT,
58 STATE_EMIT_PACKET_END,
59 STATE_EMIT_STREAM_END,
60 STATE_DONE,
61 } state;
d8866baa
PP
62};
63
64struct dmesg_component {
65 struct {
66 GString *path;
33ec5dfa 67 bt_bool read_from_stdin;
707b323a 68 bt_bool no_timestamp;
d8866baa
PP
69 } params;
70
50842bdc
PP
71 struct bt_trace *trace;
72 struct bt_stream_class *stream_class;
73 struct bt_event_class *event_class;
74 struct bt_stream *stream;
75 struct bt_packet *packet;
76 struct bt_clock_class *clock_class;
d8866baa
PP
77 struct bt_clock_class_priority_map *cc_prio_map;
78};
79
33ec5dfa 80static
5cd6d0e5 81struct bt_field_class *create_event_payload_fc(void)
33ec5dfa 82{
5cd6d0e5
PP
83 struct bt_field_class *root_fc = NULL;
84 struct bt_field_class *fc = NULL;
33ec5dfa
PP
85 int ret;
86
5cd6d0e5
PP
87 root_fc = bt_field_class_structure_create();
88 if (!root_fc) {
89 BT_LOGE_STR("Cannot create an empty structure field class object.");
33ec5dfa
PP
90 goto error;
91 }
92
5cd6d0e5
PP
93 fc = bt_field_class_string_create();
94 if (!fc) {
95 BT_LOGE_STR("Cannot create a string field class object.");
33ec5dfa
PP
96 goto error;
97 }
98
5cd6d0e5 99 ret = bt_field_class_structure_append_member(root_fc, "str", fc);
33ec5dfa 100 if (ret) {
5cd6d0e5 101 BT_LOGE("Cannot add `str` member to structure field class: "
33ec5dfa
PP
102 "ret=%d", ret);
103 goto error;
104 }
105
106 goto end;
107
108error:
65300d60 109 BT_OBJECT_PUT_REF_AND_RESET(root_fc);
33ec5dfa
PP
110
111end:
65300d60 112 bt_object_put_ref(fc);
5cd6d0e5 113 return root_fc;
33ec5dfa
PP
114}
115
33ec5dfa
PP
116static
117int create_meta(struct dmesg_component *dmesg_comp, bool has_ts)
118{
5cd6d0e5 119 struct bt_field_class *fc = NULL;
33ec5dfa
PP
120 const char *trace_name = NULL;
121 gchar *basename = NULL;
d8866baa
PP
122 int ret = 0;
123
50842bdc 124 dmesg_comp->trace = bt_trace_create();
33ec5dfa
PP
125 if (!dmesg_comp->trace) {
126 BT_LOGE_STR("Cannot create an empty trace object.");
127 goto error;
128 }
129
33ec5dfa
PP
130 if (dmesg_comp->params.read_from_stdin) {
131 trace_name = "STDIN";
132 } else {
133 basename = g_path_get_basename(dmesg_comp->params.path->str);
f6ccaed9 134 BT_ASSERT(basename);
33ec5dfa
PP
135
136 if (strcmp(basename, G_DIR_SEPARATOR_S) != 0 &&
137 strcmp(basename, ".") != 0) {
138 trace_name = basename;
139 }
140 }
141
142 if (trace_name) {
50842bdc 143 ret = bt_trace_set_name(dmesg_comp->trace, trace_name);
33ec5dfa
PP
144 if (ret) {
145 BT_LOGE("Cannot set trace's name: name=\"%s\"", trace_name);
146 goto error;
147 }
148 }
149
44c440bc 150 dmesg_comp->stream_class = bt_stream_class_create(dmesg_comp->trace);
33ec5dfa 151 if (!dmesg_comp->stream_class) {
44c440bc 152 BT_LOGE_STR("Cannot create a stream class object.");
33ec5dfa
PP
153 goto error;
154 }
155
33ec5dfa 156 if (has_ts) {
44c440bc 157 dmesg_comp->clock_class = bt_clock_class_create();
33ec5dfa
PP
158 if (!dmesg_comp->clock_class) {
159 BT_LOGE_STR("Cannot create clock class.");
160 goto error;
161 }
162
44c440bc
PP
163 ret = bt_stream_class_set_default_clock_class(
164 dmesg_comp->stream_class, dmesg_comp->clock_class);
33ec5dfa 165 if (ret) {
44c440bc 166 BT_LOGE_STR("Cannot set stream class's default clock class.");
33ec5dfa
PP
167 goto error;
168 }
169 }
170
44c440bc
PP
171 dmesg_comp->event_class = bt_event_class_create(
172 dmesg_comp->stream_class);
33ec5dfa 173 if (!dmesg_comp->event_class) {
44c440bc
PP
174 BT_LOGE_STR("Cannot create an event class object.");
175 goto error;
176 }
177
178 ret = bt_event_class_set_name(dmesg_comp->event_class, "string");
179 if (ret) {
180 BT_LOGE_STR("Cannot set event class's name.");
33ec5dfa
PP
181 goto error;
182 }
183
5cd6d0e5
PP
184 fc = create_event_payload_fc();
185 if (!fc) {
186 BT_LOGE_STR("Cannot create event payload field class.");
d8866baa
PP
187 goto error;
188 }
189
5cd6d0e5 190 ret = bt_event_class_set_payload_field_class(dmesg_comp->event_class, fc);
33ec5dfa 191 if (ret) {
5cd6d0e5 192 BT_LOGE_STR("Cannot set event class's event payload field class.");
33ec5dfa
PP
193 goto error;
194 }
195
33ec5dfa
PP
196 goto end;
197
198error:
199 ret = -1;
200
201end:
65300d60 202 bt_object_put_ref(fc);
33ec5dfa
PP
203
204 if (basename) {
205 g_free(basename);
206 }
207
208 return ret;
209}
210
211static
212int handle_params(struct dmesg_component *dmesg_comp, struct bt_value *params)
213{
707b323a 214 struct bt_value *no_timestamp = NULL;
33ec5dfa
PP
215 struct bt_value *path = NULL;
216 const char *path_str;
217 int ret = 0;
218
07208d85
PP
219 no_timestamp = bt_value_map_borrow_entry_value(params,
220 "no-extract-timestamp");
707b323a
PP
221 if (no_timestamp) {
222 if (!bt_value_is_bool(no_timestamp)) {
223 BT_LOGE("Expecting a boolean value for the `no-extract-timestamp` parameter: "
224 "type=%s",
da91b29a 225 bt_common_value_type_string(
707b323a
PP
226 bt_value_get_type(no_timestamp)));
227 goto error;
228 }
229
230 ret = bt_value_bool_get(no_timestamp,
231 &dmesg_comp->params.no_timestamp);
f6ccaed9 232 BT_ASSERT(ret == 0);
707b323a
PP
233 }
234
07208d85 235 path = bt_value_map_borrow_entry_value(params, "path");
d8866baa
PP
236 if (path) {
237 if (dmesg_comp->params.read_from_stdin) {
33ec5dfa 238 BT_LOGE_STR("Cannot specify both `read-from-stdin` and `path` parameters.");
d8866baa
PP
239 goto error;
240 }
241
242 if (!bt_value_is_string(path)) {
33ec5dfa
PP
243 BT_LOGE("Expecting a string value for the `path` parameter: "
244 "type=%s",
da91b29a 245 bt_common_value_type_string(
33ec5dfa 246 bt_value_get_type(path)));
d8866baa
PP
247 goto error;
248 }
249
33ec5dfa 250 ret = bt_value_string_get(path, &path_str);
f6ccaed9 251 BT_ASSERT(ret == 0);
d8866baa
PP
252 g_string_assign(dmesg_comp->params.path, path_str);
253 } else {
4da23e31 254 dmesg_comp->params.read_from_stdin = true;
d8866baa
PP
255 }
256
257 goto end;
258
259error:
260 ret = -1;
261
262end:
d8866baa
PP
263 return ret;
264}
265
33ec5dfa
PP
266static
267int create_packet_and_stream(struct dmesg_component *dmesg_comp)
268{
269 int ret = 0;
33ec5dfa 270
44c440bc 271 dmesg_comp->stream = bt_stream_create(dmesg_comp->stream_class);
33ec5dfa
PP
272 if (!dmesg_comp->stream) {
273 BT_LOGE_STR("Cannot create stream object.");
274 goto error;
275 }
276
44c440bc 277 dmesg_comp->packet = bt_packet_create(dmesg_comp->stream);
33ec5dfa
PP
278 if (!dmesg_comp->packet) {
279 BT_LOGE_STR("Cannot create packet object.");
280 goto error;
281 }
282
44c440bc 283 ret = bt_trace_make_static(dmesg_comp->trace);
33ec5dfa
PP
284 if (ret) {
285 BT_LOGE_STR("Cannot make trace static.");
286 goto error;
287 }
288
289 goto end;
290
291error:
292 ret = -1;
293
294end:
33ec5dfa
PP
295 return ret;
296}
297
298static
299int try_create_meta_stream_packet(struct dmesg_component *dmesg_comp,
300 bool has_ts)
301{
302 int ret = 0;
303
304 if (dmesg_comp->trace) {
305 /* Already created */
306 goto end;
307 }
308
309 ret = create_meta(dmesg_comp, has_ts);
310 if (ret) {
311 BT_LOGE("Cannot create metadata objects: dmesg-comp-addr=%p",
312 dmesg_comp);
313 goto error;
314 }
315
316 ret = create_packet_and_stream(dmesg_comp);
317 if (ret) {
318 BT_LOGE("Cannot create packet and stream objects: "
319 "dmesg-comp-addr=%p", dmesg_comp);
320 goto error;
321 }
322
323 goto end;
324
325error:
326 ret = -1;
327
328end:
329 return ret;
330}
d8866baa
PP
331
332static
333void destroy_dmesg_component(struct dmesg_component *dmesg_comp)
334{
335 if (!dmesg_comp) {
336 return;
337 }
338
339 if (dmesg_comp->params.path) {
340 g_string_free(dmesg_comp->params.path, TRUE);
341 }
342
65300d60
PP
343 bt_object_put_ref(dmesg_comp->packet);
344 bt_object_put_ref(dmesg_comp->trace);
345 bt_object_put_ref(dmesg_comp->stream_class);
346 bt_object_put_ref(dmesg_comp->event_class);
347 bt_object_put_ref(dmesg_comp->stream);
348 bt_object_put_ref(dmesg_comp->clock_class);
349 bt_object_put_ref(dmesg_comp->cc_prio_map);
d8866baa
PP
350 g_free(dmesg_comp);
351}
352
33ec5dfa
PP
353static
354enum bt_component_status create_port(struct bt_private_component *priv_comp)
355{
356 return bt_private_component_source_add_output_private_port(priv_comp,
357 "out", NULL, NULL);
358}
359
d8866baa
PP
360BT_HIDDEN
361enum bt_component_status dmesg_init(struct bt_private_component *priv_comp,
362 struct bt_value *params, void *init_method_data)
363{
364 int ret = 0;
365 struct dmesg_component *dmesg_comp = g_new0(struct dmesg_component, 1);
366 enum bt_component_status status = BT_COMPONENT_STATUS_OK;
367
368 if (!dmesg_comp) {
33ec5dfa 369 BT_LOGE_STR("Failed to allocate one dmesg component structure.");
d8866baa
PP
370 goto error;
371 }
372
373 dmesg_comp->params.path = g_string_new(NULL);
374 if (!dmesg_comp->params.path) {
33ec5dfa 375 BT_LOGE_STR("Failed to allocate a GString.");
d8866baa
PP
376 goto error;
377 }
378
33ec5dfa 379 ret = handle_params(dmesg_comp, params);
d8866baa 380 if (ret) {
33ec5dfa 381 BT_LOGE("Invalid parameters: comp-addr=%p", priv_comp);
d8866baa
PP
382 goto error;
383 }
384
33ec5dfa
PP
385 if (!dmesg_comp->params.read_from_stdin &&
386 !g_file_test(dmesg_comp->params.path->str,
387 G_FILE_TEST_IS_REGULAR)) {
388 BT_LOGE("Input path is not a regular file: "
389 "comp-addr=%p, path=\"%s\"", priv_comp,
390 dmesg_comp->params.path->str);
391 goto error;
392 }
d8866baa 393
33ec5dfa
PP
394 status = create_port(priv_comp);
395 if (status != BT_COMPONENT_STATUS_OK) {
396 goto error;
397 }
d8866baa 398
33ec5dfa 399 (void) bt_private_component_set_user_data(priv_comp, dmesg_comp);
d8866baa
PP
400 goto end;
401
402error:
403 destroy_dmesg_component(dmesg_comp);
33ec5dfa
PP
404 (void) bt_private_component_set_user_data(priv_comp, NULL);
405
406 if (status >= 0) {
407 status = BT_COMPONENT_STATUS_ERROR;
408 }
d8866baa
PP
409
410end:
411 return status;
412}
413
414BT_HIDDEN
415void dmesg_finalize(struct bt_private_component *priv_comp)
416{
33ec5dfa
PP
417 void *data = bt_private_component_get_user_data(priv_comp);
418
419 destroy_dmesg_component(data);
420}
421
422static
312c056a 423struct bt_notification *create_init_event_notif_from_line(
f0010051 424 struct dmesg_notif_iter *notif_iter,
312c056a 425 const char *line, const char **new_start)
33ec5dfa 426{
312c056a
PP
427 struct bt_event *event;
428 struct bt_notification *notif = NULL;
33ec5dfa
PP
429 bool has_timestamp = false;
430 unsigned long sec, usec, msec;
431 unsigned int year, mon, mday, hour, min;
432 uint64_t ts = 0;
33ec5dfa 433 int ret = 0;
f0010051 434 struct dmesg_component *dmesg_comp = notif_iter->dmesg_comp;
33ec5dfa 435
33ec5dfa
PP
436 *new_start = line;
437
707b323a
PP
438 if (dmesg_comp->params.no_timestamp) {
439 goto skip_ts;
440 }
441
33ec5dfa
PP
442 /* Extract time from input line */
443 if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
444 ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
445
446 /*
447 * The clock class we use has a 1 GHz frequency: convert
448 * from µs to ns.
449 */
450 ts *= NSEC_PER_USEC;
451 has_timestamp = true;
452 } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
453 &year, &mon, &mday, &hour, &min,
454 &sec, &msec) == 7) {
455 time_t ep_sec;
456 struct tm ti;
457
458 memset(&ti, 0, sizeof(ti));
459 ti.tm_year = year - 1900; /* From 1900 */
460 ti.tm_mon = mon - 1; /* 0 to 11 */
461 ti.tm_mday = mday;
462 ti.tm_hour = hour;
463 ti.tm_min = min;
464 ti.tm_sec = sec;
465
466 ep_sec = bt_timegm(&ti);
467 if (ep_sec != (time_t) -1) {
468 ts = (uint64_t) ep_sec * NSEC_PER_SEC
469 + (uint64_t) msec * NSEC_PER_MSEC;
470 }
471
472 has_timestamp = true;
473 }
474
475 if (has_timestamp) {
476 /* Set new start for the message portion of the line */
477 *new_start = strchr(line, ']');
f6ccaed9 478 BT_ASSERT(*new_start);
33ec5dfa
PP
479 (*new_start)++;
480
481 if ((*new_start)[0] == ' ') {
482 (*new_start)++;
483 }
484 }
485
707b323a 486skip_ts:
33ec5dfa
PP
487 /*
488 * At this point, we know if the stream class's event header
5cd6d0e5 489 * field class should have a timestamp or not, so we can lazily
33ec5dfa
PP
490 * create the metadata, stream, and packet objects.
491 */
492 ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
493 if (ret) {
494 /* try_create_meta_stream_packet() logs errors */
495 goto error;
496 }
497
f0010051 498 notif = bt_notification_event_create(notif_iter->pc_notif_iter,
e22b45d0 499 dmesg_comp->event_class, dmesg_comp->packet);
312c056a
PP
500 if (!notif) {
501 BT_LOGE_STR("Cannot create event notification.");
502 goto error;
503 }
33ec5dfa 504
312c056a
PP
505 event = bt_notification_event_borrow_event(notif);
506 BT_ASSERT(event);
33ec5dfa 507
312c056a 508 if (dmesg_comp->clock_class) {
44c440bc 509 ret = bt_event_set_default_clock_value(event, ts);
312c056a 510 BT_ASSERT(ret == 0);
33ec5dfa
PP
511 }
512
513 goto end;
514
515error:
65300d60 516 BT_OBJECT_PUT_REF_AND_RESET(notif);
33ec5dfa
PP
517
518end:
312c056a 519 return notif;
33ec5dfa
PP
520}
521
522static
f0010051 523int fill_event_payload_from_line(const char *line, struct bt_event *event)
33ec5dfa 524{
50842bdc
PP
525 struct bt_field *ep_field = NULL;
526 struct bt_field *str_field = NULL;
33ec5dfa
PP
527 size_t len;
528 int ret;
529
44c440bc 530 ep_field = bt_event_borrow_payload_field(event);
312c056a 531 BT_ASSERT(ep_field);
44c440bc
PP
532 str_field = bt_field_structure_borrow_member_field_by_index(ep_field,
533 0);
33ec5dfa 534 if (!str_field) {
312c056a 535 BT_LOGE_STR("Cannot borrow `timestamp` field from event payload structure field.");
33ec5dfa
PP
536 goto error;
537 }
538
539 len = strlen(line);
540 if (line[len - 1] == '\n') {
541 /* Do not include the newline character in the payload */
542 len--;
543 }
544
312c056a
PP
545 ret = bt_field_string_clear(str_field);
546 if (ret) {
547 BT_LOGE_STR("Cannot clear string field object.");
548 goto error;
549 }
550
44c440bc 551 ret = bt_field_string_append_with_length(str_field, line, len);
33ec5dfa
PP
552 if (ret) {
553 BT_LOGE("Cannot append value to string field object: "
554 "len=%zu", len);
555 goto error;
556 }
557
33ec5dfa
PP
558 goto end;
559
560error:
561 ret = -1;
562
563end:
33ec5dfa
PP
564 return ret;
565}
566
567static
568struct bt_notification *create_notif_from_line(
f0010051 569 struct dmesg_notif_iter *dmesg_notif_iter, const char *line)
33ec5dfa 570{
50842bdc 571 struct bt_event *event = NULL;
33ec5dfa
PP
572 struct bt_notification *notif = NULL;
573 const char *new_start;
574 int ret;
575
f0010051
PP
576 notif = create_init_event_notif_from_line(dmesg_notif_iter,
577 line, &new_start);
312c056a
PP
578 if (!notif) {
579 BT_LOGE_STR("Cannot create and initialize event notification from line.");
33ec5dfa
PP
580 goto error;
581 }
582
312c056a
PP
583 event = bt_notification_event_borrow_event(notif);
584 BT_ASSERT(event);
f0010051 585 ret = fill_event_payload_from_line(new_start, event);
33ec5dfa 586 if (ret) {
312c056a 587 BT_LOGE("Cannot fill event payload field from line: "
33ec5dfa
PP
588 "ret=%d", ret);
589 goto error;
590 }
591
33ec5dfa
PP
592 goto end;
593
594error:
65300d60 595 BT_OBJECT_PUT_REF_AND_RESET(notif);
33ec5dfa
PP
596
597end:
33ec5dfa
PP
598 return notif;
599}
600
601static
602void destroy_dmesg_notif_iter(struct dmesg_notif_iter *dmesg_notif_iter)
603{
604 if (!dmesg_notif_iter) {
605 return;
606 }
607
608 if (dmesg_notif_iter->fp && dmesg_notif_iter->fp != stdin) {
609 if (fclose(dmesg_notif_iter->fp)) {
610 BT_LOGE_ERRNO("Cannot close input file", ".");
611 }
612 }
d8866baa 613
65300d60 614 bt_object_put_ref(dmesg_notif_iter->tmp_event_notif);
33ec5dfa
PP
615 free(dmesg_notif_iter->linebuf);
616 g_free(dmesg_notif_iter);
d8866baa
PP
617}
618
619BT_HIDDEN
620enum bt_notification_iterator_status dmesg_notif_iter_init(
90157d89 621 struct bt_private_connection_private_notification_iterator *priv_notif_iter,
d8866baa
PP
622 struct bt_private_port *priv_port)
623{
33ec5dfa
PP
624 struct bt_private_component *priv_comp = NULL;
625 struct dmesg_component *dmesg_comp;
626 struct dmesg_notif_iter *dmesg_notif_iter =
627 g_new0(struct dmesg_notif_iter, 1);
628 enum bt_notification_iterator_status status =
629 BT_NOTIFICATION_ITERATOR_STATUS_OK;
630
631 if (!dmesg_notif_iter) {
632 BT_LOGE_STR("Failed to allocate on dmesg notification iterator structure.");
633 goto error;
634 }
635
90157d89 636 priv_comp = bt_private_connection_private_notification_iterator_get_private_component(
33ec5dfa 637 priv_notif_iter);
f6ccaed9 638 BT_ASSERT(priv_comp);
33ec5dfa 639 dmesg_comp = bt_private_component_get_user_data(priv_comp);
f6ccaed9 640 BT_ASSERT(dmesg_comp);
33ec5dfa 641 dmesg_notif_iter->dmesg_comp = dmesg_comp;
f0010051 642 dmesg_notif_iter->pc_notif_iter = priv_notif_iter;
d8866baa 643
33ec5dfa
PP
644 if (dmesg_comp->params.read_from_stdin) {
645 dmesg_notif_iter->fp = stdin;
646 } else {
647 dmesg_notif_iter->fp = fopen(dmesg_comp->params.path->str, "r");
648 if (!dmesg_notif_iter->fp) {
649 BT_LOGE_ERRNO("Cannot open input file in read mode", ": path=\"%s\"",
650 dmesg_comp->params.path->str);
651 goto error;
652 }
653 }
654
90157d89 655 (void) bt_private_connection_private_notification_iterator_set_user_data(priv_notif_iter,
33ec5dfa
PP
656 dmesg_notif_iter);
657 goto end;
658
659error:
660 destroy_dmesg_notif_iter(dmesg_notif_iter);
90157d89 661 (void) bt_private_connection_private_notification_iterator_set_user_data(priv_notif_iter,
33ec5dfa
PP
662 NULL);
663 if (status >= 0) {
664 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
665 }
666
667end:
65300d60 668 bt_object_put_ref(priv_comp);
33ec5dfa 669 return status;
d8866baa
PP
670}
671
672BT_HIDDEN
33ec5dfa 673void dmesg_notif_iter_finalize(
90157d89 674 struct bt_private_connection_private_notification_iterator *priv_notif_iter)
d8866baa 675{
90157d89 676 destroy_dmesg_notif_iter(bt_private_connection_private_notification_iterator_get_user_data(
33ec5dfa 677 priv_notif_iter));
d8866baa
PP
678}
679
d4393e08
PP
680static
681enum bt_notification_iterator_status dmesg_notif_iter_next_one(
682 struct dmesg_notif_iter *dmesg_notif_iter,
683 struct bt_notification **notif)
d8866baa 684{
33ec5dfa 685 ssize_t len;
33ec5dfa 686 struct dmesg_component *dmesg_comp;
d4393e08
PP
687 enum bt_notification_iterator_status status =
688 BT_NOTIFICATION_ITERATOR_STATUS_OK;
d8866baa 689
f6ccaed9 690 BT_ASSERT(dmesg_notif_iter);
33ec5dfa 691 dmesg_comp = dmesg_notif_iter->dmesg_comp;
f6ccaed9 692 BT_ASSERT(dmesg_comp);
33ec5dfa 693
312c056a 694 if (dmesg_notif_iter->state == STATE_DONE) {
d4393e08 695 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
312c056a
PP
696 goto end;
697 }
698
699 if (dmesg_notif_iter->tmp_event_notif ||
700 dmesg_notif_iter->state == STATE_EMIT_PACKET_END ||
701 dmesg_notif_iter->state == STATE_EMIT_STREAM_END) {
702 goto handle_state;
703 }
704
33ec5dfa
PP
705 while (true) {
706 const char *ch;
707 bool only_spaces = true;
708
709 len = bt_getline(&dmesg_notif_iter->linebuf,
710 &dmesg_notif_iter->linebuf_len, dmesg_notif_iter->fp);
711 if (len < 0) {
712 if (errno == EINVAL) {
d4393e08 713 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
33ec5dfa 714 } else if (errno == ENOMEM) {
d4393e08 715 status =
33ec5dfa
PP
716 BT_NOTIFICATION_ITERATOR_STATUS_NOMEM;
717 } else {
312c056a
PP
718 if (dmesg_notif_iter->state == STATE_EMIT_STREAM_BEGINNING) {
719 /* Stream did not even begin */
d4393e08 720 status = BT_NOTIFICATION_ITERATOR_STATUS_END;
312c056a
PP
721 goto end;
722 } else {
723 /* End current packet now */
724 dmesg_notif_iter->state =
725 STATE_EMIT_PACKET_END;
726 goto handle_state;
727 }
33ec5dfa
PP
728 }
729
730 goto end;
731 }
732
f6ccaed9 733 BT_ASSERT(dmesg_notif_iter->linebuf);
33ec5dfa
PP
734
735 /* Ignore empty lines, once trimmed */
736 for (ch = dmesg_notif_iter->linebuf; *ch != '\0'; ch++) {
737 if (!isspace(*ch)) {
738 only_spaces = false;
739 break;
740 }
741 }
742
743 if (!only_spaces) {
744 break;
745 }
746 }
747
f0010051
PP
748 dmesg_notif_iter->tmp_event_notif = create_notif_from_line(
749 dmesg_notif_iter, dmesg_notif_iter->linebuf);
312c056a 750 if (!dmesg_notif_iter->tmp_event_notif) {
33ec5dfa
PP
751 BT_LOGE("Cannot create event notification from line: "
752 "dmesg-comp-addr=%p, line=\"%s\"", dmesg_comp,
753 dmesg_notif_iter->linebuf);
312c056a
PP
754 goto end;
755 }
756
757handle_state:
758 BT_ASSERT(dmesg_comp->trace);
759
760 switch (dmesg_notif_iter->state) {
761 case STATE_EMIT_STREAM_BEGINNING:
762 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
d4393e08 763 *notif = bt_notification_stream_begin_create(
f0010051 764 dmesg_notif_iter->pc_notif_iter, dmesg_comp->stream);
312c056a
PP
765 dmesg_notif_iter->state = STATE_EMIT_PACKET_BEGINNING;
766 break;
767 case STATE_EMIT_PACKET_BEGINNING:
768 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
d4393e08 769 *notif = bt_notification_packet_begin_create(
f0010051 770 dmesg_notif_iter->pc_notif_iter, dmesg_comp->packet);
312c056a
PP
771 dmesg_notif_iter->state = STATE_EMIT_EVENT;
772 break;
773 case STATE_EMIT_EVENT:
774 BT_ASSERT(dmesg_notif_iter->tmp_event_notif);
d4393e08
PP
775 *notif = dmesg_notif_iter->tmp_event_notif;
776 dmesg_notif_iter->tmp_event_notif = NULL;
312c056a
PP
777 break;
778 case STATE_EMIT_PACKET_END:
d4393e08 779 *notif = bt_notification_packet_end_create(
f0010051 780 dmesg_notif_iter->pc_notif_iter, dmesg_comp->packet);
312c056a
PP
781 dmesg_notif_iter->state = STATE_EMIT_STREAM_END;
782 break;
783 case STATE_EMIT_STREAM_END:
d4393e08 784 *notif = bt_notification_stream_end_create(
f0010051 785 dmesg_notif_iter->pc_notif_iter, dmesg_comp->stream);
312c056a
PP
786 dmesg_notif_iter->state = STATE_DONE;
787 break;
788 default:
789 break;
790 }
791
d4393e08 792 if (!*notif) {
312c056a
PP
793 BT_LOGE("Cannot create notification: dmesg-comp-addr=%p",
794 dmesg_comp);
d4393e08 795 status = BT_NOTIFICATION_ITERATOR_STATUS_ERROR;
33ec5dfa
PP
796 }
797
798end:
d4393e08
PP
799 return status;
800}
801
802BT_HIDDEN
803enum bt_notification_iterator_status dmesg_notif_iter_next(
804 struct bt_private_connection_private_notification_iterator *priv_notif_iter,
805 bt_notification_array notifs, uint64_t capacity,
806 uint64_t *count)
807{
808 struct dmesg_notif_iter *dmesg_notif_iter =
809 bt_private_connection_private_notification_iterator_get_user_data(
810 priv_notif_iter);
811 enum bt_notification_iterator_status status =
812 BT_NOTIFICATION_ITERATOR_STATUS_OK;
813 uint64_t i = 0;
814
815 while (i < capacity && status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
816 status = dmesg_notif_iter_next_one(dmesg_notif_iter, &notifs[i]);
817 if (status == BT_NOTIFICATION_ITERATOR_STATUS_OK) {
818 i++;
819 }
820 }
821
822 if (i > 0) {
823 /*
824 * Even if dmesg_notif_iter_next_one() returned
825 * something else than
826 * BT_NOTIFICATION_ITERATOR_STATUS_OK, we accumulated
827 * notification objects in the output notification
828 * array, so we need to return
829 * BT_NOTIFICATION_ITERATOR_STATUS_OK so that they are
830 * transfered to downstream. This other status occurs
831 * again the next time muxer_notif_iter_do_next() is
832 * called, possibly without any accumulated
833 * notification, in which case we'll return it.
834 */
835 *count = i;
836 status = BT_NOTIFICATION_ITERATOR_STATUS_OK;
837 }
838
839 return status;
d8866baa 840}
This page took 0.072885 seconds and 4 git commands to generate.