From d9f883f2151a026d25277d57d56aa045417dd3bb Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Wed, 6 Jun 2018 14:59:12 +0200 Subject: [PATCH] Add utility for producing syslog message from the shell This can can be used by shell scripts to produce syslog messages, as well as aiding in debugging the usyslogd daemon. Signed-off-by: David Oberhollenzer --- .gitignore | 1 + Makefile.am | 1 + cmd/Makemodule.am | 10 ++ cmd/syslog.c | 236 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 248 insertions(+) create mode 100644 cmd/syslog.c diff --git a/.gitignore b/.gitignore index 256a460..44d1ad5 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,7 @@ reboot shutdown killall5 runsvc +syslog usyslogd services/sigkill diff --git a/Makefile.am b/Makefile.am index 09fa4ef..bdee5cb 100644 --- a/Makefile.am +++ b/Makefile.am @@ -3,6 +3,7 @@ ACLOCAL_AMFLAGS = -I m4 AM_CPPFLAGS = -D_GNU_SOURCE -I$(top_srcdir)/lib/include AM_CFLAGS = $(WARN_CFLAGS) +bin_PROGRAMS = sbin_PROGRAMS = noinst_LIBRARIES = nobase_sysconf_DATA = netcfg/ifrename diff --git a/cmd/Makemodule.am b/cmd/Makemodule.am index f92610c..f4559a9 100644 --- a/cmd/Makemodule.am +++ b/cmd/Makemodule.am @@ -32,6 +32,16 @@ service_CFLAGS = $(AM_CFLAGS) service_LDFLAGS = $(AM_LDFLAGS) service_LDADD = libinit.a libcfg.a +if USYSLOGD +syslog_SOURCES = cmd/syslog.c +syslog_CPPFLAGS = $(AM_CPPFLAGS) +syslog_CFLAGS = $(AM_CFLAGS) +syslog_LDFLAGS = $(AM_LDFLAGS) +syslog_LDADD = libinit.a + +bin_PROGRAMS += syslog +endif + EXTRA_DIST += $(SRVHEADERS) sbin_PROGRAMS += service reboot shutdown diff --git a/cmd/syslog.c b/cmd/syslog.c new file mode 100644 index 0000000..d225921 --- /dev/null +++ b/cmd/syslog.c @@ -0,0 +1,236 @@ +/* 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 "util.h" + +static int facility = LOG_USER; +static int level = LOG_INFO; +static int flags = LOG_NDELAY | LOG_NOWAIT; +static const char *ident = "(shell)"; + +static const enum_map_t facility_map[] = { + { "auth", LOG_AUTH }, + { "cron", LOG_CRON }, + { "daemon", LOG_DAEMON }, + { "ftp", LOG_FTP }, + { "local0", LOG_LOCAL0 }, + { "local1", LOG_LOCAL1 }, + { "local2", LOG_LOCAL2 }, + { "local3", LOG_LOCAL3 }, + { "local4", LOG_LOCAL4 }, + { "local5", LOG_LOCAL5 }, + { "local6", LOG_LOCAL6 }, + { "local7", LOG_LOCAL7 }, + { "lpr", LOG_LPR }, + { "news", LOG_NEWS }, + { "user", LOG_USER }, + { "uucp", LOG_UUCP }, + { NULL, 0 }, +}; + +static const enum_map_t level_map[] = { + { "emergency", LOG_EMERG }, + { "alert", LOG_ALERT }, + { "critical", LOG_CRIT }, + { "error", LOG_ERR }, + { "warning", LOG_WARNING }, + { "notice", LOG_NOTICE }, + { "info", LOG_INFO }, + { "debug", LOG_DEBUG }, + { NULL, 0 }, +}; + +static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version", no_argument, NULL, 'V' }, + { "console", required_argument, NULL, 'c' }, + { "facility", required_argument, NULL, 'f' }, + { "level", required_argument, NULL, 'l' }, + { "ident", required_argument, NULL, 'i' }, + { NULL, 0, NULL, 0 }, +}; + +static const char *shortopt = "hVcf:l:i:"; + +static const char *versiontext = +"syslog (Pygos init) "PACKAGE_VERSION"\n" +"Copyright (C) 2018 David Oberhollenzer\n" +"License GPLv3+: GNU GPL version 3 or later .\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 const char *helptext = +"Usage: syslog [OPTION]... [STRING]...\n\n" +"Concatenate the given STRINGs and send a log message to the syslog daemon.\n" +"\n" +"The following OPTIONSs can be used:\n" +" -f, --facility Logging facilty name or numeric identifier.\n" +" -l, --level Log level name or numeric identifier.\n" +" -i, --ident Program name for log syslog message.\n" +" Default is %s.\n\n" +" -c, --console Write to the console if opening the syslog\n" +" socket fails.\n\n" +" -h, --help Print this help text and exit\n" +" -V, --version Print version information and exit\n\n"; + +static void print_map(const enum_map_t *map, int defaultval, + const char *option) +{ + size_t i; + + printf("The following values can be used for %s:\n", option); + + for (i = 0; map[i].name != NULL; ++i) { + if (map[i].value == defaultval) { + printf(" %s (=%d), set as default\n", + map[i].name, map[i].value); + } else { + printf(" %s (=%d)\n", map[i].name, map[i].value); + } + } + + fputc('\n', stdout); +} + +static NORETURN void usage(int status) +{ + if (status != EXIT_SUCCESS) { + fputs("Try `syslog --help' for more information\n", stderr); + } else { + printf(helptext, ident); + print_map(level_map, level, "--level"); + print_map(facility_map, facility, "--facility"); + } + + exit(status); +} + +static NORETURN void version(void) +{ + fputs(versiontext, stdout); + exit(EXIT_SUCCESS); +} + +static int readint(const char *str) +{ + int x = 0; + + if (!isdigit(*str)) + return -1; + + while (isdigit(*str)) + x = x * 10 + (*(str++)) - '0'; + + return (*str == '\0') ? x : -1; +} + +static void process_options(int argc, char **argv) +{ + const enum_map_t *e; + int c; + + for (;;) { + c = getopt_long(argc, argv, shortopt, options, NULL); + if (c == -1) + break; + + switch (c) { + case 'f': + facility = readint(optarg); + if (facility >= 0) + break; + e = enum_by_name(facility_map, optarg); + if (e == NULL) { + fprintf(stderr, "Unknown facility name '%s'\n", + optarg); + usage(EXIT_FAILURE); + } + facility = e->value; + break; + case 'l': + level = readint(optarg); + if (level >= 0) + break; + e = enum_by_name(level_map, optarg); + if (e == NULL) { + fprintf(stderr, "Unknown log level '%s'\n", + optarg); + usage(EXIT_FAILURE); + } + level = e->value; + break; + case 'i': + ident = optarg; + break; + case 'c': + flags |= LOG_CONS; + break; + case 'h': + usage(EXIT_SUCCESS); + case 'V': + version(); + default: + usage(EXIT_FAILURE); + } + } +} + + +int main(int argc, char **argv) +{ + size_t len = 0; + char *str; + int i; + + process_options(argc, argv); + + if (optind >= argc) { + fputs("Error: no log string provided.\n", stderr); + usage(EXIT_FAILURE); + } + + for (i = optind; i < argc; ++i) + len += strlen(argv[i]); + + len += argc - optind - 1; + + str = calloc(1, len + 1); + if (str == NULL) { + fputs("syslog: out of memory\n", stderr); + return EXIT_FAILURE; + } + + for (i = optind; i < argc; ++i) { + if (i > optind) + strcat(str, " "); + strcat(str, argv[i]); + } + + openlog(ident, flags, facility); + syslog(level, "%s", str); + closelog(); + + free(str); + return EXIT_SUCCESS; +} +