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"
35 #include "process-util.h"
37 /* up to three lines (each up to 100 characters),
38 or 300 characters, whichever is less */
39 #define PRINT_LINE_THRESHOLD 3
40 #define PRINT_CHAR_THRESHOLD 300
42 #define JSON_THRESHOLD 4096
44 static int print_catalog(FILE *f, sd_journal *j) {
46 _cleanup_free_ char *t = NULL, *z = NULL;
49 r = sd_journal_get_catalog(j, &t);
53 z = strreplace(strstrip(t), "\n", "\n-- ");
64 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
77 if (memcmp(data, field, fl))
85 memcpy(buf, (const char*) data + fl, nl);
95 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
98 if (flags & OUTPUT_SHOW_ALL)
101 if (l >= PRINT_CHAR_THRESHOLD)
104 if (!utf8_is_printable(p, l))
110 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
111 const char *color_on = "", *color_off = "";
112 const char *pos, *end;
113 bool ellipsized = false;
116 if (flags & OUTPUT_COLOR) {
117 if (priority <= LOG_ERR) {
118 color_on = ANSI_HIGHLIGHT_RED_ON;
119 color_off = ANSI_HIGHLIGHT_OFF;
120 } else if (priority <= LOG_NOTICE) {
121 color_on = ANSI_HIGHLIGHT_ON;
122 color_off = ANSI_HIGHLIGHT_OFF;
126 /* A special case: make sure that we print a newline when
127 the message is empty. */
128 if (message_len == 0)
132 pos < message + message_len;
133 pos = end + 1, line++) {
134 bool continuation = line > 0;
137 for (end = pos; end < message + message_len && *end != '\n'; end++)
142 /* We need to figure out when we are showing not-last line, *and*
143 * will skip subsequent lines. In that case, we will put the dots
144 * at the end of the line, instead of putting dots in the middle
148 line + 1 == PRINT_LINE_THRESHOLD ||
149 end + 1 >= message + PRINT_CHAR_THRESHOLD;
151 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
152 (prefix + len + 1 < n_columns && !tail_line)) {
153 fprintf(f, "%*s%s%.*s%s\n",
154 continuation * prefix, "",
155 color_on, len, pos, color_off);
159 /* Beyond this point, ellipsization will happen. */
162 if (prefix < n_columns && n_columns - prefix >= 3) {
163 if (n_columns - prefix > (unsigned) len + 3)
164 fprintf(f, "%*s%s%.*s...%s\n",
165 continuation * prefix, "",
166 color_on, len, pos, color_off);
168 _cleanup_free_ char *e;
170 e = ellipsize_mem(pos, len, n_columns - prefix,
171 tail_line ? 100 : 90);
173 fprintf(f, "%*s%s%.*s%s\n",
174 continuation * prefix, "",
175 color_on, len, pos, color_off);
177 fprintf(f, "%*s%s%s%s\n",
178 continuation * prefix, "",
179 color_on, e, color_off);
191 static int output_short(
202 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
203 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;
205 bool ellipsized = false;
210 /* Set the threshold to one bigger than the actual print
211 * threshold, so that if the line is actually longer than what
212 * we're willing to print, ellipsization will occur. This way
213 * we won't output a misleading line without any indication of
216 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
218 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
220 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
226 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
232 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
238 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
244 r = parse_field(data, length, "_PID=", &pid, &pid_len);
250 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
256 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
262 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
268 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
279 if (!(flags & OUTPUT_SHOW_ALL))
280 strip_tab_ansi(&message, &message_len);
282 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
285 if (mode == OUTPUT_SHORT_MONOTONIC) {
292 r = safe_atou64(monotonic, &t);
295 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
298 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
300 fprintf(f, "[%5llu.%06llu]",
301 (unsigned long long) (t / USEC_PER_SEC),
302 (unsigned long long) (t % USEC_PER_SEC));
304 n += 1 + 5 + 1 + 6 + 1;
311 struct tm *(*gettime_r)(const time_t *, struct tm *);
314 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
317 r = safe_atou64(realtime, &x);
320 r = sd_journal_get_realtime_usec(j, &x);
323 return log_error_errno(r, "Failed to get realtime timestamp: %m");
325 t = (time_t) (x / USEC_PER_SEC);
328 case OUTPUT_SHORT_ISO:
329 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
331 case OUTPUT_SHORT_PRECISE:
332 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
334 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
335 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
339 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
343 log_error("Failed to format time.");
351 if (hostname && shall_print(hostname, hostname_len, flags)) {
352 fprintf(f, " %.*s", (int) hostname_len, hostname);
353 n += hostname_len + 1;
356 if (identifier && shall_print(identifier, identifier_len, flags)) {
357 fprintf(f, " %.*s", (int) identifier_len, identifier);
358 n += identifier_len + 1;
359 } else if (comm && shall_print(comm, comm_len, flags)) {
360 fprintf(f, " %.*s", (int) comm_len, comm);
363 fputs(" unknown", f);
365 if (pid && shall_print(pid, pid_len, flags)) {
366 fprintf(f, "[%.*s]", (int) pid_len, pid);
368 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
369 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
370 n += fake_pid_len + 2;
373 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
374 char bytes[FORMAT_BYTES_MAX];
375 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
379 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
382 if (flags & OUTPUT_CATALOG)
388 static int output_verbose(
397 _cleanup_free_ char *cursor = NULL;
399 char ts[FORMAT_TIMESTAMP_MAX + 7];
405 sd_journal_set_data_threshold(j, 0);
407 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
409 log_debug("Source realtime timestamp not found");
411 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
412 "Failed to get source realtime timestamp: %s", strerror(-r));
415 _cleanup_free_ char *value = NULL;
418 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
420 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
422 r = safe_atou64(value, &realtime);
424 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
429 r = sd_journal_get_realtime_usec(j, &realtime);
431 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
432 "Failed to get realtime timestamp: %s", strerror(-r));
437 r = sd_journal_get_cursor(j, &cursor);
439 return log_error_errno(r, "Failed to get cursor: %m");
441 fprintf(f, "%s [%s]\n",
443 format_timestamp_us_utc(ts, sizeof(ts), realtime) :
444 format_timestamp_us(ts, sizeof(ts), realtime),
447 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
450 const char *on = "", *off = "";
452 c = memchr(data, '=', length);
454 log_error("Invalid field.");
457 fieldlen = c - (const char*) data;
459 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
460 on = ANSI_HIGHLIGHT_ON;
461 off = ANSI_HIGHLIGHT_OFF;
464 if (flags & OUTPUT_SHOW_ALL ||
465 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
466 && utf8_is_printable(data, length))) {
467 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
468 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
471 char bytes[FORMAT_BYTES_MAX];
473 fprintf(f, " %s%.*s=[%s blob data]%s\n",
475 (int) (c - (const char*) data),
477 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
485 if (flags & OUTPUT_CATALOG)
491 static int output_export(
501 usec_t realtime, monotonic;
502 _cleanup_free_ char *cursor = NULL;
508 sd_journal_set_data_threshold(j, 0);
510 r = sd_journal_get_realtime_usec(j, &realtime);
512 return log_error_errno(r, "Failed to get realtime timestamp: %m");
514 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
516 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
518 r = sd_journal_get_cursor(j, &cursor);
520 return log_error_errno(r, "Failed to get cursor: %m");
524 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
525 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
530 sd_id128_to_string(boot_id, sid));
532 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
534 /* We already printed the boot id, from the data in
535 * the header, hence let's suppress it here */
537 startswith(data, "_BOOT_ID="))
540 if (utf8_is_printable_newline(data, length, false))
541 fwrite(data, length, 1, f);
546 c = memchr(data, '=', length);
548 log_error("Invalid field.");
552 fwrite(data, c - (const char*) data, 1, f);
554 le64 = htole64(length - (c - (const char*) data) - 1);
555 fwrite(&le64, sizeof(le64), 1, f);
556 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
579 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')
611 fprintf(f, "\\u%04x", *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));
714 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
728 SD_JOURNAL_FOREACH_DATA(j, data, length) {
734 /* We already printed the boot id, from the data in
735 * the header, hence let's suppress it here */
737 memcmp(data, "_BOOT_ID=", 9) == 0)
740 eq = memchr(data, '=', length);
745 if (mode == OUTPUT_JSON_PRETTY)
751 m = eq - (const char*) data;
753 n = strndup(data, m);
759 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
761 /* We already printed this, let's jump to the next */
767 /* Field only appears once, output it directly */
769 json_escape(f, data, m, flags);
772 json_escape(f, eq + 1, length - m - 1, flags);
774 hashmap_remove(h, n);
783 /* Field appears multiple times, output it as array */
784 json_escape(f, data, m, flags);
786 json_escape(f, eq + 1, length - m - 1, flags);
788 /* Iterate through the end of the list */
790 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
794 if (memcmp(data, n, m) != 0)
797 if (((const char*) data)[m] != '=')
801 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
806 hashmap_remove(h, n);
810 /* Iterate data fields form the beginning */
820 if (mode == OUTPUT_JSON_PRETTY)
822 else if (mode == OUTPUT_JSON_SSE)
830 while ((k = hashmap_steal_first_key(h)))
838 static int output_cat(
852 sd_journal_set_data_threshold(j, 0);
854 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
856 /* An entry without MESSAGE=? */
860 return log_error_errno(r, "Failed to get data: %m");
865 fwrite((const char*) data + 8, 1, l - 8, f);
871 static int (*output_funcs[_OUTPUT_MODE_MAX])(
876 OutputFlags flags) = {
878 [OUTPUT_SHORT] = output_short,
879 [OUTPUT_SHORT_ISO] = output_short,
880 [OUTPUT_SHORT_PRECISE] = output_short,
881 [OUTPUT_SHORT_MONOTONIC] = output_short,
882 [OUTPUT_VERBOSE] = output_verbose,
883 [OUTPUT_EXPORT] = output_export,
884 [OUTPUT_JSON] = output_json,
885 [OUTPUT_JSON_PRETTY] = output_json,
886 [OUTPUT_JSON_SSE] = output_json,
887 [OUTPUT_CAT] = output_cat
900 assert(mode < _OUTPUT_MODE_MAX);
903 n_columns = columns();
905 ret = output_funcs[mode](f, j, mode, n_columns, flags);
908 if (ellipsized && ret > 0)
914 static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
918 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
921 /* Print a beginning new line if that's request, but only once
922 * on the first line we print. */
925 *flags &= ~OUTPUT_BEGIN_NEWLINE;
929 static int show_journal(FILE *f,
940 bool need_seek = false;
941 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
945 assert(mode < _OUTPUT_MODE_MAX);
948 r = sd_journal_seek_tail(j);
952 r = sd_journal_previous_skip(j, how_many);
961 r = sd_journal_next(j);
971 if (not_before > 0) {
972 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
974 /* -ESTALE is returned if the
975 timestamp is not from this boot */
981 if (usec < not_before)
986 maybe_print_begin_newline(f, &flags);
988 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
993 if (warn_cutoff && line < how_many && not_before > 0) {
997 /* Check whether the cutoff line is too early */
999 r = sd_id128_get_boot(&boot_id);
1003 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1007 if (r > 0 && not_before < cutoff) {
1008 maybe_print_begin_newline(f, &flags);
1009 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
1012 warn_cutoff = false;
1015 if (!(flags & OUTPUT_FOLLOW))
1018 r = sd_journal_wait(j, USEC_INFINITY);
1028 int add_matches_for_unit(sd_journal *j, const char *unit) {
1030 char *m1, *m2, *m3, *m4;
1035 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1036 m2 = strjoina("COREDUMP_UNIT=", unit);
1037 m3 = strjoina("UNIT=", unit);
1038 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1041 /* Look for messages from the service itself */
1042 (r = sd_journal_add_match(j, m1, 0)) ||
1044 /* Look for coredumps of the service */
1045 (r = sd_journal_add_disjunction(j)) ||
1046 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1047 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1048 (r = sd_journal_add_match(j, m2, 0)) ||
1050 /* Look for messages from PID 1 about this service */
1051 (r = sd_journal_add_disjunction(j)) ||
1052 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1053 (r = sd_journal_add_match(j, m3, 0)) ||
1055 /* Look for messages from authorized daemons about this service */
1056 (r = sd_journal_add_disjunction(j)) ||
1057 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1058 (r = sd_journal_add_match(j, m4, 0))
1061 if (r == 0 && endswith(unit, ".slice")) {
1062 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1064 /* Show all messages belonging to a slice */
1066 (r = sd_journal_add_disjunction(j)) ||
1067 (r = sd_journal_add_match(j, m5, 0))
1074 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1076 char *m1, *m2, *m3, *m4;
1077 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1082 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1083 m2 = strjoina("USER_UNIT=", unit);
1084 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1085 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
1086 sprintf(muid, "_UID="UID_FMT, uid);
1089 /* Look for messages from the user service itself */
1090 (r = sd_journal_add_match(j, m1, 0)) ||
1091 (r = sd_journal_add_match(j, muid, 0)) ||
1093 /* Look for messages from systemd about this service */
1094 (r = sd_journal_add_disjunction(j)) ||
1095 (r = sd_journal_add_match(j, m2, 0)) ||
1096 (r = sd_journal_add_match(j, muid, 0)) ||
1098 /* Look for coredumps of the service */
1099 (r = sd_journal_add_disjunction(j)) ||
1100 (r = sd_journal_add_match(j, m3, 0)) ||
1101 (r = sd_journal_add_match(j, muid, 0)) ||
1102 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1104 /* Look for messages from authorized daemons about this service */
1105 (r = sd_journal_add_disjunction(j)) ||
1106 (r = sd_journal_add_match(j, m4, 0)) ||
1107 (r = sd_journal_add_match(j, muid, 0)) ||
1108 (r = sd_journal_add_match(j, "_UID=0", 0))
1111 if (r == 0 && endswith(unit, ".slice")) {
1112 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1114 /* Show all messages belonging to a slice */
1116 (r = sd_journal_add_disjunction(j)) ||
1117 (r = sd_journal_add_match(j, m5, 0)) ||
1118 (r = sd_journal_add_match(j, muid, 0))
1125 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1126 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1127 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1137 if (!machine_name_is_valid(machine))
1140 r = container_get_leader(machine, &pid);
1144 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1148 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1158 pair[0] = safe_close(pair[0]);
1160 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1162 _exit(EXIT_FAILURE);
1164 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1166 _exit(EXIT_FAILURE);
1168 r = loop_read_exact(fd, buf, 36, false);
1171 _exit(EXIT_FAILURE);
1173 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1175 _exit(EXIT_FAILURE);
1177 _exit(EXIT_SUCCESS);
1180 pair[1] = safe_close(pair[1]);
1182 r = wait_for_terminate(child, &si);
1183 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1184 return r < 0 ? r : -EIO;
1186 k = recv(pair[0], buf, 36, 0);
1191 r = sd_id128_from_string(buf, boot_id);
1198 int add_match_this_boot(sd_journal *j, const char *machine) {
1199 char match[9+32+1] = "_BOOT_ID=";
1206 r = get_boot_id_for_machine(machine, &boot_id);
1208 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
1210 r = sd_id128_get_boot(&boot_id);
1212 return log_error_errno(r, "Failed to get boot id: %m");
1215 sd_id128_to_string(boot_id, match + 9);
1216 r = sd_journal_add_match(j, match, strlen(match));
1218 return log_error_errno(r, "Failed to add match: %m");
1220 r = sd_journal_add_conjunction(j);
1227 int show_journal_by_unit(
1236 int journal_open_flags,
1240 _cleanup_journal_close_ sd_journal*j = NULL;
1244 assert(mode < _OUTPUT_MODE_MAX);
1250 r = sd_journal_open(&j, journal_open_flags);
1254 r = add_match_this_boot(j, NULL);
1259 r = add_matches_for_unit(j, unit);
1261 r = add_matches_for_user_unit(j, unit, uid);
1265 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
1266 _cleanup_free_ char *filter;
1268 filter = journal_make_match_string(j);
1269 log_debug("Journal filter: %s", filter);
1272 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1275 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1276 [OUTPUT_SHORT] = "short",
1277 [OUTPUT_SHORT_ISO] = "short-iso",
1278 [OUTPUT_SHORT_PRECISE] = "short-precise",
1279 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1280 [OUTPUT_VERBOSE] = "verbose",
1281 [OUTPUT_EXPORT] = "export",
1282 [OUTPUT_JSON] = "json",
1283 [OUTPUT_JSON_PRETTY] = "json-pretty",
1284 [OUTPUT_JSON_SSE] = "json-sse",
1285 [OUTPUT_CAT] = "cat"
1288 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);