chiark / gitweb /
journald-server: r should be checked after journal_file_open_reliably
[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
729         r = sd_id128_get_machine(&machine);
730         if (r < 0) {
731                 log_error("Failed to get machine ID: %s", strerror(-r));
732                 return r;
733         }
734
735         r = sd_id128_get_boot(&boot);
736         if (r < 0) {
737                 log_error("Failed to get boot ID: %s", strerror(-r));
738                 return r;
739         }
740
741         if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
742                      SD_ID128_FORMAT_VAL(machine)) < 0)
743                 return log_oom();
744
745         if (access(p, F_OK) >= 0) {
746                 log_error("Sealing key file %s exists already.", p);
747                 r = -EEXIST;
748                 goto finish;
749         }
750
751         if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
752                      SD_ID128_FORMAT_VAL(machine)) < 0) {
753                 r = log_oom();
754                 goto finish;
755         }
756
757         mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
758         mpk = alloca(mpk_size);
759
760         seed_size = FSPRG_RECOMMENDED_SEEDLEN;
761         seed = alloca(seed_size);
762
763         state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
764         state = alloca(state_size);
765
766         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
767         if (fd < 0) {
768                 log_error("Failed to open /dev/random: %m");
769                 r = -errno;
770                 goto finish;
771         }
772
773         log_info("Generating seed...");
774         l = loop_read(fd, seed, seed_size, true);
775         if (l < 0 || (size_t) l != seed_size) {
776                 log_error("Failed to read random seed: %s", strerror(EIO));
777                 r = -EIO;
778                 goto finish;
779         }
780
781         log_info("Generating key pair...");
782         FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
783
784         log_info("Generating sealing key...");
785         FSPRG_GenState0(state, mpk, seed, seed_size);
786
787         assert(arg_interval > 0);
788
789         n = now(CLOCK_REALTIME);
790         n /= arg_interval;
791
792         close_nointr_nofail(fd);
793         fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
794         if (fd < 0) {
795                 log_error("Failed to open %s: %m", k);
796                 r = -errno;
797                 goto finish;
798         }
799
800         /* Enable secure remove, exclusion from dump, synchronous
801          * writing and in-place updating */
802         if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
803                 log_warning("FS_IOC_GETFLAGS failed: %m");
804
805         attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
806
807         if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
808                 log_warning("FS_IOC_SETFLAGS failed: %m");
809
810         zero(h);
811         memcpy(h.signature, "KSHHRHLP", 8);
812         h.machine_id = machine;
813         h.boot_id = boot;
814         h.header_size = htole64(sizeof(h));
815         h.start_usec = htole64(n * arg_interval);
816         h.interval_usec = htole64(arg_interval);
817         h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
818         h.fsprg_state_size = htole64(state_size);
819
820         l = loop_write(fd, &h, sizeof(h), false);
821         if (l < 0 || (size_t) l != sizeof(h)) {
822                 log_error("Failed to write header: %s", strerror(EIO));
823                 r = -EIO;
824                 goto finish;
825         }
826
827         l = loop_write(fd, state, state_size, false);
828         if (l < 0 || (size_t) l != state_size) {
829                 log_error("Failed to write state: %s", strerror(EIO));
830                 r = -EIO;
831                 goto finish;
832         }
833
834         if (link(k, p) < 0) {
835                 log_error("Failed to link file: %m");
836                 r = -errno;
837                 goto finish;
838         }
839
840         if (on_tty()) {
841                 fprintf(stderr,
842                         "\n"
843                         "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
844                         "the following local file. This key file is automatically updated when the\n"
845                         "sealing key is advanced. It should not be used on multiple hosts.\n"
846                         "\n"
847                         "\t%s\n"
848                         "\n"
849                         "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
850                         "at a safe location and should not be saved locally on disk.\n"
851                         "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
852                 fflush(stderr);
853         }
854         for (i = 0; i < seed_size; i++) {
855                 if (i > 0 && i % 3 == 0)
856                         putchar('-');
857                 printf("%02x", ((uint8_t*) seed)[i]);
858         }
859
860         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
861
862         if (on_tty()) {
863                 char tsb[FORMAT_TIMESPAN_MAX], *hn;
864
865                 fprintf(stderr,
866                         ANSI_HIGHLIGHT_OFF "\n"
867                         "The sealing key is automatically changed every %s.\n",
868                         format_timespan(tsb, sizeof(tsb), arg_interval, 0));
869
870                 hn = gethostname_malloc();
871
872                 if (hn) {
873                         hostname_cleanup(hn, false);
874                         fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
875                 } else
876                         fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
877
878 #ifdef HAVE_QRENCODE
879                 /* If this is not an UTF-8 system don't print any QR codes */
880                 if (is_locale_utf8()) {
881                         fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
882                         print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
883                 }
884 #endif
885                 free(hn);
886         }
887
888         r = 0;
889
890 finish:
891         if (fd >= 0)
892                 close_nointr_nofail(fd);
893
894         if (k) {
895                 unlink(k);
896                 free(k);
897         }
898
899         free(p);
900
901         return r;
902 #else
903         log_error("Forward-secure sealing not available.");
904         return -ENOTSUP;
905 #endif
906 }
907
908 static int verify(sd_journal *j) {
909         int r = 0;
910         Iterator i;
911         JournalFile *f;
912
913         assert(j);
914
915         log_show_color(true);
916
917         HASHMAP_FOREACH(f, j->files, i) {
918                 int k;
919                 usec_t first, validated, last;
920
921 #ifdef HAVE_GCRYPT
922                 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
923                         log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
924 #endif
925
926                 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
927                 if (k == -EINVAL) {
928                         /* If the key was invalid give up right-away. */
929                         return k;
930                 } else if (k < 0) {
931                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
932                         r = k;
933                 } else {
934                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
935                         log_info("PASS: %s", f->path);
936
937                         if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
938                                 if (validated > 0) {
939                                         log_info("=> Validated from %s to %s, final %s entries not sealed.",
940                                                  format_timestamp(a, sizeof(a), first),
941                                                  format_timestamp(b, sizeof(b), validated),
942                                                  format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
943                                 } else if (last > 0)
944                                         log_info("=> No sealing yet, %s of entries not sealed.",
945                                                  format_timespan(c, sizeof(c), last - first, 0));
946                                 else
947                                         log_info("=> No sealing yet, no entries in file.");
948                         }
949                 }
950         }
951
952         return r;
953 }
954
955 #ifdef HAVE_ACL
956 static int access_check_var_log_journal(sd_journal *j) {
957         _cleanup_strv_free_ char **g = NULL;
958         bool have_access;
959         int r;
960
961         assert(j);
962
963         have_access = in_group("systemd-journal") > 0;
964
965         if (!have_access) {
966                 /* Let's enumerate all groups from the default ACL of
967                  * the directory, which generally should allow access
968                  * to most journal files too */
969                 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
970                 if (r < 0)
971                         return r;
972         }
973
974         if (!have_access) {
975
976                 if (strv_isempty(g))
977                         log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
978                                    "      Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
979                                    "      turn off this notice.");
980                 else {
981                         _cleanup_free_ char *s = NULL;
982
983                         r = strv_extend(&g, "systemd-journal");
984                         if (r < 0)
985                                 return log_oom();
986
987                         strv_sort(g);
988                         strv_uniq(g);
989
990                         s = strv_join(g, "', '");
991                         if (!s)
992                                 return log_oom();
993
994                         log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
995                                    "      Users in the groups '%s' can see all messages.\n"
996                                    "      Pass -q to turn off this notice.", s);
997                 }
998         }
999
1000         return 0;
1001 }
1002 #endif
1003
1004 static int access_check(sd_journal *j) {
1005         Iterator it;
1006         void *code;
1007         int r = 0;
1008
1009         assert(j);
1010
1011         if (set_isempty(j->errors)) {
1012                 if (hashmap_isempty(j->files))
1013                         log_notice("No journal files were found.");
1014                 return 0;
1015         }
1016
1017         if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
1018 #ifdef HAVE_ACL
1019                 /* If /var/log/journal doesn't even exist,
1020                  * unprivileged users have no access at all */
1021                 if (access("/var/log/journal", F_OK) < 0 &&
1022                     geteuid() != 0 &&
1023                     in_group("systemd-journal") <= 0) {
1024                         log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1025                                   "enabled. Users in the 'systemd-journal' group may always access messages.");
1026                         return -EACCES;
1027                 }
1028
1029                 /* If /var/log/journal exists, try to pring a nice
1030                    notice if the user lacks access to it */
1031                 if (!arg_quiet && geteuid() != 0) {
1032                         r = access_check_var_log_journal(j);
1033                         if (r < 0)
1034                                 return r;
1035                 }
1036 #else
1037                 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1038                         log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1039                                   "group may access messages.");
1040                         return -EACCES;
1041                 }
1042 #endif
1043
1044                 if (hashmap_isempty(j->files)) {
1045                         log_error("No journal files were opened due to insufficient permissions.");
1046                         r = -EACCES;
1047                 }
1048         }
1049
1050         SET_FOREACH(code, j->errors, it) {
1051                 int err;
1052
1053                 err = -PTR_TO_INT(code);
1054                 assert(err > 0);
1055
1056                 if (err != EACCES)
1057                         log_warning("Error was encountered while opening journal files: %s",
1058                                     strerror(err));
1059         }
1060
1061         return r;
1062 }
1063
1064 int main(int argc, char *argv[]) {
1065         int r;
1066         _cleanup_journal_close_ sd_journal*j = NULL;
1067         bool need_seek = false;
1068         sd_id128_t previous_boot_id;
1069         bool previous_boot_id_valid = false, first_line = true;
1070         int n_shown = 0;
1071
1072         setlocale(LC_ALL, "");
1073         log_parse_environment();
1074         log_open();
1075
1076         r = parse_argv(argc, argv);
1077         if (r <= 0)
1078                 goto finish;
1079
1080         signal(SIGWINCH, columns_lines_cache_reset);
1081
1082         if (arg_action == ACTION_NEW_ID128) {
1083                 r = generate_new_id128();
1084                 goto finish;
1085         }
1086
1087         if (arg_action == ACTION_SETUP_KEYS) {
1088                 r = setup_keys();
1089                 goto finish;
1090         }
1091
1092         if (arg_action == ACTION_UPDATE_CATALOG ||
1093             arg_action == ACTION_LIST_CATALOG ||
1094             arg_action == ACTION_DUMP_CATALOG) {
1095
1096                 const char* database = CATALOG_DATABASE;
1097                 _cleanup_free_ char *copy = NULL;
1098                 if (arg_root) {
1099                         copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
1100                         if (!copy) {
1101                                 r = log_oom();
1102                                 goto finish;
1103                         }
1104                         path_kill_slashes(copy);
1105                         database = copy;
1106                 }
1107
1108                 if (arg_action == ACTION_UPDATE_CATALOG) {
1109                         r = catalog_update(database, arg_root, catalog_file_dirs);
1110                         if (r < 0)
1111                                 log_error("Failed to list catalog: %s", strerror(-r));
1112                 } else {
1113                         bool oneline = arg_action == ACTION_LIST_CATALOG;
1114
1115                         if (optind < argc)
1116                                 r = catalog_list_items(stdout, database,
1117                                                        oneline, argv + optind);
1118                         else
1119                                 r = catalog_list(stdout, database, oneline);
1120                         if (r < 0)
1121                                 log_error("Failed to list catalog: %s", strerror(-r));
1122                 }
1123
1124                 goto finish;
1125         }
1126
1127         if (arg_directory)
1128                 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
1129         else if (arg_file)
1130                 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
1131         else
1132                 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
1133         if (r < 0) {
1134                 log_error("Failed to open %s: %s",
1135                           arg_directory ? arg_directory : arg_file ? "files" : "journal",
1136                           strerror(-r));
1137                 return EXIT_FAILURE;
1138         }
1139
1140         r = access_check(j);
1141         if (r < 0)
1142                 return EXIT_FAILURE;
1143
1144         if (arg_action == ACTION_VERIFY) {
1145                 r = verify(j);
1146                 goto finish;
1147         }
1148
1149         if (arg_action == ACTION_PRINT_HEADER) {
1150                 journal_print_header(j);
1151                 return EXIT_SUCCESS;
1152         }
1153
1154         if (arg_action == ACTION_DISK_USAGE) {
1155                 uint64_t bytes;
1156                 char sbytes[FORMAT_BYTES_MAX];
1157
1158                 r = sd_journal_get_usage(j, &bytes);
1159                 if (r < 0)
1160                         return EXIT_FAILURE;
1161
1162                 printf("Journals take up %s on disk.\n",
1163                        format_bytes(sbytes, sizeof(sbytes), bytes));
1164                 return EXIT_SUCCESS;
1165         }
1166
1167         r = add_this_boot(j);
1168         if (r < 0)
1169                 return EXIT_FAILURE;
1170
1171         r = add_dmesg(j);
1172         if (r < 0)
1173                 return EXIT_FAILURE;
1174
1175         r = add_units(j);
1176         strv_free(arg_system_units);
1177         strv_free(arg_user_units);
1178
1179         if (r < 0)
1180                 return EXIT_FAILURE;
1181
1182         r = add_priorities(j);
1183         if (r < 0)
1184                 return EXIT_FAILURE;
1185
1186         r = add_matches(j, argv + optind);
1187         if (r < 0)
1188                 return EXIT_FAILURE;
1189
1190         log_debug("Journal filter: %s", j->level0 ? journal_make_match_string(j) : "none");
1191
1192         if (arg_field) {
1193                 const void *data;
1194                 size_t size;
1195
1196                 r = sd_journal_set_data_threshold(j, 0);
1197                 if (r < 0) {
1198                         log_error("Failed to unset data size threshold");
1199                         return EXIT_FAILURE;
1200                 }
1201
1202                 r = sd_journal_query_unique(j, arg_field);
1203                 if (r < 0) {
1204                         log_error("Failed to query unique data objects: %s", strerror(-r));
1205                         return EXIT_FAILURE;
1206                 }
1207
1208                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1209                         const void *eq;
1210
1211                         if (arg_lines >= 0 && n_shown >= arg_lines)
1212                                 break;
1213
1214                         eq = memchr(data, '=', size);
1215                         if (eq)
1216                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1217                         else
1218                                 printf("%.*s\n", (int) size, (const char*) data);
1219
1220                         n_shown ++;
1221                 }
1222
1223                 return EXIT_SUCCESS;
1224         }
1225
1226         /* Opening the fd now means the first sd_journal_wait() will actually wait */
1227         if (arg_follow) {
1228                 r = sd_journal_get_fd(j);
1229                 if (r < 0)
1230                         return EXIT_FAILURE;
1231         }
1232
1233         if (arg_cursor) {
1234                 r = sd_journal_seek_cursor(j, arg_cursor);
1235                 if (r < 0) {
1236                         log_error("Failed to seek to cursor: %s", strerror(-r));
1237                         return EXIT_FAILURE;
1238                 }
1239                 if (!arg_reverse)
1240                         r = sd_journal_next(j);
1241                 else
1242                         r = sd_journal_previous(j);
1243
1244         } else if (arg_since_set && !arg_reverse) {
1245                 r = sd_journal_seek_realtime_usec(j, arg_since);
1246                 if (r < 0) {
1247                         log_error("Failed to seek to date: %s", strerror(-r));
1248                         return EXIT_FAILURE;
1249                 }
1250                 r = sd_journal_next(j);
1251
1252         } else if (arg_until_set && arg_reverse) {
1253                 r = sd_journal_seek_realtime_usec(j, arg_until);
1254                 if (r < 0) {
1255                         log_error("Failed to seek to date: %s", strerror(-r));
1256                         return EXIT_FAILURE;
1257                 }
1258                 r = sd_journal_previous(j);
1259
1260         } else if (arg_lines >= 0) {
1261                 r = sd_journal_seek_tail(j);
1262                 if (r < 0) {
1263                         log_error("Failed to seek to tail: %s", strerror(-r));
1264                         return EXIT_FAILURE;
1265                 }
1266
1267                 r = sd_journal_previous_skip(j, arg_lines);
1268
1269         } else if (arg_reverse) {
1270                 r = sd_journal_seek_tail(j);
1271                 if (r < 0) {
1272                         log_error("Failed to seek to tail: %s", strerror(-r));
1273                         return EXIT_FAILURE;
1274                 }
1275
1276                 r = sd_journal_previous(j);
1277
1278         } else {
1279                 r = sd_journal_seek_head(j);
1280                 if (r < 0) {
1281                         log_error("Failed to seek to head: %s", strerror(-r));
1282                         return EXIT_FAILURE;
1283                 }
1284
1285                 r = sd_journal_next(j);
1286         }
1287
1288         if (r < 0) {
1289                 log_error("Failed to iterate through journal: %s", strerror(-r));
1290                 return EXIT_FAILURE;
1291         }
1292
1293         if (!arg_no_pager && !arg_follow)
1294                 pager_open(arg_pager_end);
1295
1296         if (!arg_quiet) {
1297                 usec_t start, end;
1298                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1299
1300                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1301                 if (r < 0) {
1302                         log_error("Failed to get cutoff: %s", strerror(-r));
1303                         goto finish;
1304                 }
1305
1306                 if (r > 0) {
1307                         if (arg_follow)
1308                                 printf("-- Logs begin at %s. --\n",
1309                                        format_timestamp(start_buf, sizeof(start_buf), start));
1310                         else
1311                                 printf("-- Logs begin at %s, end at %s. --\n",
1312                                        format_timestamp(start_buf, sizeof(start_buf), start),
1313                                        format_timestamp(end_buf, sizeof(end_buf), end));
1314                 }
1315         }
1316
1317         for (;;) {
1318                 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1319                         int flags;
1320
1321                         if (need_seek) {
1322                                 if (!arg_reverse)
1323                                         r = sd_journal_next(j);
1324                                 else
1325                                         r = sd_journal_previous(j);
1326                                 if (r < 0) {
1327                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1328                                         goto finish;
1329                                 }
1330                                 if (r == 0)
1331                                         break;
1332                         }
1333
1334                         if (arg_until_set && !arg_reverse) {
1335                                 usec_t usec;
1336
1337                                 r = sd_journal_get_realtime_usec(j, &usec);
1338                                 if (r < 0) {
1339                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1340                                         goto finish;
1341                                 }
1342                                 if (usec > arg_until)
1343                                         goto finish;
1344                         }
1345
1346                         if (arg_since_set && arg_reverse) {
1347                                 usec_t usec;
1348
1349                                 r = sd_journal_get_realtime_usec(j, &usec);
1350                                 if (r < 0) {
1351                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1352                                         goto finish;
1353                                 }
1354                                 if (usec < arg_since)
1355                                         goto finish;
1356                         }
1357
1358                         if (!arg_merge) {
1359                                 sd_id128_t boot_id;
1360                                 const char *color_on = on_tty() ? ANSI_HIGHLIGHT_ON : "",
1361                                            *color_off = on_tty() ? ANSI_HIGHLIGHT_OFF : "";
1362
1363                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1364                                 if (r >= 0) {
1365                                         if (previous_boot_id_valid &&
1366                                             !sd_id128_equal(boot_id, previous_boot_id))
1367                                                 printf("%s-- Reboot --%s\n", color_on, color_off);
1368
1369                                         previous_boot_id = boot_id;
1370                                         previous_boot_id_valid = true;
1371                                 }
1372                         }
1373
1374                         flags =
1375                                 arg_all * OUTPUT_SHOW_ALL |
1376                                 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1377                                 on_tty() * OUTPUT_COLOR |
1378                                 arg_catalog * OUTPUT_CATALOG;
1379
1380                         r = output_journal(stdout, j, arg_output, 0, flags);
1381                         need_seek = true;
1382                         if (r == -EADDRNOTAVAIL)
1383                                 break;
1384                         else if (r < 0 || ferror(stdout))
1385                                 goto finish;
1386
1387                         n_shown++;
1388                 }
1389
1390                 if (!arg_follow)
1391                         break;
1392
1393                 r = sd_journal_wait(j, (uint64_t) -1);
1394                 if (r < 0) {
1395                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1396                         goto finish;
1397                 }
1398
1399                 first_line = false;
1400         }
1401
1402 finish:
1403         pager_close();
1404
1405         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1406 }