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