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