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