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