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"
32 #include "journal-internal.h"
34 #include "logs-show.h"
35 #include "process-util.h"
36 #include "string-util.h"
37 #include "terminal-util.h"
41 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
42 #define PRINT_LINE_THRESHOLD 3
43 #define PRINT_CHAR_THRESHOLD 300
45 #define JSON_THRESHOLD 4096
47 static int print_catalog(FILE *f
, sd_journal
*j
) {
49 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
52 r
= sd_journal_get_catalog(j
, &t
);
56 z
= strreplace(strstrip(t
), "\n", "\n-- ");
67 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
80 if (memcmp(data
, field
, fl
))
88 memcpy(buf
, (const char*) data
+ fl
, nl
);
98 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
101 if (flags
& OUTPUT_SHOW_ALL
)
104 if (l
>= PRINT_CHAR_THRESHOLD
)
107 if (!utf8_is_printable(p
, l
))
113 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
114 const char *color_on
= "", *color_off
= "";
115 const char *pos
, *end
;
116 bool ellipsized
= false;
119 if (flags
& OUTPUT_COLOR
) {
120 if (priority
<= LOG_ERR
) {
121 color_on
= ANSI_HIGHLIGHT_RED
;
122 color_off
= ANSI_NORMAL
;
123 } else if (priority
<= LOG_NOTICE
) {
124 color_on
= ANSI_HIGHLIGHT
;
125 color_off
= ANSI_NORMAL
;
129 /* A special case: make sure that we print a newline when
130 the message is empty. */
131 if (message_len
== 0)
135 pos
< message
+ message_len
;
136 pos
= end
+ 1, line
++) {
137 bool continuation
= line
> 0;
140 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
145 /* We need to figure out when we are showing not-last line, *and*
146 * will skip subsequent lines. In that case, we will put the dots
147 * at the end of the line, instead of putting dots in the middle
151 line
+ 1 == PRINT_LINE_THRESHOLD
||
152 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
154 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
155 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
156 fprintf(f
, "%*s%s%.*s%s\n",
157 continuation
* prefix
, "",
158 color_on
, len
, pos
, color_off
);
162 /* Beyond this point, ellipsization will happen. */
165 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
166 if (n_columns
- prefix
> (unsigned) len
+ 3)
167 fprintf(f
, "%*s%s%.*s...%s\n",
168 continuation
* prefix
, "",
169 color_on
, len
, pos
, color_off
);
171 _cleanup_free_
char *e
;
173 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
174 tail_line
? 100 : 90);
176 fprintf(f
, "%*s%s%.*s%s\n",
177 continuation
* prefix
, "",
178 color_on
, len
, pos
, color_off
);
180 fprintf(f
, "%*s%s%s%s\n",
181 continuation
* prefix
, "",
182 color_on
, e
, color_off
);
194 static int output_short(
205 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
206 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;
208 bool ellipsized
= false;
213 /* Set the threshold to one bigger than the actual print
214 * threshold, so that if the line is actually longer than what
215 * we're willing to print, ellipsization will occur. This way
216 * we won't output a misleading line without any indication of
219 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
221 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
223 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
229 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
235 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
241 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
247 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
253 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
259 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
265 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
271 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
277 return log_error_errno(r
, "Failed to get journal fields: %m");
280 log_debug("Skipping message without MESSAGE= field.");
284 if (!(flags
& OUTPUT_SHOW_ALL
))
285 strip_tab_ansi(&message
, &message_len
);
287 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
290 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
297 r
= safe_atou64(monotonic
, &t
);
300 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
303 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
305 fprintf(f
, "[%5llu.%06llu]",
306 (unsigned long long) (t
/ USEC_PER_SEC
),
307 (unsigned long long) (t
% USEC_PER_SEC
));
309 n
+= 1 + 5 + 1 + 6 + 1;
316 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
319 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
322 r
= safe_atou64(realtime
, &x
);
325 r
= sd_journal_get_realtime_usec(j
, &x
);
328 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
330 t
= (time_t) (x
/ USEC_PER_SEC
);
333 case OUTPUT_SHORT_ISO
:
334 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
336 case OUTPUT_SHORT_PRECISE
:
337 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
339 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
340 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
343 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
347 log_error("Failed to format time.");
355 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
356 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
357 n
+= hostname_len
+ 1;
360 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
361 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
362 n
+= identifier_len
+ 1;
363 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
364 fprintf(f
, " %.*s", (int) comm_len
, comm
);
367 fputs(" unknown", f
);
369 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
370 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
372 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
373 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
374 n
+= fake_pid_len
+ 2;
377 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
378 char bytes
[FORMAT_BYTES_MAX
];
379 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
383 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
386 if (flags
& OUTPUT_CATALOG
)
392 static int output_verbose(
401 _cleanup_free_
char *cursor
= NULL
;
403 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
409 sd_journal_set_data_threshold(j
, 0);
411 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
413 log_debug("Source realtime timestamp not found");
415 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
417 _cleanup_free_
char *value
= NULL
;
420 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
422 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
424 r
= safe_atou64(value
, &realtime
);
426 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
431 r
= sd_journal_get_realtime_usec(j
, &realtime
);
433 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
436 r
= sd_journal_get_cursor(j
, &cursor
);
438 return log_error_errno(r
, "Failed to get cursor: %m");
440 fprintf(f
, "%s [%s]\n",
442 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
443 format_timestamp_us(ts
, sizeof(ts
), realtime
),
446 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
449 const char *on
= "", *off
= "";
451 c
= memchr(data
, '=', length
);
453 log_error("Invalid field.");
456 fieldlen
= c
- (const char*) data
;
458 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
463 if (flags
& OUTPUT_SHOW_ALL
||
464 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
465 && utf8_is_printable(data
, length
))) {
466 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
467 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
470 char bytes
[FORMAT_BYTES_MAX
];
472 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
474 (int) (c
- (const char*) data
),
476 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
484 if (flags
& OUTPUT_CATALOG
)
490 static int output_export(
500 usec_t realtime
, monotonic
;
501 _cleanup_free_
char *cursor
= NULL
;
507 sd_journal_set_data_threshold(j
, 0);
509 r
= sd_journal_get_realtime_usec(j
, &realtime
);
511 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
513 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
515 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
517 r
= sd_journal_get_cursor(j
, &cursor
);
519 return log_error_errno(r
, "Failed to get cursor: %m");
523 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
524 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
529 sd_id128_to_string(boot_id
, sid
));
531 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
533 /* We already printed the boot id, from the data in
534 * the header, hence let's suppress it here */
536 startswith(data
, "_BOOT_ID="))
539 if (utf8_is_printable_newline(data
, length
, false))
540 fwrite(data
, length
, 1, f
);
545 c
= memchr(data
, '=', length
);
547 log_error("Invalid field.");
551 fwrite(data
, c
- (const char*) data
, 1, f
);
553 le64
= htole64(length
- (c
- (const char*) data
) - 1);
554 fwrite(&le64
, sizeof(le64
), 1, f
);
555 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
578 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
581 else if (!utf8_is_printable(p
, l
)) {
582 bool not_first
= false;
588 fprintf(f
, ", %u", (uint8_t) *p
);
591 fprintf(f
, "%u", (uint8_t) *p
);
603 if (*p
== '"' || *p
== '\\') {
606 } else if (*p
== '\n')
608 else if ((uint8_t) *p
< ' ')
609 fprintf(f
, "\\u%04x", (uint8_t) *p
);
621 static int output_json(
628 uint64_t realtime
, monotonic
;
629 _cleanup_free_
char *cursor
= NULL
;
636 bool done
, separator
;
640 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
642 r
= sd_journal_get_realtime_usec(j
, &realtime
);
644 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
646 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
648 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
650 r
= sd_journal_get_cursor(j
, &cursor
);
652 return log_error_errno(r
, "Failed to get cursor: %m");
654 if (mode
== OUTPUT_JSON_PRETTY
)
657 "\t\"__CURSOR\" : \"%s\",\n"
658 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
659 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
660 "\t\"_BOOT_ID\" : \"%s\"",
664 sd_id128_to_string(boot_id
, sid
));
666 if (mode
== OUTPUT_JSON_SSE
)
670 "{ \"__CURSOR\" : \"%s\", "
671 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
672 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
673 "\"_BOOT_ID\" : \"%s\"",
677 sd_id128_to_string(boot_id
, sid
));
680 h
= hashmap_new(&string_hash_ops
);
684 /* First round, iterate through the entry and count how often each field appears */
685 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
691 memcmp(data
, "_BOOT_ID=", 9) == 0)
694 eq
= memchr(data
, '=', length
);
698 n
= strndup(data
, eq
- (const char*) data
);
704 u
= PTR_TO_UINT(hashmap_get(h
, n
));
706 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
713 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
729 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
735 /* We already printed the boot id, from the data in
736 * the header, hence let's suppress it here */
738 memcmp(data
, "_BOOT_ID=", 9) == 0)
741 eq
= memchr(data
, '=', length
);
746 if (mode
== OUTPUT_JSON_PRETTY
)
752 m
= eq
- (const char*) data
;
754 n
= strndup(data
, m
);
760 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
762 /* We already printed this, let's jump to the next */
768 /* Field only appears once, output it directly */
770 json_escape(f
, data
, m
, flags
);
773 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
775 hashmap_remove(h
, n
);
784 /* Field appears multiple times, output it as array */
785 json_escape(f
, data
, m
, flags
);
787 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
789 /* Iterate through the end of the list */
791 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
795 if (memcmp(data
, n
, m
) != 0)
798 if (((const char*) data
)[m
] != '=')
802 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
807 hashmap_remove(h
, n
);
811 /* Iterate data fields form the beginning */
821 if (mode
== OUTPUT_JSON_PRETTY
)
823 else if (mode
== OUTPUT_JSON_SSE
)
831 while ((k
= hashmap_steal_first_key(h
)))
839 static int output_cat(
853 sd_journal_set_data_threshold(j
, 0);
855 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
857 /* An entry without MESSAGE=? */
861 return log_error_errno(r
, "Failed to get data: %m");
866 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
872 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
877 OutputFlags flags
) = {
879 [OUTPUT_SHORT
] = output_short
,
880 [OUTPUT_SHORT_ISO
] = output_short
,
881 [OUTPUT_SHORT_PRECISE
] = output_short
,
882 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
883 [OUTPUT_VERBOSE
] = output_verbose
,
884 [OUTPUT_EXPORT
] = output_export
,
885 [OUTPUT_JSON
] = output_json
,
886 [OUTPUT_JSON_PRETTY
] = output_json
,
887 [OUTPUT_JSON_SSE
] = output_json
,
888 [OUTPUT_CAT
] = output_cat
901 assert(mode
< _OUTPUT_MODE_MAX
);
904 n_columns
= columns();
906 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
909 if (ellipsized
&& ret
> 0)
915 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
919 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
922 /* Print a beginning new line if that's request, but only once
923 * on the first line we print. */
926 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
930 static int show_journal(FILE *f
,
941 bool need_seek
= false;
942 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
946 assert(mode
< _OUTPUT_MODE_MAX
);
949 r
= sd_journal_seek_tail(j
);
951 return log_error_errno(r
, "Failed to seek to tail: %m");
953 r
= sd_journal_previous_skip(j
, how_many
);
955 return log_error_errno(r
, "Failed to skip previous: %m");
962 r
= sd_journal_next(j
);
964 return log_error_errno(r
, "Failed to iterate through journal: %m");
972 if (not_before
> 0) {
973 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
975 /* -ESTALE is returned if the
976 timestamp is not from this boot */
980 return log_error_errno(r
, "Failed to get journal time: %m");
982 if (usec
< not_before
)
987 maybe_print_begin_newline(f
, &flags
);
989 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
994 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
998 /* Check whether the cutoff line is too early */
1000 r
= sd_id128_get_boot(&boot_id
);
1002 return log_error_errno(r
, "Failed to get boot id: %m");
1004 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1006 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1008 if (r
> 0 && not_before
< cutoff
) {
1009 maybe_print_begin_newline(f
, &flags
);
1010 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1013 warn_cutoff
= false;
1016 if (!(flags
& OUTPUT_FOLLOW
))
1019 r
= sd_journal_wait(j
, USEC_INFINITY
);
1021 return log_error_errno(r
, "Failed to wait for journal: %m");
1028 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1030 char *m1
, *m2
, *m3
, *m4
;
1035 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1036 m2
= strjoina("COREDUMP_UNIT=", unit
);
1037 m3
= strjoina("UNIT=", unit
);
1038 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1041 /* Look for messages from the service itself */
1042 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1044 /* Look for coredumps of the service */
1045 (r
= sd_journal_add_disjunction(j
)) ||
1046 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1047 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1048 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1050 /* Look for messages from PID 1 about this service */
1051 (r
= sd_journal_add_disjunction(j
)) ||
1052 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1053 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1055 /* Look for messages from authorized daemons about this service */
1056 (r
= sd_journal_add_disjunction(j
)) ||
1057 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1058 (r
= sd_journal_add_match(j
, m4
, 0))
1061 if (r
== 0 && endswith(unit
, ".slice")) {
1062 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1064 /* Show all messages belonging to a slice */
1066 (r
= sd_journal_add_disjunction(j
)) ||
1067 (r
= sd_journal_add_match(j
, m5
, 0))
1074 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1076 char *m1
, *m2
, *m3
, *m4
;
1077 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1082 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1083 m2
= strjoina("USER_UNIT=", unit
);
1084 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1085 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1086 sprintf(muid
, "_UID="UID_FMT
, uid
);
1089 /* Look for messages from the user service itself */
1090 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1091 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1093 /* Look for messages from systemd about this service */
1094 (r
= sd_journal_add_disjunction(j
)) ||
1095 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1096 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1098 /* Look for coredumps of the service */
1099 (r
= sd_journal_add_disjunction(j
)) ||
1100 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1101 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1102 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1104 /* Look for messages from authorized daemons about this service */
1105 (r
= sd_journal_add_disjunction(j
)) ||
1106 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1107 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1108 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1111 if (r
== 0 && endswith(unit
, ".slice")) {
1112 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1114 /* Show all messages belonging to a slice */
1116 (r
= sd_journal_add_disjunction(j
)) ||
1117 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1118 (r
= sd_journal_add_match(j
, muid
, 0))
1125 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1126 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1127 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1137 if (!machine_name_is_valid(machine
))
1140 r
= container_get_leader(machine
, &pid
);
1144 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1148 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1158 pair
[0] = safe_close(pair
[0]);
1160 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1162 _exit(EXIT_FAILURE
);
1164 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1166 _exit(EXIT_FAILURE
);
1168 r
= loop_read_exact(fd
, buf
, 36, false);
1171 _exit(EXIT_FAILURE
);
1173 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1175 _exit(EXIT_FAILURE
);
1177 _exit(EXIT_SUCCESS
);
1180 pair
[1] = safe_close(pair
[1]);
1182 r
= wait_for_terminate(child
, &si
);
1183 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1184 return r
< 0 ? r
: -EIO
;
1186 k
= recv(pair
[0], buf
, 36, 0);
1191 r
= sd_id128_from_string(buf
, boot_id
);
1198 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1199 char match
[9+32+1] = "_BOOT_ID=";
1206 r
= get_boot_id_for_machine(machine
, &boot_id
);
1208 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1210 r
= sd_id128_get_boot(&boot_id
);
1212 return log_error_errno(r
, "Failed to get boot id: %m");
1215 sd_id128_to_string(boot_id
, match
+ 9);
1216 r
= sd_journal_add_match(j
, match
, strlen(match
));
1218 return log_error_errno(r
, "Failed to add match: %m");
1220 r
= sd_journal_add_conjunction(j
);
1222 return log_error_errno(r
, "Failed to add conjunction: %m");
1227 int show_journal_by_unit(
1236 int journal_open_flags
,
1240 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1244 assert(mode
< _OUTPUT_MODE_MAX
);
1250 r
= sd_journal_open(&j
, journal_open_flags
);
1252 return log_error_errno(r
, "Failed to open journal: %m");
1254 r
= add_match_this_boot(j
, NULL
);
1259 r
= add_matches_for_unit(j
, unit
);
1261 r
= add_matches_for_user_unit(j
, unit
, uid
);
1263 return log_error_errno(r
, "Failed to add unit matches: %m");
1265 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1266 _cleanup_free_
char *filter
;
1268 filter
= journal_make_match_string(j
);
1272 log_debug("Journal filter: %s", filter
);
1275 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1278 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1279 [OUTPUT_SHORT
] = "short",
1280 [OUTPUT_SHORT_ISO
] = "short-iso",
1281 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1282 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1283 [OUTPUT_VERBOSE
] = "verbose",
1284 [OUTPUT_EXPORT
] = "export",
1285 [OUTPUT_JSON
] = "json",
1286 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1287 [OUTPUT_JSON_SSE
] = "json-sse",
1288 [OUTPUT_CAT
] = "cat"
1291 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);