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