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