chiark / gitweb /
journalctl: be smarter about journal error checks
[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\n"
909                                    "the system. Users in the group 'systemd-journal' can see all messages.\n"
910                                    "Pass -q to turn this notice off.");
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 this notice off.", s);
928                 }
929         }
930
931         return 0;
932 }
933 #endif
934
935 static int access_check(sd_journal *j) {
936         uint64_t eacces = EACCES, *code;
937         Iterator it;
938         int r = 0;
939
940         assert(j);
941         assert(j->errors);
942         assert(j->files);
943
944         if (set_isempty(j->errors)) {
945                 if (hashmap_isempty(j->files))
946                         log_info("No journal files were found.");
947                 return 0;
948         }
949
950         if (!set_contains(j->errors, &eacces)) {
951 #ifdef HAVE_ACL
952                 /* If /var/log/journal doesn't even exist,
953                    unprivileged users have no access at all */
954                 if (access("/var/log/journal", F_OK) < 0 &&
955                     geteuid() != 0 &&
956                     in_group("systemd-journal") <= 0) {
957                         log_error("Unprivileged users can't see messages unless persistent log storage\n"
958                                   "is enabled. Users in the group 'systemd-journal' can always see messages.");
959                         return -EACCES;
960                 }
961
962                 /* If /var/log/journal exists, try to pring a nice
963                    notice if the user lacks access to it */
964                 if (!arg_quiet && geteuid() != 0) {
965                         r = access_check_var_log_journal(j);
966                         if (r < 0)
967                                 return r;
968                 }
969 #else
970                 if (geteuid() != 0 && in_group("systemd-journal") <= 0)
971                         log_error("No access to messages.\n"
972                                   "Users in the group 'systemd-journal' can see messages.");
973 #endif
974                 if (hashmap_isempty(j->files)) {
975                         log_error("No journal files were opened, due to insufficient permissions.");
976                         r = -EACCES;
977                 }
978         }
979
980         SET_FOREACH(code, j->errors, it) {
981                 int err = -PTR_TO_INT(code);
982                 assert(err > 0);
983                 if (err != EACCES)
984                         log_warning("Error was encountered while opening journal files: %s",
985                                     strerror(err));
986         }
987
988         log_notice("Hint: run journalctl in debug mode: SYSTEMD_LOG_LEVEL=debug journalct ...");
989
990         return r;
991 }
992
993 int main(int argc, char *argv[]) {
994         int r;
995         sd_journal _cleanup_journal_close_ *j = NULL;
996         bool need_seek = false;
997         sd_id128_t previous_boot_id;
998         bool previous_boot_id_valid = false, first_line = true;
999         int n_shown = 0;
1000
1001         setlocale(LC_ALL, "");
1002         log_parse_environment();
1003         log_open();
1004
1005         r = parse_argv(argc, argv);
1006         if (r <= 0)
1007                 goto finish;
1008
1009         signal(SIGWINCH, columns_lines_cache_reset);
1010
1011         if (arg_action == ACTION_NEW_ID128) {
1012                 r = generate_new_id128();
1013                 goto finish;
1014         }
1015
1016         if (arg_action == ACTION_SETUP_KEYS) {
1017                 r = setup_keys();
1018                 goto finish;
1019         }
1020
1021         if (arg_action == ACTION_LIST_CATALOG ||
1022             arg_action == ACTION_DUMP_CATALOG)  {
1023                 bool oneline = arg_action == ACTION_LIST_CATALOG;
1024                 if (optind < argc)
1025                         r = catalog_list_items(stdout, oneline, argv + optind);
1026                 else
1027                         r = catalog_list(stdout, oneline);
1028                 if (r < 0)
1029                         log_error("Failed to list catalog: %s", strerror(-r));
1030                 goto finish;
1031         }
1032
1033         if (arg_action == ACTION_UPDATE_CATALOG)  {
1034                 r = catalog_update();
1035                 goto finish;
1036         }
1037
1038         if (arg_directory)
1039                 r = sd_journal_open_directory(&j, arg_directory, 0);
1040         else
1041                 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
1042         if (r < 0) {
1043                 log_error("Failed to open journal: %s", strerror(-r));
1044                 return EXIT_FAILURE;
1045         }
1046
1047         r = access_check(j);
1048         if (r < 0)
1049                 return EXIT_FAILURE;
1050
1051         if (arg_action == ACTION_VERIFY) {
1052                 r = verify(j);
1053                 goto finish;
1054         }
1055
1056         if (arg_action == ACTION_PRINT_HEADER) {
1057                 journal_print_header(j);
1058                 return EXIT_SUCCESS;
1059         }
1060
1061         if (arg_action == ACTION_DISK_USAGE) {
1062                 uint64_t bytes;
1063                 char sbytes[FORMAT_BYTES_MAX];
1064
1065                 r = sd_journal_get_usage(j, &bytes);
1066                 if (r < 0)
1067                         return EXIT_FAILURE;
1068
1069                 printf("Journals take up %s on disk.\n",
1070                        format_bytes(sbytes, sizeof(sbytes), bytes));
1071                 return EXIT_SUCCESS;
1072         }
1073
1074         r = add_this_boot(j);
1075         if (r < 0)
1076                 return EXIT_FAILURE;
1077
1078         r = add_unit(j);
1079         if (r < 0)
1080                 return EXIT_FAILURE;
1081
1082         r = add_matches(j, argv + optind);
1083         if (r < 0)
1084                 return EXIT_FAILURE;
1085
1086         r = add_priorities(j);
1087         if (r < 0)
1088                 return EXIT_FAILURE;
1089
1090         /* Opening the fd now means the first sd_journal_wait() will actually wait */
1091         r = sd_journal_get_fd(j);
1092         if (r < 0)
1093                 return EXIT_FAILURE;
1094
1095         if (arg_field) {
1096                 const void *data;
1097                 size_t size;
1098
1099                 r = sd_journal_query_unique(j, arg_field);
1100                 if (r < 0) {
1101                         log_error("Failed to query unique data objects: %s", strerror(-r));
1102                         return EXIT_FAILURE;
1103                 }
1104
1105                 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1106                         const void *eq;
1107
1108                         if (arg_lines >= 0 && n_shown >= arg_lines)
1109                                 break;
1110
1111                         eq = memchr(data, '=', size);
1112                         if (eq)
1113                                 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1114                         else
1115                                 printf("%.*s\n", (int) size, (const char*) data);
1116
1117                         n_shown ++;
1118                 }
1119
1120                 return EXIT_SUCCESS;
1121         }
1122
1123         if (arg_cursor) {
1124                 r = sd_journal_seek_cursor(j, arg_cursor);
1125                 if (r < 0) {
1126                         log_error("Failed to seek to cursor: %s", strerror(-r));
1127                         return EXIT_FAILURE;
1128                 }
1129                 if (!arg_reverse)
1130                         r = sd_journal_next(j);
1131                 else
1132                         r = sd_journal_previous(j);
1133
1134         } else if (arg_since_set && !arg_reverse) {
1135                 r = sd_journal_seek_realtime_usec(j, arg_since);
1136                 if (r < 0) {
1137                         log_error("Failed to seek to date: %s", strerror(-r));
1138                         return EXIT_FAILURE;
1139                 }
1140                 r = sd_journal_next(j);
1141
1142         } else if (arg_until_set && arg_reverse) {
1143                 r = sd_journal_seek_realtime_usec(j, arg_until);
1144                 if (r < 0) {
1145                         log_error("Failed to seek to date: %s", strerror(-r));
1146                         return EXIT_FAILURE;
1147                 }
1148                 r = sd_journal_previous(j);
1149
1150         } else if (arg_lines >= 0) {
1151                 r = sd_journal_seek_tail(j);
1152                 if (r < 0) {
1153                         log_error("Failed to seek to tail: %s", strerror(-r));
1154                         return EXIT_FAILURE;
1155                 }
1156
1157                 r = sd_journal_previous_skip(j, arg_lines);
1158
1159         } else if (arg_reverse) {
1160                 r = sd_journal_seek_tail(j);
1161                 if (r < 0) {
1162                         log_error("Failed to seek to tail: %s", strerror(-r));
1163                         return EXIT_FAILURE;
1164                 }
1165
1166                 r = sd_journal_previous(j);
1167
1168         } else {
1169                 r = sd_journal_seek_head(j);
1170                 if (r < 0) {
1171                         log_error("Failed to seek to head: %s", strerror(-r));
1172                         return EXIT_FAILURE;
1173                 }
1174
1175                 r = sd_journal_next(j);
1176         }
1177
1178         if (r < 0) {
1179                 log_error("Failed to iterate through journal: %s", strerror(-r));
1180                 return EXIT_FAILURE;
1181         }
1182
1183         if (!arg_no_pager && !arg_follow)
1184                 pager_open(arg_pager_end);
1185
1186         if (!arg_quiet) {
1187                 usec_t start, end;
1188                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1189
1190                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1191                 if (r < 0) {
1192                         log_error("Failed to get cutoff: %s", strerror(-r));
1193                         goto finish;
1194                 }
1195
1196                 if (r > 0) {
1197                         if (arg_follow)
1198                                 printf("-- Logs begin at %s. --\n",
1199                                        format_timestamp(start_buf, sizeof(start_buf), start));
1200                         else
1201                                 printf("-- Logs begin at %s, end at %s. --\n",
1202                                        format_timestamp(start_buf, sizeof(start_buf), start),
1203                                        format_timestamp(end_buf, sizeof(end_buf), end));
1204                 }
1205         }
1206
1207         for (;;) {
1208                 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
1209                         int flags;
1210
1211                         if (need_seek) {
1212                                 if (!arg_reverse)
1213                                         r = sd_journal_next(j);
1214                                 else
1215                                         r = sd_journal_previous(j);
1216                                 if (r < 0) {
1217                                         log_error("Failed to iterate through journal: %s", strerror(-r));
1218                                         goto finish;
1219                                 }
1220                         }
1221
1222                         if (r == 0)
1223                                 break;
1224
1225                         if (arg_until_set && !arg_reverse) {
1226                                 usec_t usec;
1227
1228                                 r = sd_journal_get_realtime_usec(j, &usec);
1229                                 if (r < 0) {
1230                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1231                                         goto finish;
1232                                 }
1233                                 if (usec > arg_until)
1234                                         goto finish;
1235                         }
1236
1237                         if (arg_since_set && arg_reverse) {
1238                                 usec_t usec;
1239
1240                                 r = sd_journal_get_realtime_usec(j, &usec);
1241                                 if (r < 0) {
1242                                         log_error("Failed to determine timestamp: %s", strerror(-r));
1243                                         goto finish;
1244                                 }
1245                                 if (usec < arg_since)
1246                                         goto finish;
1247                         }
1248
1249                         if (!arg_merge) {
1250                                 sd_id128_t boot_id;
1251
1252                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1253                                 if (r >= 0) {
1254                                         if (previous_boot_id_valid &&
1255                                             !sd_id128_equal(boot_id, previous_boot_id))
1256                                                 printf(ANSI_HIGHLIGHT_ON "-- Reboot --" ANSI_HIGHLIGHT_OFF "\n");
1257
1258                                         previous_boot_id = boot_id;
1259                                         previous_boot_id_valid = true;
1260                                 }
1261                         }
1262
1263                         flags =
1264                                 arg_all * OUTPUT_SHOW_ALL |
1265                                 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
1266                                 on_tty() * OUTPUT_COLOR |
1267                                 arg_catalog * OUTPUT_CATALOG;
1268
1269                         r = output_journal(stdout, j, arg_output, 0, flags);
1270                         if (r < 0 || ferror(stdout))
1271                                 goto finish;
1272
1273                         need_seek = true;
1274                         n_shown++;
1275                 }
1276
1277                 if (!arg_follow)
1278                         break;
1279
1280                 r = sd_journal_wait(j, (uint64_t) -1);
1281                 if (r < 0) {
1282                         log_error("Couldn't wait for journal event: %s", strerror(-r));
1283                         goto finish;
1284                 }
1285
1286                 first_line = false;
1287         }
1288
1289 finish:
1290         pager_close();
1291
1292         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
1293 }