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