]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/journal/journalctl.c
a couple of fixes to make llvm-analyze quiet
[thirdparty/systemd.git] / src / journal / journalctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2011 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/poll.h>
30 #include <time.h>
31 #include <getopt.h>
32
33 #include <systemd/sd-journal.h>
34
35 #include "log.h"
36 #include "util.h"
37 #include "build.h"
38 #include "pager.h"
39 #include "logs-show.h"
40
41 static OutputMode arg_output = OUTPUT_SHORT;
42 static bool arg_follow = false;
43 static bool arg_show_all = false;
44 static bool arg_no_pager = false;
45 static int arg_lines = -1;
46 static bool arg_no_tail = false;
47 static bool arg_new_id128 = false;
48 static bool arg_quiet = false;
49
50 static int help(void) {
51
52 printf("%s [OPTIONS...] {COMMAND} ...\n\n"
53 "Send control commands to or query the journal.\n\n"
54 " -h --help Show this help\n"
55 " --version Show package version\n"
56 " --no-pager Do not pipe output into a pager\n"
57 " -a --all Show all properties, including long and unprintable\n"
58 " -f --follow Follow journal\n"
59 " -n --lines=INTEGER Journal entries to show\n"
60 " --no-tail Show all lines, even in follow mode\n"
61 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
62 " verbose, export, json, cat)\n"
63 " -q --quiet Don't show privilege warning\n"
64 " --new-id128 Generate a new 128 Bit id\n",
65 program_invocation_short_name);
66
67 return 0;
68 }
69
70 static int parse_argv(int argc, char *argv[]) {
71
72 enum {
73 ARG_VERSION = 0x100,
74 ARG_NO_PAGER,
75 ARG_NO_TAIL,
76 ARG_NEW_ID128
77 };
78
79 static const struct option options[] = {
80 { "help", no_argument, NULL, 'h' },
81 { "version" , no_argument, NULL, ARG_VERSION },
82 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
83 { "follow", no_argument, NULL, 'f' },
84 { "output", required_argument, NULL, 'o' },
85 { "all", no_argument, NULL, 'a' },
86 { "lines", required_argument, NULL, 'n' },
87 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
88 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
89 { "quiet", no_argument, NULL, 'q' },
90 { NULL, 0, NULL, 0 }
91 };
92
93 int c, r;
94
95 assert(argc >= 0);
96 assert(argv);
97
98 while ((c = getopt_long(argc, argv, "hfo:an:q", options, NULL)) >= 0) {
99
100 switch (c) {
101
102 case 'h':
103 help();
104 return 0;
105
106 case ARG_VERSION:
107 puts(PACKAGE_STRING);
108 puts(DISTRIBUTION);
109 puts(SYSTEMD_FEATURES);
110 return 0;
111
112 case ARG_NO_PAGER:
113 arg_no_pager = true;
114 break;
115
116 case 'f':
117 arg_follow = true;
118 break;
119
120 case 'o':
121 arg_output = output_mode_from_string(optarg);
122 if (arg_output < 0) {
123 log_error("Unknown output '%s'.", optarg);
124 return -EINVAL;
125 }
126
127 break;
128
129 case 'a':
130 arg_show_all = true;
131 break;
132
133 case 'n':
134 r = safe_atoi(optarg, &arg_lines);
135 if (r < 0 || arg_lines < 0) {
136 log_error("Failed to parse lines '%s'", optarg);
137 return -EINVAL;
138 }
139 break;
140
141 case ARG_NO_TAIL:
142 arg_no_tail = true;
143 break;
144
145 case ARG_NEW_ID128:
146 arg_new_id128 = true;
147 break;
148
149 case 'q':
150 arg_quiet = true;
151 break;
152
153 case '?':
154 return -EINVAL;
155
156 default:
157 log_error("Unknown option code %c", c);
158 return -EINVAL;
159 }
160 }
161
162 if (arg_follow && !arg_no_tail && arg_lines < 0)
163 arg_lines = 10;
164
165 return 1;
166 }
167
168 static int generate_new_id128(void) {
169 sd_id128_t id;
170 int r;
171 unsigned i;
172
173 r = sd_id128_randomize(&id);
174 if (r < 0) {
175 log_error("Failed to generate ID: %s", strerror(-r));
176 return r;
177 }
178
179 printf("As string:\n"
180 SD_ID128_FORMAT_STR "\n\n"
181 "As UUID:\n"
182 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
183 "As macro:\n"
184 "#define MESSAGE_XYZ SD_ID128_MAKE(",
185 SD_ID128_FORMAT_VAL(id),
186 SD_ID128_FORMAT_VAL(id));
187
188 for (i = 0; i < 16; i++)
189 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
190
191 fputs(")\n", stdout);
192
193 return 0;
194 }
195
196 int main(int argc, char *argv[]) {
197 int r, i, fd;
198 sd_journal *j = NULL;
199 unsigned line = 0;
200 bool need_seek = false;
201
202 log_parse_environment();
203 log_open();
204
205 r = parse_argv(argc, argv);
206 if (r <= 0)
207 goto finish;
208
209 if (arg_new_id128) {
210 r = generate_new_id128();
211 goto finish;
212 }
213
214 #ifdef HAVE_ACL
215 if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
216 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this message off.");
217 #endif
218
219 r = sd_journal_open(&j, 0);
220 if (r < 0) {
221 log_error("Failed to open journal: %s", strerror(-r));
222 goto finish;
223 }
224
225 for (i = optind; i < argc; i++) {
226 r = sd_journal_add_match(j, argv[i], strlen(argv[i]));
227 if (r < 0) {
228 log_error("Failed to add match: %s", strerror(-r));
229 goto finish;
230 }
231 }
232
233 fd = sd_journal_get_fd(j);
234 if (fd < 0) {
235 log_error("Failed to get wakeup fd: %s", strerror(-fd));
236 goto finish;
237 }
238
239 if (arg_lines >= 0) {
240 r = sd_journal_seek_tail(j);
241 if (r < 0) {
242 log_error("Failed to seek to tail: %s", strerror(-r));
243 goto finish;
244 }
245
246 r = sd_journal_previous_skip(j, arg_lines);
247 } else {
248 r = sd_journal_seek_head(j);
249 if (r < 0) {
250 log_error("Failed to seek to head: %s", strerror(-r));
251 goto finish;
252 }
253
254 r = sd_journal_next(j);
255 }
256
257 if (r < 0) {
258 log_error("Failed to iterate through journal: %s", strerror(-r));
259 goto finish;
260 }
261
262 if (!arg_no_pager && !arg_follow) {
263 columns();
264 pager_open();
265 }
266
267 if (arg_output == OUTPUT_JSON) {
268 fputc('[', stdout);
269 fflush(stdout);
270 }
271
272 for (;;) {
273 for (;;) {
274 if (need_seek) {
275 r = sd_journal_next(j);
276 if (r < 0) {
277 log_error("Failed to iterate through journal: %s", strerror(-r));
278 goto finish;
279 }
280 }
281
282 if (r == 0)
283 break;
284
285 line ++;
286
287 r = output_journal(j, arg_output, line, 0, arg_show_all);
288 if (r < 0)
289 goto finish;
290
291 need_seek = true;
292 }
293
294 if (!arg_follow)
295 break;
296
297 r = fd_wait_for_event(fd, POLLIN, (usec_t) -1);
298 if (r < 0) {
299 log_error("Couldn't wait for event: %s", strerror(-r));
300 goto finish;
301 }
302
303 r = sd_journal_process(j);
304 if (r < 0) {
305 log_error("Failed to process: %s", strerror(-r));
306 goto finish;
307 }
308 }
309
310 if (arg_output == OUTPUT_JSON)
311 fputs("\n]\n", stdout);
312
313 finish:
314 if (j)
315 sd_journal_close(j);
316
317 pager_close();
318
319 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
320 }