chiark / gitweb /
journalctl: Add support for showing messages from a previous boot
[elogind.git] / src / journal / journalctl.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2011 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <locale.h>
23 #include <fcntl.h>
24 #include <errno.h>
25 #include <stddef.h>
26 #include <string.h>
27 #include <stdio.h>
28 #include <unistd.h>
29 #include <stdlib.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <signal.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <linux/fs.h>
36
37 #ifdef HAVE_ACL
38 #include <sys/acl.h>
39 #include "acl-util.h"
40 #endif
41
42 #include <systemd/sd-journal.h>
43
44 #include "log.h"
45 #include "logs-show.h"
46 #include "util.h"
47 #include "path-util.h"
48 #include "build.h"
49 #include "pager.h"
50 #include "logs-show.h"
51 #include "strv.h"
52 #include "journal-internal.h"
53 #include "journal-def.h"
54 #include "journal-verify.h"
55 #include "journal-authenticate.h"
56 #include "journal-qrcode.h"
57 #include "fsprg.h"
58 #include "unit-name.h"
59 #include "catalog.h"
60
61 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
62
63 static OutputMode arg_output = OUTPUT_SHORT;
64 static bool arg_pager_end = false;
65 static bool arg_follow = false;
66 static bool arg_full = false;
67 static bool arg_all = false;
68 static bool arg_no_pager = false;
69 static int arg_lines = -1;
70 static bool arg_no_tail = false;
71 static bool arg_quiet = false;
72 static bool arg_merge = false;
73 static bool arg_boot_id = false;
74 static char *arg_boot_id_descriptor = NULL;
75 static bool arg_dmesg = false;
76 static const char *arg_cursor = NULL;
77 static const char *arg_directory = NULL;
78 static char **arg_file = NULL;
79 static int arg_priorities = 0xFF;
80 static const char *arg_verify_key = NULL;
81 #ifdef HAVE_GCRYPT
82 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
83 static bool arg_force = false;
84 #endif
85 static usec_t arg_since, arg_until;
86 static bool arg_since_set = false, arg_until_set = false;
87 static char **arg_system_units = NULL;
88 static char **arg_user_units = NULL;
89 static const char *arg_field = NULL;
90 static bool arg_catalog = false;
91 static bool arg_reverse = false;
92 static int arg_journal_type = 0;
93 static const char *arg_root = NULL;
94
95 static enum {
96         ACTION_SHOW,
97         ACTION_NEW_ID128,
98         ACTION_PRINT_HEADER,
99         ACTION_SETUP_KEYS,
100         ACTION_VERIFY,
101         ACTION_DISK_USAGE,
102         ACTION_LIST_CATALOG,
103         ACTION_DUMP_CATALOG,
104         ACTION_UPDATE_CATALOG
105 } arg_action = ACTION_SHOW;
106
107 typedef struct boot_id_t {
108         sd_id128_t id;
109         uint64_t timestamp;
110 } boot_id_t;
111
112 static int help(void) {
113
114         printf("%s [OPTIONS...] [MATCHES...]\n\n"
115                "Query the journal.\n\n"
116                "Flags:\n"
117                "     --system            Show only the system journal\n"
118                "     --user              Show only the user journal for current user\n"
119                "     --since=DATE        Start showing entries newer or of the specified date\n"
120                "     --until=DATE        Stop showing entries older or of the specified date\n"
121                "  -c --cursor=CURSOR     Start showing entries from specified cursor\n"
122                "  -b --boot[=ID]         Show data only from ID or current boot if unspecified\n"
123                "  -k --dmesg             Show kernel message log from current boot\n"
124                "  -u --unit=UNIT         Show data only from the specified unit\n"
125                "     --user-unit=UNIT    Show data only from the specified user session unit\n"
126                "  -p --priority=RANGE    Show only messages within the specified priority range\n"
127                "  -e --pager-end         Immediately jump to end of the journal in the pager\n"
128                "  -f --follow            Follow journal\n"
129                "  -n --lines[=INTEGER]   Number of journal entries to show\n"
130                "     --no-tail           Show all lines, even in follow mode\n"
131                "  -r --reverse           Show the newest entries first\n"
132                "  -o --output=STRING     Change journal output mode (short, short-monotonic,\n"
133                "                         verbose, export, json, json-pretty, json-sse, cat)\n"
134                "  -x --catalog           Add message explanations where available\n"
135                "  -l --full              Do not ellipsize fields\n"
136                "  -a --all               Show all fields, including long and unprintable\n"
137                "  -q --quiet             Don't show privilege warning\n"
138                "     --no-pager          Do not pipe output into a pager\n"
139                "  -m --merge             Show entries from all available journals\n"
140                "  -D --directory=PATH    Show journal files from directory\n"
141                "     --file=PATH         Show journal file\n"
142                "     --root=ROOT         Operate on catalog files underneath the root ROOT\n"
143 #ifdef HAVE_GCRYPT
144                "     --interval=TIME     Time interval for changing the FSS sealing key\n"
145                "     --verify-key=KEY    Specify FSS verification key\n"
146 #endif
147                "\nCommands:\n"
148                "  -h --help              Show this help\n"
149                "     --version           Show package version\n"
150                "     --new-id128         Generate a new 128 Bit ID\n"
151                "     --header            Show journal header information\n"
152                "     --disk-usage        Show total disk usage\n"
153                "  -F --field=FIELD       List all values a certain field takes\n"
154                "     --list-catalog      Show message IDs of all entries in the message catalog\n"
155                "     --dump-catalog      Show entries in the message catalog\n"
156                "     --update-catalog    Update the message catalog database\n"
157 #ifdef HAVE_GCRYPT
158                "     --setup-keys        Generate new FSS key pair\n"
159                "     --force             Force overriding new FSS key pair with --setup-keys\n"
160                "     --verify            Verify journal file consistency\n"
161 #endif
162                , program_invocation_short_name);
163
164         return 0;
165 }
166
167 static int parse_argv(int argc, char *argv[]) {
168
169         enum {
170                 ARG_VERSION = 0x100,
171                 ARG_NO_PAGER,
172                 ARG_NO_TAIL,
173                 ARG_NEW_ID128,
174                 ARG_USER,
175                 ARG_SYSTEM,
176                 ARG_ROOT,
177                 ARG_HEADER,
178                 ARG_SETUP_KEYS,
179                 ARG_FILE,
180                 ARG_INTERVAL,
181                 ARG_VERIFY,
182                 ARG_VERIFY_KEY,
183                 ARG_DISK_USAGE,
184                 ARG_SINCE,
185                 ARG_UNTIL,
186                 ARG_USER_UNIT,
187                 ARG_LIST_CATALOG,
188                 ARG_DUMP_CATALOG,
189                 ARG_UPDATE_CATALOG,
190                 ARG_FORCE,
191         };
192
193         static const struct option options[] = {
194                 { "help",         no_argument,       NULL, 'h'              },
195                 { "version" ,     no_argument,       NULL, ARG_VERSION      },
196                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
197                 { "pager-end",    no_argument,       NULL, 'e'              },
198                 { "follow",       no_argument,       NULL, 'f'              },
199                 { "force",        no_argument,       NULL, ARG_FORCE        },
200                 { "output",       required_argument, NULL, 'o'              },
201                 { "all",          no_argument,       NULL, 'a'              },
202                 { "full",         no_argument,       NULL, 'l'              },
203                 { "lines",        optional_argument, NULL, 'n'              },
204                 { "no-tail",      no_argument,       NULL, ARG_NO_TAIL      },
205                 { "new-id128",    no_argument,       NULL, ARG_NEW_ID128    },
206                 { "quiet",        no_argument,       NULL, 'q'              },
207                 { "merge",        no_argument,       NULL, 'm'              },
208                 { "boot",         optional_argument, NULL, 'b'              },
209                 { "this-boot",    optional_argument, NULL, 'b'              }, /* deprecated */
210                 { "dmesg",        no_argument,       NULL, 'k'              },
211                 { "system",       no_argument,       NULL, ARG_SYSTEM       },
212                 { "user",         no_argument,       NULL, ARG_USER         },
213                 { "directory",    required_argument, NULL, 'D'              },
214                 { "file",         required_argument, NULL, ARG_FILE         },
215                 { "root",         required_argument, NULL, ARG_ROOT         },
216                 { "header",       no_argument,       NULL, ARG_HEADER       },
217                 { "priority",     required_argument, NULL, 'p'              },
218                 { "setup-keys",   no_argument,       NULL, ARG_SETUP_KEYS   },
219                 { "interval",     required_argument, NULL, ARG_INTERVAL     },
220                 { "verify",       no_argument,       NULL, ARG_VERIFY       },
221                 { "verify-key",   required_argument, NULL, ARG_VERIFY_KEY   },
222                 { "disk-usage",   no_argument,       NULL, ARG_DISK_USAGE   },
223                 { "cursor",       required_argument, NULL, 'c'              },
224                 { "since",        required_argument, NULL, ARG_SINCE        },
225                 { "until",        required_argument, NULL, ARG_UNTIL        },
226                 { "unit",         required_argument, NULL, 'u'              },
227                 { "user-unit",    required_argument, NULL, ARG_USER_UNIT    },
228                 { "field",        required_argument, NULL, 'F'              },
229                 { "catalog",      no_argument,       NULL, 'x'              },
230                 { "list-catalog", no_argument,       NULL, ARG_LIST_CATALOG },
231                 { "dump-catalog", no_argument,       NULL, ARG_DUMP_CATALOG },
232                 { "update-catalog",no_argument,      NULL, ARG_UPDATE_CATALOG },
233                 { "reverse",      no_argument,       NULL, 'r'              },
234                 { NULL,           0,                 NULL, 0                }
235         };
236
237         int c, r;
238
239         assert(argc >= 0);
240         assert(argv);
241
242         while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xr", options, NULL)) >= 0) {
243
244                 switch (c) {
245
246                 case 'h':
247                         help();
248                         return 0;
249
250                 case ARG_VERSION:
251                         puts(PACKAGE_STRING);
252                         puts(SYSTEMD_FEATURES);
253                         return 0;
254
255                 case ARG_NO_PAGER:
256                         arg_no_pager = true;
257                         break;
258
259                 case 'e':
260                         arg_pager_end = true;
261
262                         if (arg_lines < 0)
263                                 arg_lines = 1000;
264
265                         break;
266
267                 case 'f':
268                         arg_follow = true;
269                         break;
270
271                 case 'o':
272                         arg_output = output_mode_from_string(optarg);
273                         if (arg_output < 0) {
274                                 log_error("Unknown output format '%s'.", optarg);
275                                 return -EINVAL;
276                         }
277
278                         if (arg_output == OUTPUT_EXPORT ||
279                             arg_output == OUTPUT_JSON ||
280                             arg_output == OUTPUT_JSON_PRETTY ||
281                             arg_output == OUTPUT_JSON_SSE ||
282                             arg_output == OUTPUT_CAT)
283                                 arg_quiet = true;
284
285                         break;
286
287                 case 'l':
288                         arg_full = true;
289                         break;
290
291                 case 'a':
292                         arg_all = true;
293                         break;
294
295                 case 'n':
296                         if (optarg) {
297                                 r = safe_atoi(optarg, &arg_lines);
298                                 if (r < 0 || arg_lines < 0) {
299                                         log_error("Failed to parse lines '%s'", optarg);
300                                         return -EINVAL;
301                                 }
302                         } else {
303                                 int n;
304
305                                 /* Hmm, no argument? Maybe the next
306                                  * word on the command line is
307                                  * supposed to be the argument? Let's
308                                  * see if there is one, and is
309                                  * parsable as a positive
310                                  * integer... */
311
312                                 if (optind < argc &&
313                                     safe_atoi(argv[optind], &n) >= 0 &&
314                                     n >= 0) {
315
316                                         arg_lines = n;
317                                         optind++;
318                                 } else
319                                         arg_lines = 10;
320                         }
321
322                         break;
323
324                 case ARG_NO_TAIL:
325                         arg_no_tail = true;
326                         break;
327
328                 case ARG_NEW_ID128:
329                         arg_action = ACTION_NEW_ID128;
330                         break;
331
332                 case 'q':
333                         arg_quiet = true;
334                         break;
335
336                 case 'm':
337                         arg_merge = true;
338                         break;
339
340                 case 'b':
341                         if (optarg)
342                                 arg_boot_id_descriptor = optarg;
343                         else if (optind < argc && argv[optind][0] != '-') {
344                                 arg_boot_id_descriptor = argv[optind];
345                                 optind++;
346                         }
347                         arg_boot_id = true;
348                         break;
349
350                 case 'k':
351                         arg_boot_id = arg_dmesg = true;
352                         break;
353
354                 case ARG_SYSTEM:
355                         arg_journal_type |= SD_JOURNAL_SYSTEM;
356                         break;
357
358                 case ARG_USER:
359                         arg_journal_type |= SD_JOURNAL_CURRENT_USER;
360                         break;
361
362                 case 'D':
363                         arg_directory = optarg;
364                         break;
365
366                 case ARG_FILE:
367                         r = glob_extend(&arg_file, optarg);
368                         if (r < 0) {
369                                 log_error("Failed to add paths: %s", strerror(-r));
370                                 return r;
371                         };
372                         break;
373
374                 case ARG_ROOT:
375                         arg_root = optarg;
376                         break;
377
378                 case 'c':
379                         arg_cursor = optarg;
380                         break;
381
382                 case ARG_HEADER:
383                         arg_action = ACTION_PRINT_HEADER;
384                         break;
385
386                 case ARG_VERIFY:
387                         arg_action = ACTION_VERIFY;
388                         break;
389
390                 case ARG_DISK_USAGE:
391                         arg_action = ACTION_DISK_USAGE;
392                         break;
393
394 #ifdef HAVE_GCRYPT
395                 case ARG_FORCE:
396                         arg_force = true;
397                         break;
398
399                 case ARG_SETUP_KEYS:
400                         arg_action = ACTION_SETUP_KEYS;
401                         break;
402
403
404                 case ARG_VERIFY_KEY:
405                         arg_action = ACTION_VERIFY;
406                         arg_verify_key = optarg;
407                         arg_merge = false;
408                         break;
409
410                 case ARG_INTERVAL:
411                         r = parse_sec(optarg, &arg_interval);
412                         if (r < 0 || arg_interval <= 0) {
413                                 log_error("Failed to parse sealing key change interval: %s", optarg);
414                                 return -EINVAL;
415                         }
416                         break;
417 #else
418                 case ARG_SETUP_KEYS:
419                 case ARG_VERIFY_KEY:
420                 case ARG_INTERVAL:
421                 case ARG_FORCE:
422                         log_error("Forward-secure sealing not available.");
423                         return -ENOTSUP;
424 #endif
425
426                 case 'p': {
427                         const char *dots;
428
429                         dots = strstr(optarg, "..");
430                         if (dots) {
431                                 char *a;
432                                 int from, to, i;
433
434                                 /* a range */
435                                 a = strndup(optarg, dots - optarg);
436                                 if (!a)
437                                         return log_oom();
438
439                                 from = log_level_from_string(a);
440                                 to = log_level_from_string(dots + 2);
441                                 free(a);
442
443                                 if (from < 0 || to < 0) {
444                                         log_error("Failed to parse log level range %s", optarg);
445                                         return -EINVAL;
446                                 }
447
448                                 arg_priorities = 0;
449
450                                 if (from < to) {
451                                         for (i = from; i <= to; i++)
452                                                 arg_priorities |= 1 << i;
453                                 } else {
454                                         for (i = to; i <= from; i++)
455                                                 arg_priorities |= 1 << i;
456                                 }
457
458                         } else {
459                                 int p, i;
460
461                                 p = log_level_from_string(optarg);
462                                 if (p < 0) {
463                                         log_error("Unknown log level %s", optarg);
464                                         return -EINVAL;
465                                 }
466
467                                 arg_priorities = 0;
468
469                                 for (i = 0; i <= p; i++)
470                                         arg_priorities |= 1 << i;
471                         }
472
473                         break;
474                 }
475
476                 case ARG_SINCE:
477                         r = parse_timestamp(optarg, &arg_since);
478                         if (r < 0) {
479                                 log_error("Failed to parse timestamp: %s", optarg);
480                                 return -EINVAL;
481                         }
482                         arg_since_set = true;
483                         break;
484
485                 case ARG_UNTIL:
486                         r = parse_timestamp(optarg, &arg_until);
487                         if (r < 0) {
488                                 log_error("Failed to parse timestamp: %s", optarg);
489                                 return -EINVAL;
490                         }
491                         arg_until_set = true;
492                         break;
493
494                 case 'u':
495                         r = strv_extend(&arg_system_units, optarg);
496                         if (r < 0)
497                                 return log_oom();
498                         break;
499
500                 case ARG_USER_UNIT:
501                         r = strv_extend(&arg_user_units, optarg);
502                         if (r < 0)
503                                 return log_oom();
504                         break;
505
506                 case '?':
507                         return -EINVAL;
508
509                 case 'F':
510                         arg_field = optarg;
511                         break;
512
513                 case 'x':
514                         arg_catalog = true;
515                         break;
516
517                 case ARG_LIST_CATALOG:
518                         arg_action = ACTION_LIST_CATALOG;
519                         break;
520
521                 case ARG_DUMP_CATALOG:
522                         arg_action = ACTION_DUMP_CATALOG;
523                         break;
524
525                 case ARG_UPDATE_CATALOG:
526                         arg_action = ACTION_UPDATE_CATALOG;
527                         break;
528
529                 case 'r':
530                         arg_reverse = true;
531                         break;
532
533                 default:
534                         log_error("Unknown option code %c", c);
535                         return -EINVAL;
536                 }
537         }
538
539         if (arg_follow && !arg_no_tail && arg_lines < 0)
540                 arg_lines = 10;
541
542         if (arg_directory && arg_file) {
543                 log_error("Please specify either -D/--directory= or --file=, not both.");
544                 return -EINVAL;
545         }
546
547         if (arg_since_set && arg_until_set && arg_since > arg_until) {
548                 log_error("--since= must be before --until=.");
549                 return -EINVAL;
550         }
551
552         if (arg_cursor && arg_since_set) {
553                 log_error("Please specify either --since= or --cursor=, not both.");
554                 return -EINVAL;
555         }
556
557         if (arg_follow && arg_reverse) {
558                 log_error("Please specify either --reverse= or --follow=, not both.");
559                 return -EINVAL;
560         }
561
562         return 1;
563 }
564
565 static int generate_new_id128(void) {
566         sd_id128_t id;
567         int r;
568         unsigned i;
569
570         r = sd_id128_randomize(&id);
571         if (r < 0) {
572                 log_error("Failed to generate ID: %s", strerror(-r));
573                 return r;
574         }
575
576         printf("As string:\n"
577                SD_ID128_FORMAT_STR "\n\n"
578                "As UUID:\n"
579                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
580                "As macro:\n"
581                "#define MESSAGE_XYZ SD_ID128_MAKE(",
582                SD_ID128_FORMAT_VAL(id),
583                SD_ID128_FORMAT_VAL(id));
584         for (i = 0; i < 16; i++)
585                 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
586         fputs(")\n\n", stdout);
587
588         printf("As Python constant:\n"
589                ">>> import uuid\n"
590                ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
591                SD_ID128_FORMAT_VAL(id));
592
593         return 0;
594 }
595
596 static int add_matches(sd_journal *j, char **args) {
597         char **i;
598
599         assert(j);
600
601         STRV_FOREACH(i, args) {
602                 int r;
603
604                 if (streq(*i, "+"))
605                         r = sd_journal_add_disjunction(j);
606                 else if (path_is_absolute(*i)) {
607                         _cleanup_free_ char *p, *t = NULL;
608                         const char *path;
609                         struct stat st;
610
611                         p = canonicalize_file_name(*i);
612                         path = p ? p : *i;
613
614                         if (stat(path, &st) < 0)  {
615                                 log_error("Couldn't stat file: %m");
616                                 return -errno;
617                         }
618
619                         if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
620                                 t = strappend("_EXE=", path);
621                         else if (S_ISCHR(st.st_mode))
622                                 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
623                         else if (S_ISBLK(st.st_mode))
624                                 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
625                         else {
626                                 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
627                                 return -EINVAL;
628                         }
629
630                         if (!t)
631                                 return log_oom();
632
633                         r = sd_journal_add_match(j, t, 0);
634                 } else
635                         r = sd_journal_add_match(j, *i, 0);
636
637                 if (r < 0) {
638                         log_error("Failed to add match '%s': %s", *i, strerror(-r));
639                         return r;
640                 }
641         }
642
643         return 0;
644 }
645
646 static int boot_id_cmp(const void *a, const void *b) {
647         uint64_t _a, _b;
648
649         _a = ((const boot_id_t *)a)->timestamp;
650         _b = ((const boot_id_t *)b)->timestamp;
651
652         return _a < _b ? -1 : (_a > _b ? 1 : 0);
653 }
654
655 static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
656         int r;
657         const void *data;
658         unsigned int id_count = 0;
659         size_t length, allocated = 0;
660         boot_id_t ref_boot_id, *id;
661         _cleanup_free_ boot_id_t *all_ids = NULL;
662         bool find_first_boot = false, ref_boot_found = false;
663
664         assert(j);
665         assert(boot_id);
666
667         if (relative == 0)
668                 return 0;
669
670         if (sd_id128_equal(*boot_id, SD_ID128_NULL) && relative > 0) {
671                 find_first_boot = true;
672                 relative--;
673         }
674
675         r = sd_journal_query_unique(j, "_BOOT_ID");
676         if (r < 0)
677                 return r;
678
679         SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
680                 if (length < strlen("_BOOT_ID="))
681                         continue;
682
683                 if (!GREEDY_REALLOC(all_ids, allocated, id_count + 1))
684                         return log_oom();
685
686                 id = &all_ids[id_count];
687
688                 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
689                 if (r < 0) {
690                         continue;
691                 }
692
693                 sd_journal_flush_matches(j);
694                 r = sd_journal_add_match(j, data, length);
695                 if (r < 0)
696                         continue;
697
698                 r = sd_journal_seek_head(j);
699                 if (r < 0)
700                         continue;
701
702                 r = sd_journal_next(j);
703                 if (r <= 0)
704                         continue;
705
706                 r = sd_journal_get_realtime_usec(j, &id->timestamp);
707                 if (r < 0)
708                         continue;
709
710                 if (!find_first_boot && sd_id128_equal(id->id, *boot_id)) {
711                         ref_boot_id = *id;
712                         ref_boot_found = true;
713                 }
714
715                 id_count++;
716         }
717
718         *boot_id = SD_ID128_NULL;
719         sd_journal_flush_matches(j);
720
721         if (id_count == 0 || (!find_first_boot && !ref_boot_found))
722                 return 0;
723
724         qsort(all_ids, id_count, sizeof(boot_id_t), boot_id_cmp);
725         if (find_first_boot)
726                 id = all_ids;
727         else
728                 id = bsearch(&ref_boot_id, all_ids, id_count, sizeof(boot_id_t), boot_id_cmp);
729
730         if (!id || (relative < 0 && ((id - all_ids) + relative) < 0) ||
731             (relative >= 0 && (unsigned long)((id - all_ids) + relative) >= id_count))
732                 return 0;
733
734         id += relative;
735         *boot_id = id->id;
736         return 0;
737 }
738
739 static int add_boot(sd_journal *j) {
740         char match[9+32+1] = "_BOOT_ID=";
741         char *marker;
742         sd_id128_t boot_id;
743         int r, relative = 0;
744
745         assert(j);
746
747         if (!arg_boot_id)
748                 return 0;
749
750         if (arg_boot_id_descriptor) {
751                 marker = strchr(arg_boot_id_descriptor, ':');
752                 if (marker) {
753                         *marker = '\0';
754                         marker++;
755
756                         if (*marker == '\0')
757                                 relative = -1;
758                         else {
759                                 r = safe_atoi(marker, &relative);
760                                 if (r < 0) {
761                                         log_error("Failed to parse relative boot ID number '%s'", marker);
762                                         return -EINVAL;
763                                 }
764                         }
765                 }
766         }
767
768         if (isempty(arg_boot_id_descriptor)) {
769                 if (relative > 0) {
770                         /* We cannot look into the future. Instead, we look
771                          * into the past (starting from first boot). The ID
772                          * will be looked up later */
773                         boot_id = SD_ID128_NULL;
774                 } else {
775                         r = sd_id128_get_boot(&boot_id);
776                         if (r < 0) {
777                                 log_error("Failed to get boot ID: %s", strerror(-r));
778                                 return r;
779                         }
780                 }
781         } else {
782                 r = sd_id128_from_string(arg_boot_id_descriptor, &boot_id);
783                 if (r < 0) {
784                         log_error("Failed to parse boot ID: %s", strerror(-r));
785                         return r;
786                 }
787         }
788
789         r = get_relative_boot_id(j, &boot_id, relative);
790         if (r < 0) {
791                 log_error("Failed to look up boot ID: %s", strerror(-r));
792                 return r;
793         } else if (sd_id128_equal(boot_id, SD_ID128_NULL)) {
794                 log_error("Failed to find boot ID");
795                 return -1;
796         }
797
798         sd_id128_to_string(boot_id, match + 9);
799         r = sd_journal_add_match(j, match, strlen(match));
800         if (r < 0) {
801                 log_error("Failed to add match: %s", strerror(-r));
802                 return r;
803         }
804
805         r = sd_journal_add_conjunction(j);
806         if (r < 0)
807                 return r;
808
809         return 0;
810 }
811
812 static int add_dmesg(sd_journal *j) {
813         int r;
814         assert(j);
815
816         if (!arg_dmesg)
817                 return 0;
818
819         r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
820         if (r < 0) {
821                 log_error("Failed to add match: %s", strerror(-r));
822                 return r;
823         }
824
825         r = sd_journal_add_conjunction(j);
826         if (r < 0)
827                 return r;
828
829         return 0;
830 }
831
832 static int add_units(sd_journal *j) {
833         _cleanup_free_ char *u = NULL;
834         int r;
835         char **i;
836
837         assert(j);
838
839         STRV_FOREACH(i, arg_system_units) {
840                 u = unit_name_mangle(*i);
841                 if (!u)
842                         return log_oom();
843                 r = add_matches_for_unit(j, u);
844                 if (r < 0)
845                         return r;
846                 r = sd_journal_add_disjunction(j);
847                 if (r < 0)
848                         return r;
849         }
850
851         STRV_FOREACH(i, arg_user_units) {
852                 u = unit_name_mangle(*i);
853                 if (!u)
854                         return log_oom();
855
856                 r = add_matches_for_user_unit(j, u, getuid());
857                 if (r < 0)
858                         return r;
859
860                 r = sd_journal_add_disjunction(j);
861                 if (r < 0)
862                         return r;
863
864         }
865
866         r = sd_journal_add_conjunction(j);
867         if (r < 0)
868                 return r;
869
870         return 0;
871 }
872
873 static int add_priorities(sd_journal *j) {
874         char match[] = "PRIORITY=0";
875         int i, r;
876         assert(j);
877
878         if (arg_priorities == 0xFF)
879                 return 0;
880
881         for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
882                 if (arg_priorities & (1 << i)) {
883                         match[sizeof(match)-2] = '0' + i;
884
885                         r = sd_journal_add_match(j, match, strlen(match));
886                         if (r < 0) {
887                                 log_error("Failed to add match: %s", strerror(-r));
888                                 return r;
889                         }
890                 }
891
892         r = sd_journal_add_conjunction(j);
893         if (r < 0)
894                 return r;
895
896         return 0;
897 }
898
899 static int setup_keys(void) {
900 #ifdef HAVE_GCRYPT
901         size_t mpk_size, seed_size, state_size, i;
902         uint8_t *mpk, *seed, *state;
903         ssize_t l;
904         int fd = -1, r, attr = 0;
905         sd_id128_t machine, boot;
906         char *p = NULL, *k = NULL;
907         struct FSSHeader h;
908         uint64_t n;
909         struct stat st;
910
911         r = stat("/var/log/journal", &st);
912         if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
913                 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
914                 return -errno;
915         }
916
917         if (r < 0 || !S_ISDIR(st.st_mode)) {
918                 log_error("%s is not a directory, must be using persistent logging for FSS.",
919                           "/var/log/journal");
920                 return r < 0 ? -errno : -ENOTDIR;
921         }
922
923         r = sd_id128_get_machine(&machine);
924         if (r < 0) {
925                 log_error("Failed to get machine ID: %s", strerror(-r));
926                 return r;
927         }
928
929         r = sd_id128_get_boot(&boot);
930         if (r < 0) {
931                 log_error("Failed to get boot ID: %s", strerror(-r));
932                 return r;
933         }
934
935         if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
936                      SD_ID128_FORMAT_VAL(machine)) < 0)
937                 return log_oom();
938
939         if (access(p, F_OK) >= 0) {
940                 if (arg_force) {
941                         r = unlink(p);
942                         if (r < 0) {
943                                 log_error("unlink(\"%s\") failed: %m", p);
944                                 r = -errno;
945                                 goto finish;
946                         }
947                 } else {
948                         log_error("Sealing key file %s exists already. (--force to recreate)", p);
949                         r = -EEXIST;
950                         goto finish;
951                 }
952         }
953
954         if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
955                      SD_ID128_FORMAT_VAL(machine)) < 0) {
956                 r = log_oom();
957                 goto finish;
958         }
959
960         mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
961         mpk = alloca(mpk_size);
962
963         seed_size = FSPRG_RECOMMENDED_SEEDLEN;
964         seed = alloca(seed_size);
965
966         state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
967         state = alloca(state_size);
968
969         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
970         if (fd < 0) {
971                 log_error("Failed to open /dev/random: %m");
972                 r = -errno;
973                 goto finish;
974         }
975
976         log_info("Generating seed...");
977         l = loop_read(fd, seed, seed_size, true);
978         if (l < 0 || (size_t) l != seed_size) {
979                 log_error("Failed to read random seed: %s", strerror(EIO));
980                 r = -EIO;
981                 goto finish;
982         }
983
984         log_info("Generating key pair...");
985         FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
986
987         log_info("Generating sealing key...");
988         FSPRG_GenState0(state, mpk, seed, seed_size);
989
990         assert(arg_interval > 0);
991
992         n = now(CLOCK_REALTIME);
993         n /= arg_interval;
994
995         close_nointr_nofail(fd);
996         fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
997         if (fd < 0) {
998                 log_error("Failed to open %s: %m", k);
999                 r = -errno;
1000                 goto finish;
1001         }
1002
1003         /* Enable secure remove, exclusion from dump, synchronous
1004          * writing and in-place updating */
1005         if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1006                 log_warning("FS_IOC_GETFLAGS failed: %m");
1007
1008         attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1009
1010         if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1011                 log_warning("FS_IOC_SETFLAGS failed: %m");
1012
1013         zero(h);
1014         memcpy(h.signature, "KSHHRHLP", 8);
1015         h.machine_id = machine;
1016         h.boot_id = boot;
1017         h.header_size = htole64(sizeof(h));
1018         h.start_usec = htole64(n * arg_interval);
1019         h.interval_usec = htole64(arg_interval);
1020         h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1021         h.fsprg_state_size = htole64(state_size);
1022
1023         l = loop_write(fd, &h, sizeof(h), false);
1024         if (l < 0 || (size_t) l != sizeof(h)) {
1025                 log_error("Failed to write header: %s", strerror(EIO));
1026                 r = -EIO;
1027                 goto finish;
1028         }
1029
1030         l = loop_write(fd, state, state_size, false);
1031         if (l < 0 || (size_t) l != state_size) {
1032                 log_error("Failed to write state: %s", strerror(EIO));
1033                 r = -EIO;
1034                 goto finish;
1035         }
1036
1037         if (link(k, p) < 0) {
1038                 log_error("Failed to link file: %m");
1039                 r = -errno;
1040                 goto finish;
1041         }
1042
1043         if (on_tty()) {
1044                 fprintf(stderr,
1045                         "\n"
1046                         "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
1047                         "the following local file. This key file is automatically updated when the\n"
1048                         "sealing key is advanced. It should not be used on multiple hosts.\n"
1049                         "\n"
1050                         "\t%s\n"
1051                         "\n"
1052                         "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1053                         "at a safe location and should not be saved locally on disk.\n"
1054                         "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1055                 fflush(stderr);
1056         }
1057         for (i = 0; i < seed_size; i++) {
1058                 if (i > 0 && i % 3 == 0)
1059                         putchar('-');
1060                 printf("%02x", ((uint8_t*) seed)[i]);
1061         }
1062
1063         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1064
1065         if (on_tty()) {
1066                 char tsb[FORMAT_TIMESPAN_MAX], *hn;
1067
1068                 fprintf(stderr,
1069                         ANSI_HIGHLIGHT_OFF "\n"
1070                         "The sealing key is automatically changed every %s.\n",
1071                         format_timespan(tsb, sizeof(tsb), arg_interval, 0));
1072
1073                 hn = gethostname_malloc();
1074
1075                 if (hn) {
1076                         hostname_cleanup(hn, false);
1077                         fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
1078                 } else
1079                         fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
1080
1081 #ifdef HAVE_QRENCODE
1082                 /* If this is not an UTF-8 system don't print any QR codes */
1083                 if (is_locale_utf8()) {
1084                         fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1085                         print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1086                 }
1087 #endif
1088                 free(hn);
1089         }
1090
1091         r = 0;
1092
1093 finish:
1094         if (fd >= 0)
1095                 close_nointr_nofail(fd);
1096
1097         if (k) {
1098                 unlink(k);
1099                 free(k);
1100         }
1101
1102         free(p);
1103
1104         return r;
1105 #else
1106         log_error("Forward-secure sealing not available.");
1107         return -ENOTSUP;
1108 #endif
1109 }
1110
1111 static int verify(sd_journal *j) {
1112         int r = 0;
1113         Iterator i;
1114         JournalFile *f;
1115
1116         assert(j);
1117
1118         log_show_color(true);
1119
1120         HASHMAP_FOREACH(f, j->files, i) {
1121                 int k;
1122                 usec_t first, validated, last;
1123
1124 #ifdef HAVE_GCRYPT
1125                 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
1126                         log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
1127 #endif
1128
1129                 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
1130                 if (k == -EINVAL) {
1131                         /* If the key was invalid give up right-away. */
1132                         return k;
1133                 } else if (k < 0) {
1134                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
1135                         r = k;
1136                 } else {
1137                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
1138                         log_info("PASS: %s", f->path);
1139
1140                         if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
1141                                 if (validated > 0) {
1142                                         log_info("=> Validated from %s to %s, final %s entries not sealed.",
1143                                                  format_timestamp(a, sizeof(a), first),
1144                                                  format_timestamp(b, sizeof(b), validated),
1145                                                  format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
1146                                 } else if (last > 0)
1147                                         log_info("=> No sealing yet, %s of entries not sealed.",
1148                                                  format_timespan(c, sizeof(c), last - first, 0));
1149                                 else
1150                                         log_info("=> No sealing yet, no entries in file.");
1151                         }
1152                 }
1153         }
1154
1155         return r;
1156 }
1157
1158 #ifdef HAVE_ACL
1159 static int access_check_var_log_journal(sd_journal *j) {
1160         _cleanup_strv_free_ char **g = NULL;
1161         bool have_access;
1162         int r;
1163
1164         assert(j);
1165
1166         have_access = in_group("systemd-journal") > 0;
1167
1168         if (!have_access) {
1169                 /* Let's enumerate all groups from the default ACL of
1170                  * the directory, which generally should allow access
1171                  * to most journal files too */
1172                 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1173                 if (r < 0)
1174                         return r;
1175         }
1176
1177         if (!have_access) {
1178
1179                 if (strv_isempty(g))
1180                         log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1181                                    "      Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1182                                    "      turn off this notice.");
1183                 else {
1184                         _cleanup_free_ char *s = NULL;
1185
1186                         r = strv_extend(&g, "systemd-journal");
1187                         if (r < 0)
1188                                 return log_oom();
1189
1190                         strv_sort(g);
1191                         strv_uniq(g);
1192
1193                         s = strv_join(g, "', '");
1194                         if (!s)
1195                                 return log_oom();
1196
1197                         log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1198                                    "      Users in the groups '%s' can see all messages.\n"
1199                                    "      Pass -q to turn off this notice.", s);
1200                 }
1201         }
1202
1203         return 0;
1204 }
1205 #endif
1206
1207 static int access_check(sd_journal *j) {
1208         Iterator it;
1209         void *code;
1210         int r = 0;
1211
1212         assert(j);
1213
1214         if (set_isempty(j->errors)) {
1215                 if (hashmap_isempty(j->files))
1216                         log_notice("No journal files were found.");
1217                 return 0;
1218         }
1219
1220         if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1221 #ifdef HAVE_ACL
1222                 /* If /var/log/journal doesn't even exist,
1223                  * unprivileged users have no access at all */
1224                 if (access("/var/log/journal", F_OK) < 0 &&
1225                     geteuid() != 0 &&
1226                     in_group("systemd-journal") <= 0) {
1227                         log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1228                                   "enabled. Users in the 'systemd-journal' group may always access messages.");
1229                         return -EACCES;
1230                 }
1231
1232                 /* If /var/log/journal exists, try to pring a nice
1233                    notice if the user lacks access to it */
1234                 if (!arg_quiet && geteuid() != 0) {
1235                         r = access_check_var_log_journal(j);
1236                         if (r < 0)
1237                                 return r;
1238                 }
1239 #else
1240                 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1241                         log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1242                                   "group may access messages.");
1243                         return -EACCES;
1244                 }
1245 #endif
1246
1247                 if (hashmap_isempty(j->files)) {
1248                         log_error("No journal files were opened due to insufficient permissions.");
1249                         r = -EACCES;
1250                 }
1251         }
1252
1253         SET_FOREACH(code, j->errors, it) {
1254                 int err;
1255
1256                 err = -PTR_TO_INT(code);
1257                 assert(err > 0);
1258
1259                 if (err != EACCES)
1260                         log_warning("Error was encountered while opening journal files: %s",
1261                                     strerror(err));
1262         }
1263
1264         return r;
1265 }
1266
1267 int main(int argc, char *argv[]) {
1268         int r;
1269         _cleanup_journal_close_ sd_journal*j = NULL;
1270         bool need_seek = false;
1271         sd_id128_t previous_boot_id;
1272         bool previous_boot_id_valid = false, first_line = true;
1273         int n_shown = 0;
1274
1275         setlocale(LC_ALL, "");
1276         log_parse_environment();
1277         log_open();
1278
1279         r = parse_argv(argc, argv);
1280         if (r <= 0)
1281                 goto finish;
1282
1283         signal(SIGWINCH, columns_lines_cache_reset);
1284
1285         if (arg_action == ACTION_NEW_ID128) {
1286                 r = generate_new_id128();
1287                 goto finish;
1288         }
1289
1290         if (arg_action == ACTION_SETUP_KEYS) {
1291                 r = setup_keys();
1292                 goto finish;
1293         }
1294
1295         if (arg_action == ACTION_UPDATE_CATALOG ||
1296             arg_action == ACTION_LIST_CATALOG ||
1297             arg_action == ACTION_DUMP_CATALOG) {
1298
1299                 const char* database = CATALOG_DATABASE;
1300                 _cleanup_free_ char *copy = NULL;
1301                 if (arg_root) {
1302                         copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1303                         if (!copy) {
1304                                 r = log_oom();
1305                                 goto finish;
1306                         }
1307                         path_kill_slashes(copy);
1308                         database = copy;
1309                 }
1310
1311                 if (arg_action == ACTION_UPDATE_CATALOG) {
1312                         r = catalog_update(database, arg_root, catalog_file_dirs);
1313                         if (r < 0)
1314                                 log_error("Failed to list catalog: %s", strerror(-r));
1315                 } else {
1316                         bool oneline = arg_action == ACTION_LIST_CATALOG;
1317
1318                         if (optind < argc)
1319                                 r = catalog_list_items(stdout, database,
1320                                                        oneline, argv + optind);
1321                         else
1322                                 r = catalog_list(stdout, database, oneline);
1323                         if (r < 0)
1324                                 log_error("Failed to list catalog: %s", strerror(-r));
1325                 }
1326
1327                 goto finish;
1328         }
1329
1330         if (arg_directory)
1331                 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1332         else if (arg_file)
1333                 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1334         else
1335                 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1336         if (r < 0) {
1337                 log_error("Failed to open %s: %s",
1338                           arg_directory ? arg_directory : arg_file ? "files" : "journal",
1339                           strerror(-r));
1340                 return EXIT_FAILURE;
1341         }
1342
1343         r = access_check(j);
1344         if (r < 0)
1345                 return EXIT_FAILURE;
1346
1347         if (arg_action == ACTION_VERIFY) {
1348                 r = verify(j);
1349                 goto finish;
1350         }
1351
1352         if (arg_action == ACTION_PRINT_HEADER) {
1353                 journal_print_header(j);
1354                 return EXIT_SUCCESS;
1355         }
1356
1357         if (arg_action == ACTION_DISK_USAGE) {
1358                 uint64_t bytes;
1359                 char sbytes[FORMAT_BYTES_MAX];
1360
1361                 r = sd_journal_get_usage(j, &bytes);
1362                 if (r < 0)
1363                         return EXIT_FAILURE;
1364
1365                 printf("Journals take up %s on disk.\n",
1366                        format_bytes(sbytes, sizeof(sbytes), bytes));
1367                 return EXIT_SUCCESS;
1368         }
1369
1370         /* add_boot() must be called first!
1371          * It may need to seek the journal to find parent boot IDs. */
1372         r = add_boot(j);
1373         if (r < 0)
1374                 return EXIT_FAILURE;
1375
1376         r = add_dmesg(j);
1377         if (r < 0)
1378                 return EXIT_FAILURE;
1379
1380         r = add_units(j);
1381         strv_free(arg_system_units);
1382         strv_free(arg_user_units);
1383
1384         if (r < 0)
1385                 return EXIT_FAILURE;
1386
1387         r = add_priorities(j);
1388         if (r < 0)
1389                 return EXIT_FAILURE;
1390
1391         r = add_matches(j, argv + optind);
1392         if (r < 0)
1393                 return EXIT_FAILURE;
1394
1395         log_debug("Journal filter: %s", j->level0 ? journal_make_match_string(j) : "none");
1396
1397         if (arg_field) {
1398                 const void *data;
1399                 size_t size;
1400
1401                 r = sd_journal_set_data_threshold(j, 0);
1402                 if (r < 0) {
1403                         log_error("Failed to unset data size threshold");
1404                         return EXIT_FAILURE;
1405                 }
1406
1407                 r = sd_journal_query_unique(j, arg_field);
1408                 if (r < 0) {
1409                         log_error("Failed to query unique data objects: %s", strerror(-r));
1410                         return EXIT_FAILURE;
1411                 }
1412
1413                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1414                         const void *eq;
1415
1416                         if (arg_lines >= 0 && n_shown >= arg_lines)
1417                                 break;
1418
1419                         eq = memchr(data, '=', size);
1420                         if (eq)
1421                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1422                         else
1423                                 printf("%.*s\n", (int) size, (const char*) data);
1424
1425                         n_shown ++;
1426                 }
1427
1428                 return EXIT_SUCCESS;
1429         }
1430
1431         /* Opening the fd now means the first sd_journal_wait() will actually wait */
1432         if (arg_follow) {
1433                 r = sd_journal_get_fd(j);
1434                 if (r < 0)
1435                         return EXIT_FAILURE;
1436         }
1437
1438         if (arg_cursor) {
1439                 r = sd_journal_seek_cursor(j, arg_cursor);
1440                 if (r < 0) {
1441                         log_error("Failed to seek to cursor: %s", strerror(-r));
1442                         return EXIT_FAILURE;
1443                 }
1444                 if (!arg_reverse)
1445                         r = sd_journal_next(j);
1446                 else
1447                         r = sd_journal_previous(j);
1448
1449         } else if (arg_since_set && !arg_reverse) {
1450                 r = sd_journal_seek_realtime_usec(j, arg_since);
1451                 if (r < 0) {
1452                         log_error("Failed to seek to date: %s", strerror(-r));
1453                         return EXIT_FAILURE;
1454                 }
1455                 r = sd_journal_next(j);
1456
1457         } else if (arg_until_set && arg_reverse) {
1458                 r = sd_journal_seek_realtime_usec(j, arg_until);
1459                 if (r < 0) {
1460                         log_error("Failed to seek to date: %s", strerror(-r));
1461                         return EXIT_FAILURE;
1462                 }
1463                 r = sd_journal_previous(j);
1464
1465         } else if (arg_lines >= 0) {
1466                 r = sd_journal_seek_tail(j);
1467                 if (r < 0) {
1468                         log_error("Failed to seek to tail: %s", strerror(-r));
1469                         return EXIT_FAILURE;
1470                 }
1471
1472                 r = sd_journal_previous_skip(j, arg_lines);
1473
1474         } else if (arg_reverse) {
1475                 r = sd_journal_seek_tail(j);
1476                 if (r < 0) {
1477                         log_error("Failed to seek to tail: %s", strerror(-r));
1478                         return EXIT_FAILURE;
1479                 }
1480
1481                 r = sd_journal_previous(j);
1482
1483         } else {
1484                 r = sd_journal_seek_head(j);
1485                 if (r < 0) {
1486                         log_error("Failed to seek to head: %s", strerror(-r));
1487                         return EXIT_FAILURE;
1488                 }
1489
1490                 r = sd_journal_next(j);
1491         }
1492
1493         if (r < 0) {
1494                 log_error("Failed to iterate through journal: %s", strerror(-r));
1495                 return EXIT_FAILURE;
1496         }
1497
1498         if (!arg_no_pager && !arg_follow)
1499                 pager_open(arg_pager_end);
1500
1501         if (!arg_quiet) {
1502                 usec_t start, end;
1503                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1504
1505                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1506                 if (r < 0) {
1507                         log_error("Failed to get cutoff: %s", strerror(-r));
1508                         goto finish;
1509                 }
1510
1511                 if (r > 0) {
1512                         if (arg_follow)
1513                                 printf("-- Logs begin at %s. --\n",
1514                                        format_timestamp(start_buf, sizeof(start_buf), start));
1515                         else
1516                                 printf("-- Logs begin at %s, end at %s. --\n",
1517                                        format_timestamp(start_buf, sizeof(start_buf), start),
1518                                        format_timestamp(end_buf, sizeof(end_buf), end));
1519                 }
1520         }
1521
1522         for (;;) {
1523                 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1524                         int flags;
1525
1526                         if (need_seek) {
1527                                 if (!arg_reverse)
1528                                         r = sd_journal_next(j);
1529                                 else
1530                                         r = sd_journal_previous(j);
1531                                 if (r < 0) {
1532                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1533                                         goto finish;
1534                                 }
1535                                 if (r == 0)
1536                                         break;
1537                         }
1538
1539                         if (arg_until_set && !arg_reverse) {
1540                                 usec_t usec;
1541
1542                                 r = sd_journal_get_realtime_usec(j, &usec);
1543                                 if (r < 0) {
1544                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1545                                         goto finish;
1546                                 }
1547                                 if (usec > arg_until)
1548                                         goto finish;
1549                         }
1550
1551                         if (arg_since_set && arg_reverse) {
1552                                 usec_t usec;
1553
1554                                 r = sd_journal_get_realtime_usec(j, &usec);
1555                                 if (r < 0) {
1556                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1557                                         goto finish;
1558                                 }
1559                                 if (usec < arg_since)
1560                                         goto finish;
1561                         }
1562
1563                         if (!arg_merge) {
1564                                 sd_id128_t boot_id;
1565                                 const char *color_on = on_tty() ? ANSI_HIGHLIGHT_ON : "",
1566                                            *color_off = on_tty() ? ANSI_HIGHLIGHT_OFF : "";
1567
1568                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1569                                 if (r >= 0) {
1570                                         if (previous_boot_id_valid &&
1571                                             !sd_id128_equal(boot_id, previous_boot_id))
1572                                                 printf("%s-- Reboot --%s\n", color_on, color_off);
1573
1574                                         previous_boot_id = boot_id;
1575                                         previous_boot_id_valid = true;
1576                                 }
1577                         }
1578
1579                         flags =
1580                                 arg_all * OUTPUT_SHOW_ALL |
1581                                 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1582                                 on_tty() * OUTPUT_COLOR |
1583                                 arg_catalog * OUTPUT_CATALOG;
1584
1585                         r = output_journal(stdout, j, arg_output, 0, flags);
1586                         need_seek = true;
1587                         if (r == -EADDRNOTAVAIL)
1588                                 break;
1589                         else if (r < 0 || ferror(stdout))
1590                                 goto finish;
1591
1592                         n_shown++;
1593                 }
1594
1595                 if (!arg_follow)
1596                         break;
1597
1598                 r = sd_journal_wait(j, (uint64_t) -1);
1599                 if (r < 0) {
1600                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1601                         goto finish;
1602                 }
1603
1604                 first_line = false;
1605         }
1606
1607 finish:
1608         pager_close();
1609
1610         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1611 }