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