diff --git a/.gitignore b/.gitignore index 73b3efb..256a460 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ reboot shutdown killall5 runsvc +usyslogd services/sigkill services/sigterm diff --git a/Makefile.am b/Makefile.am index 0b24ded..09fa4ef 100644 --- a/Makefile.am +++ b/Makefile.am @@ -19,6 +19,10 @@ include initd/Makemodule.am include scripts/Makemodule.am include services/Makemodule.am +if USYSLOGD +include syslogd/Makemodule.am +endif + install-data-local: $(MKDIR_P) $(DESTDIR)$(SVCDIR) $(LN_S) $(TEMPLATEDIR)/loopback $(DESTDIR)$(SVCDIR)/loopback @@ -39,3 +43,6 @@ install-data-local: $(LN_S) $(TEMPLATEDIR)/sigkill $(DESTDIR)$(SVCDIR)/sigkill@reboot $(LN_S) $(TEMPLATEDIR)/sigterm $(DESTDIR)$(SVCDIR)/sigterm@reboot $(LN_S) $(TEMPLATEDIR)/ifcfg $(DESTDIR)$(SVCDIR)/ifcfg +if USYSLOGD + $(LN_S) $(TEMPLATEDIR)/usyslogd $(DESTDIR)$(SVCDIR)/usyslogd +endif diff --git a/configure.ac b/configure.ac index 8a4b4d9..c1c7788 100644 --- a/configure.ac +++ b/configure.ac @@ -37,6 +37,16 @@ UL_WARN_ADD([-pedantic]) AC_SUBST([WARN_CFLAGS]) +AC_ARG_WITH([usyslogd], + [AS_HELP_STRING([--without-usyslogd], [Build without syslog daemon])], + [case "${withval}" in + yes) AM_CONDITIONAL([USYSLOGD], [true]) ;; + no) AM_CONDITIONAL([USYSLOGD], [false]) ;; + *) AC_MSG_ERROR([bad value ${withval} for --without-usyslogd]) ;; + esac], + [AM_CONDITIONAL([USYSLOGD], [true])]) + + AC_CONFIG_HEADERS([lib/include/config.h]) AC_DEFINE_DIR(SVCDIR, sysconfdir/init.d, [Startup service directory]) AC_DEFINE_DIR(TEMPLATEDIR, datadir/init, [Service template directory]) diff --git a/services/Makemodule.am b/services/Makemodule.am index c11a365..e9e6ac7 100644 --- a/services/Makemodule.am +++ b/services/Makemodule.am @@ -8,10 +8,12 @@ init_DATA += services/vfs services/ifrename services/ifcfg init_DATA += services/dhcpcd services/dhcpcdmaster services/unbound init_DATA += services/dnsmasq +if USYSLOGD +init_DATA += services/usyslogd +endif + EXTRA_DIST += services/sysinit services/vfs services/agetty services/hostname EXTRA_DIST += services/hwclock services/loopback services/reboot EXTRA_DIST += services/shutdown services/sync services/sysctl services/tmpfs -EXTRA_DIST += services/dhcpcd services/dhcpcdmaster EXTRA_DIST += services/dhcpcd services/dhcpcdmaster services/unbound -EXTRA_DIST += services/dnsmasq - +EXTRA_DIST += services/usyslogd services/dnsmasq diff --git a/services/usyslogd b/services/usyslogd new file mode 100644 index 0000000..23bea3b --- /dev/null +++ b/services/usyslogd @@ -0,0 +1,6 @@ +description "starting usyslogd" +exec usyslogd +type respawn limit 5 +target boot +after hostname vfs +before sysinit \ No newline at end of file diff --git a/syslogd/Makemodule.am b/syslogd/Makemodule.am new file mode 100644 index 0000000..489acc9 --- /dev/null +++ b/syslogd/Makemodule.am @@ -0,0 +1,8 @@ +usyslogd_SOURCES = syslogd/main.c +usyslogd_SOURCES += syslogd/logfile.c syslogd/logfile.h +usyslogd_CPPFLAGS = $(AM_CPPFLAGS) +usyslogd_CFLAGS = $(AM_CFLAGS) +usyslogd_LDFLAGS = $(AM_LDFLAGS) +usyslogd_LDADD = libinit.a + +sbin_PROGRAMS += usyslogd diff --git a/syslogd/logfile.c b/syslogd/logfile.c new file mode 100644 index 0000000..a59f7e7 --- /dev/null +++ b/syslogd/logfile.c @@ -0,0 +1,69 @@ +/* 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 +#include + +#include "logfile.h" + + +logfile_t *logfile_create(const char *name) +{ + logfile_t *file; + + file = calloc(1, sizeof(*file) + strlen(name) + 1); + if (file == NULL) { + perror("calloc"); + return NULL; + } + + strcpy(file->name, name); + + file->fd = open(file->name, O_WRONLY | O_CREAT, 0640); + if (file->fd < 0) + goto fail; + + if (lseek(file->fd, 0, SEEK_END)) + goto fail; + + return file; +fail: + perror(file->name); + free(file); + return NULL; +} + +void logfile_destroy(logfile_t *file) +{ + close(file->fd); + free(file); +} + +void logfile_write(logfile_t *file, const char *format, ...) +{ + va_list ap; + + va_start(ap, format); + vdprintf(file->fd, format, ap); + va_end(ap); + + fsync(file->fd); +} diff --git a/syslogd/logfile.h b/syslogd/logfile.h new file mode 100644 index 0000000..58da272 --- /dev/null +++ b/syslogd/logfile.h @@ -0,0 +1,34 @@ +/* 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 LOGFILE_H +#define LOGFILE_H + +typedef struct logfile_t { + struct logfile_t *next; + int fd; + + char name[]; +} logfile_t; + +logfile_t *logfile_create(const char *name); + +void logfile_destroy(logfile_t *file); + +void logfile_write(logfile_t *file, const char *format, ...); + +#endif /* LOGFILE_H */ diff --git a/syslogd/main.c b/syslogd/main.c new file mode 100644 index 0000000..a5702b7 --- /dev/null +++ b/syslogd/main.c @@ -0,0 +1,209 @@ +/* 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 +#include +#include +#include +#include +#include + +#include "logfile.h" +#include "util.h" + + +#define SYSLOG_SOCKET "/dev/log" +#define SYSLOG_PATH "/var/log" + + +static volatile sig_atomic_t syslog_run = 1; +static logfile_t *logfiles = NULL; + +static const enum_map_t facilities[] = { + { "kernel.log", 0 }, + { "user.log", 1 }, + { "mail.log", 2 }, + { "daemon.log", 3 }, + { "auth.log", 4 }, + { "syslog.log", 5 }, + { "lpr.log", 6 }, + { "news.log", 7 }, + { "uucp.log", 8 }, + { "clock.log", 9 }, + { "authpriv.log", 10 }, + { "ftp.log", 11 }, + { "ntp.log", 12 }, + { "audit.log", 13 }, + { "alert.log", 14 }, + { "cron.log", 15 }, + { "local0.log", 16 }, + { "local1.log", 17 }, + { "local2.log", 18 }, + { "local3.log", 19 }, + { "local4.log", 20 }, + { "local5.log", 21 }, + { "local6.log", 22 }, + { "local7.log", 23 }, + { NULL, 0 }, +}; + +static const enum_map_t levels[] = { + { "emergency", 0 }, + { "alert", 1 }, + { "critical", 2 }, + { "error", 3 }, + { "warning", 4 }, + { "notice", 5 }, + { "info", 6 }, + { "debug", 7 }, + { NULL, 0 }, +}; + + +static int directory_setup(void) +{ + if (mkdir(SYSLOG_PATH, 0755)) { + if (errno != EEXIST) { + perror("mkdir " SYSLOG_PATH); + return -1; + } + } + + if (chdir(SYSLOG_PATH)) { + perror("cd " SYSLOG_PATH); + return -1; + } + + return 0; +} + +static void sighandler(int signo) +{ + switch (signo) { + case SIGINT: + case SIGTERM: + syslog_run = 0; + break; + default: + break; + } +} + +static void signal_setup(void) +{ + struct sigaction act; + + memset(&act, 0, sizeof(act)); + act.sa_handler = sighandler; + + sigaction(SIGINT, &act, NULL); + sigaction(SIGTERM, &act, NULL); +} + +static int print_to_log(int facility, int level, const char *data) +{ + const char *fac_name, *lvl_str; + logfile_t *log; + + fac_name = enum_to_name(facilities, facility); + if (fac_name == NULL) + return -1; + + lvl_str = enum_to_name(levels, level); + if (lvl_str == NULL) + return -1; + + for (log = logfiles; log != NULL; log = log->next) { + if (!strcmp(log->name, fac_name)) + break; + } + + if (log == NULL) { + log = logfile_create(fac_name); + if (log == NULL) + return -1; + log->next = logfiles; + logfiles = log; + } + + logfile_write(log, "[%s] %s", lvl_str, data); + return 0; +} + +static int handle_data(int fd) +{ + char buffer[2048], *ptr; + int i = 0, priority; + ssize_t ret; + + memset(buffer, 0, sizeof(buffer)); + + ret = read(fd, buffer, sizeof(buffer)); + if (ret <= 0) + return -1; + + for (ptr = buffer; isspace(*ptr); ++ptr) + ; + if (*(ptr++) != '<') + 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); +} + +int main(void) +{ + int sfd, status = EXIT_FAILURE; + logfile_t *log; + + signal_setup(); + + sfd = mksock(SYSLOG_SOCKET, SOCK_FLAG_EVERYONE | SOCK_FLAG_DGRAM); + if (sfd < 0) + return EXIT_FAILURE; + + if (directory_setup()) + goto out; + + while (syslog_run) { + handle_data(sfd); + } + + status = EXIT_SUCCESS; +out: + while (logfiles != NULL) { + log = logfiles; + logfiles = logfiles->next; + + logfile_destroy(log); + } + if (sfd > 0) + close(sfd); + unlink(SYSLOG_SOCKET); + return status; +}