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