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