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