]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/journal/journalctl.c
keymap: Add Asus WMI module
[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>
72f59706 30#include <time.h>
0d43c694 31#include <getopt.h>
585314e8 32#include <signal.h>
50940700 33#include <sys/stat.h>
f982e6f7
LP
34#include <sys/ioctl.h>
35#include <linux/fs.h>
87d2c1ff 36
4468addc
LP
37#ifdef HAVE_ACL
38#include <sys/acl.h>
478c8269 39#include "acl-util.h"
4468addc
LP
40#endif
41
81527be1
LP
42#include <systemd/sd-journal.h>
43
3fbf9cbb 44#include "log.h"
7199aa96 45#include "logs-show.h"
72f59706 46#include "util.h"
e5124088 47#include "path-util.h"
68fee104 48#include "fileio.h"
0d43c694
LP
49#include "build.h"
50#include "pager.h"
86aa7ba4 51#include "logs-show.h"
a963990f 52#include "strv.h"
dca6219e 53#include "journal-internal.h"
7560fffc 54#include "journal-def.h"
0284adc6 55#include "journal-verify.h"
4da416aa 56#include "journal-authenticate.h"
f6a971bc 57#include "journal-qrcode.h"
4da416aa 58#include "fsprg.h"
c3f60ec5 59#include "unit-name.h"
d4205751 60#include "catalog.h"
7560fffc 61
baed47c3 62#define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
250d54b5 63
df50185b 64static OutputMode arg_output = OUTPUT_SHORT;
1b12a7b5 65static bool arg_pager_end = false;
72f59706 66static bool arg_follow = false;
e3657ecd 67static bool arg_full = false;
cd4b13e0 68static bool arg_all = false;
0d43c694 69static bool arg_no_pager = false;
67e04a48 70static int arg_lines = -1;
e91af489 71static bool arg_no_tail = false;
43673799 72static bool arg_quiet = false;
9e8a535f 73static bool arg_merge = false;
d121b396
ZJS
74static bool arg_boot = false;
75static char *arg_boot_descriptor = NULL;
99271804 76static bool arg_dmesg = false;
8f14c832 77static const char *arg_cursor = NULL;
248fc619
ZJS
78static const char *arg_after_cursor = NULL;
79static bool arg_show_cursor = false;
a963990f 80static const char *arg_directory = NULL;
8d98da3f 81static char **arg_file = NULL;
941e990d 82static int arg_priorities = 0xFF;
baed47c3 83static const char *arg_verify_key = NULL;
feb12d3e 84#ifdef HAVE_GCRYPT
baed47c3 85static usec_t arg_interval = DEFAULT_FSS_INTERVAL_USEC;
b8547c10 86static bool arg_force = false;
feb12d3e 87#endif
cfbc22ab
LP
88static usec_t arg_since, arg_until;
89static bool arg_since_set = false, arg_until_set = false;
b9e40524
HH
90static char **arg_system_units = NULL;
91static char **arg_user_units = NULL;
3c1668da 92static const char *arg_field = NULL;
d4205751 93static bool arg_catalog = false;
d89d6c86 94static bool arg_reverse = false;
3f3a438f 95static int arg_journal_type = 0;
13cbf3a5 96static const char *arg_root = NULL;
50f20cfd 97
7560fffc
LP
98static enum {
99 ACTION_SHOW,
100 ACTION_NEW_ID128,
101 ACTION_PRINT_HEADER,
beec0085 102 ACTION_SETUP_KEYS,
a1a03e30
LP
103 ACTION_VERIFY,
104 ACTION_DISK_USAGE,
d4205751 105 ACTION_LIST_CATALOG,
54b7254c 106 ACTION_DUMP_CATALOG,
d4205751 107 ACTION_UPDATE_CATALOG
7560fffc
LP
108} arg_action = ACTION_SHOW;
109
a331b5e6
JJ
110typedef struct boot_id_t {
111 sd_id128_t id;
112 uint64_t timestamp;
113} boot_id_t;
114
0d43c694
LP
115static int help(void) {
116
cd4b13e0 117 printf("%s [OPTIONS...] [MATCHES...]\n\n"
15119c16
LP
118 "Query the journal.\n\n"
119 "Flags:\n"
248fc619
ZJS
120 " --system Show only the system journal\n"
121 " --user Show only the user journal for current user\n"
122 " --since=DATE Start showing entries newer or of the specified date\n"
123 " --until=DATE Stop showing entries older or of the specified date\n"
124 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
125 " --after-cursor=CURSOR Start showing entries from specified cursor\n"
126 " --show-cursor Print the cursor after all the entries\n"
127 " -b --boot[=ID] Show data only from ID or current boot if unspecified\n"
128 " -k --dmesg Show kernel message log from current boot\n"
129 " -u --unit=UNIT Show data only from the specified unit\n"
130 " --user-unit=UNIT Show data only from the specified user session unit\n"
131 " -p --priority=RANGE Show only messages within the specified priority range\n"
132 " -e --pager-end Immediately jump to end of the journal in the pager\n"
133 " -f --follow Follow journal\n"
134 " -n --lines[=INTEGER] Number of journal entries to show\n"
135 " --no-tail Show all lines, even in follow mode\n"
136 " -r --reverse Show the newest entries first\n"
f02d8367
ZJS
137 " -o --output=STRING Change journal output mode (short, short-iso,\n"
138 " short-precise, short-monotonic, verbose,\n"
139 " export, json, json-pretty, json-sse, cat)\n"
248fc619
ZJS
140 " -x --catalog Add message explanations where available\n"
141 " -l --full Do not ellipsize fields\n"
142 " -a --all Show all fields, including long and unprintable\n"
143 " -q --quiet Don't show privilege warning\n"
144 " --no-pager Do not pipe output into a pager\n"
145 " -m --merge Show entries from all available journals\n"
146 " -D --directory=PATH Show journal files from directory\n"
147 " --file=PATH Show journal file\n"
148 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
15119c16 149#ifdef HAVE_GCRYPT
248fc619
ZJS
150 " --interval=TIME Time interval for changing the FSS sealing key\n"
151 " --verify-key=KEY Specify FSS verification key\n"
152 " --force Force overriding new FSS key pair with --setup-keys\n"
15119c16
LP
153#endif
154 "\nCommands:\n"
248fc619
ZJS
155 " -h --help Show this help\n"
156 " --version Show package version\n"
157 " --new-id128 Generate a new 128 Bit ID\n"
158 " --header Show journal header information\n"
159 " --disk-usage Show total disk usage\n"
160 " -F --field=FIELD List all values a certain field takes\n"
161 " --list-catalog Show message IDs of all entries in the message catalog\n"
162 " --dump-catalog Show entries in the message catalog\n"
163 " --update-catalog Update the message catalog database\n"
feb12d3e 164#ifdef HAVE_GCRYPT
248fc619
ZJS
165 " --setup-keys Generate new FSS key pair\n"
166 " --verify Verify journal file consistency\n"
feb12d3e
LP
167#endif
168 , program_invocation_short_name);
0d43c694
LP
169
170 return 0;
171}
172
173static int parse_argv(int argc, char *argv[]) {
174
175 enum {
176 ARG_VERSION = 0x100,
e91af489 177 ARG_NO_PAGER,
55ee336c 178 ARG_NO_TAIL,
dca6219e 179 ARG_NEW_ID128,
3f3a438f
ZJS
180 ARG_USER,
181 ARG_SYSTEM,
13cbf3a5 182 ARG_ROOT,
7560fffc 183 ARG_HEADER,
beec0085 184 ARG_SETUP_KEYS,
8d98da3f 185 ARG_FILE,
baed47c3 186 ARG_INTERVAL,
4da416aa 187 ARG_VERIFY,
a1a03e30 188 ARG_VERIFY_KEY,
cfbc22ab
LP
189 ARG_DISK_USAGE,
190 ARG_SINCE,
d4205751 191 ARG_UNTIL,
248fc619
ZJS
192 ARG_AFTER_CURSOR,
193 ARG_SHOW_CURSOR,
ffa7cd15 194 ARG_USER_UNIT,
d4205751 195 ARG_LIST_CATALOG,
54b7254c 196 ARG_DUMP_CATALOG,
3f3a438f 197 ARG_UPDATE_CATALOG,
b8547c10 198 ARG_FORCE,
0d43c694
LP
199 };
200
201 static const struct option options[] = {
248fc619
ZJS
202 { "help", no_argument, NULL, 'h' },
203 { "version" , no_argument, NULL, ARG_VERSION },
204 { "no-pager", no_argument, NULL, ARG_NO_PAGER },
205 { "pager-end", no_argument, NULL, 'e' },
206 { "follow", no_argument, NULL, 'f' },
207 { "force", no_argument, NULL, ARG_FORCE },
208 { "output", required_argument, NULL, 'o' },
209 { "all", no_argument, NULL, 'a' },
210 { "full", no_argument, NULL, 'l' },
211 { "lines", optional_argument, NULL, 'n' },
212 { "no-tail", no_argument, NULL, ARG_NO_TAIL },
213 { "new-id128", no_argument, NULL, ARG_NEW_ID128 },
214 { "quiet", no_argument, NULL, 'q' },
215 { "merge", no_argument, NULL, 'm' },
216 { "boot", optional_argument, NULL, 'b' },
217 { "this-boot", optional_argument, NULL, 'b' }, /* deprecated */
218 { "dmesg", no_argument, NULL, 'k' },
219 { "system", no_argument, NULL, ARG_SYSTEM },
220 { "user", no_argument, NULL, ARG_USER },
221 { "directory", required_argument, NULL, 'D' },
222 { "file", required_argument, NULL, ARG_FILE },
223 { "root", required_argument, NULL, ARG_ROOT },
224 { "header", no_argument, NULL, ARG_HEADER },
225 { "priority", required_argument, NULL, 'p' },
226 { "setup-keys", no_argument, NULL, ARG_SETUP_KEYS },
227 { "interval", required_argument, NULL, ARG_INTERVAL },
228 { "verify", no_argument, NULL, ARG_VERIFY },
229 { "verify-key", required_argument, NULL, ARG_VERIFY_KEY },
230 { "disk-usage", no_argument, NULL, ARG_DISK_USAGE },
231 { "cursor", required_argument, NULL, 'c' },
232 { "after-cursor", required_argument, NULL, ARG_AFTER_CURSOR },
233 { "show-cursor", no_argument, NULL, ARG_SHOW_CURSOR },
234 { "since", required_argument, NULL, ARG_SINCE },
235 { "until", required_argument, NULL, ARG_UNTIL },
236 { "unit", required_argument, NULL, 'u' },
237 { "user-unit", required_argument, NULL, ARG_USER_UNIT },
238 { "field", required_argument, NULL, 'F' },
239 { "catalog", no_argument, NULL, 'x' },
240 { "list-catalog", no_argument, NULL, ARG_LIST_CATALOG },
241 { "dump-catalog", no_argument, NULL, ARG_DUMP_CATALOG },
242 { "update-catalog", no_argument, NULL, ARG_UPDATE_CATALOG },
243 { "reverse", no_argument, NULL, 'r' },
244 { NULL, 0, NULL, 0 }
0d43c694
LP
245 };
246
2100675e 247 int c, r;
0d43c694
LP
248
249 assert(argc >= 0);
250 assert(argv);
251
a331b5e6 252 while ((c = getopt_long(argc, argv, "hefo:aln::qmb::kD:p:c:u:F:xr", options, NULL)) >= 0) {
0d43c694
LP
253
254 switch (c) {
255
256 case 'h':
257 help();
258 return 0;
259
260 case ARG_VERSION:
261 puts(PACKAGE_STRING);
0d43c694
LP
262 puts(SYSTEMD_FEATURES);
263 return 0;
264
265 case ARG_NO_PAGER:
266 arg_no_pager = true;
267 break;
268
1b12a7b5
HH
269 case 'e':
270 arg_pager_end = true;
fe59e38b
LP
271
272 if (arg_lines < 0)
273 arg_lines = 1000;
274
1b12a7b5
HH
275 break;
276
0d43c694
LP
277 case 'f':
278 arg_follow = true;
279 break;
280
281 case 'o':
1705594f 282 arg_output = output_mode_from_string(optarg);
df50185b 283 if (arg_output < 0) {
edfb521a 284 log_error("Unknown output format '%s'.", optarg);
0d43c694
LP
285 return -EINVAL;
286 }
df50185b 287
edfb521a
ZJS
288 if (arg_output == OUTPUT_EXPORT ||
289 arg_output == OUTPUT_JSON ||
290 arg_output == OUTPUT_JSON_PRETTY ||
291 arg_output == OUTPUT_JSON_SSE ||
292 arg_output == OUTPUT_CAT)
293 arg_quiet = true;
294
0d43c694
LP
295 break;
296
98a6e132 297 case 'l':
e3657ecd
ZJS
298 arg_full = true;
299 break;
300
0d43c694 301 case 'a':
cd4b13e0 302 arg_all = true;
0d43c694
LP
303 break;
304
2100675e 305 case 'n':
1705594f 306 if (optarg) {
67e04a48
ZJS
307 r = safe_atoi(optarg, &arg_lines);
308 if (r < 0 || arg_lines < 0) {
1705594f
LP
309 log_error("Failed to parse lines '%s'", optarg);
310 return -EINVAL;
311 }
96088db0
LP
312 } else {
313 int n;
314
315 /* Hmm, no argument? Maybe the next
316 * word on the command line is
317 * supposed to be the argument? Let's
318 * see if there is one, and is
319 * parsable as a positive
320 * integer... */
321
322 if (optind < argc &&
323 safe_atoi(argv[optind], &n) >= 0 &&
324 n >= 0) {
325
326 arg_lines = n;
327 optind++;
328 } else
329 arg_lines = 10;
330 }
1705594f 331
2100675e
LP
332 break;
333
e91af489
LP
334 case ARG_NO_TAIL:
335 arg_no_tail = true;
336 break;
337
39f7f5c1 338 case ARG_NEW_ID128:
7560fffc 339 arg_action = ACTION_NEW_ID128;
55ee336c
LP
340 break;
341
43673799
LP
342 case 'q':
343 arg_quiet = true;
490e567d 344 break;
43673799 345
9e8a535f
LP
346 case 'm':
347 arg_merge = true;
2bd3c38a
LP
348 break;
349
59cea26a 350 case 'b':
d121b396
ZJS
351 arg_boot = true;
352
a331b5e6 353 if (optarg)
d121b396
ZJS
354 arg_boot_descriptor = optarg;
355 else if (optind < argc) {
356 int boot;
357
358 if (argv[optind][0] != '-' ||
359 safe_atoi(argv[optind], &boot) >= 0) {
360 arg_boot_descriptor = argv[optind];
361 optind++;
362 }
a331b5e6 363 }
d121b396 364
59cea26a
LP
365 break;
366
99271804 367 case 'k':
d121b396 368 arg_boot = arg_dmesg = true;
99271804
ZJS
369 break;
370
3f3a438f
ZJS
371 case ARG_SYSTEM:
372 arg_journal_type |= SD_JOURNAL_SYSTEM;
373 break;
374
375 case ARG_USER:
376 arg_journal_type |= SD_JOURNAL_CURRENT_USER;
377 break;
378
a963990f
LP
379 case 'D':
380 arg_directory = optarg;
381 break;
382
8d98da3f
ZJS
383 case ARG_FILE:
384 r = glob_extend(&arg_file, optarg);
385 if (r < 0) {
386 log_error("Failed to add paths: %s", strerror(-r));
387 return r;
388 };
389 break;
390
13cbf3a5
ZJS
391 case ARG_ROOT:
392 arg_root = optarg;
393 break;
394
8f14c832
LP
395 case 'c':
396 arg_cursor = optarg;
397 break;
398
248fc619
ZJS
399 case ARG_AFTER_CURSOR:
400 arg_after_cursor = optarg;
401 break;
402
403 case ARG_SHOW_CURSOR:
404 arg_show_cursor = true;
405 break;
406
dca6219e 407 case ARG_HEADER:
7560fffc
LP
408 arg_action = ACTION_PRINT_HEADER;
409 break;
410
feb12d3e
LP
411 case ARG_VERIFY:
412 arg_action = ACTION_VERIFY;
413 break;
414
a1a03e30
LP
415 case ARG_DISK_USAGE:
416 arg_action = ACTION_DISK_USAGE;
417 break;
418
feb12d3e 419#ifdef HAVE_GCRYPT
b8547c10
SL
420 case ARG_FORCE:
421 arg_force = true;
422 break;
423
7560fffc
LP
424 case ARG_SETUP_KEYS:
425 arg_action = ACTION_SETUP_KEYS;
dca6219e
LP
426 break;
427
beec0085 428
baed47c3 429 case ARG_VERIFY_KEY:
4da416aa 430 arg_action = ACTION_VERIFY;
baed47c3 431 arg_verify_key = optarg;
9e8a535f 432 arg_merge = false;
4da416aa
LP
433 break;
434
baed47c3 435 case ARG_INTERVAL:
7f602784 436 r = parse_sec(optarg, &arg_interval);
baed47c3
LP
437 if (r < 0 || arg_interval <= 0) {
438 log_error("Failed to parse sealing key change interval: %s", optarg);
14d10188
LP
439 return -EINVAL;
440 }
441 break;
feb12d3e
LP
442#else
443 case ARG_SETUP_KEYS:
444 case ARG_VERIFY_KEY:
445 case ARG_INTERVAL:
b8547c10 446 case ARG_FORCE:
feb12d3e
LP
447 log_error("Forward-secure sealing not available.");
448 return -ENOTSUP;
449#endif
14d10188 450
941e990d
LP
451 case 'p': {
452 const char *dots;
453
454 dots = strstr(optarg, "..");
455 if (dots) {
456 char *a;
457 int from, to, i;
458
459 /* a range */
460 a = strndup(optarg, dots - optarg);
461 if (!a)
462 return log_oom();
463
464 from = log_level_from_string(a);
465 to = log_level_from_string(dots + 2);
466 free(a);
467
468 if (from < 0 || to < 0) {
469 log_error("Failed to parse log level range %s", optarg);
470 return -EINVAL;
471 }
472
473 arg_priorities = 0;
474
475 if (from < to) {
476 for (i = from; i <= to; i++)
477 arg_priorities |= 1 << i;
478 } else {
479 for (i = to; i <= from; i++)
480 arg_priorities |= 1 << i;
481 }
482
483 } else {
484 int p, i;
485
486 p = log_level_from_string(optarg);
487 if (p < 0) {
488 log_error("Unknown log level %s", optarg);
489 return -EINVAL;
490 }
491
492 arg_priorities = 0;
493
494 for (i = 0; i <= p; i++)
495 arg_priorities |= 1 << i;
496 }
497
498 break;
499 }
500
cfbc22ab
LP
501 case ARG_SINCE:
502 r = parse_timestamp(optarg, &arg_since);
503 if (r < 0) {
504 log_error("Failed to parse timestamp: %s", optarg);
505 return -EINVAL;
506 }
507 arg_since_set = true;
508 break;
509
510 case ARG_UNTIL:
511 r = parse_timestamp(optarg, &arg_until);
512 if (r < 0) {
513 log_error("Failed to parse timestamp: %s", optarg);
514 return -EINVAL;
515 }
516 arg_until_set = true;
517 break;
518
7199aa96 519 case 'u':
b9e40524
HH
520 r = strv_extend(&arg_system_units, optarg);
521 if (r < 0)
522 return log_oom();
ffa7cd15
DW
523 break;
524
7199aa96 525 case ARG_USER_UNIT:
b9e40524
HH
526 r = strv_extend(&arg_user_units, optarg);
527 if (r < 0)
528 return log_oom();
c3f60ec5
LP
529 break;
530
0d43c694
LP
531 case '?':
532 return -EINVAL;
533
15119c16
LP
534 case 'F':
535 arg_field = optarg;
536 break;
537
d4205751
LP
538 case 'x':
539 arg_catalog = true;
540 break;
541
542 case ARG_LIST_CATALOG:
543 arg_action = ACTION_LIST_CATALOG;
544 break;
545
54b7254c
ZJS
546 case ARG_DUMP_CATALOG:
547 arg_action = ACTION_DUMP_CATALOG;
548 break;
549
d4205751
LP
550 case ARG_UPDATE_CATALOG:
551 arg_action = ACTION_UPDATE_CATALOG;
552 break;
553
d89d6c86
LN
554 case 'r':
555 arg_reverse = true;
556 break;
557
0d43c694
LP
558 default:
559 log_error("Unknown option code %c", c);
560 return -EINVAL;
561 }
562 }
563
67e04a48 564 if (arg_follow && !arg_no_tail && arg_lines < 0)
e91af489
LP
565 arg_lines = 10;
566
8d98da3f
ZJS
567 if (arg_directory && arg_file) {
568 log_error("Please specify either -D/--directory= or --file=, not both.");
569 return -EINVAL;
570 }
571
3ba09ee8 572 if (arg_since_set && arg_until_set && arg_since > arg_until) {
cfbc22ab
LP
573 log_error("--since= must be before --until=.");
574 return -EINVAL;
575 }
576
248fc619
ZJS
577 if (!!arg_cursor + !!arg_after_cursor + !!arg_since_set > 1) {
578 log_error("Please specify only one of --since=, --cursor=, and --after-cursor.");
cfbc22ab
LP
579 return -EINVAL;
580 }
581
d89d6c86
LN
582 if (arg_follow && arg_reverse) {
583 log_error("Please specify either --reverse= or --follow=, not both.");
584 return -EINVAL;
585 }
586
0d43c694
LP
587 return 1;
588}
589
39f7f5c1 590static int generate_new_id128(void) {
55ee336c
LP
591 sd_id128_t id;
592 int r;
593 unsigned i;
594
595 r = sd_id128_randomize(&id);
596 if (r < 0) {
597 log_error("Failed to generate ID: %s", strerror(-r));
598 return r;
599 }
600
601 printf("As string:\n"
602 SD_ID128_FORMAT_STR "\n\n"
603 "As UUID:\n"
604 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
605 "As macro:\n"
d489071f 606 "#define MESSAGE_XYZ SD_ID128_MAKE(",
55ee336c
LP
607 SD_ID128_FORMAT_VAL(id),
608 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
609 for (i = 0; i < 16; i++)
610 printf("%02x%s", id.bytes[i], i != 15 ? "," : "");
d489071f 611 fputs(")\n\n", stdout);
55ee336c 612
d489071f
ZJS
613 printf("As Python constant:\n"
614 ">>> import uuid\n"
615 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR "')\n",
616 SD_ID128_FORMAT_VAL(id));
55ee336c
LP
617
618 return 0;
619}
620
a963990f
LP
621static int add_matches(sd_journal *j, char **args) {
622 char **i;
59cea26a 623
a963990f 624 assert(j);
59cea26a 625
a963990f 626 STRV_FOREACH(i, args) {
52aeb63c 627 int r;
59cea26a 628
cbdca852
LP
629 if (streq(*i, "+"))
630 r = sd_journal_add_disjunction(j);
631 else if (path_is_absolute(*i)) {
68fee104 632 _cleanup_free_ char *p, *t = NULL, *t2 = NULL;
e5124088 633 const char *path;
68fee104 634 _cleanup_free_ char *interpreter = NULL;
a963990f 635 struct stat st;
e5124088 636
a963990f
LP
637 p = canonicalize_file_name(*i);
638 path = p ? p : *i;
e5124088
LP
639
640 if (stat(path, &st) < 0) {
e5124088 641 log_error("Couldn't stat file: %m");
a963990f 642 return -errno;
e5124088
LP
643 }
644
68fee104
ZJS
645 if (S_ISREG(st.st_mode) && (0111 & st.st_mode)) {
646 if (executable_is_script(path, &interpreter) > 0) {
647 _cleanup_free_ char *comm;
648
649 comm = strndup(path_get_file_name(path), 15);
650 if (!comm)
651 return log_oom();
652
653 t = strappend("_COMM=", comm);
654
655 /* Append _EXE only if the interpreter is not a link.
656 Otherwise it might be outdated often. */
657 if (lstat(interpreter, &st) == 0 &&
658 !S_ISLNK(st.st_mode)) {
659 t2 = strappend("_EXE=", interpreter);
660 if (!t2)
661 return log_oom();
662 }
663 } else
664 t = strappend("_EXE=", path);
665 } else if (S_ISCHR(st.st_mode))
b6a34514
LP
666 asprintf(&t, "_KERNEL_DEVICE=c%u:%u", major(st.st_rdev), minor(st.st_rdev));
667 else if (S_ISBLK(st.st_mode))
668 asprintf(&t, "_KERNEL_DEVICE=b%u:%u", major(st.st_rdev), minor(st.st_rdev));
669 else {
fb93cf73 670 log_error("File is neither a device node, nor regular file, nor executable: %s", *i);
a963990f 671 return -EINVAL;
50940700 672 }
e5124088 673
b6a34514
LP
674 if (!t)
675 return log_oom();
676
677 r = sd_journal_add_match(j, t, 0);
68fee104
ZJS
678 if (t2)
679 r = sd_journal_add_match(j, t2, 0);
e5124088 680 } else
cbdca852 681 r = sd_journal_add_match(j, *i, 0);
e5124088 682
de7b95cd 683 if (r < 0) {
cbdca852 684 log_error("Failed to add match '%s': %s", *i, strerror(-r));
a963990f 685 return r;
de7b95cd
LP
686 }
687 }
688
a963990f
LP
689 return 0;
690}
691
a331b5e6
JJ
692static int boot_id_cmp(const void *a, const void *b) {
693 uint64_t _a, _b;
694
695 _a = ((const boot_id_t *)a)->timestamp;
696 _b = ((const boot_id_t *)b)->timestamp;
697
698 return _a < _b ? -1 : (_a > _b ? 1 : 0);
699}
700
701static int get_relative_boot_id(sd_journal *j, sd_id128_t *boot_id, int relative) {
702 int r;
703 const void *data;
d121b396 704 unsigned int count = 0;
a331b5e6 705 size_t length, allocated = 0;
d121b396 706 boot_id_t ref_boot_id = {SD_ID128_NULL}, *id;
a331b5e6 707 _cleanup_free_ boot_id_t *all_ids = NULL;
a331b5e6
JJ
708
709 assert(j);
710 assert(boot_id);
711
d121b396 712 if (relative == 0 && !sd_id128_equal(*boot_id, SD_ID128_NULL))
a331b5e6
JJ
713 return 0;
714
a331b5e6
JJ
715 r = sd_journal_query_unique(j, "_BOOT_ID");
716 if (r < 0)
717 return r;
718
719 SD_JOURNAL_FOREACH_UNIQUE(j, data, length) {
720 if (length < strlen("_BOOT_ID="))
721 continue;
722
d121b396 723 if (!GREEDY_REALLOC(all_ids, allocated, count + 1))
a331b5e6
JJ
724 return log_oom();
725
d121b396 726 id = &all_ids[count];
a331b5e6
JJ
727
728 r = sd_id128_from_string(((const char *)data) + strlen("_BOOT_ID="), &id->id);
d121b396 729 if (r < 0)
a331b5e6 730 continue;
a331b5e6 731
a331b5e6
JJ
732 r = sd_journal_add_match(j, data, length);
733 if (r < 0)
d121b396 734 return r;
a331b5e6
JJ
735
736 r = sd_journal_seek_head(j);
737 if (r < 0)
d121b396 738 return r;
a331b5e6
JJ
739
740 r = sd_journal_next(j);
d121b396
ZJS
741 if (r < 0)
742 return r;
743 else if (r == 0)
744 goto flush;
a331b5e6
JJ
745
746 r = sd_journal_get_realtime_usec(j, &id->timestamp);
747 if (r < 0)
d121b396 748 return r;
a331b5e6 749
d121b396 750 if (sd_id128_equal(id->id, *boot_id))
a331b5e6 751 ref_boot_id = *id;
a331b5e6 752
d121b396
ZJS
753 count++;
754 flush:
755 sd_journal_flush_matches(j);
a331b5e6
JJ
756 }
757
d121b396 758 qsort(all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 759
d121b396
ZJS
760 if (sd_id128_equal(*boot_id, SD_ID128_NULL)) {
761 if (relative > (int) count || relative <= -(int)count)
762 return -EADDRNOTAVAIL;
a331b5e6 763
d121b396
ZJS
764 *boot_id = all_ids[(relative <= 0)*count + relative - 1].id;
765 } else {
766 id = bsearch(&ref_boot_id, all_ids, count, sizeof(boot_id_t), boot_id_cmp);
a331b5e6 767
d121b396
ZJS
768 if (!id ||
769 relative <= 0 ? (id - all_ids) + relative < 0 :
a54e3b3d 770 (id - all_ids) + relative >= (int) count)
d121b396
ZJS
771 return -EADDRNOTAVAIL;
772
773 *boot_id = (id + relative)->id;
774 }
a963990f 775
a331b5e6
JJ
776 return 0;
777}
778
779static int add_boot(sd_journal *j) {
780 char match[9+32+1] = "_BOOT_ID=";
d121b396
ZJS
781 char *offset;
782 sd_id128_t boot_id = SD_ID128_NULL;
a331b5e6
JJ
783 int r, relative = 0;
784
785 assert(j);
786
d121b396 787 if (!arg_boot)
a331b5e6
JJ
788 return 0;
789
d121b396
ZJS
790 if (!arg_boot_descriptor)
791 return add_match_this_boot(j);
a331b5e6 792
d121b396
ZJS
793 if (strlen(arg_boot_descriptor) >= 32) {
794 char tmp = arg_boot_descriptor[32];
795 arg_boot_descriptor[32] = '\0';
796 r = sd_id128_from_string(arg_boot_descriptor, &boot_id);
797 arg_boot_descriptor[32] = tmp;
798
799 if (r < 0) {
800 log_error("Failed to parse boot ID '%.32s': %s",
801 arg_boot_descriptor, strerror(-r));
802 return r;
a331b5e6 803 }
a331b5e6 804
d121b396
ZJS
805 offset = arg_boot_descriptor + 32;
806
a54e3b3d 807 if (*offset && *offset != '-' && *offset != '+') {
d121b396
ZJS
808 log_error("Relative boot ID offset must start with a '+' or a '-', found '%s' ", offset);
809 return -EINVAL;
a331b5e6 810 }
d121b396
ZJS
811 } else
812 offset = arg_boot_descriptor;
813
814 if (*offset) {
815 r = safe_atoi(offset, &relative);
a331b5e6 816 if (r < 0) {
d121b396
ZJS
817 log_error("Failed to parse relative boot ID number '%s'", offset);
818 return -EINVAL;
a331b5e6
JJ
819 }
820 }
821
822 r = get_relative_boot_id(j, &boot_id, relative);
823 if (r < 0) {
d121b396
ZJS
824 if (sd_id128_equal(boot_id, SD_ID128_NULL))
825 log_error("Failed to look up boot %+d: %s", relative, strerror(-r));
826 else
827 log_error("Failed to look up boot ID "SD_ID128_FORMAT_STR"%+d: %s",
828 SD_ID128_FORMAT_VAL(boot_id), relative, strerror(-r));
a331b5e6 829 return r;
a331b5e6
JJ
830 }
831
832 sd_id128_to_string(boot_id, match + 9);
d121b396
ZJS
833
834 r = sd_journal_add_match(j, match, sizeof(match) - 1);
a331b5e6
JJ
835 if (r < 0) {
836 log_error("Failed to add match: %s", strerror(-r));
837 return r;
838 }
839
840 r = sd_journal_add_conjunction(j);
841 if (r < 0)
842 return r;
843
844 return 0;
a963990f
LP
845}
846
99271804
ZJS
847static int add_dmesg(sd_journal *j) {
848 int r;
849 assert(j);
850
851 if (!arg_dmesg)
852 return 0;
853
854 r = sd_journal_add_match(j, "_TRANSPORT=kernel", strlen("_TRANSPORT=kernel"));
855 if (r < 0) {
856 log_error("Failed to add match: %s", strerror(-r));
857 return r;
858 }
859
860 r = sd_journal_add_conjunction(j);
861 if (r < 0)
862 return r;
863
864 return 0;
865}
866
b9e40524 867static int add_units(sd_journal *j) {
4750fade 868 _cleanup_free_ char *u = NULL;
c3f60ec5 869 int r;
b9e40524 870 char **i;
c3f60ec5
LP
871
872 assert(j);
873
b9e40524
HH
874 STRV_FOREACH(i, arg_system_units) {
875 u = unit_name_mangle(*i);
876 if (!u)
877 return log_oom();
878 r = add_matches_for_unit(j, u);
879 if (r < 0)
880 return r;
881 r = sd_journal_add_disjunction(j);
882 if (r < 0)
883 return r;
884 }
c3f60ec5 885
b9e40524
HH
886 STRV_FOREACH(i, arg_user_units) {
887 u = unit_name_mangle(*i);
888 if (!u)
889 return log_oom();
c3f60ec5 890
7199aa96 891 r = add_matches_for_user_unit(j, u, getuid());
b9e40524
HH
892 if (r < 0)
893 return r;
894
895 r = sd_journal_add_disjunction(j);
896 if (r < 0)
897 return r;
898
899 }
c3f60ec5 900
cd34b3c6
HH
901 r = sd_journal_add_conjunction(j);
902 if (r < 0)
903 return r;
904
c3f60ec5
LP
905 return 0;
906}
907
941e990d
LP
908static int add_priorities(sd_journal *j) {
909 char match[] = "PRIORITY=0";
910 int i, r;
941e990d
LP
911 assert(j);
912
913 if (arg_priorities == 0xFF)
914 return 0;
915
916 for (i = LOG_EMERG; i <= LOG_DEBUG; i++)
917 if (arg_priorities & (1 << i)) {
918 match[sizeof(match)-2] = '0' + i;
919
941e990d
LP
920 r = sd_journal_add_match(j, match, strlen(match));
921 if (r < 0) {
922 log_error("Failed to add match: %s", strerror(-r));
923 return r;
924 }
925 }
926
cd34b3c6
HH
927 r = sd_journal_add_conjunction(j);
928 if (r < 0)
929 return r;
930
941e990d
LP
931 return 0;
932}
933
7560fffc
LP
934static int setup_keys(void) {
935#ifdef HAVE_GCRYPT
936 size_t mpk_size, seed_size, state_size, i;
937 uint8_t *mpk, *seed, *state;
938 ssize_t l;
f982e6f7 939 int fd = -1, r, attr = 0;
7560fffc
LP
940 sd_id128_t machine, boot;
941 char *p = NULL, *k = NULL;
baed47c3 942 struct FSSHeader h;
14d10188 943 uint64_t n;
b98e3866
SL
944 struct stat st;
945
946 r = stat("/var/log/journal", &st);
947 if (r < 0 && errno != ENOENT && errno != ENOTDIR) {
948 log_error("stat(\"%s\") failed: %m", "/var/log/journal");
949 return -errno;
950 }
951
952 if (r < 0 || !S_ISDIR(st.st_mode)) {
953 log_error("%s is not a directory, must be using persistent logging for FSS.",
954 "/var/log/journal");
955 return r < 0 ? -errno : -ENOTDIR;
956 }
7560fffc
LP
957
958 r = sd_id128_get_machine(&machine);
959 if (r < 0) {
960 log_error("Failed to get machine ID: %s", strerror(-r));
961 return r;
962 }
963
964 r = sd_id128_get_boot(&boot);
965 if (r < 0) {
966 log_error("Failed to get boot ID: %s", strerror(-r));
967 return r;
968 }
969
baed47c3 970 if (asprintf(&p, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss",
7560fffc
LP
971 SD_ID128_FORMAT_VAL(machine)) < 0)
972 return log_oom();
973
974 if (access(p, F_OK) >= 0) {
b8547c10
SL
975 if (arg_force) {
976 r = unlink(p);
977 if (r < 0) {
978 log_error("unlink(\"%s\") failed: %m", p);
979 r = -errno;
980 goto finish;
981 }
982 } else {
983 log_error("Sealing key file %s exists already. (--force to recreate)", p);
984 r = -EEXIST;
985 goto finish;
986 }
7560fffc
LP
987 }
988
baed47c3 989 if (asprintf(&k, "/var/log/journal/" SD_ID128_FORMAT_STR "/fss.tmp.XXXXXX",
7560fffc
LP
990 SD_ID128_FORMAT_VAL(machine)) < 0) {
991 r = log_oom();
992 goto finish;
993 }
994
995 mpk_size = FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR);
996 mpk = alloca(mpk_size);
997
998 seed_size = FSPRG_RECOMMENDED_SEEDLEN;
999 seed = alloca(seed_size);
1000
1001 state_size = FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR);
1002 state = alloca(state_size);
1003
1004 fd = open("/dev/random", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1005 if (fd < 0) {
1006 log_error("Failed to open /dev/random: %m");
1007 r = -errno;
1008 goto finish;
1009 }
1010
1011 log_info("Generating seed...");
1012 l = loop_read(fd, seed, seed_size, true);
1013 if (l < 0 || (size_t) l != seed_size) {
1014 log_error("Failed to read random seed: %s", strerror(EIO));
1015 r = -EIO;
1016 goto finish;
1017 }
1018
1019 log_info("Generating key pair...");
1020 FSPRG_GenMK(NULL, mpk, seed, seed_size, FSPRG_RECOMMENDED_SECPAR);
1021
baed47c3 1022 log_info("Generating sealing key...");
7560fffc
LP
1023 FSPRG_GenState0(state, mpk, seed, seed_size);
1024
baed47c3
LP
1025 assert(arg_interval > 0);
1026
7560fffc 1027 n = now(CLOCK_REALTIME);
baed47c3 1028 n /= arg_interval;
7560fffc
LP
1029
1030 close_nointr_nofail(fd);
1031 fd = mkostemp(k, O_WRONLY|O_CLOEXEC|O_NOCTTY);
1032 if (fd < 0) {
1033 log_error("Failed to open %s: %m", k);
1034 r = -errno;
1035 goto finish;
1036 }
1037
f982e6f7
LP
1038 /* Enable secure remove, exclusion from dump, synchronous
1039 * writing and in-place updating */
1040 if (ioctl(fd, FS_IOC_GETFLAGS, &attr) < 0)
1041 log_warning("FS_IOC_GETFLAGS failed: %m");
1042
1043 attr |= FS_SECRM_FL|FS_NODUMP_FL|FS_SYNC_FL|FS_NOCOW_FL;
1044
1045 if (ioctl(fd, FS_IOC_SETFLAGS, &attr) < 0)
1046 log_warning("FS_IOC_SETFLAGS failed: %m");
1047
7560fffc
LP
1048 zero(h);
1049 memcpy(h.signature, "KSHHRHLP", 8);
1050 h.machine_id = machine;
1051 h.boot_id = boot;
1052 h.header_size = htole64(sizeof(h));
baed47c3
LP
1053 h.start_usec = htole64(n * arg_interval);
1054 h.interval_usec = htole64(arg_interval);
1055 h.fsprg_secpar = htole16(FSPRG_RECOMMENDED_SECPAR);
1056 h.fsprg_state_size = htole64(state_size);
7560fffc
LP
1057
1058 l = loop_write(fd, &h, sizeof(h), false);
1059 if (l < 0 || (size_t) l != sizeof(h)) {
1060 log_error("Failed to write header: %s", strerror(EIO));
1061 r = -EIO;
1062 goto finish;
1063 }
1064
1065 l = loop_write(fd, state, state_size, false);
1066 if (l < 0 || (size_t) l != state_size) {
1067 log_error("Failed to write state: %s", strerror(EIO));
1068 r = -EIO;
1069 goto finish;
1070 }
1071
1072 if (link(k, p) < 0) {
1073 log_error("Failed to link file: %m");
1074 r = -errno;
1075 goto finish;
1076 }
1077
8481248b 1078 if (on_tty()) {
7560fffc
LP
1079 fprintf(stderr,
1080 "\n"
baed47c3 1081 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON "secret sealing key" ANSI_HIGHLIGHT_OFF " has been written to\n"
c05276f2
LP
1082 "the following local file. This key file is automatically updated when the\n"
1083 "sealing key is advanced. It should not be used on multiple hosts.\n"
7560fffc
LP
1084 "\n"
1085 "\t%s\n"
1086 "\n"
baed47c3
LP
1087 "Please write down the following " ANSI_HIGHLIGHT_ON "secret verification key" ANSI_HIGHLIGHT_OFF ". It should be stored\n"
1088 "at a safe location and should not be saved locally on disk.\n"
7560fffc
LP
1089 "\n\t" ANSI_HIGHLIGHT_RED_ON, p);
1090 fflush(stderr);
1091 }
1092 for (i = 0; i < seed_size; i++) {
1093 if (i > 0 && i % 3 == 0)
1094 putchar('-');
1095 printf("%02x", ((uint8_t*) seed)[i]);
1096 }
1097
baed47c3
LP
1098 printf("/%llx-%llx\n", (unsigned long long) n, (unsigned long long) arg_interval);
1099
8481248b 1100 if (on_tty()) {
f6a971bc 1101 char tsb[FORMAT_TIMESPAN_MAX], *hn;
7560fffc 1102
baed47c3
LP
1103 fprintf(stderr,
1104 ANSI_HIGHLIGHT_OFF "\n"
1105 "The sealing key is automatically changed every %s.\n",
2fa4092c 1106 format_timespan(tsb, sizeof(tsb), arg_interval, 0));
f6a971bc
LP
1107
1108 hn = gethostname_malloc();
1109
1110 if (hn) {
e724b063 1111 hostname_cleanup(hn, false);
adac1c93 1112 fprintf(stderr, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR ".\n", hn, SD_ID128_FORMAT_VAL(machine));
f6a971bc 1113 } else
adac1c93 1114 fprintf(stderr, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR ".\n", SD_ID128_FORMAT_VAL(machine));
f6a971bc
LP
1115
1116#ifdef HAVE_QRENCODE
cf5a3432 1117 /* If this is not an UTF-8 system don't print any QR codes */
09017585 1118 if (is_locale_utf8()) {
cf5a3432
LP
1119 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr);
1120 print_qr_code(stderr, seed, seed_size, n, arg_interval, hn, machine);
1121 }
f6a971bc
LP
1122#endif
1123 free(hn);
baed47c3 1124 }
7560fffc
LP
1125
1126 r = 0;
1127
1128finish:
1129 if (fd >= 0)
1130 close_nointr_nofail(fd);
1131
1132 if (k) {
1133 unlink(k);
1134 free(k);
1135 }
1136
1137 free(p);
1138
1139 return r;
1140#else
feb12d3e
LP
1141 log_error("Forward-secure sealing not available.");
1142 return -ENOTSUP;
7560fffc
LP
1143#endif
1144}
1145
beec0085
LP
1146static int verify(sd_journal *j) {
1147 int r = 0;
1148 Iterator i;
1149 JournalFile *f;
1150
1151 assert(j);
1152
cedb42bb
LP
1153 log_show_color(true);
1154
beec0085
LP
1155 HASHMAP_FOREACH(f, j->files, i) {
1156 int k;
2a7b539a 1157 usec_t first, validated, last;
beec0085 1158
56e81f7c 1159#ifdef HAVE_GCRYPT
feb12d3e 1160 if (!arg_verify_key && JOURNAL_HEADER_SEALED(f->header))
cedb42bb 1161 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f->path);
56e81f7c 1162#endif
4da416aa 1163
2a7b539a 1164 k = journal_file_verify(f, arg_verify_key, &first, &validated, &last, true);
56e81f7c 1165 if (k == -EINVAL) {
baed47c3 1166 /* If the key was invalid give up right-away. */
56e81f7c
LP
1167 return k;
1168 } else if (k < 0) {
beec0085 1169 log_warning("FAIL: %s (%s)", f->path, strerror(-k));
56e81f7c 1170 r = k;
6c7be122
LP
1171 } else {
1172 char a[FORMAT_TIMESTAMP_MAX], b[FORMAT_TIMESTAMP_MAX], c[FORMAT_TIMESPAN_MAX];
beec0085 1173 log_info("PASS: %s", f->path);
6c7be122 1174
c0ca7aee 1175 if (arg_verify_key && JOURNAL_HEADER_SEALED(f->header)) {
2a7b539a 1176 if (validated > 0) {
c0ca7aee 1177 log_info("=> Validated from %s to %s, final %s entries not sealed.",
2a7b539a
LP
1178 format_timestamp(a, sizeof(a), first),
1179 format_timestamp(b, sizeof(b), validated),
2fa4092c 1180 format_timespan(c, sizeof(c), last > validated ? last - validated : 0, 0));
2a7b539a 1181 } else if (last > 0)
c0ca7aee 1182 log_info("=> No sealing yet, %s of entries not sealed.",
2fa4092c 1183 format_timespan(c, sizeof(c), last - first, 0));
c0ca7aee
LP
1184 else
1185 log_info("=> No sealing yet, no entries in file.");
1186 }
6c7be122 1187 }
beec0085
LP
1188 }
1189
1190 return r;
1191}
1192
15804ceb 1193#ifdef HAVE_ACL
6fe391c5
ZJS
1194static int access_check_var_log_journal(sd_journal *j) {
1195 _cleanup_strv_free_ char **g = NULL;
1196 bool have_access;
1197 int r;
1198
1199 assert(j);
1200
1201 have_access = in_group("systemd-journal") > 0;
1202
1203 if (!have_access) {
1204 /* Let's enumerate all groups from the default ACL of
1205 * the directory, which generally should allow access
1206 * to most journal files too */
1207 r = search_acl_groups(&g, "/var/log/journal/", &have_access);
1208 if (r < 0)
1209 return r;
15804ceb
LP
1210 }
1211
6fe391c5 1212 if (!have_access) {
4468addc 1213
6fe391c5 1214 if (strv_isempty(g))
3ac251b8
LP
1215 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
1216 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
1217 " turn off this notice.");
6fe391c5
ZJS
1218 else {
1219 _cleanup_free_ char *s = NULL;
4468addc 1220
6fe391c5 1221 r = strv_extend(&g, "systemd-journal");
478c8269 1222 if (r < 0)
6fe391c5
ZJS
1223 return log_oom();
1224
1225 strv_sort(g);
1226 strv_uniq(g);
1227
1228 s = strv_join(g, "', '");
1229 if (!s)
1230 return log_oom();
1231
1232 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
3ac251b8
LP
1233 " Users in the groups '%s' can see all messages.\n"
1234 " Pass -q to turn off this notice.", s);
4468addc 1235 }
6fe391c5 1236 }
4468addc 1237
6fe391c5
ZJS
1238 return 0;
1239}
1240#endif
4468addc 1241
6fe391c5 1242static int access_check(sd_journal *j) {
6fe391c5 1243 Iterator it;
3ac251b8 1244 void *code;
6fe391c5 1245 int r = 0;
4468addc 1246
6fe391c5 1247 assert(j);
4468addc 1248
6fe391c5
ZJS
1249 if (set_isempty(j->errors)) {
1250 if (hashmap_isempty(j->files))
3ac251b8 1251 log_notice("No journal files were found.");
6fe391c5
ZJS
1252 return 0;
1253 }
4468addc 1254
3ac251b8 1255 if (set_contains(j->errors, INT_TO_PTR(-EACCES))) {
6fe391c5
ZJS
1256#ifdef HAVE_ACL
1257 /* If /var/log/journal doesn't even exist,
3ac251b8 1258 * unprivileged users have no access at all */
6fe391c5
ZJS
1259 if (access("/var/log/journal", F_OK) < 0 &&
1260 geteuid() != 0 &&
1261 in_group("systemd-journal") <= 0) {
3ac251b8
LP
1262 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
1263 "enabled. Users in the 'systemd-journal' group may always access messages.");
6fe391c5
ZJS
1264 return -EACCES;
1265 }
4468addc 1266
6fe391c5
ZJS
1267 /* If /var/log/journal exists, try to pring a nice
1268 notice if the user lacks access to it */
1269 if (!arg_quiet && geteuid() != 0) {
1270 r = access_check_var_log_journal(j);
1271 if (r < 0)
1272 return r;
4468addc 1273 }
15804ceb 1274#else
3ac251b8
LP
1275 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
1276 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
1277 "group may access messages.");
1278 return -EACCES;
1279 }
15804ceb 1280#endif
3ac251b8 1281
6fe391c5 1282 if (hashmap_isempty(j->files)) {
3ac251b8 1283 log_error("No journal files were opened due to insufficient permissions.");
6fe391c5
ZJS
1284 r = -EACCES;
1285 }
1286 }
15804ceb 1287
6fe391c5 1288 SET_FOREACH(code, j->errors, it) {
3ac251b8
LP
1289 int err;
1290
1291 err = -PTR_TO_INT(code);
6fe391c5 1292 assert(err > 0);
3ac251b8 1293
6fe391c5
ZJS
1294 if (err != EACCES)
1295 log_warning("Error was encountered while opening journal files: %s",
1296 strerror(err));
1297 }
1298
6fe391c5 1299 return r;
15804ceb
LP
1300}
1301
a963990f
LP
1302int main(int argc, char *argv[]) {
1303 int r;
7fd1b19b 1304 _cleanup_journal_close_ sd_journal*j = NULL;
a963990f 1305 bool need_seek = false;
14a65d65 1306 sd_id128_t previous_boot_id;
67e04a48
ZJS
1307 bool previous_boot_id_valid = false, first_line = true;
1308 int n_shown = 0;
94e0bd7d 1309 bool ellipsized = false;
a963990f 1310
a9cdc94f 1311 setlocale(LC_ALL, "");
a963990f
LP
1312 log_parse_environment();
1313 log_open();
1314
1315 r = parse_argv(argc, argv);
1316 if (r <= 0)
1317 goto finish;
1318
ed757c0c
LP
1319 signal(SIGWINCH, columns_lines_cache_reset);
1320
7560fffc 1321 if (arg_action == ACTION_NEW_ID128) {
a963990f
LP
1322 r = generate_new_id128();
1323 goto finish;
1324 }
1325
7560fffc
LP
1326 if (arg_action == ACTION_SETUP_KEYS) {
1327 r = setup_keys();
1328 goto finish;
1329 }
1330
844ec79b
ZJS
1331 if (arg_action == ACTION_UPDATE_CATALOG ||
1332 arg_action == ACTION_LIST_CATALOG ||
1333 arg_action == ACTION_DUMP_CATALOG) {
1334
0db80948 1335 const char* database = CATALOG_DATABASE;
7fd1b19b 1336 _cleanup_free_ char *copy = NULL;
0db80948
ZJS
1337 if (arg_root) {
1338 copy = strjoin(arg_root, "/", CATALOG_DATABASE, NULL);
3a819b1b 1339 if (!copy) {
0db80948
ZJS
1340 r = log_oom();
1341 goto finish;
1342 }
1343 path_kill_slashes(copy);
1344 database = copy;
13cbf3a5
ZJS
1345 }
1346
844ec79b 1347 if (arg_action == ACTION_UPDATE_CATALOG) {
13cbf3a5 1348 r = catalog_update(database, arg_root, catalog_file_dirs);
844ec79b
ZJS
1349 if (r < 0)
1350 log_error("Failed to list catalog: %s", strerror(-r));
1351 } else {
1352 bool oneline = arg_action == ACTION_LIST_CATALOG;
1353
1354 if (optind < argc)
13cbf3a5 1355 r = catalog_list_items(stdout, database,
844ec79b
ZJS
1356 oneline, argv + optind);
1357 else
13cbf3a5 1358 r = catalog_list(stdout, database, oneline);
844ec79b
ZJS
1359 if (r < 0)
1360 log_error("Failed to list catalog: %s", strerror(-r));
1361 }
d4205751 1362
d4205751
LP
1363 goto finish;
1364 }
1365
a963990f 1366 if (arg_directory)
3f3a438f 1367 r = sd_journal_open_directory(&j, arg_directory, arg_journal_type);
8d98da3f
ZJS
1368 else if (arg_file)
1369 r = sd_journal_open_files(&j, (const char**) arg_file, 0);
a963990f 1370 else
3f3a438f 1371 r = sd_journal_open(&j, !arg_merge*SD_JOURNAL_LOCAL_ONLY + arg_journal_type);
a963990f 1372 if (r < 0) {
8d98da3f
ZJS
1373 log_error("Failed to open %s: %s",
1374 arg_directory ? arg_directory : arg_file ? "files" : "journal",
1375 strerror(-r));
763c7aa2 1376 return EXIT_FAILURE;
a963990f
LP
1377 }
1378
6fe391c5
ZJS
1379 r = access_check(j);
1380 if (r < 0)
1381 return EXIT_FAILURE;
1382
beec0085
LP
1383 if (arg_action == ACTION_VERIFY) {
1384 r = verify(j);
1385 goto finish;
1386 }
1387
7560fffc 1388 if (arg_action == ACTION_PRINT_HEADER) {
dca6219e 1389 journal_print_header(j);
763c7aa2 1390 return EXIT_SUCCESS;
dca6219e
LP
1391 }
1392
a1a03e30
LP
1393 if (arg_action == ACTION_DISK_USAGE) {
1394 uint64_t bytes;
1395 char sbytes[FORMAT_BYTES_MAX];
1396
1397 r = sd_journal_get_usage(j, &bytes);
1398 if (r < 0)
763c7aa2 1399 return EXIT_FAILURE;
a1a03e30 1400
763c7aa2
ZJS
1401 printf("Journals take up %s on disk.\n",
1402 format_bytes(sbytes, sizeof(sbytes), bytes));
1403 return EXIT_SUCCESS;
a1a03e30
LP
1404 }
1405
a331b5e6
JJ
1406 /* add_boot() must be called first!
1407 * It may need to seek the journal to find parent boot IDs. */
1408 r = add_boot(j);
a963990f 1409 if (r < 0)
763c7aa2 1410 return EXIT_FAILURE;
a963990f 1411
99271804
ZJS
1412 r = add_dmesg(j);
1413 if (r < 0)
1414 return EXIT_FAILURE;
1415
b9e40524
HH
1416 r = add_units(j);
1417 strv_free(arg_system_units);
1418 strv_free(arg_user_units);
1419
c3f60ec5 1420 if (r < 0)
763c7aa2 1421 return EXIT_FAILURE;
c3f60ec5 1422
cd34b3c6 1423 r = add_priorities(j);
a963990f 1424 if (r < 0)
763c7aa2 1425 return EXIT_FAILURE;
a963990f 1426
cd34b3c6 1427 r = add_matches(j, argv + optind);
941e990d 1428 if (r < 0)
763c7aa2 1429 return EXIT_FAILURE;
941e990d 1430
4ad16808
ZJS
1431 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1432 _cleanup_free_ char *filter;
1433
1434 filter = journal_make_match_string(j);
1435 log_debug("Journal filter: %s", filter);
1436 }
67e04a48 1437
15119c16
LP
1438 if (arg_field) {
1439 const void *data;
1440 size_t size;
1441
21ae4593
ZJS
1442 r = sd_journal_set_data_threshold(j, 0);
1443 if (r < 0) {
1444 log_error("Failed to unset data size threshold");
1445 return EXIT_FAILURE;
1446 }
1447
15119c16
LP
1448 r = sd_journal_query_unique(j, arg_field);
1449 if (r < 0) {
1450 log_error("Failed to query unique data objects: %s", strerror(-r));
763c7aa2 1451 return EXIT_FAILURE;
15119c16
LP
1452 }
1453
1454 SD_JOURNAL_FOREACH_UNIQUE(j, data, size) {
1455 const void *eq;
1456
67e04a48 1457 if (arg_lines >= 0 && n_shown >= arg_lines)
fd6e8875
LP
1458 break;
1459
15119c16
LP
1460 eq = memchr(data, '=', size);
1461 if (eq)
1462 printf("%.*s\n", (int) (size - ((const uint8_t*) eq - (const uint8_t*) data + 1)), (const char*) eq + 1);
1463 else
1464 printf("%.*s\n", (int) size, (const char*) data);
fd6e8875
LP
1465
1466 n_shown ++;
15119c16
LP
1467 }
1468
763c7aa2 1469 return EXIT_SUCCESS;
15119c16
LP
1470 }
1471
8d98da3f
ZJS
1472 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1473 if (arg_follow) {
1474 r = sd_journal_get_fd(j);
1475 if (r < 0)
1476 return EXIT_FAILURE;
1477 }
1478
248fc619
ZJS
1479 if (arg_cursor || arg_after_cursor) {
1480 r = sd_journal_seek_cursor(j, arg_cursor ? arg_cursor : arg_after_cursor);
08984293 1481 if (r < 0) {
cfbc22ab 1482 log_error("Failed to seek to cursor: %s", strerror(-r));
763c7aa2 1483 return EXIT_FAILURE;
08984293 1484 }
d89d6c86 1485 if (!arg_reverse)
248fc619 1486 r = sd_journal_next_skip(j, 1 + !!arg_after_cursor);
d89d6c86 1487 else
248fc619
ZJS
1488 r = sd_journal_previous_skip(j, 1 + !!arg_after_cursor);
1489
1490 if (arg_after_cursor && r < 2 && !arg_follow)
1491 /* We couldn't find the next entry after the cursor. */
1492 arg_lines = 0;
08984293 1493
d89d6c86 1494 } else if (arg_since_set && !arg_reverse) {
cfbc22ab 1495 r = sd_journal_seek_realtime_usec(j, arg_since);
8f14c832 1496 if (r < 0) {
cfbc22ab 1497 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1498 return EXIT_FAILURE;
8f14c832 1499 }
8f14c832
LP
1500 r = sd_journal_next(j);
1501
d89d6c86
LN
1502 } else if (arg_until_set && arg_reverse) {
1503 r = sd_journal_seek_realtime_usec(j, arg_until);
1504 if (r < 0) {
1505 log_error("Failed to seek to date: %s", strerror(-r));
763c7aa2 1506 return EXIT_FAILURE;
d89d6c86
LN
1507 }
1508 r = sd_journal_previous(j);
1509
67e04a48 1510 } else if (arg_lines >= 0) {
2100675e
LP
1511 r = sd_journal_seek_tail(j);
1512 if (r < 0) {
1513 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1514 return EXIT_FAILURE;
2100675e
LP
1515 }
1516
1517 r = sd_journal_previous_skip(j, arg_lines);
8f14c832 1518
d89d6c86
LN
1519 } else if (arg_reverse) {
1520 r = sd_journal_seek_tail(j);
1521 if (r < 0) {
1522 log_error("Failed to seek to tail: %s", strerror(-r));
763c7aa2 1523 return EXIT_FAILURE;
d89d6c86
LN
1524 }
1525
1526 r = sd_journal_previous(j);
1527
2100675e
LP
1528 } else {
1529 r = sd_journal_seek_head(j);
1530 if (r < 0) {
1531 log_error("Failed to seek to head: %s", strerror(-r));
763c7aa2 1532 return EXIT_FAILURE;
2100675e 1533 }
6f003b43
LP
1534
1535 r = sd_journal_next(j);
1536 }
1537
1538 if (r < 0) {
1539 log_error("Failed to iterate through journal: %s", strerror(-r));
763c7aa2 1540 return EXIT_FAILURE;
50f20cfd 1541 }
87d2c1ff 1542
f89a3b6f 1543 if (!arg_no_pager && !arg_follow)
1b12a7b5 1544 pager_open(arg_pager_end);
0d43c694 1545
cfbc22ab
LP
1546 if (!arg_quiet) {
1547 usec_t start, end;
1548 char start_buf[FORMAT_TIMESTAMP_MAX], end_buf[FORMAT_TIMESTAMP_MAX];
1549
1550 r = sd_journal_get_cutoff_realtime_usec(j, &start, &end);
1551 if (r < 0) {
1552 log_error("Failed to get cutoff: %s", strerror(-r));
1553 goto finish;
1554 }
1555
1556 if (r > 0) {
1557 if (arg_follow)
9048b11f
LP
1558 printf("-- Logs begin at %s. --\n",
1559 format_timestamp(start_buf, sizeof(start_buf), start));
cfbc22ab 1560 else
9048b11f 1561 printf("-- Logs begin at %s, end at %s. --\n",
cfbc22ab
LP
1562 format_timestamp(start_buf, sizeof(start_buf), start),
1563 format_timestamp(end_buf, sizeof(end_buf), end));
1564 }
1565 }
1566
50f20cfd 1567 for (;;) {
67e04a48 1568 while (arg_lines < 0 || n_shown < arg_lines || (arg_follow && !first_line)) {
cfbc22ab
LP
1569 int flags;
1570
6f003b43 1571 if (need_seek) {
99613ec5 1572 if (!arg_reverse)
d89d6c86
LN
1573 r = sd_journal_next(j);
1574 else
1575 r = sd_journal_previous(j);
6f003b43
LP
1576 if (r < 0) {
1577 log_error("Failed to iterate through journal: %s", strerror(-r));
1578 goto finish;
1579 }
a72b6353
ZJS
1580 if (r == 0)
1581 break;
0d43c694
LP
1582 }
1583
d89d6c86 1584 if (arg_until_set && !arg_reverse) {
cfbc22ab
LP
1585 usec_t usec;
1586
1587 r = sd_journal_get_realtime_usec(j, &usec);
1588 if (r < 0) {
1589 log_error("Failed to determine timestamp: %s", strerror(-r));
1590 goto finish;
1591 }
3ba09ee8
PF
1592 if (usec > arg_until)
1593 goto finish;
cfbc22ab
LP
1594 }
1595
d89d6c86
LN
1596 if (arg_since_set && arg_reverse) {
1597 usec_t usec;
1598
1599 r = sd_journal_get_realtime_usec(j, &usec);
1600 if (r < 0) {
1601 log_error("Failed to determine timestamp: %s", strerror(-r));
1602 goto finish;
1603 }
1604 if (usec < arg_since)
1605 goto finish;
1606 }
1607
cd931c0a
LP
1608 if (!arg_merge) {
1609 sd_id128_t boot_id;
14a65d65 1610
cd931c0a
LP
1611 r = sd_journal_get_monotonic_usec(j, NULL, &boot_id);
1612 if (r >= 0) {
1613 if (previous_boot_id_valid &&
1614 !sd_id128_equal(boot_id, previous_boot_id))
0b5a519c
DS
1615 printf("%s-- Reboot --%s\n",
1616 ansi_highlight(), ansi_highlight_off());
cd931c0a
LP
1617
1618 previous_boot_id = boot_id;
1619 previous_boot_id_valid = true;
1620 }
14a65d65
LP
1621 }
1622
cfbc22ab 1623 flags =
cd4b13e0 1624 arg_all * OUTPUT_SHOW_ALL |
e3657ecd 1625 (arg_full || !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH |
d4205751
LP
1626 on_tty() * OUTPUT_COLOR |
1627 arg_catalog * OUTPUT_CATALOG;
cfbc22ab 1628
94e0bd7d 1629 r = output_journal(stdout, j, arg_output, 0, flags, &ellipsized);
a72b6353
ZJS
1630 need_seek = true;
1631 if (r == -EADDRNOTAVAIL)
1632 break;
1633 else if (r < 0 || ferror(stdout))
72f59706 1634 goto finish;
6f003b43 1635
cfbc22ab 1636 n_shown++;
87d2c1ff
LP
1637 }
1638
248fc619
ZJS
1639 if (!arg_follow) {
1640 if (arg_show_cursor) {
1641 _cleanup_free_ char *cursor = NULL;
1642
1643 r = sd_journal_get_cursor(j, &cursor);
1644 if (r < 0 && r != -EADDRNOTAVAIL)
1645 log_error("Failed to get cursor: %s", strerror(-r));
1646 else if (r >= 0)
1647 printf("-- cursor: %s\n", cursor);
1648 }
1649
50f20cfd 1650 break;
248fc619 1651 }
50f20cfd 1652
e02d1cf7 1653 r = sd_journal_wait(j, (uint64_t) -1);
50f20cfd 1654 if (r < 0) {
7a69007a 1655 log_error("Couldn't wait for journal event: %s", strerror(-r));
50f20cfd
LP
1656 goto finish;
1657 }
67e04a48
ZJS
1658
1659 first_line = false;
de190aef 1660 }
87d2c1ff
LP
1661
1662finish:
0d43c694
LP
1663 pager_close();
1664
3fbf9cbb 1665 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
87d2c1ff 1666}