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 "parse-util.h"
37 #include "process-util.h"
38 #include "string-table.h"
39 #include "string-util.h"
40 #include "terminal-util.h"
44 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
45 #define PRINT_LINE_THRESHOLD 3
46 #define PRINT_CHAR_THRESHOLD 300
48 #define JSON_THRESHOLD 4096
50 static int print_catalog(FILE *f
, sd_journal
*j
) {
52 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
55 r
= sd_journal_get_catalog(j
, &t
);
59 z
= strreplace(strstrip(t
), "\n", "\n-- ");
70 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
83 if (memcmp(data
, field
, fl
))
91 memcpy(buf
, (const char*) data
+ fl
, nl
);
101 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
104 if (flags
& OUTPUT_SHOW_ALL
)
107 if (l
>= PRINT_CHAR_THRESHOLD
)
110 if (!utf8_is_printable(p
, l
))
116 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
117 const char *color_on
= "", *color_off
= "";
118 const char *pos
, *end
;
119 bool ellipsized
= false;
122 if (flags
& OUTPUT_COLOR
) {
123 if (priority
<= LOG_ERR
) {
124 color_on
= ANSI_HIGHLIGHT_RED
;
125 color_off
= ANSI_NORMAL
;
126 } else if (priority
<= LOG_NOTICE
) {
127 color_on
= ANSI_HIGHLIGHT
;
128 color_off
= ANSI_NORMAL
;
132 /* A special case: make sure that we print a newline when
133 the message is empty. */
134 if (message_len
== 0)
138 pos
< message
+ message_len
;
139 pos
= end
+ 1, line
++) {
140 bool continuation
= line
> 0;
143 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
148 /* We need to figure out when we are showing not-last line, *and*
149 * will skip subsequent lines. In that case, we will put the dots
150 * at the end of the line, instead of putting dots in the middle
154 line
+ 1 == PRINT_LINE_THRESHOLD
||
155 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
157 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
158 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
159 fprintf(f
, "%*s%s%.*s%s\n",
160 continuation
* prefix
, "",
161 color_on
, len
, pos
, color_off
);
165 /* Beyond this point, ellipsization will happen. */
168 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
169 if (n_columns
- prefix
> (unsigned) len
+ 3)
170 fprintf(f
, "%*s%s%.*s...%s\n",
171 continuation
* prefix
, "",
172 color_on
, len
, pos
, color_off
);
174 _cleanup_free_
char *e
;
176 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
177 tail_line
? 100 : 90);
179 fprintf(f
, "%*s%s%.*s%s\n",
180 continuation
* prefix
, "",
181 color_on
, len
, pos
, color_off
);
183 fprintf(f
, "%*s%s%s%s\n",
184 continuation
* prefix
, "",
185 color_on
, e
, color_off
);
197 static int output_short(
208 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
209 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;
211 bool ellipsized
= false;
216 /* Set the threshold to one bigger than the actual print
217 * threshold, so that if the line is actually longer than what
218 * we're willing to print, ellipsization will occur. This way
219 * we won't output a misleading line without any indication of
222 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
224 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
226 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
232 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
238 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
244 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
250 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
256 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
262 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
268 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
274 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
280 return log_error_errno(r
, "Failed to get journal fields: %m");
283 log_debug("Skipping message without MESSAGE= field.");
287 if (!(flags
& OUTPUT_SHOW_ALL
))
288 strip_tab_ansi(&message
, &message_len
);
290 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
293 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
300 r
= safe_atou64(monotonic
, &t
);
303 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
306 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
308 fprintf(f
, "[%5llu.%06llu]",
309 (unsigned long long) (t
/ USEC_PER_SEC
),
310 (unsigned long long) (t
% USEC_PER_SEC
));
312 n
+= 1 + 5 + 1 + 6 + 1;
319 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
322 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
325 r
= safe_atou64(realtime
, &x
);
328 r
= sd_journal_get_realtime_usec(j
, &x
);
331 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
333 t
= (time_t) (x
/ USEC_PER_SEC
);
336 case OUTPUT_SHORT_ISO
:
337 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
339 case OUTPUT_SHORT_PRECISE
:
340 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
342 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
343 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
346 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
350 log_error("Failed to format time.");
358 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
359 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
360 n
+= hostname_len
+ 1;
363 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
364 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
365 n
+= identifier_len
+ 1;
366 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
367 fprintf(f
, " %.*s", (int) comm_len
, comm
);
370 fputs(" unknown", f
);
372 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
373 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
375 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
376 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
377 n
+= fake_pid_len
+ 2;
380 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
381 char bytes
[FORMAT_BYTES_MAX
];
382 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
386 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
389 if (flags
& OUTPUT_CATALOG
)
395 static int output_verbose(
404 _cleanup_free_
char *cursor
= NULL
;
406 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
412 sd_journal_set_data_threshold(j
, 0);
414 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
416 log_debug("Source realtime timestamp not found");
418 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
420 _cleanup_free_
char *value
= NULL
;
423 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
425 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
427 r
= safe_atou64(value
, &realtime
);
429 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
434 r
= sd_journal_get_realtime_usec(j
, &realtime
);
436 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
439 r
= sd_journal_get_cursor(j
, &cursor
);
441 return log_error_errno(r
, "Failed to get cursor: %m");
443 fprintf(f
, "%s [%s]\n",
445 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
446 format_timestamp_us(ts
, sizeof(ts
), realtime
),
449 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
452 const char *on
= "", *off
= "";
454 c
= memchr(data
, '=', length
);
456 log_error("Invalid field.");
459 fieldlen
= c
- (const char*) data
;
461 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
466 if (flags
& OUTPUT_SHOW_ALL
||
467 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
468 && utf8_is_printable(data
, length
))) {
469 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
470 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
473 char bytes
[FORMAT_BYTES_MAX
];
475 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
477 (int) (c
- (const char*) data
),
479 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
487 if (flags
& OUTPUT_CATALOG
)
493 static int output_export(
503 usec_t realtime
, monotonic
;
504 _cleanup_free_
char *cursor
= NULL
;
510 sd_journal_set_data_threshold(j
, 0);
512 r
= sd_journal_get_realtime_usec(j
, &realtime
);
514 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
516 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
518 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
520 r
= sd_journal_get_cursor(j
, &cursor
);
522 return log_error_errno(r
, "Failed to get cursor: %m");
526 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
527 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
532 sd_id128_to_string(boot_id
, sid
));
534 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
536 /* We already printed the boot id, from the data in
537 * the header, hence let's suppress it here */
539 startswith(data
, "_BOOT_ID="))
542 if (utf8_is_printable_newline(data
, length
, false))
543 fwrite(data
, length
, 1, f
);
548 c
= memchr(data
, '=', length
);
550 log_error("Invalid field.");
554 fwrite(data
, c
- (const char*) data
, 1, f
);
556 le64
= htole64(length
- (c
- (const char*) data
) - 1);
557 fwrite(&le64
, sizeof(le64
), 1, f
);
558 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
581 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
584 else if (!utf8_is_printable(p
, l
)) {
585 bool not_first
= false;
591 fprintf(f
, ", %u", (uint8_t) *p
);
594 fprintf(f
, "%u", (uint8_t) *p
);
606 if (*p
== '"' || *p
== '\\') {
609 } else if (*p
== '\n')
611 else if ((uint8_t) *p
< ' ')
612 fprintf(f
, "\\u%04x", (uint8_t) *p
);
624 static int output_json(
631 uint64_t realtime
, monotonic
;
632 _cleanup_free_
char *cursor
= NULL
;
639 bool done
, separator
;
643 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
645 r
= sd_journal_get_realtime_usec(j
, &realtime
);
647 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
649 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
651 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
653 r
= sd_journal_get_cursor(j
, &cursor
);
655 return log_error_errno(r
, "Failed to get cursor: %m");
657 if (mode
== OUTPUT_JSON_PRETTY
)
660 "\t\"__CURSOR\" : \"%s\",\n"
661 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
662 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
663 "\t\"_BOOT_ID\" : \"%s\"",
667 sd_id128_to_string(boot_id
, sid
));
669 if (mode
== OUTPUT_JSON_SSE
)
673 "{ \"__CURSOR\" : \"%s\", "
674 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
675 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
676 "\"_BOOT_ID\" : \"%s\"",
680 sd_id128_to_string(boot_id
, sid
));
683 h
= hashmap_new(&string_hash_ops
);
687 /* First round, iterate through the entry and count how often each field appears */
688 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
694 memcmp(data
, "_BOOT_ID=", 9) == 0)
697 eq
= memchr(data
, '=', length
);
701 n
= strndup(data
, eq
- (const char*) data
);
707 u
= PTR_TO_UINT(hashmap_get(h
, n
));
709 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
716 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
732 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
738 /* We already printed the boot id, from the data in
739 * the header, hence let's suppress it here */
741 memcmp(data
, "_BOOT_ID=", 9) == 0)
744 eq
= memchr(data
, '=', length
);
749 if (mode
== OUTPUT_JSON_PRETTY
)
755 m
= eq
- (const char*) data
;
757 n
= strndup(data
, m
);
763 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
765 /* We already printed this, let's jump to the next */
771 /* Field only appears once, output it directly */
773 json_escape(f
, data
, m
, flags
);
776 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
778 hashmap_remove(h
, n
);
787 /* Field appears multiple times, output it as array */
788 json_escape(f
, data
, m
, flags
);
790 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
792 /* Iterate through the end of the list */
794 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
798 if (memcmp(data
, n
, m
) != 0)
801 if (((const char*) data
)[m
] != '=')
805 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
810 hashmap_remove(h
, n
);
814 /* Iterate data fields form the beginning */
824 if (mode
== OUTPUT_JSON_PRETTY
)
826 else if (mode
== OUTPUT_JSON_SSE
)
834 while ((k
= hashmap_steal_first_key(h
)))
842 static int output_cat(
856 sd_journal_set_data_threshold(j
, 0);
858 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
860 /* An entry without MESSAGE=? */
864 return log_error_errno(r
, "Failed to get data: %m");
869 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
875 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
880 OutputFlags flags
) = {
882 [OUTPUT_SHORT
] = output_short
,
883 [OUTPUT_SHORT_ISO
] = output_short
,
884 [OUTPUT_SHORT_PRECISE
] = output_short
,
885 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
886 [OUTPUT_VERBOSE
] = output_verbose
,
887 [OUTPUT_EXPORT
] = output_export
,
888 [OUTPUT_JSON
] = output_json
,
889 [OUTPUT_JSON_PRETTY
] = output_json
,
890 [OUTPUT_JSON_SSE
] = output_json
,
891 [OUTPUT_CAT
] = output_cat
904 assert(mode
< _OUTPUT_MODE_MAX
);
907 n_columns
= columns();
909 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
912 if (ellipsized
&& ret
> 0)
918 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
922 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
925 /* Print a beginning new line if that's request, but only once
926 * on the first line we print. */
929 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
933 static int show_journal(FILE *f
,
944 bool need_seek
= false;
945 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
949 assert(mode
< _OUTPUT_MODE_MAX
);
952 r
= sd_journal_seek_tail(j
);
954 return log_error_errno(r
, "Failed to seek to tail: %m");
956 r
= sd_journal_previous_skip(j
, how_many
);
958 return log_error_errno(r
, "Failed to skip previous: %m");
965 r
= sd_journal_next(j
);
967 return log_error_errno(r
, "Failed to iterate through journal: %m");
975 if (not_before
> 0) {
976 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
978 /* -ESTALE is returned if the
979 timestamp is not from this boot */
983 return log_error_errno(r
, "Failed to get journal time: %m");
985 if (usec
< not_before
)
990 maybe_print_begin_newline(f
, &flags
);
992 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
997 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1001 /* Check whether the cutoff line is too early */
1003 r
= sd_id128_get_boot(&boot_id
);
1005 return log_error_errno(r
, "Failed to get boot id: %m");
1007 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1009 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1011 if (r
> 0 && not_before
< cutoff
) {
1012 maybe_print_begin_newline(f
, &flags
);
1013 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1016 warn_cutoff
= false;
1019 if (!(flags
& OUTPUT_FOLLOW
))
1022 r
= sd_journal_wait(j
, USEC_INFINITY
);
1024 return log_error_errno(r
, "Failed to wait for journal: %m");
1031 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1033 char *m1
, *m2
, *m3
, *m4
;
1038 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1039 m2
= strjoina("COREDUMP_UNIT=", unit
);
1040 m3
= strjoina("UNIT=", unit
);
1041 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1044 /* Look for messages from the service itself */
1045 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1047 /* Look for coredumps of the service */
1048 (r
= sd_journal_add_disjunction(j
)) ||
1049 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1050 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1051 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1053 /* Look for messages from PID 1 about this service */
1054 (r
= sd_journal_add_disjunction(j
)) ||
1055 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1056 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1058 /* Look for messages from authorized daemons about this service */
1059 (r
= sd_journal_add_disjunction(j
)) ||
1060 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1061 (r
= sd_journal_add_match(j
, m4
, 0))
1064 if (r
== 0 && endswith(unit
, ".slice")) {
1065 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1067 /* Show all messages belonging to a slice */
1069 (r
= sd_journal_add_disjunction(j
)) ||
1070 (r
= sd_journal_add_match(j
, m5
, 0))
1077 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1079 char *m1
, *m2
, *m3
, *m4
;
1080 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1085 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1086 m2
= strjoina("USER_UNIT=", unit
);
1087 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1088 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1089 sprintf(muid
, "_UID="UID_FMT
, uid
);
1092 /* Look for messages from the user service itself */
1093 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1094 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1096 /* Look for messages from systemd about this service */
1097 (r
= sd_journal_add_disjunction(j
)) ||
1098 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1099 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1101 /* Look for coredumps of the service */
1102 (r
= sd_journal_add_disjunction(j
)) ||
1103 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1104 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1105 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1107 /* Look for messages from authorized daemons about this service */
1108 (r
= sd_journal_add_disjunction(j
)) ||
1109 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1110 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1111 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1114 if (r
== 0 && endswith(unit
, ".slice")) {
1115 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1117 /* Show all messages belonging to a slice */
1119 (r
= sd_journal_add_disjunction(j
)) ||
1120 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1121 (r
= sd_journal_add_match(j
, muid
, 0))
1128 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1129 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1130 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1140 if (!machine_name_is_valid(machine
))
1143 r
= container_get_leader(machine
, &pid
);
1147 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1151 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1161 pair
[0] = safe_close(pair
[0]);
1163 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1165 _exit(EXIT_FAILURE
);
1167 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1169 _exit(EXIT_FAILURE
);
1171 r
= loop_read_exact(fd
, buf
, 36, false);
1174 _exit(EXIT_FAILURE
);
1176 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1178 _exit(EXIT_FAILURE
);
1180 _exit(EXIT_SUCCESS
);
1183 pair
[1] = safe_close(pair
[1]);
1185 r
= wait_for_terminate(child
, &si
);
1186 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1187 return r
< 0 ? r
: -EIO
;
1189 k
= recv(pair
[0], buf
, 36, 0);
1194 r
= sd_id128_from_string(buf
, boot_id
);
1201 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1202 char match
[9+32+1] = "_BOOT_ID=";
1209 r
= get_boot_id_for_machine(machine
, &boot_id
);
1211 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1213 r
= sd_id128_get_boot(&boot_id
);
1215 return log_error_errno(r
, "Failed to get boot id: %m");
1218 sd_id128_to_string(boot_id
, match
+ 9);
1219 r
= sd_journal_add_match(j
, match
, strlen(match
));
1221 return log_error_errno(r
, "Failed to add match: %m");
1223 r
= sd_journal_add_conjunction(j
);
1225 return log_error_errno(r
, "Failed to add conjunction: %m");
1230 int show_journal_by_unit(
1239 int journal_open_flags
,
1243 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1247 assert(mode
< _OUTPUT_MODE_MAX
);
1253 r
= sd_journal_open(&j
, journal_open_flags
);
1255 return log_error_errno(r
, "Failed to open journal: %m");
1257 r
= add_match_this_boot(j
, NULL
);
1262 r
= add_matches_for_unit(j
, unit
);
1264 r
= add_matches_for_user_unit(j
, unit
, uid
);
1266 return log_error_errno(r
, "Failed to add unit matches: %m");
1268 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1269 _cleanup_free_
char *filter
;
1271 filter
= journal_make_match_string(j
);
1275 log_debug("Journal filter: %s", filter
);
1278 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1281 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1282 [OUTPUT_SHORT
] = "short",
1283 [OUTPUT_SHORT_ISO
] = "short-iso",
1284 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1285 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1286 [OUTPUT_VERBOSE
] = "verbose",
1287 [OUTPUT_EXPORT
] = "export",
1288 [OUTPUT_JSON
] = "json",
1289 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1290 [OUTPUT_JSON_SSE
] = "json-sse",
1291 [OUTPUT_CAT
] = "cat"
1294 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);