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/>.
24 #include <sys/socket.h>
28 #include "logs-show.h"
33 #include "journal-internal.h"
34 #include "formats-util.h"
35 #include "process-util.h"
36 #include "terminal-util.h"
37 #include "hostname-util.h"
39 /* up to three lines (each up to 100 characters),
40 or 300 characters, whichever is less */
41 #define PRINT_LINE_THRESHOLD 3
42 #define PRINT_CHAR_THRESHOLD 300
44 #define JSON_THRESHOLD 4096
46 static int print_catalog(FILE *f
, sd_journal
*j
) {
48 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
51 r
= sd_journal_get_catalog(j
, &t
);
55 z
= strreplace(strstrip(t
), "\n", "\n-- ");
66 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
79 if (memcmp(data
, field
, fl
))
87 memcpy(buf
, (const char*) data
+ fl
, nl
);
97 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
100 if (flags
& OUTPUT_SHOW_ALL
)
103 if (l
>= PRINT_CHAR_THRESHOLD
)
106 if (!utf8_is_printable(p
, l
))
112 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
113 const char *color_on
= "", *color_off
= "";
114 const char *pos
, *end
;
115 bool ellipsized
= false;
118 if (flags
& OUTPUT_COLOR
) {
119 if (priority
<= LOG_ERR
) {
120 color_on
= ANSI_HIGHLIGHT_RED_ON
;
121 color_off
= ANSI_HIGHLIGHT_OFF
;
122 } else if (priority
<= LOG_NOTICE
) {
123 color_on
= ANSI_HIGHLIGHT_ON
;
124 color_off
= ANSI_HIGHLIGHT_OFF
;
128 /* A special case: make sure that we print a newline when
129 the message is empty. */
130 if (message_len
== 0)
134 pos
< message
+ message_len
;
135 pos
= end
+ 1, line
++) {
136 bool continuation
= line
> 0;
139 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
144 /* We need to figure out when we are showing not-last line, *and*
145 * will skip subsequent lines. In that case, we will put the dots
146 * at the end of the line, instead of putting dots in the middle
150 line
+ 1 == PRINT_LINE_THRESHOLD
||
151 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
153 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
154 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
155 fprintf(f
, "%*s%s%.*s%s\n",
156 continuation
* prefix
, "",
157 color_on
, len
, pos
, color_off
);
161 /* Beyond this point, ellipsization will happen. */
164 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
165 if (n_columns
- prefix
> (unsigned) len
+ 3)
166 fprintf(f
, "%*s%s%.*s...%s\n",
167 continuation
* prefix
, "",
168 color_on
, len
, pos
, color_off
);
170 _cleanup_free_
char *e
;
172 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
173 tail_line
? 100 : 90);
175 fprintf(f
, "%*s%s%.*s%s\n",
176 continuation
* prefix
, "",
177 color_on
, len
, pos
, color_off
);
179 fprintf(f
, "%*s%s%s%s\n",
180 continuation
* prefix
, "",
181 color_on
, e
, color_off
);
193 static int output_short(
204 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
205 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;
207 bool ellipsized
= false;
212 /* Set the threshold to one bigger than the actual print
213 * threshold, so that if the line is actually longer than what
214 * we're willing to print, ellipsization will occur. This way
215 * we won't output a misleading line without any indication of
218 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
220 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
222 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
228 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
234 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
240 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
246 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
252 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
258 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
264 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
270 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
276 return log_error_errno(r
, "Failed to get journal fields: %m");
279 log_debug("Skipping message without MESSAGE= field.");
283 if (!(flags
& OUTPUT_SHOW_ALL
))
284 strip_tab_ansi(&message
, &message_len
);
286 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
289 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
296 r
= safe_atou64(monotonic
, &t
);
299 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
302 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
304 fprintf(f
, "[%5llu.%06llu]",
305 (unsigned long long) (t
/ USEC_PER_SEC
),
306 (unsigned long long) (t
% USEC_PER_SEC
));
308 n
+= 1 + 5 + 1 + 6 + 1;
315 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
318 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
321 r
= safe_atou64(realtime
, &x
);
324 r
= sd_journal_get_realtime_usec(j
, &x
);
327 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
329 t
= (time_t) (x
/ USEC_PER_SEC
);
332 case OUTPUT_SHORT_ISO
:
333 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
335 case OUTPUT_SHORT_PRECISE
:
336 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
338 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
339 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
342 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
346 log_error("Failed to format time.");
354 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
355 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
356 n
+= hostname_len
+ 1;
359 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
360 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
361 n
+= identifier_len
+ 1;
362 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
363 fprintf(f
, " %.*s", (int) comm_len
, comm
);
366 fputs(" unknown", f
);
368 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
369 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
371 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
372 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
373 n
+= fake_pid_len
+ 2;
376 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
377 char bytes
[FORMAT_BYTES_MAX
];
378 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
382 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
385 if (flags
& OUTPUT_CATALOG
)
391 static int output_verbose(
400 _cleanup_free_
char *cursor
= NULL
;
402 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
408 sd_journal_set_data_threshold(j
, 0);
410 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
412 log_debug("Source realtime timestamp not found");
414 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
416 _cleanup_free_
char *value
= NULL
;
419 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
421 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
423 r
= safe_atou64(value
, &realtime
);
425 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
430 r
= sd_journal_get_realtime_usec(j
, &realtime
);
432 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
435 r
= sd_journal_get_cursor(j
, &cursor
);
437 return log_error_errno(r
, "Failed to get cursor: %m");
439 fprintf(f
, "%s [%s]\n",
441 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
442 format_timestamp_us(ts
, sizeof(ts
), realtime
),
445 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
448 const char *on
= "", *off
= "";
450 c
= memchr(data
, '=', length
);
452 log_error("Invalid field.");
455 fieldlen
= c
- (const char*) data
;
457 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
458 on
= ANSI_HIGHLIGHT_ON
;
459 off
= ANSI_HIGHLIGHT_OFF
;
462 if (flags
& OUTPUT_SHOW_ALL
||
463 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
464 && utf8_is_printable(data
, length
))) {
465 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
466 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
469 char bytes
[FORMAT_BYTES_MAX
];
471 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
473 (int) (c
- (const char*) data
),
475 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
483 if (flags
& OUTPUT_CATALOG
)
489 static int output_export(
499 usec_t realtime
, monotonic
;
500 _cleanup_free_
char *cursor
= NULL
;
506 sd_journal_set_data_threshold(j
, 0);
508 r
= sd_journal_get_realtime_usec(j
, &realtime
);
510 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
512 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
514 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
516 r
= sd_journal_get_cursor(j
, &cursor
);
518 return log_error_errno(r
, "Failed to get cursor: %m");
522 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
523 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
528 sd_id128_to_string(boot_id
, sid
));
530 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
532 /* We already printed the boot id, from the data in
533 * the header, hence let's suppress it here */
535 startswith(data
, "_BOOT_ID="))
538 if (utf8_is_printable_newline(data
, length
, false))
539 fwrite(data
, length
, 1, f
);
544 c
= memchr(data
, '=', length
);
546 log_error("Invalid field.");
550 fwrite(data
, c
- (const char*) data
, 1, f
);
552 le64
= htole64(length
- (c
- (const char*) data
) - 1);
553 fwrite(&le64
, sizeof(le64
), 1, f
);
554 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
577 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
580 else if (!utf8_is_printable(p
, l
)) {
581 bool not_first
= false;
587 fprintf(f
, ", %u", (uint8_t) *p
);
590 fprintf(f
, "%u", (uint8_t) *p
);
602 if (*p
== '"' || *p
== '\\') {
605 } else if (*p
== '\n')
607 else if ((uint8_t) *p
< ' ')
608 fprintf(f
, "\\u%04x", (uint8_t) *p
);
620 static int output_json(
627 uint64_t realtime
, monotonic
;
628 _cleanup_free_
char *cursor
= NULL
;
635 bool done
, separator
;
639 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
641 r
= sd_journal_get_realtime_usec(j
, &realtime
);
643 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
645 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
647 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
649 r
= sd_journal_get_cursor(j
, &cursor
);
651 return log_error_errno(r
, "Failed to get cursor: %m");
653 if (mode
== OUTPUT_JSON_PRETTY
)
656 "\t\"__CURSOR\" : \"%s\",\n"
657 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
658 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
659 "\t\"_BOOT_ID\" : \"%s\"",
663 sd_id128_to_string(boot_id
, sid
));
665 if (mode
== OUTPUT_JSON_SSE
)
669 "{ \"__CURSOR\" : \"%s\", "
670 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
671 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
672 "\"_BOOT_ID\" : \"%s\"",
676 sd_id128_to_string(boot_id
, sid
));
679 h
= hashmap_new(&string_hash_ops
);
683 /* First round, iterate through the entry and count how often each field appears */
684 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
690 memcmp(data
, "_BOOT_ID=", 9) == 0)
693 eq
= memchr(data
, '=', length
);
697 n
= strndup(data
, eq
- (const char*) data
);
703 u
= PTR_TO_UINT(hashmap_get(h
, n
));
705 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
712 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
728 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
734 /* We already printed the boot id, from the data in
735 * the header, hence let's suppress it here */
737 memcmp(data
, "_BOOT_ID=", 9) == 0)
740 eq
= memchr(data
, '=', length
);
745 if (mode
== OUTPUT_JSON_PRETTY
)
751 m
= eq
- (const char*) data
;
753 n
= strndup(data
, m
);
759 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
761 /* We already printed this, let's jump to the next */
767 /* Field only appears once, output it directly */
769 json_escape(f
, data
, m
, flags
);
772 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
774 hashmap_remove(h
, n
);
783 /* Field appears multiple times, output it as array */
784 json_escape(f
, data
, m
, flags
);
786 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
788 /* Iterate through the end of the list */
790 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
794 if (memcmp(data
, n
, m
) != 0)
797 if (((const char*) data
)[m
] != '=')
801 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
806 hashmap_remove(h
, n
);
810 /* Iterate data fields form the beginning */
820 if (mode
== OUTPUT_JSON_PRETTY
)
822 else if (mode
== OUTPUT_JSON_SSE
)
830 while ((k
= hashmap_steal_first_key(h
)))
838 static int output_cat(
852 sd_journal_set_data_threshold(j
, 0);
854 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
856 /* An entry without MESSAGE=? */
860 return log_error_errno(r
, "Failed to get data: %m");
865 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
871 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
876 OutputFlags flags
) = {
878 [OUTPUT_SHORT
] = output_short
,
879 [OUTPUT_SHORT_ISO
] = output_short
,
880 [OUTPUT_SHORT_PRECISE
] = output_short
,
881 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
882 [OUTPUT_VERBOSE
] = output_verbose
,
883 [OUTPUT_EXPORT
] = output_export
,
884 [OUTPUT_JSON
] = output_json
,
885 [OUTPUT_JSON_PRETTY
] = output_json
,
886 [OUTPUT_JSON_SSE
] = output_json
,
887 [OUTPUT_CAT
] = output_cat
900 assert(mode
< _OUTPUT_MODE_MAX
);
903 n_columns
= columns();
905 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
908 if (ellipsized
&& ret
> 0)
914 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
918 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
921 /* Print a beginning new line if that's request, but only once
922 * on the first line we print. */
925 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
929 static int show_journal(FILE *f
,
940 bool need_seek
= false;
941 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
945 assert(mode
< _OUTPUT_MODE_MAX
);
948 r
= sd_journal_seek_tail(j
);
950 return log_error_errno(r
, "Failed to seek to tail: %m");
952 r
= sd_journal_previous_skip(j
, how_many
);
954 return log_error_errno(r
, "Failed to skip previous: %m");
961 r
= sd_journal_next(j
);
963 return log_error_errno(r
, "Failed to iterate through journal: %m");
971 if (not_before
> 0) {
972 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
974 /* -ESTALE is returned if the
975 timestamp is not from this boot */
979 return log_error_errno(r
, "Failed to get journal time: %m");
981 if (usec
< not_before
)
986 maybe_print_begin_newline(f
, &flags
);
988 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
993 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
997 /* Check whether the cutoff line is too early */
999 r
= sd_id128_get_boot(&boot_id
);
1001 return log_error_errno(r
, "Failed to get boot id: %m");
1003 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1005 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1007 if (r
> 0 && not_before
< cutoff
) {
1008 maybe_print_begin_newline(f
, &flags
);
1009 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1012 warn_cutoff
= false;
1015 if (!(flags
& OUTPUT_FOLLOW
))
1018 r
= sd_journal_wait(j
, USEC_INFINITY
);
1020 return log_error_errno(r
, "Failed to wait for journal: %m");
1027 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1029 char *m1
, *m2
, *m3
, *m4
;
1034 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1035 m2
= strjoina("COREDUMP_UNIT=", unit
);
1036 m3
= strjoina("UNIT=", unit
);
1037 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1040 /* Look for messages from the service itself */
1041 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1043 /* Look for coredumps of the service */
1044 (r
= sd_journal_add_disjunction(j
)) ||
1045 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1046 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1047 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1049 /* Look for messages from PID 1 about this service */
1050 (r
= sd_journal_add_disjunction(j
)) ||
1051 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1052 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1054 /* Look for messages from authorized daemons about this service */
1055 (r
= sd_journal_add_disjunction(j
)) ||
1056 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1057 (r
= sd_journal_add_match(j
, m4
, 0))
1060 if (r
== 0 && endswith(unit
, ".slice")) {
1061 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1063 /* Show all messages belonging to a slice */
1065 (r
= sd_journal_add_disjunction(j
)) ||
1066 (r
= sd_journal_add_match(j
, m5
, 0))
1073 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1075 char *m1
, *m2
, *m3
, *m4
;
1076 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1081 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1082 m2
= strjoina("USER_UNIT=", unit
);
1083 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1084 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1085 sprintf(muid
, "_UID="UID_FMT
, uid
);
1088 /* Look for messages from the user service itself */
1089 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1090 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1092 /* Look for messages from systemd about this service */
1093 (r
= sd_journal_add_disjunction(j
)) ||
1094 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1095 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1097 /* Look for coredumps of the service */
1098 (r
= sd_journal_add_disjunction(j
)) ||
1099 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1100 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1101 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1103 /* Look for messages from authorized daemons about this service */
1104 (r
= sd_journal_add_disjunction(j
)) ||
1105 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1106 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1107 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1110 if (r
== 0 && endswith(unit
, ".slice")) {
1111 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1113 /* Show all messages belonging to a slice */
1115 (r
= sd_journal_add_disjunction(j
)) ||
1116 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1117 (r
= sd_journal_add_match(j
, muid
, 0))
1124 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1125 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1126 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1136 if (!machine_name_is_valid(machine
))
1139 r
= container_get_leader(machine
, &pid
);
1143 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1147 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1157 pair
[0] = safe_close(pair
[0]);
1159 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1161 _exit(EXIT_FAILURE
);
1163 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1165 _exit(EXIT_FAILURE
);
1167 r
= loop_read_exact(fd
, buf
, 36, false);
1170 _exit(EXIT_FAILURE
);
1172 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1174 _exit(EXIT_FAILURE
);
1176 _exit(EXIT_SUCCESS
);
1179 pair
[1] = safe_close(pair
[1]);
1181 r
= wait_for_terminate(child
, &si
);
1182 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1183 return r
< 0 ? r
: -EIO
;
1185 k
= recv(pair
[0], buf
, 36, 0);
1190 r
= sd_id128_from_string(buf
, boot_id
);
1197 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1198 char match
[9+32+1] = "_BOOT_ID=";
1205 r
= get_boot_id_for_machine(machine
, &boot_id
);
1207 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1209 r
= sd_id128_get_boot(&boot_id
);
1211 return log_error_errno(r
, "Failed to get boot id: %m");
1214 sd_id128_to_string(boot_id
, match
+ 9);
1215 r
= sd_journal_add_match(j
, match
, strlen(match
));
1217 return log_error_errno(r
, "Failed to add match: %m");
1219 r
= sd_journal_add_conjunction(j
);
1221 return log_error_errno(r
, "Failed to add conjunction: %m");
1226 int show_journal_by_unit(
1235 int journal_open_flags
,
1239 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1243 assert(mode
< _OUTPUT_MODE_MAX
);
1249 r
= sd_journal_open(&j
, journal_open_flags
);
1251 return log_error_errno(r
, "Failed to open journal: %m");
1253 r
= add_match_this_boot(j
, NULL
);
1258 r
= add_matches_for_unit(j
, unit
);
1260 r
= add_matches_for_user_unit(j
, unit
, uid
);
1262 return log_error_errno(r
, "Failed to add unit matches: %m");
1264 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1265 _cleanup_free_
char *filter
;
1267 filter
= journal_make_match_string(j
);
1271 log_debug("Journal filter: %s", filter
);
1274 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1277 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1278 [OUTPUT_SHORT
] = "short",
1279 [OUTPUT_SHORT_ISO
] = "short-iso",
1280 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1281 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1282 [OUTPUT_VERBOSE
] = "verbose",
1283 [OUTPUT_EXPORT
] = "export",
1284 [OUTPUT_JSON
] = "json",
1285 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1286 [OUTPUT_JSON_SSE
] = "json-sse",
1287 [OUTPUT_CAT
] = "cat"
1290 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);