chiark / gitweb /
journal: add new system-cat tool as kind of a more powerfull BSD logger
authorLennart Poettering <lennart@poettering.net>
Fri, 13 Jan 2012 22:17:54 +0000 (23:17 +0100)
committerLennart Poettering <lennart@poettering.net>
Sat, 14 Jan 2012 00:54:33 +0000 (01:54 +0100)
.gitignore
Makefile.am
src/journal/cat.c [new file with mode: 0644]

index 8daf8f0..c260210 100644 (file)
@@ -1,3 +1,4 @@
+/systemd-cat
 /systemd-rc-local-generator
 /libsystemd-id128.pc
 systemd-journalctl
index 42da4fb..d94de56 100644 (file)
@@ -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 (file)
index 0000000..6745f1c
--- /dev/null
@@ -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;
+}