From f1cc12f55ebb51209cb26e71985d35c5e6671520 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 11 Jun 2018 16:35:45 +0200 Subject: [PATCH] [usyslogd] split off syslog parsing - Add proto.{h,c} for parsing of syslog message - Also parse time stamp in addition to priority Signed-off-by: David Oberhollenzer --- syslogd/Makemodule.am | 1 + syslogd/main.c | 35 ++++----- syslogd/proto.c | 177 ++++++++++++++++++++++++++++++++++++++++++ syslogd/proto.h | 35 +++++++++ 4 files changed, 229 insertions(+), 19 deletions(-) create mode 100644 syslogd/proto.c create mode 100644 syslogd/proto.h diff --git a/syslogd/Makemodule.am b/syslogd/Makemodule.am index 489acc9..9e5378d 100644 --- a/syslogd/Makemodule.am +++ b/syslogd/Makemodule.am @@ -1,5 +1,6 @@ usyslogd_SOURCES = syslogd/main.c usyslogd_SOURCES += syslogd/logfile.c syslogd/logfile.h +usyslogd_SOURCES += syslogd/proto.c syslogd/proto.h usyslogd_CPPFLAGS = $(AM_CPPFLAGS) usyslogd_CFLAGS = $(AM_CFLAGS) usyslogd_LDFLAGS = $(AM_LDFLAGS) diff --git a/syslogd/main.c b/syslogd/main.c index a5702b7..b1b70b0 100644 --- a/syslogd/main.c +++ b/syslogd/main.c @@ -24,9 +24,9 @@ #include #include #include -#include #include "logfile.h" +#include "proto.h" #include "util.h" @@ -118,16 +118,18 @@ static void signal_setup(void) sigaction(SIGTERM, &act, NULL); } -static int print_to_log(int facility, int level, const char *data) +static int print_to_log(const syslog_msg_t *msg) { const char *fac_name, *lvl_str; + char timebuf[32]; logfile_t *log; + struct tm tm; - fac_name = enum_to_name(facilities, facility); + fac_name = enum_to_name(facilities, msg->facility); if (fac_name == NULL) return -1; - lvl_str = enum_to_name(levels, level); + lvl_str = enum_to_name(levels, msg->level); if (lvl_str == NULL) return -1; @@ -144,14 +146,19 @@ static int print_to_log(int facility, int level, const char *data) logfiles = log; } - logfile_write(log, "[%s] %s", lvl_str, data); + gmtime_r(&msg->timestamp, &tm); + strftime(timebuf, sizeof(timebuf), "%FT%T", &tm); + + logfile_write(log, "[%s][%s][%s][%u] %s", timebuf, lvl_str, + msg->ident ? msg->ident : "", msg->pid, + msg->message); return 0; } static int handle_data(int fd) { - char buffer[2048], *ptr; - int i = 0, priority; + char buffer[2048]; + syslog_msg_t msg; ssize_t ret; memset(buffer, 0, sizeof(buffer)); @@ -160,20 +167,10 @@ static int handle_data(int fd) if (ret <= 0) return -1; - for (ptr = buffer; isspace(*ptr); ++ptr) - ; - if (*(ptr++) != '<') + if (syslog_msg_parse(&msg, buffer)) return -1; - if (!isdigit(*ptr)) - return -1; - for (priority = 0; isdigit(*ptr); ++ptr) - priority = priority * 10 + (*ptr) - '0'; - if (*(ptr++) != '>') - return -1; - while (isspace(*ptr)) - ++ptr; - return print_to_log(priority >> 3, priority & 0x07, ptr); + return print_to_log(&msg); } int main(void) diff --git a/syslogd/proto.c b/syslogd/proto.c new file mode 100644 index 0000000..3487dbd --- /dev/null +++ b/syslogd/proto.c @@ -0,0 +1,177 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * Copyright (C) 2018 - David Oberhollenzer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#include +#include +#include +#include + +#include "proto.h" + +static const char *months[] = { + "Jan", "Feb", "Mar", "Apr", + "May", "Jun", "Jul", "Aug", + "Sep", "Oct", "Nov", "Dec" +}; + +static const int days[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; + +static int isleap(int year) +{ + return ((year % 4 == 0) && (year % 100 != 0)) || ((year % 400) == 0); +} + +static int mdays(int year, int month) +{ + return (isleap(year) && month == 2) ? 29 : days[month - 1]; +} + +static char *read_num(char *str, int *out, int maxval) +{ + if (str == NULL || !isdigit(*str)) + return NULL; + for (*out = 0; isdigit(*str); ++str) { + (*out) = (*out) * 10 + (*str) - '0'; + if ((*out) > maxval) + return NULL; + } + return str; +} + +static char *skip_space(char *str) +{ + if (str == NULL || !isspace(*str)) + return NULL; + while (isspace(*str)) + ++str; + return str; +} + +static char *read_date_bsd(char *str, struct tm *tm) +{ + int year, month, day, hour, minute, second; + time_t t; + + /* decode date */ + for (month = 0; month < 12; ++month) { + if (strncmp(str, months[month], 3) == 0) { + str = skip_space(str + 3); + break; + } + } + + str = read_num(str, &day, 31); + str = skip_space(str); + + t = time(NULL); + if (localtime_r(&t, tm) == NULL) + return NULL; + + year = tm->tm_year; + + /* sanity check */ + if (str == NULL || month >= 12 || day < 1) + return NULL; + if (month == 11 && tm->tm_mon == 0) + --year; + if (day > mdays(year + 1900, month + 1)) + return NULL; + + /* decode time */ + str = read_num(str, &hour, 23); + if (str == NULL || *(str++) != ':') + return NULL; + str = read_num(str, &minute, 59); + if (str == NULL || *(str++) != ':') + return NULL; + str = read_num(str, &second, 59); + str = skip_space(str); + + /* store result */ + memset(tm, 0, sizeof(*tm)); + tm->tm_sec = second; + tm->tm_min = minute; + tm->tm_hour = hour; + tm->tm_mday = day; + tm->tm_mon = month; + tm->tm_year = year; + return str; +} + +static char *decode_priority(char *str, int *priority) +{ + while (isspace(*str)) + ++str; + if (*(str++) != '<') + return NULL; + str = read_num(str, priority, 23 * 8 + 7); + if (str == NULL || *(str++) != '>') + return NULL; + while (isspace(*str)) + ++str; + return str; +} + +int syslog_msg_parse(syslog_msg_t *msg, char *str) +{ + char *ident, *ptr; + struct tm tstamp; + pid_t pid = 0; + int priority; + + memset(msg, 0, sizeof(*msg)); + + str = decode_priority(str, &priority); + if (str == NULL) + return -1; + + msg->facility = priority >> 3; + msg->level = priority & 0x07; + + str = read_date_bsd(str, &tstamp); + if (str == NULL) + return -1; + + ident = str; + while (*str != '\0' && *str != ':') + ++str; + + if (*str == ':') { + *(str++) = '\0'; + while (isspace(*str)) + ++str; + + ptr = ident; + while (*ptr != '[' && *ptr != '\0') + ++ptr; + + if (*ptr == '[') { + *(ptr++) = '\0'; + + while (isdigit(*ptr)) + pid = pid * 10 + *(ptr++) - '0'; + } + } else { + ident = NULL; + } + + msg->timestamp = mktime(&tstamp); + msg->pid = pid; + msg->ident = ident; + msg->message = str; + return 0; +} diff --git a/syslogd/proto.h b/syslogd/proto.h new file mode 100644 index 0000000..c64c9e1 --- /dev/null +++ b/syslogd/proto.h @@ -0,0 +1,35 @@ +/* SPDX-License-Identifier: GPL-3.0-or-later */ +/* + * Copyright (C) 2018 - David Oberhollenzer + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +#ifndef PROTO_H +#define PROTO_H + +#include +#include + +typedef struct { + int facility; + int level; + time_t timestamp; + pid_t pid; + const char *ident; + const char *message; +} syslog_msg_t; + +int syslog_msg_parse(syslog_msg_t *msg, char *str); + +#endif /* PROTO_H */