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