chiark / gitweb /
8f452dd92db77e6e0adca6c1f99b75891398b542
[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                 if (r < 0)
871                         log_error("Failed to list catalog: %s", strerror(-r));
872                 goto finish;
873         }
874
875         if (arg_action == ACTION_UPDATE_CATALOG)  {
876                 r = catalog_update();
877                 goto finish;
878         }
879
880         r = access_check();
881         if (r < 0)
882                 goto finish;
883
884         if (arg_directory)
885                 r = sd_journal_open_directory(&j, arg_directory, 0);
886         else
887                 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
888         if (r < 0) {
889                 log_error("Failed to open journal: %s", strerror(-r));
890                 goto finish;
891         }
892
893         if (arg_action == ACTION_VERIFY) {
894                 r = verify(j);
895                 goto finish;
896         }
897
898         if (arg_action == ACTION_PRINT_HEADER) {
899                 journal_print_header(j);
900                 r = 0;
901                 goto finish;
902         }
903
904         if (arg_action == ACTION_DISK_USAGE) {
905                 uint64_t bytes;
906                 char sbytes[FORMAT_BYTES_MAX];
907
908                 r = sd_journal_get_usage(j, &bytes);
909                 if (r < 0)
910                         goto finish;
911
912                 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
913                 r = 0;
914                 goto finish;
915         }
916
917         r = add_this_boot(j);
918         if (r < 0)
919                 goto finish;
920
921         r = add_unit(j);
922         if (r < 0)
923                 goto finish;
924
925         r = add_matches(j, argv + optind);
926         if (r < 0)
927                 goto finish;
928
929         r = add_priorities(j);
930         if (r < 0)
931                 goto finish;
932
933         if (arg_field) {
934                 const void *data;
935                 size_t size;
936
937                 r = sd_journal_query_unique(j, arg_field);
938                 if (r < 0) {
939                         log_error("Failed to query unique data objects: %s", strerror(-r));
940                         goto finish;
941                 }
942
943                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
944                         const void *eq;
945
946                         if (arg_lines > 0 && n_shown >= arg_lines)
947                                 break;
948
949                         eq = memchr(data, '=', size);
950                         if (eq)
951                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
952                         else
953                                 printf("%.*s\n", (int) size, (const char*) data);
954
955                         n_shown ++;
956                 }
957
958                 r = 0;
959                 goto finish;
960         }
961
962         if (arg_cursor) {
963                 r = sd_journal_seek_cursor(j, arg_cursor);
964                 if (r < 0) {
965                         log_error("Failed to seek to cursor: %s", strerror(-r));
966                         goto finish;
967                 }
968
969                 r = sd_journal_next(j);
970
971         } else if (arg_since_set) {
972                 r = sd_journal_seek_realtime_usec(j, arg_since);
973                 if (r < 0) {
974                         log_error("Failed to seek to date: %s", strerror(-r));
975                         goto finish;
976                 }
977                 r = sd_journal_next(j);
978
979         } else if (arg_lines > 0) {
980                 r = sd_journal_seek_tail(j);
981                 if (r < 0) {
982                         log_error("Failed to seek to tail: %s", strerror(-r));
983                         goto finish;
984                 }
985
986                 r = sd_journal_previous_skip(j, arg_lines);
987
988         } else {
989                 r = sd_journal_seek_head(j);
990                 if (r < 0) {
991                         log_error("Failed to seek to head: %s", strerror(-r));
992                         goto finish;
993                 }
994
995                 r = sd_journal_next(j);
996         }
997
998         if (r < 0) {
999                 log_error("Failed to iterate through journal: %s", strerror(-r));
1000                 goto finish;
1001         }
1002
1003         if (!arg_no_pager && !arg_follow)
1004                 pager_open();
1005
1006         if (!arg_quiet) {
1007                 usec_t start, end;
1008                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1009
1010                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1011                 if (r < 0) {
1012                         log_error("Failed to get cutoff: %s", strerror(-r));
1013                         goto finish;
1014                 }
1015
1016                 if (r > 0) {
1017                         if (arg_follow)
1018                                 printf("-- Logs begin at %s. --\n",
1019                                        format_timestamp(start_buf, sizeof(start_buf), start));
1020                         else
1021                                 printf("-- Logs begin at %s, end at %s. --\n",
1022                                        format_timestamp(start_buf, sizeof(start_buf), start),
1023                                        format_timestamp(end_buf, sizeof(end_buf), end));
1024                 }
1025         }
1026
1027         for (;;) {
1028                 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
1029                         int flags;
1030
1031                         if (need_seek) {
1032                                 r = sd_journal_next(j);
1033                                 if (r < 0) {
1034                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1035                                         goto finish;
1036                                 }
1037                         }
1038
1039                         if (r == 0)
1040                                 break;
1041
1042                         if (arg_until_set) {
1043                                 usec_t usec;
1044
1045                                 r = sd_journal_get_realtime_usec(j, &usec);
1046                                 if (r < 0) {
1047                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1048                                         goto finish;
1049                                 }
1050                         }
1051
1052                         if (!arg_merge) {
1053                                 sd_id128_t boot_id;
1054
1055                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1056                                 if (r >= 0) {
1057                                         if (previous_boot_id_valid &&
1058                                             !sd_id128_equal(boot_id, previous_boot_id))
1059                                                 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1060
1061                                         previous_boot_id = boot_id;
1062                                         previous_boot_id_valid = true;
1063                                 }
1064                         }
1065
1066                         flags =
1067                                 arg_all * OUTPUT_SHOW_ALL |
1068                                 (!on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1069                                 on_tty() * OUTPUT_COLOR |
1070                                 arg_catalog * OUTPUT_CATALOG;
1071
1072                         r = output_journal(stdout, j, arg_output, 0, flags);
1073                         if (r < 0)
1074                                 goto finish;
1075
1076                         need_seek = true;
1077                         n_shown++;
1078                 }
1079
1080                 if (!arg_follow)
1081                         break;
1082
1083                 r = sd_journal_wait(j, (uint64_t) -1);
1084                 if (r < 0) {
1085                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1086                         goto finish;
1087                 }
1088         }
1089
1090 finish:
1091         if (j)
1092                 sd_journal_close(j);
1093
1094         pager_close();
1095
1096         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1097 }