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