+static int parse_kernel_timestamp(char **_p, usec_t *t) {
+ usec_t r;
+ int k, i;
+ char *p;
+
+ assert(_p);
+ assert(*_p);
+ assert(t);
+
+ p = *_p;
+
+ if (strlen(p) < 14 || p[0] != '[' || p[13] != ']' || p[6] != '.')
+ return 0;
+
+ r = 0;
+
+ for (i = 1; i <= 5; i++) {
+ r *= 10;
+
+ if (p[i] == ' ')
+ continue;
+
+ k = undecchar(p[i]);
+ if (k < 0)
+ return 0;
+
+ r += k;
+ }
+
+ for (i = 7; i <= 12; i++) {
+ r *= 10;
+
+ k = undecchar(p[i]);
+ if (k < 0)
+ return 0;
+
+ r += k;
+ }
+
+ *t = r;
+ *_p += 14;
+ *_p += strspn(*_p, WHITESPACE);
+
+ return 1;
+}
+
+static void proc_kmsg_line(Server *s, const char *p) {
+ struct iovec iovec[N_IOVEC_META_FIELDS + 7];
+ char *message = NULL, *syslog_priority = NULL, *syslog_pid = NULL, *syslog_facility = NULL, *syslog_identifier = NULL, *source_time = NULL;
+ int priority = LOG_KERN | LOG_INFO;
+ unsigned n = 0;
+ usec_t usec;
+ char *identifier = NULL, *pid = NULL;
+
+ assert(s);
+ assert(p);
+
+ if (isempty(p))
+ return;
+
+ parse_syslog_priority((char **) &p, &priority);
+
+ if (s->forward_to_kmsg && (priority & LOG_FACMASK) != LOG_KERN)
+ return;
+
+ if (parse_kernel_timestamp((char **) &p, &usec) > 0) {
+ if (asprintf(&source_time, "_SOURCE_MONOTONIC_TIMESTAMP=%llu",
+ (unsigned long long) usec) >= 0)
+ IOVEC_SET_STRING(iovec[n++], source_time);
+ }
+
+ IOVEC_SET_STRING(iovec[n++], "_TRANSPORT=kernel");
+
+ if (asprintf(&syslog_priority, "PRIORITY=%i", priority & LOG_PRIMASK) >= 0)
+ IOVEC_SET_STRING(iovec[n++], syslog_priority);
+
+ if ((priority & LOG_FACMASK) == LOG_KERN) {
+
+ if (s->forward_to_syslog)
+ forward_syslog(s, priority, "kernel", p, NULL, NULL);
+
+ IOVEC_SET_STRING(iovec[n++], "SYSLOG_IDENTIFIER=kernel");
+ } else {
+ read_identifier(&p, &identifier, &pid);
+
+ if (s->forward_to_syslog)
+ forward_syslog(s, priority, identifier, p, NULL, NULL);
+
+ if (identifier) {
+ syslog_identifier = strappend("SYSLOG_IDENTIFIER=", identifier);
+ if (syslog_identifier)
+ IOVEC_SET_STRING(iovec[n++], syslog_identifier);
+ }
+
+ if (pid) {
+ syslog_pid = strappend("SYSLOG_PID=", pid);
+ if (syslog_pid)
+ IOVEC_SET_STRING(iovec[n++], syslog_pid);
+ }
+
+ if (asprintf(&syslog_facility, "SYSLOG_FACILITY=%i", LOG_FAC(priority)) >= 0)
+ IOVEC_SET_STRING(iovec[n++], syslog_facility);
+ }
+
+ message = strappend("MESSAGE=", p);
+ if (message)
+ IOVEC_SET_STRING(iovec[n++], message);
+
+ dispatch_message(s, iovec, n, ELEMENTSOF(iovec), NULL, NULL, priority);
+
+ free(message);
+ free(syslog_priority);
+ free(syslog_identifier);
+ free(syslog_pid);
+ free(syslog_facility);
+ free(source_time);
+ free(identifier);
+ free(pid);
+}
+
+static void proc_kmsg_scan(Server *s) {
+ char *p;
+ size_t remaining;
+
+ assert(s);
+
+ p = s->proc_kmsg_buffer;
+ remaining = s->proc_kmsg_length;
+ for (;;) {
+ char *end;
+ size_t skip;
+
+ end = memchr(p, '\n', remaining);
+ if (end)
+ skip = end - p + 1;
+ else if (remaining >= sizeof(s->proc_kmsg_buffer) - 1) {
+ end = p + sizeof(s->proc_kmsg_buffer) - 1;
+ skip = remaining;
+ } else
+ break;
+
+ *end = 0;
+
+ proc_kmsg_line(s, p);
+
+ remaining -= skip;
+ p += skip;
+ }
+
+ if (p > s->proc_kmsg_buffer) {
+ memmove(s->proc_kmsg_buffer, p, remaining);
+ s->proc_kmsg_length = remaining;
+ }
+}
+