diff options
author | Lennart Poettering <lennart@poettering.net> | 2012-01-13 23:17:54 +0100 |
---|---|---|
committer | Lennart Poettering <lennart@poettering.net> | 2012-01-14 01:54:33 +0100 |
commit | 755a02c6800246e7e293897d0594fe7e7531ba59 (patch) | |
tree | 6466acaaddf50cb29f4f9b55425191365ee32c6e | |
parent | 3043935f02da2e680b37cf282587106ad05440ee (diff) |
journal: add new system-cat tool as kind of a more powerfull BSD logger
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | Makefile.am | 10 | ||||
-rw-r--r-- | src/journal/cat.c | 181 |
3 files changed, 192 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore index 8daf8f0a8e..c260210311 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ +/systemd-cat /systemd-rc-local-generator /libsystemd-id128.pc systemd-journalctl diff --git a/Makefile.am b/Makefile.am index 42da4fb753..d94de56ff1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1237,6 +1237,13 @@ systemd_journald_LDADD += \ $(XZ_LIBS) endif +systemd_cat_SOURCES = \ + src/journal/cat.c + +systemd_cat_LDADD = \ + libsystemd-basic.la \ + libsystemd-journal.la + systemd_journalctl_SOURCES = \ src/journal/journalctl.c \ src/pager.c \ @@ -1345,6 +1352,9 @@ rootlibexec_PROGRAMS += \ rootbin_PROGRAMS += \ systemd-journalctl +bin_PROGRAMS += \ + systemd-cat + dist_systemunit_DATA += \ units/systemd-journald.socket diff --git a/src/journal/cat.c b/src/journal/cat.c new file mode 100644 index 0000000000..6745f1ce0a --- /dev/null +++ b/src/journal/cat.c @@ -0,0 +1,181 @@ +/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/ + +/*** + This file is part of systemd. + + Copyright 2012 Lennart Poettering + + systemd 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 2 of the License, or + (at your option) any later version. + + systemd 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 systemd; If not, see <http://www.gnu.org/licenses/>. +***/ + +#include <stdio.h> +#include <getopt.h> +#include <assert.h> +#include <unistd.h> +#include <stdlib.h> +#include <errno.h> +#include <sys/fcntl.h> + +#include <systemd/sd-journal.h> + +#include "util.h" +#include "build.h" + +static char *arg_identifier = NULL; +static char arg_priority = LOG_INFO; +static bool arg_level_prefix = true; + +static int help(void) { + + printf("%s [OPTIONS...] {COMMAND} ...\n\n" + "Execute process with stdout/stderr connected to the journal.\n\n" + " -h --help Show this help\n" + " --version Show package version\n" + " -t --identifier=STRING Set syslog identifier\n" + " -p --priority=PRIORITY Set priority value (0..7)\n" + " --level-prefix=BOOL Control whether level prefix shall be parsed\n", + program_invocation_short_name); + + return 0; +} + +static int parse_argv(int argc, char *argv[]) { + + enum { + ARG_VERSION = 0x100, + ARG_LEVEL_PREFIX + }; + + static const struct option options[] = { + { "help", no_argument, NULL, 'h' }, + { "version" , no_argument, NULL, ARG_VERSION }, + { "identifier", required_argument, NULL, 't' }, + { "priority", required_argument, NULL, 'p' }, + { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX }, + { NULL, 0, NULL, 0 } + }; + + int c; + + assert(argc >= 0); + assert(argv); + + while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) { + + switch (c) { + + case 'h': + help(); + return 0; + + case ARG_VERSION: + puts(PACKAGE_STRING); + puts(DISTRIBUTION); + puts(SYSTEMD_FEATURES); + return 0; + + case 't': + free(arg_identifier); + if (isempty(optarg)) + arg_identifier = NULL; + else { + arg_identifier = strdup(optarg); + if (!arg_identifier) { + log_error("Out of memory."); + return -ENOMEM; + } + } + break; + + case 'p': + arg_priority = log_level_from_string(optarg); + if (arg_priority < 0) { + log_error("Failed to parse priority value."); + return arg_priority; + } + break; + + case ARG_LEVEL_PREFIX: { + int k; + + k = parse_boolean(optarg); + if (k < 0) { + log_error("Failed to parse level prefix value."); + return k; + } + arg_level_prefix = k; + break; + } + + default: + log_error("Unknown option code %c", c); + return -EINVAL; + } + } + + return 1; +} + +int main(int argc, char *argv[]) { + int r, fd = -1, saved_stderr = -1; + + log_parse_environment(); + log_open(); + + r = parse_argv(argc, argv); + if (r <= 0) + goto finish; + + fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); + if (fd < 0) { + log_error("Failed to create stream fd: %s", strerror(fd)); + r = fd; + goto finish; + } + + saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); + + if (dup3(fd, STDOUT_FILENO, 0) < 0 || + dup3(fd, STDERR_FILENO, 0) < 0) { + log_error("Failed to duplicate fd: %s", strerror(fd)); + r = -errno; + goto finish; + } + + if (fd >= 3) + close_nointr_nofail(fd); + + fd = -1; + + if (argc <= optind) + execl("/bin/cat", "/bin/cat", NULL); + else + execvp(argv[optind], argv + optind); + + /* Let's try to restore a working stderr, so we can print the error message */ + if (saved_stderr >= 0) + dup3(saved_stderr, STDERR_FILENO, 0); + + log_error("Failed to execute process: %m"); + r = -errno; + +finish: + if (fd >= 0) + close_nointr_nofail(fd); + + if (saved_stderr >= 0) + close_nointr_nofail(saved_stderr); + + return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS; +} |