chiark / gitweb /
journalctl: implement quering field values with new -F switch
[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 int main(int argc, char *argv[]) {
818         int r;
819         sd_journal *j = NULL;
820         bool need_seek = false;
821         sd_id128_t previous_boot_id;
822         bool previous_boot_id_valid = false;
823         bool have_pager;
824         unsigned n_shown = 0;
825
826         log_parse_environment();
827         log_open();
828
829         r = parse_argv(argc, argv);
830         if (r <= 0)
831                 goto finish;
832
833         if (arg_action == ACTION_NEW_ID128) {
834                 r = generate_new_id128();
835                 goto finish;
836         }
837
838         if (arg_action == ACTION_SETUP_KEYS) {
839                 r = setup_keys();
840                 goto finish;
841         }
842
843         if (arg_directory)
844                 r = sd_journal_open_directory(&j, arg_directory, 0);
845         else
846                 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
847
848         if (r < 0) {
849                 log_error("Failed to open journal: %s", strerror(-r));
850                 goto finish;
851         }
852
853         if (arg_action == ACTION_VERIFY) {
854                 r = verify(j);
855                 goto finish;
856         }
857
858         if (arg_action == ACTION_PRINT_HEADER) {
859                 journal_print_header(j);
860                 r = 0;
861                 goto finish;
862         }
863
864         if (arg_action == ACTION_DISK_USAGE) {
865                 uint64_t bytes;
866                 char sbytes[FORMAT_BYTES_MAX];
867
868                 r = sd_journal_get_usage(j, &bytes);
869                 if (r < 0)
870                         goto finish;
871
872                 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
873                 r = 0;
874                 goto finish;
875         }
876
877 #ifdef HAVE_ACL
878         if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
879                 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
880                 r = -EACCES;
881                 goto finish;
882         }
883
884         if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
885                 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
886 #else
887         if (geteuid() != 0 && in_group("adm") <= 0) {
888                 log_error("No access to messages. Only users in the group 'adm' can see messages.");
889                 r = -EACCES;
890                 goto finish;
891         }
892 #endif
893
894         r = add_this_boot(j);
895         if (r < 0)
896                 goto finish;
897
898         r = add_unit(j);
899         if (r < 0)
900                 goto finish;
901
902         r = add_matches(j, argv + optind);
903         if (r < 0)
904                 goto finish;
905
906         r = add_priorities(j);
907         if (r < 0)
908                 goto finish;
909
910         if (arg_field) {
911                 const void *data;
912                 size_t size;
913
914                 r = sd_journal_query_unique(j, arg_field);
915                 if (r < 0) {
916                         log_error("Failed to query unique data objects: %s", strerror(-r));
917                         goto finish;
918                 }
919
920                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
921                         const void *eq;
922
923                         eq = memchr(data, '=', size);
924                         if (eq)
925                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
926                         else
927                                 printf("%.*s\n", (int) size, (const char*) data);
928                 }
929
930                 r = 0;
931                 goto finish;
932         }
933
934         if (arg_cursor) {
935                 r = sd_journal_seek_cursor(j, arg_cursor);
936                 if (r < 0) {
937                         log_error("Failed to seek to cursor: %s", strerror(-r));
938                         goto finish;
939                 }
940
941                 r = sd_journal_next(j);
942
943         } else if (arg_since_set) {
944                 r = sd_journal_seek_realtime_usec(j, arg_since);
945                 if (r < 0) {
946                         log_error("Failed to seek to date: %s", strerror(-r));
947                         goto finish;
948                 }
949                 r = sd_journal_next(j);
950
951         } else if (arg_lines > 0) {
952                 r = sd_journal_seek_tail(j);
953                 if (r < 0) {
954                         log_error("Failed to seek to tail: %s", strerror(-r));
955                         goto finish;
956                 }
957
958                 r = sd_journal_previous_skip(j, arg_lines);
959
960         } else {
961                 r = sd_journal_seek_head(j);
962                 if (r < 0) {
963                         log_error("Failed to seek to head: %s", strerror(-r));
964                         goto finish;
965                 }
966
967                 r = sd_journal_next(j);
968         }
969
970         if (r < 0) {
971                 log_error("Failed to iterate through journal: %s", strerror(-r));
972                 goto finish;
973         }
974
975         on_tty();
976         have_pager = !arg_no_pager && !arg_follow && pager_open();
977
978         if (!arg_quiet) {
979                 usec_t start, end;
980                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
981
982                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
983                 if (r < 0) {
984                         log_error("Failed to get cutoff: %s", strerror(-r));
985                         goto finish;
986                 }
987
988                 if (r > 0) {
989                         if (arg_follow)
990                                 printf("-- Logs begin at %s. --\n",
991                                        format_timestamp(start_buf, sizeof(start_buf), start));
992                         else
993                                 printf("-- Logs begin at %s, end at %s. --\n",
994                                        format_timestamp(start_buf, sizeof(start_buf), start),
995                                        format_timestamp(end_buf, sizeof(end_buf), end));
996                 }
997         }
998
999         for (;;) {
1000                 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1001                         int flags;
1002
1003                         if (need_seek) {
1004                                 r = sd_journal_next(j);
1005                                 if (r < 0) {
1006                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1007                                         goto finish;
1008                                 }
1009                         }
1010
1011                         if (r == 0)
1012                                 break;
1013
1014                         if (arg_until_set) {
1015                                 usec_t usec;
1016
1017                                 r = sd_journal_get_realtime_usec(j, &usec);
1018                                 if (r < 0) {
1019                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1020                                         goto finish;
1021                                 }
1022                         }
1023
1024                         if (!arg_merge) {
1025                                 sd_id128_t boot_id;
1026
1027                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1028                                 if (r >= 0) {
1029                                         if (previous_boot_id_valid &&
1030                                             !sd_id128_equal(boot_id, previous_boot_id))
1031                                                 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1032
1033                                         previous_boot_id = boot_id;
1034                                         previous_boot_id_valid = true;
1035                                 }
1036                         }
1037
1038                         flags =
1039                                 arg_show_all * OUTPUT_SHOW_ALL |
1040                                 have_pager * OUTPUT_FULL_WIDTH |
1041                                 on_tty() * OUTPUT_COLOR;
1042
1043                         r = output_journal(stdout, j, arg_output, 0, flags);
1044                         if (r < 0)
1045                                 goto finish;
1046
1047                         need_seek = true;
1048                         n_shown++;
1049                 }
1050
1051                 if (!arg_follow)
1052                         break;
1053
1054                 r = sd_journal_wait(j, (uint64_t) -1);
1055                 if (r < 0) {
1056                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1057                         goto finish;
1058                 }
1059         }
1060
1061 finish:
1062         if (j)
1063                 sd_journal_close(j);
1064
1065         pager_close();
1066
1067         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1068 }