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