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-util.h"
39 #include "terminal-util.h"
43 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
44 #define PRINT_LINE_THRESHOLD 3
45 #define PRINT_CHAR_THRESHOLD 300
47 #define JSON_THRESHOLD 4096
49 static int print_catalog(FILE *f
, sd_journal
*j
) {
51 _cleanup_free_
char *t
= NULL
, *z
= NULL
;
54 r
= sd_journal_get_catalog(j
, &t
);
58 z
= strreplace(strstrip(t
), "\n", "\n-- ");
69 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
82 if (memcmp(data
, field
, fl
))
90 memcpy(buf
, (const char*) data
+ fl
, nl
);
100 static bool shall_print(const char *p
, size_t l
, OutputFlags flags
) {
103 if (flags
& OUTPUT_SHOW_ALL
)
106 if (l
>= PRINT_CHAR_THRESHOLD
)
109 if (!utf8_is_printable(p
, l
))
115 static bool print_multiline(FILE *f
, unsigned prefix
, unsigned n_columns
, OutputFlags flags
, int priority
, const char* message
, size_t message_len
) {
116 const char *color_on
= "", *color_off
= "";
117 const char *pos
, *end
;
118 bool ellipsized
= false;
121 if (flags
& OUTPUT_COLOR
) {
122 if (priority
<= LOG_ERR
) {
123 color_on
= ANSI_HIGHLIGHT_RED
;
124 color_off
= ANSI_NORMAL
;
125 } else if (priority
<= LOG_NOTICE
) {
126 color_on
= ANSI_HIGHLIGHT
;
127 color_off
= ANSI_NORMAL
;
131 /* A special case: make sure that we print a newline when
132 the message is empty. */
133 if (message_len
== 0)
137 pos
< message
+ message_len
;
138 pos
= end
+ 1, line
++) {
139 bool continuation
= line
> 0;
142 for (end
= pos
; end
< message
+ message_len
&& *end
!= '\n'; end
++)
147 /* We need to figure out when we are showing not-last line, *and*
148 * will skip subsequent lines. In that case, we will put the dots
149 * at the end of the line, instead of putting dots in the middle
153 line
+ 1 == PRINT_LINE_THRESHOLD
||
154 end
+ 1 >= message
+ PRINT_CHAR_THRESHOLD
;
156 if (flags
& (OUTPUT_FULL_WIDTH
| OUTPUT_SHOW_ALL
) ||
157 (prefix
+ len
+ 1 < n_columns
&& !tail_line
)) {
158 fprintf(f
, "%*s%s%.*s%s\n",
159 continuation
* prefix
, "",
160 color_on
, len
, pos
, color_off
);
164 /* Beyond this point, ellipsization will happen. */
167 if (prefix
< n_columns
&& n_columns
- prefix
>= 3) {
168 if (n_columns
- prefix
> (unsigned) len
+ 3)
169 fprintf(f
, "%*s%s%.*s...%s\n",
170 continuation
* prefix
, "",
171 color_on
, len
, pos
, color_off
);
173 _cleanup_free_
char *e
;
175 e
= ellipsize_mem(pos
, len
, n_columns
- prefix
,
176 tail_line
? 100 : 90);
178 fprintf(f
, "%*s%s%.*s%s\n",
179 continuation
* prefix
, "",
180 color_on
, len
, pos
, color_off
);
182 fprintf(f
, "%*s%s%s%s\n",
183 continuation
* prefix
, "",
184 color_on
, e
, color_off
);
196 static int output_short(
207 _cleanup_free_
char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
, *priority
= NULL
;
208 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;
210 bool ellipsized
= false;
215 /* Set the threshold to one bigger than the actual print
216 * threshold, so that if the line is actually longer than what
217 * we're willing to print, ellipsization will occur. This way
218 * we won't output a misleading line without any indication of
221 sd_journal_set_data_threshold(j
, flags
& (OUTPUT_SHOW_ALL
|OUTPUT_FULL_WIDTH
) ? 0 : PRINT_CHAR_THRESHOLD
+ 1);
223 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
225 r
= parse_field(data
, length
, "PRIORITY=", &priority
, &priority_len
);
231 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
237 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
243 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
249 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
255 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
261 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
267 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
273 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
279 return log_error_errno(r
, "Failed to get journal fields: %m");
282 log_debug("Skipping message without MESSAGE= field.");
286 if (!(flags
& OUTPUT_SHOW_ALL
))
287 strip_tab_ansi(&message
, &message_len
);
289 if (priority_len
== 1 && *priority
>= '0' && *priority
<= '7')
292 if (mode
== OUTPUT_SHORT_MONOTONIC
) {
299 r
= safe_atou64(monotonic
, &t
);
302 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
305 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
307 fprintf(f
, "[%5llu.%06llu]",
308 (unsigned long long) (t
/ USEC_PER_SEC
),
309 (unsigned long long) (t
% USEC_PER_SEC
));
311 n
+= 1 + 5 + 1 + 6 + 1;
318 struct tm
*(*gettime_r
)(const time_t *, struct tm
*);
321 gettime_r
= (flags
& OUTPUT_UTC
) ? gmtime_r
: localtime_r
;
324 r
= safe_atou64(realtime
, &x
);
327 r
= sd_journal_get_realtime_usec(j
, &x
);
330 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
332 t
= (time_t) (x
/ USEC_PER_SEC
);
335 case OUTPUT_SHORT_ISO
:
336 r
= strftime(buf
, sizeof(buf
), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t
, &tm
));
338 case OUTPUT_SHORT_PRECISE
:
339 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
341 snprintf(buf
+ strlen(buf
), sizeof(buf
) - strlen(buf
),
342 ".%06llu", (unsigned long long) (x
% USEC_PER_SEC
));
345 r
= strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", gettime_r(&t
, &tm
));
349 log_error("Failed to format time.");
357 if (hostname
&& shall_print(hostname
, hostname_len
, flags
)) {
358 fprintf(f
, " %.*s", (int) hostname_len
, hostname
);
359 n
+= hostname_len
+ 1;
362 if (identifier
&& shall_print(identifier
, identifier_len
, flags
)) {
363 fprintf(f
, " %.*s", (int) identifier_len
, identifier
);
364 n
+= identifier_len
+ 1;
365 } else if (comm
&& shall_print(comm
, comm_len
, flags
)) {
366 fprintf(f
, " %.*s", (int) comm_len
, comm
);
369 fputs(" unknown", f
);
371 if (pid
&& shall_print(pid
, pid_len
, flags
)) {
372 fprintf(f
, "[%.*s]", (int) pid_len
, pid
);
374 } else if (fake_pid
&& shall_print(fake_pid
, fake_pid_len
, flags
)) {
375 fprintf(f
, "[%.*s]", (int) fake_pid_len
, fake_pid
);
376 n
+= fake_pid_len
+ 2;
379 if (!(flags
& OUTPUT_SHOW_ALL
) && !utf8_is_printable(message
, message_len
)) {
380 char bytes
[FORMAT_BYTES_MAX
];
381 fprintf(f
, ": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
385 print_multiline(f
, n
+ 2, n_columns
, flags
, p
, message
, message_len
);
388 if (flags
& OUTPUT_CATALOG
)
394 static int output_verbose(
403 _cleanup_free_
char *cursor
= NULL
;
405 char ts
[FORMAT_TIMESTAMP_MAX
+ 7];
411 sd_journal_set_data_threshold(j
, 0);
413 r
= sd_journal_get_data(j
, "_SOURCE_REALTIME_TIMESTAMP", &data
, &length
);
415 log_debug("Source realtime timestamp not found");
417 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get source realtime timestamp: %m");
419 _cleanup_free_
char *value
= NULL
;
422 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &value
, &size
);
424 log_debug_errno(r
, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
426 r
= safe_atou64(value
, &realtime
);
428 log_debug_errno(r
, "Failed to parse realtime timestamp: %m");
433 r
= sd_journal_get_realtime_usec(j
, &realtime
);
435 return log_full_errno(r
== -EADDRNOTAVAIL
? LOG_DEBUG
: LOG_ERR
, r
, "Failed to get realtime timestamp: %m");
438 r
= sd_journal_get_cursor(j
, &cursor
);
440 return log_error_errno(r
, "Failed to get cursor: %m");
442 fprintf(f
, "%s [%s]\n",
444 format_timestamp_us_utc(ts
, sizeof(ts
), realtime
) :
445 format_timestamp_us(ts
, sizeof(ts
), realtime
),
448 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
451 const char *on
= "", *off
= "";
453 c
= memchr(data
, '=', length
);
455 log_error("Invalid field.");
458 fieldlen
= c
- (const char*) data
;
460 if (flags
& OUTPUT_COLOR
&& startswith(data
, "MESSAGE=")) {
465 if (flags
& OUTPUT_SHOW_ALL
||
466 (((length
< PRINT_CHAR_THRESHOLD
) || flags
& OUTPUT_FULL_WIDTH
)
467 && utf8_is_printable(data
, length
))) {
468 fprintf(f
, " %s%.*s=", on
, fieldlen
, (const char*)data
);
469 print_multiline(f
, 4 + fieldlen
+ 1, 0, OUTPUT_FULL_WIDTH
, 0, c
+ 1, length
- fieldlen
- 1);
472 char bytes
[FORMAT_BYTES_MAX
];
474 fprintf(f
, " %s%.*s=[%s blob data]%s\n",
476 (int) (c
- (const char*) data
),
478 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1),
486 if (flags
& OUTPUT_CATALOG
)
492 static int output_export(
502 usec_t realtime
, monotonic
;
503 _cleanup_free_
char *cursor
= NULL
;
509 sd_journal_set_data_threshold(j
, 0);
511 r
= sd_journal_get_realtime_usec(j
, &realtime
);
513 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
515 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
517 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
519 r
= sd_journal_get_cursor(j
, &cursor
);
521 return log_error_errno(r
, "Failed to get cursor: %m");
525 "__REALTIME_TIMESTAMP="USEC_FMT
"\n"
526 "__MONOTONIC_TIMESTAMP="USEC_FMT
"\n"
531 sd_id128_to_string(boot_id
, sid
));
533 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
535 /* We already printed the boot id, from the data in
536 * the header, hence let's suppress it here */
538 startswith(data
, "_BOOT_ID="))
541 if (utf8_is_printable_newline(data
, length
, false))
542 fwrite(data
, length
, 1, f
);
547 c
= memchr(data
, '=', length
);
549 log_error("Invalid field.");
553 fwrite(data
, c
- (const char*) data
, 1, f
);
555 le64
= htole64(length
- (c
- (const char*) data
) - 1);
556 fwrite(&le64
, sizeof(le64
), 1, f
);
557 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, f
);
580 if (!(flags
& OUTPUT_SHOW_ALL
) && l
>= JSON_THRESHOLD
)
583 else if (!utf8_is_printable(p
, l
)) {
584 bool not_first
= false;
590 fprintf(f
, ", %u", (uint8_t) *p
);
593 fprintf(f
, "%u", (uint8_t) *p
);
605 if (*p
== '"' || *p
== '\\') {
608 } else if (*p
== '\n')
610 else if ((uint8_t) *p
< ' ')
611 fprintf(f
, "\\u%04x", (uint8_t) *p
);
623 static int output_json(
630 uint64_t realtime
, monotonic
;
631 _cleanup_free_
char *cursor
= NULL
;
638 bool done
, separator
;
642 sd_journal_set_data_threshold(j
, flags
& OUTPUT_SHOW_ALL
? 0 : JSON_THRESHOLD
);
644 r
= sd_journal_get_realtime_usec(j
, &realtime
);
646 return log_error_errno(r
, "Failed to get realtime timestamp: %m");
648 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
650 return log_error_errno(r
, "Failed to get monotonic timestamp: %m");
652 r
= sd_journal_get_cursor(j
, &cursor
);
654 return log_error_errno(r
, "Failed to get cursor: %m");
656 if (mode
== OUTPUT_JSON_PRETTY
)
659 "\t\"__CURSOR\" : \"%s\",\n"
660 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\",\n"
661 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\",\n"
662 "\t\"_BOOT_ID\" : \"%s\"",
666 sd_id128_to_string(boot_id
, sid
));
668 if (mode
== OUTPUT_JSON_SSE
)
672 "{ \"__CURSOR\" : \"%s\", "
673 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT
"\", "
674 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT
"\", "
675 "\"_BOOT_ID\" : \"%s\"",
679 sd_id128_to_string(boot_id
, sid
));
682 h
= hashmap_new(&string_hash_ops
);
686 /* First round, iterate through the entry and count how often each field appears */
687 JOURNAL_FOREACH_DATA_RETVAL(j
, data
, length
, r
) {
693 memcmp(data
, "_BOOT_ID=", 9) == 0)
696 eq
= memchr(data
, '=', length
);
700 n
= strndup(data
, eq
- (const char*) data
);
706 u
= PTR_TO_UINT(hashmap_get(h
, n
));
708 r
= hashmap_put(h
, n
, UINT_TO_PTR(1));
715 r
= hashmap_update(h
, n
, UINT_TO_PTR(u
+ 1));
731 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
737 /* We already printed the boot id, from the data in
738 * the header, hence let's suppress it here */
740 memcmp(data
, "_BOOT_ID=", 9) == 0)
743 eq
= memchr(data
, '=', length
);
748 if (mode
== OUTPUT_JSON_PRETTY
)
754 m
= eq
- (const char*) data
;
756 n
= strndup(data
, m
);
762 u
= PTR_TO_UINT(hashmap_get2(h
, n
, (void**) &kk
));
764 /* We already printed this, let's jump to the next */
770 /* Field only appears once, output it directly */
772 json_escape(f
, data
, m
, flags
);
775 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
777 hashmap_remove(h
, n
);
786 /* Field appears multiple times, output it as array */
787 json_escape(f
, data
, m
, flags
);
789 json_escape(f
, eq
+ 1, length
- m
- 1, flags
);
791 /* Iterate through the end of the list */
793 while (sd_journal_enumerate_data(j
, &data
, &length
) > 0) {
797 if (memcmp(data
, n
, m
) != 0)
800 if (((const char*) data
)[m
] != '=')
804 json_escape(f
, (const char*) data
+ m
+ 1, length
- m
- 1, flags
);
809 hashmap_remove(h
, n
);
813 /* Iterate data fields form the beginning */
823 if (mode
== OUTPUT_JSON_PRETTY
)
825 else if (mode
== OUTPUT_JSON_SSE
)
833 while ((k
= hashmap_steal_first_key(h
)))
841 static int output_cat(
855 sd_journal_set_data_threshold(j
, 0);
857 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
859 /* An entry without MESSAGE=? */
863 return log_error_errno(r
, "Failed to get data: %m");
868 fwrite((const char*) data
+ 8, 1, l
- 8, f
);
874 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(
879 OutputFlags flags
) = {
881 [OUTPUT_SHORT
] = output_short
,
882 [OUTPUT_SHORT_ISO
] = output_short
,
883 [OUTPUT_SHORT_PRECISE
] = output_short
,
884 [OUTPUT_SHORT_MONOTONIC
] = output_short
,
885 [OUTPUT_VERBOSE
] = output_verbose
,
886 [OUTPUT_EXPORT
] = output_export
,
887 [OUTPUT_JSON
] = output_json
,
888 [OUTPUT_JSON_PRETTY
] = output_json
,
889 [OUTPUT_JSON_SSE
] = output_json
,
890 [OUTPUT_CAT
] = output_cat
903 assert(mode
< _OUTPUT_MODE_MAX
);
906 n_columns
= columns();
908 ret
= output_funcs
[mode
](f
, j
, mode
, n_columns
, flags
);
911 if (ellipsized
&& ret
> 0)
917 static int maybe_print_begin_newline(FILE *f
, OutputFlags
*flags
) {
921 if (!(*flags
& OUTPUT_BEGIN_NEWLINE
))
924 /* Print a beginning new line if that's request, but only once
925 * on the first line we print. */
928 *flags
&= ~OUTPUT_BEGIN_NEWLINE
;
932 static int show_journal(FILE *f
,
943 bool need_seek
= false;
944 int warn_cutoff
= flags
& OUTPUT_WARN_CUTOFF
;
948 assert(mode
< _OUTPUT_MODE_MAX
);
951 r
= sd_journal_seek_tail(j
);
953 return log_error_errno(r
, "Failed to seek to tail: %m");
955 r
= sd_journal_previous_skip(j
, how_many
);
957 return log_error_errno(r
, "Failed to skip previous: %m");
964 r
= sd_journal_next(j
);
966 return log_error_errno(r
, "Failed to iterate through journal: %m");
974 if (not_before
> 0) {
975 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
977 /* -ESTALE is returned if the
978 timestamp is not from this boot */
982 return log_error_errno(r
, "Failed to get journal time: %m");
984 if (usec
< not_before
)
989 maybe_print_begin_newline(f
, &flags
);
991 r
= output_journal(f
, j
, mode
, n_columns
, flags
, ellipsized
);
996 if (warn_cutoff
&& line
< how_many
&& not_before
> 0) {
1000 /* Check whether the cutoff line is too early */
1002 r
= sd_id128_get_boot(&boot_id
);
1004 return log_error_errno(r
, "Failed to get boot id: %m");
1006 r
= sd_journal_get_cutoff_monotonic_usec(j
, boot_id
, &cutoff
, NULL
);
1008 return log_error_errno(r
, "Failed to get journal cutoff time: %m");
1010 if (r
> 0 && not_before
< cutoff
) {
1011 maybe_print_begin_newline(f
, &flags
);
1012 fprintf(f
, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1015 warn_cutoff
= false;
1018 if (!(flags
& OUTPUT_FOLLOW
))
1021 r
= sd_journal_wait(j
, USEC_INFINITY
);
1023 return log_error_errno(r
, "Failed to wait for journal: %m");
1030 int add_matches_for_unit(sd_journal
*j
, const char *unit
) {
1032 char *m1
, *m2
, *m3
, *m4
;
1037 m1
= strjoina("_SYSTEMD_UNIT=", unit
);
1038 m2
= strjoina("COREDUMP_UNIT=", unit
);
1039 m3
= strjoina("UNIT=", unit
);
1040 m4
= strjoina("OBJECT_SYSTEMD_UNIT=", unit
);
1043 /* Look for messages from the service itself */
1044 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1046 /* Look for coredumps of the service */
1047 (r
= sd_journal_add_disjunction(j
)) ||
1048 (r
= sd_journal_add_match(j
, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1049 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1050 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1052 /* Look for messages from PID 1 about this service */
1053 (r
= sd_journal_add_disjunction(j
)) ||
1054 (r
= sd_journal_add_match(j
, "_PID=1", 0)) ||
1055 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1057 /* Look for messages from authorized daemons about this service */
1058 (r
= sd_journal_add_disjunction(j
)) ||
1059 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1060 (r
= sd_journal_add_match(j
, m4
, 0))
1063 if (r
== 0 && endswith(unit
, ".slice")) {
1064 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1066 /* Show all messages belonging to a slice */
1068 (r
= sd_journal_add_disjunction(j
)) ||
1069 (r
= sd_journal_add_match(j
, m5
, 0))
1076 int add_matches_for_user_unit(sd_journal
*j
, const char *unit
, uid_t uid
) {
1078 char *m1
, *m2
, *m3
, *m4
;
1079 char muid
[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t
)];
1084 m1
= strjoina("_SYSTEMD_USER_UNIT=", unit
);
1085 m2
= strjoina("USER_UNIT=", unit
);
1086 m3
= strjoina("COREDUMP_USER_UNIT=", unit
);
1087 m4
= strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit
);
1088 sprintf(muid
, "_UID="UID_FMT
, uid
);
1091 /* Look for messages from the user service itself */
1092 (r
= sd_journal_add_match(j
, m1
, 0)) ||
1093 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1095 /* Look for messages from systemd about this service */
1096 (r
= sd_journal_add_disjunction(j
)) ||
1097 (r
= sd_journal_add_match(j
, m2
, 0)) ||
1098 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1100 /* Look for coredumps of the service */
1101 (r
= sd_journal_add_disjunction(j
)) ||
1102 (r
= sd_journal_add_match(j
, m3
, 0)) ||
1103 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1104 (r
= sd_journal_add_match(j
, "_UID=0", 0)) ||
1106 /* Look for messages from authorized daemons about this service */
1107 (r
= sd_journal_add_disjunction(j
)) ||
1108 (r
= sd_journal_add_match(j
, m4
, 0)) ||
1109 (r
= sd_journal_add_match(j
, muid
, 0)) ||
1110 (r
= sd_journal_add_match(j
, "_UID=0", 0))
1113 if (r
== 0 && endswith(unit
, ".slice")) {
1114 char *m5
= strappend("_SYSTEMD_SLICE=", unit
);
1116 /* Show all messages belonging to a slice */
1118 (r
= sd_journal_add_disjunction(j
)) ||
1119 (r
= sd_journal_add_match(j
, m5
, 0)) ||
1120 (r
= sd_journal_add_match(j
, muid
, 0))
1127 static int get_boot_id_for_machine(const char *machine
, sd_id128_t
*boot_id
) {
1128 _cleanup_close_pair_
int pair
[2] = { -1, -1 };
1129 _cleanup_close_
int pidnsfd
= -1, mntnsfd
= -1, rootfd
= -1;
1139 if (!machine_name_is_valid(machine
))
1142 r
= container_get_leader(machine
, &pid
);
1146 r
= namespace_open(pid
, &pidnsfd
, &mntnsfd
, NULL
, NULL
, &rootfd
);
1150 if (socketpair(AF_UNIX
, SOCK_DGRAM
, 0, pair
) < 0)
1160 pair
[0] = safe_close(pair
[0]);
1162 r
= namespace_enter(pidnsfd
, mntnsfd
, -1, -1, rootfd
);
1164 _exit(EXIT_FAILURE
);
1166 fd
= open("/proc/sys/kernel/random/boot_id", O_RDONLY
|O_CLOEXEC
|O_NOCTTY
);
1168 _exit(EXIT_FAILURE
);
1170 r
= loop_read_exact(fd
, buf
, 36, false);
1173 _exit(EXIT_FAILURE
);
1175 k
= send(pair
[1], buf
, 36, MSG_NOSIGNAL
);
1177 _exit(EXIT_FAILURE
);
1179 _exit(EXIT_SUCCESS
);
1182 pair
[1] = safe_close(pair
[1]);
1184 r
= wait_for_terminate(child
, &si
);
1185 if (r
< 0 || si
.si_code
!= CLD_EXITED
|| si
.si_status
!= EXIT_SUCCESS
)
1186 return r
< 0 ? r
: -EIO
;
1188 k
= recv(pair
[0], buf
, 36, 0);
1193 r
= sd_id128_from_string(buf
, boot_id
);
1200 int add_match_this_boot(sd_journal
*j
, const char *machine
) {
1201 char match
[9+32+1] = "_BOOT_ID=";
1208 r
= get_boot_id_for_machine(machine
, &boot_id
);
1210 return log_error_errno(r
, "Failed to get boot id of container %s: %m", machine
);
1212 r
= sd_id128_get_boot(&boot_id
);
1214 return log_error_errno(r
, "Failed to get boot id: %m");
1217 sd_id128_to_string(boot_id
, match
+ 9);
1218 r
= sd_journal_add_match(j
, match
, strlen(match
));
1220 return log_error_errno(r
, "Failed to add match: %m");
1222 r
= sd_journal_add_conjunction(j
);
1224 return log_error_errno(r
, "Failed to add conjunction: %m");
1229 int show_journal_by_unit(
1238 int journal_open_flags
,
1242 _cleanup_journal_close_ sd_journal
*j
= NULL
;
1246 assert(mode
< _OUTPUT_MODE_MAX
);
1252 r
= sd_journal_open(&j
, journal_open_flags
);
1254 return log_error_errno(r
, "Failed to open journal: %m");
1256 r
= add_match_this_boot(j
, NULL
);
1261 r
= add_matches_for_unit(j
, unit
);
1263 r
= add_matches_for_user_unit(j
, unit
, uid
);
1265 return log_error_errno(r
, "Failed to add unit matches: %m");
1267 if (_unlikely_(log_get_max_level() >= LOG_DEBUG
)) {
1268 _cleanup_free_
char *filter
;
1270 filter
= journal_make_match_string(j
);
1274 log_debug("Journal filter: %s", filter
);
1277 return show_journal(f
, j
, mode
, n_columns
, not_before
, how_many
, flags
, ellipsized
);
1280 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
1281 [OUTPUT_SHORT
] = "short",
1282 [OUTPUT_SHORT_ISO
] = "short-iso",
1283 [OUTPUT_SHORT_PRECISE
] = "short-precise",
1284 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
1285 [OUTPUT_VERBOSE
] = "verbose",
1286 [OUTPUT_EXPORT
] = "export",
1287 [OUTPUT_JSON
] = "json",
1288 [OUTPUT_JSON_PRETTY
] = "json-pretty",
1289 [OUTPUT_JSON_SSE
] = "json-sse",
1290 [OUTPUT_CAT
] = "cat"
1293 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);