1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
35 #include <sys/ioctl.h>
43 #include <systemd/sd-journal.h>
46 #include "logs-show.h"
48 #include "path-util.h"
51 #include "logs-show.h"
53 #include "journal-internal.h"
54 #include "journal-def.h"
55 #include "journal-verify.h"
56 #include "journal-authenticate.h"
57 #include "journal-qrcode.h"
59 #include "unit-name.h"
62 #define DEFAULT_FSS_INTERVAL_USEC (15*USEC_PER_MINUTE)
64 static OutputMode arg_output
= OUTPUT_SHORT
;
65 static bool arg_pager_end
= false;
66 static bool arg_follow
= false;
67 static bool arg_full
= false;
68 static bool arg_all
= false;
69 static bool arg_no_pager
= false;
70 static int arg_lines
= -1;
71 static bool arg_no_tail
= false;
72 static bool arg_quiet
= false;
73 static bool arg_merge
= false;
74 static bool arg_this_boot
= false;
75 static const char *arg_cursor
= NULL
;
76 static const char *arg_directory
= NULL
;
77 static int arg_priorities
= 0xFF;
78 static const char *arg_verify_key
= NULL
;
80 static usec_t arg_interval
= DEFAULT_FSS_INTERVAL_USEC
;
82 static usec_t arg_since
, arg_until
;
83 static bool arg_since_set
= false, arg_until_set
= false;
84 static const char *arg_unit
= NULL
;
85 static bool arg_unit_system
;
86 static const char *arg_field
= NULL
;
87 static bool arg_catalog
= false;
88 static bool arg_reverse
= false;
89 static const char *arg_root
= NULL
;
100 ACTION_UPDATE_CATALOG
101 } arg_action
= ACTION_SHOW
;
103 static int help(void) {
105 printf("%s [OPTIONS...] [MATCHES...]\n\n"
106 "Query the journal.\n\n"
108 " --since=DATE Start showing entries newer or of the specified date\n"
109 " --until=DATE Stop showing entries older or of the specified date\n"
110 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
111 " -b --this-boot Show data only from current boot\n"
112 " -u --unit=UNIT Show data only from the specified unit\n"
113 " --user-unit=UNIT Show data only from the specified user session unit\n"
114 " -p --priority=RANGE Show only messages within the specified priority range\n"
115 " -e --pager-end Immediately jump to end of the journal in the pager\n"
116 " -f --follow Follow journal\n"
117 " -n --lines[=INTEGER] Number of journal entries to show\n"
118 " --no-tail Show all lines, even in follow mode\n"
119 " -r --reverse Show the newest entries first\n"
120 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
121 " verbose, export, json, json-pretty, json-sse, cat)\n"
122 " -x --catalog Add message explanations where available\n"
123 " --full Do not ellipsize fields\n"
124 " -a --all Show all fields, including long and unprintable\n"
125 " -q --quiet Don't show privilege warning\n"
126 " --no-pager Do not pipe output into a pager\n"
127 " -m --merge Show entries from all available journals\n"
128 " -D --directory=PATH Show journal files from directory\n"
129 " --root=ROOT Operate on catalog files underneath the root ROOT\n"
131 " --interval=TIME Time interval for changing the FSS sealing key\n"
132 " --verify-key=KEY Specify FSS verification key\n"
135 " -h --help Show this help\n"
136 " --version Show package version\n"
137 " --new-id128 Generate a new 128 Bit ID\n"
138 " --header Show journal header information\n"
139 " --disk-usage Show total disk usage\n"
140 " -F --field=FIELD List all values a certain field takes\n"
141 " --list-catalog Show message IDs of all entries in the message catalog\n"
142 " --dump-catalog Show entries in the message catalog\n"
143 " --update-catalog Update the message catalog database\n"
145 " --setup-keys Generate new FSS key pair\n"
146 " --verify Verify journal file consistency\n"
148 , program_invocation_short_name
);
153 static int parse_argv(int argc
, char *argv
[]) {
176 static const struct option options
[] = {
177 { "help", no_argument
, NULL
, 'h' },
178 { "version" , no_argument
, NULL
, ARG_VERSION
},
179 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
180 { "pager-end", no_argument
, NULL
, 'e' },
181 { "follow", no_argument
, NULL
, 'f' },
182 { "output", required_argument
, NULL
, 'o' },
183 { "all", no_argument
, NULL
, 'a' },
184 { "full", no_argument
, NULL
, ARG_FULL
},
185 { "lines", optional_argument
, NULL
, 'n' },
186 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
187 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
188 { "quiet", no_argument
, NULL
, 'q' },
189 { "merge", no_argument
, NULL
, 'm' },
190 { "this-boot", no_argument
, NULL
, 'b' },
191 { "directory", required_argument
, NULL
, 'D' },
192 { "root", required_argument
, NULL
, ARG_ROOT
},
193 { "header", no_argument
, NULL
, ARG_HEADER
},
194 { "priority", required_argument
, NULL
, 'p' },
195 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
196 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
197 { "verify", no_argument
, NULL
, ARG_VERIFY
},
198 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
199 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
200 { "cursor", required_argument
, NULL
, 'c' },
201 { "since", required_argument
, NULL
, ARG_SINCE
},
202 { "until", required_argument
, NULL
, ARG_UNTIL
},
203 { "unit", required_argument
, NULL
, 'u' },
204 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
205 { "field", required_argument
, NULL
, 'F' },
206 { "catalog", no_argument
, NULL
, 'x' },
207 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
208 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
209 { "update-catalog",no_argument
, NULL
, ARG_UPDATE_CATALOG
},
210 { "reverse", no_argument
, NULL
, 'r' },
219 while ((c
= getopt_long(argc
, argv
, "hefo:an::qmbD:p:c:u:F:xr", options
, NULL
)) >= 0) {
228 puts(PACKAGE_STRING
);
229 puts(SYSTEMD_FEATURES
);
237 arg_pager_end
= true;
249 arg_output
= output_mode_from_string(optarg
);
250 if (arg_output
< 0) {
251 log_error("Unknown output format '%s'.", optarg
);
255 if (arg_output
== OUTPUT_EXPORT
||
256 arg_output
== OUTPUT_JSON
||
257 arg_output
== OUTPUT_JSON_PRETTY
||
258 arg_output
== OUTPUT_JSON_SSE
||
259 arg_output
== OUTPUT_CAT
)
274 r
= safe_atoi(optarg
, &arg_lines
);
275 if (r
< 0 || arg_lines
< 0) {
276 log_error("Failed to parse lines '%s'", optarg
);
282 /* Hmm, no argument? Maybe the next
283 * word on the command line is
284 * supposed to be the argument? Let's
285 * see if there is one, and is
286 * parsable as a positive
290 safe_atoi(argv
[optind
], &n
) >= 0 &&
306 arg_action
= ACTION_NEW_ID128
;
318 arg_this_boot
= true;
322 arg_directory
= optarg
;
334 arg_action
= ACTION_PRINT_HEADER
;
338 arg_action
= ACTION_VERIFY
;
342 arg_action
= ACTION_DISK_USAGE
;
347 arg_action
= ACTION_SETUP_KEYS
;
352 arg_action
= ACTION_VERIFY
;
353 arg_verify_key
= optarg
;
358 r
= parse_sec(optarg
, &arg_interval
);
359 if (r
< 0 || arg_interval
<= 0) {
360 log_error("Failed to parse sealing key change interval: %s", optarg
);
368 log_error("Forward-secure sealing not available.");
375 dots
= strstr(optarg
, "..");
381 a
= strndup(optarg
, dots
- optarg
);
385 from
= log_level_from_string(a
);
386 to
= log_level_from_string(dots
+ 2);
389 if (from
< 0 || to
< 0) {
390 log_error("Failed to parse log level range %s", optarg
);
397 for (i
= from
; i
<= to
; i
++)
398 arg_priorities
|= 1 << i
;
400 for (i
= to
; i
<= from
; i
++)
401 arg_priorities
|= 1 << i
;
407 p
= log_level_from_string(optarg
);
409 log_error("Unknown log level %s", optarg
);
415 for (i
= 0; i
<= p
; i
++)
416 arg_priorities
|= 1 << i
;
423 r
= parse_timestamp(optarg
, &arg_since
);
425 log_error("Failed to parse timestamp: %s", optarg
);
428 arg_since_set
= true;
432 r
= parse_timestamp(optarg
, &arg_until
);
434 log_error("Failed to parse timestamp: %s", optarg
);
437 arg_until_set
= true;
442 arg_unit_system
= true;
447 arg_unit_system
= false;
461 case ARG_LIST_CATALOG
:
462 arg_action
= ACTION_LIST_CATALOG
;
465 case ARG_DUMP_CATALOG
:
466 arg_action
= ACTION_DUMP_CATALOG
;
469 case ARG_UPDATE_CATALOG
:
470 arg_action
= ACTION_UPDATE_CATALOG
;
478 log_error("Unknown option code %c", c
);
483 if (arg_follow
&& !arg_no_tail
&& arg_lines
< 0)
486 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
487 log_error("--since= must be before --until=.");
491 if (arg_cursor
&& arg_since_set
) {
492 log_error("Please specify either --since= or --cursor=, not both.");
496 if (arg_follow
&& arg_reverse
) {
497 log_error("Please specify either --reverse= or --follow=, not both.");
504 static int generate_new_id128(void) {
509 r
= sd_id128_randomize(&id
);
511 log_error("Failed to generate ID: %s", strerror(-r
));
515 printf("As string:\n"
516 SD_ID128_FORMAT_STR
"\n\n"
518 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
520 "#define MESSAGE_XYZ SD_ID128_MAKE(",
521 SD_ID128_FORMAT_VAL(id
),
522 SD_ID128_FORMAT_VAL(id
));
523 for (i
= 0; i
< 16; i
++)
524 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
525 fputs(")\n\n", stdout
);
527 printf("As Python constant:\n"
529 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
530 SD_ID128_FORMAT_VAL(id
));
535 static int add_matches(sd_journal
*j
, char **args
) {
540 STRV_FOREACH(i
, args
) {
544 r
= sd_journal_add_disjunction(j
);
545 else if (path_is_absolute(*i
)) {
546 char _cleanup_free_
*p
, *t
= NULL
;
550 p
= canonicalize_file_name(*i
);
553 if (stat(path
, &st
) < 0) {
554 log_error("Couldn't stat file: %m");
558 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
))
559 t
= strappend("_EXE=", path
);
560 else if (S_ISCHR(st
.st_mode
))
561 asprintf(&t
, "_KERNEL_DEVICE=c%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
562 else if (S_ISBLK(st
.st_mode
))
563 asprintf(&t
, "_KERNEL_DEVICE=b%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
565 log_error("File is neither a device node, nor regular file, nor executable: %s", *i
);
572 r
= sd_journal_add_match(j
, t
, 0);
574 r
= sd_journal_add_match(j
, *i
, 0);
577 log_error("Failed to add match '%s': %s", *i
, strerror(-r
));
585 static int add_this_boot(sd_journal
*j
) {
586 char match
[9+32+1] = "_BOOT_ID=";
595 r
= sd_id128_get_boot(&boot_id
);
597 log_error("Failed to get boot id: %s", strerror(-r
));
601 sd_id128_to_string(boot_id
, match
+ 9);
602 r
= sd_journal_add_match(j
, match
, strlen(match
));
604 log_error("Failed to add match: %s", strerror(-r
));
611 static int add_unit(sd_journal
*j
) {
612 _cleanup_free_
char *u
= NULL
;
617 if (isempty(arg_unit
))
620 u
= unit_name_mangle(arg_unit
);
625 r
= add_matches_for_unit(j
, u
);
627 r
= add_matches_for_user_unit(j
, u
, getuid());
634 static int add_priorities(sd_journal
*j
) {
635 char match
[] = "PRIORITY=0";
640 if (arg_priorities
== 0xFF)
643 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
644 if (arg_priorities
& (1 << i
)) {
645 match
[sizeof(match
)-2] = '0' + i
;
647 r
= sd_journal_add_match(j
, match
, strlen(match
));
649 log_error("Failed to add match: %s", strerror(-r
));
657 static int setup_keys(void) {
659 size_t mpk_size
, seed_size
, state_size
, i
;
660 uint8_t *mpk
, *seed
, *state
;
662 int fd
= -1, r
, attr
= 0;
663 sd_id128_t machine
, boot
;
664 char *p
= NULL
, *k
= NULL
;
668 r
= sd_id128_get_machine(&machine
);
670 log_error("Failed to get machine ID: %s", strerror(-r
));
674 r
= sd_id128_get_boot(&boot
);
676 log_error("Failed to get boot ID: %s", strerror(-r
));
680 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
681 SD_ID128_FORMAT_VAL(machine
)) < 0)
684 if (access(p
, F_OK
) >= 0) {
685 log_error("Sealing key file %s exists already.", p
);
690 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
691 SD_ID128_FORMAT_VAL(machine
)) < 0) {
696 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
697 mpk
= alloca(mpk_size
);
699 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
700 seed
= alloca(seed_size
);
702 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
703 state
= alloca(state_size
);
705 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
707 log_error("Failed to open /dev/random: %m");
712 log_info("Generating seed...");
713 l
= loop_read(fd
, seed
, seed_size
, true);
714 if (l
< 0 || (size_t) l
!= seed_size
) {
715 log_error("Failed to read random seed: %s", strerror(EIO
));
720 log_info("Generating key pair...");
721 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
723 log_info("Generating sealing key...");
724 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
726 assert(arg_interval
> 0);
728 n
= now(CLOCK_REALTIME
);
731 close_nointr_nofail(fd
);
732 fd
= mkostemp(k
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
734 log_error("Failed to open %s: %m", k
);
739 /* Enable secure remove, exclusion from dump, synchronous
740 * writing and in-place updating */
741 if (ioctl(fd
, FS_IOC_GETFLAGS
, &attr
) < 0)
742 log_warning("FS_IOC_GETFLAGS failed: %m");
744 attr
|= FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
;
746 if (ioctl(fd
, FS_IOC_SETFLAGS
, &attr
) < 0)
747 log_warning("FS_IOC_SETFLAGS failed: %m");
750 memcpy(h
.signature
, "KSHHRHLP", 8);
751 h
.machine_id
= machine
;
753 h
.header_size
= htole64(sizeof(h
));
754 h
.start_usec
= htole64(n
* arg_interval
);
755 h
.interval_usec
= htole64(arg_interval
);
756 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
757 h
.fsprg_state_size
= htole64(state_size
);
759 l
= loop_write(fd
, &h
, sizeof(h
), false);
760 if (l
< 0 || (size_t) l
!= sizeof(h
)) {
761 log_error("Failed to write header: %s", strerror(EIO
));
766 l
= loop_write(fd
, state
, state_size
, false);
767 if (l
< 0 || (size_t) l
!= state_size
) {
768 log_error("Failed to write state: %s", strerror(EIO
));
773 if (link(k
, p
) < 0) {
774 log_error("Failed to link file: %m");
782 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON
"secret sealing key" ANSI_HIGHLIGHT_OFF
" has been written to\n"
783 "the following local file. This key file is automatically updated when the\n"
784 "sealing key is advanced. It should not be used on multiple hosts.\n"
788 "Please write down the following " ANSI_HIGHLIGHT_ON
"secret verification key" ANSI_HIGHLIGHT_OFF
". It should be stored\n"
789 "at a safe location and should not be saved locally on disk.\n"
790 "\n\t" ANSI_HIGHLIGHT_RED_ON
, p
);
793 for (i
= 0; i
< seed_size
; i
++) {
794 if (i
> 0 && i
% 3 == 0)
796 printf("%02x", ((uint8_t*) seed
)[i
]);
799 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
802 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
805 ANSI_HIGHLIGHT_OFF
"\n"
806 "The sealing key is automatically changed every %s.\n",
807 format_timespan(tsb
, sizeof(tsb
), arg_interval
));
809 hn
= gethostname_malloc();
812 hostname_cleanup(hn
);
813 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
815 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
818 /* If this is not an UTF-8 system don't print any QR codes */
819 if (is_locale_utf8()) {
820 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
821 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
831 close_nointr_nofail(fd
);
842 log_error("Forward-secure sealing not available.");
847 static int verify(sd_journal
*j
) {
854 log_show_color(true);
856 HASHMAP_FOREACH(f
, j
->files
, i
) {
858 usec_t first
, validated
, last
;
861 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
862 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
865 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
867 /* If the key was invalid give up right-away. */
870 log_warning("FAIL: %s (%s)", f
->path
, strerror(-k
));
873 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
874 log_info("PASS: %s", f
->path
);
876 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
878 log_info("=> Validated from %s to %s, final %s entries not sealed.",
879 format_timestamp(a
, sizeof(a
), first
),
880 format_timestamp(b
, sizeof(b
), validated
),
881 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0));
883 log_info("=> No sealing yet, %s of entries not sealed.",
884 format_timespan(c
, sizeof(c
), last
- first
));
886 log_info("=> No sealing yet, no entries in file.");
895 static int access_check_var_log_journal(sd_journal
*j
) {
896 _cleanup_strv_free_
char **g
= NULL
;
902 have_access
= in_group("systemd-journal") > 0;
905 /* Let's enumerate all groups from the default ACL of
906 * the directory, which generally should allow access
907 * to most journal files too */
908 r
= search_acl_groups(&g
, "/var/log/journal/", &have_access
);
916 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
917 " Users in the 'systemd-journal' group can see all messages. Pass -q to\n"
918 " turn off this notice.");
920 _cleanup_free_
char *s
= NULL
;
922 r
= strv_extend(&g
, "systemd-journal");
929 s
= strv_join(g
, "', '");
933 log_notice("Hint: You are currently not seeing messages from other users and the system.\n"
934 " Users in the groups '%s' can see all messages.\n"
935 " Pass -q to turn off this notice.", s
);
943 static int access_check(sd_journal
*j
) {
950 if (set_isempty(j
->errors
)) {
951 if (hashmap_isempty(j
->files
))
952 log_notice("No journal files were found.");
956 if (set_contains(j
->errors
, INT_TO_PTR(-EACCES
))) {
958 /* If /var/log/journal doesn't even exist,
959 * unprivileged users have no access at all */
960 if (access("/var/log/journal", F_OK
) < 0 &&
962 in_group("systemd-journal") <= 0) {
963 log_error("Unprivileged users cannot access messages, unless persistent log storage is\n"
964 "enabled. Users in the 'systemd-journal' group may always access messages.");
968 /* If /var/log/journal exists, try to pring a nice
969 notice if the user lacks access to it */
970 if (!arg_quiet
&& geteuid() != 0) {
971 r
= access_check_var_log_journal(j
);
976 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
977 log_error("Unprivileged users cannot access messages. Users in the 'systemd-journal' group\n"
978 "group may access messages.");
983 if (hashmap_isempty(j
->files
)) {
984 log_error("No journal files were opened due to insufficient permissions.");
989 SET_FOREACH(code
, j
->errors
, it
) {
992 err
= -PTR_TO_INT(code
);
996 log_warning("Error was encountered while opening journal files: %s",
1003 int main(int argc
, char *argv
[]) {
1005 sd_journal _cleanup_journal_close_
*j
= NULL
;
1006 bool need_seek
= false;
1007 sd_id128_t previous_boot_id
;
1008 bool previous_boot_id_valid
= false, first_line
= true;
1011 setlocale(LC_ALL
, "");
1012 log_parse_environment();
1015 r
= parse_argv(argc
, argv
);
1019 signal(SIGWINCH
, columns_lines_cache_reset
);
1021 if (arg_action
== ACTION_NEW_ID128
) {
1022 r
= generate_new_id128();
1026 if (arg_action
== ACTION_SETUP_KEYS
) {
1031 if (arg_action
== ACTION_UPDATE_CATALOG
||
1032 arg_action
== ACTION_LIST_CATALOG
||
1033 arg_action
== ACTION_DUMP_CATALOG
) {
1035 const char* database
= CATALOG_DATABASE
;
1036 char _cleanup_free_
*copy
= NULL
;
1038 copy
= strjoin(arg_root
, "/", CATALOG_DATABASE
, NULL
);
1043 path_kill_slashes(copy
);
1047 if (arg_action
== ACTION_UPDATE_CATALOG
) {
1048 r
= catalog_update(database
, arg_root
, catalog_file_dirs
);
1050 log_error("Failed to list catalog: %s", strerror(-r
));
1052 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
1055 r
= catalog_list_items(stdout
, database
,
1056 oneline
, argv
+ optind
);
1058 r
= catalog_list(stdout
, database
, oneline
);
1060 log_error("Failed to list catalog: %s", strerror(-r
));
1067 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
1069 r
= sd_journal_open(&j
, arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
);
1071 log_error("Failed to open journal: %s", strerror(-r
));
1072 return EXIT_FAILURE
;
1075 r
= access_check(j
);
1077 return EXIT_FAILURE
;
1079 if (arg_action
== ACTION_VERIFY
) {
1084 if (arg_action
== ACTION_PRINT_HEADER
) {
1085 journal_print_header(j
);
1086 return EXIT_SUCCESS
;
1089 if (arg_action
== ACTION_DISK_USAGE
) {
1091 char sbytes
[FORMAT_BYTES_MAX
];
1093 r
= sd_journal_get_usage(j
, &bytes
);
1095 return EXIT_FAILURE
;
1097 printf("Journals take up %s on disk.\n",
1098 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
1099 return EXIT_SUCCESS
;
1102 r
= add_this_boot(j
);
1104 return EXIT_FAILURE
;
1108 return EXIT_FAILURE
;
1110 r
= add_matches(j
, argv
+ optind
);
1112 return EXIT_FAILURE
;
1114 r
= add_priorities(j
);
1116 return EXIT_FAILURE
;
1118 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1119 r
= sd_journal_get_fd(j
);
1121 return EXIT_FAILURE
;
1127 r
= sd_journal_query_unique(j
, arg_field
);
1129 log_error("Failed to query unique data objects: %s", strerror(-r
));
1130 return EXIT_FAILURE
;
1133 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1136 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
1139 eq
= memchr(data
, '=', size
);
1141 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
1143 printf("%.*s\n", (int) size
, (const char*) data
);
1148 return EXIT_SUCCESS
;
1152 r
= sd_journal_seek_cursor(j
, arg_cursor
);
1154 log_error("Failed to seek to cursor: %s", strerror(-r
));
1155 return EXIT_FAILURE
;
1158 r
= sd_journal_next(j
);
1160 r
= sd_journal_previous(j
);
1162 } else if (arg_since_set
&& !arg_reverse
) {
1163 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
1165 log_error("Failed to seek to date: %s", strerror(-r
));
1166 return EXIT_FAILURE
;
1168 r
= sd_journal_next(j
);
1170 } else if (arg_until_set
&& arg_reverse
) {
1171 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
1173 log_error("Failed to seek to date: %s", strerror(-r
));
1174 return EXIT_FAILURE
;
1176 r
= sd_journal_previous(j
);
1178 } else if (arg_lines
>= 0) {
1179 r
= sd_journal_seek_tail(j
);
1181 log_error("Failed to seek to tail: %s", strerror(-r
));
1182 return EXIT_FAILURE
;
1185 r
= sd_journal_previous_skip(j
, arg_lines
);
1187 } else if (arg_reverse
) {
1188 r
= sd_journal_seek_tail(j
);
1190 log_error("Failed to seek to tail: %s", strerror(-r
));
1191 return EXIT_FAILURE
;
1194 r
= sd_journal_previous(j
);
1197 r
= sd_journal_seek_head(j
);
1199 log_error("Failed to seek to head: %s", strerror(-r
));
1200 return EXIT_FAILURE
;
1203 r
= sd_journal_next(j
);
1207 log_error("Failed to iterate through journal: %s", strerror(-r
));
1208 return EXIT_FAILURE
;
1211 if (!arg_no_pager
&& !arg_follow
)
1212 pager_open(arg_pager_end
);
1216 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
1218 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
1220 log_error("Failed to get cutoff: %s", strerror(-r
));
1226 printf("-- Logs begin at %s. --\n",
1227 format_timestamp(start_buf
, sizeof(start_buf
), start
));
1229 printf("-- Logs begin at %s, end at %s. --\n",
1230 format_timestamp(start_buf
, sizeof(start_buf
), start
),
1231 format_timestamp(end_buf
, sizeof(end_buf
), end
));
1236 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
1241 r
= sd_journal_next(j
);
1243 r
= sd_journal_previous(j
);
1245 log_error("Failed to iterate through journal: %s", strerror(-r
));
1253 if (arg_until_set
&& !arg_reverse
) {
1256 r
= sd_journal_get_realtime_usec(j
, &usec
);
1258 log_error("Failed to determine timestamp: %s", strerror(-r
));
1261 if (usec
> arg_until
)
1265 if (arg_since_set
&& arg_reverse
) {
1268 r
= sd_journal_get_realtime_usec(j
, &usec
);
1270 log_error("Failed to determine timestamp: %s", strerror(-r
));
1273 if (usec
< arg_since
)
1280 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1282 if (previous_boot_id_valid
&&
1283 !sd_id128_equal(boot_id
, previous_boot_id
))
1284 printf(ANSI_HIGHLIGHT_ON
"-- Reboot --" ANSI_HIGHLIGHT_OFF
"\n");
1286 previous_boot_id
= boot_id
;
1287 previous_boot_id_valid
= true;
1292 arg_all
* OUTPUT_SHOW_ALL
|
1293 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
1294 on_tty() * OUTPUT_COLOR
|
1295 arg_catalog
* OUTPUT_CATALOG
;
1297 r
= output_journal(stdout
, j
, arg_output
, 0, flags
);
1298 if (r
< 0 || ferror(stdout
))
1308 r
= sd_journal_wait(j
, (uint64_t) -1);
1310 log_error("Couldn't wait for journal event: %s", strerror(-r
));
1320 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;