755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering/***
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering This file is part of systemd.
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering Copyright 2012 Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering systemd is free software; you can redistribute it and/or modify it
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering under the terms of the GNU Lesser General Public License as published by
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering the Free Software Foundation; either version 2.1 of the License, or
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering (at your option) any later version.
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering systemd is distributed in the hope that it will be useful, but
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering WITHOUT ANY WARRANTY; without even the implied warranty of
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering Lesser General Public License for more details.
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
5430f7f2bc7330f3088b894166bf3524a067e3d8Lennart Poettering You should have received a copy of the GNU Lesser General Public License
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering along with systemd; If not, see <http://www.gnu.org/licenses/>.
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering***/
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering#include <errno.h>
abad76cc4c8586bc088fec65560cf4db2e0903c2Zbigniew Jędrzejewski-Szmek#include <fcntl.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <getopt.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <stdio.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <stdlib.h>
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include <unistd.h>
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering#include "sd-journal.h"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
3ffd4af22052963e7a29431721ee204e634bea75Lennart Poettering#include "fd-util.h"
6bedfcbb2970e06a4d3280c8fb62083d252ede73Lennart Poettering#include "parse-util.h"
07630cea1f3a845c09309f197ac7c4f11edd3b62Lennart Poettering#include "string-util.h"
7ccbd1ae843d77275f2c542582a9a80e5e058a70Lennart Poettering#include "syslog-util.h"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering#include "util.h"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
2afcd6902b5c04e8b05c9d1ffd8bc6175fac6efbLennart Poetteringstatic const char *arg_identifier = NULL;
d508ac0ba0c43efa8caacdd8050970efb1e30243Lennart Poetteringstatic int arg_priority = LOG_INFO;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poetteringstatic bool arg_level_prefix = true;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmekstatic void help(void) {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering printf("%s [OPTIONS...] {COMMAND} ...\n\n"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering "Execute process with stdout/stderr connected to the journal.\n\n"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering " -h --help Show this help\n"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering " --version Show package version\n"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering " -t --identifier=STRING Set syslog identifier\n"
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering " -p --priority=PRIORITY Set priority value (0..7)\n"
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek " --level-prefix=BOOL Control whether level prefix shall be parsed\n"
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek , program_invocation_short_name);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering}
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poetteringstatic int parse_argv(int argc, char *argv[]) {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering enum {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering ARG_VERSION = 0x100,
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering ARG_LEVEL_PREFIX
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering };
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering static const struct option options[] = {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering { "help", no_argument, NULL, 'h' },
9aac0b2c19c558b853da7a6d67a0929b2d44dee4Lennart Poettering { "version", no_argument, NULL, ARG_VERSION },
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering { "identifier", required_argument, NULL, 't' },
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering { "priority", required_argument, NULL, 'p' },
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX },
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering {}
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering };
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering int c;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering assert(argc >= 0);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering assert(argv);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0)
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering switch (c) {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering case 'h':
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek help();
601185b43da638b1c74153deae01dbd518680889Zbigniew Jędrzejewski-Szmek return 0;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering case ARG_VERSION:
3f6fd1ba65f962702753c4ad284b588e59689a23Lennart Poettering return version();
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering case 't':
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (isempty(optarg))
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering arg_identifier = NULL;
2afcd6902b5c04e8b05c9d1ffd8bc6175fac6efbLennart Poettering else
2afcd6902b5c04e8b05c9d1ffd8bc6175fac6efbLennart Poettering arg_identifier = optarg;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering break;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering case 'p':
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering arg_priority = log_level_from_string(optarg);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (arg_priority < 0) {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering log_error("Failed to parse priority value.");
e4603df5cf80bbd7a7d51fc66fa6c60e042423bcLennart Poettering return -EINVAL;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering }
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering break;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering case ARG_LEVEL_PREFIX: {
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering int k;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering k = parse_boolean(optarg);
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering if (k < 0)
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering return log_error_errno(k, "Failed to parse level prefix value.");
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering arg_level_prefix = k;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering break;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering }
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering case '?':
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering return -EINVAL;
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering default:
eb9da376d76b48585b3b63b4f91903b54f7abd36Lennart Poettering assert_not_reached("Unhandled option");
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering }
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering return 1;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering}
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poetteringint main(int argc, char *argv[]) {
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering _cleanup_close_ int fd = -1, saved_stderr = -1;
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering int r;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering log_parse_environment();
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering log_open();
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering r = parse_argv(argc, argv);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (r <= 0)
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering goto finish;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering fd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (fd < 0) {
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering r = log_error_errno(fd, "Failed to create stream fd: %m");
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering goto finish;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering }
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (dup3(fd, STDOUT_FILENO, 0) < 0 ||
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering dup3(fd, STDERR_FILENO, 0) < 0) {
76ef789d264f9eb7d7624b994aa6eead1dacfac4Lennart Poettering r = log_error_errno(errno, "Failed to duplicate fd: %m");
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering goto finish;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering }
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (fd >= 3)
03e334a1c7dc8c20c38902aa039440763acc9b17Lennart Poettering safe_close(fd);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering fd = -1;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (argc <= optind)
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering (void) execl("/bin/cat", "/bin/cat", NULL);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering else
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering (void) execvp(argv[optind], argv + optind);
9aac0b2c19c558b853da7a6d67a0929b2d44dee4Lennart Poettering r = -errno;
9aac0b2c19c558b853da7a6d67a0929b2d44dee4Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering /* Let's try to restore a working stderr, so we can print the error message */
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering if (saved_stderr >= 0)
939c173f60c4cc1e2ce8cbf014910b13c53358bbLennart Poettering (void) dup3(saved_stderr, STDERR_FILENO, 0);
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
da927ba997d68401563b927f92e6e40e021a8e5cMichal Schmidt log_error_errno(r, "Failed to execute process: %m");
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poetteringfinish:
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
755a02c6800246e7e293897d0594fe7e7531ba59Lennart Poettering}