]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
755a02c6 | 2 | |
755a02c6 | 3 | #include <errno.h> |
abad76cc | 4 | #include <fcntl.h> |
3f6fd1ba LP |
5 | #include <getopt.h> |
6 | #include <stdio.h> | |
7 | #include <stdlib.h> | |
8 | #include <unistd.h> | |
755a02c6 | 9 | |
3f6fd1ba | 10 | #include "sd-journal.h" |
755a02c6 | 11 | |
37ec0fdd | 12 | #include "alloc-util.h" |
3ffd4af2 | 13 | #include "fd-util.h" |
5e332028 | 14 | #include "main-func.h" |
6bedfcbb | 15 | #include "parse-util.h" |
294bf0c3 | 16 | #include "pretty-print.h" |
07630cea | 17 | #include "string-util.h" |
7ccbd1ae | 18 | #include "syslog-util.h" |
5e332028 | 19 | #include "util.h" |
755a02c6 | 20 | |
2afcd690 | 21 | static const char *arg_identifier = NULL; |
d508ac0b | 22 | static int arg_priority = LOG_INFO; |
a08c3e8f | 23 | static int arg_stderr_priority = -1; |
755a02c6 LP |
24 | static bool arg_level_prefix = true; |
25 | ||
37ec0fdd LP |
26 | static int help(void) { |
27 | _cleanup_free_ char *link = NULL; | |
28 | int r; | |
29 | ||
30 | r = terminal_urlify_man("systemd-cat", "1", &link); | |
31 | if (r < 0) | |
32 | return log_oom(); | |
33 | ||
755a02c6 LP |
34 | printf("%s [OPTIONS...] {COMMAND} ...\n\n" |
35 | "Execute process with stdout/stderr connected to the journal.\n\n" | |
a08c3e8f MS |
36 | " -h --help Show this help\n" |
37 | " --version Show package version\n" | |
38 | " -t --identifier=STRING Set syslog identifier\n" | |
39 | " -p --priority=PRIORITY Set priority value (0..7)\n" | |
40 | " --stderr-priority=PRIORITY Set priority value (0..7) used for stderr\n" | |
41 | " --level-prefix=BOOL Control whether level prefix shall be parsed\n" | |
37ec0fdd LP |
42 | "\nSee the %s for details.\n" |
43 | , program_invocation_short_name | |
44 | , link | |
45 | ); | |
46 | ||
47 | return 0; | |
755a02c6 LP |
48 | } |
49 | ||
50 | static int parse_argv(int argc, char *argv[]) { | |
51 | ||
52 | enum { | |
53 | ARG_VERSION = 0x100, | |
a08c3e8f | 54 | ARG_STDERR_PRIORITY, |
755a02c6 LP |
55 | ARG_LEVEL_PREFIX |
56 | }; | |
57 | ||
58 | static const struct option options[] = { | |
a08c3e8f MS |
59 | { "help", no_argument, NULL, 'h' }, |
60 | { "version", no_argument, NULL, ARG_VERSION }, | |
61 | { "identifier", required_argument, NULL, 't' }, | |
62 | { "priority", required_argument, NULL, 'p' }, | |
63 | { "stderr-priority", required_argument, NULL, ARG_STDERR_PRIORITY }, | |
64 | { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX }, | |
eb9da376 | 65 | {} |
755a02c6 LP |
66 | }; |
67 | ||
68 | int c; | |
69 | ||
70 | assert(argc >= 0); | |
71 | assert(argv); | |
72 | ||
601185b4 | 73 | while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0) |
755a02c6 LP |
74 | |
75 | switch (c) { | |
76 | ||
77 | case 'h': | |
601185b4 ZJS |
78 | help(); |
79 | return 0; | |
755a02c6 LP |
80 | |
81 | case ARG_VERSION: | |
3f6fd1ba | 82 | return version(); |
755a02c6 LP |
83 | |
84 | case 't': | |
755a02c6 LP |
85 | if (isempty(optarg)) |
86 | arg_identifier = NULL; | |
2afcd690 LP |
87 | else |
88 | arg_identifier = optarg; | |
755a02c6 LP |
89 | break; |
90 | ||
91 | case 'p': | |
92 | arg_priority = log_level_from_string(optarg); | |
baaa35ad ZJS |
93 | if (arg_priority < 0) |
94 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
95 | "Failed to parse priority value."); | |
755a02c6 LP |
96 | break; |
97 | ||
a08c3e8f MS |
98 | case ARG_STDERR_PRIORITY: |
99 | arg_stderr_priority = log_level_from_string(optarg); | |
100 | if (arg_stderr_priority < 0) | |
101 | return log_error_errno(SYNTHETIC_ERRNO(EINVAL), | |
102 | "Failed to parse stderr priority value."); | |
103 | break; | |
104 | ||
755a02c6 LP |
105 | case ARG_LEVEL_PREFIX: { |
106 | int k; | |
107 | ||
108 | k = parse_boolean(optarg); | |
939c173f LP |
109 | if (k < 0) |
110 | return log_error_errno(k, "Failed to parse level prefix value."); | |
111 | ||
755a02c6 LP |
112 | arg_level_prefix = k; |
113 | break; | |
114 | } | |
115 | ||
eb9da376 | 116 | case '?': |
755a02c6 | 117 | return -EINVAL; |
eb9da376 LP |
118 | |
119 | default: | |
120 | assert_not_reached("Unhandled option"); | |
755a02c6 | 121 | } |
755a02c6 LP |
122 | |
123 | return 1; | |
124 | } | |
125 | ||
634a0ad3 | 126 | static int run(int argc, char *argv[]) { |
a08c3e8f | 127 | _cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1; |
939c173f | 128 | int r; |
755a02c6 LP |
129 | |
130 | log_parse_environment(); | |
131 | log_open(); | |
132 | ||
133 | r = parse_argv(argc, argv); | |
134 | if (r <= 0) | |
634a0ad3 | 135 | return r; |
755a02c6 | 136 | |
a08c3e8f MS |
137 | outfd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix); |
138 | if (outfd < 0) | |
139 | return log_error_errno(outfd, "Failed to create stream fd: %m"); | |
140 | ||
141 | if (arg_stderr_priority >= 0 && arg_stderr_priority != arg_priority) { | |
142 | errfd = sd_journal_stream_fd(arg_identifier, arg_stderr_priority, arg_level_prefix); | |
143 | if (errfd < 0) | |
144 | return log_error_errno(errfd, "Failed to create stream fd: %m"); | |
145 | } | |
755a02c6 LP |
146 | |
147 | saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3); | |
148 | ||
a08c3e8f MS |
149 | r = rearrange_stdio(STDIN_FILENO, outfd, errfd < 0 ? outfd : errfd); /* Invalidates fd on succcess + error! */ |
150 | TAKE_FD(outfd); | |
151 | TAKE_FD(errfd); | |
634a0ad3 ZJS |
152 | if (r < 0) |
153 | return log_error_errno(r, "Failed to rearrange stdout/stderr: %m"); | |
755a02c6 | 154 | |
755a02c6 | 155 | if (argc <= optind) |
939c173f | 156 | (void) execl("/bin/cat", "/bin/cat", NULL); |
755a02c6 | 157 | else |
939c173f | 158 | (void) execvp(argv[optind], argv + optind); |
9aac0b2c LP |
159 | r = -errno; |
160 | ||
755a02c6 LP |
161 | /* Let's try to restore a working stderr, so we can print the error message */ |
162 | if (saved_stderr >= 0) | |
939c173f | 163 | (void) dup3(saved_stderr, STDERR_FILENO, 0); |
755a02c6 | 164 | |
634a0ad3 | 165 | return log_error_errno(r, "Failed to execute process: %m"); |
755a02c6 | 166 | } |
634a0ad3 ZJS |
167 | |
168 | DEFINE_MAIN_FUNCTION(run); |