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