chiark / gitweb /
34017484be49fb67a980c166da353a7f035b32b5
[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 <fcntl.h>
23 #include <errno.h>
24 #include <stddef.h>
25 #include <string.h>
26 #include <stdio.h>
27 #include <unistd.h>
28 #include <stdlib.h>
29 #include <sys/poll.h>
30 #include <time.h>
31 #include <getopt.h>
32 #include <signal.h>
33 #include <sys/stat.h>
34 #include <sys/ioctl.h>
35 #include <linux/fs.h>
36 #include <locale.h>
37 #include <langinfo.h>
38
39 #include <systemd/sd-journal.h>
40
41 #include "log.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
55 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
56
57 static OutputMode arg_output = OUTPUT_SHORT;
58 static bool arg_follow = false;
59 static bool arg_show_all = false;
60 static bool arg_no_pager = false;
61 static unsigned arg_lines = 0;
62 static bool arg_no_tail = false;
63 static bool arg_quiet = false;
64 static bool arg_merge = false;
65 static bool arg_this_boot = false;
66 static const char *arg_cursor = NULL;
67 static const char *arg_directory = NULL;
68 static int arg_priorities = 0xFF;
69 static const char *arg_verify_key = NULL;
70 #ifdef HAVE_GCRYPT
71 static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
72 #endif
73 static usec_t arg_since, arg_until;
74 static bool arg_since_set = false, arg_until_set = false;
75
76 static enum {
77         ACTION_SHOW,
78         ACTION_NEW_ID128,
79         ACTION_PRINT_HEADER,
80         ACTION_SETUP_KEYS,
81         ACTION_VERIFY,
82         ACTION_DISK_USAGE,
83 } arg_action = ACTION_SHOW;
84
85 static int help(void) {
86
87         printf("%s [OPTIONS...] [MATCH]\n\n"
88                "Send control commands to or query the journal.\n\n"
89                "  -h --help              Show this help\n"
90                "     --version           Show package version\n"
91                "     --no-pager          Do not pipe output into a pager\n"
92                "  -a --all               Show all fields, including long and unprintable\n"
93                "  -c --cursor=CURSOR     Start showing entries from specified cursor\n"
94                "     --since=DATE        Start showing entries newer or of the specified date\n"
95                "     --until=DATE        Stop showing entries older or of the specified date\n"
96                "  -f --follow            Follow journal\n"
97                "  -n --lines[=INTEGER]   Number of journal entries to show\n"
98                "     --no-tail           Show all lines, even in follow mode\n"
99                "  -o --output=STRING     Change journal output mode (short, short-monotonic,\n"
100                "                         verbose, export, json, json-pretty, json-sse, cat)\n"
101                "  -q --quiet             Don't show privilege warning\n"
102                "  -m --merge             Show entries from all available journals\n"
103                "  -b --this-boot         Show data only from current boot\n"
104                "  -D --directory=PATH    Show journal files from directory\n"
105                "  -p --priority=RANGE    Show only messages within the specified priority range\n\n"
106                "Commands:\n"
107                "     --new-id128         Generate a new 128 Bit ID\n"
108                "     --header            Show journal header information\n"
109                "     --disk-usage        Show total disk usage\n"
110 #ifdef HAVE_GCRYPT
111                "     --setup-keys        Generate new FSS key pair\n"
112                "       --interval=TIME   Time interval for changing the FSS sealing key\n"
113                "     --verify            Verify journal file consistency\n"
114                "       --verify-key=KEY  Specify FSS verification key\n"
115 #endif
116                , program_invocation_short_name);
117
118         return 0;
119 }
120
121 static int parse_argv(int argc, char *argv[]) {
122
123         enum {
124                 ARG_VERSION = 0x100,
125                 ARG_NO_PAGER,
126                 ARG_NO_TAIL,
127                 ARG_NEW_ID128,
128                 ARG_HEADER,
129                 ARG_SETUP_KEYS,
130                 ARG_INTERVAL,
131                 ARG_VERIFY,
132                 ARG_VERIFY_KEY,
133                 ARG_DISK_USAGE,
134                 ARG_SINCE,
135                 ARG_UNTIL
136         };
137
138         static const struct option options[] = {
139                 { "help",         no_argument,       NULL, 'h'              },
140                 { "version" ,     no_argument,       NULL, ARG_VERSION      },
141                 { "no-pager",     no_argument,       NULL, ARG_NO_PAGER     },
142                 { "follow",       no_argument,       NULL, 'f'              },
143                 { "output",       required_argument, NULL, 'o'              },
144                 { "all",          no_argument,       NULL, 'a'              },
145                 { "lines",        optional_argument, NULL, 'n'              },
146                 { "no-tail",      no_argument,       NULL, ARG_NO_TAIL      },
147                 { "new-id128",    no_argument,       NULL, ARG_NEW_ID128    },
148                 { "quiet",        no_argument,       NULL, 'q'              },
149                 { "merge",        no_argument,       NULL, 'm'              },
150                 { "this-boot",    no_argument,       NULL, 'b'              },
151                 { "directory",    required_argument, NULL, 'D'              },
152                 { "header",       no_argument,       NULL, ARG_HEADER       },
153                 { "priority",     no_argument,       NULL, 'p'              },
154                 { "setup-keys",   no_argument,       NULL, ARG_SETUP_KEYS   },
155                 { "interval",     required_argument, NULL, ARG_INTERVAL     },
156                 { "verify",       no_argument,       NULL, ARG_VERIFY       },
157                 { "verify-key",   required_argument, NULL, ARG_VERIFY_KEY   },
158                 { "disk-usage",   no_argument,       NULL, ARG_DISK_USAGE   },
159                 { "cursor",       required_argument, NULL, 'c'              },
160                 { "since",        required_argument, NULL, ARG_SINCE        },
161                 { "until",        required_argument, NULL, ARG_UNTIL        },
162                 { NULL,           0,                 NULL, 0                }
163         };
164
165         int c, r;
166
167         assert(argc >= 0);
168         assert(argv);
169
170         while ((c = getopt_long(argc, argv, "hfo:an::qmbD:p:c:", options, NULL)) >= 0) {
171
172                 switch (c) {
173
174                 case 'h':
175                         help();
176                         return 0;
177
178                 case ARG_VERSION:
179                         puts(PACKAGE_STRING);
180                         puts(DISTRIBUTION);
181                         puts(SYSTEMD_FEATURES);
182                         return 0;
183
184                 case ARG_NO_PAGER:
185                         arg_no_pager = true;
186                         break;
187
188                 case 'f':
189                         arg_follow = true;
190                         signal(SIGWINCH, columns_cache_reset);
191                         break;
192
193                 case 'o':
194                         arg_output = output_mode_from_string(optarg);
195                         if (arg_output < 0) {
196                                 log_error("Unknown output '%s'.", optarg);
197                                 return -EINVAL;
198                         }
199
200                         break;
201
202                 case 'a':
203                         arg_show_all = true;
204                         break;
205
206                 case 'n':
207                         if (optarg) {
208                                 r = safe_atou(optarg, &arg_lines);
209                                 if (r < 0 || arg_lines <= 0) {
210                                         log_error("Failed to parse lines '%s'", optarg);
211                                         return -EINVAL;
212                                 }
213                         } else
214                                 arg_lines = 10;
215
216                         break;
217
218                 case ARG_NO_TAIL:
219                         arg_no_tail = true;
220                         break;
221
222                 case ARG_NEW_ID128:
223                         arg_action = ACTION_NEW_ID128;
224                         break;
225
226                 case 'q':
227                         arg_quiet = true;
228                         break;
229
230                 case 'm':
231                         arg_merge = true;
232                         break;
233
234                 case 'b':
235                         arg_this_boot = true;
236                         break;
237
238                 case 'D':
239                         arg_directory = optarg;
240                         break;
241
242                 case 'c':
243                         arg_cursor = optarg;
244                         break;
245
246                 case ARG_HEADER:
247                         arg_action = ACTION_PRINT_HEADER;
248                         break;
249
250                 case ARG_VERIFY:
251                         arg_action = ACTION_VERIFY;
252                         break;
253
254                 case ARG_DISK_USAGE:
255                         arg_action = ACTION_DISK_USAGE;
256                         break;
257
258 #ifdef HAVE_GCRYPT
259                 case ARG_SETUP_KEYS:
260                         arg_action = ACTION_SETUP_KEYS;
261                         break;
262
263
264                 case ARG_VERIFY_KEY:
265                         arg_action = ACTION_VERIFY;
266                         arg_verify_key = optarg;
267                         arg_merge = false;
268                         break;
269
270                 case ARG_INTERVAL:
271                         r = parse_usec(optarg, &arg_interval);
272                         if (r < 0 || arg_interval <= 0) {
273                                 log_error("Failed to parse sealing key change interval: %s", optarg);
274                                 return -EINVAL;
275                         }
276                         break;
277 #else
278                 case ARG_SETUP_KEYS:
279                 case ARG_VERIFY_KEY:
280                 case ARG_INTERVAL:
281                         log_error("Forward-secure sealing not available.");
282                         return -ENOTSUP;
283 #endif
284
285                 case 'p': {
286                         const char *dots;
287
288                         dots = strstr(optarg, "..");
289                         if (dots) {
290                                 char *a;
291                                 int from, to, i;
292
293                                 /* a range */
294                                 a = strndup(optarg, dots - optarg);
295                                 if (!a)
296                                         return log_oom();
297
298                                 from = log_level_from_string(a);
299                                 to = log_level_from_string(dots + 2);
300                                 free(a);
301
302                                 if (from < 0 || to < 0) {
303                                         log_error("Failed to parse log level range %s", optarg);
304                                         return -EINVAL;
305                                 }
306
307                                 arg_priorities = 0;
308
309                                 if (from < to) {
310                                         for (i = from; i <= to; i++)
311                                                 arg_priorities |= 1 << i;
312                                 } else {
313                                         for (i = to; i <= from; i++)
314                                                 arg_priorities |= 1 << i;
315                                 }
316
317                         } else {
318                                 int p, i;
319
320                                 p = log_level_from_string(optarg);
321                                 if (p < 0) {
322                                         log_error("Unknown log level %s", optarg);
323                                         return -EINVAL;
324                                 }
325
326                                 arg_priorities = 0;
327
328                                 for (i = 0; i <= p; i++)
329                                         arg_priorities |= 1 << i;
330                         }
331
332                         break;
333                 }
334
335                 case ARG_SINCE:
336                         r = parse_timestamp(optarg, &arg_since);
337                         if (r < 0) {
338                                 log_error("Failed to parse timestamp: %s", optarg);
339                                 return -EINVAL;
340                         }
341                         arg_since_set = true;
342                         break;
343
344                 case ARG_UNTIL:
345                         r = parse_timestamp(optarg, &arg_until);
346                         if (r < 0) {
347                                 log_error("Failed to parse timestamp: %s", optarg);
348                                 return -EINVAL;
349                         }
350                         arg_until_set = true;
351                         break;
352
353                 case '?':
354                         return -EINVAL;
355
356                 default:
357                         log_error("Unknown option code %c", c);
358                         return -EINVAL;
359                 }
360         }
361
362         if (arg_follow && !arg_no_tail && arg_lines <= 0)
363                 arg_lines = 10;
364
365         if (arg_since_set && arg_until_set && arg_since_set > arg_until_set) {
366                 log_error("--since= must be before --until=.");
367                 return -EINVAL;
368         }
369
370         if (arg_cursor && arg_since_set) {
371                 log_error("Please specify either --since= or --cursor=, not both.");
372                 return -EINVAL;
373         }
374
375         return 1;
376 }
377
378 static bool on_tty(void) {
379         static int t = -1;
380
381         /* Note that this is invoked relatively early, before we start
382          * the pager. That means the value we return reflects whether
383          * we originally were started on a tty, not if we currently
384          * are. But this is intended, since we want colour and so on
385          * when run in our own pager. */
386
387         if (_unlikely_(t < 0))
388                 t = isatty(STDOUT_FILENO) > 0;
389
390         return t;
391 }
392
393 static int generate_new_id128(void) {
394         sd_id128_t id;
395         int r;
396         unsigned i;
397
398         r = sd_id128_randomize(&id);
399         if (r < 0) {
400                 log_error("Failed to generate ID: %s", strerror(-r));
401                 return r;
402         }
403
404         printf("As string:\n"
405                SD_ID128_FORMAT_STR "\n\n"
406                "As UUID:\n"
407                "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
408                "As macro:\n"
409               "#define MESSAGE_XYZ SD_ID128_MAKE(",
410                SD_ID128_FORMAT_VAL(id),
411                SD_ID128_FORMAT_VAL(id));
412
413         for (i = 0; i < 16; i++)
414                 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
415
416         fputs(")\n", stdout);
417
418         return 0;
419 }
420
421 static int add_matches(sd_journal *j, char **args) {
422         char **i;
423         int r;
424
425         assert(j);
426
427         STRV_FOREACH(i, args) {
428
429                 if (streq(*i, "+"))
430                         r = sd_journal_add_disjunction(j);
431                 else if (path_is_absolute(*i)) {
432                         char *p, *t = NULL;
433                         const char *path;
434                         struct stat st;
435
436                         p = canonicalize_file_name(*i);
437                         path = p ? p : *i;
438
439                         if (stat(path, &st) < 0)  {
440                                 free(p);
441                                 log_error("Couldn't stat file: %m");
442                                 return -errno;
443                         }
444
445                         if (S_ISREG(st.st_mode) && (0111 & st.st_mode))
446                                 t = strappend("_EXE=", path);
447                         else if (S_ISCHR(st.st_mode))
448                                 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
449                         else if (S_ISBLK(st.st_mode))
450                                 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
451                         else {
452                                 free(p);
453                                 log_error("File is not a device node, regular file or is not executable: %s", *i);
454                                 return -EINVAL;
455                         }
456
457                         free(p);
458
459                         if (!t)
460                                 return log_oom();
461
462                         r = sd_journal_add_match(j, t, 0);
463                         free(t);
464                 } else
465                         r = sd_journal_add_match(j, *i, 0);
466
467                 if (r < 0) {
468                         log_error("Failed to add match '%s': %s", *i, strerror(-r));
469                         return r;
470                 }
471         }
472
473         return 0;
474 }
475
476 static int add_this_boot(sd_journal *j) {
477         char match[9+32+1] = "_BOOT_ID=";
478         sd_id128_t boot_id;
479         int r;
480
481         assert(j);
482
483         if (!arg_this_boot)
484                 return 0;
485
486         r = sd_id128_get_boot(&boot_id);
487         if (r < 0) {
488                 log_error("Failed to get boot id: %s", strerror(-r));
489                 return r;
490         }
491
492         sd_id128_to_string(boot_id, match + 9);
493         r = sd_journal_add_match(j, match, strlen(match));
494         if (r < 0) {
495                 log_error("Failed to add match: %s", strerror(-r));
496                 return r;
497         }
498
499         return 0;
500 }
501
502 static int add_priorities(sd_journal *j) {
503         char match[] = "PRIORITY=0";
504         int i, r;
505
506         assert(j);
507
508         if (arg_priorities == 0xFF)
509                 return 0;
510
511         for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
512                 if (arg_priorities & (1 << i)) {
513                         match[sizeof(match)-2] = '0' + i;
514
515                         log_info("adding match %s", match);
516
517                         r = sd_journal_add_match(j, match, strlen(match));
518                         if (r < 0) {
519                                 log_error("Failed to add match: %s", strerror(-r));
520                                 return r;
521                         }
522                 }
523
524         return 0;
525 }
526
527 static int setup_keys(void) {
528 #ifdef HAVE_GCRYPT
529         size_t mpk_size, seed_size, state_size, i;
530         uint8_t *mpk, *seed, *state;
531         ssize_t l;
532         int fd = -1, r, attr = 0;
533         sd_id128_t machine, boot;
534         char *p = NULL, *k = NULL;
535         struct FSSHeader h;
536         uint64_t n;
537
538         r = sd_id128_get_machine(&machine);
539         if (r < 0) {
540                 log_error("Failed to get machine ID: %s", strerror(-r));
541                 return r;
542         }
543
544         r = sd_id128_get_boot(&boot);
545         if (r < 0) {
546                 log_error("Failed to get boot ID: %s", strerror(-r));
547                 return r;
548         }
549
550         if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
551                      SD_ID128_FORMAT_VAL(machine)) < 0)
552                 return log_oom();
553
554         if (access(p, F_OK) >= 0) {
555                 log_error("Sealing key file %s exists already.", p);
556                 r = -EEXIST;
557                 goto finish;
558         }
559
560         if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
561                      SD_ID128_FORMAT_VAL(machine)) < 0) {
562                 r = log_oom();
563                 goto finish;
564         }
565
566         mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
567         mpk = alloca(mpk_size);
568
569         seed_size = FSPRG_RECOMMENDED_SEEDLEN;
570         seed = alloca(seed_size);
571
572         state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
573         state = alloca(state_size);
574
575         fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
576         if (fd < 0) {
577                 log_error("Failed to open /dev/random: %m");
578                 r = -errno;
579                 goto finish;
580         }
581
582         log_info("Generating seed...");
583         l = loop_read(fd, seed, seed_size, true);
584         if (l < 0 || (size_t) l != seed_size) {
585                 log_error("Failed to read random seed: %s", strerror(EIO));
586                 r = -EIO;
587                 goto finish;
588         }
589
590         log_info("Generating key pair...");
591         FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
592
593         log_info("Generating sealing key...");
594         FSPRG_GenState0(state, mpk, seed, seed_size);
595
596         assert(arg_interval > 0);
597
598         n = now(CLOCK_REALTIME);
599         n /= arg_interval;
600
601         close_nointr_nofail(fd);
602         fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
603         if (fd < 0) {
604                 log_error("Failed to open %s: %m", k);
605                 r = -errno;
606                 goto finish;
607         }
608
609         /* Enable secure remove, exclusion from dump, synchronous
610          * writing and in-place updating */
611         if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
612                 log_warning("FS_IOC_GETFLAGS failed: %m");
613
614         attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
615
616         if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
617                 log_warning("FS_IOC_SETFLAGS failed: %m");
618
619         zero(h);
620         memcpy(h.signature, "KSHHRHLP", 8);
621         h.machine_id = machine;
622         h.boot_id = boot;
623         h.header_size = htole64(sizeof(h));
624         h.start_usec = htole64(n * arg_interval);
625         h.interval_usec = htole64(arg_interval);
626         h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
627         h.fsprg_state_size = htole64(state_size);
628
629         l = loop_write(fd, &h, sizeof(h), false);
630         if (l < 0 || (size_t) l != sizeof(h)) {
631                 log_error("Failed to write header: %s", strerror(EIO));
632                 r = -EIO;
633                 goto finish;
634         }
635
636         l = loop_write(fd, state, state_size, false);
637         if (l < 0 || (size_t) l != state_size) {
638                 log_error("Failed to write state: %s", strerror(EIO));
639                 r = -EIO;
640                 goto finish;
641         }
642
643         if (link(k, p) < 0) {
644                 log_error("Failed to link file: %m");
645                 r = -errno;
646                 goto finish;
647         }
648
649         if (isatty(STDOUT_FILENO)) {
650                 fprintf(stderr,
651                         "\n"
652                         "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
653                         "the following local file. This key file is automatically updated when the\n"
654                         "sealing key is advanced. It should not be used on multiple hosts.\n"
655                         "\n"
656                         "\t%s\n"
657                         "\n"
658                         "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
659                         "at a safe location and should not be saved locally on disk.\n"
660                         "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
661                 fflush(stderr);
662         }
663         for (i = 0; i < seed_size; i++) {
664                 if (i > 0 && i % 3 == 0)
665                         putchar('-');
666                 printf("%02x", ((uint8_t*) seed)[i]);
667         }
668
669         printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
670
671         if (isatty(STDOUT_FILENO)) {
672                 char tsb[FORMAT_TIMESPAN_MAX], *hn;
673
674                 fprintf(stderr,
675                         ANSI_HIGHLIGHT_OFF "\n"
676                         "The sealing key is automatically changed every %s.\n",
677                         format_timespan(tsb, sizeof(tsb), arg_interval));
678
679                 hn = gethostname_malloc();
680
681                 if (hn) {
682                         hostname_cleanup(hn);
683                         fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
684                 } else
685                         fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
686
687 #ifdef HAVE_QRENCODE
688                 /* If this is not an UTF-8 system don't print any QR codes */
689                 setlocale(LC_CTYPE, "");
690
691                 if (streq_ptr(nl_langinfo(CODESET), "UTF-8")) {
692                         fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
693                         print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
694                 }
695 #endif
696                 free(hn);
697         }
698
699         r = 0;
700
701 finish:
702         if (fd >= 0)
703                 close_nointr_nofail(fd);
704
705         if (k) {
706                 unlink(k);
707                 free(k);
708         }
709
710         free(p);
711
712         return r;
713 #else
714         log_error("Forward-secure sealing not available.");
715         return -ENOTSUP;
716 #endif
717 }
718
719 static int verify(sd_journal *j) {
720         int r = 0;
721         Iterator i;
722         JournalFile *f;
723
724         assert(j);
725
726         log_show_color(true);
727
728         HASHMAP_FOREACH(f, j->files, i) {
729                 int k;
730                 usec_t first, validated, last;
731
732 #ifdef HAVE_GCRYPT
733                 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
734                         log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
735 #endif
736
737                 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
738                 if (k == -EINVAL) {
739                         /* If the key was invalid give up right-away. */
740                         return k;
741                 } else if (k < 0) {
742                         log_warning("FAIL: %s (%s)", f->path, strerror(-k));
743                         r = k;
744                 } else {
745                         char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
746                         log_info("PASS: %s", f->path);
747
748                         if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
749                                 if (validated > 0) {
750                                         log_info("=> Validated from %s to %s, final %s entries not sealed.",
751                                                  format_timestamp(a, sizeof(a), first),
752                                                  format_timestamp(b, sizeof(b), validated),
753                                                  format_timespan(c, sizeof(c), last > validated ? last - validated : 0));
754                                 } else if (last > 0)
755                                         log_info("=> No sealing yet, %s of entries not sealed.",
756                                                  format_timespan(c, sizeof(c), last - first));
757                                 else
758                                         log_info("=> No sealing yet, no entries in file.");
759                         }
760                 }
761         }
762
763         return r;
764 }
765
766 int main(int argc, char *argv[]) {
767         int r;
768         sd_journal *j = NULL;
769         bool need_seek = false;
770         sd_id128_t previous_boot_id;
771         bool previous_boot_id_valid = false;
772         bool have_pager;
773         unsigned n_shown = 0;
774
775         log_parse_environment();
776         log_open();
777
778         r = parse_argv(argc, argv);
779         if (r <= 0)
780                 goto finish;
781
782         if (arg_action == ACTION_NEW_ID128) {
783                 r = generate_new_id128();
784                 goto finish;
785         }
786
787         if (arg_action == ACTION_SETUP_KEYS) {
788                 r = setup_keys();
789                 goto finish;
790         }
791
792         if (arg_directory)
793                 r = sd_journal_open_directory(&j, arg_directory, 0);
794         else
795                 r = sd_journal_open(&j, arg_merge ? 0 : SD_JOURNAL_LOCAL_ONLY);
796
797         if (r < 0) {
798                 log_error("Failed to open journal: %s", strerror(-r));
799                 goto finish;
800         }
801
802         if (arg_action == ACTION_VERIFY) {
803                 r = verify(j);
804                 goto finish;
805         }
806
807         if (arg_action == ACTION_PRINT_HEADER) {
808                 journal_print_header(j);
809                 r = 0;
810                 goto finish;
811         }
812
813         if (arg_action == ACTION_DISK_USAGE) {
814                 uint64_t bytes;
815                 char sbytes[FORMAT_BYTES_MAX];
816
817                 r = sd_journal_get_usage(j, &bytes);
818                 if (r < 0)
819                         goto finish;
820
821                 printf("Journals take up %s on disk.\n", format_bytes(sbytes, sizeof(sbytes), bytes));
822                 r = 0;
823                 goto finish;
824         }
825
826 #ifdef HAVE_ACL
827         if (access("/var/log/journal", F_OK) < 0 && geteuid() != 0 && in_group("adm") <= 0) {
828                 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'adm' can always see messages.");
829                 r = -EACCES;
830                 goto finish;
831         }
832
833         if (!arg_quiet && geteuid() != 0 && in_group("adm") <= 0)
834                 log_warning("Showing user generated messages only. Users in the group 'adm' can see all messages. Pass -q to turn this notice off.");
835 #else
836         if (geteuid() != 0 && in_group("adm") <= 0) {
837                 log_error("No access to messages. Only users in the group 'adm' can see messages.");
838                 r = -EACCES;
839                 goto finish;
840         }
841 #endif
842
843         r = add_this_boot(j);
844         if (r < 0)
845                 goto finish;
846
847         r = add_matches(j, argv + optind);
848         if (r < 0)
849                 goto finish;
850
851         r = add_priorities(j);
852         if (r < 0)
853                 goto finish;
854
855         if (arg_cursor) {
856                 r = sd_journal_seek_cursor(j, arg_cursor);
857                 if (r < 0) {
858                         log_error("Failed to seek to cursor: %s", strerror(-r));
859                         goto finish;
860                 }
861
862                 r = sd_journal_next(j);
863
864         } else if (arg_since_set) {
865                 r = sd_journal_seek_realtime_usec(j, arg_since);
866                 if (r < 0) {
867                         log_error("Failed to seek to date: %s", strerror(-r));
868                         goto finish;
869                 }
870                 r = sd_journal_next(j);
871
872         } else if (arg_lines > 0) {
873                 r = sd_journal_seek_tail(j);
874                 if (r < 0) {
875                         log_error("Failed to seek to tail: %s", strerror(-r));
876                         goto finish;
877                 }
878
879                 r = sd_journal_previous_skip(j, arg_lines);
880
881         } else {
882                 r = sd_journal_seek_head(j);
883                 if (r < 0) {
884                         log_error("Failed to seek to head: %s", strerror(-r));
885                         goto finish;
886                 }
887
888                 r = sd_journal_next(j);
889         }
890
891         if (r < 0) {
892                 log_error("Failed to iterate through journal: %s", strerror(-r));
893                 goto finish;
894         }
895
896         on_tty();
897         have_pager = !arg_no_pager && !arg_follow && pager_open();
898
899         if (!arg_quiet) {
900                 usec_t start, end;
901                 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
902
903                 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
904                 if (r < 0) {
905                         log_error("Failed to get cutoff: %s", strerror(-r));
906                         goto finish;
907                 }
908
909                 if (r > 0) {
910                         if (arg_follow)
911                                 printf("---- Logs begin at %s.\n", format_timestamp(start_buf, sizeof(start_buf), start));
912                         else
913                                 printf("---- Logs begin at %s, end at %s.\n",
914                                        format_timestamp(start_buf, sizeof(start_buf), start),
915                                        format_timestamp(end_buf, sizeof(end_buf), end));
916                 }
917         }
918
919         for (;;) {
920                 while (arg_lines == 0 || arg_follow || n_shown < arg_lines) {
921                         int flags;
922
923                         if (need_seek) {
924                                 r = sd_journal_next(j);
925                                 if (r < 0) {
926                                         log_error("Failed to iterate through journal: %s", strerror(-r));
927                                         goto finish;
928                                 }
929                         }
930
931                         if (r == 0)
932                                 break;
933
934                         if (arg_until_set) {
935                                 usec_t usec;
936
937                                 r = sd_journal_get_realtime_usec(j, &usec);
938                                 if (r < 0) {
939                                         log_error("Failed to determine timestamp: %s", strerror(-r));
940                                         goto finish;
941                                 }
942                         }
943
944                         if (!arg_merge) {
945                                 sd_id128_t boot_id;
946
947                                 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
948                                 if (r >= 0) {
949                                         if (previous_boot_id_valid &&
950                                             !sd_id128_equal(boot_id, previous_boot_id))
951                                                 printf(ANSI_HIGHLIGHT_ON "---- Reboot ----" ANSI_HIGHLIGHT_OFF "\n");
952
953                                         previous_boot_id = boot_id;
954                                         previous_boot_id_valid = true;
955                                 }
956                         }
957
958                         flags =
959                                 arg_show_all * OUTPUT_SHOW_ALL |
960                                 have_pager * OUTPUT_FULL_WIDTH |
961                                 on_tty() * OUTPUT_COLOR;
962
963                         r = output_journal(stdout, j, arg_output, 0, flags);
964                         if (r < 0)
965                                 goto finish;
966
967                         need_seek = true;
968                         n_shown++;
969                 }
970
971                 if (!arg_follow)
972                         break;
973
974                 r = sd_journal_wait(j, (uint64_t) -1);
975                 if (r < 0) {
976                         log_error("Couldn't wait for journal event: %s", strerror(-r));
977                         goto finish;
978                 }
979         }
980
981 finish:
982         if (j)
983                 sd_journal_close(j);
984
985         pager_close();
986
987         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
988 }