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"
35 /* up to three lines (each up to 100 characters),
36 or 300 characters, whichever is less */
37 #define PRINT_LINE_THRESHOLD 3
38 #define PRINT_CHAR_THRESHOLD 300
40 #define JSON_THRESHOLD 4096
42 static int print_catalog(FILE *f, sd_journal *j) {
44 _cleanup_free_ char *t = NULL, *z = NULL;
47 r = sd_journal_get_catalog(j, &t);
51 z = strreplace(strstrip(t), "\n", "\n-- ");
62 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
75 if (memcmp(data, field, fl))
83 memcpy(buf, (const char*) data + fl, nl);
93 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
96 if (flags & OUTPUT_SHOW_ALL)
99 if (l >= PRINT_CHAR_THRESHOLD)
102 if (!utf8_is_printable(p, l))
108 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
109 const char *color_on = "", *color_off = "";
110 const char *pos, *end;
111 bool ellipsized = false;
114 if (flags & OUTPUT_COLOR) {
115 if (priority <= LOG_ERR) {
116 color_on = ANSI_HIGHLIGHT_RED_ON;
117 color_off = ANSI_HIGHLIGHT_OFF;
118 } else if (priority <= LOG_NOTICE) {
119 color_on = ANSI_HIGHLIGHT_ON;
120 color_off = ANSI_HIGHLIGHT_OFF;
124 /* A special case: make sure that we print a newline when
125 the message is empty. */
126 if (message_len == 0)
130 pos < message + message_len;
131 pos = end + 1, line++) {
132 bool continuation = line > 0;
135 for (end = pos; end < message + message_len && *end != '\n'; end++)
140 /* We need to figure out when we are showing not-last line, *and*
141 * will skip subsequent lines. In that case, we will put the dots
142 * at the end of the line, instead of putting dots in the middle
146 line + 1 == PRINT_LINE_THRESHOLD ||
147 end + 1 >= message + PRINT_CHAR_THRESHOLD;
149 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
150 (prefix + len + 1 < n_columns && !tail_line)) {
151 fprintf(f, "%*s%s%.*s%s\n",
152 continuation * prefix, "",
153 color_on, len, pos, color_off);
157 /* Beyond this point, ellipsization will happen. */
160 if (prefix < n_columns && n_columns - prefix >= 3) {
161 if (n_columns - prefix > (unsigned) len + 3)
162 fprintf(f, "%*s%s%.*s...%s\n",
163 continuation * prefix, "",
164 color_on, len, pos, color_off);
166 _cleanup_free_ char *e;
168 e = ellipsize_mem(pos, len, n_columns - prefix,
169 tail_line ? 100 : 90);
171 fprintf(f, "%*s%s%.*s%s\n",
172 continuation * prefix, "",
173 color_on, len, pos, color_off);
175 fprintf(f, "%*s%s%s%s\n",
176 continuation * prefix, "",
177 color_on, e, color_off);
189 static int output_short(
200 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
201 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;
203 bool ellipsized = false;
208 /* Set the threshold to one bigger than the actual print
209 * threshold, so that if the line is actually longer than what
210 * we're willing to print, ellipsization will occur. This way
211 * we won't output a misleading line without any indication of
214 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
216 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
218 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
224 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
230 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
236 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
242 r = parse_field(data, length, "_PID=", &pid, &pid_len);
248 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
254 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
260 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
266 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
277 if (!(flags & OUTPUT_SHOW_ALL))
278 strip_tab_ansi(&message, &message_len);
280 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
283 if (mode == OUTPUT_SHORT_MONOTONIC) {
290 r = safe_atou64(monotonic, &t);
293 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
296 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
298 fprintf(f, "[%5llu.%06llu]",
299 (unsigned long long) (t / USEC_PER_SEC),
300 (unsigned long long) (t % USEC_PER_SEC));
302 n += 1 + 5 + 1 + 6 + 1;
309 struct tm *(*gettime_r)(const time_t *, struct tm *);
312 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
315 r = safe_atou64(realtime, &x);
318 r = sd_journal_get_realtime_usec(j, &x);
321 return log_error_errno(r, "Failed to get realtime timestamp: %m");
323 t = (time_t) (x / USEC_PER_SEC);
326 case OUTPUT_SHORT_ISO:
327 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
329 case OUTPUT_SHORT_PRECISE:
330 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
332 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
333 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
337 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
341 log_error("Failed to format time.");
349 if (hostname && shall_print(hostname, hostname_len, flags)) {
350 fprintf(f, " %.*s", (int) hostname_len, hostname);
351 n += hostname_len + 1;
354 if (identifier && shall_print(identifier, identifier_len, flags)) {
355 fprintf(f, " %.*s", (int) identifier_len, identifier);
356 n += identifier_len + 1;
357 } else if (comm && shall_print(comm, comm_len, flags)) {
358 fprintf(f, " %.*s", (int) comm_len, comm);
361 fputs(" unknown", f);
363 if (pid && shall_print(pid, pid_len, flags)) {
364 fprintf(f, "[%.*s]", (int) pid_len, pid);
366 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
367 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
368 n += fake_pid_len + 2;
371 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
372 char bytes[FORMAT_BYTES_MAX];
373 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
377 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
380 if (flags & OUTPUT_CATALOG)
386 static int output_verbose(
395 _cleanup_free_ char *cursor = NULL;
397 char ts[FORMAT_TIMESTAMP_MAX + 7];
403 sd_journal_set_data_threshold(j, 0);
405 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
407 log_debug("Source realtime timestamp not found");
409 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
410 "Failed to get source realtime timestamp: %s", strerror(-r));
413 _cleanup_free_ char *value = NULL;
416 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
418 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
420 r = safe_atou64(value, &realtime);
422 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
427 r = sd_journal_get_realtime_usec(j, &realtime);
429 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
430 "Failed to get realtime timestamp: %s", strerror(-r));
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)
581 else if (!utf8_is_printable(p, l)) {
582 bool not_first = false;
588 fprintf(f, ", %u", (uint8_t) *p);
591 fprintf(f, "%u", (uint8_t) *p);
603 if (*p == '"' || *p == '\\') {
606 } else if (*p == '\n')
609 fprintf(f, "\\u%04x", *p);
621 static int output_json(
628 uint64_t realtime, monotonic;
629 _cleanup_free_ char *cursor = NULL;
636 bool done, separator;
640 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
642 r = sd_journal_get_realtime_usec(j, &realtime);
644 return log_error_errno(r, "Failed to get realtime timestamp: %m");
646 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
648 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
650 r = sd_journal_get_cursor(j, &cursor);
652 return log_error_errno(r, "Failed to get cursor: %m");
654 if (mode == OUTPUT_JSON_PRETTY)
657 "\t\"__CURSOR\" : \"%s\",\n"
658 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
659 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
660 "\t\"_BOOT_ID\" : \"%s\"",
664 sd_id128_to_string(boot_id, sid));
666 if (mode == OUTPUT_JSON_SSE)
670 "{ \"__CURSOR\" : \"%s\", "
671 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
672 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
673 "\"_BOOT_ID\" : \"%s\"",
677 sd_id128_to_string(boot_id, sid));
680 h = hashmap_new(&string_hash_ops);
684 /* First round, iterate through the entry and count how often each field appears */
685 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
691 memcmp(data, "_BOOT_ID=", 9) == 0)
694 eq = memchr(data, '=', length);
698 n = strndup(data, eq - (const char*) data);
704 u = PTR_TO_UINT(hashmap_get(h, n));
706 r = hashmap_put(h, n, UINT_TO_PTR(1));
712 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
726 SD_JOURNAL_FOREACH_DATA(j, data, length) {
732 /* We already printed the boot id, from the data in
733 * the header, hence let's suppress it here */
735 memcmp(data, "_BOOT_ID=", 9) == 0)
738 eq = memchr(data, '=', length);
743 if (mode == OUTPUT_JSON_PRETTY)
749 m = eq - (const char*) data;
751 n = strndup(data, m);
757 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
759 /* We already printed this, let's jump to the next */
765 /* Field only appears once, output it directly */
767 json_escape(f, data, m, flags);
770 json_escape(f, eq + 1, length - m - 1, flags);
772 hashmap_remove(h, n);
781 /* Field appears multiple times, output it as array */
782 json_escape(f, data, m, flags);
784 json_escape(f, eq + 1, length - m - 1, flags);
786 /* Iterate through the end of the list */
788 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
792 if (memcmp(data, n, m) != 0)
795 if (((const char*) data)[m] != '=')
799 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
804 hashmap_remove(h, n);
808 /* Iterate data fields form the beginning */
818 if (mode == OUTPUT_JSON_PRETTY)
820 else if (mode == OUTPUT_JSON_SSE)
828 while ((k = hashmap_steal_first_key(h)))
836 static int output_cat(
850 sd_journal_set_data_threshold(j, 0);
852 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
854 /* An entry without MESSAGE=? */
858 return log_error_errno(r, "Failed to get data: %m");
863 fwrite((const char*) data + 8, 1, l - 8, f);
869 static int (*output_funcs[_OUTPUT_MODE_MAX])(
874 OutputFlags flags) = {
876 [OUTPUT_SHORT] = output_short,
877 [OUTPUT_SHORT_ISO] = output_short,
878 [OUTPUT_SHORT_PRECISE] = output_short,
879 [OUTPUT_SHORT_MONOTONIC] = output_short,
880 [OUTPUT_VERBOSE] = output_verbose,
881 [OUTPUT_EXPORT] = output_export,
882 [OUTPUT_JSON] = output_json,
883 [OUTPUT_JSON_PRETTY] = output_json,
884 [OUTPUT_JSON_SSE] = output_json,
885 [OUTPUT_CAT] = output_cat
898 assert(mode < _OUTPUT_MODE_MAX);
901 n_columns = columns();
903 ret = output_funcs[mode](f, j, mode, n_columns, flags);
906 if (ellipsized && ret > 0)
912 static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
916 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
919 /* Print a beginning new line if that's request, but only once
920 * on the first line we print. */
923 *flags &= ~OUTPUT_BEGIN_NEWLINE;
927 static int show_journal(FILE *f,
938 bool need_seek = false;
939 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
943 assert(mode < _OUTPUT_MODE_MAX);
946 r = sd_journal_seek_tail(j);
950 r = sd_journal_previous_skip(j, how_many);
959 r = sd_journal_next(j);
969 if (not_before > 0) {
970 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
972 /* -ESTALE is returned if the
973 timestamp is not from this boot */
979 if (usec < not_before)
984 maybe_print_begin_newline(f, &flags);
986 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
991 if (warn_cutoff && line < how_many && not_before > 0) {
995 /* Check whether the cutoff line is too early */
997 r = sd_id128_get_boot(&boot_id);
1001 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1005 if (r > 0 && not_before < cutoff) {
1006 maybe_print_begin_newline(f, &flags);
1007 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1010 warn_cutoff = false;
1013 if (!(flags & OUTPUT_FOLLOW))
1016 r = sd_journal_wait(j, USEC_INFINITY);
1026 int add_matches_for_unit(sd_journal *j, const char *unit) {
1028 char *m1, *m2, *m3, *m4;
1033 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1034 m2 = strjoina("COREDUMP_UNIT=", unit);
1035 m3 = strjoina("UNIT=", unit);
1036 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1039 /* Look for messages from the service itself */
1040 (r = sd_journal_add_match(j, m1, 0)) ||
1042 /* Look for coredumps of the service */
1043 (r = sd_journal_add_disjunction(j)) ||
1044 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1045 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1046 (r = sd_journal_add_match(j, m2, 0)) ||
1048 /* Look for messages from PID 1 about this service */
1049 (r = sd_journal_add_disjunction(j)) ||
1050 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1051 (r = sd_journal_add_match(j, m3, 0)) ||
1053 /* Look for messages from authorized daemons about this service */
1054 (r = sd_journal_add_disjunction(j)) ||
1055 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1056 (r = sd_journal_add_match(j, m4, 0))
1059 if (r == 0 && endswith(unit, ".slice")) {
1060 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1062 /* Show all messages belonging to a slice */
1064 (r = sd_journal_add_disjunction(j)) ||
1065 (r = sd_journal_add_match(j, m5, 0))
1072 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1074 char *m1, *m2, *m3, *m4;
1075 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1080 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1081 m2 = strjoina("USER_UNIT=", unit);
1082 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1083 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
1084 sprintf(muid, "_UID="UID_FMT, uid);
1087 /* Look for messages from the user service itself */
1088 (r = sd_journal_add_match(j, m1, 0)) ||
1089 (r = sd_journal_add_match(j, muid, 0)) ||
1091 /* Look for messages from systemd about this service */
1092 (r = sd_journal_add_disjunction(j)) ||
1093 (r = sd_journal_add_match(j, m2, 0)) ||
1094 (r = sd_journal_add_match(j, muid, 0)) ||
1096 /* Look for coredumps of the service */
1097 (r = sd_journal_add_disjunction(j)) ||
1098 (r = sd_journal_add_match(j, m3, 0)) ||
1099 (r = sd_journal_add_match(j, muid, 0)) ||
1100 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1102 /* Look for messages from authorized daemons about this service */
1103 (r = sd_journal_add_disjunction(j)) ||
1104 (r = sd_journal_add_match(j, m4, 0)) ||
1105 (r = sd_journal_add_match(j, muid, 0)) ||
1106 (r = sd_journal_add_match(j, "_UID=0", 0))
1109 if (r == 0 && endswith(unit, ".slice")) {
1110 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1112 /* Show all messages belonging to a slice */
1114 (r = sd_journal_add_disjunction(j)) ||
1115 (r = sd_journal_add_match(j, m5, 0)) ||
1116 (r = sd_journal_add_match(j, muid, 0))
1123 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1124 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1125 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1135 if (!machine_name_is_valid(machine))
1138 r = container_get_leader(machine, &pid);
1142 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1146 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1156 pair[0] = safe_close(pair[0]);
1158 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1160 _exit(EXIT_FAILURE);
1162 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1164 _exit(EXIT_FAILURE);
1166 r = loop_read_exact(fd, buf, 36, false);
1169 _exit(EXIT_FAILURE);
1171 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1173 _exit(EXIT_FAILURE);
1175 _exit(EXIT_SUCCESS);
1178 pair[1] = safe_close(pair[1]);
1180 r = wait_for_terminate(child, &si);
1181 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1182 return r < 0 ? r : -EIO;
1184 k = recv(pair[0], buf, 36, 0);
1189 r = sd_id128_from_string(buf, boot_id);
1196 int add_match_this_boot(sd_journal *j, const char *machine) {
1197 char match[9+32+1] = "_BOOT_ID=";
1204 r = get_boot_id_for_machine(machine, &boot_id);
1206 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
1208 r = sd_id128_get_boot(&boot_id);
1210 return log_error_errno(r, "Failed to get boot id: %m");
1213 sd_id128_to_string(boot_id, match + 9);
1214 r = sd_journal_add_match(j, match, strlen(match));
1216 return log_error_errno(r, "Failed to add match: %m");
1218 r = sd_journal_add_conjunction(j);
1225 int show_journal_by_unit(
1234 int journal_open_flags,
1238 _cleanup_journal_close_ sd_journal*j = NULL;
1242 assert(mode < _OUTPUT_MODE_MAX);
1248 r = sd_journal_open(&j, journal_open_flags);
1252 r = add_match_this_boot(j, NULL);
1257 r = add_matches_for_unit(j, unit);
1259 r = add_matches_for_user_unit(j, unit, uid);
1263 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
1264 _cleanup_free_ char *filter;
1266 filter = journal_make_match_string(j);
1267 log_debug("Journal filter: %s", filter);
1270 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1273 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1274 [OUTPUT_SHORT] = "short",
1275 [OUTPUT_SHORT_ISO] = "short-iso",
1276 [OUTPUT_SHORT_PRECISE] = "short-precise",
1277 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1278 [OUTPUT_VERBOSE] = "verbose",
1279 [OUTPUT_EXPORT] = "export",
1280 [OUTPUT_JSON] = "json",
1281 [OUTPUT_JSON_PRETTY] = "json-pretty",
1282 [OUTPUT_JSON_SSE] = "json-sse",
1283 [OUTPUT_CAT] = "cat"
1286 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);