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