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;
100 } arg_action
= ACTION_SHOW
;
102 static int help(void) {
104 printf("%s [OPTIONS...] [MATCHES...]\n\n"
105 "Query the journal.\n\n"
107 " --since=DATE Start showing entries newer or of the specified date\n"
108 " --until=DATE Stop showing entries older or of the specified date\n"
109 " -c --cursor=CURSOR Start showing entries from specified cursor\n"
110 " -b --this-boot Show data only from current boot\n"
111 " -u --unit=UNIT Show data only from the specified unit\n"
112 " --user-unit=UNIT Show data only from the specified user session unit\n"
113 " -p --priority=RANGE Show only messages within the specified priority range\n"
114 " -e --pager-end Immediately jump to end of the journal in the pager\n"
115 " -f --follow Follow journal\n"
116 " -n --lines[=INTEGER] Number of journal entries to show\n"
117 " --no-tail Show all lines, even in follow mode\n"
118 " -r --reverse Show the newest entries first\n"
119 " -o --output=STRING Change journal output mode (short, short-monotonic,\n"
120 " verbose, export, json, json-pretty, json-sse, cat)\n"
121 " -x --catalog Add message explanations where available\n"
122 " --full Do not ellipsize fields\n"
123 " -a --all Show all fields, including long and unprintable\n"
124 " -q --quiet Don't show privilege warning\n"
125 " --no-pager Do not pipe output into a pager\n"
126 " -m --merge Show entries from all available journals\n"
127 " -D --directory=PATH Show journal files from directory\n"
129 " --interval=TIME Time interval for changing the FSS sealing key\n"
130 " --verify-key=KEY Specify FSS verification key\n"
133 " -h --help Show this help\n"
134 " --version Show package version\n"
135 " --new-id128 Generate a new 128 Bit ID\n"
136 " --header Show journal header information\n"
137 " --disk-usage Show total disk usage\n"
138 " -F --field=FIELD List all values a certain field takes\n"
139 " --list-catalog Show message IDs of all entries in the message catalog\n"
140 " --dump-catalog Show entries in the message catalog\n"
141 " --update-catalog Update the message catalog database\n"
143 " --setup-keys Generate new FSS key pair\n"
144 " --verify Verify journal file consistency\n"
146 , program_invocation_short_name
);
151 static int parse_argv(int argc
, char *argv
[]) {
173 static const struct option options
[] = {
174 { "help", no_argument
, NULL
, 'h' },
175 { "version" , no_argument
, NULL
, ARG_VERSION
},
176 { "no-pager", no_argument
, NULL
, ARG_NO_PAGER
},
177 { "pager-end", no_argument
, NULL
, 'e' },
178 { "follow", no_argument
, NULL
, 'f' },
179 { "output", required_argument
, NULL
, 'o' },
180 { "all", no_argument
, NULL
, 'a' },
181 { "full", no_argument
, NULL
, ARG_FULL
},
182 { "lines", optional_argument
, NULL
, 'n' },
183 { "no-tail", no_argument
, NULL
, ARG_NO_TAIL
},
184 { "new-id128", no_argument
, NULL
, ARG_NEW_ID128
},
185 { "quiet", no_argument
, NULL
, 'q' },
186 { "merge", no_argument
, NULL
, 'm' },
187 { "this-boot", no_argument
, NULL
, 'b' },
188 { "directory", required_argument
, NULL
, 'D' },
189 { "header", no_argument
, NULL
, ARG_HEADER
},
190 { "priority", required_argument
, NULL
, 'p' },
191 { "setup-keys", no_argument
, NULL
, ARG_SETUP_KEYS
},
192 { "interval", required_argument
, NULL
, ARG_INTERVAL
},
193 { "verify", no_argument
, NULL
, ARG_VERIFY
},
194 { "verify-key", required_argument
, NULL
, ARG_VERIFY_KEY
},
195 { "disk-usage", no_argument
, NULL
, ARG_DISK_USAGE
},
196 { "cursor", required_argument
, NULL
, 'c' },
197 { "since", required_argument
, NULL
, ARG_SINCE
},
198 { "until", required_argument
, NULL
, ARG_UNTIL
},
199 { "unit", required_argument
, NULL
, 'u' },
200 { "user-unit", required_argument
, NULL
, ARG_USER_UNIT
},
201 { "field", required_argument
, NULL
, 'F' },
202 { "catalog", no_argument
, NULL
, 'x' },
203 { "list-catalog", no_argument
, NULL
, ARG_LIST_CATALOG
},
204 { "dump-catalog", no_argument
, NULL
, ARG_DUMP_CATALOG
},
205 { "update-catalog",no_argument
, NULL
, ARG_UPDATE_CATALOG
},
206 { "reverse", no_argument
, NULL
, 'r' },
215 while ((c
= getopt_long(argc
, argv
, "hefo:an::qmbD:p:c:u:F:xr", options
, NULL
)) >= 0) {
224 puts(PACKAGE_STRING
);
225 puts(SYSTEMD_FEATURES
);
233 arg_pager_end
= true;
245 arg_output
= output_mode_from_string(optarg
);
246 if (arg_output
< 0) {
247 log_error("Unknown output format '%s'.", optarg
);
251 if (arg_output
== OUTPUT_EXPORT
||
252 arg_output
== OUTPUT_JSON
||
253 arg_output
== OUTPUT_JSON_PRETTY
||
254 arg_output
== OUTPUT_JSON_SSE
||
255 arg_output
== OUTPUT_CAT
)
270 r
= safe_atoi(optarg
, &arg_lines
);
271 if (r
< 0 || arg_lines
< 0) {
272 log_error("Failed to parse lines '%s'", optarg
);
278 /* Hmm, no argument? Maybe the next
279 * word on the command line is
280 * supposed to be the argument? Let's
281 * see if there is one, and is
282 * parsable as a positive
286 safe_atoi(argv
[optind
], &n
) >= 0 &&
302 arg_action
= ACTION_NEW_ID128
;
314 arg_this_boot
= true;
318 arg_directory
= optarg
;
326 arg_action
= ACTION_PRINT_HEADER
;
330 arg_action
= ACTION_VERIFY
;
334 arg_action
= ACTION_DISK_USAGE
;
339 arg_action
= ACTION_SETUP_KEYS
;
344 arg_action
= ACTION_VERIFY
;
345 arg_verify_key
= optarg
;
350 r
= parse_usec(optarg
, &arg_interval
);
351 if (r
< 0 || arg_interval
<= 0) {
352 log_error("Failed to parse sealing key change interval: %s", optarg
);
360 log_error("Forward-secure sealing not available.");
367 dots
= strstr(optarg
, "..");
373 a
= strndup(optarg
, dots
- optarg
);
377 from
= log_level_from_string(a
);
378 to
= log_level_from_string(dots
+ 2);
381 if (from
< 0 || to
< 0) {
382 log_error("Failed to parse log level range %s", optarg
);
389 for (i
= from
; i
<= to
; i
++)
390 arg_priorities
|= 1 << i
;
392 for (i
= to
; i
<= from
; i
++)
393 arg_priorities
|= 1 << i
;
399 p
= log_level_from_string(optarg
);
401 log_error("Unknown log level %s", optarg
);
407 for (i
= 0; i
<= p
; i
++)
408 arg_priorities
|= 1 << i
;
415 r
= parse_timestamp(optarg
, &arg_since
);
417 log_error("Failed to parse timestamp: %s", optarg
);
420 arg_since_set
= true;
424 r
= parse_timestamp(optarg
, &arg_until
);
426 log_error("Failed to parse timestamp: %s", optarg
);
429 arg_until_set
= true;
434 arg_unit_system
= true;
439 arg_unit_system
= false;
453 case ARG_LIST_CATALOG
:
454 arg_action
= ACTION_LIST_CATALOG
;
457 case ARG_DUMP_CATALOG
:
458 arg_action
= ACTION_DUMP_CATALOG
;
461 case ARG_UPDATE_CATALOG
:
462 arg_action
= ACTION_UPDATE_CATALOG
;
470 log_error("Unknown option code %c", c
);
475 if (arg_follow
&& !arg_no_tail
&& arg_lines
< 0)
478 if (arg_since_set
&& arg_until_set
&& arg_since
> arg_until
) {
479 log_error("--since= must be before --until=.");
483 if (arg_cursor
&& arg_since_set
) {
484 log_error("Please specify either --since= or --cursor=, not both.");
488 if (arg_follow
&& arg_reverse
) {
489 log_error("Please specify either --reverse= or --follow=, not both.");
496 static int generate_new_id128(void) {
501 r
= sd_id128_randomize(&id
);
503 log_error("Failed to generate ID: %s", strerror(-r
));
507 printf("As string:\n"
508 SD_ID128_FORMAT_STR
"\n\n"
510 "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x\n\n"
512 "#define MESSAGE_XYZ SD_ID128_MAKE(",
513 SD_ID128_FORMAT_VAL(id
),
514 SD_ID128_FORMAT_VAL(id
));
515 for (i
= 0; i
< 16; i
++)
516 printf("%02x%s", id
.bytes
[i
], i
!= 15 ? "," : "");
517 fputs(")\n\n", stdout
);
519 printf("As Python constant:\n"
521 ">>> MESSAGE_XYZ = uuid.UUID('" SD_ID128_FORMAT_STR
"')\n",
522 SD_ID128_FORMAT_VAL(id
));
527 static int add_matches(sd_journal
*j
, char **args
) {
532 STRV_FOREACH(i
, args
) {
536 r
= sd_journal_add_disjunction(j
);
537 else if (path_is_absolute(*i
)) {
538 char _cleanup_free_
*p
, *t
= NULL
;
542 p
= canonicalize_file_name(*i
);
545 if (stat(path
, &st
) < 0) {
546 log_error("Couldn't stat file: %m");
550 if (S_ISREG(st
.st_mode
) && (0111 & st
.st_mode
))
551 t
= strappend("_EXE=", path
);
552 else if (S_ISCHR(st
.st_mode
))
553 asprintf(&t
, "_KERNEL_DEVICE=c%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
554 else if (S_ISBLK(st
.st_mode
))
555 asprintf(&t
, "_KERNEL_DEVICE=b%u:%u", major(st
.st_rdev
), minor(st
.st_rdev
));
557 log_error("File is not a device node, regular file or is not executable: %s", *i
);
564 r
= sd_journal_add_match(j
, t
, 0);
566 r
= sd_journal_add_match(j
, *i
, 0);
569 log_error("Failed to add match '%s': %s", *i
, strerror(-r
));
577 static int add_this_boot(sd_journal
*j
) {
578 char match
[9+32+1] = "_BOOT_ID=";
587 r
= sd_id128_get_boot(&boot_id
);
589 log_error("Failed to get boot id: %s", strerror(-r
));
593 sd_id128_to_string(boot_id
, match
+ 9);
594 r
= sd_journal_add_match(j
, match
, strlen(match
));
596 log_error("Failed to add match: %s", strerror(-r
));
603 static int add_unit(sd_journal
*j
) {
604 _cleanup_free_
char *u
= NULL
;
609 if (isempty(arg_unit
))
612 u
= unit_name_mangle(arg_unit
);
617 r
= add_matches_for_unit(j
, u
);
619 r
= add_matches_for_user_unit(j
, u
, getuid());
626 static int add_priorities(sd_journal
*j
) {
627 char match
[] = "PRIORITY=0";
632 if (arg_priorities
== 0xFF)
635 for (i
= LOG_EMERG
; i
<= LOG_DEBUG
; i
++)
636 if (arg_priorities
& (1 << i
)) {
637 match
[sizeof(match
)-2] = '0' + i
;
639 r
= sd_journal_add_match(j
, match
, strlen(match
));
641 log_error("Failed to add match: %s", strerror(-r
));
649 static int setup_keys(void) {
651 size_t mpk_size
, seed_size
, state_size
, i
;
652 uint8_t *mpk
, *seed
, *state
;
654 int fd
= -1, r
, attr
= 0;
655 sd_id128_t machine
, boot
;
656 char *p
= NULL
, *k
= NULL
;
660 r
= sd_id128_get_machine(&machine
);
662 log_error("Failed to get machine ID: %s", strerror(-r
));
666 r
= sd_id128_get_boot(&boot
);
668 log_error("Failed to get boot ID: %s", strerror(-r
));
672 if (asprintf(&p
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss",
673 SD_ID128_FORMAT_VAL(machine
)) < 0)
676 if (access(p
, F_OK
) >= 0) {
677 log_error("Sealing key file %s exists already.", p
);
682 if (asprintf(&k
, "/var/log/journal/" SD_ID128_FORMAT_STR
"/fss.tmp.XXXXXX",
683 SD_ID128_FORMAT_VAL(machine
)) < 0) {
688 mpk_size
= FSPRG_mskinbytes(FSPRG_RECOMMENDED_SECPAR
);
689 mpk
= alloca(mpk_size
);
691 seed_size
= FSPRG_RECOMMENDED_SEEDLEN
;
692 seed
= alloca(seed_size
);
694 state_size
= FSPRG_stateinbytes(FSPRG_RECOMMENDED_SECPAR
);
695 state
= alloca(state_size
);
697 fd
= open("/dev/random", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
699 log_error("Failed to open /dev/random: %m");
704 log_info("Generating seed...");
705 l
= loop_read(fd
, seed
, seed_size
, true);
706 if (l
< 0 || (size_t) l
!= seed_size
) {
707 log_error("Failed to read random seed: %s", strerror(EIO
));
712 log_info("Generating key pair...");
713 FSPRG_GenMK(NULL
, mpk
, seed
, seed_size
, FSPRG_RECOMMENDED_SECPAR
);
715 log_info("Generating sealing key...");
716 FSPRG_GenState0(state
, mpk
, seed
, seed_size
);
718 assert(arg_interval
> 0);
720 n
= now(CLOCK_REALTIME
);
723 close_nointr_nofail(fd
);
724 fd
= mkostemp(k
, O_WRONLY
|O_CLOEXEC
|O_NOCTTY
);
726 log_error("Failed to open %s: %m", k
);
731 /* Enable secure remove, exclusion from dump, synchronous
732 * writing and in-place updating */
733 if (ioctl(fd
, FS_IOC_GETFLAGS
, &attr
) < 0)
734 log_warning("FS_IOC_GETFLAGS failed: %m");
736 attr
|= FS_SECRM_FL
|FS_NODUMP_FL
|FS_SYNC_FL
|FS_NOCOW_FL
;
738 if (ioctl(fd
, FS_IOC_SETFLAGS
, &attr
) < 0)
739 log_warning("FS_IOC_SETFLAGS failed: %m");
742 memcpy(h
.signature
, "KSHHRHLP", 8);
743 h
.machine_id
= machine
;
745 h
.header_size
= htole64(sizeof(h
));
746 h
.start_usec
= htole64(n
* arg_interval
);
747 h
.interval_usec
= htole64(arg_interval
);
748 h
.fsprg_secpar
= htole16(FSPRG_RECOMMENDED_SECPAR
);
749 h
.fsprg_state_size
= htole64(state_size
);
751 l
= loop_write(fd
, &h
, sizeof(h
), false);
752 if (l
< 0 || (size_t) l
!= sizeof(h
)) {
753 log_error("Failed to write header: %s", strerror(EIO
));
758 l
= loop_write(fd
, state
, state_size
, false);
759 if (l
< 0 || (size_t) l
!= state_size
) {
760 log_error("Failed to write state: %s", strerror(EIO
));
765 if (link(k
, p
) < 0) {
766 log_error("Failed to link file: %m");
774 "The new key pair has been generated. The " ANSI_HIGHLIGHT_ON
"secret sealing key" ANSI_HIGHLIGHT_OFF
" has been written to\n"
775 "the following local file. This key file is automatically updated when the\n"
776 "sealing key is advanced. It should not be used on multiple hosts.\n"
780 "Please write down the following " ANSI_HIGHLIGHT_ON
"secret verification key" ANSI_HIGHLIGHT_OFF
". It should be stored\n"
781 "at a safe location and should not be saved locally on disk.\n"
782 "\n\t" ANSI_HIGHLIGHT_RED_ON
, p
);
785 for (i
= 0; i
< seed_size
; i
++) {
786 if (i
> 0 && i
% 3 == 0)
788 printf("%02x", ((uint8_t*) seed
)[i
]);
791 printf("/%llx-%llx\n", (unsigned long long) n
, (unsigned long long) arg_interval
);
794 char tsb
[FORMAT_TIMESPAN_MAX
], *hn
;
797 ANSI_HIGHLIGHT_OFF
"\n"
798 "The sealing key is automatically changed every %s.\n",
799 format_timespan(tsb
, sizeof(tsb
), arg_interval
));
801 hn
= gethostname_malloc();
804 hostname_cleanup(hn
);
805 fprintf(stderr
, "\nThe keys have been generated for host %s/" SD_ID128_FORMAT_STR
".\n", hn
, SD_ID128_FORMAT_VAL(machine
));
807 fprintf(stderr
, "\nThe keys have been generated for host " SD_ID128_FORMAT_STR
".\n", SD_ID128_FORMAT_VAL(machine
));
810 /* If this is not an UTF-8 system don't print any QR codes */
811 if (is_locale_utf8()) {
812 fputs("\nTo transfer the verification key to your phone please scan the QR code below:\n\n", stderr
);
813 print_qr_code(stderr
, seed
, seed_size
, n
, arg_interval
, hn
, machine
);
823 close_nointr_nofail(fd
);
834 log_error("Forward-secure sealing not available.");
839 static int verify(sd_journal
*j
) {
846 log_show_color(true);
848 HASHMAP_FOREACH(f
, j
->files
, i
) {
850 usec_t first
, validated
, last
;
853 if (!arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
))
854 log_notice("Journal file %s has sealing enabled but verification key has not been passed using --verify-key=.", f
->path
);
857 k
= journal_file_verify(f
, arg_verify_key
, &first
, &validated
, &last
, true);
859 /* If the key was invalid give up right-away. */
862 log_warning("FAIL: %s (%s)", f
->path
, strerror(-k
));
865 char a
[FORMAT_TIMESTAMP_MAX
], b
[FORMAT_TIMESTAMP_MAX
], c
[FORMAT_TIMESPAN_MAX
];
866 log_info("PASS: %s", f
->path
);
868 if (arg_verify_key
&& JOURNAL_HEADER_SEALED(f
->header
)) {
870 log_info("=> Validated from %s to %s, final %s entries not sealed.",
871 format_timestamp(a
, sizeof(a
), first
),
872 format_timestamp(b
, sizeof(b
), validated
),
873 format_timespan(c
, sizeof(c
), last
> validated
? last
- validated
: 0));
875 log_info("=> No sealing yet, %s of entries not sealed.",
876 format_timespan(c
, sizeof(c
), last
- first
));
878 log_info("=> No sealing yet, no entries in file.");
886 static int access_check(void) {
889 /* If /var/log/journal doesn't even exist, unprivileged users have no access at all */
890 if (access("/var/log/journal", F_OK
) < 0 && geteuid() != 0 && in_group("systemd-journal") <= 0) {
891 log_error("Unprivileged users can't see messages unless persistent log storage is enabled. Users in the group 'systemd-journal' can always see messages.");
895 /* If /var/log/journal exists, try to pring a nice notice if the user lacks access to it */
896 if (!arg_quiet
&& geteuid() != 0) {
897 _cleanup_strv_free_
char **g
= NULL
;
901 have_access
= in_group("systemd-journal") > 0;
904 /* Let's enumerate all groups from the default
905 * ACL of the directory, which generally
906 * should allow access to most journal
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. Users in the group 'systemd-journal' can see all messages. Pass -q to turn this notice off.");
918 _cleanup_free_
char *s
= NULL
;
920 r
= strv_extend(&g
, "systemd-journal");
927 s
= strv_join(g
, "', '");
931 log_notice("Hint: You are currently not seeing messages from other users and the system. Users in the groups '%s' can see all messages. Pass -q to turn this notice off.", s
);
936 if (geteuid() != 0 && in_group("systemd-journal") <= 0) {
937 log_error("No access to messages. Only users in the group 'systemd-journal' can see messages.");
945 int main(int argc
, char *argv
[]) {
947 sd_journal _cleanup_journal_close_
*j
= NULL
;
948 bool need_seek
= false;
949 sd_id128_t previous_boot_id
;
950 bool previous_boot_id_valid
= false, first_line
= true;
953 setlocale(LC_ALL
, "");
954 log_parse_environment();
957 r
= parse_argv(argc
, argv
);
961 signal(SIGWINCH
, columns_lines_cache_reset
);
963 if (arg_action
== ACTION_NEW_ID128
) {
964 r
= generate_new_id128();
968 if (arg_action
== ACTION_SETUP_KEYS
) {
973 if (arg_action
== ACTION_LIST_CATALOG
||
974 arg_action
== ACTION_DUMP_CATALOG
) {
975 bool oneline
= arg_action
== ACTION_LIST_CATALOG
;
977 r
= catalog_list_items(stdout
, oneline
, argv
+ optind
);
979 r
= catalog_list(stdout
, oneline
);
981 log_error("Failed to list catalog: %s", strerror(-r
));
985 if (arg_action
== ACTION_UPDATE_CATALOG
) {
986 r
= catalog_update();
995 r
= sd_journal_open_directory(&j
, arg_directory
, 0);
997 r
= sd_journal_open(&j
, arg_merge
? 0 : SD_JOURNAL_LOCAL_ONLY
);
999 log_error("Failed to open journal: %s", strerror(-r
));
1000 return EXIT_FAILURE
;
1003 if (arg_action
== ACTION_VERIFY
) {
1008 if (arg_action
== ACTION_PRINT_HEADER
) {
1009 journal_print_header(j
);
1010 return EXIT_SUCCESS
;
1013 if (arg_action
== ACTION_DISK_USAGE
) {
1015 char sbytes
[FORMAT_BYTES_MAX
];
1017 r
= sd_journal_get_usage(j
, &bytes
);
1019 return EXIT_FAILURE
;
1021 printf("Journals take up %s on disk.\n",
1022 format_bytes(sbytes
, sizeof(sbytes
), bytes
));
1023 return EXIT_SUCCESS
;
1026 r
= add_this_boot(j
);
1028 return EXIT_FAILURE
;
1032 return EXIT_FAILURE
;
1034 r
= add_matches(j
, argv
+ optind
);
1036 return EXIT_FAILURE
;
1038 r
= add_priorities(j
);
1040 return EXIT_FAILURE
;
1042 /* Opening the fd now means the first sd_journal_wait() will actually wait */
1043 r
= sd_journal_get_fd(j
);
1045 return EXIT_FAILURE
;
1051 r
= sd_journal_query_unique(j
, arg_field
);
1053 log_error("Failed to query unique data objects: %s", strerror(-r
));
1054 return EXIT_FAILURE
;
1057 SD_JOURNAL_FOREACH_UNIQUE(j
, data
, size
) {
1060 if (arg_lines
>= 0 && n_shown
>= arg_lines
)
1063 eq
= memchr(data
, '=', size
);
1065 printf("%.*s\n", (int) (size
- ((const uint8_t*) eq
- (const uint8_t*) data
+ 1)), (const char*) eq
+ 1);
1067 printf("%.*s\n", (int) size
, (const char*) data
);
1072 return EXIT_SUCCESS
;
1076 r
= sd_journal_seek_cursor(j
, arg_cursor
);
1078 log_error("Failed to seek to cursor: %s", strerror(-r
));
1079 return EXIT_FAILURE
;
1082 r
= sd_journal_next(j
);
1084 r
= sd_journal_previous(j
);
1086 } else if (arg_since_set
&& !arg_reverse
) {
1087 r
= sd_journal_seek_realtime_usec(j
, arg_since
);
1089 log_error("Failed to seek to date: %s", strerror(-r
));
1090 return EXIT_FAILURE
;
1092 r
= sd_journal_next(j
);
1094 } else if (arg_until_set
&& arg_reverse
) {
1095 r
= sd_journal_seek_realtime_usec(j
, arg_until
);
1097 log_error("Failed to seek to date: %s", strerror(-r
));
1098 return EXIT_FAILURE
;
1100 r
= sd_journal_previous(j
);
1102 } else if (arg_lines
>= 0) {
1103 r
= sd_journal_seek_tail(j
);
1105 log_error("Failed to seek to tail: %s", strerror(-r
));
1106 return EXIT_FAILURE
;
1109 r
= sd_journal_previous_skip(j
, arg_lines
);
1111 } else if (arg_reverse
) {
1112 r
= sd_journal_seek_tail(j
);
1114 log_error("Failed to seek to tail: %s", strerror(-r
));
1115 return EXIT_FAILURE
;
1118 r
= sd_journal_previous(j
);
1121 r
= sd_journal_seek_head(j
);
1123 log_error("Failed to seek to head: %s", strerror(-r
));
1124 return EXIT_FAILURE
;
1127 r
= sd_journal_next(j
);
1131 log_error("Failed to iterate through journal: %s", strerror(-r
));
1132 return EXIT_FAILURE
;
1135 if (!arg_no_pager
&& !arg_follow
)
1136 pager_open(arg_pager_end
);
1140 char start_buf
[FORMAT_TIMESTAMP_MAX
], end_buf
[FORMAT_TIMESTAMP_MAX
];
1142 r
= sd_journal_get_cutoff_realtime_usec(j
, &start
, &end
);
1144 log_error("Failed to get cutoff: %s", strerror(-r
));
1150 printf("-- Logs begin at %s. --\n",
1151 format_timestamp(start_buf
, sizeof(start_buf
), start
));
1153 printf("-- Logs begin at %s, end at %s. --\n",
1154 format_timestamp(start_buf
, sizeof(start_buf
), start
),
1155 format_timestamp(end_buf
, sizeof(end_buf
), end
));
1160 while (arg_lines
< 0 || n_shown
< arg_lines
|| (arg_follow
&& !first_line
)) {
1165 r
= sd_journal_next(j
);
1167 r
= sd_journal_previous(j
);
1169 log_error("Failed to iterate through journal: %s", strerror(-r
));
1177 if (arg_until_set
&& !arg_reverse
) {
1180 r
= sd_journal_get_realtime_usec(j
, &usec
);
1182 log_error("Failed to determine timestamp: %s", strerror(-r
));
1185 if (usec
> arg_until
)
1189 if (arg_since_set
&& arg_reverse
) {
1192 r
= sd_journal_get_realtime_usec(j
, &usec
);
1194 log_error("Failed to determine timestamp: %s", strerror(-r
));
1197 if (usec
< arg_since
)
1204 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot_id
);
1206 if (previous_boot_id_valid
&&
1207 !sd_id128_equal(boot_id
, previous_boot_id
))
1208 printf(ANSI_HIGHLIGHT_ON
"-- Reboot --" ANSI_HIGHLIGHT_OFF
"\n");
1210 previous_boot_id
= boot_id
;
1211 previous_boot_id_valid
= true;
1216 arg_all
* OUTPUT_SHOW_ALL
|
1217 (arg_full
|| !on_tty() || pager_have()) * OUTPUT_FULL_WIDTH
|
1218 on_tty() * OUTPUT_COLOR
|
1219 arg_catalog
* OUTPUT_CATALOG
;
1221 r
= output_journal(stdout
, j
, arg_output
, 0, flags
);
1222 if (r
< 0 || ferror(stdout
))
1232 r
= sd_journal_wait(j
, (uint64_t) -1);
1234 log_error("Couldn't wait for journal event: %s", strerror(-r
));
1244 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;