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