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"
36 /* up to three lines (each up to 100 characters),
37 or 300 characters, whichever is less */
38 #define PRINT_LINE_THRESHOLD 3
39 #define PRINT_CHAR_THRESHOLD 300
41 #define JSON_THRESHOLD 4096
43 static int print_catalog(FILE *f, sd_journal *j) {
45 _cleanup_free_ char *t = NULL, *z = NULL;
48 r = sd_journal_get_catalog(j, &t);
52 z = strreplace(strstrip(t), "\n", "\n-- ");
63 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
76 if (memcmp(data, field, fl))
84 memcpy(buf, (const char*) data + fl, nl);
94 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
97 if (flags & OUTPUT_SHOW_ALL)
100 if (l >= PRINT_CHAR_THRESHOLD)
103 if (!utf8_is_printable(p, l))
109 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
110 const char *color_on = "", *color_off = "";
111 const char *pos, *end;
112 bool ellipsized = false;
115 if (flags & OUTPUT_COLOR) {
116 if (priority <= LOG_ERR) {
117 color_on = ANSI_HIGHLIGHT_RED_ON;
118 color_off = ANSI_HIGHLIGHT_OFF;
119 } else if (priority <= LOG_NOTICE) {
120 color_on = ANSI_HIGHLIGHT_ON;
121 color_off = ANSI_HIGHLIGHT_OFF;
125 /* A special case: make sure that we print a newline when
126 the message is empty. */
127 if (message_len == 0)
131 pos < message + message_len;
132 pos = end + 1, line++) {
133 bool continuation = line > 0;
136 for (end = pos; end < message + message_len && *end != '\n'; end++)
141 /* We need to figure out when we are showing not-last line, *and*
142 * will skip subsequent lines. In that case, we will put the dots
143 * at the end of the line, instead of putting dots in the middle
147 line + 1 == PRINT_LINE_THRESHOLD ||
148 end + 1 >= message + PRINT_CHAR_THRESHOLD;
150 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
151 (prefix + len + 1 < n_columns && !tail_line)) {
152 fprintf(f, "%*s%s%.*s%s\n",
153 continuation * prefix, "",
154 color_on, len, pos, color_off);
158 /* Beyond this point, ellipsization will happen. */
161 if (prefix < n_columns && n_columns - prefix >= 3) {
162 if (n_columns - prefix > (unsigned) len + 3)
163 fprintf(f, "%*s%s%.*s...%s\n",
164 continuation * prefix, "",
165 color_on, len, pos, color_off);
167 _cleanup_free_ char *e;
169 e = ellipsize_mem(pos, len, n_columns - prefix,
170 tail_line ? 100 : 90);
172 fprintf(f, "%*s%s%.*s%s\n",
173 continuation * prefix, "",
174 color_on, len, pos, color_off);
176 fprintf(f, "%*s%s%s%s\n",
177 continuation * prefix, "",
178 color_on, e, color_off);
190 static int output_short(
201 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
202 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;
204 bool ellipsized = false;
209 /* Set the threshold to one bigger than the actual print
210 * threshold, so that if the line is actually longer than what
211 * we're willing to print, ellipsization will occur. This way
212 * we won't output a misleading line without any indication of
215 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
217 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
219 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
225 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
231 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
237 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
243 r = parse_field(data, length, "_PID=", &pid, &pid_len);
249 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
255 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
261 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
267 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
278 if (!(flags & OUTPUT_SHOW_ALL))
279 strip_tab_ansi(&message, &message_len);
281 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
284 if (mode == OUTPUT_SHORT_MONOTONIC) {
291 r = safe_atou64(monotonic, &t);
294 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
297 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
299 fprintf(f, "[%5llu.%06llu]",
300 (unsigned long long) (t / USEC_PER_SEC),
301 (unsigned long long) (t % USEC_PER_SEC));
303 n += 1 + 5 + 1 + 6 + 1;
310 struct tm *(*gettime_r)(const time_t *, struct tm *);
313 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
316 r = safe_atou64(realtime, &x);
319 r = sd_journal_get_realtime_usec(j, &x);
322 return log_error_errno(r, "Failed to get realtime timestamp: %m");
324 t = (time_t) (x / USEC_PER_SEC);
327 case OUTPUT_SHORT_ISO:
328 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
330 case OUTPUT_SHORT_PRECISE:
331 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
333 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
334 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
338 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
342 log_error("Failed to format time.");
350 if (hostname && shall_print(hostname, hostname_len, flags)) {
351 fprintf(f, " %.*s", (int) hostname_len, hostname);
352 n += hostname_len + 1;
355 if (identifier && shall_print(identifier, identifier_len, flags)) {
356 fprintf(f, " %.*s", (int) identifier_len, identifier);
357 n += identifier_len + 1;
358 } else if (comm && shall_print(comm, comm_len, flags)) {
359 fprintf(f, " %.*s", (int) comm_len, comm);
362 fputs(" unknown", f);
364 if (pid && shall_print(pid, pid_len, flags)) {
365 fprintf(f, "[%.*s]", (int) pid_len, pid);
367 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
368 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
369 n += fake_pid_len + 2;
372 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
373 char bytes[FORMAT_BYTES_MAX];
374 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
378 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
381 if (flags & OUTPUT_CATALOG)
387 static int output_verbose(
396 _cleanup_free_ char *cursor = NULL;
398 char ts[FORMAT_TIMESTAMP_MAX + 7];
404 sd_journal_set_data_threshold(j, 0);
406 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
408 log_debug("Source realtime timestamp not found");
410 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
411 "Failed to get source realtime timestamp: %s", strerror(-r));
414 _cleanup_free_ char *value = NULL;
417 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
419 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
421 r = safe_atou64(value, &realtime);
423 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
428 r = sd_journal_get_realtime_usec(j, &realtime);
430 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
431 "Failed to get realtime timestamp: %s", strerror(-r));
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=")) {
459 on = ANSI_HIGHLIGHT_ON;
460 off = ANSI_HIGHLIGHT_OFF;
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)
582 else if (!utf8_is_printable(p, l)) {
583 bool not_first = false;
589 fprintf(f, ", %u", (uint8_t) *p);
592 fprintf(f, "%u", (uint8_t) *p);
604 if (*p == '"' || *p == '\\') {
607 } else if (*p == '\n')
610 fprintf(f, "\\u%04x", *p);
622 static int output_json(
629 uint64_t realtime, monotonic;
630 _cleanup_free_ char *cursor = NULL;
637 bool done, separator;
641 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
643 r = sd_journal_get_realtime_usec(j, &realtime);
645 return log_error_errno(r, "Failed to get realtime timestamp: %m");
647 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
649 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
651 r = sd_journal_get_cursor(j, &cursor);
653 return log_error_errno(r, "Failed to get cursor: %m");
655 if (mode == OUTPUT_JSON_PRETTY)
658 "\t\"__CURSOR\" : \"%s\",\n"
659 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
660 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
661 "\t\"_BOOT_ID\" : \"%s\"",
665 sd_id128_to_string(boot_id, sid));
667 if (mode == OUTPUT_JSON_SSE)
671 "{ \"__CURSOR\" : \"%s\", "
672 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
673 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
674 "\"_BOOT_ID\" : \"%s\"",
678 sd_id128_to_string(boot_id, sid));
681 h = hashmap_new(&string_hash_ops);
685 /* First round, iterate through the entry and count how often each field appears */
686 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
692 memcmp(data, "_BOOT_ID=", 9) == 0)
695 eq = memchr(data, '=', length);
699 n = strndup(data, eq - (const char*) data);
705 u = PTR_TO_UINT(hashmap_get(h, n));
707 r = hashmap_put(h, n, UINT_TO_PTR(1));
713 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
727 SD_JOURNAL_FOREACH_DATA(j, data, length) {
733 /* We already printed the boot id, from the data in
734 * the header, hence let's suppress it here */
736 memcmp(data, "_BOOT_ID=", 9) == 0)
739 eq = memchr(data, '=', length);
744 if (mode == OUTPUT_JSON_PRETTY)
750 m = eq - (const char*) data;
752 n = strndup(data, m);
758 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
760 /* We already printed this, let's jump to the next */
766 /* Field only appears once, output it directly */
768 json_escape(f, data, m, flags);
771 json_escape(f, eq + 1, length - m - 1, flags);
773 hashmap_remove(h, n);
782 /* Field appears multiple times, output it as array */
783 json_escape(f, data, m, flags);
785 json_escape(f, eq + 1, length - m - 1, flags);
787 /* Iterate through the end of the list */
789 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
793 if (memcmp(data, n, m) != 0)
796 if (((const char*) data)[m] != '=')
800 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
805 hashmap_remove(h, n);
809 /* Iterate data fields form the beginning */
819 if (mode == OUTPUT_JSON_PRETTY)
821 else if (mode == OUTPUT_JSON_SSE)
829 while ((k = hashmap_steal_first_key(h)))
837 static int output_cat(
851 sd_journal_set_data_threshold(j, 0);
853 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
855 /* An entry without MESSAGE=? */
859 return log_error_errno(r, "Failed to get data: %m");
864 fwrite((const char*) data + 8, 1, l - 8, f);
870 static int (*output_funcs[_OUTPUT_MODE_MAX])(
875 OutputFlags flags) = {
877 [OUTPUT_SHORT] = output_short,
878 [OUTPUT_SHORT_ISO] = output_short,
879 [OUTPUT_SHORT_PRECISE] = output_short,
880 [OUTPUT_SHORT_MONOTONIC] = output_short,
881 [OUTPUT_VERBOSE] = output_verbose,
882 [OUTPUT_EXPORT] = output_export,
883 [OUTPUT_JSON] = output_json,
884 [OUTPUT_JSON_PRETTY] = output_json,
885 [OUTPUT_JSON_SSE] = output_json,
886 [OUTPUT_CAT] = output_cat
899 assert(mode < _OUTPUT_MODE_MAX);
902 n_columns = columns();
904 ret = output_funcs[mode](f, j, mode, n_columns, flags);
907 if (ellipsized && ret > 0)
913 static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
917 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
920 /* Print a beginning new line if that's request, but only once
921 * on the first line we print. */
924 *flags &= ~OUTPUT_BEGIN_NEWLINE;
928 static int show_journal(FILE *f,
939 bool need_seek = false;
940 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
944 assert(mode < _OUTPUT_MODE_MAX);
947 r = sd_journal_seek_tail(j);
951 r = sd_journal_previous_skip(j, how_many);
960 r = sd_journal_next(j);
970 if (not_before > 0) {
971 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
973 /* -ESTALE is returned if the
974 timestamp is not from this boot */
980 if (usec < not_before)
985 maybe_print_begin_newline(f, &flags);
987 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
992 if (warn_cutoff && line < how_many && not_before > 0) {
996 /* Check whether the cutoff line is too early */
998 r = sd_id128_get_boot(&boot_id);
1002 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1006 if (r > 0 && not_before < cutoff) {
1007 maybe_print_begin_newline(f, &flags);
1008 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1011 warn_cutoff = false;
1014 if (!(flags & OUTPUT_FOLLOW))
1017 r = sd_journal_wait(j, USEC_INFINITY);
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, &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, 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);
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);
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);
1264 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
1265 _cleanup_free_ char *filter;
1267 filter = journal_make_match_string(j);
1268 log_debug("Journal filter: %s", filter);
1271 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1274 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1275 [OUTPUT_SHORT] = "short",
1276 [OUTPUT_SHORT_ISO] = "short-iso",
1277 [OUTPUT_SHORT_PRECISE] = "short-precise",
1278 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1279 [OUTPUT_VERBOSE] = "verbose",
1280 [OUTPUT_EXPORT] = "export",
1281 [OUTPUT_JSON] = "json",
1282 [OUTPUT_JSON_PRETTY] = "json-pretty",
1283 [OUTPUT_JSON_SSE] = "json-sse",
1284 [OUTPUT_CAT] = "cat"
1287 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);