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