/* 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 *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 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':
print_version("syslog");
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;
}