1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2012 Lennart Poettering
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
27 #include <sys/socket.h>
33 #include "sd-journal.h"
35 #include "alloc-util.h"
37 #include "format-util.h"
39 #include "hostname-util.h"
41 #include "journal-internal.h"
43 #include "logs-show.h"
45 #include "output-mode.h"
46 #include "parse-util.h"
47 #include "process-util.h"
48 #include "sparse-endian.h"
49 #include "stdio-util.h"
50 #include "string-table.h"
51 #include "string-util.h"
53 #include "terminal-util.h"
54 #include "time-util.h"
58 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
59 #define PRINT_LINE_THRESHOLD 3
60 #define PRINT_CHAR_THRESHOLD 300
62 #define JSON_THRESHOLD 4096
64 static int print_catalog(FILE *f
, sd_journal
*j
) {
66 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
69 r
= sd_journal_get_catalog(j
, &t
);
73 z
= strreplace(strstrip(t
), "\n", "\n-- ");
84 static int parse_field(const void *data
, size_t length
, const char *field
, size_t field_len
, char **target
, size_t *target_len
) {
92 if (length
< field_len
)
95 if (memcmp(data
, field
, field_len
))
98 nl
= length
- field_len
;
101 buf
= newdup_suffix0(char, (const char*) data
+ field_len
, nl
);
114 typedef struct ParseFieldVec
{
121 #define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
122 { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
124 static int parse_fieldv(const void *data
, size_t length
, const ParseFieldVec
*fields
, unsigned n_fields
) {
127 for (i
= 0; i
< n_fields
; i
++) {
128 const ParseFieldVec
*f
= &fields
[i
];
131 r
= parse_field(data
, length
, f
->field
, f
->field_len
, f
->target
, f
->target_len
);
141 static int field_set_test(Set
*fields
, const char *name
, size_t n
) {
147 s
= strndupa(name
, n
);
151 return set_get(fields
, s
) ? 1 : 0;
154 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
157 if (flags
& OUTPUT_SHOW_ALL
)
160 if (l
>= PRINT_CHAR_THRESHOLD
)
163 if (!utf8_is_printable(p
, l
))
169 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
170 const char *color_on
= "", *color_off
= "";
171 const char *pos
, *end
;
172 bool ellipsized
= false;
175 if (flags
& OUTPUT_COLOR
) {
176 if (priority
<= LOG_ERR
) {
177 color_on
= ANSI_HIGHLIGHT_RED
;
178 color_off
= ANSI_NORMAL
;
179 } else if (priority
<= LOG_NOTICE
) {
180 color_on
= ANSI_HIGHLIGHT
;
181 color_off
= ANSI_NORMAL
;
185 /* A special case: make sure that we print a newline when
186 the message is empty. */
187 if (message_len
== 0)
191 pos
< message
+ message_len
;
192 pos
= end
+ 1, line
++) {
193 bool continuation
= line
> 0;
196 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
201 /* We need to figure out when we are showing not-last line, *and*
202 * will skip subsequent lines. In that case, we will put the dots
203 * at the end of the line, instead of putting dots in the middle
207 line
+ 1 == PRINT_LINE_THRESHOLD
||
208 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
210 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
211 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
212 fprintf(f
, "%*s%s%.*s%s\n",
213 continuation
* prefix
, "",
214 color_on
, len
, pos
, color_off
);
218 /* Beyond this point, ellipsization will happen. */
221 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
222 if (n_columns
- prefix
> (unsigned) len
+ 3)
223 fprintf(f
, "%*s%s%.*s...%s\n",
224 continuation
* prefix
, "",
225 color_on
, len
, pos
, color_off
);
227 _cleanup_free_
char *e
;
229 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
230 tail_line
? 100 : 90);
232 fprintf(f
, "%*s%s%.*s%s\n",
233 continuation
* prefix
, "",
234 color_on
, len
, pos
, color_off
);
236 fprintf(f
, "%*s%s%s%s\n",
237 continuation
* prefix
, "",
238 color_on
, e
, color_off
);
250 static int output_timestamp_monotonic(FILE *f
, sd_journal
*j
, const char *monotonic
) {
260 r
= safe_atou64(monotonic
, &t
);
262 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
264 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
266 fprintf(f
, "[%5"PRI_USEC
".%06"PRI_USEC
"]", t
/ USEC_PER_SEC
, t
% USEC_PER_SEC
);
267 return 1 + 5 + 1 + 6 + 1;
270 static int output_timestamp_realtime(FILE *f
, sd_journal
*j
, OutputMode mode
, OutputFlags flags
, const char *realtime
) {
271 char buf
[MAX(FORMAT_TIMESTAMP_MAX
, 64)];
272 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
283 r
= safe_atou64(realtime
, &x
);
285 r
= sd_journal_get_realtime_usec(j
, &x
);
287 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
289 if (x
> USEC_TIMESTAMP_FORMATTABLE_MAX
) {
290 log_error("Timestamp cannot be printed");
294 if (mode
== OUTPUT_SHORT_FULL
) {
297 if (flags
& OUTPUT_UTC
)
298 k
= format_timestamp_utc(buf
, sizeof(buf
), x
);
300 k
= format_timestamp(buf
, sizeof(buf
), x
);
302 log_error("Failed to format timestamp.");
309 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
310 t
= (time_t) (x
/ USEC_PER_SEC
);
314 case OUTPUT_SHORT_UNIX
:
315 xsprintf(buf
, "%10"PRI_TIME
".%06"PRIu64
, t
, x
% USEC_PER_SEC
);
318 case OUTPUT_SHORT_ISO
:
319 if (strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
)) <= 0) {
320 log_error("Failed to format ISO time");
325 case OUTPUT_SHORT_ISO_PRECISE
:
326 /* No usec in strftime, so we leave space and copy over */
327 if (strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t
, &tm
)) <= 0) {
328 log_error("Failed to format ISO-precise time");
331 xsprintf(usec
, "%06"PRI_USEC
, x
% USEC_PER_SEC
);
332 memcpy(buf
+ 20, usec
, 6);
336 case OUTPUT_SHORT_PRECISE
:
338 if (strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
)) <= 0) {
339 log_error("Failed to format syslog time");
343 if (mode
== OUTPUT_SHORT_PRECISE
) {
346 assert(sizeof(buf
) > strlen(buf
));
347 k
= sizeof(buf
) - strlen(buf
);
349 r
= snprintf(buf
+ strlen(buf
), k
, ".%06"PRIu64
, x
% USEC_PER_SEC
);
350 if (r
<= 0 || (size_t) r
>= k
) { /* too long? */
351 log_error("Failed to format precise time");
358 assert_not_reached("Unknown time format");
363 return (int) strlen(buf
);
366 static int output_short(
372 Set
*output_fields
) {
378 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
379 size_t hostname_len
= 0, identifier_len
= 0, comm_len
= 0, pid_len
= 0, fake_pid_len
= 0, message_len
= 0, realtime_len
= 0, monotonic_len
= 0, priority_len
= 0;
381 bool ellipsized
= false;
382 const ParseFieldVec fields
[] = {
383 PARSE_FIELD_VEC_ENTRY("_PID=", &pid
, &pid_len
),
384 PARSE_FIELD_VEC_ENTRY("_COMM=", &comm
, &comm_len
),
385 PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message
, &message_len
),
386 PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority
, &priority_len
),
387 PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname
, &hostname_len
),
388 PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid
, &fake_pid_len
),
389 PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
),
390 PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
),
391 PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
),
397 /* Set the threshold to one bigger than the actual print
398 * threshold, so that if the line is actually longer than what
399 * we're willing to print, ellipsization will occur. This way
400 * we won't output a misleading line without any indication of
403 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
405 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
407 r
= parse_fieldv(data
, length
, fields
, ELEMENTSOF(fields
));
412 log_debug_errno(r
, "Skipping message we can't read: %m");
416 return log_error_errno(r
, "Failed to get journal fields: %m");
419 log_debug("Skipping message without MESSAGE= field.");
423 if (!(flags
& OUTPUT_SHOW_ALL
))
424 strip_tab_ansi(&message
, &message_len
);
426 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
429 if (mode
== OUTPUT_SHORT_MONOTONIC
)
430 r
= output_timestamp_monotonic(f
, j
, monotonic
);
432 r
= output_timestamp_realtime(f
, j
, mode
, flags
, realtime
);
437 if (flags
& OUTPUT_NO_HOSTNAME
) {
438 /* Suppress display of the hostname if this is requested. */
439 hostname
= mfree(hostname
);
443 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
444 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
445 n
+= hostname_len
+ 1;
448 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
449 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
450 n
+= identifier_len
+ 1;
451 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
452 fprintf(f
, " %.*s", (int) comm_len
, comm
);
455 fputs(" unknown", f
);
457 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
458 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
460 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
461 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
462 n
+= fake_pid_len
+ 2;
465 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
466 char bytes
[FORMAT_BYTES_MAX
];
467 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
471 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
474 if (flags
& OUTPUT_CATALOG
)
480 static int output_verbose(
486 Set
*output_fields
) {
490 _cleanup_free_
char *cursor
= NULL
;
491 uint64_t realtime
= 0;
492 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
493 const char *timestamp
;
499 sd_journal_set_data_threshold(j
, 0);
501 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
503 log_debug("Source realtime timestamp not found");
505 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
507 _cleanup_free_
char *value
= NULL
;
509 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=",
510 STRLEN("_SOURCE_REALTIME_TIMESTAMP="), &value
,
516 r
= safe_atou64(value
, &realtime
);
518 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
522 r
= sd_journal_get_realtime_usec(j
, &realtime
);
524 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
527 r
= sd_journal_get_cursor(j
, &cursor
);
529 return log_error_errno(r
, "Failed to get cursor: %m");
531 timestamp
= flags
& OUTPUT_UTC
? format_timestamp_us_utc(ts
, sizeof ts
, realtime
)
532 : format_timestamp_us(ts
, sizeof ts
, realtime
);
533 fprintf(f
, "%s [%s]\n",
534 timestamp
?: "(no timestamp)",
537 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
540 const char *on
= "", *off
= "";
542 c
= memchr(data
, '=', length
);
544 log_error("Invalid field.");
547 fieldlen
= c
- (const char*) data
;
549 r
= field_set_test(output_fields
, data
, fieldlen
);
555 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
560 if ((flags
& OUTPUT_SHOW_ALL
) ||
561 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
562 && utf8_is_printable(data
, length
))) {
563 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
564 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
567 char bytes
[FORMAT_BYTES_MAX
];
569 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
571 (int) (c
- (const char*) data
),
573 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
581 if (flags
& OUTPUT_CATALOG
)
587 static int output_export(
593 Set
*output_fields
) {
598 usec_t realtime
, monotonic
;
599 _cleanup_free_
char *cursor
= NULL
;
605 sd_journal_set_data_threshold(j
, 0);
607 r
= sd_journal_get_realtime_usec(j
, &realtime
);
609 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
611 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
613 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
615 r
= sd_journal_get_cursor(j
, &cursor
);
617 return log_error_errno(r
, "Failed to get cursor: %m");
621 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
622 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
627 sd_id128_to_string(boot_id
, sid
));
629 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
632 /* We already printed the boot id, from the data in
633 * the header, hence let's suppress it here */
635 startswith(data
, "_BOOT_ID="))
638 c
= memchr(data
, '=', length
);
640 log_error("Invalid field.");
644 r
= field_set_test(output_fields
, data
, c
- (const char *) data
);
650 if (utf8_is_printable_newline(data
, length
, false))
651 fwrite(data
, length
, 1, f
);
655 fwrite(data
, c
- (const char*) data
, 1, f
);
657 le64
= htole64(length
- (c
- (const char*) data
) - 1);
658 fwrite(&le64
, sizeof(le64
), 1, f
);
659 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
682 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
685 else if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(p
, l
)) {
686 bool not_first
= false;
692 fprintf(f
, ", %u", (uint8_t) *p
);
695 fprintf(f
, "%u", (uint8_t) *p
);
707 if (IN_SET(*p
, '"', '\\')) {
710 } else if (*p
== '\n')
712 else if ((uint8_t) *p
< ' ')
713 fprintf(f
, "\\u%04x", (uint8_t) *p
);
725 static int output_json(
731 Set
*output_fields
) {
733 uint64_t realtime
, monotonic
;
734 _cleanup_free_
char *cursor
= NULL
;
741 bool done
, separator
;
745 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
747 r
= sd_journal_get_realtime_usec(j
, &realtime
);
749 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
751 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
753 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
755 r
= sd_journal_get_cursor(j
, &cursor
);
757 return log_error_errno(r
, "Failed to get cursor: %m");
759 if (mode
== OUTPUT_JSON_PRETTY
)
762 "\t\"__CURSOR\" : \"%s\",\n"
763 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
764 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
765 "\t\"_BOOT_ID\" : \"%s\"",
769 sd_id128_to_string(boot_id
, sid
));
771 if (mode
== OUTPUT_JSON_SSE
)
775 "{ \"__CURSOR\" : \"%s\", "
776 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
777 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
778 "\"_BOOT_ID\" : \"%s\"",
782 sd_id128_to_string(boot_id
, sid
));
785 h
= hashmap_new(&string_hash_ops
);
789 /* First round, iterate through the entry and count how often each field appears */
790 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
796 memcmp(data
, "_BOOT_ID=", 9) == 0)
799 eq
= memchr(data
, '=', length
);
803 n
= strndup(data
, eq
- (const char*) data
);
809 u
= PTR_TO_UINT(hashmap_get(h
, n
));
811 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
818 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
834 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
840 /* We already printed the boot id, from the data in
841 * the header, hence let's suppress it here */
843 memcmp(data
, "_BOOT_ID=", 9) == 0)
846 eq
= memchr(data
, '=', length
);
850 m
= eq
- (const char*) data
;
852 n
= strndup(data
, m
);
858 if (output_fields
&& !set_get(output_fields
, n
)) {
864 if (mode
== OUTPUT_JSON_PRETTY
)
870 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
872 /* We already printed this, let's jump to the next */
878 /* Field only appears once, output it directly */
880 json_escape(f
, data
, m
, flags
);
883 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
885 hashmap_remove(h
, n
);
894 /* Field appears multiple times, output it as array */
895 json_escape(f
, data
, m
, flags
);
897 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
899 /* Iterate through the end of the list */
901 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
905 if (memcmp(data
, n
, m
) != 0)
908 if (((const char*) data
)[m
] != '=')
912 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
917 hashmap_remove(h
, n
);
921 /* Iterate data fields form the beginning */
931 if (mode
== OUTPUT_JSON_PRETTY
)
933 else if (mode
== OUTPUT_JSON_SSE
)
941 while ((k
= hashmap_steal_first_key(h
)))
949 static int output_cat(
955 Set
*output_fields
) {
964 sd_journal_set_data_threshold(j
, 0);
966 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
968 /* An entry without MESSAGE=? */
972 return log_error_errno(r
, "Failed to get data: %m");
977 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
983 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
989 Set
*output_fields
) = {
991 [OUTPUT_SHORT
] = output_short
,
992 [OUTPUT_SHORT_ISO
] = output_short
,
993 [OUTPUT_SHORT_ISO_PRECISE
] = output_short
,
994 [OUTPUT_SHORT_PRECISE
] = output_short
,
995 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
996 [OUTPUT_SHORT_UNIX
] = output_short
,
997 [OUTPUT_SHORT_FULL
] = output_short
,
998 [OUTPUT_VERBOSE
] = output_verbose
,
999 [OUTPUT_EXPORT
] = output_export
,
1000 [OUTPUT_JSON
] = output_json
,
1001 [OUTPUT_JSON_PRETTY
] = output_json
,
1002 [OUTPUT_JSON_SSE
] = output_json
,
1003 [OUTPUT_CAT
] = output_cat
1012 char **output_fields
,
1016 _cleanup_set_free_free_ Set
*fields
= NULL
;
1018 assert(mode
< _OUTPUT_MODE_MAX
);
1021 n_columns
= columns();
1023 if (output_fields
) {
1024 fields
= set_new(&string_hash_ops
);
1028 ret
= set_put_strdupv(fields
, output_fields
);
1033 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
, fields
);
1035 if (ellipsized
&& ret
> 0)
1041 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
1045 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
1048 /* Print a beginning new line if that's request, but only once
1049 * on the first line we print. */
1052 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
1056 static int show_journal(FILE *f
,
1067 bool need_seek
= false;
1068 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
1072 assert(mode
< _OUTPUT_MODE_MAX
);
1075 r
= sd_journal_seek_tail(j
);
1077 return log_error_errno(r
, "Failed to seek to tail: %m");
1079 r
= sd_journal_previous_skip(j
, how_many
);
1081 return log_error_errno(r
, "Failed to skip previous: %m");
1088 r
= sd_journal_next(j
);
1090 return log_error_errno(r
, "Failed to iterate through journal: %m");
1098 if (not_before
> 0) {
1099 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
1101 /* -ESTALE is returned if the
1102 timestamp is not from this boot */
1106 return log_error_errno(r
, "Failed to get journal time: %m");
1108 if (usec
< not_before
)
1113 maybe_print_begin_newline(f
, &flags
);
1115 r
= output_journal(f
, j
, mode
, n_columns
, flags
, NULL
, ellipsized
);
1120 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1124 /* Check whether the cutoff line is too early */
1126 r
= sd_id128_get_boot(&boot_id
);
1128 return log_error_errno(r
, "Failed to get boot id: %m");
1130 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1132 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1134 if (r
> 0 && not_before
< cutoff
) {
1135 maybe_print_begin_newline(f
, &flags
);
1136 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1139 warn_cutoff
= false;
1142 if (!(flags
& OUTPUT_FOLLOW
))
1145 r
= sd_journal_wait(j
, USEC_INFINITY
);
1147 return log_error_errno(r
, "Failed to wait for journal: %m");
1154 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1155 const char *m1
, *m2
, *m3
, *m4
;
1161 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1162 m2
= strjoina("COREDUMP_UNIT=", unit
);
1163 m3
= strjoina("UNIT=", unit
);
1164 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1167 /* Look for messages from the service itself */
1168 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1170 /* Look for coredumps of the service */
1171 (r
= sd_journal_add_disjunction(j
)) ||
1172 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1173 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1174 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1176 /* Look for messages from PID 1 about this service */
1177 (r
= sd_journal_add_disjunction(j
)) ||
1178 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1179 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1181 /* Look for messages from authorized daemons about this service */
1182 (r
= sd_journal_add_disjunction(j
)) ||
1183 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1184 (r
= sd_journal_add_match(j
, m4
, 0))
1187 if (r
== 0 && endswith(unit
, ".slice")) {
1190 m5
= strjoina("_SYSTEMD_SLICE=", unit
);
1192 /* Show all messages belonging to a slice */
1194 (r
= sd_journal_add_disjunction(j
)) ||
1195 (r
= sd_journal_add_match(j
, m5
, 0))
1202 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1204 char *m1
, *m2
, *m3
, *m4
;
1205 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1210 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1211 m2
= strjoina("USER_UNIT=", unit
);
1212 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1213 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1214 sprintf(muid
, "_UID="UID_FMT
, uid
);
1217 /* Look for messages from the user service itself */
1218 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1219 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1221 /* Look for messages from systemd about this service */
1222 (r
= sd_journal_add_disjunction(j
)) ||
1223 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1224 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1226 /* Look for coredumps of the service */
1227 (r
= sd_journal_add_disjunction(j
)) ||
1228 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1229 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1230 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1232 /* Look for messages from authorized daemons about this service */
1233 (r
= sd_journal_add_disjunction(j
)) ||
1234 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1235 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1236 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1239 if (r
== 0 && endswith(unit
, ".slice")) {
1242 m5
= strjoina("_SYSTEMD_SLICE=", unit
);
1244 /* Show all messages belonging to a slice */
1246 (r
= sd_journal_add_disjunction(j
)) ||
1247 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1248 (r
= sd_journal_add_match(j
, muid
, 0))
1255 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1256 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1257 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1267 if (!machine_name_is_valid(machine
))
1270 r
= container_get_leader(machine
, &pid
);
1274 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1278 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1288 pair
[0] = safe_close(pair
[0]);
1290 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1292 _exit(EXIT_FAILURE
);
1294 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1296 _exit(EXIT_FAILURE
);
1298 r
= loop_read_exact(fd
, buf
, 36, false);
1301 _exit(EXIT_FAILURE
);
1303 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1305 _exit(EXIT_FAILURE
);
1307 _exit(EXIT_SUCCESS
);
1310 pair
[1] = safe_close(pair
[1]);
1312 r
= wait_for_terminate(child
, &si
);
1313 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1314 return r
< 0 ? r
: -EIO
;
1316 k
= recv(pair
[0], buf
, 36, 0);
1321 r
= sd_id128_from_string(buf
, boot_id
);
1328 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1329 char match
[9+32+1] = "_BOOT_ID=";
1336 r
= get_boot_id_for_machine(machine
, &boot_id
);
1338 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1340 r
= sd_id128_get_boot(&boot_id
);
1342 return log_error_errno(r
, "Failed to get boot id: %m");
1345 sd_id128_to_string(boot_id
, match
+ 9);
1346 r
= sd_journal_add_match(j
, match
, strlen(match
));
1348 return log_error_errno(r
, "Failed to add match: %m");
1350 r
= sd_journal_add_conjunction(j
);
1352 return log_error_errno(r
, "Failed to add conjunction: %m");
1357 int show_journal_by_unit(
1366 int journal_open_flags
,
1370 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1374 assert(mode
< _OUTPUT_MODE_MAX
);
1380 r
= sd_journal_open(&j
, journal_open_flags
);
1382 return log_error_errno(r
, "Failed to open journal: %m");
1384 r
= add_match_this_boot(j
, NULL
);
1389 r
= add_matches_for_unit(j
, unit
);
1391 r
= add_matches_for_user_unit(j
, unit
, uid
);
1393 return log_error_errno(r
, "Failed to add unit matches: %m");
1395 if (DEBUG_LOGGING
) {
1396 _cleanup_free_
char *filter
;
1398 filter
= journal_make_match_string(j
);
1402 log_debug("Journal filter: %s", filter
);
1405 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);