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