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