chiark / gitweb /
journalctl: honour -n if -F is used
[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 <fcntl.h>
23 #include <errno.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/poll.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 #include <locale.h>
37 #include <langinfo.h>
38
39 #include <systemd/sd-journal.h>
40
41 #include "log.h"
42 #include "util.h"
43 #include "path-util.h"
44 #include "build.h"
45 #include "pager.h"
46 #include "logs-show.h"
47 #include "strv.h"
48 #include "journal-internal.h"
49 #include "journal-def.h"
50 #include "journal-verify.h"
51 #include "journal-authenticate.h"
52 #include "journal-qrcode.h"
53 #include "fsprg.h"
54 #include "unit-name.h"
55
56 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
57
58 static OutputMode arg_output = OUTPUT_SHORT;
59 static bool arg_follow = false;
60 static bool arg_show_all = false;
61 static bool arg_no_pager = false;
62 static unsigned arg_lines = 0;
63 static bool arg_no_tail = false;
64 static bool arg_quiet = false;
65 static bool arg_merge = false;
66 static bool arg_this_boot = false;
67 static const char *arg_cursor = NULL;
68 static const char *arg_directory = NULL;
69 static int arg_priorities = 0xFF;
70 static const char *arg_verify_key = NULL;
71 #ifdef HAVE_GCRYPT
72 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
73 #endif
74 static usec_t arg_since, arg_until;
75 static bool arg_since_set = false, arg_until_set = false;
76 static const char *arg_unit = NULL;
77 static const char *arg_field = NULL;
78
79 static enum {
80         ACTION_SHOW,
81         ACTION_NEW_ID128,
82         ACTION_PRINT_HEADER,
83         ACTION_SETUP_KEYS,
84         ACTION_VERIFY,
85         ACTION_DISK_USAGE,
86 } arg_action = ACTION_SHOW;
87
88 static int help(void) {
89
90         printf("%s [OPTIONS...] [MATCH]\n\n"
91                "Query the journal.\n\n"
92                "Flags:\n"
93                "  -c --cursor=CURSOR     Start showing entries from specified cursor\n"
94                "     --since=DATE        Start showing entries newer or of the specified date\n"
95                "     --until=DATE        Stop showing entries older or of the specified date\n"
96                "  -b --this-boot         Show data only from current boot\n"
97                "  -u --unit=UNIT         Show data only from the specified unit\n"
98                "  -p --priority=RANGE    Show only messages within the specified priority range\n\n"
99                "  -f --follow            Follow journal\n"
100                "  -n --lines[=INTEGER]   Number of journal entries to show\n"
101                "     --no-tail           Show all lines, even in follow mode\n"
102                "  -o --output=STRING     Change journal output mode (short, short-monotonic,\n"
103                "                         verbose, export, json, json-pretty, json-sse, cat)\n"
104                "  -a --all               Show all fields, including long and unprintable\n"
105                "  -q --quiet             Don't show privilege warning\n"
106                "     --no-pager          Do not pipe output into a pager\n"
107                "  -m --merge             Show entries from all available journals\n"
108                "  -D --directory=PATH    Show journal files from directory\n"
109 #ifdef HAVE_GCRYPT
110                "     --interval=TIME     Time interval for changing the FSS sealing key\n"
111                "     --verify-key=KEY    Specify FSS verification key\n"
112 #endif
113                "\nCommands:\n"
114                "  -h --help              Show this help\n"
115                "     --version           Show package version\n"
116                "     --new-id128         Generate a new 128 Bit ID\n"
117                "     --header            Show journal header information\n"
118                "     --disk-usage        Show total disk usage\n"
119                "  -F --field=FIELD       List all values a certain field takes\n"
120 #ifdef HAVE_GCRYPT
121                "     --setup-keys        Generate new FSS key pair\n"
122                "     --verify            Verify journal file consistency\n"
123 #endif
124                , program_invocation_short_name);
125
126         return 0;
127 }
128
129 static int parse_argv(int argc, char *argv[]) {
130
131         enum {
132                 ARG_VERSION = 0x100,
133                 ARG_NO_PAGER,
134                 ARG_NO_TAIL,
135                 ARG_NEW_ID128,
136                 ARG_HEADER,
137                 ARG_SETUP_KEYS,
138                 ARG_INTERVAL,
139                 ARG_VERIFY,
140                 ARG_VERIFY_KEY,
141                 ARG_DISK_USAGE,
142                 ARG_SINCE,
143                 ARG_UNTIL
144         };
145
146         static const struct option options[] = {
147                 { "help",         no_argument,       NULL, 'h'              },
148                 { "version" ,     no_argument,       NULL, ARG_VERSION      },
149                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
150                 { "follow",       no_argument,       NULL, 'f'              },
151                 { "output",       required_argument, NULL, 'o'              },
152                 { "all",          no_argument,       NULL, 'a'              },
153                 { "lines",        optional_argument, NULL, 'n'              },
154                 { "no-tail",      no_argument,       NULL, ARG_NO_TAIL      },
155                 { "new-id128",    no_argument,       NULL, ARG_NEW_ID128    },
156                 { "quiet",        no_argument,       NULL, 'q'              },
157                 { "merge",        no_argument,       NULL, 'm'              },
158                 { "this-boot",    no_argument,       NULL, 'b'              },
159                 { "directory",    required_argument, NULL, 'D'              },
160                 { "header",       no_argument,       NULL, ARG_HEADER       },
161                 { "priority",     no_argument,       NULL, 'p'              },
162                 { "setup-keys",   no_argument,       NULL, ARG_SETUP_KEYS   },
163                 { "interval",     required_argument, NULL, ARG_INTERVAL     },
164                 { "verify",       no_argument,       NULL, ARG_VERIFY       },
165                 { "verify-key",   required_argument, NULL, ARG_VERIFY_KEY   },
166                 { "disk-usage",   no_argument,       NULL, ARG_DISK_USAGE   },
167                 { "cursor",       required_argument, NULL, 'c'              },
168                 { "since",        required_argument, NULL, ARG_SINCE        },
169                 { "until",        required_argument, NULL, ARG_UNTIL        },
170                 { "unit",         required_argument, NULL, 'u'              },
171                 { "field",        required_argument, NULL, 'F'              },
172                 { NULL,           0,                 NULL, 0                }
173         };
174
175         int c, r;
176
177         assert(argc >= 0);
178         assert(argv);
179
180         while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:u:F:", options, NULL)) >= 0) {
181
182                 switch (c) {
183
184                 case 'h':
185                         help();
186                         return 0;
187
188                 case ARG_VERSION:
189                         puts(PACKAGE_STRING);
190                         puts(DISTRIBUTION);
191                         puts(SYSTEMD_FEATURES);
192                         return 0;
193
194                 case ARG_NO_PAGER:
195                         arg_no_pager = true;
196                         break;
197
198                 case 'f':
199                         arg_follow = true;
200                         signal(SIGWINCH, columns_cache_reset);
201                         break;
202
203                 case 'o':
204                         arg_output = output_mode_from_string(optarg);
205                         if (arg_output < 0) {
206                                 log_error("Unknown output format '%s'.", optarg);
207                                 return -EINVAL;
208                         }
209
210                         if (arg_output == OUTPUT_EXPORT ||
211                             arg_output == OUTPUT_JSON ||
212                             arg_output == OUTPUT_JSON_PRETTY ||
213                             arg_output == OUTPUT_JSON_SSE ||
214                             arg_output == OUTPUT_CAT)
215                                 arg_quiet = true;
216
217                         break;
218
219                 case 'a':
220                         arg_show_all = true;
221                         break;
222
223                 case 'n':
224                         if (optarg) {
225                                 r = safe_atou(optarg, &arg_lines);
226                                 if (r < 0 || arg_lines <= 0) {
227                                         log_error("Failed to parse lines '%s'", optarg);
228                                         return -EINVAL;
229                                 }
230                         } else
231                                 arg_lines = 10;
232
233                         break;
234
235                 case ARG_NO_TAIL:
236                         arg_no_tail = true;
237                         break;
238
239                 case ARG_NEW_ID128:
240                         arg_action = ACTION_NEW_ID128;
241                         break;
242
243                 case 'q':
244                         arg_quiet = true;
245                         break;
246
247                 case 'm':
248                         arg_merge = true;
249                         break;
250
251                 case 'b':
252                         arg_this_boot = true;
253                         break;
254
255                 case 'D':
256                         arg_directory = optarg;
257                         break;
258
259                 case 'c':
260                         arg_cursor = optarg;
261                         break;
262
263                 case ARG_HEADER:
264                         arg_action = ACTION_PRINT_HEADER;
265                         break;
266
267                 case ARG_VERIFY:
268                         arg_action = ACTION_VERIFY;
269                         break;
270
271                 case ARG_DISK_USAGE:
272                         arg_action = ACTION_DISK_USAGE;
273                         break;
274
275 #ifdef HAVE_GCRYPT
276                 case ARG_SETUP_KEYS:
277                         arg_action = ACTION_SETUP_KEYS;
278                         break;
279
280
281                 case ARG_VERIFY_KEY:
282                         arg_action = ACTION_VERIFY;
283                         arg_verify_key = optarg;
284                         arg_merge = false;
285                         break;
286
287                 case ARG_INTERVAL:
288                         r = parse_usec(optarg, &arg_interval);
289                         if (r < 0 || arg_interval <= 0) {
290                                 log_error("Failed to parse sealing key change interval: %s", optarg);
291                                 return -EINVAL;
292                         }
293                         break;
294 #else
295                 case ARG_SETUP_KEYS:
296                 case ARG_VERIFY_KEY:
297                 case ARG_INTERVAL:
298                         log_error("Forward-secure sealing not available.");
299                         return -ENOTSUP;
300 #endif
301
302                 case 'p': {
303                         const char *dots;
304
305                         dots = strstr(optarg, "..");
306                         if (dots) {
307                                 char *a;
308                                 int from, to, i;
309
310                                 /* a range */
311                                 a = strndup(optarg, dots - optarg);
312                                 if (!a)
313                                         return log_oom();
314
315                                 from = log_level_from_string(a);
316                                 to = log_level_from_string(dots + 2);
317                                 free(a);
318
319                                 if (from < 0 || to < 0) {
320                                         log_error("Failed to parse log level range %s", optarg);
321                                         return -EINVAL;
322                                 }
323
324                                 arg_priorities = 0;
325
326                                 if (from < to) {
327                                         for (i = from; i <= to; i++)
328                                                 arg_priorities |= 1 << i;
329                                 } else {
330                                         for (i = to; i <= from; i++)
331                                                 arg_priorities |= 1 << i;
332                                 }
333
334                         } else {
335                                 int p, i;
336
337                                 p = log_level_from_string(optarg);
338                                 if (p < 0) {
339                                         log_error("Unknown log level %s", optarg);
340                                         return -EINVAL;
341                                 }
342
343                                 arg_priorities = 0;
344
345                                 for (i = 0; i <= p; i++)
346                                         arg_priorities |= 1 << i;
347                         }
348
349                         break;
350                 }
351
352                 case ARG_SINCE:
353                         r = parse_timestamp(optarg, &arg_since);
354                         if (r < 0) {
355                                 log_error("Failed to parse timestamp: %s", optarg);
356                                 return -EINVAL;
357                         }
358                         arg_since_set = true;
359                         break;
360
361                 case ARG_UNTIL:
362                         r = parse_timestamp(optarg, &arg_until);
363                         if (r < 0) {
364                                 log_error("Failed to parse timestamp: %s", optarg);
365                                 return -EINVAL;
366                         }
367                         arg_until_set = true;
368                         break;
369
370                 case 'u':
371                         arg_unit = optarg;
372                         break;
373
374                 case '?':
375                         return -EINVAL;
376
377                 case 'F':
378                         arg_field = optarg;
379                         break;
380
381                 default:
382                         log_error("Unknown option code %c", c);
383                         return -EINVAL;
384                 }
385         }
386
387         if (arg_follow && !arg_no_tail && arg_lines <= 0)
388                 arg_lines = 10;
389
390         if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
391                 log_error("--since= must be before --until=.");
392                 return -EINVAL;
393         }
394
395         if (arg_cursor && arg_since_set) {
396                 log_error("Please specify either --since= or --cursor=, not both.");
397                 return -EINVAL;
398         }
399
400         return 1;
401 }
402
403 static bool on_tty(void) {
404         static int t = -1;
405
406         /* Note that this is invoked relatively early, before we start
407          * the pager. That means the value we return reflects whether
408          * we originally were started on a tty, not if we currently
409          * are. But this is intended, since we want colour and so on
410          * when run in our own pager. */
411
412         if (_unlikely_(t < 0))
413                 t = isatty(STDOUT_FILENO) > 0;
414
415         return t;
416 }
417
418 static int generate_new_id128(void) {
419         sd_id128_t id;
420         int r;
421         unsigned i;
422
423         r = sd_id128_randomize(&id);
424         if (r < 0) {
425                 log_error("Failed to generate ID: %s", strerror(-r));
426                 return r;
427         }
428
429         printf("As string:\n"
430                SD_ID128_FORMAT_STR "\n\n"
431                "As UUID:\n"
432                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
433                "As macro:\n"
434               "#define MESSAGE_XYZ SD_ID128_MAKE(",
435                SD_ID128_FORMAT_VAL(id),
436                SD_ID128_FORMAT_VAL(id));
437
438         for (i = 0; i < 16; i++)
439                 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
440
441         fputs(")\n", stdout);
442
443         return 0;
444 }
445
446 static int add_matches(sd_journal *j, char **args) {
447         char **i;
448         int r;
449
450         assert(j);
451
452         STRV_FOREACH(i, args) {
453
454                 if (streq(*i, "+"))
455                         r = sd_journal_add_disjunction(j);
456                 else if (path_is_absolute(*i)) {
457                         char *p, *t = NULL;
458                         const char *path;
459                         struct stat st;
460
461                         p = canonicalize_file_name(*i);
462                         path = p ? p : *i;
463
464                         if (stat(path, &st) < 0)  {
465                                 free(p);
466                                 log_error("Couldn't stat file: %m");
467                                 return -errno;
468                         }
469
470                         if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
471                                 t = strappend("_EXE=", path);
472                         else if (S_ISCHR(st.st_mode))
473                                 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
474                         else if (S_ISBLK(st.st_mode))
475                                 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
476                         else {
477                                 free(p);
478                                 log_error("File is not a device node, regular file or is not executable: %s", *i);
479                                 return -EINVAL;
480                         }
481
482                         free(p);
483
484                         if (!t)
485                                 return log_oom();
486
487                         r = sd_journal_add_match(j, t, 0);
488                         free(t);
489                 } else
490                         r = sd_journal_add_match(j, *i, 0);
491
492                 if (r < 0) {
493                         log_error("Failed to add match '%s': %s", *i, strerror(-r));
494                         return r;
495                 }
496         }
497
498         return 0;
499 }
500
501 static int add_this_boot(sd_journal *j) {
502         char match[9+32+1] = "_BOOT_ID=";
503         sd_id128_t boot_id;
504         int r;
505
506         assert(j);
507
508         if (!arg_this_boot)
509                 return 0;
510
511         r = sd_id128_get_boot(&boot_id);
512         if (r < 0) {
513                 log_error("Failed to get boot id: %s", strerror(-r));
514                 return r;
515         }
516
517         sd_id128_to_string(boot_id, match + 9);
518         r = sd_journal_add_match(j, match, strlen(match));
519         if (r < 0) {
520                 log_error("Failed to add match: %s", strerror(-r));
521                 return r;
522         }
523
524         return 0;
525 }
526
527 static int add_unit(sd_journal *j) {
528         _cleanup_free_ char *m = NULL, *u = NULL;
529         int r;
530
531         assert(j);
532
533         if (isempty(arg_unit))
534                 return 0;
535
536         u = unit_name_mangle(arg_unit);
537         if (!u)
538                 return log_oom();
539
540         m = strappend("_SYSTEMD_UNIT=", u);
541         if (!m)
542                 return log_oom();
543
544         r = sd_journal_add_match(j, m, strlen(m));
545         if (r < 0) {
546                 log_error("Failed to add match: %s", strerror(-r));
547                 return r;
548         }
549
550         return 0;
551 }
552
553 static int add_priorities(sd_journal *j) {
554         char match[] = "PRIORITY=0";
555         int i, r;
556
557         assert(j);
558
559         if (arg_priorities == 0xFF)
560                 return 0;
561
562         for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
563                 if (arg_priorities & (1 << i)) {
564                         match[sizeof(match)-2] = '0' + i;
565
566                         log_info("adding match %s", match);
567
568                         r = sd_journal_add_match(j, match, strlen(match));
569                         if (r < 0) {
570                                 log_error("Failed to add match: %s", strerror(-r));
571                                 return r;
572                         }
573                 }
574
575         return 0;
576 }
577
578 static int setup_keys(void) {
579 #ifdef HAVE_GCRYPT
580         size_t mpk_size, seed_size, state_size, i;
581         uint8_t *mpk, *seed, *state;
582         ssize_t l;
583         int fd = -1, r, attr = 0;
584         sd_id128_t machine, boot;
585         char *p = NULL, *k = NULL;
586         struct FSSHeader h;
587         uint64_t n;
588
589         r = sd_id128_get_machine(&machine);
590         if (r < 0) {
591                 log_error("Failed to get machine ID: %s", strerror(-r));
592                 return r;
593         }
594
595         r = sd_id128_get_boot(&boot);
596         if (r < 0) {
597                 log_error("Failed to get boot ID: %s", strerror(-r));
598                 return r;
599         }
600
601         if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
602                      SD_ID128_FORMAT_VAL(machine)) < 0)
603                 return log_oom();
604
605         if (access(p, F_OK) >= 0) {
606                 log_error("Sealing key file %s exists already.", p);
607                 r = -EEXIST;
608                 goto finish;
609         }
610
611         if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
612                      SD_ID128_FORMAT_VAL(machine)) < 0) {
613                 r = log_oom();
614                 goto finish;
615         }
616
617         mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
618         mpk = alloca(mpk_size);
619
620         seed_size = FSPRG_RECOMMENDED_SEEDLEN;
621         seed = alloca(seed_size);
622
623         state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
624         state = alloca(state_size);
625
626         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
627         if (fd < 0) {
628                 log_error("Failed to open /dev/random: %m");
629                 r = -errno;
630                 goto finish;
631         }
632
633         log_info("Generating seed...");
634         l = loop_read(fd, seed, seed_size, true);
635         if (l < 0 || (size_t) l != seed_size) {
636                 log_error("Failed to read random seed: %s", strerror(EIO));
637                 r = -EIO;
638                 goto finish;
639         }
640
641         log_info("Generating key pair...");
642         FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
643
644         log_info("Generating sealing key...");
645         FSPRG_GenState0(state, mpk, seed, seed_size);
646
647         assert(arg_interval > 0);
648
649         n = now(CLOCK_REALTIME);
650         n /= arg_interval;
651
652         close_nointr_nofail(fd);
653         fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
654         if (fd < 0) {
655                 log_error("Failed to open %s: %m", k);
656                 r = -errno;
657                 goto finish;
658         }
659
660         /* Enable secure remove, exclusion from dump, synchronous
661          * writing and in-place updating */
662         if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
663                 log_warning("FS_IOC_GETFLAGS failed: %m");
664
665         attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
666
667         if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
668                 log_warning("FS_IOC_SETFLAGS failed: %m");
669
670         zero(h);
671         memcpy(h.signature, "KSHHRHLP", 8);
672         h.machine_id = machine;
673         h.boot_id = boot;
674         h.header_size = htole64(sizeof(h));
675         h.start_usec = htole64(n * arg_interval);
676         h.interval_usec = htole64(arg_interval);
677         h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
678         h.fsprg_state_size = htole64(state_size);
679
680         l = loop_write(fd, &h, sizeof(h), false);
681         if (l < 0 || (size_t) l != sizeof(h)) {
682                 log_error("Failed to write header: %s", strerror(EIO));
683                 r = -EIO;
684                 goto finish;
685         }
686
687         l = loop_write(fd, state, state_size, false);
688         if (l < 0 || (size_t) l != state_size) {
689                 log_error("Failed to write state: %s", strerror(EIO));
690                 r = -EIO;
691                 goto finish;
692         }
693
694         if (link(k, p) < 0) {
695                 log_error("Failed to link file: %m");
696                 r = -errno;
697                 goto finish;
698         }
699
700         if (isatty(STDOUT_FILENO)) {
701                 fprintf(stderr,
702                         "\n"
703                         "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
704                         "the following local file. This key file is automatically updated when the\n"
705                         "sealing key is advanced. It should not be used on multiple hosts.\n"
706                         "\n"
707                         "\t%s\n"
708                         "\n"
709                         "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
710                         "at a safe location and should not be saved locally on disk.\n"
711                         "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
712                 fflush(stderr);
713         }
714         for (i = 0; i < seed_size; i++) {
715                 if (i > 0 && i % 3 == 0)
716                         putchar('-');
717                 printf("%02x", ((uint8_t*) seed)[i]);
718         }
719
720         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
721
722         if (isatty(STDOUT_FILENO)) {
723                 char tsb[FORMAT_TIMESPAN_MAX], *hn;
724
725                 fprintf(stderr,
726                         ANSI_HIGHLIGHT_OFF "\n"
727                         "The sealing key is automatically changed every %s.\n",
728                         format_timespan(tsb, sizeof(tsb), arg_interval));
729
730                 hn = gethostname_malloc();
731
732                 if (hn) {
733                         hostname_cleanup(hn);
734                         fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
735                 } else
736                         fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
737
738 #ifdef HAVE_QRENCODE
739                 /* If this is not an UTF-8 system don't print any QR codes */
740                 setlocale(LC_CTYPE, "");
741
742                 if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) {
743                         fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
744                         print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
745                 }
746 #endif
747                 free(hn);
748         }
749
750         r = 0;
751
752 finish:
753         if (fd >= 0)
754                 close_nointr_nofail(fd);
755
756         if (k) {
757                 unlink(k);
758                 free(k);
759         }
760
761         free(p);
762
763         return r;
764 #else
765         log_error("Forward-secure sealing not available.");
766         return -ENOTSUP;
767 #endif
768 }
769
770 static int verify(sd_journal *j) {
771         int r = 0;
772         Iterator i;
773         JournalFile *f;
774
775         assert(j);
776
777         log_show_color(true);
778
779         HASHMAP_FOREACH(f, j->files, i) {
780                 int k;
781                 usec_t first, validated, last;
782
783 #ifdef HAVE_GCRYPT
784                 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
785                         log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
786 #endif
787
788                 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
789                 if (k == -EINVAL) {
790                         /* If the key was invalid give up right-away. */
791                         return k;
792                 } else if (k < 0) {
793                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
794                         r = k;
795                 } else {
796                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
797                         log_info("PASS: %s", f->path);
798
799                         if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
800                                 if (validated > 0) {
801                                         log_info("=> Validated from %s to %s, final %s entries not sealed.",
802                                                  format_timestamp(a, sizeof(a), first),
803                                                  format_timestamp(b, sizeof(b), validated),
804                                                  format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
805                                 } else if (last > 0)
806                                         log_info("=> No sealing yet, %s of entries not sealed.",
807                                                  format_timespan(c, sizeof(c), last - first));
808                                 else
809                                         log_info("=> No sealing yet, no entries in file.");
810                         }
811                 }
812         }
813
814         return r;
815 }
816
817 static int access_check(void) {
818
819 #ifdef HAVE_ACL
820         if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
821                 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
822                 return -EACCES;
823         }
824
825         if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
826                 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
827 #else
828         if (geteuid() != 0 && in_group("adm") <= 0) {
829                 log_error("No access to messages. Only users in the group 'adm' can see messages.");
830                 return -EACCES;
831         }
832 #endif
833
834         return 0;
835 }
836
837 int main(int argc, char *argv[]) {
838         int r;
839         sd_journal *j = NULL;
840         bool need_seek = false;
841         sd_id128_t previous_boot_id;
842         bool previous_boot_id_valid = false;
843         bool have_pager;
844         unsigned n_shown = 0;
845
846         log_parse_environment();
847         log_open();
848
849         r = parse_argv(argc, argv);
850         if (r <= 0)
851                 goto finish;
852
853         if (arg_action == ACTION_NEW_ID128) {
854                 r = generate_new_id128();
855                 goto finish;
856         }
857
858         if (arg_action == ACTION_SETUP_KEYS) {
859                 r = setup_keys();
860                 goto finish;
861         }
862
863         r = access_check();
864         if (r < 0)
865                 goto finish;
866
867         if (arg_directory)
868                 r = sd_journal_open_directory(&j, arg_directory, 0);
869         else
870                 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
871         if (r < 0) {
872                 log_error("Failed to open journal: %s", strerror(-r));
873                 goto finish;
874         }
875
876         if (arg_action == ACTION_VERIFY) {
877                 r = verify(j);
878                 goto finish;
879         }
880
881         if (arg_action == ACTION_PRINT_HEADER) {
882                 journal_print_header(j);
883                 r = 0;
884                 goto finish;
885         }
886
887         if (arg_action == ACTION_DISK_USAGE) {
888                 uint64_t bytes;
889                 char sbytes[FORMAT_BYTES_MAX];
890
891                 r = sd_journal_get_usage(j, &bytes);
892                 if (r < 0)
893                         goto finish;
894
895                 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
896                 r = 0;
897                 goto finish;
898         }
899
900         r = add_this_boot(j);
901         if (r < 0)
902                 goto finish;
903
904         r = add_unit(j);
905         if (r < 0)
906                 goto finish;
907
908         r = add_matches(j, argv + optind);
909         if (r < 0)
910                 goto finish;
911
912         r = add_priorities(j);
913         if (r < 0)
914                 goto finish;
915
916         if (arg_field) {
917                 const void *data;
918                 size_t size;
919
920                 r = sd_journal_query_unique(j, arg_field);
921                 if (r < 0) {
922                         log_error("Failed to query unique data objects: %s", strerror(-r));
923                         goto finish;
924                 }
925
926                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
927                         const void *eq;
928
929                         if (arg_lines > 0 && n_shown >= arg_lines)
930                                 break;
931
932                         eq = memchr(data, '=', size);
933                         if (eq)
934                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
935                         else
936                                 printf("%.*s\n", (int) size, (const char*) data);
937
938                         n_shown ++;
939                 }
940
941                 r = 0;
942                 goto finish;
943         }
944
945         if (arg_cursor) {
946                 r = sd_journal_seek_cursor(j, arg_cursor);
947                 if (r < 0) {
948                         log_error("Failed to seek to cursor: %s", strerror(-r));
949                         goto finish;
950                 }
951
952                 r = sd_journal_next(j);
953
954         } else if (arg_since_set) {
955                 r = sd_journal_seek_realtime_usec(j, arg_since);
956                 if (r < 0) {
957                         log_error("Failed to seek to date: %s", strerror(-r));
958                         goto finish;
959                 }
960                 r = sd_journal_next(j);
961
962         } else if (arg_lines > 0) {
963                 r = sd_journal_seek_tail(j);
964                 if (r < 0) {
965                         log_error("Failed to seek to tail: %s", strerror(-r));
966                         goto finish;
967                 }
968
969                 r = sd_journal_previous_skip(j, arg_lines);
970
971         } else {
972                 r = sd_journal_seek_head(j);
973                 if (r < 0) {
974                         log_error("Failed to seek to head: %s", strerror(-r));
975                         goto finish;
976                 }
977
978                 r = sd_journal_next(j);
979         }
980
981         if (r < 0) {
982                 log_error("Failed to iterate through journal: %s", strerror(-r));
983                 goto finish;
984         }
985
986         on_tty();
987         have_pager = !arg_no_pager && !arg_follow && pager_open();
988
989         if (!arg_quiet) {
990                 usec_t start, end;
991                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
992
993                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
994                 if (r < 0) {
995                         log_error("Failed to get cutoff: %s", strerror(-r));
996                         goto finish;
997                 }
998
999                 if (r > 0) {
1000                         if (arg_follow)
1001                                 printf("-- Logs begin at %s. --\n",
1002                                        format_timestamp(start_buf, sizeof(start_buf), start));
1003                         else
1004                                 printf("-- Logs begin at %s, end at %s. --\n",
1005                                        format_timestamp(start_buf, sizeof(start_buf), start),
1006                                        format_timestamp(end_buf, sizeof(end_buf), end));
1007                 }
1008         }
1009
1010         for (;;) {
1011                 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1012                         int flags;
1013
1014                         if (need_seek) {
1015                                 r = sd_journal_next(j);
1016                                 if (r < 0) {
1017                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1018                                         goto finish;
1019                                 }
1020                         }
1021
1022                         if (r == 0)
1023                                 break;
1024
1025                         if (arg_until_set) {
1026                                 usec_t usec;
1027
1028                                 r = sd_journal_get_realtime_usec(j, &usec);
1029                                 if (r < 0) {
1030                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1031                                         goto finish;
1032                                 }
1033                         }
1034
1035                         if (!arg_merge) {
1036                                 sd_id128_t boot_id;
1037
1038                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1039                                 if (r >= 0) {
1040                                         if (previous_boot_id_valid &&
1041                                             !sd_id128_equal(boot_id, previous_boot_id))
1042                                                 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1043
1044                                         previous_boot_id = boot_id;
1045                                         previous_boot_id_valid = true;
1046                                 }
1047                         }
1048
1049                         flags =
1050                                 arg_show_all * OUTPUT_SHOW_ALL |
1051                                 have_pager * OUTPUT_FULL_WIDTH |
1052                                 on_tty() * OUTPUT_COLOR;
1053
1054                         r = output_journal(stdout, j, arg_output, 0, flags);
1055                         if (r < 0)
1056                                 goto finish;
1057
1058                         need_seek = true;
1059                         n_shown++;
1060                 }
1061
1062                 if (!arg_follow)
1063                         break;
1064
1065                 r = sd_journal_wait(j, (uint64_t) -1);
1066                 if (r < 0) {
1067                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1068                         goto finish;
1069                 }
1070         }
1071
1072 finish:
1073         if (j)
1074                 sd_journal_close(j);
1075
1076         pager_close();
1077
1078         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1079 }