]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include <sys/socket.h>
34 #include "sd-journal.h"
36 #include "alloc-util.h"
38 #include "formats-util.h"
40 #include "hostname-util.h"
42 #include "journal-internal.h"
44 #include "logs-show.h"
46 #include "output-mode.h"
47 #include "parse-util.h"
48 #include "process-util.h"
49 #include "sparse-endian.h"
50 #include "string-table.h"
51 #include "string-util.h"
52 #include "terminal-util.h"
53 #include "time-util.h"
57 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
58 #define PRINT_LINE_THRESHOLD 3
59 #define PRINT_CHAR_THRESHOLD 300
61 #define JSON_THRESHOLD 4096
63 static int print_catalog(FILE *f
, sd_journal
*j
) {
65 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
68 r
= sd_journal_get_catalog(j
, &t
);
72 z
= strreplace(strstrip(t
), "\n", "\n-- ");
83 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
96 if (memcmp(data
, field
, fl
))
104 memcpy(buf
, (const char*) data
+ fl
, nl
);
105 ((char*)buf
)[nl
] = 0;
114 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
117 if (flags
& OUTPUT_SHOW_ALL
)
120 if (l
>= PRINT_CHAR_THRESHOLD
)
123 if (!utf8_is_printable(p
, l
))
129 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
130 const char *color_on
= "", *color_off
= "";
131 const char *pos
, *end
;
132 bool ellipsized
= false;
135 if (flags
& OUTPUT_COLOR
) {
136 if (priority
<= LOG_ERR
) {
137 color_on
= ANSI_HIGHLIGHT_RED
;
138 color_off
= ANSI_NORMAL
;
139 } else if (priority
<= LOG_NOTICE
) {
140 color_on
= ANSI_HIGHLIGHT
;
141 color_off
= ANSI_NORMAL
;
145 /* A special case: make sure that we print a newline when
146 the message is empty. */
147 if (message_len
== 0)
151 pos
< message
+ message_len
;
152 pos
= end
+ 1, line
++) {
153 bool continuation
= line
> 0;
156 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
161 /* We need to figure out when we are showing not-last line, *and*
162 * will skip subsequent lines. In that case, we will put the dots
163 * at the end of the line, instead of putting dots in the middle
167 line
+ 1 == PRINT_LINE_THRESHOLD
||
168 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
170 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
171 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
172 fprintf(f
, "%*s%s%.*s%s\n",
173 continuation
* prefix
, "",
174 color_on
, len
, pos
, color_off
);
178 /* Beyond this point, ellipsization will happen. */
181 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
182 if (n_columns
- prefix
> (unsigned) len
+ 3)
183 fprintf(f
, "%*s%s%.*s...%s\n",
184 continuation
* prefix
, "",
185 color_on
, len
, pos
, color_off
);
187 _cleanup_free_
char *e
;
189 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
190 tail_line
? 100 : 90);
192 fprintf(f
, "%*s%s%.*s%s\n",
193 continuation
* prefix
, "",
194 color_on
, len
, pos
, color_off
);
196 fprintf(f
, "%*s%s%s%s\n",
197 continuation
* prefix
, "",
198 color_on
, e
, color_off
);
210 static int output_short(
221 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
222 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;
224 bool ellipsized
= false;
229 /* Set the threshold to one bigger than the actual print
230 * threshold, so that if the line is actually longer than what
231 * we're willing to print, ellipsization will occur. This way
232 * we won't output a misleading line without any indication of
235 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
237 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
239 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
245 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
251 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
257 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
263 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
269 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
275 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
281 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
287 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
293 return log_error_errno(r
, "Failed to get journal fields: %m");
296 log_debug("Skipping message without MESSAGE= field.");
300 if (!(flags
& OUTPUT_SHOW_ALL
))
301 strip_tab_ansi(&message
, &message_len
);
303 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
306 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
313 r
= safe_atou64(monotonic
, &t
);
316 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
319 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
321 fprintf(f
, "[%5llu.%06llu]",
322 (unsigned long long) (t
/ USEC_PER_SEC
),
323 (unsigned long long) (t
% USEC_PER_SEC
));
325 n
+= 1 + 5 + 1 + 6 + 1;
332 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
335 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
338 r
= safe_atou64(realtime
, &x
);
341 r
= sd_journal_get_realtime_usec(j
, &x
);
344 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
346 t
= (time_t) (x
/ USEC_PER_SEC
);
349 case OUTPUT_SHORT_ISO
:
350 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
352 case OUTPUT_SHORT_PRECISE
:
353 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
355 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
356 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
359 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
363 log_error("Failed to format time.");
371 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
372 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
373 n
+= hostname_len
+ 1;
376 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
377 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
378 n
+= identifier_len
+ 1;
379 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
380 fprintf(f
, " %.*s", (int) comm_len
, comm
);
383 fputs(" unknown", f
);
385 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
386 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
388 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
389 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
390 n
+= fake_pid_len
+ 2;
393 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
394 char bytes
[FORMAT_BYTES_MAX
];
395 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
399 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
402 if (flags
& OUTPUT_CATALOG
)
408 static int output_verbose(
417 _cleanup_free_
char *cursor
= NULL
;
419 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
425 sd_journal_set_data_threshold(j
, 0);
427 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
429 log_debug("Source realtime timestamp not found");
431 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
433 _cleanup_free_
char *value
= NULL
;
436 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
441 r
= safe_atou64(value
, &realtime
);
443 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
448 r
= sd_journal_get_realtime_usec(j
, &realtime
);
450 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
453 r
= sd_journal_get_cursor(j
, &cursor
);
455 return log_error_errno(r
, "Failed to get cursor: %m");
457 fprintf(f
, "%s [%s]\n",
459 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
460 format_timestamp_us(ts
, sizeof(ts
), realtime
),
463 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
466 const char *on
= "", *off
= "";
468 c
= memchr(data
, '=', length
);
470 log_error("Invalid field.");
473 fieldlen
= c
- (const char*) data
;
475 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
480 if (flags
& OUTPUT_SHOW_ALL
||
481 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
482 && utf8_is_printable(data
, length
))) {
483 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
484 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
487 char bytes
[FORMAT_BYTES_MAX
];
489 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
491 (int) (c
- (const char*) data
),
493 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
501 if (flags
& OUTPUT_CATALOG
)
507 static int output_export(
517 usec_t realtime
, monotonic
;
518 _cleanup_free_
char *cursor
= NULL
;
524 sd_journal_set_data_threshold(j
, 0);
526 r
= sd_journal_get_realtime_usec(j
, &realtime
);
528 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
530 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
532 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
534 r
= sd_journal_get_cursor(j
, &cursor
);
536 return log_error_errno(r
, "Failed to get cursor: %m");
540 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
541 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
546 sd_id128_to_string(boot_id
, sid
));
548 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
550 /* We already printed the boot id, from the data in
551 * the header, hence let's suppress it here */
553 startswith(data
, "_BOOT_ID="))
556 if (utf8_is_printable_newline(data
, length
, false))
557 fwrite(data
, length
, 1, f
);
562 c
= memchr(data
, '=', length
);
564 log_error("Invalid field.");
568 fwrite(data
, c
- (const char*) data
, 1, f
);
570 le64
= htole64(length
- (c
- (const char*) data
) - 1);
571 fwrite(&le64
, sizeof(le64
), 1, f
);
572 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
595 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
598 else if (!utf8_is_printable(p
, l
)) {
599 bool not_first
= false;
605 fprintf(f
, ", %u", (uint8_t) *p
);
608 fprintf(f
, "%u", (uint8_t) *p
);
620 if (*p
== '"' || *p
== '\\') {
623 } else if (*p
== '\n')
625 else if ((uint8_t) *p
< ' ')
626 fprintf(f
, "\\u%04x", (uint8_t) *p
);
638 static int output_json(
645 uint64_t realtime
, monotonic
;
646 _cleanup_free_
char *cursor
= NULL
;
653 bool done
, separator
;
657 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
659 r
= sd_journal_get_realtime_usec(j
, &realtime
);
661 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
663 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
665 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
667 r
= sd_journal_get_cursor(j
, &cursor
);
669 return log_error_errno(r
, "Failed to get cursor: %m");
671 if (mode
== OUTPUT_JSON_PRETTY
)
674 "\t\"__CURSOR\" : \"%s\",\n"
675 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
676 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
677 "\t\"_BOOT_ID\" : \"%s\"",
681 sd_id128_to_string(boot_id
, sid
));
683 if (mode
== OUTPUT_JSON_SSE
)
687 "{ \"__CURSOR\" : \"%s\", "
688 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
689 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
690 "\"_BOOT_ID\" : \"%s\"",
694 sd_id128_to_string(boot_id
, sid
));
697 h
= hashmap_new(&string_hash_ops
);
701 /* First round, iterate through the entry and count how often each field appears */
702 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
708 memcmp(data
, "_BOOT_ID=", 9) == 0)
711 eq
= memchr(data
, '=', length
);
715 n
= strndup(data
, eq
- (const char*) data
);
721 u
= PTR_TO_UINT(hashmap_get(h
, n
));
723 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
730 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
746 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
752 /* We already printed the boot id, from the data in
753 * the header, hence let's suppress it here */
755 memcmp(data
, "_BOOT_ID=", 9) == 0)
758 eq
= memchr(data
, '=', length
);
763 if (mode
== OUTPUT_JSON_PRETTY
)
769 m
= eq
- (const char*) data
;
771 n
= strndup(data
, m
);
777 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
779 /* We already printed this, let's jump to the next */
785 /* Field only appears once, output it directly */
787 json_escape(f
, data
, m
, flags
);
790 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
792 hashmap_remove(h
, n
);
801 /* Field appears multiple times, output it as array */
802 json_escape(f
, data
, m
, flags
);
804 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
806 /* Iterate through the end of the list */
808 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
812 if (memcmp(data
, n
, m
) != 0)
815 if (((const char*) data
)[m
] != '=')
819 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
824 hashmap_remove(h
, n
);
828 /* Iterate data fields form the beginning */
838 if (mode
== OUTPUT_JSON_PRETTY
)
840 else if (mode
== OUTPUT_JSON_SSE
)
848 while ((k
= hashmap_steal_first_key(h
)))
856 static int output_cat(
870 sd_journal_set_data_threshold(j
, 0);
872 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
874 /* An entry without MESSAGE=? */
878 return log_error_errno(r
, "Failed to get data: %m");
883 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
889 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
894 OutputFlags flags
) = {
896 [OUTPUT_SHORT
] = output_short
,
897 [OUTPUT_SHORT_ISO
] = output_short
,
898 [OUTPUT_SHORT_PRECISE
] = output_short
,
899 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
900 [OUTPUT_VERBOSE
] = output_verbose
,
901 [OUTPUT_EXPORT
] = output_export
,
902 [OUTPUT_JSON
] = output_json
,
903 [OUTPUT_JSON_PRETTY
] = output_json
,
904 [OUTPUT_JSON_SSE
] = output_json
,
905 [OUTPUT_CAT
] = output_cat
918 assert(mode
< _OUTPUT_MODE_MAX
);
921 n_columns
= columns();
923 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
926 if (ellipsized
&& ret
> 0)
932 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
936 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
939 /* Print a beginning new line if that's request, but only once
940 * on the first line we print. */
943 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
947 static int show_journal(FILE *f
,
958 bool need_seek
= false;
959 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
963 assert(mode
< _OUTPUT_MODE_MAX
);
966 r
= sd_journal_seek_tail(j
);
968 return log_error_errno(r
, "Failed to seek to tail: %m");
970 r
= sd_journal_previous_skip(j
, how_many
);
972 return log_error_errno(r
, "Failed to skip previous: %m");
979 r
= sd_journal_next(j
);
981 return log_error_errno(r
, "Failed to iterate through journal: %m");
989 if (not_before
> 0) {
990 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
992 /* -ESTALE is returned if the
993 timestamp is not from this boot */
997 return log_error_errno(r
, "Failed to get journal time: %m");
999 if (usec
< not_before
)
1004 maybe_print_begin_newline(f
, &flags
);
1006 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
1011 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1015 /* Check whether the cutoff line is too early */
1017 r
= sd_id128_get_boot(&boot_id
);
1019 return log_error_errno(r
, "Failed to get boot id: %m");
1021 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1023 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1025 if (r
> 0 && not_before
< cutoff
) {
1026 maybe_print_begin_newline(f
, &flags
);
1027 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1030 warn_cutoff
= false;
1033 if (!(flags
& OUTPUT_FOLLOW
))
1036 r
= sd_journal_wait(j
, USEC_INFINITY
);
1038 return log_error_errno(r
, "Failed to wait for journal: %m");
1045 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1047 char *m1
, *m2
, *m3
, *m4
;
1052 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1053 m2
= strjoina("COREDUMP_UNIT=", unit
);
1054 m3
= strjoina("UNIT=", unit
);
1055 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1058 /* Look for messages from the service itself */
1059 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1061 /* Look for coredumps of the service */
1062 (r
= sd_journal_add_disjunction(j
)) ||
1063 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1064 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1065 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1067 /* Look for messages from PID 1 about this service */
1068 (r
= sd_journal_add_disjunction(j
)) ||
1069 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1070 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1072 /* Look for messages from authorized daemons about this service */
1073 (r
= sd_journal_add_disjunction(j
)) ||
1074 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1075 (r
= sd_journal_add_match(j
, m4
, 0))
1078 if (r
== 0 && endswith(unit
, ".slice")) {
1079 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1081 /* Show all messages belonging to a slice */
1083 (r
= sd_journal_add_disjunction(j
)) ||
1084 (r
= sd_journal_add_match(j
, m5
, 0))
1091 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1093 char *m1
, *m2
, *m3
, *m4
;
1094 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1099 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1100 m2
= strjoina("USER_UNIT=", unit
);
1101 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1102 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1103 sprintf(muid
, "_UID="UID_FMT
, uid
);
1106 /* Look for messages from the user service itself */
1107 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1108 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1110 /* Look for messages from systemd about this service */
1111 (r
= sd_journal_add_disjunction(j
)) ||
1112 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1113 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1115 /* Look for coredumps of the service */
1116 (r
= sd_journal_add_disjunction(j
)) ||
1117 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1118 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1119 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1121 /* Look for messages from authorized daemons about this service */
1122 (r
= sd_journal_add_disjunction(j
)) ||
1123 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1124 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1125 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1128 if (r
== 0 && endswith(unit
, ".slice")) {
1129 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1131 /* Show all messages belonging to a slice */
1133 (r
= sd_journal_add_disjunction(j
)) ||
1134 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1135 (r
= sd_journal_add_match(j
, muid
, 0))
1142 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1143 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1144 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1154 if (!machine_name_is_valid(machine
))
1157 r
= container_get_leader(machine
, &pid
);
1161 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1165 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1175 pair
[0] = safe_close(pair
[0]);
1177 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1179 _exit(EXIT_FAILURE
);
1181 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1183 _exit(EXIT_FAILURE
);
1185 r
= loop_read_exact(fd
, buf
, 36, false);
1188 _exit(EXIT_FAILURE
);
1190 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1192 _exit(EXIT_FAILURE
);
1194 _exit(EXIT_SUCCESS
);
1197 pair
[1] = safe_close(pair
[1]);
1199 r
= wait_for_terminate(child
, &si
);
1200 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1201 return r
< 0 ? r
: -EIO
;
1203 k
= recv(pair
[0], buf
, 36, 0);
1208 r
= sd_id128_from_string(buf
, boot_id
);
1215 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1216 char match
[9+32+1] = "_BOOT_ID=";
1223 r
= get_boot_id_for_machine(machine
, &boot_id
);
1225 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1227 r
= sd_id128_get_boot(&boot_id
);
1229 return log_error_errno(r
, "Failed to get boot id: %m");
1232 sd_id128_to_string(boot_id
, match
+ 9);
1233 r
= sd_journal_add_match(j
, match
, strlen(match
));
1235 return log_error_errno(r
, "Failed to add match: %m");
1237 r
= sd_journal_add_conjunction(j
);
1239 return log_error_errno(r
, "Failed to add conjunction: %m");
1244 int show_journal_by_unit(
1253 int journal_open_flags
,
1257 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1261 assert(mode
< _OUTPUT_MODE_MAX
);
1267 r
= sd_journal_open(&j
, journal_open_flags
);
1269 return log_error_errno(r
, "Failed to open journal: %m");
1271 r
= add_match_this_boot(j
, NULL
);
1276 r
= add_matches_for_unit(j
, unit
);
1278 r
= add_matches_for_user_unit(j
, unit
, uid
);
1280 return log_error_errno(r
, "Failed to add unit matches: %m");
1282 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1283 _cleanup_free_
char *filter
;
1285 filter
= journal_make_match_string(j
);
1289 log_debug("Journal filter: %s", filter
);
1292 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1295 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1296 [OUTPUT_SHORT
] = "short",
1297 [OUTPUT_SHORT_ISO
] = "short-iso",
1298 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1299 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1300 [OUTPUT_VERBOSE
] = "verbose",
1301 [OUTPUT_EXPORT
] = "export",
1302 [OUTPUT_JSON
] = "json",
1303 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1304 [OUTPUT_JSON_SSE
] = "json-sse",
1305 [OUTPUT_CAT
] = "cat"
1308 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);