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