]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
Merge pull request #16112 from poettering/nss-systemd-block-fix
[thirdparty/systemd.git] / src / shared / logs-show.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <errno.h>
4 #include <fcntl.h>
5 #include <signal.h>
6 #include <stdint.h>
7 #include <stdlib.h>
8 #include <sys/socket.h>
9 #include <syslog.h>
10 #include <unistd.h>
11
12 #include "sd-id128.h"
13 #include "sd-journal.h"
14
15 #include "alloc-util.h"
16 #include "fd-util.h"
17 #include "format-util.h"
18 #include "hashmap.h"
19 #include "hostname-util.h"
20 #include "id128-util.h"
21 #include "io-util.h"
22 #include "journal-internal.h"
23 #include "journal-util.h"
24 #include "json.h"
25 #include "locale-util.h"
26 #include "log.h"
27 #include "logs-show.h"
28 #include "macro.h"
29 #include "namespace-util.h"
30 #include "output-mode.h"
31 #include "parse-util.h"
32 #include "pretty-print.h"
33 #include "process-util.h"
34 #include "sparse-endian.h"
35 #include "stdio-util.h"
36 #include "string-table.h"
37 #include "string-util.h"
38 #include "strv.h"
39 #include "terminal-util.h"
40 #include "time-util.h"
41 #include "utf8.h"
42 #include "util.h"
43 #include "web-util.h"
44
45 /* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
46 #define PRINT_LINE_THRESHOLD 3
47 #define PRINT_CHAR_THRESHOLD 300
48
49 #define JSON_THRESHOLD 4096U
50
51 static int print_catalog(FILE *f, sd_journal *j) {
52 _cleanup_free_ char *t = NULL, *z = NULL;
53 int r;
54
55 assert(j);
56
57 r = sd_journal_get_catalog(j, &t);
58 if (r == -ENOENT)
59 return 0;
60 if (r < 0)
61 return log_error_errno(r, "Failed to find catalog entry: %m");
62
63 z = strreplace(strstrip(t), "\n", "\n-- ");
64 if (!z)
65 return log_oom();
66
67 fputs("-- ", f);
68 fputs(z, f);
69 fputc('\n', f);
70
71 return 1;
72 }
73
74 static int url_from_catalog(sd_journal *j, char **ret) {
75 _cleanup_free_ char *t = NULL, *url = NULL;
76 const char *weblink;
77 int r;
78
79 assert(j);
80 assert(ret);
81
82 r = sd_journal_get_catalog(j, &t);
83 if (r == -ENOENT)
84 goto notfound;
85 if (r < 0)
86 return log_error_errno(r, "Failed to find catalog entry: %m");
87
88 weblink = startswith(t, "Documentation:");
89 if (!weblink) {
90 weblink = strstr(t + 1, "\nDocumentation:");
91 if (!weblink)
92 goto notfound;
93
94 weblink += 15;
95 }
96
97 /* Skip whitespace to value */
98 weblink += strspn(weblink, " \t");
99
100 /* Cut out till next whitespace/newline */
101 url = strndup(weblink, strcspn(weblink, WHITESPACE));
102 if (!url)
103 return log_oom();
104
105 if (!documentation_url_is_valid(url))
106 goto notfound;
107
108 *ret = TAKE_PTR(url);
109 return 1;
110
111 notfound:
112 *ret = NULL;
113 return 0;
114 }
115
116 static int parse_field(const void *data, size_t length, const char *field, size_t field_len, char **target, size_t *target_len) {
117 size_t nl;
118 char *buf;
119
120 assert(data);
121 assert(field);
122 assert(target);
123
124 if (length < field_len)
125 return 0;
126
127 if (memcmp(data, field, field_len))
128 return 0;
129
130 nl = length - field_len;
131
132 buf = newdup_suffix0(char, (const char*) data + field_len, nl);
133 if (!buf)
134 return log_oom();
135
136 free(*target);
137 *target = buf;
138
139 if (target_len)
140 *target_len = nl;
141
142 return 1;
143 }
144
145 typedef struct ParseFieldVec {
146 const char *field;
147 size_t field_len;
148 char **target;
149 size_t *target_len;
150 } ParseFieldVec;
151
152 #define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
153 { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
154
155 static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
156 unsigned i;
157
158 for (i = 0; i < n_fields; i++) {
159 const ParseFieldVec *f = &fields[i];
160 int r;
161
162 r = parse_field(data, length, f->field, f->field_len, f->target, f->target_len);
163 if (r < 0)
164 return r;
165 else if (r > 0)
166 break;
167 }
168
169 return 0;
170 }
171
172 static int field_set_test(const Set *fields, const char *name, size_t n) {
173 char *s;
174
175 if (!fields)
176 return 1;
177
178 s = strndupa(name, n);
179 return set_contains(fields, s);
180 }
181
182 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
183 assert(p);
184
185 if (flags & OUTPUT_SHOW_ALL)
186 return true;
187
188 if (l >= PRINT_CHAR_THRESHOLD)
189 return false;
190
191 if (!utf8_is_printable(p, l))
192 return false;
193
194 return true;
195 }
196
197 static bool print_multiline(
198 FILE *f,
199 unsigned prefix,
200 unsigned n_columns,
201 OutputFlags flags,
202 int priority,
203 bool audit,
204 const char* message,
205 size_t message_len,
206 size_t highlight[2]) {
207
208 const char *color_on = "", *color_off = "", *highlight_on = "";
209 const char *pos, *end;
210 bool ellipsized = false;
211 int line = 0;
212
213 if (flags & OUTPUT_COLOR) {
214 get_log_colors(priority, &color_on, &color_off, &highlight_on);
215
216 if (audit && strempty(color_on)) {
217 color_on = ANSI_BLUE;
218 color_off = ANSI_NORMAL;
219 }
220 }
221
222 /* A special case: make sure that we print a newline when
223 the message is empty. */
224 if (message_len == 0)
225 fputs("\n", f);
226
227 for (pos = message;
228 pos < message + message_len;
229 pos = end + 1, line++) {
230 bool continuation = line > 0;
231 bool tail_line;
232 int len;
233 for (end = pos; end < message + message_len && *end != '\n'; end++)
234 ;
235 len = end - pos;
236 assert(len >= 0);
237
238 /* We need to figure out when we are showing not-last line, *and*
239 * will skip subsequent lines. In that case, we will put the dots
240 * at the end of the line, instead of putting dots in the middle
241 * or not at all.
242 */
243 tail_line =
244 line + 1 == PRINT_LINE_THRESHOLD ||
245 end + 1 >= message + PRINT_CHAR_THRESHOLD;
246
247 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
248 (prefix + len + 1 < n_columns && !tail_line)) {
249 if (highlight &&
250 (size_t) (pos - message) <= highlight[0] &&
251 highlight[0] < (size_t) len) {
252
253 fprintf(f, "%*s%s%.*s",
254 continuation * prefix, "",
255 color_on, (int) highlight[0], pos);
256 fprintf(f, "%s%.*s",
257 highlight_on,
258 (int) (MIN((size_t) len, highlight[1]) - highlight[0]),
259 pos + highlight[0]);
260 if ((size_t) len > highlight[1])
261 fprintf(f, "%s%.*s",
262 color_on,
263 (int) (len - highlight[1]),
264 pos + highlight[1]);
265 fprintf(f, "%s\n", color_off);
266
267 } else
268 fprintf(f, "%*s%s%.*s%s\n",
269 continuation * prefix, "",
270 color_on, len, pos, color_off);
271 continue;
272 }
273
274 /* Beyond this point, ellipsization will happen. */
275 ellipsized = true;
276
277 if (prefix < n_columns && n_columns - prefix >= 3) {
278 if (n_columns - prefix > (unsigned) len + 3)
279 fprintf(f, "%*s%s%.*s...%s\n",
280 continuation * prefix, "",
281 color_on, len, pos, color_off);
282 else {
283 _cleanup_free_ char *e;
284
285 e = ellipsize_mem(pos, len, n_columns - prefix,
286 tail_line ? 100 : 90);
287 if (!e)
288 fprintf(f, "%*s%s%.*s%s\n",
289 continuation * prefix, "",
290 color_on, len, pos, color_off);
291 else
292 fprintf(f, "%*s%s%s%s\n",
293 continuation * prefix, "",
294 color_on, e, color_off);
295 }
296 } else
297 fputs("...\n", f);
298
299 if (tail_line)
300 break;
301 }
302
303 return ellipsized;
304 }
305
306 static int output_timestamp_monotonic(FILE *f, sd_journal *j, const char *monotonic) {
307 sd_id128_t boot_id;
308 uint64_t t;
309 int r;
310
311 assert(f);
312 assert(j);
313
314 r = -ENXIO;
315 if (monotonic)
316 r = safe_atou64(monotonic, &t);
317 if (r < 0)
318 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
319 if (r < 0)
320 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
321
322 fprintf(f, "[%5"PRI_USEC".%06"PRI_USEC"]", t / USEC_PER_SEC, t % USEC_PER_SEC);
323 return 1 + 5 + 1 + 6 + 1;
324 }
325
326 static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) {
327 char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)];
328 struct tm *(*gettime_r)(const time_t *, struct tm *);
329 struct tm tm;
330 uint64_t x;
331 time_t t;
332 int r;
333
334 assert(f);
335 assert(j);
336
337 if (realtime)
338 r = safe_atou64(realtime, &x);
339 if (!realtime || r < 0 || !VALID_REALTIME(x))
340 r = sd_journal_get_realtime_usec(j, &x);
341 if (r < 0)
342 return log_error_errno(r, "Failed to get realtime timestamp: %m");
343
344 if (IN_SET(mode, OUTPUT_SHORT_FULL, OUTPUT_WITH_UNIT)) {
345 const char *k;
346
347 if (flags & OUTPUT_UTC)
348 k = format_timestamp_utc(buf, sizeof(buf), x);
349 else
350 k = format_timestamp(buf, sizeof(buf), x);
351 if (!k)
352 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
353 "Failed to format timestamp: %" PRIu64, x);
354
355 } else {
356 char usec[7];
357
358 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
359 t = (time_t) (x / USEC_PER_SEC);
360
361 switch (mode) {
362
363 case OUTPUT_SHORT_UNIX:
364 xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, x % USEC_PER_SEC);
365 break;
366
367 case OUTPUT_SHORT_ISO:
368 if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)) <= 0)
369 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
370 "Failed to format ISO time");
371 break;
372
373 case OUTPUT_SHORT_ISO_PRECISE:
374 /* No usec in strftime, so we leave space and copy over */
375 if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t, &tm)) <= 0)
376 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
377 "Failed to format ISO-precise time");
378 xsprintf(usec, "%06"PRI_USEC, x % USEC_PER_SEC);
379 memcpy(buf + 20, usec, 6);
380 break;
381
382 case OUTPUT_SHORT:
383 case OUTPUT_SHORT_PRECISE:
384
385 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)) <= 0)
386 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
387 "Failed to format syslog time");
388
389 if (mode == OUTPUT_SHORT_PRECISE) {
390 size_t k;
391
392 assert(sizeof(buf) > strlen(buf));
393 k = sizeof(buf) - strlen(buf);
394
395 r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, x % USEC_PER_SEC);
396 if (r <= 0 || (size_t) r >= k) /* too long? */
397 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
398 "Failed to format precise time");
399 }
400 break;
401
402 default:
403 assert_not_reached("Unknown time format");
404 }
405 }
406
407 fputs(buf, f);
408 return (int) strlen(buf);
409 }
410
411 static int output_short(
412 FILE *f,
413 sd_journal *j,
414 OutputMode mode,
415 unsigned n_columns,
416 OutputFlags flags,
417 const Set *output_fields,
418 const size_t highlight[2]) {
419
420 int r;
421 const void *data;
422 size_t length, n = 0;
423 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL,
424 *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL, *transport = NULL,
425 *config_file = NULL, *unit = NULL, *user_unit = NULL, *documentation_url = NULL;
426 size_t hostname_len = 0, identifier_len = 0, comm_len = 0, pid_len = 0, fake_pid_len = 0, message_len = 0,
427 realtime_len = 0, monotonic_len = 0, priority_len = 0, transport_len = 0, config_file_len = 0,
428 unit_len = 0, user_unit_len = 0, documentation_url_len = 0;
429 int p = LOG_INFO;
430 bool ellipsized = false, audit;
431 const ParseFieldVec fields[] = {
432 PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len),
433 PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len),
434 PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len),
435 PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len),
436 PARSE_FIELD_VEC_ENTRY("_TRANSPORT=", &transport, &transport_len),
437 PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len),
438 PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len),
439 PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len),
440 PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
441 PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
442 PARSE_FIELD_VEC_ENTRY("CONFIG_FILE=", &config_file, &config_file_len),
443 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_UNIT=", &unit, &unit_len),
444 PARSE_FIELD_VEC_ENTRY("_SYSTEMD_USER_UNIT=", &user_unit, &user_unit_len),
445 PARSE_FIELD_VEC_ENTRY("DOCUMENTATION=", &documentation_url, &documentation_url_len),
446 };
447 size_t highlight_shifted[] = {highlight ? highlight[0] : 0, highlight ? highlight[1] : 0};
448
449 assert(f);
450 assert(j);
451
452 /* Set the threshold to one bigger than the actual print
453 * threshold, so that if the line is actually longer than what
454 * we're willing to print, ellipsization will occur. This way
455 * we won't output a misleading line without any indication of
456 * truncation.
457 */
458 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
459
460 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
461 r = parse_fieldv(data, length, fields, ELEMENTSOF(fields));
462 if (r < 0)
463 return r;
464 }
465 if (r == -EBADMSG) {
466 log_debug_errno(r, "Skipping message we can't read: %m");
467 return 0;
468 }
469 if (r < 0)
470 return log_error_errno(r, "Failed to get journal fields: %m");
471
472 if (!message) {
473 log_debug("Skipping message without MESSAGE= field.");
474 return 0;
475 }
476
477 if (!(flags & OUTPUT_SHOW_ALL))
478 strip_tab_ansi(&message, &message_len, highlight_shifted);
479
480 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
481 p = *priority - '0';
482
483 audit = streq_ptr(transport, "audit");
484
485 if (mode == OUTPUT_SHORT_MONOTONIC)
486 r = output_timestamp_monotonic(f, j, monotonic);
487 else
488 r = output_timestamp_realtime(f, j, mode, flags, realtime);
489 if (r < 0)
490 return r;
491 n += r;
492
493 if (flags & OUTPUT_NO_HOSTNAME) {
494 /* Suppress display of the hostname if this is requested. */
495 hostname = mfree(hostname);
496 hostname_len = 0;
497 }
498
499 if (hostname && shall_print(hostname, hostname_len, flags)) {
500 fprintf(f, " %.*s", (int) hostname_len, hostname);
501 n += hostname_len + 1;
502 }
503
504 if (mode == OUTPUT_WITH_UNIT && ((unit && shall_print(unit, unit_len, flags)) ||
505 (user_unit && shall_print(user_unit, user_unit_len, flags)))) {
506 if (unit) {
507 fprintf(f, " %.*s", (int) unit_len, unit);
508 n += unit_len + 1;
509 }
510 if (user_unit) {
511 if (unit)
512 fprintf(f, "/%.*s", (int) user_unit_len, user_unit);
513 else
514 fprintf(f, " %.*s", (int) user_unit_len, user_unit);
515 n += unit_len + 1;
516 }
517 } else if (identifier && shall_print(identifier, identifier_len, flags)) {
518 fprintf(f, " %.*s", (int) identifier_len, identifier);
519 n += identifier_len + 1;
520 } else if (comm && shall_print(comm, comm_len, flags)) {
521 fprintf(f, " %.*s", (int) comm_len, comm);
522 n += comm_len + 1;
523 } else
524 fputs(" unknown", f);
525
526 if (pid && shall_print(pid, pid_len, flags)) {
527 fprintf(f, "[%.*s]", (int) pid_len, pid);
528 n += pid_len + 2;
529 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
530 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
531 n += fake_pid_len + 2;
532 }
533
534 fputs(": ", f);
535
536 if (urlify_enabled()) {
537 _cleanup_free_ char *c = NULL;
538
539 /* Insert a hyperlink to a documentation URL before the message. Note that we don't make the
540 * whole message a hyperlink, since otherwise the whole screen might end up being just
541 * hyperlinks. Moreover, we want to be able to highlight parts of the message (such as the
542 * config file, see below) hence let's keep the documentation URL link separate. */
543
544 if (documentation_url && shall_print(documentation_url, documentation_url_len, flags)) {
545 c = strndup(documentation_url, documentation_url_len);
546 if (!c)
547 return log_oom();
548
549 if (!documentation_url_is_valid(c)) /* Eat up invalid links */
550 c = mfree(c);
551 }
552
553 if (!c)
554 (void) url_from_catalog(j, &c); /* Acquire from catalog if not embedded in log message itself */
555
556 if (c) {
557 _cleanup_free_ char *urlified = NULL;
558
559 if (terminal_urlify(c, special_glyph(SPECIAL_GLYPH_EXTERNAL_LINK), &urlified) >= 0) {
560 fputs(urlified, f);
561 fputc(' ', f);
562 }
563 }
564 }
565
566 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
567 char bytes[FORMAT_BYTES_MAX];
568 fprintf(f, "[%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
569 } else {
570
571 /* URLify config_file string in message, if the message starts with it.
572 * Skip URLification if the highlighted pattern overlaps. */
573 if (config_file &&
574 message_len >= config_file_len &&
575 memcmp(message, config_file, config_file_len) == 0 &&
576 IN_SET(message[config_file_len], ':', ' ', '\0') &&
577 (!highlight || highlight_shifted[0] == 0 || highlight_shifted[0] > config_file_len)) {
578
579 _cleanup_free_ char *t = NULL, *urlified = NULL;
580
581 t = strndup(config_file, config_file_len);
582 if (t && terminal_urlify_path(t, NULL, &urlified) >= 0) {
583 size_t shift = strlen(urlified) - config_file_len;
584 char *joined;
585
586 joined = strjoin(urlified, message + config_file_len);
587 if (joined) {
588 free_and_replace(message, joined);
589 message_len += shift;
590 if (highlight) {
591 highlight_shifted[0] += shift;
592 highlight_shifted[1] += shift;
593 }
594 }
595 }
596 }
597
598 ellipsized |=
599 print_multiline(f, n + 2, n_columns, flags, p, audit,
600 message, message_len,
601 highlight_shifted);
602 }
603
604 if (flags & OUTPUT_CATALOG)
605 (void) print_catalog(f, j);
606
607 return ellipsized;
608 }
609
610 static int output_verbose(
611 FILE *f,
612 sd_journal *j,
613 OutputMode mode,
614 unsigned n_columns,
615 OutputFlags flags,
616 const Set *output_fields,
617 const size_t highlight[2]) {
618
619 const void *data;
620 size_t length;
621 _cleanup_free_ char *cursor = NULL;
622 uint64_t realtime = 0;
623 char ts[FORMAT_TIMESTAMP_MAX + 7];
624 const char *timestamp;
625 int r;
626
627 assert(f);
628 assert(j);
629
630 sd_journal_set_data_threshold(j, 0);
631
632 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
633 if (r == -ENOENT)
634 log_debug("Source realtime timestamp not found");
635 else if (r < 0)
636 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
637 else {
638 _cleanup_free_ char *value = NULL;
639
640 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=",
641 STRLEN("_SOURCE_REALTIME_TIMESTAMP="), &value,
642 NULL);
643 if (r < 0)
644 return r;
645 assert(r > 0);
646
647 r = safe_atou64(value, &realtime);
648 if (r < 0)
649 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
650 }
651
652 if (r < 0) {
653 r = sd_journal_get_realtime_usec(j, &realtime);
654 if (r < 0)
655 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
656 }
657
658 r = sd_journal_get_cursor(j, &cursor);
659 if (r < 0)
660 return log_error_errno(r, "Failed to get cursor: %m");
661
662 timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
663 : format_timestamp_us(ts, sizeof ts, realtime);
664 fprintf(f, "%s [%s]\n",
665 timestamp ?: "(no timestamp)",
666 cursor);
667
668 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
669 const char *c, *p;
670 int fieldlen;
671 const char *on = "", *off = "";
672 _cleanup_free_ char *urlified = NULL;
673 size_t valuelen;
674
675 c = memchr(data, '=', length);
676 if (!c)
677 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
678 "Invalid field.");
679 fieldlen = c - (const char*) data;
680
681 r = field_set_test(output_fields, data, fieldlen);
682 if (r < 0)
683 return r;
684 if (r == 0)
685 continue;
686
687 valuelen = length - 1 - fieldlen;
688
689 if ((flags & OUTPUT_COLOR) && (p = startswith(data, "MESSAGE="))) {
690 on = ANSI_HIGHLIGHT;
691 off = ANSI_NORMAL;
692 } else if ((p = startswith(data, "CONFIG_FILE="))) {
693 if (terminal_urlify_path(p, NULL, &urlified) >= 0) {
694 p = urlified;
695 valuelen = strlen(urlified);
696 }
697 } else
698 p = c + 1;
699
700 if ((flags & OUTPUT_SHOW_ALL) ||
701 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
702 && utf8_is_printable(data, length))) {
703 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
704 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, false,
705 p, valuelen,
706 NULL);
707 fputs(off, f);
708 } else {
709 char bytes[FORMAT_BYTES_MAX];
710
711 fprintf(f, " %s%.*s=[%s blob data]%s\n",
712 on,
713 (int) (c - (const char*) data),
714 (const char*) data,
715 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
716 off);
717 }
718 }
719
720 if (r < 0)
721 return r;
722
723 if (flags & OUTPUT_CATALOG)
724 (void) print_catalog(f, j);
725
726 return 0;
727 }
728
729 static int output_export(
730 FILE *f,
731 sd_journal *j,
732 OutputMode mode,
733 unsigned n_columns,
734 OutputFlags flags,
735 const Set *output_fields,
736 const size_t highlight[2]) {
737
738 sd_id128_t boot_id;
739 char sid[SD_ID128_STRING_MAX];
740 int r;
741 usec_t realtime, monotonic;
742 _cleanup_free_ char *cursor = NULL;
743 const void *data;
744 size_t length;
745
746 assert(j);
747
748 sd_journal_set_data_threshold(j, 0);
749
750 r = sd_journal_get_realtime_usec(j, &realtime);
751 if (r < 0)
752 return log_error_errno(r, "Failed to get realtime timestamp: %m");
753
754 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
755 if (r < 0)
756 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
757
758 r = sd_journal_get_cursor(j, &cursor);
759 if (r < 0)
760 return log_error_errno(r, "Failed to get cursor: %m");
761
762 fprintf(f,
763 "__CURSOR=%s\n"
764 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
765 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
766 "_BOOT_ID=%s\n",
767 cursor,
768 realtime,
769 monotonic,
770 sd_id128_to_string(boot_id, sid));
771
772 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
773 const char *c;
774
775 /* We already printed the boot id from the data in the header, hence let's suppress it here */
776 if (memory_startswith(data, length, "_BOOT_ID="))
777 continue;
778
779 c = memchr(data, '=', length);
780 if (!c)
781 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
782 "Invalid field.");
783
784 r = field_set_test(output_fields, data, c - (const char *) data);
785 if (r < 0)
786 return r;
787 if (!r)
788 continue;
789
790 if (utf8_is_printable_newline(data, length, false))
791 fwrite(data, length, 1, f);
792 else {
793 uint64_t le64;
794
795 fwrite(data, c - (const char*) data, 1, f);
796 fputc('\n', f);
797 le64 = htole64(length - (c - (const char*) data) - 1);
798 fwrite(&le64, sizeof(le64), 1, f);
799 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
800 }
801
802 fputc('\n', f);
803 }
804 if (r == -EBADMSG) {
805 log_debug_errno(r, "Skipping message we can't read: %m");
806 return 0;
807 }
808
809 if (r < 0)
810 return r;
811
812 fputc('\n', f);
813
814 return 0;
815 }
816
817 void json_escape(
818 FILE *f,
819 const char* p,
820 size_t l,
821 OutputFlags flags) {
822
823 assert(f);
824 assert(p);
825
826 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
827 fputs("null", f);
828
829 else if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(p, l)) {
830 bool not_first = false;
831
832 fputs("[ ", f);
833
834 while (l > 0) {
835 if (not_first)
836 fprintf(f, ", %u", (uint8_t) *p);
837 else {
838 not_first = true;
839 fprintf(f, "%u", (uint8_t) *p);
840 }
841
842 p++;
843 l--;
844 }
845
846 fputs(" ]", f);
847 } else {
848 fputc('"', f);
849
850 while (l > 0) {
851 if (IN_SET(*p, '"', '\\')) {
852 fputc('\\', f);
853 fputc(*p, f);
854 } else if (*p == '\n')
855 fputs("\\n", f);
856 else if ((uint8_t) *p < ' ')
857 fprintf(f, "\\u%04x", (uint8_t) *p);
858 else
859 fputc(*p, f);
860
861 p++;
862 l--;
863 }
864
865 fputc('"', f);
866 }
867 }
868
869 struct json_data {
870 JsonVariant* name;
871 size_t n_values;
872 JsonVariant* values[];
873 };
874
875 static int update_json_data(
876 Hashmap *h,
877 OutputFlags flags,
878 const char *name,
879 const void *value,
880 size_t size) {
881
882 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
883 struct json_data *d;
884 int r;
885
886 if (!(flags & OUTPUT_SHOW_ALL) && strlen(name) + 1 + size >= JSON_THRESHOLD)
887 r = json_variant_new_null(&v);
888 else if (utf8_is_printable(value, size))
889 r = json_variant_new_stringn(&v, value, size);
890 else
891 r = json_variant_new_array_bytes(&v, value, size);
892 if (r < 0)
893 return log_error_errno(r, "Failed to allocate JSON data: %m");
894
895 d = hashmap_get(h, name);
896 if (d) {
897 struct json_data *w;
898
899 w = realloc(d, offsetof(struct json_data, values) + sizeof(JsonVariant*) * (d->n_values + 1));
900 if (!w)
901 return log_oom();
902
903 d = w;
904 assert_se(hashmap_update(h, json_variant_string(d->name), d) >= 0);
905 } else {
906 _cleanup_(json_variant_unrefp) JsonVariant *n = NULL;
907
908 r = json_variant_new_string(&n, name);
909 if (r < 0)
910 return log_error_errno(r, "Failed to allocate JSON name variant: %m");
911
912 d = malloc0(offsetof(struct json_data, values) + sizeof(JsonVariant*));
913 if (!d)
914 return log_oom();
915
916 r = hashmap_put(h, json_variant_string(n), d);
917 if (r < 0) {
918 free(d);
919 return log_error_errno(r, "Failed to insert JSON name into hashmap: %m");
920 }
921
922 d->name = TAKE_PTR(n);
923 }
924
925 d->values[d->n_values++] = TAKE_PTR(v);
926 return 0;
927 }
928
929 static int update_json_data_split(
930 Hashmap *h,
931 OutputFlags flags,
932 const Set *output_fields,
933 const void *data,
934 size_t size) {
935
936 const char *eq;
937 char *name;
938
939 assert(h);
940 assert(data || size == 0);
941
942 if (memory_startswith(data, size, "_BOOT_ID="))
943 return 0;
944
945 eq = memchr(data, '=', MIN(size, JSON_THRESHOLD));
946 if (!eq)
947 return 0;
948
949 if (eq == data)
950 return 0;
951
952 name = strndupa(data, eq - (const char*) data);
953 if (output_fields && !set_contains(output_fields, name))
954 return 0;
955
956 return update_json_data(h, flags, name, eq + 1, size - (eq - (const char*) data) - 1);
957 }
958
959 static int output_json(
960 FILE *f,
961 sd_journal *j,
962 OutputMode mode,
963 unsigned n_columns,
964 OutputFlags flags,
965 const Set *output_fields,
966 const size_t highlight[2]) {
967
968 char sid[SD_ID128_STRING_MAX], usecbuf[DECIMAL_STR_MAX(usec_t)];
969 _cleanup_(json_variant_unrefp) JsonVariant *object = NULL;
970 _cleanup_free_ char *cursor = NULL;
971 uint64_t realtime, monotonic;
972 JsonVariant **array = NULL;
973 struct json_data *d;
974 sd_id128_t boot_id;
975 Hashmap *h = NULL;
976 size_t n = 0;
977 Iterator i;
978 int r;
979
980 assert(j);
981
982 (void) sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
983
984 r = sd_journal_get_realtime_usec(j, &realtime);
985 if (r < 0)
986 return log_error_errno(r, "Failed to get realtime timestamp: %m");
987
988 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
989 if (r < 0)
990 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
991
992 r = sd_journal_get_cursor(j, &cursor);
993 if (r < 0)
994 return log_error_errno(r, "Failed to get cursor: %m");
995
996 h = hashmap_new(&string_hash_ops);
997 if (!h)
998 return log_oom();
999
1000 r = update_json_data(h, flags, "__CURSOR", cursor, strlen(cursor));
1001 if (r < 0)
1002 goto finish;
1003
1004 xsprintf(usecbuf, USEC_FMT, realtime);
1005 r = update_json_data(h, flags, "__REALTIME_TIMESTAMP", usecbuf, strlen(usecbuf));
1006 if (r < 0)
1007 goto finish;
1008
1009 xsprintf(usecbuf, USEC_FMT, monotonic);
1010 r = update_json_data(h, flags, "__MONOTONIC_TIMESTAMP", usecbuf, strlen(usecbuf));
1011 if (r < 0)
1012 goto finish;
1013
1014 sd_id128_to_string(boot_id, sid);
1015 r = update_json_data(h, flags, "_BOOT_ID", sid, strlen(sid));
1016 if (r < 0)
1017 goto finish;
1018
1019 for (;;) {
1020 const void *data;
1021 size_t size;
1022
1023 r = sd_journal_enumerate_data(j, &data, &size);
1024 if (r == -EBADMSG) {
1025 log_debug_errno(r, "Skipping message we can't read: %m");
1026 r = 0;
1027 goto finish;
1028 }
1029 if (r < 0) {
1030 log_error_errno(r, "Failed to read journal: %m");
1031 goto finish;
1032 }
1033 if (r == 0)
1034 break;
1035
1036 r = update_json_data_split(h, flags, output_fields, data, size);
1037 if (r < 0)
1038 goto finish;
1039 }
1040
1041 array = new(JsonVariant*, hashmap_size(h)*2);
1042 if (!array) {
1043 r = log_oom();
1044 goto finish;
1045 }
1046
1047 HASHMAP_FOREACH(d, h, i) {
1048 assert(d->n_values > 0);
1049
1050 array[n++] = json_variant_ref(d->name);
1051
1052 if (d->n_values == 1)
1053 array[n++] = json_variant_ref(d->values[0]);
1054 else {
1055 _cleanup_(json_variant_unrefp) JsonVariant *q = NULL;
1056
1057 r = json_variant_new_array(&q, d->values, d->n_values);
1058 if (r < 0) {
1059 log_error_errno(r, "Failed to create JSON array: %m");
1060 goto finish;
1061 }
1062
1063 array[n++] = TAKE_PTR(q);
1064 }
1065 }
1066
1067 r = json_variant_new_object(&object, array, n);
1068 if (r < 0) {
1069 log_error_errno(r, "Failed to allocate JSON object: %m");
1070 goto finish;
1071 }
1072
1073 json_variant_dump(object,
1074 output_mode_to_json_format_flags(mode) |
1075 (FLAGS_SET(flags, OUTPUT_COLOR) ? JSON_FORMAT_COLOR : 0),
1076 f, NULL);
1077
1078 r = 0;
1079
1080 finish:
1081 while ((d = hashmap_steal_first(h))) {
1082 size_t k;
1083
1084 json_variant_unref(d->name);
1085 for (k = 0; k < d->n_values; k++)
1086 json_variant_unref(d->values[k]);
1087
1088 free(d);
1089 }
1090
1091 hashmap_free(h);
1092
1093 json_variant_unref_many(array, n);
1094 free(array);
1095
1096 return r;
1097 }
1098
1099 static int output_cat_field(
1100 FILE *f,
1101 sd_journal *j,
1102 OutputFlags flags,
1103 const char *field,
1104 const size_t highlight[2]) {
1105
1106 const char *highlight_on, *highlight_off;
1107 const void *data;
1108 size_t l, fl;
1109 int r;
1110
1111 if (FLAGS_SET(flags, OUTPUT_COLOR)) {
1112 highlight_on = ANSI_HIGHLIGHT_RED;
1113 highlight_off = ANSI_NORMAL;
1114 } else
1115 highlight_on = highlight_off = "";
1116
1117 r = sd_journal_get_data(j, field, &data, &l);
1118 if (r == -EBADMSG) {
1119 log_debug_errno(r, "Skipping message we can't read: %m");
1120 return 0;
1121 }
1122 if (r == -ENOENT) /* An entry without the requested field */
1123 return 0;
1124 if (r < 0)
1125 return log_error_errno(r, "Failed to get data: %m");
1126
1127 fl = strlen(field);
1128 assert(l >= fl + 1);
1129 assert(((char*) data)[fl] == '=');
1130
1131 data = (const uint8_t*) data + fl + 1;
1132 l -= fl + 1;
1133
1134 if (highlight && FLAGS_SET(flags, OUTPUT_COLOR)) {
1135 assert(highlight[0] <= highlight[1]);
1136 assert(highlight[1] <= l);
1137
1138 fwrite((const char*) data, 1, highlight[0], f);
1139 fwrite(highlight_on, 1, strlen(highlight_on), f);
1140 fwrite((const char*) data + highlight[0], 1, highlight[1] - highlight[0], f);
1141 fwrite(highlight_off, 1, strlen(highlight_off), f);
1142 fwrite((const char*) data + highlight[1], 1, l - highlight[1], f);
1143 } else
1144 fwrite((const char*) data, 1, l, f);
1145
1146 fputc('\n', f);
1147 return 0;
1148 }
1149
1150 static int output_cat(
1151 FILE *f,
1152 sd_journal *j,
1153 OutputMode mode,
1154 unsigned n_columns,
1155 OutputFlags flags,
1156 const Set *output_fields,
1157 const size_t highlight[2]) {
1158
1159 const char *field;
1160 Iterator iterator;
1161 int r;
1162
1163 assert(j);
1164 assert(f);
1165
1166 (void) sd_journal_set_data_threshold(j, 0);
1167
1168 if (set_isempty(output_fields))
1169 return output_cat_field(f, j, flags, "MESSAGE", highlight);
1170
1171 SET_FOREACH(field, output_fields, iterator) {
1172 r = output_cat_field(f, j, flags, field, streq(field, "MESSAGE") ? highlight : NULL);
1173 if (r < 0)
1174 return r;
1175 }
1176
1177 return 0;
1178 }
1179
1180 static int (*output_funcs[_OUTPUT_MODE_MAX])(
1181 FILE *f,
1182 sd_journal *j,
1183 OutputMode mode,
1184 unsigned n_columns,
1185 OutputFlags flags,
1186 const Set *output_fields,
1187 const size_t highlight[2]) = {
1188
1189 [OUTPUT_SHORT] = output_short,
1190 [OUTPUT_SHORT_ISO] = output_short,
1191 [OUTPUT_SHORT_ISO_PRECISE] = output_short,
1192 [OUTPUT_SHORT_PRECISE] = output_short,
1193 [OUTPUT_SHORT_MONOTONIC] = output_short,
1194 [OUTPUT_SHORT_UNIX] = output_short,
1195 [OUTPUT_SHORT_FULL] = output_short,
1196 [OUTPUT_VERBOSE] = output_verbose,
1197 [OUTPUT_EXPORT] = output_export,
1198 [OUTPUT_JSON] = output_json,
1199 [OUTPUT_JSON_PRETTY] = output_json,
1200 [OUTPUT_JSON_SSE] = output_json,
1201 [OUTPUT_JSON_SEQ] = output_json,
1202 [OUTPUT_CAT] = output_cat,
1203 [OUTPUT_WITH_UNIT] = output_short,
1204 };
1205
1206 int show_journal_entry(
1207 FILE *f,
1208 sd_journal *j,
1209 OutputMode mode,
1210 unsigned n_columns,
1211 OutputFlags flags,
1212 char **output_fields,
1213 const size_t highlight[2],
1214 bool *ellipsized) {
1215
1216 _cleanup_set_free_ Set *fields = NULL;
1217 int r;
1218
1219 assert(mode >= 0);
1220 assert(mode < _OUTPUT_MODE_MAX);
1221
1222 if (n_columns <= 0)
1223 n_columns = columns();
1224
1225 r = set_put_strdupv(&fields, output_fields);
1226 if (r < 0)
1227 return r;
1228
1229 r = output_funcs[mode](f, j, mode, n_columns, flags, fields, highlight);
1230
1231 if (ellipsized && r > 0)
1232 *ellipsized = true;
1233
1234 return r;
1235 }
1236
1237 static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
1238 assert(f);
1239 assert(flags);
1240
1241 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
1242 return 0;
1243
1244 /* Print a beginning new line if that's request, but only once
1245 * on the first line we print. */
1246
1247 fputc('\n', f);
1248 *flags &= ~OUTPUT_BEGIN_NEWLINE;
1249 return 0;
1250 }
1251
1252 int show_journal(
1253 FILE *f,
1254 sd_journal *j,
1255 OutputMode mode,
1256 unsigned n_columns,
1257 usec_t not_before,
1258 unsigned how_many,
1259 OutputFlags flags,
1260 bool *ellipsized) {
1261
1262 int r;
1263 unsigned line = 0;
1264 bool need_seek = false;
1265 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
1266
1267 assert(j);
1268 assert(mode >= 0);
1269 assert(mode < _OUTPUT_MODE_MAX);
1270
1271 if (how_many == (unsigned) -1)
1272 need_seek = true;
1273 else {
1274 /* Seek to end */
1275 r = sd_journal_seek_tail(j);
1276 if (r < 0)
1277 return log_error_errno(r, "Failed to seek to tail: %m");
1278
1279 r = sd_journal_previous_skip(j, how_many);
1280 if (r < 0)
1281 return log_error_errno(r, "Failed to skip previous: %m");
1282 }
1283
1284 for (;;) {
1285 usec_t usec;
1286
1287 if (need_seek) {
1288 r = sd_journal_next(j);
1289 if (r < 0)
1290 return log_error_errno(r, "Failed to iterate through journal: %m");
1291 }
1292
1293 if (r == 0)
1294 break;
1295
1296 need_seek = true;
1297
1298 if (not_before > 0) {
1299 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
1300
1301 /* -ESTALE is returned if the timestamp is not from this boot */
1302 if (r == -ESTALE)
1303 continue;
1304 else if (r < 0)
1305 return log_error_errno(r, "Failed to get journal time: %m");
1306
1307 if (usec < not_before)
1308 continue;
1309 }
1310
1311 line++;
1312 maybe_print_begin_newline(f, &flags);
1313
1314 r = show_journal_entry(f, j, mode, n_columns, flags, NULL, NULL, ellipsized);
1315 if (r < 0)
1316 return r;
1317 }
1318
1319 if (warn_cutoff && line < how_many && not_before > 0) {
1320 sd_id128_t boot_id;
1321 usec_t cutoff = 0;
1322
1323 /* Check whether the cutoff line is too early */
1324
1325 r = sd_id128_get_boot(&boot_id);
1326 if (r < 0)
1327 return log_error_errno(r, "Failed to get boot id: %m");
1328
1329 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1330 if (r < 0)
1331 return log_error_errno(r, "Failed to get journal cutoff time: %m");
1332
1333 if (r > 0 && not_before < cutoff) {
1334 maybe_print_begin_newline(f, &flags);
1335
1336 /* If we logged *something* and no permission error happened, than we can reliably
1337 * emit the warning about rotation. If we didn't log anything and access errors
1338 * happened, emit hint about permissions. Otherwise, give a generic message, since we
1339 * can't diagnose the issue. */
1340
1341 bool noaccess = journal_access_blocked(j);
1342
1343 if (line == 0 && noaccess)
1344 fprintf(f, "Warning: some journal files were not opened due to insufficient permissions.");
1345 else if (!noaccess)
1346 fprintf(f, "Warning: journal has been rotated since unit was started, output may be incomplete.\n");
1347 else
1348 fprintf(f, "Warning: journal has been rotated since unit was started and some journal "
1349 "files were not opened due to insufficient permissions, output may be incomplete.\n");
1350 }
1351
1352 warn_cutoff = false;
1353 }
1354
1355 return 0;
1356 }
1357
1358 int add_matches_for_unit(sd_journal *j, const char *unit) {
1359 const char *m1, *m2, *m3, *m4;
1360 int r;
1361
1362 assert(j);
1363 assert(unit);
1364
1365 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1366 m2 = strjoina("COREDUMP_UNIT=", unit);
1367 m3 = strjoina("UNIT=", unit);
1368 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1369
1370 (void)(
1371 /* Look for messages from the service itself */
1372 (r = sd_journal_add_match(j, m1, 0)) ||
1373
1374 /* Look for coredumps of the service */
1375 (r = sd_journal_add_disjunction(j)) ||
1376 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1377 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1378 (r = sd_journal_add_match(j, m2, 0)) ||
1379
1380 /* Look for messages from PID 1 about this service */
1381 (r = sd_journal_add_disjunction(j)) ||
1382 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1383 (r = sd_journal_add_match(j, m3, 0)) ||
1384
1385 /* Look for messages from authorized daemons about this service */
1386 (r = sd_journal_add_disjunction(j)) ||
1387 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1388 (r = sd_journal_add_match(j, m4, 0))
1389 );
1390
1391 if (r == 0 && endswith(unit, ".slice")) {
1392 const char *m5;
1393
1394 m5 = strjoina("_SYSTEMD_SLICE=", unit);
1395
1396 /* Show all messages belonging to a slice */
1397 (void)(
1398 (r = sd_journal_add_disjunction(j)) ||
1399 (r = sd_journal_add_match(j, m5, 0))
1400 );
1401 }
1402
1403 return r;
1404 }
1405
1406 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1407 int r;
1408 char *m1, *m2, *m3, *m4;
1409 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1410
1411 assert(j);
1412 assert(unit);
1413
1414 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1415 m2 = strjoina("USER_UNIT=", unit);
1416 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1417 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
1418 sprintf(muid, "_UID="UID_FMT, uid);
1419
1420 (void) (
1421 /* Look for messages from the user service itself */
1422 (r = sd_journal_add_match(j, m1, 0)) ||
1423 (r = sd_journal_add_match(j, muid, 0)) ||
1424
1425 /* Look for messages from systemd about this service */
1426 (r = sd_journal_add_disjunction(j)) ||
1427 (r = sd_journal_add_match(j, m2, 0)) ||
1428 (r = sd_journal_add_match(j, muid, 0)) ||
1429
1430 /* Look for coredumps of the service */
1431 (r = sd_journal_add_disjunction(j)) ||
1432 (r = sd_journal_add_match(j, m3, 0)) ||
1433 (r = sd_journal_add_match(j, muid, 0)) ||
1434 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1435
1436 /* Look for messages from authorized daemons about this service */
1437 (r = sd_journal_add_disjunction(j)) ||
1438 (r = sd_journal_add_match(j, m4, 0)) ||
1439 (r = sd_journal_add_match(j, muid, 0)) ||
1440 (r = sd_journal_add_match(j, "_UID=0", 0))
1441 );
1442
1443 if (r == 0 && endswith(unit, ".slice")) {
1444 const char *m5;
1445
1446 m5 = strjoina("_SYSTEMD_SLICE=", unit);
1447
1448 /* Show all messages belonging to a slice */
1449 (void)(
1450 (r = sd_journal_add_disjunction(j)) ||
1451 (r = sd_journal_add_match(j, m5, 0)) ||
1452 (r = sd_journal_add_match(j, muid, 0))
1453 );
1454 }
1455
1456 return r;
1457 }
1458
1459 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1460 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1461 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1462 char buf[ID128_UUID_STRING_MAX];
1463 pid_t pid, child;
1464 ssize_t k;
1465 int r;
1466
1467 assert(machine);
1468 assert(boot_id);
1469
1470 if (!machine_name_is_valid(machine))
1471 return -EINVAL;
1472
1473 r = container_get_leader(machine, &pid);
1474 if (r < 0)
1475 return r;
1476
1477 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
1478 if (r < 0)
1479 return r;
1480
1481 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1482 return -errno;
1483
1484 r = namespace_fork("(sd-bootidns)", "(sd-bootid)", NULL, 0, FORK_RESET_SIGNALS|FORK_DEATHSIG,
1485 pidnsfd, mntnsfd, -1, -1, rootfd, &child);
1486 if (r < 0)
1487 return r;
1488 if (r == 0) {
1489 int fd;
1490
1491 pair[0] = safe_close(pair[0]);
1492
1493 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1494 if (fd < 0)
1495 _exit(EXIT_FAILURE);
1496
1497 r = loop_read_exact(fd, buf, 36, false);
1498 safe_close(fd);
1499 if (r < 0)
1500 _exit(EXIT_FAILURE);
1501
1502 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1503 if (k != 36)
1504 _exit(EXIT_FAILURE);
1505
1506 _exit(EXIT_SUCCESS);
1507 }
1508
1509 pair[1] = safe_close(pair[1]);
1510
1511 r = wait_for_terminate_and_check("(sd-bootidns)", child, 0);
1512 if (r < 0)
1513 return r;
1514 if (r != EXIT_SUCCESS)
1515 return -EIO;
1516
1517 k = recv(pair[0], buf, 36, 0);
1518 if (k != 36)
1519 return -EIO;
1520
1521 buf[36] = 0;
1522 r = sd_id128_from_string(buf, boot_id);
1523 if (r < 0)
1524 return r;
1525
1526 return 0;
1527 }
1528
1529 int add_match_this_boot(sd_journal *j, const char *machine) {
1530 char match[9+32+1] = "_BOOT_ID=";
1531 sd_id128_t boot_id;
1532 int r;
1533
1534 assert(j);
1535
1536 if (machine) {
1537 r = get_boot_id_for_machine(machine, &boot_id);
1538 if (r < 0)
1539 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
1540 } else {
1541 r = sd_id128_get_boot(&boot_id);
1542 if (r < 0)
1543 return log_error_errno(r, "Failed to get boot id: %m");
1544 }
1545
1546 sd_id128_to_string(boot_id, match + 9);
1547 r = sd_journal_add_match(j, match, strlen(match));
1548 if (r < 0)
1549 return log_error_errno(r, "Failed to add match: %m");
1550
1551 r = sd_journal_add_conjunction(j);
1552 if (r < 0)
1553 return log_error_errno(r, "Failed to add conjunction: %m");
1554
1555 return 0;
1556 }
1557
1558 int show_journal_by_unit(
1559 FILE *f,
1560 const char *unit,
1561 const char *log_namespace,
1562 OutputMode mode,
1563 unsigned n_columns,
1564 usec_t not_before,
1565 unsigned how_many,
1566 uid_t uid,
1567 OutputFlags flags,
1568 int journal_open_flags,
1569 bool system_unit,
1570 bool *ellipsized) {
1571
1572 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1573 int r;
1574
1575 assert(mode >= 0);
1576 assert(mode < _OUTPUT_MODE_MAX);
1577 assert(unit);
1578
1579 if (how_many <= 0)
1580 return 0;
1581
1582 r = sd_journal_open_namespace(&j, log_namespace, journal_open_flags | SD_JOURNAL_INCLUDE_DEFAULT_NAMESPACE);
1583 if (r < 0)
1584 return log_error_errno(r, "Failed to open journal: %m");
1585
1586 r = add_match_this_boot(j, NULL);
1587 if (r < 0)
1588 return r;
1589
1590 if (system_unit)
1591 r = add_matches_for_unit(j, unit);
1592 else
1593 r = add_matches_for_user_unit(j, unit, uid);
1594 if (r < 0)
1595 return log_error_errno(r, "Failed to add unit matches: %m");
1596
1597 if (DEBUG_LOGGING) {
1598 _cleanup_free_ char *filter;
1599
1600 filter = journal_make_match_string(j);
1601 if (!filter)
1602 return log_oom();
1603
1604 log_debug("Journal filter: %s", filter);
1605 }
1606
1607 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1608 }