]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/cat.c
Merge pull request #15891 from bluca/host_os_release
[thirdparty/systemd.git] / src / journal / cat.c
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 "terminal-util.h"
20 #include "util.h"
21
22 static const char *arg_identifier = NULL;
23 static int arg_priority = LOG_INFO;
24 static int arg_stderr_priority = -1;
25 static bool arg_level_prefix = true;
26
27 static int help(void) {
28 _cleanup_free_ char *link = NULL;
29 int r;
30
31 r = terminal_urlify_man("systemd-cat", "1", &link);
32 if (r < 0)
33 return log_oom();
34
35 printf("%s [OPTIONS...] COMMAND ...\n"
36 "\n%sExecute process with stdout/stderr connected to the journal.%s\n\n"
37 " -h --help Show this help\n"
38 " --version Show package version\n"
39 " -t --identifier=STRING Set syslog identifier\n"
40 " -p --priority=PRIORITY Set priority value (0..7)\n"
41 " --stderr-priority=PRIORITY Set priority value (0..7) used for stderr\n"
42 " --level-prefix=BOOL Control whether level prefix shall be parsed\n"
43 "\nSee the %s for details.\n"
44 , program_invocation_short_name
45 , ansi_highlight(), ansi_normal()
46 , link
47 );
48
49 return 0;
50 }
51
52 static int parse_argv(int argc, char *argv[]) {
53
54 enum {
55 ARG_VERSION = 0x100,
56 ARG_STDERR_PRIORITY,
57 ARG_LEVEL_PREFIX
58 };
59
60 static const struct option options[] = {
61 { "help", no_argument, NULL, 'h' },
62 { "version", no_argument, NULL, ARG_VERSION },
63 { "identifier", required_argument, NULL, 't' },
64 { "priority", required_argument, NULL, 'p' },
65 { "stderr-priority", required_argument, NULL, ARG_STDERR_PRIORITY },
66 { "level-prefix", required_argument, NULL, ARG_LEVEL_PREFIX },
67 {}
68 };
69
70 int c;
71
72 assert(argc >= 0);
73 assert(argv);
74
75 while ((c = getopt_long(argc, argv, "+ht:p:", options, NULL)) >= 0)
76
77 switch (c) {
78
79 case 'h':
80 help();
81 return 0;
82
83 case ARG_VERSION:
84 return version();
85
86 case 't':
87 if (isempty(optarg))
88 arg_identifier = NULL;
89 else
90 arg_identifier = optarg;
91 break;
92
93 case 'p':
94 arg_priority = log_level_from_string(optarg);
95 if (arg_priority < 0)
96 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
97 "Failed to parse priority value.");
98 break;
99
100 case ARG_STDERR_PRIORITY:
101 arg_stderr_priority = log_level_from_string(optarg);
102 if (arg_stderr_priority < 0)
103 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
104 "Failed to parse stderr priority value.");
105 break;
106
107 case ARG_LEVEL_PREFIX: {
108 int k;
109
110 k = parse_boolean(optarg);
111 if (k < 0)
112 return log_error_errno(k, "Failed to parse level prefix value.");
113
114 arg_level_prefix = k;
115 break;
116 }
117
118 case '?':
119 return -EINVAL;
120
121 default:
122 assert_not_reached("Unhandled option");
123 }
124
125 return 1;
126 }
127
128 static int run(int argc, char *argv[]) {
129 _cleanup_close_ int outfd = -1, errfd = -1, saved_stderr = -1;
130 int r;
131
132 log_setup_cli();
133
134 r = parse_argv(argc, argv);
135 if (r <= 0)
136 return r;
137
138 outfd = sd_journal_stream_fd(arg_identifier, arg_priority, arg_level_prefix);
139 if (outfd < 0)
140 return log_error_errno(outfd, "Failed to create stream fd: %m");
141
142 if (arg_stderr_priority >= 0 && arg_stderr_priority != arg_priority) {
143 errfd = sd_journal_stream_fd(arg_identifier, arg_stderr_priority, arg_level_prefix);
144 if (errfd < 0)
145 return log_error_errno(errfd, "Failed to create stream fd: %m");
146 }
147
148 saved_stderr = fcntl(STDERR_FILENO, F_DUPFD_CLOEXEC, 3);
149
150 r = rearrange_stdio(STDIN_FILENO, outfd, errfd < 0 ? outfd : errfd); /* Invalidates fd on success + error! */
151 TAKE_FD(outfd);
152 TAKE_FD(errfd);
153 if (r < 0)
154 return log_error_errno(r, "Failed to rearrange stdout/stderr: %m");
155
156 if (argc <= optind)
157 (void) execl("/bin/cat", "/bin/cat", NULL);
158 else
159 (void) execvp(argv[optind], argv + optind);
160 r = -errno;
161
162 /* Let's try to restore a working stderr, so we can print the error message */
163 if (saved_stderr >= 0)
164 (void) dup3(saved_stderr, STDERR_FILENO, 0);
165
166 return log_error_errno(r, "Failed to execute process: %m");
167 }
168
169 DEFINE_MAIN_FUNCTION(run);