]>
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
);
438 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
440 r
= safe_atou64(value
, &realtime
);
442 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
447 r
= sd_journal_get_realtime_usec(j
, &realtime
);
449 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
452 r
= sd_journal_get_cursor(j
, &cursor
);
454 return log_error_errno(r
, "Failed to get cursor: %m");
456 fprintf(f
, "%s [%s]\n",
458 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
459 format_timestamp_us(ts
, sizeof(ts
), realtime
),
462 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
465 const char *on
= "", *off
= "";
467 c
= memchr(data
, '=', length
);
469 log_error("Invalid field.");
472 fieldlen
= c
- (const char*) data
;
474 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
479 if (flags
& OUTPUT_SHOW_ALL
||
480 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
481 && utf8_is_printable(data
, length
))) {
482 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
483 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
486 char bytes
[FORMAT_BYTES_MAX
];
488 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
490 (int) (c
- (const char*) data
),
492 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
500 if (flags
& OUTPUT_CATALOG
)
506 static int output_export(
516 usec_t realtime
, monotonic
;
517 _cleanup_free_
char *cursor
= NULL
;
523 sd_journal_set_data_threshold(j
, 0);
525 r
= sd_journal_get_realtime_usec(j
, &realtime
);
527 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
529 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
531 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
533 r
= sd_journal_get_cursor(j
, &cursor
);
535 return log_error_errno(r
, "Failed to get cursor: %m");
539 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
540 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
545 sd_id128_to_string(boot_id
, sid
));
547 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
549 /* We already printed the boot id, from the data in
550 * the header, hence let's suppress it here */
552 startswith(data
, "_BOOT_ID="))
555 if (utf8_is_printable_newline(data
, length
, false))
556 fwrite(data
, length
, 1, f
);
561 c
= memchr(data
, '=', length
);
563 log_error("Invalid field.");
567 fwrite(data
, c
- (const char*) data
, 1, f
);
569 le64
= htole64(length
- (c
- (const char*) data
) - 1);
570 fwrite(&le64
, sizeof(le64
), 1, f
);
571 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
594 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
597 else if (!utf8_is_printable(p
, l
)) {
598 bool not_first
= false;
604 fprintf(f
, ", %u", (uint8_t) *p
);
607 fprintf(f
, "%u", (uint8_t) *p
);
619 if (*p
== '"' || *p
== '\\') {
622 } else if (*p
== '\n')
624 else if ((uint8_t) *p
< ' ')
625 fprintf(f
, "\\u%04x", (uint8_t) *p
);
637 static int output_json(
644 uint64_t realtime
, monotonic
;
645 _cleanup_free_
char *cursor
= NULL
;
652 bool done
, separator
;
656 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
658 r
= sd_journal_get_realtime_usec(j
, &realtime
);
660 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
662 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
664 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
666 r
= sd_journal_get_cursor(j
, &cursor
);
668 return log_error_errno(r
, "Failed to get cursor: %m");
670 if (mode
== OUTPUT_JSON_PRETTY
)
673 "\t\"__CURSOR\" : \"%s\",\n"
674 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
675 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
676 "\t\"_BOOT_ID\" : \"%s\"",
680 sd_id128_to_string(boot_id
, sid
));
682 if (mode
== OUTPUT_JSON_SSE
)
686 "{ \"__CURSOR\" : \"%s\", "
687 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
688 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
689 "\"_BOOT_ID\" : \"%s\"",
693 sd_id128_to_string(boot_id
, sid
));
696 h
= hashmap_new(&string_hash_ops
);
700 /* First round, iterate through the entry and count how often each field appears */
701 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
707 memcmp(data
, "_BOOT_ID=", 9) == 0)
710 eq
= memchr(data
, '=', length
);
714 n
= strndup(data
, eq
- (const char*) data
);
720 u
= PTR_TO_UINT(hashmap_get(h
, n
));
722 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
729 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
745 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
751 /* We already printed the boot id, from the data in
752 * the header, hence let's suppress it here */
754 memcmp(data
, "_BOOT_ID=", 9) == 0)
757 eq
= memchr(data
, '=', length
);
762 if (mode
== OUTPUT_JSON_PRETTY
)
768 m
= eq
- (const char*) data
;
770 n
= strndup(data
, m
);
776 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
778 /* We already printed this, let's jump to the next */
784 /* Field only appears once, output it directly */
786 json_escape(f
, data
, m
, flags
);
789 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
791 hashmap_remove(h
, n
);
800 /* Field appears multiple times, output it as array */
801 json_escape(f
, data
, m
, flags
);
803 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
805 /* Iterate through the end of the list */
807 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
811 if (memcmp(data
, n
, m
) != 0)
814 if (((const char*) data
)[m
] != '=')
818 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
823 hashmap_remove(h
, n
);
827 /* Iterate data fields form the beginning */
837 if (mode
== OUTPUT_JSON_PRETTY
)
839 else if (mode
== OUTPUT_JSON_SSE
)
847 while ((k
= hashmap_steal_first_key(h
)))
855 static int output_cat(
869 sd_journal_set_data_threshold(j
, 0);
871 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
873 /* An entry without MESSAGE=? */
877 return log_error_errno(r
, "Failed to get data: %m");
882 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
888 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
893 OutputFlags flags
) = {
895 [OUTPUT_SHORT
] = output_short
,
896 [OUTPUT_SHORT_ISO
] = output_short
,
897 [OUTPUT_SHORT_PRECISE
] = output_short
,
898 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
899 [OUTPUT_VERBOSE
] = output_verbose
,
900 [OUTPUT_EXPORT
] = output_export
,
901 [OUTPUT_JSON
] = output_json
,
902 [OUTPUT_JSON_PRETTY
] = output_json
,
903 [OUTPUT_JSON_SSE
] = output_json
,
904 [OUTPUT_CAT
] = output_cat
917 assert(mode
< _OUTPUT_MODE_MAX
);
920 n_columns
= columns();
922 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
925 if (ellipsized
&& ret
> 0)
931 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
935 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
938 /* Print a beginning new line if that's request, but only once
939 * on the first line we print. */
942 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
946 static int show_journal(FILE *f
,
957 bool need_seek
= false;
958 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
962 assert(mode
< _OUTPUT_MODE_MAX
);
965 r
= sd_journal_seek_tail(j
);
967 return log_error_errno(r
, "Failed to seek to tail: %m");
969 r
= sd_journal_previous_skip(j
, how_many
);
971 return log_error_errno(r
, "Failed to skip previous: %m");
978 r
= sd_journal_next(j
);
980 return log_error_errno(r
, "Failed to iterate through journal: %m");
988 if (not_before
> 0) {
989 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
991 /* -ESTALE is returned if the
992 timestamp is not from this boot */
996 return log_error_errno(r
, "Failed to get journal time: %m");
998 if (usec
< not_before
)
1003 maybe_print_begin_newline(f
, &flags
);
1005 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
1010 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1014 /* Check whether the cutoff line is too early */
1016 r
= sd_id128_get_boot(&boot_id
);
1018 return log_error_errno(r
, "Failed to get boot id: %m");
1020 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1022 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1024 if (r
> 0 && not_before
< cutoff
) {
1025 maybe_print_begin_newline(f
, &flags
);
1026 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1029 warn_cutoff
= false;
1032 if (!(flags
& OUTPUT_FOLLOW
))
1035 r
= sd_journal_wait(j
, USEC_INFINITY
);
1037 return log_error_errno(r
, "Failed to wait for journal: %m");
1044 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1046 char *m1
, *m2
, *m3
, *m4
;
1051 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1052 m2
= strjoina("COREDUMP_UNIT=", unit
);
1053 m3
= strjoina("UNIT=", unit
);
1054 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1057 /* Look for messages from the service itself */
1058 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1060 /* Look for coredumps of the service */
1061 (r
= sd_journal_add_disjunction(j
)) ||
1062 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1063 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1064 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1066 /* Look for messages from PID 1 about this service */
1067 (r
= sd_journal_add_disjunction(j
)) ||
1068 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1069 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1071 /* Look for messages from authorized daemons about this service */
1072 (r
= sd_journal_add_disjunction(j
)) ||
1073 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1074 (r
= sd_journal_add_match(j
, m4
, 0))
1077 if (r
== 0 && endswith(unit
, ".slice")) {
1078 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1080 /* Show all messages belonging to a slice */
1082 (r
= sd_journal_add_disjunction(j
)) ||
1083 (r
= sd_journal_add_match(j
, m5
, 0))
1090 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1092 char *m1
, *m2
, *m3
, *m4
;
1093 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1098 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1099 m2
= strjoina("USER_UNIT=", unit
);
1100 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1101 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1102 sprintf(muid
, "_UID="UID_FMT
, uid
);
1105 /* Look for messages from the user service itself */
1106 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1107 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1109 /* Look for messages from systemd about this service */
1110 (r
= sd_journal_add_disjunction(j
)) ||
1111 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1112 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1114 /* Look for coredumps of the service */
1115 (r
= sd_journal_add_disjunction(j
)) ||
1116 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1117 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1118 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1120 /* Look for messages from authorized daemons about this service */
1121 (r
= sd_journal_add_disjunction(j
)) ||
1122 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1123 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1124 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1127 if (r
== 0 && endswith(unit
, ".slice")) {
1128 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1130 /* Show all messages belonging to a slice */
1132 (r
= sd_journal_add_disjunction(j
)) ||
1133 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1134 (r
= sd_journal_add_match(j
, muid
, 0))
1141 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1142 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1143 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1153 if (!machine_name_is_valid(machine
))
1156 r
= container_get_leader(machine
, &pid
);
1160 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1164 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1174 pair
[0] = safe_close(pair
[0]);
1176 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1178 _exit(EXIT_FAILURE
);
1180 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1182 _exit(EXIT_FAILURE
);
1184 r
= loop_read_exact(fd
, buf
, 36, false);
1187 _exit(EXIT_FAILURE
);
1189 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1191 _exit(EXIT_FAILURE
);
1193 _exit(EXIT_SUCCESS
);
1196 pair
[1] = safe_close(pair
[1]);
1198 r
= wait_for_terminate(child
, &si
);
1199 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1200 return r
< 0 ? r
: -EIO
;
1202 k
= recv(pair
[0], buf
, 36, 0);
1207 r
= sd_id128_from_string(buf
, boot_id
);
1214 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1215 char match
[9+32+1] = "_BOOT_ID=";
1222 r
= get_boot_id_for_machine(machine
, &boot_id
);
1224 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1226 r
= sd_id128_get_boot(&boot_id
);
1228 return log_error_errno(r
, "Failed to get boot id: %m");
1231 sd_id128_to_string(boot_id
, match
+ 9);
1232 r
= sd_journal_add_match(j
, match
, strlen(match
));
1234 return log_error_errno(r
, "Failed to add match: %m");
1236 r
= sd_journal_add_conjunction(j
);
1238 return log_error_errno(r
, "Failed to add conjunction: %m");
1243 int show_journal_by_unit(
1252 int journal_open_flags
,
1256 _cleanup_(sd_journal_closep
) sd_journal
*j
= NULL
;
1260 assert(mode
< _OUTPUT_MODE_MAX
);
1266 r
= sd_journal_open(&j
, journal_open_flags
);
1268 return log_error_errno(r
, "Failed to open journal: %m");
1270 r
= add_match_this_boot(j
, NULL
);
1275 r
= add_matches_for_unit(j
, unit
);
1277 r
= add_matches_for_user_unit(j
, unit
, uid
);
1279 return log_error_errno(r
, "Failed to add unit matches: %m");
1281 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1282 _cleanup_free_
char *filter
;
1284 filter
= journal_make_match_string(j
);
1288 log_debug("Journal filter: %s", filter
);
1291 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1294 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1295 [OUTPUT_SHORT
] = "short",
1296 [OUTPUT_SHORT_ISO
] = "short-iso",
1297 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1298 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1299 [OUTPUT_VERBOSE
] = "verbose",
1300 [OUTPUT_EXPORT
] = "export",
1301 [OUTPUT_JSON
] = "json",
1302 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1303 [OUTPUT_JSON_SSE
] = "json-sse",
1304 [OUTPUT_CAT
] = "cat"
1307 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);