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