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/>.
25 #include <sys/socket.h>
29 #include "formats-util.h"
31 #include "hostname-util.h"
33 #include "journal-internal.h"
35 #include "logs-show.h"
36 #include "process-util.h"
37 #include "string-util.h"
38 #include "terminal-util.h"
42 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
43 #define PRINT_LINE_THRESHOLD 3
44 #define PRINT_CHAR_THRESHOLD 300
46 #define JSON_THRESHOLD 4096
48 static int print_catalog(FILE *f
, sd_journal
*j
) {
50 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
53 r
= sd_journal_get_catalog(j
, &t
);
57 z
= strreplace(strstrip(t
), "\n", "\n-- ");
68 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
81 if (memcmp(data
, field
, fl
))
89 memcpy(buf
, (const char*) data
+ fl
, nl
);
99 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
102 if (flags
& OUTPUT_SHOW_ALL
)
105 if (l
>= PRINT_CHAR_THRESHOLD
)
108 if (!utf8_is_printable(p
, l
))
114 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
115 const char *color_on
= "", *color_off
= "";
116 const char *pos
, *end
;
117 bool ellipsized
= false;
120 if (flags
& OUTPUT_COLOR
) {
121 if (priority
<= LOG_ERR
) {
122 color_on
= ANSI_HIGHLIGHT_RED
;
123 color_off
= ANSI_NORMAL
;
124 } else if (priority
<= LOG_NOTICE
) {
125 color_on
= ANSI_HIGHLIGHT
;
126 color_off
= ANSI_NORMAL
;
130 /* A special case: make sure that we print a newline when
131 the message is empty. */
132 if (message_len
== 0)
136 pos
< message
+ message_len
;
137 pos
= end
+ 1, line
++) {
138 bool continuation
= line
> 0;
141 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
146 /* We need to figure out when we are showing not-last line, *and*
147 * will skip subsequent lines. In that case, we will put the dots
148 * at the end of the line, instead of putting dots in the middle
152 line
+ 1 == PRINT_LINE_THRESHOLD
||
153 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
155 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
156 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
157 fprintf(f
, "%*s%s%.*s%s\n",
158 continuation
* prefix
, "",
159 color_on
, len
, pos
, color_off
);
163 /* Beyond this point, ellipsization will happen. */
166 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
167 if (n_columns
- prefix
> (unsigned) len
+ 3)
168 fprintf(f
, "%*s%s%.*s...%s\n",
169 continuation
* prefix
, "",
170 color_on
, len
, pos
, color_off
);
172 _cleanup_free_
char *e
;
174 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
175 tail_line
? 100 : 90);
177 fprintf(f
, "%*s%s%.*s%s\n",
178 continuation
* prefix
, "",
179 color_on
, len
, pos
, color_off
);
181 fprintf(f
, "%*s%s%s%s\n",
182 continuation
* prefix
, "",
183 color_on
, e
, color_off
);
195 static int output_short(
206 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
207 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;
209 bool ellipsized
= false;
214 /* Set the threshold to one bigger than the actual print
215 * threshold, so that if the line is actually longer than what
216 * we're willing to print, ellipsization will occur. This way
217 * we won't output a misleading line without any indication of
220 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
222 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
224 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
230 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
236 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
242 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
248 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
254 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
260 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
266 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
272 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
278 return log_error_errno(r
, "Failed to get journal fields: %m");
281 log_debug("Skipping message without MESSAGE= field.");
285 if (!(flags
& OUTPUT_SHOW_ALL
))
286 strip_tab_ansi(&message
, &message_len
);
288 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
291 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
298 r
= safe_atou64(monotonic
, &t
);
301 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
304 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
306 fprintf(f
, "[%5llu.%06llu]",
307 (unsigned long long) (t
/ USEC_PER_SEC
),
308 (unsigned long long) (t
% USEC_PER_SEC
));
310 n
+= 1 + 5 + 1 + 6 + 1;
317 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
320 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
323 r
= safe_atou64(realtime
, &x
);
326 r
= sd_journal_get_realtime_usec(j
, &x
);
329 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
331 t
= (time_t) (x
/ USEC_PER_SEC
);
334 case OUTPUT_SHORT_ISO
:
335 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
337 case OUTPUT_SHORT_PRECISE
:
338 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
340 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
341 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
344 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
348 log_error("Failed to format time.");
356 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
357 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
358 n
+= hostname_len
+ 1;
361 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
362 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
363 n
+= identifier_len
+ 1;
364 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
365 fprintf(f
, " %.*s", (int) comm_len
, comm
);
368 fputs(" unknown", f
);
370 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
371 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
373 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
374 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
375 n
+= fake_pid_len
+ 2;
378 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
379 char bytes
[FORMAT_BYTES_MAX
];
380 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
384 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
387 if (flags
& OUTPUT_CATALOG
)
393 static int output_verbose(
402 _cleanup_free_
char *cursor
= NULL
;
404 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
410 sd_journal_set_data_threshold(j
, 0);
412 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
414 log_debug("Source realtime timestamp not found");
416 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
418 _cleanup_free_
char *value
= NULL
;
421 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
423 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
425 r
= safe_atou64(value
, &realtime
);
427 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
432 r
= sd_journal_get_realtime_usec(j
, &realtime
);
434 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
437 r
= sd_journal_get_cursor(j
, &cursor
);
439 return log_error_errno(r
, "Failed to get cursor: %m");
441 fprintf(f
, "%s [%s]\n",
443 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
444 format_timestamp_us(ts
, sizeof(ts
), realtime
),
447 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
450 const char *on
= "", *off
= "";
452 c
= memchr(data
, '=', length
);
454 log_error("Invalid field.");
457 fieldlen
= c
- (const char*) data
;
459 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
464 if (flags
& OUTPUT_SHOW_ALL
||
465 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
466 && utf8_is_printable(data
, length
))) {
467 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
468 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
471 char bytes
[FORMAT_BYTES_MAX
];
473 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
475 (int) (c
- (const char*) data
),
477 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
485 if (flags
& OUTPUT_CATALOG
)
491 static int output_export(
501 usec_t realtime
, monotonic
;
502 _cleanup_free_
char *cursor
= NULL
;
508 sd_journal_set_data_threshold(j
, 0);
510 r
= sd_journal_get_realtime_usec(j
, &realtime
);
512 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
514 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
516 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
518 r
= sd_journal_get_cursor(j
, &cursor
);
520 return log_error_errno(r
, "Failed to get cursor: %m");
524 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
525 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
530 sd_id128_to_string(boot_id
, sid
));
532 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
534 /* We already printed the boot id, from the data in
535 * the header, hence let's suppress it here */
537 startswith(data
, "_BOOT_ID="))
540 if (utf8_is_printable_newline(data
, length
, false))
541 fwrite(data
, length
, 1, f
);
546 c
= memchr(data
, '=', length
);
548 log_error("Invalid field.");
552 fwrite(data
, c
- (const char*) data
, 1, f
);
554 le64
= htole64(length
- (c
- (const char*) data
) - 1);
555 fwrite(&le64
, sizeof(le64
), 1, f
);
556 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
579 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
582 else if (!utf8_is_printable(p
, l
)) {
583 bool not_first
= false;
589 fprintf(f
, ", %u", (uint8_t) *p
);
592 fprintf(f
, "%u", (uint8_t) *p
);
604 if (*p
== '"' || *p
== '\\') {
607 } else if (*p
== '\n')
609 else if ((uint8_t) *p
< ' ')
610 fprintf(f
, "\\u%04x", (uint8_t) *p
);
622 static int output_json(
629 uint64_t realtime
, monotonic
;
630 _cleanup_free_
char *cursor
= NULL
;
637 bool done
, separator
;
641 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
643 r
= sd_journal_get_realtime_usec(j
, &realtime
);
645 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
647 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
649 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
651 r
= sd_journal_get_cursor(j
, &cursor
);
653 return log_error_errno(r
, "Failed to get cursor: %m");
655 if (mode
== OUTPUT_JSON_PRETTY
)
658 "\t\"__CURSOR\" : \"%s\",\n"
659 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
660 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
661 "\t\"_BOOT_ID\" : \"%s\"",
665 sd_id128_to_string(boot_id
, sid
));
667 if (mode
== OUTPUT_JSON_SSE
)
671 "{ \"__CURSOR\" : \"%s\", "
672 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
673 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
674 "\"_BOOT_ID\" : \"%s\"",
678 sd_id128_to_string(boot_id
, sid
));
681 h
= hashmap_new(&string_hash_ops
);
685 /* First round, iterate through the entry and count how often each field appears */
686 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
692 memcmp(data
, "_BOOT_ID=", 9) == 0)
695 eq
= memchr(data
, '=', length
);
699 n
= strndup(data
, eq
- (const char*) data
);
705 u
= PTR_TO_UINT(hashmap_get(h
, n
));
707 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
714 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
730 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
736 /* We already printed the boot id, from the data in
737 * the header, hence let's suppress it here */
739 memcmp(data
, "_BOOT_ID=", 9) == 0)
742 eq
= memchr(data
, '=', length
);
747 if (mode
== OUTPUT_JSON_PRETTY
)
753 m
= eq
- (const char*) data
;
755 n
= strndup(data
, m
);
761 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
763 /* We already printed this, let's jump to the next */
769 /* Field only appears once, output it directly */
771 json_escape(f
, data
, m
, flags
);
774 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
776 hashmap_remove(h
, n
);
785 /* Field appears multiple times, output it as array */
786 json_escape(f
, data
, m
, flags
);
788 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
790 /* Iterate through the end of the list */
792 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
796 if (memcmp(data
, n
, m
) != 0)
799 if (((const char*) data
)[m
] != '=')
803 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
808 hashmap_remove(h
, n
);
812 /* Iterate data fields form the beginning */
822 if (mode
== OUTPUT_JSON_PRETTY
)
824 else if (mode
== OUTPUT_JSON_SSE
)
832 while ((k
= hashmap_steal_first_key(h
)))
840 static int output_cat(
854 sd_journal_set_data_threshold(j
, 0);
856 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
858 /* An entry without MESSAGE=? */
862 return log_error_errno(r
, "Failed to get data: %m");
867 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
873 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
878 OutputFlags flags
) = {
880 [OUTPUT_SHORT
] = output_short
,
881 [OUTPUT_SHORT_ISO
] = output_short
,
882 [OUTPUT_SHORT_PRECISE
] = output_short
,
883 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
884 [OUTPUT_VERBOSE
] = output_verbose
,
885 [OUTPUT_EXPORT
] = output_export
,
886 [OUTPUT_JSON
] = output_json
,
887 [OUTPUT_JSON_PRETTY
] = output_json
,
888 [OUTPUT_JSON_SSE
] = output_json
,
889 [OUTPUT_CAT
] = output_cat
902 assert(mode
< _OUTPUT_MODE_MAX
);
905 n_columns
= columns();
907 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
910 if (ellipsized
&& ret
> 0)
916 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
920 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
923 /* Print a beginning new line if that's request, but only once
924 * on the first line we print. */
927 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
931 static int show_journal(FILE *f
,
942 bool need_seek
= false;
943 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
947 assert(mode
< _OUTPUT_MODE_MAX
);
950 r
= sd_journal_seek_tail(j
);
952 return log_error_errno(r
, "Failed to seek to tail: %m");
954 r
= sd_journal_previous_skip(j
, how_many
);
956 return log_error_errno(r
, "Failed to skip previous: %m");
963 r
= sd_journal_next(j
);
965 return log_error_errno(r
, "Failed to iterate through journal: %m");
973 if (not_before
> 0) {
974 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
976 /* -ESTALE is returned if the
977 timestamp is not from this boot */
981 return log_error_errno(r
, "Failed to get journal time: %m");
983 if (usec
< not_before
)
988 maybe_print_begin_newline(f
, &flags
);
990 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
995 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
999 /* Check whether the cutoff line is too early */
1001 r
= sd_id128_get_boot(&boot_id
);
1003 return log_error_errno(r
, "Failed to get boot id: %m");
1005 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1007 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1009 if (r
> 0 && not_before
< cutoff
) {
1010 maybe_print_begin_newline(f
, &flags
);
1011 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1014 warn_cutoff
= false;
1017 if (!(flags
& OUTPUT_FOLLOW
))
1020 r
= sd_journal_wait(j
, USEC_INFINITY
);
1022 return log_error_errno(r
, "Failed to wait for journal: %m");
1029 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1031 char *m1
, *m2
, *m3
, *m4
;
1036 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1037 m2
= strjoina("COREDUMP_UNIT=", unit
);
1038 m3
= strjoina("UNIT=", unit
);
1039 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1042 /* Look for messages from the service itself */
1043 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1045 /* Look for coredumps of the service */
1046 (r
= sd_journal_add_disjunction(j
)) ||
1047 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1048 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1049 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1051 /* Look for messages from PID 1 about this service */
1052 (r
= sd_journal_add_disjunction(j
)) ||
1053 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1054 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1056 /* Look for messages from authorized daemons about this service */
1057 (r
= sd_journal_add_disjunction(j
)) ||
1058 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1059 (r
= sd_journal_add_match(j
, m4
, 0))
1062 if (r
== 0 && endswith(unit
, ".slice")) {
1063 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1065 /* Show all messages belonging to a slice */
1067 (r
= sd_journal_add_disjunction(j
)) ||
1068 (r
= sd_journal_add_match(j
, m5
, 0))
1075 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1077 char *m1
, *m2
, *m3
, *m4
;
1078 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1083 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1084 m2
= strjoina("USER_UNIT=", unit
);
1085 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1086 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1087 sprintf(muid
, "_UID="UID_FMT
, uid
);
1090 /* Look for messages from the user service itself */
1091 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1092 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1094 /* Look for messages from systemd about this service */
1095 (r
= sd_journal_add_disjunction(j
)) ||
1096 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1097 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1099 /* Look for coredumps of the service */
1100 (r
= sd_journal_add_disjunction(j
)) ||
1101 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1102 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1103 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1105 /* Look for messages from authorized daemons about this service */
1106 (r
= sd_journal_add_disjunction(j
)) ||
1107 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1108 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1109 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1112 if (r
== 0 && endswith(unit
, ".slice")) {
1113 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1115 /* Show all messages belonging to a slice */
1117 (r
= sd_journal_add_disjunction(j
)) ||
1118 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1119 (r
= sd_journal_add_match(j
, muid
, 0))
1126 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1127 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1128 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1138 if (!machine_name_is_valid(machine
))
1141 r
= container_get_leader(machine
, &pid
);
1145 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1149 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1159 pair
[0] = safe_close(pair
[0]);
1161 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1163 _exit(EXIT_FAILURE
);
1165 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1167 _exit(EXIT_FAILURE
);
1169 r
= loop_read_exact(fd
, buf
, 36, false);
1172 _exit(EXIT_FAILURE
);
1174 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1176 _exit(EXIT_FAILURE
);
1178 _exit(EXIT_SUCCESS
);
1181 pair
[1] = safe_close(pair
[1]);
1183 r
= wait_for_terminate(child
, &si
);
1184 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1185 return r
< 0 ? r
: -EIO
;
1187 k
= recv(pair
[0], buf
, 36, 0);
1192 r
= sd_id128_from_string(buf
, boot_id
);
1199 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1200 char match
[9+32+1] = "_BOOT_ID=";
1207 r
= get_boot_id_for_machine(machine
, &boot_id
);
1209 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1211 r
= sd_id128_get_boot(&boot_id
);
1213 return log_error_errno(r
, "Failed to get boot id: %m");
1216 sd_id128_to_string(boot_id
, match
+ 9);
1217 r
= sd_journal_add_match(j
, match
, strlen(match
));
1219 return log_error_errno(r
, "Failed to add match: %m");
1221 r
= sd_journal_add_conjunction(j
);
1223 return log_error_errno(r
, "Failed to add conjunction: %m");
1228 int show_journal_by_unit(
1237 int journal_open_flags
,
1241 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1245 assert(mode
< _OUTPUT_MODE_MAX
);
1251 r
= sd_journal_open(&j
, journal_open_flags
);
1253 return log_error_errno(r
, "Failed to open journal: %m");
1255 r
= add_match_this_boot(j
, NULL
);
1260 r
= add_matches_for_unit(j
, unit
);
1262 r
= add_matches_for_user_unit(j
, unit
, uid
);
1264 return log_error_errno(r
, "Failed to add unit matches: %m");
1266 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1267 _cleanup_free_
char *filter
;
1269 filter
= journal_make_match_string(j
);
1273 log_debug("Journal filter: %s", filter
);
1276 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1279 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1280 [OUTPUT_SHORT
] = "short",
1281 [OUTPUT_SHORT_ISO
] = "short-iso",
1282 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1283 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1284 [OUTPUT_VERBOSE
] = "verbose",
1285 [OUTPUT_EXPORT
] = "export",
1286 [OUTPUT_JSON
] = "json",
1287 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1288 [OUTPUT_JSON_SSE
] = "json-sse",
1289 [OUTPUT_CAT
] = "cat"
1292 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);