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=", strlen("_SOURCE_REALTIME_TIMESTAMP="), &value
, NULL
);
514 r
= safe_atou64(value
, &realtime
);
516 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
520 r
= sd_journal_get_realtime_usec(j
, &realtime
);
522 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
525 r
= sd_journal_get_cursor(j
, &cursor
);
527 return log_error_errno(r
, "Failed to get cursor: %m");
529 timestamp
= flags
& OUTPUT_UTC
? format_timestamp_us_utc(ts
, sizeof ts
, realtime
)
530 : format_timestamp_us(ts
, sizeof ts
, realtime
);
531 fprintf(f
, "%s [%s]\n",
532 timestamp
?: "(no timestamp)",
535 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
538 const char *on
= "", *off
= "";
540 c
= memchr(data
, '=', length
);
542 log_error("Invalid field.");
545 fieldlen
= c
- (const char*) data
;
547 r
= field_set_test(output_fields
, data
, fieldlen
);
553 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
558 if ((flags
& OUTPUT_SHOW_ALL
) ||
559 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
560 && utf8_is_printable(data
, length
))) {
561 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
562 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
565 char bytes
[FORMAT_BYTES_MAX
];
567 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
569 (int) (c
- (const char*) data
),
571 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
579 if (flags
& OUTPUT_CATALOG
)
585 static int output_export(
591 Set
*output_fields
) {
596 usec_t realtime
, monotonic
;
597 _cleanup_free_
char *cursor
= NULL
;
603 sd_journal_set_data_threshold(j
, 0);
605 r
= sd_journal_get_realtime_usec(j
, &realtime
);
607 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
609 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
611 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
613 r
= sd_journal_get_cursor(j
, &cursor
);
615 return log_error_errno(r
, "Failed to get cursor: %m");
619 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
620 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
625 sd_id128_to_string(boot_id
, sid
));
627 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
630 /* We already printed the boot id, from the data in
631 * the header, hence let's suppress it here */
633 startswith(data
, "_BOOT_ID="))
636 c
= memchr(data
, '=', length
);
638 log_error("Invalid field.");
642 r
= field_set_test(output_fields
, data
, c
- (const char *) data
);
648 if (utf8_is_printable_newline(data
, length
, false))
649 fwrite(data
, length
, 1, f
);
653 fwrite(data
, c
- (const char*) data
, 1, f
);
655 le64
= htole64(length
- (c
- (const char*) data
) - 1);
656 fwrite(&le64
, sizeof(le64
), 1, f
);
657 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
680 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
683 else if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(p
, l
)) {
684 bool not_first
= false;
690 fprintf(f
, ", %u", (uint8_t) *p
);
693 fprintf(f
, "%u", (uint8_t) *p
);
705 if (IN_SET(*p
, '"', '\\')) {
708 } else if (*p
== '\n')
710 else if ((uint8_t) *p
< ' ')
711 fprintf(f
, "\\u%04x", (uint8_t) *p
);
723 static int output_json(
729 Set
*output_fields
) {
731 uint64_t realtime
, monotonic
;
732 _cleanup_free_
char *cursor
= NULL
;
739 bool done
, separator
;
743 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
745 r
= sd_journal_get_realtime_usec(j
, &realtime
);
747 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
749 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
751 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
753 r
= sd_journal_get_cursor(j
, &cursor
);
755 return log_error_errno(r
, "Failed to get cursor: %m");
757 if (mode
== OUTPUT_JSON_PRETTY
)
760 "\t\"__CURSOR\" : \"%s\",\n"
761 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
762 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
763 "\t\"_BOOT_ID\" : \"%s\"",
767 sd_id128_to_string(boot_id
, sid
));
769 if (mode
== OUTPUT_JSON_SSE
)
773 "{ \"__CURSOR\" : \"%s\", "
774 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
775 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
776 "\"_BOOT_ID\" : \"%s\"",
780 sd_id128_to_string(boot_id
, sid
));
783 h
= hashmap_new(&string_hash_ops
);
787 /* First round, iterate through the entry and count how often each field appears */
788 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
794 memcmp(data
, "_BOOT_ID=", 9) == 0)
797 eq
= memchr(data
, '=', length
);
801 n
= strndup(data
, eq
- (const char*) data
);
807 u
= PTR_TO_UINT(hashmap_get(h
, n
));
809 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
816 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
832 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
838 /* We already printed the boot id, from the data in
839 * the header, hence let's suppress it here */
841 memcmp(data
, "_BOOT_ID=", 9) == 0)
844 eq
= memchr(data
, '=', length
);
848 m
= eq
- (const char*) data
;
850 n
= strndup(data
, m
);
856 if (output_fields
&& !set_get(output_fields
, n
)) {
862 if (mode
== OUTPUT_JSON_PRETTY
)
868 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
870 /* We already printed this, let's jump to the next */
876 /* Field only appears once, output it directly */
878 json_escape(f
, data
, m
, flags
);
881 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
883 hashmap_remove(h
, n
);
892 /* Field appears multiple times, output it as array */
893 json_escape(f
, data
, m
, flags
);
895 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
897 /* Iterate through the end of the list */
899 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
903 if (memcmp(data
, n
, m
) != 0)
906 if (((const char*) data
)[m
] != '=')
910 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
915 hashmap_remove(h
, n
);
919 /* Iterate data fields form the beginning */
929 if (mode
== OUTPUT_JSON_PRETTY
)
931 else if (mode
== OUTPUT_JSON_SSE
)
939 while ((k
= hashmap_steal_first_key(h
)))
947 static int output_cat(
953 Set
*output_fields
) {
962 sd_journal_set_data_threshold(j
, 0);
964 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
966 /* An entry without MESSAGE=? */
970 return log_error_errno(r
, "Failed to get data: %m");
975 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
981 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
987 Set
*output_fields
) = {
989 [OUTPUT_SHORT
] = output_short
,
990 [OUTPUT_SHORT_ISO
] = output_short
,
991 [OUTPUT_SHORT_ISO_PRECISE
] = output_short
,
992 [OUTPUT_SHORT_PRECISE
] = output_short
,
993 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
994 [OUTPUT_SHORT_UNIX
] = output_short
,
995 [OUTPUT_SHORT_FULL
] = output_short
,
996 [OUTPUT_VERBOSE
] = output_verbose
,
997 [OUTPUT_EXPORT
] = output_export
,
998 [OUTPUT_JSON
] = output_json
,
999 [OUTPUT_JSON_PRETTY
] = output_json
,
1000 [OUTPUT_JSON_SSE
] = output_json
,
1001 [OUTPUT_CAT
] = output_cat
1010 char **output_fields
,
1014 _cleanup_set_free_free_ Set
*fields
= NULL
;
1016 assert(mode
< _OUTPUT_MODE_MAX
);
1019 n_columns
= columns();
1021 if (output_fields
) {
1022 fields
= set_new(&string_hash_ops
);
1026 ret
= set_put_strdupv(fields
, output_fields
);
1031 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
, fields
);
1033 if (ellipsized
&& ret
> 0)
1039 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
1043 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
1046 /* Print a beginning new line if that's request, but only once
1047 * on the first line we print. */
1050 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
1054 static int show_journal(FILE *f
,
1065 bool need_seek
= false;
1066 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
1070 assert(mode
< _OUTPUT_MODE_MAX
);
1073 r
= sd_journal_seek_tail(j
);
1075 return log_error_errno(r
, "Failed to seek to tail: %m");
1077 r
= sd_journal_previous_skip(j
, how_many
);
1079 return log_error_errno(r
, "Failed to skip previous: %m");
1086 r
= sd_journal_next(j
);
1088 return log_error_errno(r
, "Failed to iterate through journal: %m");
1096 if (not_before
> 0) {
1097 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
1099 /* -ESTALE is returned if the
1100 timestamp is not from this boot */
1104 return log_error_errno(r
, "Failed to get journal time: %m");
1106 if (usec
< not_before
)
1111 maybe_print_begin_newline(f
, &flags
);
1113 r
= output_journal(f
, j
, mode
, n_columns
, flags
, NULL
, ellipsized
);
1118 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1122 /* Check whether the cutoff line is too early */
1124 r
= sd_id128_get_boot(&boot_id
);
1126 return log_error_errno(r
, "Failed to get boot id: %m");
1128 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1130 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1132 if (r
> 0 && not_before
< cutoff
) {
1133 maybe_print_begin_newline(f
, &flags
);
1134 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1137 warn_cutoff
= false;
1140 if (!(flags
& OUTPUT_FOLLOW
))
1143 r
= sd_journal_wait(j
, USEC_INFINITY
);
1145 return log_error_errno(r
, "Failed to wait for journal: %m");
1152 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1153 const char *m1
, *m2
, *m3
, *m4
;
1159 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1160 m2
= strjoina("COREDUMP_UNIT=", unit
);
1161 m3
= strjoina("UNIT=", unit
);
1162 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1165 /* Look for messages from the service itself */
1166 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1168 /* Look for coredumps of the service */
1169 (r
= sd_journal_add_disjunction(j
)) ||
1170 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1171 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1172 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1174 /* Look for messages from PID 1 about this service */
1175 (r
= sd_journal_add_disjunction(j
)) ||
1176 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1177 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1179 /* Look for messages from authorized daemons about this service */
1180 (r
= sd_journal_add_disjunction(j
)) ||
1181 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1182 (r
= sd_journal_add_match(j
, m4
, 0))
1185 if (r
== 0 && endswith(unit
, ".slice")) {
1188 m5
= strjoina("_SYSTEMD_SLICE=", unit
);
1190 /* Show all messages belonging to a slice */
1192 (r
= sd_journal_add_disjunction(j
)) ||
1193 (r
= sd_journal_add_match(j
, m5
, 0))
1200 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1202 char *m1
, *m2
, *m3
, *m4
;
1203 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1208 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1209 m2
= strjoina("USER_UNIT=", unit
);
1210 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1211 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1212 sprintf(muid
, "_UID="UID_FMT
, uid
);
1215 /* Look for messages from the user service itself */
1216 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1217 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1219 /* Look for messages from systemd about this service */
1220 (r
= sd_journal_add_disjunction(j
)) ||
1221 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1222 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1224 /* Look for coredumps of the service */
1225 (r
= sd_journal_add_disjunction(j
)) ||
1226 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1227 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1228 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1230 /* Look for messages from authorized daemons about this service */
1231 (r
= sd_journal_add_disjunction(j
)) ||
1232 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1233 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1234 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1237 if (r
== 0 && endswith(unit
, ".slice")) {
1240 m5
= strjoina("_SYSTEMD_SLICE=", unit
);
1242 /* Show all messages belonging to a slice */
1244 (r
= sd_journal_add_disjunction(j
)) ||
1245 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1246 (r
= sd_journal_add_match(j
, muid
, 0))
1253 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1254 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1255 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1265 if (!machine_name_is_valid(machine
))
1268 r
= container_get_leader(machine
, &pid
);
1272 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1276 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1286 pair
[0] = safe_close(pair
[0]);
1288 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1290 _exit(EXIT_FAILURE
);
1292 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1294 _exit(EXIT_FAILURE
);
1296 r
= loop_read_exact(fd
, buf
, 36, false);
1299 _exit(EXIT_FAILURE
);
1301 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1303 _exit(EXIT_FAILURE
);
1305 _exit(EXIT_SUCCESS
);
1308 pair
[1] = safe_close(pair
[1]);
1310 r
= wait_for_terminate(child
, &si
);
1311 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1312 return r
< 0 ? r
: -EIO
;
1314 k
= recv(pair
[0], buf
, 36, 0);
1319 r
= sd_id128_from_string(buf
, boot_id
);
1326 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1327 char match
[9+32+1] = "_BOOT_ID=";
1334 r
= get_boot_id_for_machine(machine
, &boot_id
);
1336 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1338 r
= sd_id128_get_boot(&boot_id
);
1340 return log_error_errno(r
, "Failed to get boot id: %m");
1343 sd_id128_to_string(boot_id
, match
+ 9);
1344 r
= sd_journal_add_match(j
, match
, strlen(match
));
1346 return log_error_errno(r
, "Failed to add match: %m");
1348 r
= sd_journal_add_conjunction(j
);
1350 return log_error_errno(r
, "Failed to add conjunction: %m");
1355 int show_journal_by_unit(
1364 int journal_open_flags
,
1368 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1372 assert(mode
< _OUTPUT_MODE_MAX
);
1378 r
= sd_journal_open(&j
, journal_open_flags
);
1380 return log_error_errno(r
, "Failed to open journal: %m");
1382 r
= add_match_this_boot(j
, NULL
);
1387 r
= add_matches_for_unit(j
, unit
);
1389 r
= add_matches_for_user_unit(j
, unit
, uid
);
1391 return log_error_errno(r
, "Failed to add unit matches: %m");
1393 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1394 _cleanup_free_
char *filter
;
1396 filter
= journal_make_match_string(j
);
1400 log_debug("Journal filter: %s", filter
);
1403 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);