From 200daf7dbbce90d4006d7dbf53affa48a110ed00 Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Sun, 28 Oct 2018 13:29:42 +0100 Subject: [PATCH] Import syslog utility program Signed-off-by: David Oberhollenzer --- .gitignore | 1 + Makefile.am | 4 +- protomap.c | 24 ++++++- syslog.1 | 45 +++++++++++++ syslog.c | 184 ++++++++++++++++++++++++++++++++++++++++++++++++++++ syslogd.h | 6 +- 6 files changed, 260 insertions(+), 4 deletions(-) create mode 100644 syslog.1 create mode 100644 syslog.c diff --git a/.gitignore b/.gitignore index 9635e08..387cb50 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,4 @@ config.h *~ klogd usyslogd +syslog diff --git a/Makefile.am b/Makefile.am index ccfe661..f4719a3 100644 --- a/Makefile.am +++ b/Makefile.am @@ -5,7 +5,9 @@ AM_CFLAGS = $(WARN_CFLAGS) usyslogd_SOURCES = syslogd.c syslogd.h proto.c logfile.c mksock.c protomap.c klogd_SOURCES = klogd.c +syslog_SOURCES = syslog.c protomap.c -bin_PROGRAMS = +dist_man1_MANS = syslog.1 +bin_PROGRAMS = syslog sbin_PROGRAMS = usyslogd klogd EXTRA_DIST = LICENSE diff --git a/protomap.c b/protomap.c index 1ace2bb..60e2c6a 100644 --- a/protomap.c +++ b/protomap.c @@ -1,6 +1,8 @@ /* SPDX-License-Identifier: ISC */ #include "syslogd.h" +#include + typedef struct { const char *name; int id; @@ -54,12 +56,30 @@ static const char *enum_to_name(const enum_map_t *map, int id) return map->name; } +static int enum_by_name(const enum_map_t *map, const char *name) +{ + while (map->name != NULL && strcmp(map->name, name) != 0) + ++map; + + return map->name == NULL ? -1 : map->id; +} + const char *level_id_to_string(int level) { return enum_to_name(levels, level); } -const char *facility_id_to_string(int level) +const char *facility_id_to_string(int id) { - return enum_to_name(facilities, level); + return enum_to_name(facilities, id); +} + +int level_id_from_string(const char *level) +{ + return enum_by_name(levels, level); +} + +int facility_id_from_string(const char *fac) +{ + return enum_by_name(facilities, fac); } diff --git a/syslog.1 b/syslog.1 new file mode 100644 index 0000000..2990f90 --- /dev/null +++ b/syslog.1 @@ -0,0 +1,45 @@ +.TH syslog 1 "August 2018" "usyslog" +.SH NAME +syslog \- send a log message to the syslog daemon +.SH SYNOPSIS +.B syslog +[options] message.. +.SH DESCRIPTION +The syslog command concatenates all non option arguments to a single message +that it sends to the syslog daemon. +.SH OPTIONS +.TP +.BR \-h , " \-\-help" +Display a brief help text, a list of available facilities, log levels, all the +default setting and exit. +.TP +.BR \-V , " \-\-version" +Print version information and exit. +.TP +.BR \-f , " \-\-facility " \fIfacility\fP +Logging facility name or numeric identifier. Use +.B \-\-help +to get a list of all available facility names. +.TP +.BR \-l , " \-\-level " \fIlevel\fP +A log level number from 0 to 8 with 8 being most severe, or a name from +.I debug +to +.I emergency. +Use +.B \-\-help +to get a list of all available log level names. +.TP +.BR \-i , " \-\-ident " \fIname\fP +Program name to specify to syslog. If not set, "(shell)" is used as sensible +default to indicate that the message came from the command line. +.TP +.BR \-c , " \-\-console" +Try to write directly to the console if opening the syslog socket fails. +.SH AVAILABILITY +This program is part of the Pygos init system. +.SH COPYRIGHT +Copyright \(co 2018 David Oberhollenzer +.br +This is free software: you are free to change and redistribute it. +There is NO WARRANTY, to the extent permitted by law. diff --git a/syslog.c b/syslog.c new file mode 100644 index 0000000..024428a --- /dev/null +++ b/syslog.c @@ -0,0 +1,184 @@ +/* SPDX-License-Identifier: ISC */ +#include +#include +#include +#include +#include +#include + +#include "syslogd.h" + +static int facility = 1; +static int level = LOG_INFO; +static int flags = LOG_NDELAY | LOG_NOWAIT; +static const char *ident = "(shell)"; + +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 *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 const char *version_string = +"syslog (usyslog) " PACKAGE_VERSION "\n" +"Copyright (C) 2018 David Oberhollenzer\n\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 usage(int status) +{ + const char *str; + int i; + + if (status != EXIT_SUCCESS) { + fputs("Try `syslog --help' for more information\n", stderr); + } else { + printf(helptext, ident); + + fputs("The following values can be used for --level:\n", + stdout); + + i = 0; + while ((str = level_id_to_string(i)) != NULL) { + printf(" %s (=%d)%s\n", str, i, + i == level ? ", set as default" : ""); + ++i; + } + + fputs("\nThe following values can be used for --facility:\n", + stdout); + + i = 0; + while ((str = facility_id_to_string(i)) != NULL) { + printf(" %s (=%d)%s\n", str, i, + i == facility ? ", set as default" : ""); + ++i; + } + } + + exit(status); +} + +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) +{ + 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; + facility = facility_id_from_string(optarg); + if (facility < 0) { + fprintf(stderr, "Unknown facility name '%s'\n", + optarg); + usage(EXIT_FAILURE); + } + break; + case 'l': + level = readint(optarg); + if (level >= 0) + break; + level = level_id_from_string(optarg); + if (level < 0) { + fprintf(stderr, "Unknown log level '%s'\n", + optarg); + usage(EXIT_FAILURE); + } + break; + case 'i': + ident = optarg; + break; + case 'c': + flags |= LOG_CONS; + break; + case 'V': + fputs(version_string, stdout); + exit(EXIT_SUCCESS); + break; + case 'h': + usage(EXIT_SUCCESS); + break; + default: + usage(EXIT_FAILURE); + break; + } + } +} + + +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 << 3); + syslog(level, "%s", str); + closelog(); + + free(str); + return EXIT_SUCCESS; +} diff --git a/syslogd.h b/syslogd.h index 740d90e..0935d1a 100644 --- a/syslogd.h +++ b/syslogd.h @@ -76,6 +76,10 @@ int mksock(const char *path); const char *level_id_to_string(int level); -const char *facility_id_to_string(int level); +const char *facility_id_to_string(int id); + +int level_id_from_string(const char *level); + +int facility_id_from_string(const char *fac); #endif /* LOGFILE_H */