1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
8 #include <sys/socket.h>
13 #include "sd-journal.h"
15 #include "alloc-util.h"
17 #include "format-util.h"
18 #include "glyph-util.h"
20 #include "hostname-util.h"
21 #include "id128-util.h"
23 #include "journal-internal.h"
24 #include "journal-util.h"
26 #include "locale-util.h"
28 #include "logs-show.h"
30 #include "namespace-util.h"
31 #include "output-mode.h"
32 #include "parse-util.h"
33 #include "pretty-print.h"
34 #include "process-util.h"
35 #include "sparse-endian.h"
36 #include "stdio-util.h"
37 #include "string-table.h"
38 #include "string-util.h"
40 #include "terminal-util.h"
41 #include "time-util.h"
45 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
46 #define PRINT_LINE_THRESHOLD 3
47 #define PRINT_CHAR_THRESHOLD 300
49 #define JSON_THRESHOLD 4096U
51 static int print_catalog(FILE *f
, sd_journal
*j
) {
52 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
53 const char *newline
, *prefix
;
58 r
= sd_journal_get_catalog(j
, &t
);
62 return log_error_errno(r
, "Failed to find catalog entry: %m");
65 prefix
= strjoina(special_glyph(SPECIAL_GLYPH_LIGHT_SHADE
), special_glyph(SPECIAL_GLYPH_LIGHT_SHADE
));
69 newline
= strjoina(ansi_normal(), "\n", ansi_grey(), prefix
, ansi_normal(), " ", ansi_green());
71 z
= strreplace(strstrip(t
), "\n", newline
);
75 fprintf(f
, "%s%s %s%s", ansi_grey(), prefix
, ansi_normal(), ansi_green());
77 fprintf(f
, "%s\n", ansi_normal());
82 static int url_from_catalog(sd_journal
*j
, char **ret
) {
83 _cleanup_free_
char *t
= NULL
, *url
= NULL
;
90 r
= sd_journal_get_catalog(j
, &t
);
94 return log_error_errno(r
, "Failed to find catalog entry: %m");
96 weblink
= find_line_startswith(t
, "Documentation:");
100 /* Skip whitespace to value */
101 weblink
+= strspn(weblink
, " \t");
103 /* Cut out till next whitespace/newline */
104 url
= strdupcspn(weblink
, WHITESPACE
);
108 if (!documentation_url_is_valid(url
))
111 *ret
= TAKE_PTR(url
);
119 static int parse_field(
125 size_t *target_len
) {
134 if (length
< field_len
)
137 if (memcmp(data
, field
, field_len
))
140 nl
= length
- field_len
;
142 buf
= newdup_suffix0(char, (const char*) data
+ field_len
, nl
);
146 free_and_replace(*target
, buf
);
154 typedef struct ParseFieldVec
{
161 #define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) { \
163 .field_len = strlen(_field), \
165 .target_len = _target_len \
168 static int parse_fieldv(
171 const ParseFieldVec
*fields
,
176 for (size_t i
= 0; i
< n_fields
; i
++) {
177 const ParseFieldVec
*f
= &fields
[i
];
179 r
= parse_field(data
, length
, f
->field
, f
->field_len
, f
->target
, f
->target_len
);
189 static int field_set_test(const Set
*fields
, const char *name
, size_t n
) {
195 s
= strndupa_safe(name
, n
);
196 return set_contains(fields
, s
);
199 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
202 if (flags
& OUTPUT_SHOW_ALL
)
205 if (l
>= PRINT_CHAR_THRESHOLD
)
208 if (!utf8_is_printable(p
, l
))
214 static bool print_multiline(
223 size_t highlight
[2]) {
225 const char *color_on
= "", *color_off
= "", *highlight_on
= "";
226 const char *pos
, *end
;
227 bool ellipsized
= false;
230 if (flags
& OUTPUT_COLOR
) {
231 get_log_colors(priority
, &color_on
, &color_off
, &highlight_on
);
233 if (audit
&& strempty(color_on
)) {
234 color_on
= ANSI_BLUE
;
235 color_off
= ANSI_NORMAL
;
239 /* A special case: make sure that we print a newline when
240 the message is empty. */
241 if (message_len
== 0)
245 pos
< message
+ message_len
;
246 pos
= end
+ 1, line
++) {
248 int len
, indent
= (line
> 0) * prefix
;
249 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
254 /* We need to figure out when we are showing not-last line, *and*
255 * will skip subsequent lines. In that case, we will put the dots
256 * at the end of the line, instead of putting dots in the middle
260 line
+ 1 == PRINT_LINE_THRESHOLD
||
261 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
263 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
264 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
266 (size_t) (pos
- message
) <= highlight
[0] &&
267 highlight
[0] < (size_t) len
) {
269 fprintf(f
, "%*s%s%.*s",
271 color_on
, (int) highlight
[0], pos
);
274 (int) (MIN((size_t) len
, highlight
[1]) - highlight
[0]),
276 if ((size_t) len
> highlight
[1])
279 (int) (len
- highlight
[1]),
281 fprintf(f
, "%s\n", color_off
);
284 fprintf(f
, "%*s%s%.*s%s\n",
286 color_on
, len
, pos
, color_off
);
290 /* Beyond this point, ellipsization will happen. */
293 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
294 if (n_columns
- prefix
> (unsigned) len
+ 3)
295 fprintf(f
, "%*s%s%.*s...%s\n",
297 color_on
, len
, pos
, color_off
);
299 _cleanup_free_
char *e
= NULL
;
301 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
302 tail_line
? 100 : 90);
304 fprintf(f
, "%*s%s%.*s%s\n",
306 color_on
, len
, pos
, color_off
);
308 fprintf(f
, "%*s%s%s%s\n",
310 color_on
, e
, color_off
);
322 static int output_timestamp_monotonic(
325 const dual_timestamp
*display_ts
,
326 const sd_id128_t
*boot_id
,
327 const dual_timestamp
*previous_display_ts
,
328 const sd_id128_t
*previous_boot_id
) {
330 int written_chars
= 0;
335 assert(previous_display_ts
);
336 assert(previous_boot_id
);
338 if (!VALID_MONOTONIC(display_ts
->monotonic
))
339 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No valid monotonic timestamp available");
341 written_chars
+= fprintf(f
, "[%5"PRI_USEC
".%06"PRI_USEC
, display_ts
->monotonic
/ USEC_PER_SEC
, display_ts
->monotonic
% USEC_PER_SEC
);
343 if (mode
== OUTPUT_SHORT_DELTA
) {
345 bool reliable_ts
= true;
347 if (VALID_MONOTONIC(previous_display_ts
->monotonic
) && sd_id128_equal(*boot_id
, *previous_boot_id
))
348 delta
= usec_sub_unsigned(display_ts
->monotonic
, previous_display_ts
->monotonic
);
349 else if (VALID_REALTIME(display_ts
->realtime
) && VALID_REALTIME(previous_display_ts
->realtime
)) {
350 delta
= usec_sub_unsigned(display_ts
->realtime
, previous_display_ts
->realtime
);
353 written_chars
+= fprintf(f
, "%16s", "");
357 written_chars
+= fprintf(f
, " <%5"PRI_USEC
".%06"PRI_USEC
"%s>", delta
/ USEC_PER_SEC
, delta
% USEC_PER_SEC
, reliable_ts
? " " : "*");
361 written_chars
+= fprintf(f
, "%s", "]");
362 return written_chars
;
365 static int output_timestamp_realtime(
370 const dual_timestamp
*display_ts
) {
372 char buf
[CONST_MAX(FORMAT_TIMESTAMP_MAX
, 64U)];
379 if (!VALID_REALTIME(display_ts
->realtime
))
380 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No valid realtime timestamp available");
382 if (IN_SET(mode
, OUTPUT_SHORT_FULL
, OUTPUT_WITH_UNIT
)) {
385 if (flags
& OUTPUT_UTC
)
386 k
= format_timestamp_style(buf
, sizeof(buf
), display_ts
->realtime
, TIMESTAMP_UTC
);
388 k
= format_timestamp(buf
, sizeof(buf
), display_ts
->realtime
);
390 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
391 "Failed to format timestamp: %" PRIu64
, display_ts
->realtime
);
397 t
= (time_t) (display_ts
->realtime
/ USEC_PER_SEC
);
401 case OUTPUT_SHORT_UNIX
:
402 xsprintf(buf
, "%10"PRI_TIME
".%06"PRIu64
, t
, display_ts
->realtime
% USEC_PER_SEC
);
405 case OUTPUT_SHORT_ISO
:
406 case OUTPUT_SHORT_ISO_PRECISE
: {
407 size_t tail
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S",
408 localtime_or_gmtime_r(&t
, &tm
, flags
& OUTPUT_UTC
));
410 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
411 "Failed to format ISO time");
413 /* No usec in strftime, need to append */
414 if (mode
== OUTPUT_SHORT_ISO_PRECISE
) {
415 assert(ELEMENTSOF(buf
) - tail
>= 7);
416 snprintf(buf
+ tail
, ELEMENTSOF(buf
) - tail
, ".%06"PRI_USEC
, display_ts
->realtime
% USEC_PER_SEC
);
420 int h
= tm
.tm_gmtoff
/ 60 / 60;
421 int m
= labs((tm
.tm_gmtoff
/ 60) % 60);
422 snprintf(buf
+ tail
, ELEMENTSOF(buf
) - tail
, "%+03d:%02d", h
, m
);
427 case OUTPUT_SHORT_PRECISE
:
429 if (strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S",
430 localtime_or_gmtime_r(&t
, &tm
, flags
& OUTPUT_UTC
)) <= 0)
431 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
432 "Failed to format syslog time");
434 if (mode
== OUTPUT_SHORT_PRECISE
) {
437 assert(sizeof(buf
) > strlen(buf
));
438 k
= sizeof(buf
) - strlen(buf
);
440 r
= snprintf(buf
+ strlen(buf
), k
, ".%06"PRIu64
, display_ts
->realtime
% USEC_PER_SEC
);
441 if (r
<= 0 || (size_t) r
>= k
) /* too long? */
442 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
),
443 "Failed to format precise time");
448 assert_not_reached();
453 return (int) strlen(buf
);
456 static int output_short(
462 const Set
*output_fields
,
463 const size_t highlight
[2],
464 const dual_timestamp
*display_ts
,
465 const sd_id128_t
*boot_id
,
466 const dual_timestamp
*previous_display_ts
,
467 const sd_id128_t
*previous_boot_id
) {
471 size_t length
, n
= 0;
472 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
,
473 *message
= NULL
, *priority
= NULL
, *transport
= NULL
,
474 *config_file
= NULL
, *unit
= NULL
, *user_unit
= NULL
, *documentation_url
= NULL
;
475 size_t hostname_len
= 0, identifier_len
= 0, comm_len
= 0, pid_len
= 0, fake_pid_len
= 0, message_len
= 0,
476 priority_len
= 0, transport_len
= 0, config_file_len
= 0,
477 unit_len
= 0, user_unit_len
= 0, documentation_url_len
= 0;
479 bool ellipsized
= false, audit
;
480 const ParseFieldVec fields
[] = {
481 PARSE_FIELD_VEC_ENTRY("_PID=", &pid
, &pid_len
),
482 PARSE_FIELD_VEC_ENTRY("_COMM=", &comm
, &comm_len
),
483 PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message
, &message_len
),
484 PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority
, &priority_len
),
485 PARSE_FIELD_VEC_ENTRY("_TRANSPORT=", &transport
, &transport_len
),
486 PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname
, &hostname_len
),
487 PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid
, &fake_pid_len
),
488 PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
),
489 PARSE_FIELD_VEC_ENTRY("CONFIG_FILE=", &config_file
, &config_file_len
),
490 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_UNIT=", &unit
, &unit_len
),
491 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_USER_UNIT=", &user_unit
, &user_unit_len
),
492 PARSE_FIELD_VEC_ENTRY("DOCUMENTATION=", &documentation_url
, &documentation_url_len
),
494 size_t highlight_shifted
[] = {highlight
? highlight
[0] : 0, highlight
? highlight
[1] : 0};
500 assert(previous_display_ts
);
501 assert(previous_boot_id
);
503 /* Set the threshold to one bigger than the actual print threshold, so that if the line is actually
504 * longer than what we're willing to print, ellipsization will occur. This way we won't output a
505 * misleading line without any indication of truncation.
507 (void) sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
509 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
510 r
= parse_fieldv(data
, length
, fields
, ELEMENTSOF(fields
));
514 if (IN_SET(r
, -EBADMSG
, -EADDRNOTAVAIL
)) {
515 log_debug_errno(r
, "Skipping message we can't read: %m");
519 return log_error_errno(r
, "Failed to get journal fields: %m");
522 log_debug("Skipping message without MESSAGE= field.");
526 if (!(flags
& OUTPUT_SHOW_ALL
))
527 strip_tab_ansi(&message
, &message_len
, highlight_shifted
);
529 if (flags
& OUTPUT_TRUNCATE_NEWLINE
)
530 truncate_nl_full(message
, &message_len
);
532 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
535 audit
= streq_ptr(transport
, "audit");
537 if (IN_SET(mode
, OUTPUT_SHORT_MONOTONIC
, OUTPUT_SHORT_DELTA
))
538 r
= output_timestamp_monotonic(f
, mode
, display_ts
, boot_id
, previous_display_ts
, previous_boot_id
);
540 r
= output_timestamp_realtime(f
, j
, mode
, flags
, display_ts
);
545 if (flags
& OUTPUT_NO_HOSTNAME
) {
546 /* Suppress display of the hostname if this is requested. */
547 hostname
= mfree(hostname
);
551 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
552 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
553 n
+= hostname_len
+ 1;
556 if (mode
== OUTPUT_WITH_UNIT
&& ((unit
&& shall_print(unit
, unit_len
, flags
)) ||
557 (user_unit
&& shall_print(user_unit
, user_unit_len
, flags
)))) {
559 fprintf(f
, " %.*s", (int) unit_len
, unit
);
564 fprintf(f
, "/%.*s", (int) user_unit_len
, user_unit
);
566 fprintf(f
, " %.*s", (int) user_unit_len
, user_unit
);
569 } else if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
570 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
571 n
+= identifier_len
+ 1;
572 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
573 fprintf(f
, " %.*s", (int) comm_len
, comm
);
576 fputs(" unknown", f
);
578 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
579 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
581 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
582 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
583 n
+= fake_pid_len
+ 2;
588 if (urlify_enabled()) {
589 _cleanup_free_
char *c
= NULL
;
591 /* Insert a hyperlink to a documentation URL before the message. Note that we don't make the
592 * whole message a hyperlink, since otherwise the whole screen might end up being just
593 * hyperlinks. Moreover, we want to be able to highlight parts of the message (such as the
594 * config file, see below) hence let's keep the documentation URL link separate. */
596 if (documentation_url
&& shall_print(documentation_url
, documentation_url_len
, flags
)) {
597 c
= strndup(documentation_url
, documentation_url_len
);
601 if (!documentation_url_is_valid(c
)) /* Eat up invalid links */
606 (void) url_from_catalog(j
, &c
); /* Acquire from catalog if not embedded in log message itself */
609 _cleanup_free_
char *urlified
= NULL
;
611 if (terminal_urlify(c
, special_glyph(SPECIAL_GLYPH_EXTERNAL_LINK
), &urlified
) >= 0) {
618 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
))
619 fprintf(f
, "[%s blob data]\n", FORMAT_BYTES(message_len
));
622 /* URLify config_file string in message, if the message starts with it.
623 * Skip URLification if the highlighted pattern overlaps. */
625 message_len
>= config_file_len
&&
626 memcmp(message
, config_file
, config_file_len
) == 0 &&
627 (message_len
== config_file_len
|| IN_SET(message
[config_file_len
], ':', ' ')) &&
628 (!highlight
|| highlight_shifted
[0] == 0 || highlight_shifted
[0] > config_file_len
)) {
630 _cleanup_free_
char *t
= NULL
, *urlified
= NULL
;
632 t
= strndup(config_file
, config_file_len
);
633 if (t
&& terminal_urlify_path(t
, NULL
, &urlified
) >= 0) {
634 size_t urlified_len
= strlen(urlified
);
635 size_t shift
= urlified_len
- config_file_len
;
638 joined
= realloc(urlified
, message_len
+ shift
);
640 memcpy(joined
+ urlified_len
, message
+ config_file_len
, message_len
- config_file_len
);
641 free_and_replace(message
, joined
);
643 message_len
+= shift
;
645 highlight_shifted
[0] += shift
;
646 highlight_shifted
[1] += shift
;
653 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, audit
,
654 message
, message_len
,
658 if (flags
& OUTPUT_CATALOG
)
659 (void) print_catalog(f
, j
);
664 static int output_verbose(
670 const Set
*output_fields
,
671 const size_t highlight
[2],
672 const dual_timestamp
*display_ts
,
673 const sd_id128_t
*boot_id
,
674 const dual_timestamp
*previous_display_ts
,
675 const sd_id128_t
*previous_boot_id
) {
679 _cleanup_free_
char *cursor
= NULL
;
680 char buf
[FORMAT_TIMESTAMP_MAX
+ 7];
681 const char *timestamp
;
688 assert(previous_display_ts
);
689 assert(previous_boot_id
);
691 (void) sd_journal_set_data_threshold(j
, 0);
693 if (!VALID_REALTIME(display_ts
->realtime
))
694 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "No valid realtime timestamp available");
696 r
= sd_journal_get_cursor(j
, &cursor
);
698 return log_error_errno(r
, "Failed to get cursor: %m");
700 timestamp
= format_timestamp_style(buf
, sizeof buf
, display_ts
->realtime
,
701 flags
& OUTPUT_UTC
? TIMESTAMP_US_UTC
: TIMESTAMP_US
);
702 fprintf(f
, "%s%s%s %s[%s]%s\n",
703 timestamp
&& (flags
& OUTPUT_COLOR
) ? ANSI_UNDERLINE
: "",
704 timestamp
?: "(no timestamp)",
705 timestamp
&& (flags
& OUTPUT_COLOR
) ? ANSI_NORMAL
: "",
706 (flags
& OUTPUT_COLOR
) ? ANSI_GREY
: "",
708 (flags
& OUTPUT_COLOR
) ? ANSI_NORMAL
: "");
710 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
711 _cleanup_free_
char *urlified
= NULL
;
712 const char *on
= "", *off
= "";
713 const char *c
, *p
= NULL
;
714 size_t fieldlen
, valuelen
;
716 c
= memchr(data
, '=', length
);
718 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid field.");
720 fieldlen
= c
- (const char*) data
;
721 if (!journal_field_valid(data
, fieldlen
, true))
722 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid field.");
724 r
= field_set_test(output_fields
, data
, fieldlen
);
730 valuelen
= length
- 1 - fieldlen
;
733 if (flags
& OUTPUT_COLOR
) {
734 if (startswith(data
, "MESSAGE=")) {
737 } else if (startswith(data
, "CONFIG_FILE=")) {
738 _cleanup_free_
char *u
= NULL
;
740 u
= memdup_suffix0(p
, valuelen
);
744 if (terminal_urlify_path(u
, NULL
, &urlified
) >= 0) {
746 valuelen
= strlen(urlified
);
749 } else if (startswith(data
, "_")) {
750 /* Highlight trusted data as such */
756 if ((flags
& OUTPUT_SHOW_ALL
) ||
757 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
758 && utf8_is_printable(data
, length
))) {
759 fprintf(f
, " %s%.*s=", on
, (int) fieldlen
, (const char*)data
);
760 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, false,
765 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
767 (int) (c
- (const char*) data
),
769 FORMAT_BYTES(length
- (c
- (const char *) data
) - 1),
775 if (flags
& OUTPUT_CATALOG
)
776 (void) print_catalog(f
, j
);
781 static int output_export(
787 const Set
*output_fields
,
788 const size_t highlight
[2],
789 const dual_timestamp
*display_ts
,
790 const sd_id128_t
*boot_id
,
791 const dual_timestamp
*previous_display_ts
,
792 const sd_id128_t
*previous_boot_id
) {
794 sd_id128_t journal_boot_id
, seqnum_id
;
795 _cleanup_free_
char *cursor
= NULL
;
796 usec_t monotonic
, realtime
;
805 assert(previous_display_ts
);
806 assert(previous_boot_id
);
808 (void) sd_journal_set_data_threshold(j
, 0);
810 r
= sd_journal_get_cursor(j
, &cursor
);
812 return log_error_errno(r
, "Failed to get cursor: %m");
814 r
= sd_journal_get_realtime_usec(j
, &realtime
);
816 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
818 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &journal_boot_id
);
820 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
822 r
= sd_journal_get_seqnum(j
, &seqnum
, &seqnum_id
);
824 return log_error_errno(r
, "Failed to get seqnum: %m");
828 "__REALTIME_TIMESTAMP=" USEC_FMT
"\n"
829 "__MONOTONIC_TIMESTAMP=" USEC_FMT
"\n"
830 "__SEQNUM=%" PRIu64
"\n"
837 SD_ID128_TO_STRING(seqnum_id
),
838 SD_ID128_TO_STRING(journal_boot_id
));
840 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
844 /* We already printed the boot id from the data in the header, hence let's suppress it here */
845 if (memory_startswith(data
, length
, "_BOOT_ID="))
848 c
= memchr(data
, '=', length
);
850 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid field.");
852 fieldlen
= c
- (const char*) data
;
853 if (!journal_field_valid(data
, fieldlen
, true))
854 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid field.");
856 r
= field_set_test(output_fields
, data
, fieldlen
);
862 if (utf8_is_printable_newline(data
, length
, false))
863 fwrite(data
, length
, 1, f
);
867 fwrite(data
, fieldlen
, 1, f
);
869 le64
= htole64(length
- fieldlen
- 1);
870 fwrite(&le64
, sizeof(le64
), 1, f
);
871 fwrite(c
+ 1, length
- fieldlen
- 1, 1, f
);
876 if (IN_SET(r
, -EADDRNOTAVAIL
, -EBADMSG
)) {
877 log_debug_errno(r
, "Skipping message we can't read: %m");
898 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
901 else if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(p
, l
)) {
902 bool not_first
= false;
908 fprintf(f
, ", %u", (uint8_t) *p
);
911 fprintf(f
, "%u", (uint8_t) *p
);
923 if (IN_SET(*p
, '"', '\\')) {
926 } else if (*p
== '\n')
928 else if ((uint8_t) *p
< ' ')
929 fprintf(f
, "\\u%04x", (uint8_t) *p
);
941 typedef struct JsonData
{
946 static JsonData
* json_data_free(JsonData
*d
) {
950 json_variant_unref(d
->name
);
951 json_variant_unref(d
->values
);
956 DEFINE_TRIVIAL_CLEANUP_FUNC(JsonData
*, json_data_free
);
958 DEFINE_HASH_OPS_WITH_VALUE_DESTRUCTOR(json_data_hash_ops_free
,
959 char, string_hash_func
, string_compare_func
,
960 JsonData
, json_data_free
);
962 static int update_json_data(
969 _cleanup_(json_variant_unrefp
) JsonVariant
*v
= NULL
;
976 if (size
== SIZE_MAX
)
977 size
= strlen(value
);
979 if (!(flags
& OUTPUT_SHOW_ALL
) && strlen(name
) + 1 + size
>= JSON_THRESHOLD
)
980 r
= json_variant_new_null(&v
);
981 else if (utf8_is_printable(value
, size
))
982 r
= json_variant_new_stringn(&v
, value
, size
);
984 r
= json_variant_new_array_bytes(&v
, value
, size
);
986 return log_error_errno(r
, "Failed to allocate JSON data: %m");
988 d
= hashmap_get(h
, name
);
990 r
= json_variant_append_array(&d
->values
, v
);
992 return log_error_errno(r
, "Failed to append JSON value into array: %m");
994 _cleanup_(json_data_freep
) JsonData
*e
= NULL
;
996 e
= new0(JsonData
, 1);
1000 r
= json_variant_new_string(&e
->name
, name
);
1002 return log_error_errno(r
, "Failed to allocate JSON name variant: %m");
1004 r
= json_variant_append_array(&e
->values
, v
);
1006 return log_error_errno(r
, "Failed to create JSON value array: %m");
1008 r
= hashmap_put(h
, json_variant_string(e
->name
), e
);
1010 return log_error_errno(r
, "Failed to insert JSON data into hashmap: %m");
1018 static int update_json_data_split(
1021 const Set
*output_fields
,
1030 assert(data
|| size
== 0);
1032 if (memory_startswith(data
, size
, "_BOOT_ID="))
1035 eq
= memchr(data
, '=', MIN(size
, JSON_THRESHOLD
));
1039 fieldlen
= eq
- (const char*) data
;
1040 if (!journal_field_valid(data
, fieldlen
, true))
1041 return log_error_errno(SYNTHETIC_ERRNO(EINVAL
), "Invalid field.");
1043 name
= strndupa_safe(data
, fieldlen
);
1044 if (output_fields
&& !set_contains(output_fields
, name
))
1047 return update_json_data(h
, flags
, name
, eq
+ 1, size
- fieldlen
- 1);
1050 static int output_json(
1056 const Set
*output_fields
,
1057 const size_t highlight
[2],
1058 const dual_timestamp
*display_ts
,
1059 const sd_id128_t
*boot_id
,
1060 const dual_timestamp
*previous_display_ts
,
1061 const sd_id128_t
*previous_boot_id
) {
1063 char usecbuf
[CONST_MAX(DECIMAL_STR_MAX(usec_t
), DECIMAL_STR_MAX(uint64_t))];
1064 _cleanup_(json_variant_unrefp
) JsonVariant
*object
= NULL
;
1065 _cleanup_hashmap_free_ Hashmap
*h
= NULL
;
1066 sd_id128_t journal_boot_id
, seqnum_id
;
1067 _cleanup_free_
char *cursor
= NULL
;
1068 usec_t realtime
, monotonic
;
1069 JsonVariant
**array
= NULL
;
1078 assert(previous_display_ts
);
1079 assert(previous_boot_id
);
1081 (void) sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
1083 r
= sd_journal_get_cursor(j
, &cursor
);
1085 return log_error_errno(r
, "Failed to get cursor: %m");
1087 r
= sd_journal_get_realtime_usec(j
, &realtime
);
1089 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
1091 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &journal_boot_id
);
1093 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
1095 r
= sd_journal_get_seqnum(j
, &seqnum
, &seqnum_id
);
1097 return log_error_errno(r
, "Failed to get seqnum: %m");
1099 h
= hashmap_new(&json_data_hash_ops_free
);
1103 r
= update_json_data(h
, flags
, "__CURSOR", cursor
, SIZE_MAX
);
1107 xsprintf(usecbuf
, USEC_FMT
, realtime
);
1108 r
= update_json_data(h
, flags
, "__REALTIME_TIMESTAMP", usecbuf
, SIZE_MAX
);
1112 xsprintf(usecbuf
, USEC_FMT
, monotonic
);
1113 r
= update_json_data(h
, flags
, "__MONOTONIC_TIMESTAMP", usecbuf
, SIZE_MAX
);
1117 r
= update_json_data(h
, flags
, "_BOOT_ID", SD_ID128_TO_STRING(journal_boot_id
), SIZE_MAX
);
1121 xsprintf(usecbuf
, USEC_FMT
, seqnum
);
1122 r
= update_json_data(h
, flags
, "__SEQNUM", usecbuf
, SIZE_MAX
);
1126 r
= update_json_data(h
, flags
, "__SEQNUM_ID", SD_ID128_TO_STRING(seqnum_id
), SIZE_MAX
);
1134 r
= sd_journal_enumerate_data(j
, &data
, &size
);
1135 if (IN_SET(r
, -EBADMSG
, -EADDRNOTAVAIL
)) {
1136 log_debug_errno(r
, "Skipping message we can't read: %m");
1140 return log_error_errno(r
, "Failed to read journal: %m");
1144 r
= update_json_data_split(h
, flags
, output_fields
, data
, size
);
1149 array
= new(JsonVariant
*, hashmap_size(h
)*2);
1153 CLEANUP_ARRAY(array
, n
, json_variant_unref_many
);
1155 HASHMAP_FOREACH(d
, h
) {
1156 assert(json_variant_elements(d
->values
) > 0);
1158 array
[n
++] = json_variant_ref(d
->name
);
1160 if (json_variant_elements(d
->values
) == 1)
1161 array
[n
++] = json_variant_ref(json_variant_by_index(d
->values
, 0));
1163 array
[n
++] = json_variant_ref(d
->values
);
1166 r
= json_variant_new_object(&object
, array
, n
);
1168 return log_error_errno(r
, "Failed to allocate JSON object: %m");
1170 return json_variant_dump(object
,
1171 output_mode_to_json_format_flags(mode
) |
1172 (FLAGS_SET(flags
, OUTPUT_COLOR
) ? JSON_FORMAT_COLOR
: 0),
1176 static int output_cat_field(
1182 const size_t highlight
[2]) {
1184 const char *color_on
= "", *color_off
= "", *highlight_on
= "";
1189 if (FLAGS_SET(flags
, OUTPUT_COLOR
))
1190 get_log_colors(prio
, &color_on
, &color_off
, &highlight_on
);
1192 r
= sd_journal_get_data(j
, field
, &data
, &l
);
1193 if (IN_SET(r
, -EBADMSG
, -EADDRNOTAVAIL
)) {
1194 log_debug_errno(r
, "Skipping message we can't read: %m");
1197 if (r
== -ENOENT
) /* An entry without the requested field */
1200 return log_error_errno(r
, "Failed to get data: %m");
1203 assert(l
>= fl
+ 1);
1204 assert(((char*) data
)[fl
] == '=');
1206 data
= (const uint8_t*) data
+ fl
+ 1;
1209 if (FLAGS_SET(flags
, OUTPUT_COLOR
)) {
1211 assert(highlight
[0] <= highlight
[1]);
1212 assert(highlight
[1] <= l
);
1215 fwrite((const char*) data
, 1, highlight
[0], f
);
1216 fputs(highlight_on
, f
);
1217 fwrite((const char*) data
+ highlight
[0], 1, highlight
[1] - highlight
[0], f
);
1219 fwrite((const char*) data
+ highlight
[1], 1, l
- highlight
[1], f
);
1220 fputs(color_off
, f
);
1223 fwrite((const char*) data
, 1, l
, f
);
1224 fputs(color_off
, f
);
1227 fwrite((const char*) data
, 1, l
, f
);
1233 static int output_cat(
1239 const Set
*output_fields
,
1240 const size_t highlight
[2],
1241 const dual_timestamp
*display_ts
,
1242 const sd_id128_t
*boot_id
,
1243 const dual_timestamp
*previous_display_ts
,
1244 const sd_id128_t
*previous_boot_id
) {
1246 int r
, prio
= LOG_INFO
;
1253 assert(previous_display_ts
);
1254 assert(previous_boot_id
);
1256 (void) sd_journal_set_data_threshold(j
, 0);
1258 if (FLAGS_SET(flags
, OUTPUT_COLOR
)) {
1262 /* Determine priority of this entry, so that we can color it nicely */
1264 r
= sd_journal_get_data(j
, "PRIORITY", &data
, &l
);
1265 if (IN_SET(r
, -EBADMSG
, -EADDRNOTAVAIL
)) {
1266 log_debug_errno(r
, "Skipping message we can't read: %m");
1271 return log_error_errno(r
, "Failed to get data: %m");
1273 /* An entry without PRIORITY */
1274 } else if (l
== 10 && memcmp(data
, "PRIORITY=", 9) == 0) {
1275 char c
= ((char*) data
)[9];
1277 if (c
>= '0' && c
<= '7')
1282 if (set_isempty(output_fields
))
1283 return output_cat_field(f
, j
, flags
, prio
, "MESSAGE", highlight
);
1285 SET_FOREACH(field
, output_fields
) {
1286 r
= output_cat_field(f
, j
, flags
, prio
, field
, streq(field
, "MESSAGE") ? highlight
: NULL
);
1294 static int get_display_timestamp(
1296 dual_timestamp
*ret_display_ts
,
1297 sd_id128_t
*ret_boot_id
) {
1300 _cleanup_free_
char *realtime
= NULL
, *monotonic
= NULL
;
1301 size_t length
= 0, realtime_len
= 0, monotonic_len
= 0;
1302 const ParseFieldVec message_fields
[] = {
1303 PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
),
1304 PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
),
1307 bool realtime_good
= false, monotonic_good
= false, boot_id_good
= false;
1310 assert(ret_display_ts
);
1311 assert(ret_boot_id
);
1313 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
1314 r
= parse_fieldv(data
, length
, message_fields
, ELEMENTSOF(message_fields
));
1318 if (realtime
&& monotonic
)
1325 realtime_good
= safe_atou64(realtime
, &ret_display_ts
->realtime
) >= 0;
1326 if (!realtime_good
|| !VALID_REALTIME(ret_display_ts
->realtime
))
1327 realtime_good
= sd_journal_get_realtime_usec(j
, &ret_display_ts
->realtime
) >= 0;
1329 ret_display_ts
->realtime
= USEC_INFINITY
;
1332 monotonic_good
= safe_atou64(monotonic
, &ret_display_ts
->monotonic
) >= 0;
1333 if (!monotonic_good
|| !VALID_MONOTONIC(ret_display_ts
->monotonic
))
1334 monotonic_good
= boot_id_good
= sd_journal_get_monotonic_usec(j
, &ret_display_ts
->monotonic
, ret_boot_id
) >= 0;
1335 if (!monotonic_good
)
1336 ret_display_ts
->monotonic
= USEC_INFINITY
;
1339 boot_id_good
= sd_journal_get_monotonic_usec(j
, NULL
, ret_boot_id
) >= 0;
1341 *ret_boot_id
= SD_ID128_NULL
;
1343 /* Restart all data before */
1344 sd_journal_restart_data(j
);
1345 sd_journal_restart_unique(j
);
1346 sd_journal_restart_fields(j
);
1351 typedef int (*output_func_t
)(
1357 const Set
*output_fields
,
1358 const size_t highlight
[2],
1359 const dual_timestamp
*display_ts
,
1360 const sd_id128_t
*boot_id
,
1361 const dual_timestamp
*previous_display_ts
,
1362 const sd_id128_t
*previous_boot_id
);
1365 static output_func_t output_funcs
[_OUTPUT_MODE_MAX
] = {
1366 [OUTPUT_SHORT
] = output_short
,
1367 [OUTPUT_SHORT_ISO
] = output_short
,
1368 [OUTPUT_SHORT_ISO_PRECISE
] = output_short
,
1369 [OUTPUT_SHORT_PRECISE
] = output_short
,
1370 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
1371 [OUTPUT_SHORT_DELTA
] = output_short
,
1372 [OUTPUT_SHORT_UNIX
] = output_short
,
1373 [OUTPUT_SHORT_FULL
] = output_short
,
1374 [OUTPUT_VERBOSE
] = output_verbose
,
1375 [OUTPUT_EXPORT
] = output_export
,
1376 [OUTPUT_JSON
] = output_json
,
1377 [OUTPUT_JSON_PRETTY
] = output_json
,
1378 [OUTPUT_JSON_SSE
] = output_json
,
1379 [OUTPUT_JSON_SEQ
] = output_json
,
1380 [OUTPUT_CAT
] = output_cat
,
1381 [OUTPUT_WITH_UNIT
] = output_short
,
1384 int show_journal_entry(
1391 const size_t highlight
[2],
1393 dual_timestamp
*previous_display_ts
,
1394 sd_id128_t
*previous_boot_id
) {
1396 dual_timestamp display_ts
= DUAL_TIMESTAMP_NULL
;
1397 sd_id128_t boot_id
= SD_ID128_NULL
;
1401 assert(mode
< _OUTPUT_MODE_MAX
);
1402 assert(previous_display_ts
);
1403 assert(previous_boot_id
);
1406 n_columns
= columns();
1408 r
= get_display_timestamp(j
, &display_ts
, &boot_id
);
1409 if (IN_SET(r
, -EBADMSG
, -EADDRNOTAVAIL
)) {
1410 log_debug_errno(r
, "Skipping message we can't read: %m");
1414 return log_error_errno(r
, "Failed to get journal fields: %m");
1416 r
= output_funcs
[mode
](
1426 previous_display_ts
,
1429 /* Store timestamp and boot ID for next iteration */
1430 *previous_display_ts
= display_ts
;
1431 *previous_boot_id
= boot_id
;
1433 if (ellipsized
&& r
> 0)
1439 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
1443 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
1446 /* Print a beginning new line if that's request, but only once
1447 * on the first line we print. */
1450 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
1466 bool need_seek
= false;
1467 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
1468 dual_timestamp previous_display_ts
= DUAL_TIMESTAMP_NULL
;
1469 sd_id128_t previous_boot_id
= SD_ID128_NULL
;
1473 assert(mode
< _OUTPUT_MODE_MAX
);
1475 if (how_many
== UINT_MAX
)
1479 r
= sd_journal_seek_tail(j
);
1481 return log_error_errno(r
, "Failed to seek to tail: %m");
1483 r
= sd_journal_previous_skip(j
, how_many
);
1485 return log_error_errno(r
, "Failed to skip previous: %m");
1492 r
= sd_journal_next(j
);
1494 return log_error_errno(r
, "Failed to iterate through journal: %m");
1502 if (not_before
> 0) {
1503 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
1505 /* -ESTALE is returned if the timestamp is not from this boot */
1509 return log_error_errno(r
, "Failed to get journal time: %m");
1511 if (usec
< not_before
)
1516 maybe_print_begin_newline(f
, &flags
);
1518 r
= show_journal_entry(
1524 /* output_fields= */ NULL
,
1525 /* highlight= */ NULL
,
1527 &previous_display_ts
,
1533 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1537 /* Check whether the cutoff line is too early */
1539 r
= sd_id128_get_boot(&boot_id
);
1541 return log_error_errno(r
, "Failed to get boot id: %m");
1543 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1545 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1547 if (r
> 0 && not_before
< cutoff
) {
1548 maybe_print_begin_newline(f
, &flags
);
1550 /* If we logged *something* and no permission error happened, than we can reliably
1551 * emit the warning about rotation. If we didn't log anything and access errors
1552 * happened, emit hint about permissions. Otherwise, give a generic message, since we
1553 * can't diagnose the issue. */
1555 bool noaccess
= journal_access_blocked(j
);
1557 if (line
== 0 && noaccess
)
1558 fprintf(f
, "Warning: some journal files were not opened due to insufficient permissions.\n");
1560 fprintf(f
, "Notice: journal has been rotated since unit was started, output may be incomplete.\n");
1562 fprintf(f
, "Warning: journal has been rotated since unit was started and some journal "
1563 "files were not opened due to insufficient permissions, output may be incomplete.\n");
1566 warn_cutoff
= false;
1572 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1573 const char *m1
, *m2
, *m3
, *m4
;
1579 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1580 m2
= strjoina("COREDUMP_UNIT=", unit
);
1581 m3
= strjoina("UNIT=", unit
);
1582 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1585 /* Look for messages from the service itself */
1586 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1588 /* Look for coredumps of the service */
1589 (r
= sd_journal_add_disjunction(j
)) ||
1590 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1591 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1592 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1594 /* Look for messages from PID 1 about this service */
1595 (r
= sd_journal_add_disjunction(j
)) ||
1596 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1597 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1599 /* Look for messages from authorized daemons about this service */
1600 (r
= sd_journal_add_disjunction(j
)) ||
1601 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1602 (r
= sd_journal_add_match(j
, m4
, 0))
1605 if (r
== 0 && endswith(unit
, ".slice")) {
1608 m5
= strjoina("_SYSTEMD_SLICE=", unit
);
1610 /* Show all messages belonging to a slice */
1612 (r
= sd_journal_add_disjunction(j
)) ||
1613 (r
= sd_journal_add_match(j
, m5
, 0))
1620 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1622 char *m1
, *m2
, *m3
, *m4
;
1623 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1628 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1629 m2
= strjoina("USER_UNIT=", unit
);
1630 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1631 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1632 sprintf(muid
, "_UID="UID_FMT
, uid
);
1635 /* Look for messages from the user service itself */
1636 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1637 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1639 /* Look for messages from systemd about this service */
1640 (r
= sd_journal_add_disjunction(j
)) ||
1641 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1642 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1644 /* Look for coredumps of the service */
1645 (r
= sd_journal_add_disjunction(j
)) ||
1646 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1647 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1648 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1650 /* Look for messages from authorized daemons about this service */
1651 (r
= sd_journal_add_disjunction(j
)) ||
1652 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1653 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1654 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1657 if (r
== 0 && endswith(unit
, ".slice")) {
1660 m5
= strjoina("_SYSTEMD_USER_SLICE=", unit
);
1662 /* Show all messages belonging to a slice */
1664 (r
= sd_journal_add_disjunction(j
)) ||
1665 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1666 (r
= sd_journal_add_match(j
, muid
, 0))
1673 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1674 _cleanup_close_pair_
int pair
[2] = PIPE_EBADF
;
1675 _cleanup_close_
int pidnsfd
= -EBADF
, mntnsfd
= -EBADF
, rootfd
= -EBADF
;
1676 char buf
[SD_ID128_UUID_STRING_MAX
];
1684 r
= container_get_leader(machine
, &pid
);
1688 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1692 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1695 r
= namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL
, 0, FORK_RESET_SIGNALS
|FORK_DEATHSIG
,
1696 pidnsfd
, mntnsfd
, -1, -1, rootfd
, &child
);
1702 pair
[0] = safe_close(pair
[0]);
1704 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1706 _exit(EXIT_FAILURE
);
1708 r
= loop_read_exact(fd
, buf
, 36, false);
1711 _exit(EXIT_FAILURE
);
1713 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1715 _exit(EXIT_FAILURE
);
1717 _exit(EXIT_SUCCESS
);
1720 pair
[1] = safe_close(pair
[1]);
1722 r
= wait_for_terminate_and_check("(sd-bootidns)", child
, 0);
1725 if (r
!= EXIT_SUCCESS
)
1728 k
= recv(pair
[0], buf
, 36, 0);
1733 r
= sd_id128_from_string(buf
, boot_id
);
1740 int add_match_boot_id(sd_journal
*j
, sd_id128_t id
) {
1741 char match
[STRLEN("_BOOT_ID=") + SD_ID128_STRING_MAX
];
1744 assert(!sd_id128_is_null(id
));
1746 sd_id128_to_string(id
, stpcpy(match
, "_BOOT_ID="));
1747 return sd_journal_add_match(j
, match
, strlen(match
));
1750 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1757 r
= get_boot_id_for_machine(machine
, &boot_id
);
1759 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1761 r
= sd_id128_get_boot(&boot_id
);
1763 return log_error_errno(r
, "Failed to get boot id: %m");
1766 r
= add_match_boot_id(j
, boot_id
);
1768 return log_error_errno(r
, "Failed to add match: %m");
1770 r
= sd_journal_add_conjunction(j
);
1772 return log_error_errno(r
, "Failed to add conjunction: %m");
1777 int show_journal_by_unit(
1780 const char *log_namespace
,
1787 int journal_open_flags
,
1791 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1795 assert(mode
< _OUTPUT_MODE_MAX
);
1801 r
= sd_journal_open_namespace(&j
, log_namespace
, journal_open_flags
| SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE
);
1803 return log_error_errno(r
, "Failed to open journal: %m");
1806 r
= add_matches_for_unit(j
, unit
);
1808 r
= add_matches_for_user_unit(j
, unit
, uid
);
1810 return log_error_errno(r
, "Failed to add unit matches: %m");
1812 r
= sd_journal_add_conjunction(j
);
1814 return log_error_errno(r
, "Failed to add conjunction: %m");
1816 r
= add_match_this_boot(j
, NULL
);
1820 if (DEBUG_LOGGING
) {
1821 _cleanup_free_
char *filter
= NULL
;
1823 filter
= journal_make_match_string(j
);
1827 log_debug("Journal filter: %s", filter
);
1830 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1833 static int discover_next_boot(
1835 sd_id128_t previous_boot_id
,
1839 _cleanup_set_free_ Set
*broken_ids
= NULL
;
1845 /* We expect the journal to be on the last position of a boot
1846 * (in relation to the direction we are going), so that the next
1847 * invocation of sd_journal_next/previous will be from a different
1848 * boot. We then collect any information we desire and then jump
1849 * to the last location of the new boot by using a _BOOT_ID match
1850 * coming from the other journal direction. */
1852 /* Make sure we aren't restricted by any _BOOT_ID matches, so that
1853 * we can actually advance to a *different* boot. */
1854 sd_journal_flush_matches(j
);
1860 r
= sd_journal_step_one(j
, !advance_older
);
1865 return 0; /* End of journal, yay. */
1868 r
= sd_journal_get_monotonic_usec(j
, NULL
, &boot
.id
);
1872 /* We iterate through this in a loop, until the boot ID differs from the previous one. Note that
1873 * normally, this will only require a single iteration, as we moved to the last entry of the previous
1874 * boot entry already. However, it might happen that the per-journal-field entry arrays are less
1875 * complete than the main entry array, and hence might reference an entry that's not actually the last
1876 * one of the boot ID as last one. Let's hence use the per-field array is initial seek position to
1877 * speed things up, but let's not trust that it is complete, and hence, manually advance as
1880 if (!sd_id128_is_null(previous_boot_id
) && sd_id128_equal(boot
.id
, previous_boot_id
))
1883 if (set_contains(broken_ids
, &boot
.id
))
1886 /* Yay, we found a new boot ID from the entry object. Let's check there exist corresponding
1887 * entries matching with the _BOOT_ID= data. */
1889 r
= add_match_boot_id(j
, boot
.id
);
1893 /* First, seek to the first (or the last when we are going upwards) occurrence of this boot ID.
1894 * You may think this is redundant. Yes, that's redundant unless the journal is corrupted.
1895 * But when the journal is corrupted, especially, badly 'truncated', then the below may fail.
1896 * See https://github.com/systemd/systemd/pull/29334#issuecomment-1736567951. */
1898 r
= sd_journal_seek_tail(j
);
1900 r
= sd_journal_seek_head(j
);
1904 r
= sd_journal_step_one(j
, 0);
1908 log_debug("Whoopsie! We found a boot ID %s but can't read its first entry. "
1909 "The journal seems to be corrupted. Ignoring the boot ID.",
1910 SD_ID128_TO_STRING(boot
.id
));
1914 r
= sd_journal_get_realtime_usec(j
, &boot
.first_usec
);
1918 /* Next, seek to the last occurrence of this boot ID. */
1920 r
= sd_journal_seek_head(j
);
1922 r
= sd_journal_seek_tail(j
);
1926 r
= sd_journal_step_one(j
, 0);
1930 log_debug("Whoopsie! We found a boot ID %s but can't read its last entry. "
1931 "The journal seems to be corrupted. Ignoring the boot ID.",
1932 SD_ID128_TO_STRING(boot
.id
));
1936 r
= sd_journal_get_realtime_usec(j
, &boot
.last_usec
);
1940 sd_journal_flush_matches(j
);
1945 /* Save the bad boot ID. */
1946 id_dup
= newdup(sd_id128_t
, &boot
.id
, 1);
1950 r
= set_ensure_consume(&broken_ids
, &id128_hash_ops_free
, id_dup
);
1954 /* Move to the previous position again. */
1955 sd_journal_flush_matches(j
);
1957 if (!sd_id128_is_null(previous_boot_id
)) {
1958 r
= add_match_boot_id(j
, previous_boot_id
);
1964 r
= sd_journal_seek_head(j
);
1966 r
= sd_journal_seek_tail(j
);
1970 r
= sd_journal_step_one(j
, 0);
1974 return log_debug_errno(SYNTHETIC_ERRNO(ENODATA
),
1975 "Whoopsie! Cannot seek to the last entry of boot %s.",
1976 SD_ID128_TO_STRING(previous_boot_id
));
1978 sd_journal_flush_matches(j
);
1982 int journal_find_boot_by_id(sd_journal
*j
, sd_id128_t boot_id
) {
1986 assert(!sd_id128_is_null(boot_id
));
1988 sd_journal_flush_matches(j
);
1990 r
= add_match_boot_id(j
, boot_id
);
1994 r
= sd_journal_seek_head(j
); /* seek to oldest */
1998 r
= sd_journal_next(j
); /* read the oldest entry */
2002 /* At this point the read pointer is positioned at the oldest occurrence of the reference boot ID.
2003 * After flushing the matches, one more invocation of _previous() will hence place us at the
2004 * following entry, which must then have an older boot ID */
2006 sd_journal_flush_matches(j
);
2010 int journal_find_boot_by_offset(sd_journal
*j
, int offset
, sd_id128_t
*ret
) {
2017 /* Adjust for the asymmetry that offset 0 is the last (and current) boot, while 1 is considered the
2018 * (chronological) first boot in the journal. */
2019 advance_older
= offset
<= 0;
2022 r
= sd_journal_seek_tail(j
); /* seek to newest */
2024 r
= sd_journal_seek_head(j
); /* seek to oldest */
2028 /* No sd_journal_next()/_previous() here.
2030 * At this point the read pointer is positioned after the newest/before the oldest entry in the whole
2031 * journal. The next invocation of _previous()/_next() will hence position us at the newest/oldest
2034 sd_id128_t boot_id
= SD_ID128_NULL
;
2035 for (int off
= !advance_older
; ; off
+= advance_older
? -1 : 1) {
2038 r
= discover_next_boot(j
, boot_id
, advance_older
, &boot
);
2042 *ret
= SD_ID128_NULL
;
2047 log_debug("Found boot ID %s by offset %i", SD_ID128_TO_STRING(boot_id
), off
);
2057 int journal_get_boots(sd_journal
*j
, BootId
**ret_boots
, size_t *ret_n_boots
) {
2058 _cleanup_free_ BootId
*boots
= NULL
;
2064 assert(ret_n_boots
);
2066 r
= sd_journal_seek_head(j
); /* seek to oldest */
2070 /* No sd_journal_next()/_previous() here.
2072 * At this point the read pointer is positioned before the oldest entry in the whole journal. The
2073 * next invocation of _next() will hence position us at the oldest entry we have. */
2075 sd_id128_t previous_boot_id
= SD_ID128_NULL
;
2079 r
= discover_next_boot(j
, previous_boot_id
, /* advance_older = */ false, &boot
);
2085 previous_boot_id
= boot
.id
;
2087 FOREACH_ARRAY(i
, boots
, n_boots
)
2088 if (sd_id128_equal(i
->id
, boot
.id
))
2089 /* The boot id is already stored, something wrong with the journal files.
2090 * Exiting as otherwise this problem would cause an infinite loop. */
2093 if (!GREEDY_REALLOC(boots
, n_boots
+ 1))
2096 boots
[n_boots
++] = boot
;
2099 *ret_boots
= TAKE_PTR(boots
);
2100 *ret_n_boots
= n_boots
;