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;
+}