]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
Merge pull request #2507 from evverx/fix-q-on-tmpfs
[thirdparty/systemd.git] / src / journal / journalctl.c
CommitLineData
87d2c1ff
LP
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
5430f7f2
LP
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
87d2c1ff
LP
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
5430f7f2 16 Lesser General Public License for more details.
87d2c1ff 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
87d2c1ff
LP
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20***/
21
3f6fd1ba 22#include <errno.h>
87d2c1ff 23#include <fcntl.h>
ea18a4b5 24#include <fnmatch.h>
3f6fd1ba
LP
25#include <getopt.h>
26#include <linux/fs.h>
27#include <locale.h>
28#include <poll.h>
29#include <signal.h>
87d2c1ff 30#include <stddef.h>
3fbf9cbb 31#include <stdio.h>
3fbf9cbb 32#include <stdlib.h>
3f6fd1ba 33#include <string.h>
74055aa7 34#include <sys/inotify.h>
3f6fd1ba
LP
35#include <sys/stat.h>
36#include <unistd.h>
87d2c1ff 37
74055aa7 38#include "sd-bus.h"
3f6fd1ba
LP
39#include "sd-journal.h"
40
f8eeeaf9 41#include "acl-util.h"
b5efdb8a 42#include "alloc-util.h"
3f6fd1ba
LP
43#include "bus-error.h"
44#include "bus-util.h"
45#include "catalog.h"
c8b3094d 46#include "chattr-util.h"
3ffd4af2 47#include "fd-util.h"
68fee104 48#include "fileio.h"
f4f15635 49#include "fs-util.h"
3f6fd1ba 50#include "fsprg.h"
7d50b32a 51#include "glob-util.h"
3f6fd1ba 52#include "hostname-util.h"
c004493c 53#include "io-util.h"
7560fffc 54#include "journal-def.h"
3f6fd1ba 55#include "journal-internal.h"
f6a971bc 56#include "journal-qrcode.h"
dbd2a83f 57#include "journal-vacuum.h"
3f6fd1ba 58#include "journal-verify.h"
8752c575 59#include "locale-util.h"
3f6fd1ba
LP
60#include "log.h"
61#include "logs-show.h"
74055aa7 62#include "mkdir.h"
3f6fd1ba 63#include "pager.h"
6bedfcbb 64#include "parse-util.h"
3f6fd1ba 65#include "path-util.h"
78f22b97 66#include "rlimit-util.h"
3f6fd1ba
LP
67#include "set.h"
68#include "sigbus.h"
69#include "strv.h"
7ccbd1ae 70#include "syslog-util.h"
288a74cc 71#include "terminal-util.h"
795ab08f
MS
72#include "udev.h"
73#include "udev-util.h"
3f6fd1ba 74#include "unit-name.h"
b1d4f8e1 75#include "user-util.h"
7560fffc 76
baed47c3 77#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
250d54b5 78
97e1cc8b
LP
79enum {
80 /* Special values for arg_lines */
81 ARG_LINES_DEFAULT = -2,
82 ARG_LINES_ALL = -1,
83};
84
df50185b 85static OutputMode arg_output = OUTPUT_SHORT;
9fd29044 86static bool arg_utc = false;
1b12a7b5 87static bool arg_pager_end = false;
72f59706 88static bool arg_follow = false;
2b8f6883 89static bool arg_full = true;
cd4b13e0 90static bool arg_all = false;
0d43c694 91static bool arg_no_pager = false;
97e1cc8b 92static int arg_lines = ARG_LINES_DEFAULT;
e91af489 93static bool arg_no_tail = false;
43673799 94static bool arg_quiet = false;
9e8a535f 95static bool arg_merge = false;
d121b396 96static bool arg_boot = false;
442e2def
LP
97static sd_id128_t arg_boot_id = {};
98static int arg_boot_offset = 0;
99271804 99static bool arg_dmesg = false;
8f14c832 100static const char *arg_cursor = NULL;
248fc619
ZJS
101static const char *arg_after_cursor = NULL;
102static bool arg_show_cursor = false;
a963990f 103static const char *arg_directory = NULL;
8d98da3f 104static char **arg_file = NULL;
941e990d 105static int arg_priorities = 0xFF;
baed47c3 106static const char *arg_verify_key = NULL;
feb12d3e 107#ifdef HAVE_GCRYPT
baed47c3 108static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
b8547c10 109static bool arg_force = false;
feb12d3e 110#endif
cfbc22ab
LP
111static usec_t arg_since, arg_until;
112static bool arg_since_set = false, arg_until_set = false;
73083640 113static char **arg_syslog_identifier = NULL;
b9e40524
HH
114static char **arg_system_units = NULL;
115static char **arg_user_units = NULL;
3c1668da 116static const char *arg_field = NULL;
d4205751 117static bool arg_catalog = false;
d89d6c86 118static bool arg_reverse = false;
3f3a438f 119static int arg_journal_type = 0;
0f03c2a4 120static char *arg_root = NULL;
b6741478 121static const char *arg_machine = NULL;
8580d1f7
LP
122static uint64_t arg_vacuum_size = 0;
123static uint64_t arg_vacuum_n_files = 0;
124static usec_t arg_vacuum_time = 0;
50f20cfd 125
7560fffc
LP
126static enum {
127 ACTION_SHOW,
128 ACTION_NEW_ID128,
129 ACTION_PRINT_HEADER,
beec0085 130 ACTION_SETUP_KEYS,
a1a03e30
LP
131 ACTION_VERIFY,
132 ACTION_DISK_USAGE,
d4205751 133 ACTION_LIST_CATALOG,
54b7254c 134 ACTION_DUMP_CATALOG,
f1188074
ZJS
135 ACTION_UPDATE_CATALOG,
136 ACTION_LIST_BOOTS,
74055aa7 137 ACTION_FLUSH,
a020b3b3 138 ACTION_SYNC,
e3fdfb49 139 ACTION_ROTATE,
dbd2a83f 140 ACTION_VACUUM,
7560fffc
LP
141} arg_action = ACTION_SHOW;
142
45bc27b6 143typedef struct BootId {
a331b5e6 144 sd_id128_t id;
f1188074
ZJS
145 uint64_t first;
146 uint64_t last;
45bc27b6
LP
147 LIST_FIELDS(struct BootId, boot_list);
148} BootId;
a331b5e6 149
795ab08f
MS
150static int add_matches_for_device(sd_journal *j, const char *devpath) {
151 int r;
152 _cleanup_udev_unref_ struct udev *udev = NULL;
153 _cleanup_udev_device_unref_ struct udev_device *device = NULL;
154 struct udev_device *d = NULL;
155 struct stat st;
156
157 assert(j);
158 assert(devpath);
159
160 if (!path_startswith(devpath, "/dev/")) {
161 log_error("Devpath does not start with /dev/");
162 return -EINVAL;
163 }
164
165 udev = udev_new();
166 if (!udev)
167 return log_oom();
168
169 r = stat(devpath, &st);
170 if (r < 0)
171 log_error_errno(errno, "Couldn't stat file: %m");
172
173 d = device = udev_device_new_from_devnum(udev, S_ISBLK(st.st_mode) ? 'b' : 'c', st.st_rdev);
174 if (!device)
175 return log_error_errno(errno, "Failed to get udev device from devnum %u:%u: %m", major(st.st_rdev), minor(st.st_rdev));
176
177 while (d) {
178 _cleanup_free_ char *match = NULL;
179 const char *subsys, *sysname, *devnode;
180
181 subsys = udev_device_get_subsystem(d);
182 if (!subsys) {
183 d = udev_device_get_parent(d);
184 continue;
185 }
186
187 sysname = udev_device_get_sysname(d);
188 if (!sysname) {
189 d = udev_device_get_parent(d);
190 continue;
191 }
192
193 match = strjoin("_KERNEL_DEVICE=+", subsys, ":", sysname, NULL);
194 if (!match)
195 return log_oom();
196
197 r = sd_journal_add_match(j, match, 0);
198 if (r < 0)
199 return log_error_errno(r, "Failed to add match: %m");
200
201 devnode = udev_device_get_devnode(d);
202 if (devnode) {
203 _cleanup_free_ char *match1 = NULL;
204
205 r = stat(devnode, &st);
206 if (r < 0)
207 return log_error_errno(r, "Failed to stat() device node \"%s\": %m", devnode);
208
209 r = asprintf(&match1, "_KERNEL_DEVICE=%c%u:%u", S_ISBLK(st.st_mode) ? 'b' : 'c', major(st.st_rdev), minor(st.st_rdev));
210 if (r < 0)
211 return log_oom();
212
213 r = sd_journal_add_match(j, match1, 0);
214 if (r < 0)
215 return log_error_errno(r, "Failed to add match: %m");
216 }
217
218 d = udev_device_get_parent(d);
219 }
220
221 return 0;
222}
223
faf5077f
DH
224static void pager_open_if_enabled(void) {
225
226 if (arg_no_pager)
227 return;
228
229 pager_open(arg_pager_end);
230}
231
5ab99e07
LP
232static char *format_timestamp_maybe_utc(char *buf, size_t l, usec_t t) {
233
234 if (arg_utc)
235 return format_timestamp_utc(buf, l, t);
236
237 return format_timestamp(buf, l, t);
238}
239
442e2def
LP
240static int parse_boot_descriptor(const char *x, sd_id128_t *boot_id, int *offset) {
241 sd_id128_t id = SD_ID128_NULL;
242 int off = 0, r;
243
244 if (strlen(x) >= 32) {
245 char *t;
246
247 t = strndupa(x, 32);
248 r = sd_id128_from_string(t, &id);
249 if (r >= 0)
250 x += 32;
251
252 if (*x != '-' && *x != '+' && *x != 0)
253 return -EINVAL;
254
255 if (*x != 0) {
256 r = safe_atoi(x, &off);
257 if (r < 0)
258 return r;
259 }
260 } else {
261 r = safe_atoi(x, &off);
262 if (r < 0)
263 return r;
264 }
265
266 if (boot_id)
267 *boot_id = id;
268
269 if (offset)
270 *offset = off;
271
272 return 0;
273}
274
601185b4 275static void help(void) {
0d43c694 276
faf5077f
DH
277 pager_open_if_enabled();
278
cd4b13e0 279 printf("%s [OPTIONS...] [MATCHES...]\n\n"
15119c16 280 "Query the journal.\n\n"
94b65516 281 "Options:\n"
eacbb4d3
ZJS
282 " --system Show the system journal\n"
283 " --user Show the user journal for the current user\n"
b6741478 284 " -M --machine=CONTAINER Operate on local container\n"
66f52924
JS
285 " -S --since=DATE Show entries not older than the specified date\n"
286 " -U --until=DATE Show entries not newer than the specified date\n"
40f0b71b
ZJS
287 " -c --cursor=CURSOR Show entries starting at the specified cursor\n"
288 " --after-cursor=CURSOR Show entries after the specified cursor\n"
248fc619 289 " --show-cursor Print the cursor after all the entries\n"
40f0b71b 290 " -b --boot[=ID] Show current boot or the specified boot\n"
f1188074 291 " --list-boots Show terse information about recorded boots\n"
c736283b 292 " -k --dmesg Show kernel message log from the current boot\n"
40f0b71b
ZJS
293 " -u --unit=UNIT Show logs from the specified unit\n"
294 " --user-unit=UNIT Show logs from the specified user unit\n"
295 " -t --identifier=STRING Show entries with the specified syslog identifier\n"
296 " -p --priority=RANGE Show entries with the specified priority\n"
297 " -e --pager-end Immediately jump to the end in the pager\n"
c736283b 298 " -f --follow Follow the journal\n"
248fc619
ZJS
299 " -n --lines[=INTEGER] Number of journal entries to show\n"
300 " --no-tail Show all lines, even in follow mode\n"
301 " -r --reverse Show the newest entries first\n"
f02d8367 302 " -o --output=STRING Change journal output mode (short, short-iso,\n"
c736283b
JSJ
303 " short-precise, short-monotonic, verbose,\n"
304 " export, json, json-pretty, json-sse, cat)\n"
9fd29044 305 " --utc Express time in Coordinated Universal Time (UTC)\n"
248fc619 306 " -x --catalog Add message explanations where available\n"
2b8f6883 307 " --no-full Ellipsize fields\n"
248fc619 308 " -a --all Show all fields, including long and unprintable\n"
20d936ba 309 " -q --quiet Do not show info messages and privilege warning\n"
248fc619
ZJS
310 " --no-pager Do not pipe output into a pager\n"
311 " -m --merge Show entries from all available journals\n"
312 " -D --directory=PATH Show journal files from directory\n"
313 " --file=PATH Show journal file\n"
94b65516 314 " --root=ROOT Operate on catalog files below a root directory\n"
15119c16 315#ifdef HAVE_GCRYPT
248fc619
ZJS
316 " --interval=TIME Time interval for changing the FSS sealing key\n"
317 " --verify-key=KEY Specify FSS verification key\n"
40f0b71b 318 " --force Override of the FSS key pair with --setup-keys\n"
15119c16
LP
319#endif
320 "\nCommands:\n"
c736283b 321 " -h --help Show this help text\n"
248fc619 322 " --version Show package version\n"
dbd2a83f 323 " -F --field=FIELD List all values that a specified field takes\n"
c736283b 324 " --disk-usage Show total disk usage of all journal files\n"
40f0b71b 325 " --vacuum-size=BYTES Reduce disk usage below specified size\n"
8580d1f7
LP
326 " --vacuum-files=INT Leave only the specified number of journal files\n"
327 " --vacuum-time=TIME Remove journal files older than specified time\n"
94b65516
LP
328 " --verify Verify journal file consistency\n"
329 " --sync Synchronize unwritten journal messages to disk\n"
dbd2a83f 330 " --flush Flush all journal data from /run into /var\n"
e3fdfb49 331 " --rotate Request immediate rotation of the journal files\n"
dbd2a83f 332 " --header Show journal header information\n"
40f0b71b 333 " --list-catalog Show all message IDs in the catalog\n"
248fc619
ZJS
334 " --dump-catalog Show entries in the message catalog\n"
335 " --update-catalog Update the message catalog database\n"
94b65516 336 " --new-id128 Generate a new 128-bit ID\n"
feb12d3e 337#ifdef HAVE_GCRYPT
c736283b 338 " --setup-keys Generate a new FSS key pair\n"
feb12d3e
LP
339#endif
340 , program_invocation_short_name);
0d43c694
LP
341}
342
343static int parse_argv(int argc, char *argv[]) {
344
345 enum {
346 ARG_VERSION = 0x100,
e91af489 347 ARG_NO_PAGER,
2b8f6883 348 ARG_NO_FULL,
55ee336c 349 ARG_NO_TAIL,
dca6219e 350 ARG_NEW_ID128,
f1188074 351 ARG_LIST_BOOTS,
3f3a438f
ZJS
352 ARG_USER,
353 ARG_SYSTEM,
13cbf3a5 354 ARG_ROOT,
7560fffc 355 ARG_HEADER,
beec0085 356 ARG_SETUP_KEYS,
8d98da3f 357 ARG_FILE,
baed47c3 358 ARG_INTERVAL,
4da416aa 359 ARG_VERIFY,
a1a03e30 360 ARG_VERIFY_KEY,
cfbc22ab 361 ARG_DISK_USAGE,
248fc619
ZJS
362 ARG_AFTER_CURSOR,
363 ARG_SHOW_CURSOR,
ffa7cd15 364 ARG_USER_UNIT,
d4205751 365 ARG_LIST_CATALOG,
54b7254c 366 ARG_DUMP_CATALOG,
3f3a438f 367 ARG_UPDATE_CATALOG,
b8547c10 368 ARG_FORCE,
9fd29044 369 ARG_UTC,
94b65516 370 ARG_SYNC,
74055aa7 371 ARG_FLUSH,
e3fdfb49 372 ARG_ROTATE,
dbd2a83f 373 ARG_VACUUM_SIZE,
8580d1f7 374 ARG_VACUUM_FILES,
dbd2a83f 375 ARG_VACUUM_TIME,
0d43c694
LP
376 };
377
378 static const struct option options[] = {
248fc619
ZJS
379 { "help", no_argument, NULL, 'h' },
380 { "version" , no_argument, NULL, ARG_VERSION },
381 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
382 { "pager-end", no_argument, NULL, 'e' },
383 { "follow", no_argument, NULL, 'f' },
384 { "force", no_argument, NULL, ARG_FORCE },
385 { "output", required_argument, NULL, 'o' },
386 { "all", no_argument, NULL, 'a' },
387 { "full", no_argument, NULL, 'l' },
2b8f6883 388 { "no-full", no_argument, NULL, ARG_NO_FULL },
248fc619
ZJS
389 { "lines", optional_argument, NULL, 'n' },
390 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
391 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
392 { "quiet", no_argument, NULL, 'q' },
393 { "merge", no_argument, NULL, 'm' },
394 { "boot", optional_argument, NULL, 'b' },
f1188074 395 { "list-boots", no_argument, NULL, ARG_LIST_BOOTS },
248fc619
ZJS
396 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
397 { "dmesg", no_argument, NULL, 'k' },
398 { "system", no_argument, NULL, ARG_SYSTEM },
399 { "user", no_argument, NULL, ARG_USER },
400 { "directory", required_argument, NULL, 'D' },
401 { "file", required_argument, NULL, ARG_FILE },
402 { "root", required_argument, NULL, ARG_ROOT },
403 { "header", no_argument, NULL, ARG_HEADER },
73083640 404 { "identifier", required_argument, NULL, 't' },
248fc619
ZJS
405 { "priority", required_argument, NULL, 'p' },
406 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
407 { "interval", required_argument, NULL, ARG_INTERVAL },
408 { "verify", no_argument, NULL, ARG_VERIFY },
409 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
410 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
411 { "cursor", required_argument, NULL, 'c' },
412 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
413 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
66f52924
JS
414 { "since", required_argument, NULL, 'S' },
415 { "until", required_argument, NULL, 'U' },
248fc619
ZJS
416 { "unit", required_argument, NULL, 'u' },
417 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
418 { "field", required_argument, NULL, 'F' },
419 { "catalog", no_argument, NULL, 'x' },
420 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
421 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
422 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
423 { "reverse", no_argument, NULL, 'r' },
b6741478 424 { "machine", required_argument, NULL, 'M' },
9fd29044 425 { "utc", no_argument, NULL, ARG_UTC },
74055aa7 426 { "flush", no_argument, NULL, ARG_FLUSH },
94b65516 427 { "sync", no_argument, NULL, ARG_SYNC },
e3fdfb49 428 { "rotate", no_argument, NULL, ARG_ROTATE },
dbd2a83f 429 { "vacuum-size", required_argument, NULL, ARG_VACUUM_SIZE },
8580d1f7 430 { "vacuum-files", required_argument, NULL, ARG_VACUUM_FILES },
dbd2a83f 431 { "vacuum-time", required_argument, NULL, ARG_VACUUM_TIME },
eb9da376 432 {}
0d43c694
LP
433 };
434
2100675e 435 int c, r;
0d43c694
LP
436
437 assert(argc >= 0);
438 assert(argv);
439
66f52924 440 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:S:U:t:u:F:xrM:", options, NULL)) >= 0)
0d43c694
LP
441
442 switch (c) {
443
444 case 'h':
601185b4
ZJS
445 help();
446 return 0;
0d43c694
LP
447
448 case ARG_VERSION:
3f6fd1ba 449 return version();
0d43c694
LP
450
451 case ARG_NO_PAGER:
452 arg_no_pager = true;
453 break;
454
1b12a7b5
HH
455 case 'e':
456 arg_pager_end = true;
fe59e38b 457
97e1cc8b 458 if (arg_lines == ARG_LINES_DEFAULT)
fe59e38b
LP
459 arg_lines = 1000;
460
1b12a7b5
HH
461 break;
462
0d43c694
LP
463 case 'f':
464 arg_follow = true;
465 break;
466
467 case 'o':
1705594f 468 arg_output = output_mode_from_string(optarg);
df50185b 469 if (arg_output < 0) {
edfb521a 470 log_error("Unknown output format '%s'.", optarg);
0d43c694
LP
471 return -EINVAL;
472 }
df50185b 473
edfb521a
ZJS
474 if (arg_output == OUTPUT_EXPORT ||
475 arg_output == OUTPUT_JSON ||
476 arg_output == OUTPUT_JSON_PRETTY ||
477 arg_output == OUTPUT_JSON_SSE ||
478 arg_output == OUTPUT_CAT)
479 arg_quiet = true;
480
0d43c694
LP
481 break;
482
98a6e132 483 case 'l':
e3657ecd
ZJS
484 arg_full = true;
485 break;
486
2b8f6883
ZJS
487 case ARG_NO_FULL:
488 arg_full = false;
489 break;
490
0d43c694 491 case 'a':
cd4b13e0 492 arg_all = true;
0d43c694
LP
493 break;
494
2100675e 495 case 'n':
1705594f 496 if (optarg) {
48382487 497 if (streq(optarg, "all"))
97e1cc8b 498 arg_lines = ARG_LINES_ALL;
48382487
JJ
499 else {
500 r = safe_atoi(optarg, &arg_lines);
501 if (r < 0 || arg_lines < 0) {
502 log_error("Failed to parse lines '%s'", optarg);
503 return -EINVAL;
504 }
1705594f 505 }
96088db0 506 } else {
48382487 507 arg_lines = 10;
96088db0
LP
508
509 /* Hmm, no argument? Maybe the next
510 * word on the command line is
511 * supposed to be the argument? Let's
512 * see if there is one, and is
48382487
JJ
513 * parsable. */
514 if (optind < argc) {
515 int n;
516 if (streq(argv[optind], "all")) {
97e1cc8b 517 arg_lines = ARG_LINES_ALL;
48382487
JJ
518 optind++;
519 } else if (safe_atoi(argv[optind], &n) >= 0 && n >= 0) {
520 arg_lines = n;
521 optind++;
522 }
523 }
96088db0 524 }
1705594f 525
2100675e
LP
526 break;
527
e91af489
LP
528 case ARG_NO_TAIL:
529 arg_no_tail = true;
530 break;
531
39f7f5c1 532 case ARG_NEW_ID128:
7560fffc 533 arg_action = ACTION_NEW_ID128;
55ee336c
LP
534 break;
535
43673799
LP
536 case 'q':
537 arg_quiet = true;
490e567d 538 break;
43673799 539
9e8a535f
LP
540 case 'm':
541 arg_merge = true;
2bd3c38a
LP
542 break;
543
59cea26a 544 case 'b':
d121b396 545 arg_boot = true;
6cebe83c 546
442e2def 547 if (optarg) {
909dea0c 548 r = parse_boot_descriptor(optarg, &arg_boot_id, &arg_boot_offset);
442e2def
LP
549 if (r < 0) {
550 log_error("Failed to parse boot descriptor '%s'", optarg);
551 return -EINVAL;
552 }
553 } else {
6cebe83c 554
442e2def
LP
555 /* Hmm, no argument? Maybe the next
556 * word on the command line is
557 * supposed to be the argument? Let's
558 * see if there is one and is parsable
559 * as a boot descriptor... */
560
561 if (optind < argc &&
562 parse_boot_descriptor(argv[optind], &arg_boot_id, &arg_boot_offset) >= 0)
6cebe83c 563 optind++;
6cebe83c 564 }
d121b396 565
59cea26a
LP
566 break;
567
f1188074
ZJS
568 case ARG_LIST_BOOTS:
569 arg_action = ACTION_LIST_BOOTS;
570 break;
571
99271804 572 case 'k':
d121b396 573 arg_boot = arg_dmesg = true;
99271804
ZJS
574 break;
575
3f3a438f
ZJS
576 case ARG_SYSTEM:
577 arg_journal_type |= SD_JOURNAL_SYSTEM;
578 break;
579
580 case ARG_USER:
581 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
582 break;
583
b6741478
LP
584 case 'M':
585 arg_machine = optarg;
586 break;
587
a963990f
LP
588 case 'D':
589 arg_directory = optarg;
590 break;
591
8d98da3f
ZJS
592 case ARG_FILE:
593 r = glob_extend(&arg_file, optarg);
23bbb0de
MS
594 if (r < 0)
595 return log_error_errno(r, "Failed to add paths: %m");
8d98da3f
ZJS
596 break;
597
13cbf3a5 598 case ARG_ROOT:
0f03c2a4
LP
599 r = parse_path_argument_and_warn(optarg, true, &arg_root);
600 if (r < 0)
601 return r;
13cbf3a5
ZJS
602 break;
603
8f14c832
LP
604 case 'c':
605 arg_cursor = optarg;
606 break;
607
248fc619
ZJS
608 case ARG_AFTER_CURSOR:
609 arg_after_cursor = optarg;
610 break;
611
612 case ARG_SHOW_CURSOR:
613 arg_show_cursor = true;
614 break;
615
dca6219e 616 case ARG_HEADER:
7560fffc
LP
617 arg_action = ACTION_PRINT_HEADER;
618 break;
619
feb12d3e
LP
620 case ARG_VERIFY:
621 arg_action = ACTION_VERIFY;
622 break;
623
a1a03e30
LP
624 case ARG_DISK_USAGE:
625 arg_action = ACTION_DISK_USAGE;
626 break;
627
dbd2a83f
LP
628 case ARG_VACUUM_SIZE:
629 r = parse_size(optarg, 1024, &arg_vacuum_size);
630 if (r < 0) {
631 log_error("Failed to parse vacuum size: %s", optarg);
632 return r;
633 }
634
635 arg_action = ACTION_VACUUM;
636 break;
637
8580d1f7
LP
638 case ARG_VACUUM_FILES:
639 r = safe_atou64(optarg, &arg_vacuum_n_files);
640 if (r < 0) {
641 log_error("Failed to parse vacuum files: %s", optarg);
642 return r;
643 }
644
645 arg_action = ACTION_VACUUM;
646 break;
647
dbd2a83f
LP
648 case ARG_VACUUM_TIME:
649 r = parse_sec(optarg, &arg_vacuum_time);
650 if (r < 0) {
651 log_error("Failed to parse vacuum time: %s", optarg);
652 return r;
653 }
654
655 arg_action = ACTION_VACUUM;
656 break;
657
feb12d3e 658#ifdef HAVE_GCRYPT
b8547c10
SL
659 case ARG_FORCE:
660 arg_force = true;
661 break;
662
7560fffc
LP
663 case ARG_SETUP_KEYS:
664 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
665 break;
666
beec0085 667
baed47c3 668 case ARG_VERIFY_KEY:
4da416aa 669 arg_action = ACTION_VERIFY;
baed47c3 670 arg_verify_key = optarg;
9e8a535f 671 arg_merge = false;
4da416aa
LP
672 break;
673
baed47c3 674 case ARG_INTERVAL:
7f602784 675 r = parse_sec(optarg, &arg_interval);
baed47c3
LP
676 if (r < 0 || arg_interval <= 0) {
677 log_error("Failed to parse sealing key change interval: %s", optarg);
14d10188
LP
678 return -EINVAL;
679 }
680 break;
feb12d3e
LP
681#else
682 case ARG_SETUP_KEYS:
683 case ARG_VERIFY_KEY:
684 case ARG_INTERVAL:
b8547c10 685 case ARG_FORCE:
feb12d3e 686 log_error("Forward-secure sealing not available.");
15411c0c 687 return -EOPNOTSUPP;
feb12d3e 688#endif
14d10188 689
941e990d
LP
690 case 'p': {
691 const char *dots;
692
693 dots = strstr(optarg, "..");
694 if (dots) {
695 char *a;
696 int from, to, i;
697
698 /* a range */
699 a = strndup(optarg, dots - optarg);
700 if (!a)
701 return log_oom();
702
703 from = log_level_from_string(a);
704 to = log_level_from_string(dots + 2);
705 free(a);
706
707 if (from < 0 || to < 0) {
708 log_error("Failed to parse log level range %s", optarg);
709 return -EINVAL;
710 }
711
712 arg_priorities = 0;
713
714 if (from < to) {
715 for (i = from; i <= to; i++)
716 arg_priorities |= 1 << i;
717 } else {
718 for (i = to; i <= from; i++)
719 arg_priorities |= 1 << i;
720 }
721
722 } else {
723 int p, i;
724
725 p = log_level_from_string(optarg);
726 if (p < 0) {
727 log_error("Unknown log level %s", optarg);
728 return -EINVAL;
729 }
730
731 arg_priorities = 0;
732
733 for (i = 0; i <= p; i++)
734 arg_priorities |= 1 << i;
735 }
736
737 break;
738 }
739
66f52924 740 case 'S':
cfbc22ab
LP
741 r = parse_timestamp(optarg, &arg_since);
742 if (r < 0) {
743 log_error("Failed to parse timestamp: %s", optarg);
744 return -EINVAL;
745 }
746 arg_since_set = true;
747 break;
748
66f52924 749 case 'U':
cfbc22ab
LP
750 r = parse_timestamp(optarg, &arg_until);
751 if (r < 0) {
752 log_error("Failed to parse timestamp: %s", optarg);
753 return -EINVAL;
754 }
755 arg_until_set = true;
756 break;
757
73083640
HH
758 case 't':
759 r = strv_extend(&arg_syslog_identifier, optarg);
760 if (r < 0)
761 return log_oom();
762 break;
763
7199aa96 764 case 'u':
b9e40524
HH
765 r = strv_extend(&arg_system_units, optarg);
766 if (r < 0)
767 return log_oom();
ffa7cd15
DW
768 break;
769
7199aa96 770 case ARG_USER_UNIT:
b9e40524
HH
771 r = strv_extend(&arg_user_units, optarg);
772 if (r < 0)
773 return log_oom();
c3f60ec5
LP
774 break;
775
15119c16
LP
776 case 'F':
777 arg_field = optarg;
778 break;
779
d4205751
LP
780 case 'x':
781 arg_catalog = true;
782 break;
783
784 case ARG_LIST_CATALOG:
785 arg_action = ACTION_LIST_CATALOG;
786 break;
787
54b7254c
ZJS
788 case ARG_DUMP_CATALOG:
789 arg_action = ACTION_DUMP_CATALOG;
790 break;
791
d4205751
LP
792 case ARG_UPDATE_CATALOG:
793 arg_action = ACTION_UPDATE_CATALOG;
794 break;
795
d89d6c86
LN
796 case 'r':
797 arg_reverse = true;
798 break;
799
9fd29044
JS
800 case ARG_UTC:
801 arg_utc = true;
802 break;
803
74055aa7
LP
804 case ARG_FLUSH:
805 arg_action = ACTION_FLUSH;
806 break;
807
e3fdfb49
EV
808 case ARG_ROTATE:
809 arg_action = ACTION_ROTATE;
810 break;
811
94b65516
LP
812 case ARG_SYNC:
813 arg_action = ACTION_SYNC;
814 break;
815
eb9da376 816 case '?':
0d43c694 817 return -EINVAL;
eb9da376
LP
818
819 default:
820 assert_not_reached("Unhandled option");
0d43c694 821 }
0d43c694 822
70af7b8a 823 if (arg_follow && !arg_no_tail && !arg_since && arg_lines == ARG_LINES_DEFAULT)
e91af489
LP
824 arg_lines = 10;
825
b6741478
LP
826 if (!!arg_directory + !!arg_file + !!arg_machine > 1) {
827 log_error("Please specify either -D/--directory= or --file= or -M/--machine=, not more than one.");
8d98da3f
ZJS
828 return -EINVAL;
829 }
830
3ba09ee8 831 if (arg_since_set && arg_until_set && arg_since > arg_until) {
cfbc22ab
LP
832 log_error("--since= must be before --until=.");
833 return -EINVAL;
834 }
835
248fc619
ZJS
836 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
837 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
cfbc22ab
LP
838 return -EINVAL;
839 }
840
d89d6c86
LN
841 if (arg_follow && arg_reverse) {
842 log_error("Please specify either --reverse= or --follow=, not both.");
843 return -EINVAL;
844 }
845
f98a41c2 846 if (!IN_SET(arg_action, ACTION_SHOW, ACTION_DUMP_CATALOG, ACTION_LIST_CATALOG) && optind < argc) {
0b6b7c20
ZJS
847 log_error("Extraneous arguments starting with '%s'", argv[optind]);
848 return -EINVAL;
849 }
850
596a2329
JJ
851 if ((arg_boot || arg_action == ACTION_LIST_BOOTS) && (arg_file || arg_directory || arg_merge)) {
852 log_error("Using --boot or --list-boots with --file, --directory or --merge is not supported.");
853 return -EINVAL;
854 }
855
0d43c694
LP
856 return 1;
857}
858
39f7f5c1 859static int generate_new_id128(void) {
55ee336c
LP
860 sd_id128_t id;
861 int r;
862 unsigned i;
863
864 r = sd_id128_randomize(&id);
23bbb0de
MS
865 if (r < 0)
866 return log_error_errno(r, "Failed to generate ID: %m");
55ee336c
LP
867
868 printf("As string:\n"
869 SD_ID128_FORMAT_STR "\n\n"
870 "As UUID:\n"
871 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
872 "As macro:\n"
d489071f 873 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
874 SD_ID128_FORMAT_VAL(id),
875 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
876 for (i = 0; i < 16; i++)
877 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 878 fputs(")\n\n", stdout);
55ee336c 879
d489071f
ZJS
880 printf("As Python constant:\n"
881 ">>> import uuid\n"
882 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
883 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
884
885 return 0;
886}
887
a963990f
LP
888static int add_matches(sd_journal *j, char **args) {
889 char **i;
4e602943 890 bool have_term = false;
59cea26a 891
a963990f 892 assert(j);
59cea26a 893
a963990f 894 STRV_FOREACH(i, args) {
52aeb63c 895 int r;
59cea26a 896
4e602943
ZJS
897 if (streq(*i, "+")) {
898 if (!have_term)
899 break;
cbdca852 900 r = sd_journal_add_disjunction(j);
4e602943
ZJS
901 have_term = false;
902
903 } else if (path_is_absolute(*i)) {
795ab08f 904 _cleanup_free_ char *p, *t = NULL, *t2 = NULL, *interpreter = NULL;
e5124088 905 const char *path;
a963990f 906 struct stat st;
e5124088 907
a963990f 908 p = canonicalize_file_name(*i);
795ab08f 909 path = p ?: *i;
e5124088 910
26b9f165 911 if (lstat(path, &st) < 0)
4a62c710 912 return log_error_errno(errno, "Couldn't stat file: %m");
e5124088 913
68fee104
ZJS
914 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
915 if (executable_is_script(path, &interpreter) > 0) {
916 _cleanup_free_ char *comm;
917
2b6bf07d 918 comm = strndup(basename(path), 15);
68fee104
ZJS
919 if (!comm)
920 return log_oom();
921
922 t = strappend("_COMM=", comm);
795ab08f
MS
923 if (!t)
924 return log_oom();
68fee104
ZJS
925
926 /* Append _EXE only if the interpreter is not a link.
73e231ab 927 Otherwise, it might be outdated often. */
795ab08f 928 if (lstat(interpreter, &st) == 0 && !S_ISLNK(st.st_mode)) {
68fee104
ZJS
929 t2 = strappend("_EXE=", interpreter);
930 if (!t2)
931 return log_oom();
932 }
795ab08f 933 } else {
68fee104 934 t = strappend("_EXE=", path);
795ab08f
MS
935 if (!t)
936 return log_oom();
937 }
938
939 r = sd_journal_add_match(j, t, 0);
940
941 if (r >=0 && t2)
942 r = sd_journal_add_match(j, t2, 0);
943
944 } else if (S_ISCHR(st.st_mode) || S_ISBLK(st.st_mode)) {
945 r = add_matches_for_device(j, path);
946 if (r < 0)
947 return r;
948 } else {
fb93cf73 949 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
a963990f 950 return -EINVAL;
50940700 951 }
e5124088 952
4e602943 953 have_term = true;
4e602943 954 } else {
cbdca852 955 r = sd_journal_add_match(j, *i, 0);
4e602943
ZJS
956 have_term = true;
957 }
e5124088 958
23bbb0de
MS
959 if (r < 0)
960 return log_error_errno(r, "Failed to add match '%s': %m", *i);
de7b95cd
LP
961 }
962
4e602943
ZJS
963 if (!strv_isempty(args) && !have_term) {
964 log_error("\"+\" can only be used between terms");
965 return -EINVAL;
966 }
967
a963990f
LP
968 return 0;
969}
970
9530e0d0
LP
971static void boot_id_free_all(BootId *l) {
972
973 while (l) {
974 BootId *i = l;
975 LIST_REMOVE(boot_list, l, i);
976 free(i);
977 }
978}
979
45bc27b6
LP
980static int discover_next_boot(
981 sd_journal *j,
982 BootId **boot,
983 bool advance_older,
984 bool read_realtime) {
985
f1188074 986 int r;
596a2329 987 char match[9+32+1] = "_BOOT_ID=";
45bc27b6 988 _cleanup_free_ BootId *next_boot = NULL;
ea7061e4
JJ
989
990 assert(j);
596a2329
JJ
991 assert(boot);
992
993 /* We expect the journal to be on the last position of a boot
994 * (in relation to the direction we are going), so that the next
995 * invocation of sd_journal_next/previous will be from a different
996 * boot. We then collect any information we desire and then jump
997 * to the last location of the new boot by using a _BOOT_ID match
998 * coming from the other journal direction. */
999
1000 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1001 * we can actually advance to a *different* boot. */
1002 sd_journal_flush_matches(j);
1003
1004 if (advance_older)
1005 r = sd_journal_previous(j);
1006 else
1007 r = sd_journal_next(j);
1008 if (r < 0)
1009 return r;
1010 else if (r == 0)
1011 return 0; /* End of journal, yay. */
1012
45bc27b6 1013 next_boot = new0(BootId, 1);
596a2329 1014 if (!next_boot)
b56d608e 1015 return -ENOMEM;
f1188074 1016
596a2329 1017 r = sd_journal_get_monotonic_usec(j, NULL, &next_boot->id);
f1188074
ZJS
1018 if (r < 0)
1019 return r;
1020
596a2329
JJ
1021 if (read_realtime) {
1022 r = sd_journal_get_realtime_usec(j, &next_boot->first);
1023 if (r < 0)
1024 return r;
1025 }
ea7061e4 1026
596a2329
JJ
1027 /* Now seek to the last occurrence of this boot ID. */
1028 sd_id128_to_string(next_boot->id, match + 9);
1029 r = sd_journal_add_match(j, match, sizeof(match) - 1);
1030 if (r < 0)
1031 return r;
f1188074 1032
596a2329
JJ
1033 if (advance_older)
1034 r = sd_journal_seek_head(j);
1035 else
1036 r = sd_journal_seek_tail(j);
1037 if (r < 0)
1038 return r;
f1188074 1039
596a2329
JJ
1040 if (advance_older)
1041 r = sd_journal_next(j);
1042 else
1043 r = sd_journal_previous(j);
1044 if (r < 0)
1045 return r;
1046 else if (r == 0)
1047 return -ENODATA; /* This shouldn't happen. We just came from this very boot ID. */
f1188074 1048
596a2329
JJ
1049 if (read_realtime) {
1050 r = sd_journal_get_realtime_usec(j, &next_boot->last);
f1188074 1051 if (r < 0)
596a2329
JJ
1052 return r;
1053 }
1054
1055 *boot = next_boot;
1056 next_boot = NULL;
9530e0d0 1057
596a2329
JJ
1058 return 0;
1059}
1060
45bc27b6
LP
1061static int get_boots(
1062 sd_journal *j,
1063 BootId **boots,
1064 BootId *query_ref_boot,
1065 int ref_boot_offset) {
1066
596a2329
JJ
1067 bool skip_once;
1068 int r, count = 0;
45bc27b6 1069 BootId *head = NULL, *tail = NULL;
596a2329
JJ
1070 const bool advance_older = query_ref_boot && ref_boot_offset <= 0;
1071
1072 assert(j);
f1188074 1073
596a2329
JJ
1074 /* Adjust for the asymmetry that offset 0 is
1075 * the last (and current) boot, while 1 is considered the
1076 * (chronological) first boot in the journal. */
1077 skip_once = query_ref_boot && sd_id128_is_null(query_ref_boot->id) && ref_boot_offset < 0;
1078
1079 /* Advance to the earliest/latest occurrence of our reference
1080 * boot ID (taking our lookup direction into account), so that
1081 * discover_next_boot() can do its job.
1082 * If no reference is given, the journal head/tail will do,
1083 * they're "virtual" boots after all. */
1084 if (query_ref_boot && !sd_id128_is_null(query_ref_boot->id)) {
1085 char match[9+32+1] = "_BOOT_ID=";
1086
1087 sd_journal_flush_matches(j);
1088
1089 sd_id128_to_string(query_ref_boot->id, match + 9);
1090 r = sd_journal_add_match(j, match, sizeof(match) - 1);
f1188074
ZJS
1091 if (r < 0)
1092 return r;
1093
596a2329
JJ
1094 if (advance_older)
1095 r = sd_journal_seek_head(j);
1096 else
1097 r = sd_journal_seek_tail(j);
f1188074
ZJS
1098 if (r < 0)
1099 return r;
1100
596a2329
JJ
1101 if (advance_older)
1102 r = sd_journal_next(j);
1103 else
1104 r = sd_journal_previous(j);
f1188074
ZJS
1105 if (r < 0)
1106 return r;
1107 else if (r == 0)
596a2329
JJ
1108 goto finish;
1109 else if (ref_boot_offset == 0) {
1110 count = 1;
1111 goto finish;
1112 }
1113 } else {
1114 if (advance_older)
1115 r = sd_journal_seek_tail(j);
1116 else
1117 r = sd_journal_seek_head(j);
f1188074
ZJS
1118 if (r < 0)
1119 return r;
1120
596a2329
JJ
1121 /* No sd_journal_next/previous here. */
1122 }
f1188074 1123
45bc27b6
LP
1124 for (;;) {
1125 _cleanup_free_ BootId *current = NULL;
f1188074 1126
596a2329
JJ
1127 r = discover_next_boot(j, &current, advance_older, !query_ref_boot);
1128 if (r < 0) {
9530e0d0 1129 boot_id_free_all(head);
596a2329 1130 return r;
ea7061e4 1131 }
f1188074 1132
596a2329
JJ
1133 if (!current)
1134 break;
1135
1136 if (query_ref_boot) {
1137 if (!skip_once)
1138 ref_boot_offset += advance_older ? 1 : -1;
1139 skip_once = false;
1140
1141 if (ref_boot_offset == 0) {
1142 count = 1;
1143 query_ref_boot->id = current->id;
1144 break;
1145 }
1146 } else {
1147 LIST_INSERT_AFTER(boot_list, head, tail, current);
1148 tail = current;
1149 current = NULL;
1150 count++;
1151 }
f1188074
ZJS
1152 }
1153
596a2329
JJ
1154finish:
1155 if (boots)
1156 *boots = head;
1157
1158 sd_journal_flush_matches(j);
1159
1160 return count;
ea7061e4
JJ
1161}
1162
1163static int list_boots(sd_journal *j) {
596a2329 1164 int w, i, count;
9530e0d0 1165 BootId *id, *all_ids;
ea7061e4
JJ
1166
1167 assert(j);
1168
596a2329 1169 count = get_boots(j, &all_ids, NULL, 0);
b56d608e
LP
1170 if (count < 0)
1171 return log_error_errno(count, "Failed to determine boots: %m");
1172 if (count == 0)
596a2329 1173 return count;
ea7061e4
JJ
1174
1175 pager_open_if_enabled();
f1188074
ZJS
1176
1177 /* numbers are one less, but we need an extra char for the sign */
1178 w = DECIMAL_STR_WIDTH(count - 1) + 1;
1179
596a2329 1180 i = 0;
9530e0d0 1181 LIST_FOREACH(boot_list, id, all_ids) {
f1188074
ZJS
1182 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX];
1183
1184 printf("% *i " SD_ID128_FORMAT_STR " %s—%s\n",
1185 w, i - count + 1,
1186 SD_ID128_FORMAT_VAL(id->id),
5ab99e07
LP
1187 format_timestamp_maybe_utc(a, sizeof(a), id->first),
1188 format_timestamp_maybe_utc(b, sizeof(b), id->last));
596a2329 1189 i++;
d121b396 1190 }
a963990f 1191
9530e0d0
LP
1192 boot_id_free_all(all_ids);
1193
a331b5e6
JJ
1194 return 0;
1195}
1196
1197static int add_boot(sd_journal *j) {
1198 char match[9+32+1] = "_BOOT_ID=";
442e2def 1199 int r;
45bc27b6 1200 BootId ref_boot_id = {};
a331b5e6
JJ
1201
1202 assert(j);
1203
d121b396 1204 if (!arg_boot)
a331b5e6
JJ
1205 return 0;
1206
442e2def 1207 if (arg_boot_offset == 0 && sd_id128_equal(arg_boot_id, SD_ID128_NULL))
b6741478 1208 return add_match_this_boot(j, arg_machine);
a331b5e6 1209
596a2329
JJ
1210 ref_boot_id.id = arg_boot_id;
1211 r = get_boots(j, NULL, &ref_boot_id, arg_boot_offset);
1212 assert(r <= 1);
1213 if (r <= 0) {
1214 const char *reason = (r == 0) ? "No such boot ID in journal" : strerror(-r);
1215
1216 if (sd_id128_is_null(arg_boot_id))
c34e9399
JS
1217 log_error("Data from the specified boot (%+i) is not available: %s",
1218 arg_boot_offset, reason);
d121b396 1219 else
c34e9399
JS
1220 log_error("Data from the specified boot ("SD_ID128_FORMAT_STR") is not available: %s",
1221 SD_ID128_FORMAT_VAL(arg_boot_id), reason);
596a2329
JJ
1222
1223 return r == 0 ? -ENODATA : r;
a331b5e6
JJ
1224 }
1225
596a2329 1226 sd_id128_to_string(ref_boot_id.id, match + 9);
d121b396
ZJS
1227
1228 r = sd_journal_add_match(j, match, sizeof(match) - 1);
23bbb0de
MS
1229 if (r < 0)
1230 return log_error_errno(r, "Failed to add match: %m");
a331b5e6
JJ
1231
1232 r = sd_journal_add_conjunction(j);
1233 if (r < 0)
b56d608e 1234 return log_error_errno(r, "Failed to add conjunction: %m");
a331b5e6
JJ
1235
1236 return 0;
a963990f
LP
1237}
1238
99271804
ZJS
1239static int add_dmesg(sd_journal *j) {
1240 int r;
1241 assert(j);
1242
1243 if (!arg_dmesg)
1244 return 0;
1245
1246 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
23bbb0de
MS
1247 if (r < 0)
1248 return log_error_errno(r, "Failed to add match: %m");
99271804
ZJS
1249
1250 r = sd_journal_add_conjunction(j);
1251 if (r < 0)
b56d608e 1252 return log_error_errno(r, "Failed to add conjunction: %m");
99271804
ZJS
1253
1254 return 0;
1255}
1256
b56d608e
LP
1257static int get_possible_units(
1258 sd_journal *j,
1259 const char *fields,
1260 char **patterns,
1261 Set **units) {
1262
ea18a4b5
ZJS
1263 _cleanup_set_free_free_ Set *found;
1264 const char *field;
c3f60ec5 1265 int r;
ea18a4b5 1266
d5099efc 1267 found = set_new(&string_hash_ops);
ea18a4b5 1268 if (!found)
b56d608e 1269 return -ENOMEM;
ea18a4b5
ZJS
1270
1271 NULSTR_FOREACH(field, fields) {
1272 const void *data;
1273 size_t size;
1274
1275 r = sd_journal_query_unique(j, field);
1276 if (r < 0)
1277 return r;
1278
1279 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1280 char **pattern, *eq;
1281 size_t prefix;
1282 _cleanup_free_ char *u = NULL;
1283
1284 eq = memchr(data, '=', size);
1285 if (eq)
1286 prefix = eq - (char*) data + 1;
1287 else
1288 prefix = 0;
1289
1290 u = strndup((char*) data + prefix, size - prefix);
1291 if (!u)
b56d608e 1292 return -ENOMEM;
ea18a4b5
ZJS
1293
1294 STRV_FOREACH(pattern, patterns)
1295 if (fnmatch(*pattern, u, FNM_NOESCAPE) == 0) {
1296 log_debug("Matched %s with pattern %s=%s", u, field, *pattern);
1297
1298 r = set_consume(found, u);
1299 u = NULL;
1300 if (r < 0 && r != -EEXIST)
1301 return r;
1302
1303 break;
1304 }
1305 }
1306 }
1307
1308 *units = found;
1309 found = NULL;
1310 return 0;
1311}
1312
1313/* This list is supposed to return the superset of unit names
1314 * possibly matched by rules added with add_matches_for_unit... */
1315#define SYSTEM_UNITS \
1316 "_SYSTEMD_UNIT\0" \
1317 "COREDUMP_UNIT\0" \
1318 "UNIT\0" \
1319 "OBJECT_SYSTEMD_UNIT\0" \
1320 "_SYSTEMD_SLICE\0"
1321
1322/* ... and add_matches_for_user_unit */
1323#define USER_UNITS \
1324 "_SYSTEMD_USER_UNIT\0" \
1325 "USER_UNIT\0" \
1326 "COREDUMP_USER_UNIT\0" \
1327 "OBJECT_SYSTEMD_USER_UNIT\0"
1328
1329static int add_units(sd_journal *j) {
1330 _cleanup_strv_free_ char **patterns = NULL;
1331 int r, count = 0;
b9e40524 1332 char **i;
c3f60ec5
LP
1333
1334 assert(j);
1335
b9e40524 1336 STRV_FOREACH(i, arg_system_units) {
ea18a4b5
ZJS
1337 _cleanup_free_ char *u = NULL;
1338
7410616c
LP
1339 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1340 if (r < 0)
1341 return r;
ea18a4b5
ZJS
1342
1343 if (string_is_glob(u)) {
1344 r = strv_push(&patterns, u);
1345 if (r < 0)
1346 return r;
1347 u = NULL;
1348 } else {
1349 r = add_matches_for_unit(j, u);
1350 if (r < 0)
1351 return r;
1352 r = sd_journal_add_disjunction(j);
1353 if (r < 0)
1354 return r;
1355 count ++;
1356 }
1357 }
1358
1359 if (!strv_isempty(patterns)) {
1360 _cleanup_set_free_free_ Set *units = NULL;
1361 Iterator it;
1362 char *u;
1363
1364 r = get_possible_units(j, SYSTEM_UNITS, patterns, &units);
b9e40524
HH
1365 if (r < 0)
1366 return r;
ea18a4b5
ZJS
1367
1368 SET_FOREACH(u, units, it) {
1369 r = add_matches_for_unit(j, u);
1370 if (r < 0)
1371 return r;
1372 r = sd_journal_add_disjunction(j);
1373 if (r < 0)
1374 return r;
1375 count ++;
1376 }
b9e40524 1377 }
c3f60ec5 1378
97b11eed 1379 patterns = strv_free(patterns);
ea18a4b5 1380
b9e40524 1381 STRV_FOREACH(i, arg_user_units) {
ea18a4b5
ZJS
1382 _cleanup_free_ char *u = NULL;
1383
7410616c
LP
1384 r = unit_name_mangle(*i, UNIT_NAME_GLOB, &u);
1385 if (r < 0)
1386 return r;
c3f60ec5 1387
ea18a4b5
ZJS
1388 if (string_is_glob(u)) {
1389 r = strv_push(&patterns, u);
1390 if (r < 0)
1391 return r;
1392 u = NULL;
1393 } else {
1394 r = add_matches_for_user_unit(j, u, getuid());
1395 if (r < 0)
1396 return r;
1397 r = sd_journal_add_disjunction(j);
1398 if (r < 0)
1399 return r;
1400 count ++;
1401 }
1402 }
1403
1404 if (!strv_isempty(patterns)) {
1405 _cleanup_set_free_free_ Set *units = NULL;
1406 Iterator it;
1407 char *u;
b9e40524 1408
ea18a4b5 1409 r = get_possible_units(j, USER_UNITS, patterns, &units);
b9e40524
HH
1410 if (r < 0)
1411 return r;
1412
ea18a4b5
ZJS
1413 SET_FOREACH(u, units, it) {
1414 r = add_matches_for_user_unit(j, u, getuid());
1415 if (r < 0)
1416 return r;
1417 r = sd_journal_add_disjunction(j);
1418 if (r < 0)
1419 return r;
1420 count ++;
1421 }
b9e40524 1422 }
c3f60ec5 1423
ea18a4b5
ZJS
1424 /* Complain if the user request matches but nothing whatsoever was
1425 * found, since otherwise everything would be matched. */
1426 if (!(strv_isempty(arg_system_units) && strv_isempty(arg_user_units)) && count == 0)
1427 return -ENODATA;
1428
cd34b3c6
HH
1429 r = sd_journal_add_conjunction(j);
1430 if (r < 0)
1431 return r;
1432
c3f60ec5
LP
1433 return 0;
1434}
1435
941e990d
LP
1436static int add_priorities(sd_journal *j) {
1437 char match[] = "PRIORITY=0";
1438 int i, r;
941e990d
LP
1439 assert(j);
1440
1441 if (arg_priorities == 0xFF)
1442 return 0;
1443
1444 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
1445 if (arg_priorities & (1 << i)) {
1446 match[sizeof(match)-2] = '0' + i;
1447
941e990d 1448 r = sd_journal_add_match(j, match, strlen(match));
23bbb0de
MS
1449 if (r < 0)
1450 return log_error_errno(r, "Failed to add match: %m");
941e990d
LP
1451 }
1452
cd34b3c6
HH
1453 r = sd_journal_add_conjunction(j);
1454 if (r < 0)
b56d608e 1455 return log_error_errno(r, "Failed to add conjunction: %m");
cd34b3c6 1456
941e990d
LP
1457 return 0;
1458}
1459
73083640
HH
1460
1461static int add_syslog_identifier(sd_journal *j) {
1462 int r;
1463 char **i;
1464
1465 assert(j);
1466
1467 STRV_FOREACH(i, arg_syslog_identifier) {
1468 char *u;
1469
63c372cb 1470 u = strjoina("SYSLOG_IDENTIFIER=", *i);
73083640
HH
1471 r = sd_journal_add_match(j, u, 0);
1472 if (r < 0)
1473 return r;
1474 r = sd_journal_add_disjunction(j);
1475 if (r < 0)
1476 return r;
1477 }
1478
1479 r = sd_journal_add_conjunction(j);
1480 if (r < 0)
1481 return r;
1482
1483 return 0;
1484}
1485
7560fffc
LP
1486static int setup_keys(void) {
1487#ifdef HAVE_GCRYPT
1488 size_t mpk_size, seed_size, state_size, i;
1489 uint8_t *mpk, *seed, *state;
11689d2a 1490 int fd = -1, r;
7560fffc
LP
1491 sd_id128_t machine, boot;
1492 char *p = NULL, *k = NULL;
baed47c3 1493 struct FSSHeader h;
14d10188 1494 uint64_t n;
b98e3866
SL
1495 struct stat st;
1496
1497 r = stat("/var/log/journal", &st);
4a62c710
MS
1498 if (r < 0 && errno != ENOENT && errno != ENOTDIR)
1499 return log_error_errno(errno, "stat(\"%s\") failed: %m", "/var/log/journal");
b98e3866
SL
1500
1501 if (r < 0 || !S_ISDIR(st.st_mode)) {
1502 log_error("%s is not a directory, must be using persistent logging for FSS.",
1503 "/var/log/journal");
1504 return r < 0 ? -errno : -ENOTDIR;
1505 }
7560fffc
LP
1506
1507 r = sd_id128_get_machine(&machine);
23bbb0de
MS
1508 if (r < 0)
1509 return log_error_errno(r, "Failed to get machine ID: %m");
7560fffc
LP
1510
1511 r = sd_id128_get_boot(&boot);
23bbb0de
MS
1512 if (r < 0)
1513 return log_error_errno(r, "Failed to get boot ID: %m");
7560fffc 1514
baed47c3 1515 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
1516 SD_ID128_FORMAT_VAL(machine)) < 0)
1517 return log_oom();
1518
faf9da01
ZJS
1519 if (arg_force) {
1520 r = unlink(p);
1521 if (r < 0 && errno != ENOENT) {
1522 r = log_error_errno(errno, "unlink(\"%s\") failed: %m", p);
b8547c10
SL
1523 goto finish;
1524 }
faf9da01
ZJS
1525 } else if (access(p, F_OK) >= 0) {
1526 log_error("Sealing key file %s exists already. Use --force to recreate.", p);
1527 r = -EEXIST;
1528 goto finish;
7560fffc
LP
1529 }
1530
baed47c3 1531 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
1532 SD_ID128_FORMAT_VAL(machine)) < 0) {
1533 r = log_oom();
1534 goto finish;
1535 }
1536
1537 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
1538 mpk = alloca(mpk_size);
1539
1540 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
1541 seed = alloca(seed_size);
1542
1543 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1544 state = alloca(state_size);
1545
1546 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1547 if (fd < 0) {
76ef789d 1548 r = log_error_errno(errno, "Failed to open /dev/random: %m");
7560fffc
LP
1549 goto finish;
1550 }
1551
1552 log_info("Generating seed...");
a6dcc7e5
ZJS
1553 r = loop_read_exact(fd, seed, seed_size, true);
1554 if (r < 0) {
1555 log_error_errno(r, "Failed to read random seed: %m");
7560fffc
LP
1556 goto finish;
1557 }
1558
1559 log_info("Generating key pair...");
1560 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1561
baed47c3 1562 log_info("Generating sealing key...");
7560fffc
LP
1563 FSPRG_GenState0(state, mpk, seed, seed_size);
1564
baed47c3
LP
1565 assert(arg_interval > 0);
1566
7560fffc 1567 n = now(CLOCK_REALTIME);
baed47c3 1568 n /= arg_interval;
7560fffc 1569
03e334a1 1570 safe_close(fd);
2d5bdf5b 1571 fd = mkostemp_safe(k, O_WRONLY|O_CLOEXEC);
7560fffc 1572 if (fd < 0) {
709f6e46 1573 r = log_error_errno(fd, "Failed to open %s: %m", k);
7560fffc
LP
1574 goto finish;
1575 }
1576
f982e6f7
LP
1577 /* Enable secure remove, exclusion from dump, synchronous
1578 * writing and in-place updating */
1ed8f8c1 1579 r = chattr_fd(fd, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL, FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL);
11689d2a 1580 if (r < 0)
709f6e46 1581 log_warning_errno(r, "Failed to set file attributes: %m");
f982e6f7 1582
7560fffc
LP
1583 zero(h);
1584 memcpy(h.signature, "KSHHRHLP", 8);
1585 h.machine_id = machine;
1586 h.boot_id = boot;
1587 h.header_size = htole64(sizeof(h));
baed47c3
LP
1588 h.start_usec = htole64(n * arg_interval);
1589 h.interval_usec = htole64(arg_interval);
1590 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1591 h.fsprg_state_size = htole64(state_size);
7560fffc 1592
553acb7b
ZJS
1593 r = loop_write(fd, &h, sizeof(h), false);
1594 if (r < 0) {
1595 log_error_errno(r, "Failed to write header: %m");
7560fffc
LP
1596 goto finish;
1597 }
1598
553acb7b
ZJS
1599 r = loop_write(fd, state, state_size, false);
1600 if (r < 0) {
1601 log_error_errno(r, "Failed to write state: %m");
7560fffc
LP
1602 goto finish;
1603 }
1604
1605 if (link(k, p) < 0) {
76ef789d 1606 r = log_error_errno(errno, "Failed to link file: %m");
7560fffc
LP
1607 goto finish;
1608 }
1609
8481248b 1610 if (on_tty()) {
7560fffc
LP
1611 fprintf(stderr,
1612 "\n"
1fc464f6 1613 "The new key pair has been generated. The " ANSI_HIGHLIGHT "secret sealing key" ANSI_NORMAL " has been written to\n"
c05276f2
LP
1614 "the following local file. This key file is automatically updated when the\n"
1615 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1616 "\n"
1617 "\t%s\n"
1618 "\n"
1fc464f6 1619 "Please write down the following " ANSI_HIGHLIGHT "secret verification key" ANSI_NORMAL ". It should be stored\n"
baed47c3 1620 "at a safe location and should not be saved locally on disk.\n"
1fc464f6 1621 "\n\t" ANSI_HIGHLIGHT_RED, p);
7560fffc
LP
1622 fflush(stderr);
1623 }
1624 for (i = 0; i < seed_size; i++) {
1625 if (i > 0 && i % 3 == 0)
1626 putchar('-');
1627 printf("%02x", ((uint8_t*) seed)[i]);
1628 }
1629
baed47c3
LP
1630 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1631
8481248b 1632 if (on_tty()) {
f6a971bc 1633 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1634
baed47c3 1635 fprintf(stderr,
1fc464f6 1636 ANSI_NORMAL "\n"
baed47c3 1637 "The sealing key is automatically changed every %s.\n",
2fa4092c 1638 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1639
1640 hn = gethostname_malloc();
1641
1642 if (hn) {
ae691c1d 1643 hostname_cleanup(hn);
adac1c93 1644 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1645 } else
adac1c93 1646 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
1647
1648#ifdef HAVE_QRENCODE
cf5a3432 1649 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1650 if (is_locale_utf8()) {
cf5a3432
LP
1651 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1652 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1653 }
f6a971bc
LP
1654#endif
1655 free(hn);
baed47c3 1656 }
7560fffc
LP
1657
1658 r = 0;
1659
1660finish:
03e334a1 1661 safe_close(fd);
7560fffc
LP
1662
1663 if (k) {
1664 unlink(k);
1665 free(k);
1666 }
1667
1668 free(p);
1669
1670 return r;
1671#else
feb12d3e 1672 log_error("Forward-secure sealing not available.");
15411c0c 1673 return -EOPNOTSUPP;
7560fffc
LP
1674#endif
1675}
1676
beec0085
LP
1677static int verify(sd_journal *j) {
1678 int r = 0;
1679 Iterator i;
1680 JournalFile *f;
1681
1682 assert(j);
1683
cedb42bb
LP
1684 log_show_color(true);
1685
c1f906bd 1686 ORDERED_HASHMAP_FOREACH(f, j->files, i) {
beec0085 1687 int k;
a7f7d1bd 1688 usec_t first = 0, validated = 0, last = 0;
beec0085 1689
56e81f7c 1690#ifdef HAVE_GCRYPT
feb12d3e 1691 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1692 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1693#endif
4da416aa 1694
2a7b539a 1695 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1696 if (k == -EINVAL) {
baed47c3 1697 /* If the key was invalid give up right-away. */
56e81f7c
LP
1698 return k;
1699 } else if (k < 0) {
e53fc357 1700 log_warning_errno(k, "FAIL: %s (%m)", f->path);
56e81f7c 1701 r = k;
6c7be122
LP
1702 } else {
1703 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1704 log_info("PASS: %s", f->path);
6c7be122 1705
c0ca7aee 1706 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1707 if (validated > 0) {
c0ca7aee 1708 log_info("=> Validated from %s to %s, final %s entries not sealed.",
5ab99e07
LP
1709 format_timestamp_maybe_utc(a, sizeof(a), first),
1710 format_timestamp_maybe_utc(b, sizeof(b), validated),
2fa4092c 1711 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1712 } else if (last > 0)
c0ca7aee 1713 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1714 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1715 else
1716 log_info("=> No sealing yet, no entries in file.");
1717 }
6c7be122 1718 }
beec0085
LP
1719 }
1720
1721 return r;
1722}
1723
6fe391c5 1724static int access_check_var_log_journal(sd_journal *j) {
e346512c 1725#ifdef HAVE_ACL
6fe391c5 1726 _cleanup_strv_free_ char **g = NULL;
e346512c
LP
1727 const char* dir;
1728#endif
6fe391c5
ZJS
1729 int r;
1730
1731 assert(j);
1732
e346512c
LP
1733 if (arg_quiet)
1734 return 0;
05c18530 1735
e346512c
LP
1736 /* If we are root, we should have access, don't warn. */
1737 if (getuid() == 0)
1738 return 0;
05c18530 1739
e346512c
LP
1740 /* If we are in the 'systemd-journal' group, we should have
1741 * access too. */
1742 r = in_group("systemd-journal");
1743 if (r < 0)
1744 return log_error_errno(r, "Failed to check if we are in the 'systemd-journal' group: %m");
1745 if (r > 0)
1746 return 0;
15804ceb 1747
e346512c
LP
1748#ifdef HAVE_ACL
1749 if (laccess("/run/log/journal", F_OK) >= 0)
1750 dir = "/run/log/journal";
1751 else
1752 dir = "/var/log/journal";
1753
1754 /* If we are in any of the groups listed in the journal ACLs,
1755 * then all is good, too. Let's enumerate all groups from the
1756 * default ACL of the directory, which generally should allow
1757 * access to most journal files too. */
1758 r = acl_search_groups(dir, &g);
1759 if (r < 0)
1760 return log_error_errno(r, "Failed to search journal ACL: %m");
1761 if (r > 0)
1762 return 0;
4468addc 1763
e346512c
LP
1764 /* Print a pretty list, if there were ACLs set. */
1765 if (!strv_isempty(g)) {
1766 _cleanup_free_ char *s = NULL;
4468addc 1767
e346512c
LP
1768 /* Thre are groups in the ACL, let's list them */
1769 r = strv_extend(&g, "systemd-journal");
1770 if (r < 0)
1771 return log_oom();
6fe391c5 1772
e346512c
LP
1773 strv_sort(g);
1774 strv_uniq(g);
6fe391c5 1775
e346512c
LP
1776 s = strv_join(g, "', '");
1777 if (!s)
1778 return log_oom();
6fe391c5 1779
e346512c
LP
1780 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1781 " Users in groups '%s' can see all messages.\n"
1782 " Pass -q to turn off this notice.", s);
1783 return 1;
6fe391c5 1784 }
e346512c 1785#endif
4468addc 1786
e346512c
LP
1787 /* If no ACLs were found, print a short version of the message. */
1788 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1789 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1790 " turn off this notice.");
1791
1792 return 1;
6fe391c5 1793}
4468addc 1794
6fe391c5 1795static int access_check(sd_journal *j) {
6fe391c5 1796 Iterator it;
3ac251b8 1797 void *code;
5768d259 1798 char *path;
6fe391c5 1799 int r = 0;
4468addc 1800
6fe391c5 1801 assert(j);
4468addc 1802
5768d259 1803 if (hashmap_isempty(j->errors)) {
c1f906bd 1804 if (ordered_hashmap_isempty(j->files))
3ac251b8 1805 log_notice("No journal files were found.");
e346512c 1806
6fe391c5
ZJS
1807 return 0;
1808 }
4468addc 1809
5768d259 1810 if (hashmap_contains(j->errors, INT_TO_PTR(-EACCES))) {
e346512c 1811 (void) access_check_var_log_journal(j);
3ac251b8 1812
e346512c
LP
1813 if (ordered_hashmap_isempty(j->files))
1814 r = log_error_errno(EACCES, "No journal files were opened due to insufficient permissions.");
6fe391c5 1815 }
15804ceb 1816
5768d259 1817 HASHMAP_FOREACH_KEY(path, code, j->errors, it) {
3ac251b8
LP
1818 int err;
1819
4f52b822 1820 err = abs(PTR_TO_INT(code));
3ac251b8 1821
5768d259
LP
1822 switch (err) {
1823 case EACCES:
e346512c
LP
1824 continue;
1825
5768d259
LP
1826 case ENODATA:
1827 log_warning_errno(err, "Journal file %s is truncated, ignoring file.", path);
1828 break;
1829
1830 case EPROTONOSUPPORT:
1831 log_warning_errno(err, "Journal file %s uses an unsupported feature, ignoring file.", path);
1832 break;
1833
1834 case EBADMSG:
1835 log_warning_errno(err, "Journal file %s corrupted, ignoring file.", path);
1836 break;
1837
1838 default:
1839 log_warning_errno(err, "An error was encountered while opening journal file %s, ignoring file.", path);
1840 break;
1841 }
6fe391c5
ZJS
1842 }
1843
6fe391c5 1844 return r;
15804ceb
LP
1845}
1846
74055aa7 1847static int flush_to_var(void) {
4afd3348
LP
1848 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1849 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
74055aa7
LP
1850 _cleanup_close_ int watch_fd = -1;
1851 int r;
1852
176ee07b
LP
1853 if (arg_machine) {
1854 log_error("--flush is not supported in conjunction with --machine=.");
1855 return -EOPNOTSUPP;
1856 }
1857
74055aa7
LP
1858 /* Quick exit */
1859 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1860 return 0;
1861
1862 /* OK, let's actually do the full logic, send SIGUSR1 to the
1863 * daemon and set up inotify to wait for the flushed file to appear */
266f3e26 1864 r = bus_connect_system_systemd(&bus);
23bbb0de
MS
1865 if (r < 0)
1866 return log_error_errno(r, "Failed to get D-Bus connection: %m");
74055aa7
LP
1867
1868 r = sd_bus_call_method(
1869 bus,
1870 "org.freedesktop.systemd1",
1871 "/org/freedesktop/systemd1",
1872 "org.freedesktop.systemd1.Manager",
1873 "KillUnit",
1874 &error,
1875 NULL,
1876 "ssi", "systemd-journald.service", "main", SIGUSR1);
94b65516
LP
1877 if (r < 0)
1878 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
74055aa7
LP
1879
1880 mkdir_p("/run/systemd/journal", 0755);
1881
1882 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
4a62c710
MS
1883 if (watch_fd < 0)
1884 return log_error_errno(errno, "Failed to create inotify watch: %m");
74055aa7
LP
1885
1886 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_CREATE|IN_DONT_FOLLOW|IN_ONLYDIR);
4a62c710
MS
1887 if (r < 0)
1888 return log_error_errno(errno, "Failed to watch journal directory: %m");
74055aa7
LP
1889
1890 for (;;) {
1891 if (access("/run/systemd/journal/flushed", F_OK) >= 0)
1892 break;
1893
4a62c710 1894 if (errno != ENOENT)
f131770b 1895 return log_error_errno(errno, "Failed to check for existence of /run/systemd/journal/flushed: %m");
74055aa7
LP
1896
1897 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
23bbb0de
MS
1898 if (r < 0)
1899 return log_error_errno(r, "Failed to wait for event: %m");
74055aa7
LP
1900
1901 r = flush_fd(watch_fd);
23bbb0de
MS
1902 if (r < 0)
1903 return log_error_errno(r, "Failed to flush inotify events: %m");
74055aa7
LP
1904 }
1905
1906 return 0;
1907}
1908
dbd6e31c 1909static int send_signal_and_wait(int sig, const char *watch_path) {
4afd3348 1910 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
94b65516
LP
1911 _cleanup_close_ int watch_fd = -1;
1912 usec_t start;
1913 int r;
1914
176ee07b
LP
1915 if (arg_machine) {
1916 log_error("--sync and --rotate are not supported in conjunction with --machine=.");
1917 return -EOPNOTSUPP;
1918 }
1919
33d52ab9 1920 start = now(CLOCK_MONOTONIC);
94b65516 1921
dbd6e31c
LP
1922 /* This call sends the specified signal to journald, and waits
1923 * for acknowledgment by watching the mtime of the specified
1924 * flag file. This is used to trigger syncing or rotation and
1925 * then wait for the operation to complete. */
94b65516
LP
1926
1927 for (;;) {
33d52ab9 1928 usec_t tstamp;
94b65516
LP
1929
1930 /* See if a sync happened by now. */
33d52ab9
LP
1931 r = read_timestamp_file(watch_path, &tstamp);
1932 if (r < 0 && r != -ENOENT)
1933 return log_error_errno(errno, "Failed to read %s: %m", watch_path);
1934 if (r >= 0 && tstamp >= start)
1935 return 0;
94b65516
LP
1936
1937 /* Let's ask for a sync, but only once. */
1938 if (!bus) {
4afd3348 1939 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
94b65516
LP
1940
1941 r = bus_connect_system_systemd(&bus);
1942 if (r < 0)
1943 return log_error_errno(r, "Failed to get D-Bus connection: %m");
1944
1945 r = sd_bus_call_method(
1946 bus,
1947 "org.freedesktop.systemd1",
1948 "/org/freedesktop/systemd1",
1949 "org.freedesktop.systemd1.Manager",
1950 "KillUnit",
1951 &error,
1952 NULL,
dbd6e31c 1953 "ssi", "systemd-journald.service", "main", sig);
94b65516
LP
1954 if (r < 0)
1955 return log_error_errno(r, "Failed to kill journal service: %s", bus_error_message(&error, r));
1956
1957 continue;
1958 }
1959
1960 /* Let's install the inotify watch, if we didn't do that yet. */
1961 if (watch_fd < 0) {
1962
1963 mkdir_p("/run/systemd/journal", 0755);
1964
1965 watch_fd = inotify_init1(IN_NONBLOCK|IN_CLOEXEC);
1966 if (watch_fd < 0)
1967 return log_error_errno(errno, "Failed to create inotify watch: %m");
1968
33d52ab9 1969 r = inotify_add_watch(watch_fd, "/run/systemd/journal", IN_MOVED_TO|IN_DONT_FOLLOW|IN_ONLYDIR);
94b65516
LP
1970 if (r < 0)
1971 return log_error_errno(errno, "Failed to watch journal directory: %m");
1972
1973 /* Recheck the flag file immediately, so that we don't miss any event since the last check. */
1974 continue;
1975 }
1976
1977 /* OK, all preparatory steps done, let's wait until
1978 * inotify reports an event. */
1979
1980 r = fd_wait_for_event(watch_fd, POLLIN, USEC_INFINITY);
1981 if (r < 0)
1982 return log_error_errno(r, "Failed to wait for event: %m");
1983
1984 r = flush_fd(watch_fd);
1985 if (r < 0)
1986 return log_error_errno(r, "Failed to flush inotify events: %m");
1987 }
1988
1989 return 0;
1990}
1991
dbd6e31c
LP
1992static int rotate(void) {
1993 return send_signal_and_wait(SIGUSR2, "/run/systemd/journal/rotated");
1994}
1995
1996static int sync_journal(void) {
1997 return send_signal_and_wait(SIGRTMIN+1, "/run/systemd/journal/synced");
1998}
1999
a963990f
LP
2000int main(int argc, char *argv[]) {
2001 int r;
4afd3348 2002 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
a963990f 2003 bool need_seek = false;
14a65d65 2004 sd_id128_t previous_boot_id;
67e04a48
ZJS
2005 bool previous_boot_id_valid = false, first_line = true;
2006 int n_shown = 0;
94e0bd7d 2007 bool ellipsized = false;
a963990f 2008
a9cdc94f 2009 setlocale(LC_ALL, "");
a963990f
LP
2010 log_parse_environment();
2011 log_open();
2012
2013 r = parse_argv(argc, argv);
2014 if (r <= 0)
2015 goto finish;
2016
ed757c0c 2017 signal(SIGWINCH, columns_lines_cache_reset);
2cf4172a 2018 sigbus_install();
ed757c0c 2019
de45d726
LP
2020 /* Increase max number of open files to 16K if we can, we
2021 * might needs this when browsing journal files, which might
2022 * be split up into many files. */
2023 setrlimit_closest(RLIMIT_NOFILE, &RLIMIT_MAKE_CONST(16384));
2024
a020b3b3 2025 switch (arg_action) {
94b65516 2026
a020b3b3
LP
2027 case ACTION_NEW_ID128:
2028 r = generate_new_id128();
e3fdfb49 2029 goto finish;
e3fdfb49 2030
a020b3b3 2031 case ACTION_SETUP_KEYS:
7560fffc
LP
2032 r = setup_keys();
2033 goto finish;
844ec79b 2034
a020b3b3
LP
2035 case ACTION_LIST_CATALOG:
2036 case ACTION_DUMP_CATALOG:
2037 case ACTION_UPDATE_CATALOG: {
0c6ea3a4
ZJS
2038 _cleanup_free_ char *database;
2039
2040 database = path_join(arg_root, CATALOG_DATABASE, NULL);
2041 if (!database) {
2042 r = log_oom();
2043 goto finish;
13cbf3a5
ZJS
2044 }
2045
844ec79b 2046 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 2047 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b 2048 if (r < 0)
da927ba9 2049 log_error_errno(r, "Failed to list catalog: %m");
844ec79b
ZJS
2050 } else {
2051 bool oneline = arg_action == ACTION_LIST_CATALOG;
2052
dd598123 2053 pager_open_if_enabled();
a020b3b3 2054
844ec79b 2055 if (optind < argc)
a020b3b3 2056 r = catalog_list_items(stdout, database, oneline, argv + optind);
844ec79b 2057 else
13cbf3a5 2058 r = catalog_list(stdout, database, oneline);
844ec79b 2059 if (r < 0)
da927ba9 2060 log_error_errno(r, "Failed to list catalog: %m");
844ec79b 2061 }
d4205751 2062
d4205751
LP
2063 goto finish;
2064 }
2065
a020b3b3
LP
2066 case ACTION_FLUSH:
2067 r = flush_to_var();
2068 goto finish;
2069
2070 case ACTION_SYNC:
2071 r = sync_journal();
2072 goto finish;
2073
2074 case ACTION_ROTATE:
2075 r = rotate();
2076 goto finish;
2077
2078 case ACTION_SHOW:
2079 case ACTION_PRINT_HEADER:
2080 case ACTION_VERIFY:
2081 case ACTION_DISK_USAGE:
2082 case ACTION_LIST_BOOTS:
2083 case ACTION_VACUUM:
2084 /* These ones require access to the journal files, continue below. */
2085 break;
2086
2087 default:
2088 assert_not_reached("Unknown action");
2089 }
2090
a963990f 2091 if (arg_directory)
3f3a438f 2092 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
8d98da3f
ZJS
2093 else if (arg_file)
2094 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
b6741478
LP
2095 else if (arg_machine)
2096 r = sd_journal_open_container(&j, arg_machine, 0);
a963990f 2097 else
3f3a438f 2098 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 2099 if (r < 0) {
a020b3b3 2100 log_error_errno(r, "Failed to open %s: %m", arg_directory ?: arg_file ? "files" : "journal");
909dea0c 2101 goto finish;
a963990f
LP
2102 }
2103
6fe391c5
ZJS
2104 r = access_check(j);
2105 if (r < 0)
909dea0c 2106 goto finish;
6fe391c5 2107
a020b3b3 2108 switch (arg_action) {
beec0085 2109
a020b3b3
LP
2110 case ACTION_NEW_ID128:
2111 case ACTION_SETUP_KEYS:
2112 case ACTION_LIST_CATALOG:
2113 case ACTION_DUMP_CATALOG:
2114 case ACTION_UPDATE_CATALOG:
2115 case ACTION_FLUSH:
2116 case ACTION_SYNC:
2117 case ACTION_ROTATE:
2118 assert_not_reached("Unexpected action.");
2119
2120 case ACTION_PRINT_HEADER:
dca6219e 2121 journal_print_header(j);
909dea0c
LP
2122 r = 0;
2123 goto finish;
dca6219e 2124
a020b3b3
LP
2125 case ACTION_VERIFY:
2126 r = verify(j);
2127 goto finish;
2128
2129 case ACTION_DISK_USAGE: {
39883f62 2130 uint64_t bytes = 0;
a1a03e30
LP
2131 char sbytes[FORMAT_BYTES_MAX];
2132
2133 r = sd_journal_get_usage(j, &bytes);
2134 if (r < 0)
909dea0c 2135 goto finish;
a1a03e30 2136
dbd2a83f 2137 printf("Archived and active journals take up %s on disk.\n",
763c7aa2 2138 format_bytes(sbytes, sizeof(sbytes), bytes));
909dea0c 2139 goto finish;
a1a03e30
LP
2140 }
2141
a020b3b3
LP
2142 case ACTION_LIST_BOOTS:
2143 r = list_boots(j);
2144 goto finish;
2145
2146 case ACTION_VACUUM: {
dbd2a83f
LP
2147 Directory *d;
2148 Iterator i;
2149
2150 HASHMAP_FOREACH(d, j->directories_by_path, i) {
2151 int q;
2152
2153 if (d->is_root)
2154 continue;
2155
8580d1f7 2156 q = journal_directory_vacuum(d->path, arg_vacuum_size, arg_vacuum_n_files, arg_vacuum_time, NULL, true);
dbd2a83f 2157 if (q < 0) {
8580d1f7 2158 log_error_errno(q, "Failed to vacuum %s: %m", d->path);
dbd2a83f
LP
2159 r = q;
2160 }
2161 }
2162
909dea0c 2163 goto finish;
dbd2a83f
LP
2164 }
2165
a020b3b3
LP
2166 case ACTION_SHOW:
2167 break;
2168
2169 default:
2170 assert_not_reached("Unknown action");
f1188074
ZJS
2171 }
2172
0f1a9a83
JS
2173 if (arg_boot_offset != 0 &&
2174 sd_journal_has_runtime_files(j) > 0 &&
2175 sd_journal_has_persistent_files(j) == 0) {
2176 log_info("Specifying boot ID has no effect, no persistent journal was found");
2177 r = 0;
2178 goto finish;
2179 }
a331b5e6
JJ
2180 /* add_boot() must be called first!
2181 * It may need to seek the journal to find parent boot IDs. */
2182 r = add_boot(j);
a963990f 2183 if (r < 0)
909dea0c 2184 goto finish;
a963990f 2185
99271804
ZJS
2186 r = add_dmesg(j);
2187 if (r < 0)
909dea0c 2188 goto finish;
99271804 2189
b9e40524 2190 r = add_units(j);
ea18a4b5 2191 if (r < 0) {
da927ba9 2192 log_error_errno(r, "Failed to add filter for units: %m");
909dea0c 2193 goto finish;
ea18a4b5 2194 }
c3f60ec5 2195
73083640
HH
2196 r = add_syslog_identifier(j);
2197 if (r < 0) {
da927ba9 2198 log_error_errno(r, "Failed to add filter for syslog identifiers: %m");
909dea0c 2199 goto finish;
73083640
HH
2200 }
2201
cd34b3c6 2202 r = add_priorities(j);
b56d608e 2203 if (r < 0)
909dea0c 2204 goto finish;
a963990f 2205
cd34b3c6 2206 r = add_matches(j, argv + optind);
b56d608e 2207 if (r < 0)
909dea0c 2208 goto finish;
941e990d 2209
553d2243 2210 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
2211 _cleanup_free_ char *filter;
2212
2213 filter = journal_make_match_string(j);
b56d608e
LP
2214 if (!filter)
2215 return log_oom();
2216
4ad16808
ZJS
2217 log_debug("Journal filter: %s", filter);
2218 }
67e04a48 2219
15119c16
LP
2220 if (arg_field) {
2221 const void *data;
2222 size_t size;
2223
21ae4593
ZJS
2224 r = sd_journal_set_data_threshold(j, 0);
2225 if (r < 0) {
b56d608e 2226 log_error_errno(r, "Failed to unset data size threshold: %m");
909dea0c 2227 goto finish;
21ae4593
ZJS
2228 }
2229
15119c16
LP
2230 r = sd_journal_query_unique(j, arg_field);
2231 if (r < 0) {
da927ba9 2232 log_error_errno(r, "Failed to query unique data objects: %m");
909dea0c 2233 goto finish;
15119c16
LP
2234 }
2235
2236 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
2237 const void *eq;
2238
67e04a48 2239 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
2240 break;
2241
15119c16
LP
2242 eq = memchr(data, '=', size);
2243 if (eq)
2244 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
2245 else
2246 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
2247
2248 n_shown ++;
15119c16
LP
2249 }
2250
909dea0c
LP
2251 r = 0;
2252 goto finish;
15119c16
LP
2253 }
2254
8d98da3f
ZJS
2255 /* Opening the fd now means the first sd_journal_wait() will actually wait */
2256 if (arg_follow) {
2257 r = sd_journal_get_fd(j);
b56d608e
LP
2258 if (r < 0) {
2259 log_error_errno(r, "Failed to get journal fd: %m");
909dea0c 2260 goto finish;
b56d608e 2261 }
8d98da3f
ZJS
2262 }
2263
248fc619 2264 if (arg_cursor || arg_after_cursor) {
eacbb4d3 2265 r = sd_journal_seek_cursor(j, arg_cursor ?: arg_after_cursor);
08984293 2266 if (r < 0) {
da927ba9 2267 log_error_errno(r, "Failed to seek to cursor: %m");
909dea0c 2268 goto finish;
08984293 2269 }
909dea0c 2270
d89d6c86 2271 if (!arg_reverse)
248fc619 2272 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 2273 else
248fc619
ZJS
2274 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
2275
8ee8e536 2276 if (arg_after_cursor && r < 2) {
248fc619 2277 /* We couldn't find the next entry after the cursor. */
8ee8e536
WD
2278 if (arg_follow)
2279 need_seek = true;
2280 else
2281 arg_lines = 0;
2282 }
08984293 2283
d89d6c86 2284 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 2285 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 2286 if (r < 0) {
da927ba9 2287 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2288 goto finish;
8f14c832 2289 }
8f14c832
LP
2290 r = sd_journal_next(j);
2291
d89d6c86
LN
2292 } else if (arg_until_set && arg_reverse) {
2293 r = sd_journal_seek_realtime_usec(j, arg_until);
2294 if (r < 0) {
da927ba9 2295 log_error_errno(r, "Failed to seek to date: %m");
909dea0c 2296 goto finish;
d89d6c86
LN
2297 }
2298 r = sd_journal_previous(j);
2299
67e04a48 2300 } else if (arg_lines >= 0) {
2100675e
LP
2301 r = sd_journal_seek_tail(j);
2302 if (r < 0) {
da927ba9 2303 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2304 goto finish;
2100675e
LP
2305 }
2306
2307 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 2308
d89d6c86
LN
2309 } else if (arg_reverse) {
2310 r = sd_journal_seek_tail(j);
2311 if (r < 0) {
da927ba9 2312 log_error_errno(r, "Failed to seek to tail: %m");
909dea0c 2313 goto finish;
d89d6c86
LN
2314 }
2315
2316 r = sd_journal_previous(j);
2317
2100675e
LP
2318 } else {
2319 r = sd_journal_seek_head(j);
2320 if (r < 0) {
da927ba9 2321 log_error_errno(r, "Failed to seek to head: %m");
909dea0c 2322 goto finish;
2100675e 2323 }
6f003b43
LP
2324
2325 r = sd_journal_next(j);
2326 }
2327
2328 if (r < 0) {
da927ba9 2329 log_error_errno(r, "Failed to iterate through journal: %m");
909dea0c 2330 goto finish;
50f20cfd 2331 }
02ab86c7 2332 if (r == 0) {
c51e1a96
SW
2333 if (arg_follow)
2334 need_seek = true;
2335 else {
bfcb7c5f
EV
2336 if (!arg_quiet)
2337 printf("-- No entries --\n");
c51e1a96
SW
2338 goto finish;
2339 }
02ab86c7 2340 }
87d2c1ff 2341
faf5077f
DH
2342 if (!arg_follow)
2343 pager_open_if_enabled();
0d43c694 2344
cfbc22ab
LP
2345 if (!arg_quiet) {
2346 usec_t start, end;
2347 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
2348
2349 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
2350 if (r < 0) {
da927ba9 2351 log_error_errno(r, "Failed to get cutoff: %m");
cfbc22ab
LP
2352 goto finish;
2353 }
2354
2355 if (r > 0) {
2356 if (arg_follow)
9048b11f 2357 printf("-- Logs begin at %s. --\n",
5ab99e07 2358 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start));
cfbc22ab 2359 else
9048b11f 2360 printf("-- Logs begin at %s, end at %s. --\n",
5ab99e07
LP
2361 format_timestamp_maybe_utc(start_buf, sizeof(start_buf), start),
2362 format_timestamp_maybe_utc(end_buf, sizeof(end_buf), end));
cfbc22ab
LP
2363 }
2364 }
2365
50f20cfd 2366 for (;;) {
67e04a48 2367 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
2368 int flags;
2369
6f003b43 2370 if (need_seek) {
99613ec5 2371 if (!arg_reverse)
d89d6c86
LN
2372 r = sd_journal_next(j);
2373 else
2374 r = sd_journal_previous(j);
6f003b43 2375 if (r < 0) {
da927ba9 2376 log_error_errno(r, "Failed to iterate through journal: %m");
6f003b43
LP
2377 goto finish;
2378 }
a72b6353
ZJS
2379 if (r == 0)
2380 break;
0d43c694
LP
2381 }
2382
d89d6c86 2383 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
2384 usec_t usec;
2385
2386 r = sd_journal_get_realtime_usec(j, &usec);
2387 if (r < 0) {
da927ba9 2388 log_error_errno(r, "Failed to determine timestamp: %m");
cfbc22ab
LP
2389 goto finish;
2390 }
3ba09ee8
PF
2391 if (usec > arg_until)
2392 goto finish;
cfbc22ab
LP
2393 }
2394
d89d6c86
LN
2395 if (arg_since_set && arg_reverse) {
2396 usec_t usec;
2397
2398 r = sd_journal_get_realtime_usec(j, &usec);
2399 if (r < 0) {
da927ba9 2400 log_error_errno(r, "Failed to determine timestamp: %m");
d89d6c86
LN
2401 goto finish;
2402 }
2403 if (usec < arg_since)
2404 goto finish;
2405 }
2406
4bed2485 2407 if (!arg_merge && !arg_quiet) {
cd931c0a 2408 sd_id128_t boot_id;
14a65d65 2409
cd931c0a
LP
2410 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
2411 if (r >= 0) {
2412 if (previous_boot_id_valid &&
2413 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c 2414 printf("%s-- Reboot --%s\n",
1fc464f6 2415 ansi_highlight(), ansi_normal());
cd931c0a
LP
2416
2417 previous_boot_id = boot_id;
2418 previous_boot_id_valid = true;
2419 }
14a65d65
LP
2420 }
2421
cfbc22ab 2422 flags =
cd4b13e0 2423 arg_all * OUTPUT_SHOW_ALL |
2b8f6883 2424 arg_full * OUTPUT_FULL_WIDTH |
40c9fe4c 2425 colors_enabled() * OUTPUT_COLOR |
9fd29044
JS
2426 arg_catalog * OUTPUT_CATALOG |
2427 arg_utc * OUTPUT_UTC;
cfbc22ab 2428
94e0bd7d 2429 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
a72b6353
ZJS
2430 need_seek = true;
2431 if (r == -EADDRNOTAVAIL)
2432 break;
2433 else if (r < 0 || ferror(stdout))
72f59706 2434 goto finish;
6f003b43 2435
cfbc22ab 2436 n_shown++;
87d2c1ff
LP
2437 }
2438
248fc619
ZJS
2439 if (!arg_follow) {
2440 if (arg_show_cursor) {
2441 _cleanup_free_ char *cursor = NULL;
2442
2443 r = sd_journal_get_cursor(j, &cursor);
2444 if (r < 0 && r != -EADDRNOTAVAIL)
da927ba9 2445 log_error_errno(r, "Failed to get cursor: %m");
248fc619
ZJS
2446 else if (r >= 0)
2447 printf("-- cursor: %s\n", cursor);
2448 }
2449
50f20cfd 2450 break;
248fc619 2451 }
50f20cfd 2452
e02d1cf7 2453 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 2454 if (r < 0) {
da927ba9 2455 log_error_errno(r, "Couldn't wait for journal event: %m");
50f20cfd
LP
2456 goto finish;
2457 }
67e04a48
ZJS
2458
2459 first_line = false;
de190aef 2460 }
87d2c1ff
LP
2461
2462finish:
0d43c694
LP
2463 pager_close();
2464
a36b8deb
ZJS
2465 strv_free(arg_file);
2466
d52da205
LP
2467 strv_free(arg_syslog_identifier);
2468 strv_free(arg_system_units);
2469 strv_free(arg_user_units);
2470
0f03c2a4
LP
2471 free(arg_root);
2472
3fbf9cbb 2473 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 2474}