+ void *data = bt_private_component_get_user_data(priv_comp);
+
+ destroy_dmesg_component(data);
+}
+
+static
+int create_event_header_from_line(
+ struct dmesg_component *dmesg_comp,
+ const char *line, const char **new_start,
+ struct bt_ctf_field **user_field,
+ struct bt_ctf_clock_value **user_clock_value)
+{
+ bool has_timestamp = false;
+ unsigned long sec, usec, msec;
+ unsigned int year, mon, mday, hour, min;
+ uint64_t ts = 0;
+ struct bt_ctf_clock_value *clock_value = NULL;
+ struct bt_ctf_field_type *ft = NULL;
+ struct bt_ctf_field *eh_field = NULL;
+ struct bt_ctf_field *ts_field = NULL;
+ int ret = 0;
+
+ assert(user_clock_value);
+ assert(user_field);
+ *new_start = line;
+
+ /* Extract time from input line */
+ if (sscanf(line, "[%lu.%lu] ", &sec, &usec) == 2) {
+ ts = (uint64_t) sec * USEC_PER_SEC + (uint64_t) usec;
+
+ /*
+ * The clock class we use has a 1 GHz frequency: convert
+ * from µs to ns.
+ */
+ ts *= NSEC_PER_USEC;
+ has_timestamp = true;
+ } else if (sscanf(line, "[%u-%u-%u %u:%u:%lu.%lu] ",
+ &year, &mon, &mday, &hour, &min,
+ &sec, &msec) == 7) {
+ time_t ep_sec;
+ struct tm ti;
+
+ memset(&ti, 0, sizeof(ti));
+ ti.tm_year = year - 1900; /* From 1900 */
+ ti.tm_mon = mon - 1; /* 0 to 11 */
+ ti.tm_mday = mday;
+ ti.tm_hour = hour;
+ ti.tm_min = min;
+ ti.tm_sec = sec;
+
+ ep_sec = bt_timegm(&ti);
+ if (ep_sec != (time_t) -1) {
+ ts = (uint64_t) ep_sec * NSEC_PER_SEC
+ + (uint64_t) msec * NSEC_PER_MSEC;
+ }
+
+ has_timestamp = true;
+ }
+
+ if (has_timestamp) {
+ /* Set new start for the message portion of the line */
+ *new_start = strchr(line, ']');
+ assert(*new_start);
+ (*new_start)++;
+
+ if ((*new_start)[0] == ' ') {
+ (*new_start)++;
+ }
+ }
+
+ /*
+ * At this point, we know if the stream class's event header
+ * field type should have a timestamp or not, so we can lazily
+ * create the metadata, stream, and packet objects.
+ */
+ ret = try_create_meta_stream_packet(dmesg_comp, has_timestamp);
+ if (ret) {
+ /* try_create_meta_stream_packet() logs errors */
+ goto error;
+ }
+
+ if (dmesg_comp->clock_class) {
+ clock_value = bt_ctf_clock_value_create(dmesg_comp->clock_class,
+ ts);
+ if (!clock_value) {
+ BT_LOGE_STR("Cannot create clock value object.");
+ goto error;
+ }
+
+ ft = bt_ctf_stream_class_get_event_header_type(
+ dmesg_comp->stream_class);
+ assert(ft);
+ eh_field = bt_ctf_field_create(ft);
+ if (!eh_field) {
+ BT_LOGE_STR("Cannot create event header field object.");
+ goto error;
+ }
+
+ ts_field = bt_ctf_field_structure_get_field_by_name(eh_field,
+ "timestamp");
+ if (!ts_field) {
+ BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
+ goto error;
+ }
+
+ ret = bt_ctf_field_unsigned_integer_set_value(ts_field, ts);
+ if (ret) {
+ BT_LOGE_STR("Cannot set integer field's value.");
+ goto error;
+ }
+
+ *user_clock_value = clock_value;
+ clock_value = NULL;
+ *user_field = eh_field;
+ eh_field = NULL;
+ }
+
+ goto end;
+
+error:
+ ret = -1;
+
+end:
+ bt_put(ft);
+ bt_put(ts_field);
+ bt_put(clock_value);
+ bt_put(eh_field);
+ return ret;
+}
+
+static
+int create_event_payload_from_line(
+ struct dmesg_component *dmesg_comp,
+ const char *line, struct bt_ctf_field **user_field)
+{
+ struct bt_ctf_field_type *ft = NULL;
+ struct bt_ctf_field *ep_field = NULL;
+ struct bt_ctf_field *str_field = NULL;
+ size_t len;
+ int ret;
+
+ assert(user_field);
+ ft = bt_ctf_event_class_get_payload_type(dmesg_comp->event_class);
+ assert(ft);
+ ep_field = bt_ctf_field_create(ft);
+ if (!ep_field) {
+ BT_LOGE_STR("Cannot create event payload field object.");
+ goto error;
+ }
+
+ str_field = bt_ctf_field_structure_get_field_by_name(ep_field, "str");
+ if (!str_field) {
+ BT_LOGE_STR("Cannot get `timestamp` field from structure field.");
+ goto error;
+ }
+
+ len = strlen(line);
+ if (line[len - 1] == '\n') {
+ /* Do not include the newline character in the payload */
+ len--;
+ }
+
+ ret = bt_ctf_field_string_append_len(str_field, line, len);
+ if (ret) {
+ BT_LOGE("Cannot append value to string field object: "
+ "len=%zu", len);
+ goto error;
+ }
+
+ *user_field = ep_field;
+ ep_field = NULL;
+ goto end;
+
+error:
+ ret = -1;
+
+end:
+ bt_put(ft);
+ bt_put(ep_field);
+ bt_put(str_field);
+ return ret;
+}
+
+static
+struct bt_notification *create_notif_from_line(
+ struct dmesg_component *dmesg_comp, const char *line)
+{
+ struct bt_ctf_field *eh_field = NULL;
+ struct bt_ctf_field *ep_field = NULL;
+ struct bt_ctf_clock_value *clock_value = NULL;
+ struct bt_ctf_event *event = NULL;
+ struct bt_notification *notif = NULL;
+ const char *new_start;
+ int ret;
+
+ ret = create_event_header_from_line(dmesg_comp, line, &new_start,
+ &eh_field, &clock_value);
+ if (ret) {
+ BT_LOGE("Cannot create event header field from line: "
+ "ret=%d", ret);
+ goto error;
+ }
+
+ ret = create_event_payload_from_line(dmesg_comp, new_start,
+ &ep_field);
+ if (ret) {
+ BT_LOGE("Cannot create event payload field from line: "
+ "ret=%d", ret);
+ goto error;
+ }
+
+ assert(ep_field);
+ event = bt_ctf_event_create(dmesg_comp->event_class);
+ if (!event) {
+ BT_LOGE_STR("Cannot create event object.");
+ goto error;
+ }
+
+ ret = bt_ctf_event_set_packet(event, dmesg_comp->packet);
+ if (ret) {
+ BT_LOGE_STR("Cannot set event's packet.");
+ goto error;
+ }
+
+ if (eh_field) {
+ ret = bt_ctf_event_set_header(event, eh_field);
+ if (ret) {
+ BT_LOGE_STR("Cannot set event's header field.");
+ goto error;
+ }
+ }
+
+ ret = bt_ctf_event_set_event_payload(event, ep_field);
+ if (ret) {
+ BT_LOGE_STR("Cannot set event's payload field.");
+ goto error;
+ }
+
+ if (clock_value) {
+ ret = bt_ctf_event_set_clock_value(event, clock_value);
+ if (ret) {
+ BT_LOGE_STR("Cannot set event's clock value.");
+ goto error;
+ }
+ }
+
+ notif = bt_notification_event_create(event, dmesg_comp->cc_prio_map);
+ if (!notif) {
+ BT_LOGE_STR("Cannot create event notification.");
+ goto error;
+ }
+
+ goto end;
+
+error:
+ BT_PUT(notif);
+
+end:
+ bt_put(eh_field);
+ bt_put(ep_field);
+ bt_put(clock_value);
+ bt_put(event);
+ return notif;
+}
+
+static
+void destroy_dmesg_notif_iter(struct dmesg_notif_iter *dmesg_notif_iter)
+{
+ if (!dmesg_notif_iter) {
+ return;
+ }
+
+ if (dmesg_notif_iter->fp && dmesg_notif_iter->fp != stdin) {
+ if (fclose(dmesg_notif_iter->fp)) {
+ BT_LOGE_ERRNO("Cannot close input file", ".");
+ }
+ }