mirror of
https://github.com/pygos/usyslog.git
synced 2024-12-05 01:47:03 +01:00
Initial import
Signed-off-by: David Oberhollenzer <david.oberhollenzer@tele2.at>
This commit is contained in:
commit
a4423189ab
12 changed files with 1260 additions and 0 deletions
19
.gitignore
vendored
Normal file
19
.gitignore
vendored
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
.deps
|
||||||
|
Makefile
|
||||||
|
Makefile.in
|
||||||
|
aclocal.m4
|
||||||
|
autom4te.cache
|
||||||
|
compile
|
||||||
|
config.h.in
|
||||||
|
config.log
|
||||||
|
config.status
|
||||||
|
configure
|
||||||
|
depcomp
|
||||||
|
install-sh
|
||||||
|
missing
|
||||||
|
stamp-h1
|
||||||
|
config.h
|
||||||
|
*.o
|
||||||
|
*~
|
||||||
|
klogd
|
||||||
|
usyslogd
|
11
Makefile.am
Normal file
11
Makefile.am
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
ACLOCAL_AMFLAGS = -I m4
|
||||||
|
|
||||||
|
AM_CPPFLAGS = -D_GNU_SOURCE
|
||||||
|
AM_CFLAGS = $(WARN_CFLAGS)
|
||||||
|
|
||||||
|
usyslogd_SOURCES = syslogd.c syslogd.h proto.c logfile.c mksock.c protomap.c
|
||||||
|
klogd_SOURCES = klogd.c
|
||||||
|
|
||||||
|
bin_PROGRAMS =
|
||||||
|
sbin_PROGRAMS = usyslogd klogd
|
||||||
|
# EXTRA_DIST = README LICENSE
|
3
autogen.sh
Executable file
3
autogen.sh
Executable file
|
@ -0,0 +1,3 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
autoreconf --force --install --symlink
|
35
configure.ac
Normal file
35
configure.ac
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
AC_PREREQ([2.60])
|
||||||
|
AC_INIT([usyslog], [0.1], [david.oberhollenzer@tele2.at], usyslog)
|
||||||
|
AC_CONFIG_MACRO_DIR([m4])
|
||||||
|
AM_INIT_AUTOMAKE([foreign dist-xz])
|
||||||
|
AM_SILENT_RULES([yes])
|
||||||
|
AC_PROG_CC
|
||||||
|
AC_PROG_CC_C99
|
||||||
|
AC_PROG_INSTALL
|
||||||
|
|
||||||
|
UL_WARN_ADD([-Wall])
|
||||||
|
UL_WARN_ADD([-Wextra])
|
||||||
|
UL_WARN_ADD([-Wunused])
|
||||||
|
UL_WARN_ADD([-Wmissing-prototypes])
|
||||||
|
UL_WARN_ADD([-Wmissing-declarations])
|
||||||
|
UL_WARN_ADD([-Wwrite-strings])
|
||||||
|
UL_WARN_ADD([-Wjump-misses-init])
|
||||||
|
UL_WARN_ADD([-Wuninitialized])
|
||||||
|
UL_WARN_ADD([-Winit-self])
|
||||||
|
UL_WARN_ADD([-Wlogical-op])
|
||||||
|
UL_WARN_ADD([-Wunused-but-set-parameter])
|
||||||
|
UL_WARN_ADD([-Wunused-but-set-variable])
|
||||||
|
UL_WARN_ADD([-Wunused-parameter])
|
||||||
|
UL_WARN_ADD([-Wunused-result])
|
||||||
|
UL_WARN_ADD([-Wunused-variable])
|
||||||
|
UL_WARN_ADD([-Wduplicated-cond])
|
||||||
|
UL_WARN_ADD([-Wduplicated-branches])
|
||||||
|
UL_WARN_ADD([-Wrestrict])
|
||||||
|
UL_WARN_ADD([-Wnull-dereference])
|
||||||
|
UL_WARN_ADD([-pedantic])
|
||||||
|
|
||||||
|
AC_SUBST([WARN_CFLAGS])
|
||||||
|
|
||||||
|
AC_CONFIG_HEADERS([config.h])
|
||||||
|
|
||||||
|
AC_OUTPUT([Makefile])
|
193
klogd.c
Normal file
193
klogd.c
Normal file
|
@ -0,0 +1,193 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <sys/klog.h>
|
||||||
|
#include <syslog.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
enum {
|
||||||
|
KLOG_CLOSE = 0,
|
||||||
|
KLOG_OPEN = 1,
|
||||||
|
KLOG_READ = 2,
|
||||||
|
KLOG_CONSOLE_OFF = 6,
|
||||||
|
KLOG_CONSOLE_ON = 7,
|
||||||
|
KLOG_CONSOLE_LEVEL = 8,
|
||||||
|
};
|
||||||
|
|
||||||
|
static char log_buffer[4096];
|
||||||
|
static sig_atomic_t running = 1;
|
||||||
|
static int level = 0;
|
||||||
|
|
||||||
|
static const struct option options[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "level", required_argument, NULL, 'l' },
|
||||||
|
{ NULL, 0, NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *shortopt = "hVl:";
|
||||||
|
|
||||||
|
static const char *helptext =
|
||||||
|
"Usage: klogd [OPTION]... \n\n"
|
||||||
|
"Collect printk() messages from the kernel and forward them to syslogd.\n"
|
||||||
|
"\n"
|
||||||
|
"The following OPTIONSs can be used:\n"
|
||||||
|
" -l, --level <level> Minimum log level that should be printed to console.\n"
|
||||||
|
" If not set, logging to console is turned off.\n"
|
||||||
|
" -h, --help Print this help text and exit\n"
|
||||||
|
" -V, --version Print version information and exit\n\n";
|
||||||
|
|
||||||
|
#define GPL_URL "https://gnu.org/licenses/gpl.html"
|
||||||
|
|
||||||
|
static const char *version_string =
|
||||||
|
"klogd (usyslog) " PACKAGE_VERSION "\n"
|
||||||
|
"Copyright (C) 2018 David Oberhollenzer\n\n"
|
||||||
|
"License GPLv3+: GNU GPL version 3 or later <" GPL_URL ">.\n"
|
||||||
|
"This is free software: you are free to change and redistribute it.\n"
|
||||||
|
"There is NO WARRANTY, to the extent permitted by law.\n";
|
||||||
|
|
||||||
|
static void process_options(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
c = getopt_long(argc, argv, shortopt, options, NULL);
|
||||||
|
if (c == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (c) {
|
||||||
|
case 'l':
|
||||||
|
level = strtoul(optarg, NULL, 10);
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
fputs(helptext, stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'V':
|
||||||
|
fputs(version_string, stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
default:
|
||||||
|
fputs("Try `klogd --help' for more information\n",
|
||||||
|
stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sighandler(int signo)
|
||||||
|
{
|
||||||
|
if (signo == SIGTERM || signo == SIGINT)
|
||||||
|
running = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void sigsetup(void)
|
||||||
|
{
|
||||||
|
struct sigaction act;
|
||||||
|
sigset_t mask;
|
||||||
|
|
||||||
|
memset(&act, 0, sizeof(act));
|
||||||
|
act.sa_handler = sighandler;
|
||||||
|
sigaction(SIGTERM, &act, NULL);
|
||||||
|
sigaction(SIGINT, &act, NULL);
|
||||||
|
|
||||||
|
sigfillset(&mask);
|
||||||
|
sigdelset(&mask, SIGTERM);
|
||||||
|
sigdelset(&mask, SIGINT);
|
||||||
|
sigprocmask(SIG_SETMASK, &mask, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_open(void)
|
||||||
|
{
|
||||||
|
klogctl(KLOG_OPEN, NULL, 0);
|
||||||
|
|
||||||
|
if (level) {
|
||||||
|
klogctl(KLOG_CONSOLE_LEVEL, NULL, level);
|
||||||
|
} else {
|
||||||
|
klogctl(KLOG_CONSOLE_OFF, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
openlog("kernel", 0, LOG_KERN);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void log_close(void)
|
||||||
|
{
|
||||||
|
klogctl(KLOG_CONSOLE_ON, NULL, 0);
|
||||||
|
klogctl(KLOG_CLOSE, NULL, 0);
|
||||||
|
syslog(LOG_NOTICE, "-- klogd terminating --");
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int diff, count = 0, priority, ret = EXIT_SUCCESS;
|
||||||
|
char *ptr, *end;
|
||||||
|
|
||||||
|
process_options(argc, argv);
|
||||||
|
sigsetup();
|
||||||
|
log_open();
|
||||||
|
|
||||||
|
/* TODO: seccomp lockdown? */
|
||||||
|
|
||||||
|
while (running) {
|
||||||
|
diff = klogctl(KLOG_READ, log_buffer + count,
|
||||||
|
sizeof(log_buffer) - 1 - count);
|
||||||
|
|
||||||
|
if (diff < 0) {
|
||||||
|
if (errno == EINTR)
|
||||||
|
continue;
|
||||||
|
syslog(LOG_CRIT, "klogctl read: %s", strerror(errno));
|
||||||
|
ret = EXIT_FAILURE;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
count += diff;
|
||||||
|
log_buffer[count] = '\0';
|
||||||
|
ptr = log_buffer;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
end = strchr(ptr, '\n');
|
||||||
|
if (end == NULL) {
|
||||||
|
count = strlen(ptr);
|
||||||
|
memmove(log_buffer, ptr, count);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(end++) = '\0';
|
||||||
|
priority = LOG_INFO;
|
||||||
|
|
||||||
|
if (*ptr == '<') {
|
||||||
|
++ptr;
|
||||||
|
if (*ptr)
|
||||||
|
priority = strtoul(ptr, &ptr, 10);
|
||||||
|
if (*ptr == '>')
|
||||||
|
++ptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*ptr)
|
||||||
|
syslog(priority, "%s", ptr);
|
||||||
|
ptr = end;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
log_close();
|
||||||
|
return ret;
|
||||||
|
}
|
242
logfile.c
Normal file
242
logfile.c
Normal file
|
@ -0,0 +1,242 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "syslogd.h"
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct logfile_t {
|
||||||
|
struct logfile_t *next;
|
||||||
|
size_t size;
|
||||||
|
int fd;
|
||||||
|
char filename[];
|
||||||
|
} logfile_t;
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
log_backend_t base;
|
||||||
|
logfile_t *list;
|
||||||
|
size_t maxsize;
|
||||||
|
int flags;
|
||||||
|
} log_backend_file_t;
|
||||||
|
|
||||||
|
|
||||||
|
static int logfile_open(logfile_t *file)
|
||||||
|
{
|
||||||
|
struct stat sb;
|
||||||
|
|
||||||
|
file->fd = open(file->filename, O_WRONLY | O_CREAT, 0640);
|
||||||
|
if (file->fd < 0) {
|
||||||
|
perror(file->filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (lseek(file->fd, 0, SEEK_END))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
if (fstat(file->fd, &sb))
|
||||||
|
goto fail;
|
||||||
|
|
||||||
|
file->size = sb.st_size;
|
||||||
|
return 0;
|
||||||
|
fail:
|
||||||
|
perror(file->filename);
|
||||||
|
close(file->fd);
|
||||||
|
file->fd = -1;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static logfile_t *logfile_create(const char *filename)
|
||||||
|
{
|
||||||
|
logfile_t *file = calloc(1, sizeof(*file) + strlen(filename) + 1);
|
||||||
|
|
||||||
|
if (file == NULL) {
|
||||||
|
perror("calloc");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
strcpy(file->filename, filename);
|
||||||
|
|
||||||
|
if (logfile_open(file)) {
|
||||||
|
free(file);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return file;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int logfile_write(logfile_t *file, const syslog_msg_t *msg)
|
||||||
|
{
|
||||||
|
const char *lvl_str, *fac_name;
|
||||||
|
char timebuf[32];
|
||||||
|
struct tm tm;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
if (file->fd < 0 && logfile_open(file) != 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
lvl_str = level_id_to_string(msg->level);
|
||||||
|
if (lvl_str == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
gmtime_r(&msg->timestamp, &tm);
|
||||||
|
strftime(timebuf, sizeof(timebuf), "%FT%T", &tm);
|
||||||
|
|
||||||
|
if (msg->ident != NULL) {
|
||||||
|
fac_name = facility_id_to_string(msg->facility);
|
||||||
|
if (fac_name == NULL)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
ret = dprintf(file->fd, "[%s][%s][%s][%u] %s\n", timebuf,
|
||||||
|
fac_name, lvl_str, msg->pid, msg->message);
|
||||||
|
} else {
|
||||||
|
ret = dprintf(file->fd, "[%s][%s][%u] %s\n", timebuf, lvl_str,
|
||||||
|
msg->pid, msg->message);
|
||||||
|
}
|
||||||
|
|
||||||
|
fsync(file->fd);
|
||||||
|
|
||||||
|
if (ret > 0)
|
||||||
|
file->size += ret;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int logfile_rotate(logfile_t *f, int flags)
|
||||||
|
{
|
||||||
|
char timebuf[32];
|
||||||
|
char *filename;
|
||||||
|
struct tm tm;
|
||||||
|
time_t now;
|
||||||
|
|
||||||
|
if (flags & LOG_ROTATE_OVERWRITE) {
|
||||||
|
strcpy(timebuf, "1");
|
||||||
|
} else {
|
||||||
|
now = time(NULL);
|
||||||
|
gmtime_r(&now, &tm);
|
||||||
|
strftime(timebuf, sizeof(timebuf), "%FT%T", &tm);
|
||||||
|
}
|
||||||
|
|
||||||
|
filename = alloca(strlen(f->filename) + strlen(timebuf) + 2);
|
||||||
|
sprintf(filename, "%s.%s", f->filename, timebuf);
|
||||||
|
|
||||||
|
if (rename(f->filename, filename)) {
|
||||||
|
perror(filename);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
close(f->fd);
|
||||||
|
logfile_open(f);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*****************************************************************************/
|
||||||
|
|
||||||
|
static int file_backend_init(log_backend_t *backend, int flags,
|
||||||
|
size_t sizelimit)
|
||||||
|
{
|
||||||
|
log_backend_file_t *log = (log_backend_file_t *)backend;
|
||||||
|
|
||||||
|
log->flags = flags;
|
||||||
|
log->maxsize = sizelimit;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_backend_cleanup(log_backend_t *backend)
|
||||||
|
{
|
||||||
|
log_backend_file_t *log = (log_backend_file_t *)backend;
|
||||||
|
logfile_t *f;
|
||||||
|
|
||||||
|
while (log->list != NULL) {
|
||||||
|
f = log->list;
|
||||||
|
log->list = f->next;
|
||||||
|
|
||||||
|
close(f->fd);
|
||||||
|
free(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int file_backend_write(log_backend_t *backend, const syslog_msg_t *msg)
|
||||||
|
{
|
||||||
|
log_backend_file_t *log = (log_backend_file_t *)backend;
|
||||||
|
const char *ident;
|
||||||
|
char *filename;
|
||||||
|
logfile_t *f;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (msg->ident != NULL) {
|
||||||
|
ident = msg->ident;
|
||||||
|
} else {
|
||||||
|
ident = facility_id_to_string(msg->facility);
|
||||||
|
if (ident == NULL)
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = strlen(ident) + strlen(".log") + 1;
|
||||||
|
filename = alloca(len);
|
||||||
|
strcpy(filename, ident);
|
||||||
|
strcat(filename, ".log");
|
||||||
|
|
||||||
|
for (f = log->list; f != NULL; f = f->next) {
|
||||||
|
if (strcmp(filename, f->filename) == 0)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (f == NULL) {
|
||||||
|
f = logfile_create(filename);
|
||||||
|
if (f == NULL)
|
||||||
|
return -1;
|
||||||
|
f->next = log->list;
|
||||||
|
log->list = f;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (logfile_write(f, msg))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if ((log->flags & LOG_ROTATE_SIZE_LIMIT) && f->size >= log->maxsize)
|
||||||
|
logfile_rotate(f, log->flags);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void file_backend_rotate(log_backend_t *backend)
|
||||||
|
{
|
||||||
|
log_backend_file_t *log = (log_backend_file_t *)backend;
|
||||||
|
logfile_t *f;
|
||||||
|
|
||||||
|
for (f = log->list; f != NULL; f = f->next)
|
||||||
|
logfile_rotate(f, log->flags);
|
||||||
|
}
|
||||||
|
|
||||||
|
log_backend_file_t filebackend = {
|
||||||
|
.base = {
|
||||||
|
.init = file_backend_init,
|
||||||
|
.cleanup = file_backend_cleanup,
|
||||||
|
.write = file_backend_write,
|
||||||
|
.rotate = file_backend_rotate,
|
||||||
|
},
|
||||||
|
.list = NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
log_backend_t *logmgr = (log_backend_t *)&filebackend;
|
40
m4/compiler.m4
Normal file
40
m4/compiler.m4
Normal file
|
@ -0,0 +1,40 @@
|
||||||
|
dnl Copyright (C) 2008-2011 Free Software Foundation, Inc.
|
||||||
|
dnl This file is free software; the Free Software Foundation
|
||||||
|
dnl gives unlimited permission to copy and/or distribute it,
|
||||||
|
dnl with or without modifications, as long as this notice is preserved.
|
||||||
|
|
||||||
|
dnl From Simon Josefsson
|
||||||
|
dnl -- derivated from coreutils m4/warnings.m4
|
||||||
|
|
||||||
|
# UL_AS_VAR_APPEND(VAR, VALUE)
|
||||||
|
# ----------------------------
|
||||||
|
# Provide the functionality of AS_VAR_APPEND if Autoconf does not have it.
|
||||||
|
m4_ifdef([AS_VAR_APPEND],
|
||||||
|
[m4_copy([AS_VAR_APPEND], [UL_AS_VAR_APPEND])],
|
||||||
|
[m4_define([UL_AS_VAR_APPEND],
|
||||||
|
[AS_VAR_SET([$1], [AS_VAR_GET([$1])$2])])])
|
||||||
|
|
||||||
|
# UL_ADD_WARN(COMPILER_OPTION [, VARNAME])
|
||||||
|
# ------------------------
|
||||||
|
# Adds parameter to WARN_CFLAGS (or to $VARNAME) if the compiler supports it.
|
||||||
|
AC_DEFUN([UL_WARN_ADD], [
|
||||||
|
m4_define([warnvarname], m4_default([$2],WARN_CFLAGS))
|
||||||
|
AS_VAR_PUSHDEF([ul_Warn], [ul_cv_warn_$1])dnl
|
||||||
|
AC_CACHE_CHECK([whether compiler handles $1], m4_defn([ul_Warn]), [
|
||||||
|
# store AC_LANG_WERROR status, then turn it on
|
||||||
|
save_ac_[]_AC_LANG_ABBREV[]_werror_flag="${ac_[]_AC_LANG_ABBREV[]_werror_flag}"
|
||||||
|
AC_LANG_WERROR
|
||||||
|
|
||||||
|
ul_save_CPPFLAGS="$CPPFLAGS"
|
||||||
|
CPPFLAGS="-Werror ${CPPFLAGS} $1"
|
||||||
|
AC_PREPROC_IFELSE([AC_LANG_PROGRAM([])],
|
||||||
|
[AS_VAR_SET(ul_Warn, [yes])],
|
||||||
|
[AS_VAR_SET(ul_Warn, [no])])
|
||||||
|
# restore AC_LANG_WERROR
|
||||||
|
ac_[]_AC_LANG_ABBREV[]_werror_flag="${save_ac_[]_AC_LANG_ABBREV[]_werror_flag}"
|
||||||
|
|
||||||
|
CPPFLAGS="$ul_save_CPPFLAGS"
|
||||||
|
])
|
||||||
|
AS_VAR_IF(ul_Warn, [yes], [UL_AS_VAR_APPEND(warnvarname, [" $1"])])
|
||||||
|
])
|
||||||
|
|
63
mksock.c
Normal file
63
mksock.c
Normal file
|
@ -0,0 +1,63 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#include "syslogd.h"
|
||||||
|
|
||||||
|
int mksock(const char *path)
|
||||||
|
{
|
||||||
|
struct sockaddr_un un;
|
||||||
|
const char *errmsg;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
|
||||||
|
if (fd < 0) {
|
||||||
|
perror("socket");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(&un, 0, sizeof(un));
|
||||||
|
un.sun_family = AF_UNIX;
|
||||||
|
|
||||||
|
strcpy(un.sun_path, path);
|
||||||
|
|
||||||
|
if (bind(fd, (struct sockaddr *)&un, sizeof(un))) {
|
||||||
|
errmsg ="bind";
|
||||||
|
goto fail_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chmod(path, 0777)) {
|
||||||
|
errmsg = "chmod";
|
||||||
|
goto fail_errno;
|
||||||
|
}
|
||||||
|
|
||||||
|
return fd;
|
||||||
|
fail_errno:
|
||||||
|
fprintf(stderr, "%s: %s: %s\n", path, errmsg, strerror(errno));
|
||||||
|
close(fd);
|
||||||
|
unlink(path);
|
||||||
|
return -1;
|
||||||
|
}
|
194
proto.c
Normal file
194
proto.c
Normal file
|
@ -0,0 +1,194 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "syslogd.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;
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ident != NULL && ident[0] == '\0')
|
||||||
|
ident = NULL;
|
||||||
|
|
||||||
|
msg->timestamp = mktime(&tstamp);
|
||||||
|
msg->pid = pid;
|
||||||
|
msg->ident = ident;
|
||||||
|
msg->message = str;
|
||||||
|
|
||||||
|
len = strlen(str);
|
||||||
|
while (len > 0 && isspace(str[len - 1]))
|
||||||
|
--len;
|
||||||
|
str[len] = '\0';
|
||||||
|
|
||||||
|
if (ident != NULL) {
|
||||||
|
for (ptr = ident; *ptr != '\0'; ++ptr) {
|
||||||
|
if (!isalnum(*ptr))
|
||||||
|
*ptr = '_';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
81
protomap.c
Normal file
81
protomap.c
Normal file
|
@ -0,0 +1,81 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include "syslogd.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
const char *name;
|
||||||
|
int id;
|
||||||
|
} enum_map_t;
|
||||||
|
|
||||||
|
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 const enum_map_t facilities[] = {
|
||||||
|
{ "kernel", 0 },
|
||||||
|
{ "user", 1 },
|
||||||
|
{ "mail", 2 },
|
||||||
|
{ "daemon", 3 },
|
||||||
|
{ "auth", 4 },
|
||||||
|
{ "syslog", 5 },
|
||||||
|
{ "lpr", 6 },
|
||||||
|
{ "news", 7 },
|
||||||
|
{ "uucp", 8 },
|
||||||
|
{ "clock", 9 },
|
||||||
|
{ "authpriv", 10 },
|
||||||
|
{ "ftp", 11 },
|
||||||
|
{ "ntp", 12 },
|
||||||
|
{ "audit", 13 },
|
||||||
|
{ "alert", 14 },
|
||||||
|
{ "cron", 15 },
|
||||||
|
{ "local0", 16 },
|
||||||
|
{ "local1", 17 },
|
||||||
|
{ "local2", 18 },
|
||||||
|
{ "local3", 19 },
|
||||||
|
{ "local4", 20 },
|
||||||
|
{ "local5", 21 },
|
||||||
|
{ "local6", 22 },
|
||||||
|
{ "local7", 23 },
|
||||||
|
{ NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *enum_to_name(const enum_map_t *map, int id)
|
||||||
|
{
|
||||||
|
while (map->name != NULL && map->id != id)
|
||||||
|
++map;
|
||||||
|
|
||||||
|
return map->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *level_id_to_string(int level)
|
||||||
|
{
|
||||||
|
return enum_to_name(levels, level);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *facility_id_to_string(int level)
|
||||||
|
{
|
||||||
|
return enum_to_name(facilities, level);
|
||||||
|
}
|
282
syslogd.c
Normal file
282
syslogd.c
Normal file
|
@ -0,0 +1,282 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <signal.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <getopt.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
#include "syslogd.h"
|
||||||
|
|
||||||
|
static const struct option long_opts[] = {
|
||||||
|
{ "help", no_argument, NULL, 'h' },
|
||||||
|
{ "version", no_argument, NULL, 'V' },
|
||||||
|
{ "rotate-replace", no_argument, NULL, 'r' },
|
||||||
|
{ "chroot", no_argument, NULL, 'c' },
|
||||||
|
{ "max-size", required_argument, NULL, 'm' },
|
||||||
|
{ "user", required_argument, NULL, 'u' },
|
||||||
|
{ "group", required_argument, NULL, 'g' },
|
||||||
|
{ NULL, 0, NULL, 0 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const char *short_opts = "hVcrm:u:g:";
|
||||||
|
|
||||||
|
const char *usage_string =
|
||||||
|
"Usage: usyslogd [OPTIONS..]\n\n"
|
||||||
|
"The following options are supported:\n"
|
||||||
|
" -h, --help Print this help text and exit\n"
|
||||||
|
" -V, --version Print version information and exit\n"
|
||||||
|
" -r, --rotate-replace Replace old log files when doing log rotation.\n"
|
||||||
|
" -m, --max-size <size> Automatically rotate log files bigger than this.\n"
|
||||||
|
" -u, --user <name> Run the syslog daemon as this user. If not set,\n"
|
||||||
|
" try to use the user '" DEFAULT_USER "'.\n"
|
||||||
|
" -g, --group <name> Run the syslog daemon as this group. If not set,\n"
|
||||||
|
" try to use the group '" DEFAULT_GROUP "'.\n"
|
||||||
|
" -c, --chroot If set, do a chroot into the log file path.\n";
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static volatile sig_atomic_t syslog_run = 1;
|
||||||
|
static volatile sig_atomic_t syslog_rotate = 0;
|
||||||
|
static int log_flags = 0;
|
||||||
|
static size_t max_size = 0;
|
||||||
|
static uid_t uid = 0;
|
||||||
|
static gid_t gid = 0;
|
||||||
|
static bool dochroot = false;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
static void sighandler(int signo)
|
||||||
|
{
|
||||||
|
switch (signo) {
|
||||||
|
case SIGINT:
|
||||||
|
case SIGTERM:
|
||||||
|
syslog_run = 0;
|
||||||
|
break;
|
||||||
|
case SIGHUP:
|
||||||
|
syslog_rotate = 1;
|
||||||
|
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);
|
||||||
|
sigaction(SIGHUP, &act, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int handle_data(int fd)
|
||||||
|
{
|
||||||
|
char buffer[2048];
|
||||||
|
syslog_msg_t msg;
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
memset(buffer, 0, sizeof(buffer));
|
||||||
|
|
||||||
|
ret = read(fd, buffer, sizeof(buffer));
|
||||||
|
if (ret <= 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (syslog_msg_parse(&msg, buffer))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return logmgr->write(logmgr, &msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define GPL_URL "https://gnu.org/licenses/gpl.html"
|
||||||
|
|
||||||
|
static const char *version_string =
|
||||||
|
"usyslogd (usyslog) " PACKAGE_VERSION "\n"
|
||||||
|
"Copyright (C) 2018 David Oberhollenzer\n\n"
|
||||||
|
"License GPLv3+: GNU GPL version 3 or later <" GPL_URL ">.\n"
|
||||||
|
"This is free software: you are free to change and redistribute it.\n"
|
||||||
|
"There is NO WARRANTY, to the extent permitted by law.\n";
|
||||||
|
|
||||||
|
static void process_options(int argc, char **argv)
|
||||||
|
{
|
||||||
|
struct passwd *pw = getpwnam(DEFAULT_USER);
|
||||||
|
struct group *grp = getgrnam(DEFAULT_GROUP);
|
||||||
|
char *end;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
if (pw != NULL)
|
||||||
|
uid = pw->pw_uid;
|
||||||
|
|
||||||
|
if (grp != NULL)
|
||||||
|
gid = grp->gr_gid;
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
i = getopt_long(argc, argv, short_opts, long_opts, NULL);
|
||||||
|
if (i == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
switch (i) {
|
||||||
|
case 'r':
|
||||||
|
log_flags |= LOG_ROTATE_OVERWRITE;
|
||||||
|
break;
|
||||||
|
case 'm':
|
||||||
|
log_flags |= LOG_ROTATE_SIZE_LIMIT;
|
||||||
|
max_size = strtol(optarg, &end, 10);
|
||||||
|
if (max_size == 0 || *end != '\0') {
|
||||||
|
fputs("Numeric argument > 0 expected for -m\n",
|
||||||
|
stderr);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
pw = getpwnam(optarg);
|
||||||
|
if (pw == NULL) {
|
||||||
|
fprintf(stderr, "Cannot get UID for user %s\n",
|
||||||
|
optarg);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
uid = pw->pw_uid;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
grp = getgrnam(optarg);
|
||||||
|
if (grp == NULL) {
|
||||||
|
fprintf(stderr,
|
||||||
|
"Cannot get GID for group %s\n",
|
||||||
|
optarg);
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
gid = grp->gr_gid;
|
||||||
|
break;
|
||||||
|
case 'c':
|
||||||
|
dochroot = true;
|
||||||
|
break;
|
||||||
|
case 'h':
|
||||||
|
fputs(usage_string, stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
case 'V':
|
||||||
|
fputs(version_string, stdout);
|
||||||
|
exit(EXIT_SUCCESS);
|
||||||
|
default:
|
||||||
|
goto fail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
fail:
|
||||||
|
fputs("Try `usyslogd --help' for more information\n", stderr);
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int chroot_setup(void)
|
||||||
|
{
|
||||||
|
if (mkdir(SYSLOG_PATH, 0750)) {
|
||||||
|
if (errno != EEXIST) {
|
||||||
|
perror("mkdir " SYSLOG_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uid > 0 && gid > 0 && chown(SYSLOG_PATH, uid, gid) != 0) {
|
||||||
|
perror("chown " SYSLOG_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chmod(SYSLOG_PATH, 0750)) {
|
||||||
|
perror("chmod " SYSLOG_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chdir(SYSLOG_PATH)) {
|
||||||
|
perror("cd " SYSLOG_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dochroot && chroot(SYSLOG_PATH) != 0) {
|
||||||
|
perror("chroot " SYSLOG_PATH);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int user_setup(void)
|
||||||
|
{
|
||||||
|
if (gid > 0 && setresgid(gid, gid, gid) != 0) {
|
||||||
|
perror("setgid");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if (uid > 0 && setresuid(uid, uid, uid) != 0) {
|
||||||
|
perror("setuid");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int sfd, status = EXIT_FAILURE;
|
||||||
|
|
||||||
|
process_options(argc, argv);
|
||||||
|
|
||||||
|
signal_setup();
|
||||||
|
|
||||||
|
sfd = mksock(SYSLOG_SOCKET);
|
||||||
|
if (sfd < 0)
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (uid > 0 && gid > 0 && chown(SYSLOG_SOCKET, uid, gid) != 0) {
|
||||||
|
perror("chown " SYSLOG_SOCKET);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (chroot_setup())
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (user_setup())
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
|
||||||
|
if (logmgr->init(logmgr, log_flags, max_size))
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
while (syslog_run) {
|
||||||
|
if (syslog_rotate) {
|
||||||
|
logmgr->rotate(logmgr);
|
||||||
|
syslog_rotate = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
handle_data(sfd);
|
||||||
|
}
|
||||||
|
|
||||||
|
status = EXIT_SUCCESS;
|
||||||
|
out:
|
||||||
|
logmgr->cleanup(logmgr);
|
||||||
|
if (sfd > 0)
|
||||||
|
close(sfd);
|
||||||
|
unlink(SYSLOG_SOCKET);
|
||||||
|
return status;
|
||||||
|
}
|
97
syslogd.h
Normal file
97
syslogd.h
Normal file
|
@ -0,0 +1,97 @@
|
||||||
|
/* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
#ifndef SYSLOGD_H
|
||||||
|
#define SYSLOGD_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
#include "config.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define SYSLOG_SOCKET "/dev/log"
|
||||||
|
#define SYSLOG_PATH "/var/log"
|
||||||
|
#define DEFAULT_USER "syslogd"
|
||||||
|
#define DEFAULT_GROUP "syslogd"
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
encapsulates the split up data from a message received
|
||||||
|
through the local syslog socket.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
int facility;
|
||||||
|
int level;
|
||||||
|
time_t timestamp;
|
||||||
|
pid_t pid;
|
||||||
|
const char *ident;
|
||||||
|
const char *message;
|
||||||
|
} syslog_msg_t;
|
||||||
|
|
||||||
|
|
||||||
|
enum {
|
||||||
|
/*
|
||||||
|
Rotate log data in a way that we still generate a continuous stream
|
||||||
|
of log data. E.g. in the case of log files, move the current log file
|
||||||
|
to one suffixed with a timestamp. We don't lose any log data.
|
||||||
|
*/
|
||||||
|
LOG_ROTATE_CONTINUOUS = 0x00,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Rotate log data by overwriting old data with more recent data.
|
||||||
|
E.g. in the case of log files, move the current log file to one
|
||||||
|
with a constant prefix, overwriting any existing data.
|
||||||
|
*/
|
||||||
|
LOG_ROTATE_OVERWRITE = 0x01,
|
||||||
|
|
||||||
|
/*
|
||||||
|
Automatically do a log rotatation if a log stream reaches a preset
|
||||||
|
size limit.
|
||||||
|
*/
|
||||||
|
LOG_ROTATE_SIZE_LIMIT = 0x10,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct log_backend_t {
|
||||||
|
int (*init)(struct log_backend_t *log, int flags, size_t sizelimit);
|
||||||
|
|
||||||
|
void (*cleanup)(struct log_backend_t *log);
|
||||||
|
|
||||||
|
int (*write)(struct log_backend_t *log, const syslog_msg_t *msg);
|
||||||
|
|
||||||
|
void (*rotate)(struct log_backend_t *log);
|
||||||
|
} log_backend_t;
|
||||||
|
|
||||||
|
|
||||||
|
extern log_backend_t *logmgr;
|
||||||
|
|
||||||
|
/*
|
||||||
|
Parse a message string received from the syslog socket and produce
|
||||||
|
a split up representation for the message.
|
||||||
|
*/
|
||||||
|
int syslog_msg_parse(syslog_msg_t *msg, char *str);
|
||||||
|
|
||||||
|
/* Create a unix DGRAM socket. */
|
||||||
|
int mksock(const char *path);
|
||||||
|
|
||||||
|
const char *level_id_to_string(int level);
|
||||||
|
|
||||||
|
const char *facility_id_to_string(int level);
|
||||||
|
|
||||||
|
#endif /* LOGFILE_H */
|
Loading…
Reference in a new issue