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