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