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