]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / logs-show.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
86aa7ba4
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2012 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
5430f7f2
LP
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
86aa7ba4
LP
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
5430f7f2 15 Lesser General Public License for more details.
86aa7ba4 16
5430f7f2 17 You should have received a copy of the GNU Lesser General Public License
86aa7ba4
LP
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
86aa7ba4 21#include <errno.h>
b6741478 22#include <fcntl.h>
a8fbdf54
TA
23#include <signal.h>
24#include <stdint.h>
25#include <stdlib.h>
07630cea
LP
26#include <string.h>
27#include <sys/socket.h>
a8fbdf54 28#include <syslog.h>
07630cea 29#include <time.h>
a8fbdf54
TA
30#include <unistd.h>
31
32#include "sd-id128.h"
33#include "sd-journal.h"
86aa7ba4 34
b5efdb8a 35#include "alloc-util.h"
3ffd4af2 36#include "fd-util.h"
f97b34a6 37#include "format-util.h"
d99ae53a 38#include "hashmap.h"
07630cea 39#include "hostname-util.h"
c004493c 40#include "io-util.h"
dfb33a97 41#include "journal-internal.h"
07630cea 42#include "log.h"
3ffd4af2 43#include "logs-show.h"
a8fbdf54
TA
44#include "macro.h"
45#include "output-mode.h"
6bedfcbb 46#include "parse-util.h"
0b452006 47#include "process-util.h"
a8fbdf54 48#include "sparse-endian.h"
29a753df 49#include "stdio-util.h"
8b43440b 50#include "string-table.h"
07630cea 51#include "string-util.h"
cc25a67e 52#include "strv.h"
288a74cc 53#include "terminal-util.h"
a8fbdf54 54#include "time-util.h"
07630cea
LP
55#include "utf8.h"
56#include "util.h"
86aa7ba4 57
07630cea 58/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
a6f0104a
ZJS
59#define PRINT_LINE_THRESHOLD 3
60#define PRINT_CHAR_THRESHOLD 300
61
08ace05b 62#define JSON_THRESHOLD 4096
86aa7ba4 63
d4205751
LP
64static int print_catalog(FILE *f, sd_journal *j) {
65 int r;
66 _cleanup_free_ char *t = NULL, *z = NULL;
67
68
69 r = sd_journal_get_catalog(j, &t);
70 if (r < 0)
71 return r;
72
73 z = strreplace(strstrip(t), "\n", "\n-- ");
74 if (!z)
75 return log_oom();
76
77 fputs("-- ", f);
78 fputs(z, f);
79 fputc('\n', f);
80
81 return 0;
82}
83
ed054520
VC
84static int parse_field(const void *data, size_t length, const char *field, size_t field_len, char **target, size_t *target_len) {
85 size_t nl;
d813d7a3 86 char *buf;
55d7bfc1
LP
87
88 assert(data);
89 assert(field);
90 assert(target);
55d7bfc1 91
ed054520 92 if (length < field_len)
55d7bfc1
LP
93 return 0;
94
ed054520 95 if (memcmp(data, field, field_len))
55d7bfc1
LP
96 return 0;
97
ed054520 98 nl = length - field_len;
c165d97d
LP
99
100
ed054520 101 buf = newdup_suffix0(char, (const char*) data + field_len, nl);
0d0f0c50
SL
102 if (!buf)
103 return log_oom();
55d7bfc1 104
6c1e6b98 105 free(*target);
55d7bfc1 106 *target = buf;
d813d7a3 107
ed054520
VC
108 if (target_len)
109 *target_len = nl;
55d7bfc1
LP
110
111 return 1;
112}
113
ed054520
VC
114typedef struct ParseFieldVec {
115 const char *field;
116 size_t field_len;
117 char **target;
118 size_t *target_len;
119} ParseFieldVec;
120
121#define PARSE_FIELD_VEC_ENTRY(_field, _target, _target_len) \
122 { .field = _field, .field_len = strlen(_field), .target = _target, .target_len = _target_len }
123
124static int parse_fieldv(const void *data, size_t length, const ParseFieldVec *fields, unsigned n_fields) {
125 unsigned i;
126
127 for (i = 0; i < n_fields; i++) {
128 const ParseFieldVec *f = &fields[i];
129 int r;
130
131 r = parse_field(data, length, f->field, f->field_len, f->target, f->target_len);
132 if (r < 0)
133 return r;
134 else if (r > 0)
135 break;
136 }
137
138 return 0;
139}
140
cc25a67e
LK
141static int field_set_test(Set *fields, const char *name, size_t n) {
142 char *s = NULL;
143
144 if (!fields)
145 return 1;
146
147 s = strndupa(name, n);
148 if (!s)
149 return log_oom();
150
151 return set_get(fields, s) ? 1 : 0;
152}
153
08ace05b
LP
154static bool shall_print(const char *p, size_t l, OutputFlags flags) {
155 assert(p);
156
157 if (flags & OUTPUT_SHOW_ALL)
55d7bfc1
LP
158 return true;
159
a6f0104a 160 if (l >= PRINT_CHAR_THRESHOLD)
55d7bfc1
LP
161 return false;
162
31f7bf19 163 if (!utf8_is_printable(p, l))
55d7bfc1
LP
164 return false;
165
166 return true;
167}
168
00f117a5 169static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
31f7bf19
ZJS
170 const char *color_on = "", *color_off = "";
171 const char *pos, *end;
94e0bd7d 172 bool ellipsized = false;
a6f0104a 173 int line = 0;
31f7bf19
ZJS
174
175 if (flags & OUTPUT_COLOR) {
176 if (priority <= LOG_ERR) {
1fc464f6
LP
177 color_on = ANSI_HIGHLIGHT_RED;
178 color_off = ANSI_NORMAL;
31f7bf19 179 } else if (priority <= LOG_NOTICE) {
1fc464f6
LP
180 color_on = ANSI_HIGHLIGHT;
181 color_off = ANSI_NORMAL;
31f7bf19
ZJS
182 }
183 }
184
47d80904
UU
185 /* A special case: make sure that we print a newline when
186 the message is empty. */
187 if (message_len == 0)
188 fputs("\n", f);
189
a6f0104a
ZJS
190 for (pos = message;
191 pos < message + message_len;
192 pos = end + 1, line++) {
193 bool continuation = line > 0;
194 bool tail_line;
31f7bf19
ZJS
195 int len;
196 for (end = pos; end < message + message_len && *end != '\n'; end++)
197 ;
198 len = end - pos;
199 assert(len >= 0);
200
2526d626 201 /* We need to figure out when we are showing not-last line, *and*
a6f0104a
ZJS
202 * will skip subsequent lines. In that case, we will put the dots
203 * at the end of the line, instead of putting dots in the middle
204 * or not at all.
205 */
206 tail_line =
207 line + 1 == PRINT_LINE_THRESHOLD ||
2526d626 208 end + 1 >= message + PRINT_CHAR_THRESHOLD;
a6f0104a
ZJS
209
210 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
211 (prefix + len + 1 < n_columns && !tail_line)) {
31f7bf19
ZJS
212 fprintf(f, "%*s%s%.*s%s\n",
213 continuation * prefix, "",
214 color_on, len, pos, color_off);
a6f0104a
ZJS
215 continue;
216 }
31f7bf19 217
a6f0104a
ZJS
218 /* Beyond this point, ellipsization will happen. */
219 ellipsized = true;
31f7bf19 220
a6f0104a
ZJS
221 if (prefix < n_columns && n_columns - prefix >= 3) {
222 if (n_columns - prefix > (unsigned) len + 3)
223 fprintf(f, "%*s%s%.*s...%s\n",
b4b02cbe
ZJS
224 continuation * prefix, "",
225 color_on, len, pos, color_off);
a6f0104a
ZJS
226 else {
227 _cleanup_free_ char *e;
228
229 e = ellipsize_mem(pos, len, n_columns - prefix,
230 tail_line ? 100 : 90);
231 if (!e)
232 fprintf(f, "%*s%s%.*s%s\n",
233 continuation * prefix, "",
234 color_on, len, pos, color_off);
235 else
236 fprintf(f, "%*s%s%s%s\n",
237 continuation * prefix, "",
238 color_on, e, color_off);
239 }
240 } else
31f7bf19
ZJS
241 fputs("...\n", f);
242
a6f0104a
ZJS
243 if (tail_line)
244 break;
31f7bf19 245 }
94e0bd7d
ZJS
246
247 return ellipsized;
31f7bf19
ZJS
248}
249
29a753df
LP
250static int output_timestamp_monotonic(FILE *f, sd_journal *j, const char *monotonic) {
251 sd_id128_t boot_id;
252 uint64_t t;
253 int r;
254
255 assert(f);
256 assert(j);
257
258 r = -ENXIO;
259 if (monotonic)
260 r = safe_atou64(monotonic, &t);
261 if (r < 0)
262 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
263 if (r < 0)
264 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
265
70887c5f 266 fprintf(f, "[%5"PRI_USEC".%06"PRI_USEC"]", t / USEC_PER_SEC, t % USEC_PER_SEC);
29a753df
LP
267 return 1 + 5 + 1 + 6 + 1;
268}
269
270static int output_timestamp_realtime(FILE *f, sd_journal *j, OutputMode mode, OutputFlags flags, const char *realtime) {
271 char buf[MAX(FORMAT_TIMESTAMP_MAX, 64)];
272 struct tm *(*gettime_r)(const time_t *, struct tm *);
273 struct tm tm;
274 uint64_t x;
275 time_t t;
276 int r;
277
278 assert(f);
279 assert(j);
280
281 r = -ENXIO;
282 if (realtime)
283 r = safe_atou64(realtime, &x);
284 if (r < 0)
285 r = sd_journal_get_realtime_usec(j, &x);
286 if (r < 0)
287 return log_error_errno(r, "Failed to get realtime timestamp: %m");
288
1bb4b028
LP
289 if (x > USEC_TIMESTAMP_FORMATTABLE_MAX) {
290 log_error("Timestamp cannot be printed");
291 return -EINVAL;
292 }
293
29a753df
LP
294 if (mode == OUTPUT_SHORT_FULL) {
295 const char *k;
296
297 if (flags & OUTPUT_UTC)
298 k = format_timestamp_utc(buf, sizeof(buf), x);
299 else
300 k = format_timestamp(buf, sizeof(buf), x);
301 if (!k) {
302 log_error("Failed to format timestamp.");
303 return -EINVAL;
304 }
305
306 } else {
7e563bfc
IW
307 char usec[7];
308
29a753df
LP
309 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
310 t = (time_t) (x / USEC_PER_SEC);
311
312 switch (mode) {
313
314 case OUTPUT_SHORT_UNIX:
70887c5f 315 xsprintf(buf, "%10"PRI_TIME".%06"PRIu64, t, x % USEC_PER_SEC);
29a753df
LP
316 break;
317
318 case OUTPUT_SHORT_ISO:
319 if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm)) <= 0) {
7e563bfc
IW
320 log_error("Failed to format ISO time");
321 return -EINVAL;
322 }
323 break;
324
325 case OUTPUT_SHORT_ISO_PRECISE:
326 /* No usec in strftime, so we leave space and copy over */
327 if (strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S.xxxxxx%z", gettime_r(&t, &tm)) <= 0) {
328 log_error("Failed to format ISO-precise time");
29a753df
LP
329 return -EINVAL;
330 }
7e563bfc
IW
331 xsprintf(usec, "%06"PRI_USEC, x % USEC_PER_SEC);
332 memcpy(buf + 20, usec, 6);
29a753df
LP
333 break;
334
335 case OUTPUT_SHORT:
336 case OUTPUT_SHORT_PRECISE:
337
338 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm)) <= 0) {
339 log_error("Failed to format syslog time");
340 return -EINVAL;
341 }
342
343 if (mode == OUTPUT_SHORT_PRECISE) {
344 size_t k;
345
346 assert(sizeof(buf) > strlen(buf));
347 k = sizeof(buf) - strlen(buf);
348
70887c5f 349 r = snprintf(buf + strlen(buf), k, ".%06"PRIu64, x % USEC_PER_SEC);
29a753df
LP
350 if (r <= 0 || (size_t) r >= k) { /* too long? */
351 log_error("Failed to format precise time");
352 return -EINVAL;
353 }
354 }
355 break;
356
357 default:
358 assert_not_reached("Unknown time format");
359 }
360 }
361
362 fputs(buf, f);
363 return (int) strlen(buf);
364}
365
08ace05b
LP
366static int output_short(
367 FILE *f,
368 sd_journal *j,
369 OutputMode mode,
370 unsigned n_columns,
cc25a67e
LK
371 OutputFlags flags,
372 Set *output_fields) {
08ace05b 373
86aa7ba4 374 int r;
86aa7ba4
LP
375 const void *data;
376 size_t length;
377 size_t n = 0;
08ace05b 378 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
49826187
LP
379 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;
380 int p = LOG_INFO;
94e0bd7d 381 bool ellipsized = false;
ed054520
VC
382 const ParseFieldVec fields[] = {
383 PARSE_FIELD_VEC_ENTRY("_PID=", &pid, &pid_len),
384 PARSE_FIELD_VEC_ENTRY("_COMM=", &comm, &comm_len),
385 PARSE_FIELD_VEC_ENTRY("MESSAGE=", &message, &message_len),
386 PARSE_FIELD_VEC_ENTRY("PRIORITY=", &priority, &priority_len),
387 PARSE_FIELD_VEC_ENTRY("_HOSTNAME=", &hostname, &hostname_len),
388 PARSE_FIELD_VEC_ENTRY("SYSLOG_PID=", &fake_pid, &fake_pid_len),
389 PARSE_FIELD_VEC_ENTRY("SYSLOG_IDENTIFIER=", &identifier, &identifier_len),
390 PARSE_FIELD_VEC_ENTRY("_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len),
391 PARSE_FIELD_VEC_ENTRY("_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len),
392 };
86aa7ba4 393
08ace05b 394 assert(f);
86aa7ba4
LP
395 assert(j);
396
a6f0104a 397 /* Set the threshold to one bigger than the actual print
69ab8088 398 * threshold, so that if the line is actually longer than what
a6f0104a
ZJS
399 * we're willing to print, ellipsization will occur. This way
400 * we won't output a misleading line without any indication of
401 * truncation.
402 */
403 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
93b73b06 404
a72b6353 405 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
55d7bfc1 406
ed054520 407 r = parse_fieldv(data, length, fields, ELEMENTSOF(fields));
55d7bfc1 408 if (r < 0)
08ace05b 409 return r;
55d7bfc1 410 }
d00f1d57
LP
411 if (r == -EBADMSG) {
412 log_debug_errno(r, "Skipping message we can't read: %m");
413 return 0;
414 }
a72b6353 415 if (r < 0)
b56d608e 416 return log_error_errno(r, "Failed to get journal fields: %m");
a72b6353 417
07d21025
LP
418 if (!message) {
419 log_debug("Skipping message without MESSAGE= field.");
08ace05b 420 return 0;
07d21025 421 }
55d7bfc1 422
e8bc0ea2
LP
423 if (!(flags & OUTPUT_SHOW_ALL))
424 strip_tab_ansi(&message, &message_len);
425
49826187
LP
426 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
427 p = *priority - '0';
428
29a753df
LP
429 if (mode == OUTPUT_SHORT_MONOTONIC)
430 r = output_timestamp_monotonic(f, j, monotonic);
431 else
432 r = output_timestamp_realtime(f, j, mode, flags, realtime);
433 if (r < 0)
434 return r;
435 n += r;
86aa7ba4 436
29a753df 437 if (flags & OUTPUT_NO_HOSTNAME) {
991e274b 438 /* Suppress display of the hostname if this is requested. */
12104159 439 hostname = mfree(hostname);
991e274b
LP
440 hostname_len = 0;
441 }
442
08ace05b
LP
443 if (hostname && shall_print(hostname, hostname_len, flags)) {
444 fprintf(f, " %.*s", (int) hostname_len, hostname);
55d7bfc1
LP
445 n += hostname_len + 1;
446 }
447
08ace05b
LP
448 if (identifier && shall_print(identifier, identifier_len, flags)) {
449 fprintf(f, " %.*s", (int) identifier_len, identifier);
4cd9a9d9 450 n += identifier_len + 1;
08ace05b
LP
451 } else if (comm && shall_print(comm, comm_len, flags)) {
452 fprintf(f, " %.*s", (int) comm_len, comm);
55d7bfc1 453 n += comm_len + 1;
b5936820 454 } else
1248e840 455 fputs(" unknown", f);
86aa7ba4 456
08ace05b
LP
457 if (pid && shall_print(pid, pid_len, flags)) {
458 fprintf(f, "[%.*s]", (int) pid_len, pid);
55d7bfc1 459 n += pid_len + 2;
08ace05b
LP
460 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
461 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
6c1e6b98 462 n += fake_pid_len + 2;
86aa7ba4
LP
463 }
464
31f7bf19 465 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
e6acda19 466 char bytes[FORMAT_BYTES_MAX];
08ace05b 467 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
31f7bf19
ZJS
468 } else {
469 fputs(": ", f);
94e0bd7d
ZJS
470 ellipsized |=
471 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
31f7bf19 472 }
55d7bfc1 473
d4205751
LP
474 if (flags & OUTPUT_CATALOG)
475 print_catalog(f, j);
476
94e0bd7d 477 return ellipsized;
86aa7ba4
LP
478}
479
08ace05b
LP
480static int output_verbose(
481 FILE *f,
482 sd_journal *j,
483 OutputMode mode,
484 unsigned n_columns,
cc25a67e
LK
485 OutputFlags flags,
486 Set *output_fields) {
08ace05b 487
86aa7ba4
LP
488 const void *data;
489 size_t length;
7fd1b19b 490 _cleanup_free_ char *cursor = NULL;
d813d7a3 491 uint64_t realtime = 0;
f02d8367 492 char ts[FORMAT_TIMESTAMP_MAX + 7];
8924973a 493 const char *timestamp;
86aa7ba4
LP
494 int r;
495
08ace05b 496 assert(f);
86aa7ba4
LP
497 assert(j);
498
93b73b06
LP
499 sd_journal_set_data_threshold(j, 0);
500
cf40f0be
ZJS
501 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
502 if (r == -ENOENT)
503 log_debug("Source realtime timestamp not found");
b56d608e
LP
504 else if (r < 0)
505 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
506 else {
cf40f0be 507 _cleanup_free_ char *value = NULL;
cf40f0be 508
ed054520 509 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", strlen("_SOURCE_REALTIME_TIMESTAMP="), &value, NULL);
cf40f0be 510 if (r < 0)
e64c53fd 511 return r;
d813d7a3
LP
512 assert(r > 0);
513
514 r = safe_atou64(value, &realtime);
515 if (r < 0)
516 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
cf40f0be
ZJS
517 }
518
519 if (r < 0) {
520 r = sd_journal_get_realtime_usec(j, &realtime);
b56d608e
LP
521 if (r < 0)
522 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
523 }
524
525 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
526 if (r < 0)
527 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 528
8924973a
ZJS
529 timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
530 : format_timestamp_us(ts, sizeof ts, realtime);
08ace05b 531 fprintf(f, "%s [%s]\n",
8924973a 532 timestamp ?: "(no timestamp)",
08ace05b 533 cursor);
86aa7ba4 534
a72b6353 535 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
31f7bf19
ZJS
536 const char *c;
537 int fieldlen;
7ac4fa7e
ZJS
538 const char *on = "", *off = "";
539
31f7bf19
ZJS
540 c = memchr(data, '=', length);
541 if (!c) {
542 log_error("Invalid field.");
543 return -EINVAL;
544 }
545 fieldlen = c - (const char*) data;
86aa7ba4 546
cc25a67e
LK
547 r = field_set_test(output_fields, data, fieldlen);
548 if (r < 0)
549 return r;
550 if (!r)
551 continue;
552
7ac4fa7e 553 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
1fc464f6
LP
554 on = ANSI_HIGHLIGHT;
555 off = ANSI_NORMAL;
7ac4fa7e
ZJS
556 }
557
8980058a 558 if ((flags & OUTPUT_SHOW_ALL) ||
a6f0104a
ZJS
559 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
560 && utf8_is_printable(data, length))) {
7ac4fa7e 561 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
31f7bf19 562 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
7ac4fa7e 563 fputs(off, f);
31f7bf19
ZJS
564 } else {
565 char bytes[FORMAT_BYTES_MAX];
86aa7ba4 566
7ac4fa7e
ZJS
567 fprintf(f, " %s%.*s=[%s blob data]%s\n",
568 on,
31f7bf19
ZJS
569 (int) (c - (const char*) data),
570 (const char*) data,
7ac4fa7e
ZJS
571 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
572 off);
31f7bf19 573 }
86aa7ba4
LP
574 }
575
a72b6353
ZJS
576 if (r < 0)
577 return r;
578
d4205751
LP
579 if (flags & OUTPUT_CATALOG)
580 print_catalog(f, j);
581
86aa7ba4
LP
582 return 0;
583}
584
08ace05b
LP
585static int output_export(
586 FILE *f,
587 sd_journal *j,
588 OutputMode mode,
589 unsigned n_columns,
cc25a67e
LK
590 OutputFlags flags,
591 Set *output_fields) {
08ace05b 592
86aa7ba4
LP
593 sd_id128_t boot_id;
594 char sid[33];
595 int r;
596 usec_t realtime, monotonic;
7fd1b19b 597 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
598 const void *data;
599 size_t length;
600
601 assert(j);
602
93b73b06
LP
603 sd_journal_set_data_threshold(j, 0);
604
86aa7ba4 605 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
606 if (r < 0)
607 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
608
609 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
610 if (r < 0)
611 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
612
613 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
614 if (r < 0)
615 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 616
08ace05b
LP
617 fprintf(f,
618 "__CURSOR=%s\n"
de0671ee
ZJS
619 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
620 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
08ace05b
LP
621 "_BOOT_ID=%s\n",
622 cursor,
de0671ee
ZJS
623 realtime,
624 monotonic,
08ace05b 625 sd_id128_to_string(boot_id, sid));
86aa7ba4 626
a72b6353 627 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
cc25a67e 628 const char *c;
86aa7ba4 629
112301ae
LP
630 /* We already printed the boot id, from the data in
631 * the header, hence let's suppress it here */
632 if (length >= 9 &&
2a0e0692 633 startswith(data, "_BOOT_ID="))
112301ae
LP
634 continue;
635
cc25a67e
LK
636 c = memchr(data, '=', length);
637 if (!c) {
638 log_error("Invalid field.");
639 return -EINVAL;
640 }
641
642 r = field_set_test(output_fields, data, c - (const char *) data);
643 if (r < 0)
644 return r;
645 if (!r)
646 continue;
647
0ade5ffe
ZJS
648 if (utf8_is_printable_newline(data, length, false))
649 fwrite(data, length, 1, f);
650 else {
86aa7ba4
LP
651 uint64_t le64;
652
08ace05b
LP
653 fwrite(data, c - (const char*) data, 1, f);
654 fputc('\n', f);
86aa7ba4 655 le64 = htole64(length - (c - (const char*) data) - 1);
08ace05b
LP
656 fwrite(&le64, sizeof(le64), 1, f);
657 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
0ade5ffe 658 }
86aa7ba4 659
08ace05b 660 fputc('\n', f);
86aa7ba4
LP
661 }
662
a72b6353
ZJS
663 if (r < 0)
664 return r;
665
08ace05b 666 fputc('\n', f);
86aa7ba4
LP
667
668 return 0;
669}
670
240a5fe8 671void json_escape(
08ace05b
LP
672 FILE *f,
673 const char* p,
674 size_t l,
675 OutputFlags flags) {
676
677 assert(f);
678 assert(p);
679
93b73b06 680 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
08ace05b
LP
681 fputs("null", f);
682
8980058a 683 else if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(p, l)) {
86aa7ba4
LP
684 bool not_first = false;
685
08ace05b 686 fputs("[ ", f);
86aa7ba4
LP
687
688 while (l > 0) {
689 if (not_first)
08ace05b 690 fprintf(f, ", %u", (uint8_t) *p);
86aa7ba4
LP
691 else {
692 not_first = true;
08ace05b 693 fprintf(f, "%u", (uint8_t) *p);
86aa7ba4
LP
694 }
695
696 p++;
697 l--;
698 }
699
08ace05b 700 fputs(" ]", f);
86aa7ba4 701 } else {
08ace05b 702 fputc('\"', f);
86aa7ba4
LP
703
704 while (l > 0) {
4c701096 705 if (IN_SET(*p, '"', '\\')) {
08ace05b
LP
706 fputc('\\', f);
707 fputc(*p, f);
31f7bf19
ZJS
708 } else if (*p == '\n')
709 fputs("\\n", f);
91a8a108
DM
710 else if ((uint8_t) *p < ' ')
711 fprintf(f, "\\u%04x", (uint8_t) *p);
08ace05b
LP
712 else
713 fputc(*p, f);
86aa7ba4
LP
714
715 p++;
716 l--;
717 }
718
08ace05b 719 fputc('\"', f);
86aa7ba4
LP
720 }
721}
722
08ace05b
LP
723static int output_json(
724 FILE *f,
725 sd_journal *j,
726 OutputMode mode,
727 unsigned n_columns,
cc25a67e
LK
728 OutputFlags flags,
729 Set *output_fields) {
08ace05b 730
86aa7ba4 731 uint64_t realtime, monotonic;
7fd1b19b 732 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
733 const void *data;
734 size_t length;
735 sd_id128_t boot_id;
2e729834 736 char sid[33], *k;
86aa7ba4 737 int r;
d99ae53a
LP
738 Hashmap *h = NULL;
739 bool done, separator;
86aa7ba4
LP
740
741 assert(j);
742
93b73b06
LP
743 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
744
86aa7ba4 745 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
746 if (r < 0)
747 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
748
749 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
750 if (r < 0)
751 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
752
753 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
754 if (r < 0)
755 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 756
a6e87e90 757 if (mode == OUTPUT_JSON_PRETTY)
08ace05b
LP
758 fprintf(f,
759 "{\n"
760 "\t\"__CURSOR\" : \"%s\",\n"
de0671ee
ZJS
761 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
762 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
08ace05b
LP
763 "\t\"_BOOT_ID\" : \"%s\"",
764 cursor,
de0671ee
ZJS
765 realtime,
766 monotonic,
08ace05b 767 sd_id128_to_string(boot_id, sid));
48383c25
LP
768 else {
769 if (mode == OUTPUT_JSON_SSE)
770 fputs("data: ", f);
771
08ace05b
LP
772 fprintf(f,
773 "{ \"__CURSOR\" : \"%s\", "
de0671ee
ZJS
774 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
775 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
08ace05b
LP
776 "\"_BOOT_ID\" : \"%s\"",
777 cursor,
de0671ee
ZJS
778 realtime,
779 monotonic,
08ace05b 780 sd_id128_to_string(boot_id, sid));
48383c25 781 }
86aa7ba4 782
d5099efc 783 h = hashmap_new(&string_hash_ops);
d99ae53a 784 if (!h)
b56d608e 785 return log_oom();
d99ae53a
LP
786
787 /* First round, iterate through the entry and count how often each field appears */
a72b6353 788 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
d99ae53a
LP
789 const char *eq;
790 char *n;
791 unsigned u;
86aa7ba4 792
112301ae
LP
793 if (length >= 9 &&
794 memcmp(data, "_BOOT_ID=", 9) == 0)
795 continue;
796
d99ae53a
LP
797 eq = memchr(data, '=', length);
798 if (!eq)
799 continue;
86aa7ba4 800
d99ae53a
LP
801 n = strndup(data, eq - (const char*) data);
802 if (!n) {
b56d608e 803 r = log_oom();
d99ae53a
LP
804 goto finish;
805 }
a6e87e90 806
d99ae53a
LP
807 u = PTR_TO_UINT(hashmap_get(h, n));
808 if (u == 0) {
809 r = hashmap_put(h, n, UINT_TO_PTR(1));
810 if (r < 0) {
811 free(n);
b56d608e 812 log_oom();
d99ae53a
LP
813 goto finish;
814 }
815 } else {
816 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
817 free(n);
b56d608e
LP
818 if (r < 0) {
819 log_oom();
d99ae53a 820 goto finish;
b56d608e 821 }
d99ae53a 822 }
86aa7ba4
LP
823 }
824
a72b6353
ZJS
825 if (r < 0)
826 return r;
827
d99ae53a
LP
828 separator = true;
829 do {
830 done = true;
831
832 SD_JOURNAL_FOREACH_DATA(j, data, length) {
833 const char *eq;
834 char *kk, *n;
835 size_t m;
836 unsigned u;
837
838 /* We already printed the boot id, from the data in
839 * the header, hence let's suppress it here */
840 if (length >= 9 &&
841 memcmp(data, "_BOOT_ID=", 9) == 0)
842 continue;
843
844 eq = memchr(data, '=', length);
845 if (!eq)
846 continue;
847
d99ae53a
LP
848 m = eq - (const char*) data;
849
850 n = strndup(data, m);
851 if (!n) {
b56d608e 852 r = log_oom();
d99ae53a
LP
853 goto finish;
854 }
855
cc25a67e
LK
856 if (output_fields && !set_get(output_fields, n)) {
857 free(n);
858 continue;
859 }
860
861 if (separator) {
862 if (mode == OUTPUT_JSON_PRETTY)
863 fputs(",\n\t", f);
864 else
865 fputs(", ", f);
866 }
867
d99ae53a
LP
868 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
869 if (u == 0) {
870 /* We already printed this, let's jump to the next */
871 free(n);
872 separator = false;
873
874 continue;
875 } else if (u == 1) {
876 /* Field only appears once, output it directly */
877
878 json_escape(f, data, m, flags);
879 fputs(" : ", f);
880
881 json_escape(f, eq + 1, length - m - 1, flags);
882
883 hashmap_remove(h, n);
884 free(kk);
885 free(n);
886
887 separator = true;
888
889 continue;
890
891 } else {
892 /* Field appears multiple times, output it as array */
893 json_escape(f, data, m, flags);
894 fputs(" : [ ", f);
895 json_escape(f, eq + 1, length - m - 1, flags);
896
897 /* Iterate through the end of the list */
898
899 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
900 if (length < m + 1)
901 continue;
902
903 if (memcmp(data, n, m) != 0)
904 continue;
905
906 if (((const char*) data)[m] != '=')
907 continue;
908
909 fputs(", ", f);
910 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
911 }
912
913 fputs(" ]", f);
914
915 hashmap_remove(h, n);
916 free(kk);
917 free(n);
918
919 /* Iterate data fields form the beginning */
920 done = false;
921 separator = true;
922
923 break;
924 }
925 }
926
927 } while (!done);
928
a6e87e90 929 if (mode == OUTPUT_JSON_PRETTY)
08ace05b 930 fputs("\n}\n", f);
48383c25
LP
931 else if (mode == OUTPUT_JSON_SSE)
932 fputs("}\n\n", f);
a6e87e90 933 else
08ace05b 934 fputs(" }\n", f);
86aa7ba4 935
d99ae53a
LP
936 r = 0;
937
938finish:
939 while ((k = hashmap_steal_first_key(h)))
940 free(k);
941
942 hashmap_free(h);
943
944 return r;
86aa7ba4
LP
945}
946
08ace05b
LP
947static int output_cat(
948 FILE *f,
949 sd_journal *j,
950 OutputMode mode,
951 unsigned n_columns,
cc25a67e
LK
952 OutputFlags flags,
953 Set *output_fields) {
08ace05b 954
d3f2bdbf
LP
955 const void *data;
956 size_t l;
957 int r;
958
959 assert(j);
08ace05b 960 assert(f);
d3f2bdbf 961
93b73b06
LP
962 sd_journal_set_data_threshold(j, 0);
963
d3f2bdbf
LP
964 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
965 if (r < 0) {
c198300f
LP
966 /* An entry without MESSAGE=? */
967 if (r == -ENOENT)
968 return 0;
969
8d3d7072 970 return log_error_errno(r, "Failed to get data: %m");
d3f2bdbf
LP
971 }
972
973 assert(l >= 8);
974
08ace05b
LP
975 fwrite((const char*) data + 8, 1, l - 8, f);
976 fputc('\n', f);
d3f2bdbf
LP
977
978 return 0;
979}
980
08ace05b
LP
981static int (*output_funcs[_OUTPUT_MODE_MAX])(
982 FILE *f,
983 sd_journal*j,
984 OutputMode mode,
985 unsigned n_columns,
cc25a67e
LK
986 OutputFlags flags,
987 Set *output_fields) = {
08ace05b 988
a6e87e90 989 [OUTPUT_SHORT] = output_short,
44bc6e1f 990 [OUTPUT_SHORT_ISO] = output_short,
7e563bfc 991 [OUTPUT_SHORT_ISO_PRECISE] = output_short,
f02d8367
ZJS
992 [OUTPUT_SHORT_PRECISE] = output_short,
993 [OUTPUT_SHORT_MONOTONIC] = output_short,
bb321ed9 994 [OUTPUT_SHORT_UNIX] = output_short,
29a753df 995 [OUTPUT_SHORT_FULL] = output_short,
86aa7ba4
LP
996 [OUTPUT_VERBOSE] = output_verbose,
997 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 998 [OUTPUT_JSON] = output_json,
a6e87e90 999 [OUTPUT_JSON_PRETTY] = output_json,
48383c25 1000 [OUTPUT_JSON_SSE] = output_json,
d3f2bdbf 1001 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
1002};
1003
08ace05b
LP
1004int output_journal(
1005 FILE *f,
1006 sd_journal *j,
1007 OutputMode mode,
1008 unsigned n_columns,
94e0bd7d 1009 OutputFlags flags,
cc25a67e 1010 char **output_fields,
94e0bd7d 1011 bool *ellipsized) {
08ace05b 1012
e268b81e 1013 int ret;
cc25a67e 1014 _cleanup_set_free_free_ Set *fields = NULL;
df50185b 1015 assert(mode >= 0);
86aa7ba4
LP
1016 assert(mode < _OUTPUT_MODE_MAX);
1017
34a35ece
LP
1018 if (n_columns <= 0)
1019 n_columns = columns();
1020
cc25a67e
LK
1021 if (output_fields) {
1022 fields = set_new(&string_hash_ops);
1023 if (!fields)
1024 return log_oom();
1025
1026 ret = set_put_strdupv(fields, output_fields);
1027 if (ret < 0)
1028 return ret;
1029 }
1030
1031 ret = output_funcs[mode](f, j, mode, n_columns, flags, fields);
94e0bd7d
ZJS
1032
1033 if (ellipsized && ret > 0)
1034 *ellipsized = true;
1035
e268b81e 1036 return ret;
86aa7ba4
LP
1037}
1038
ea6c2dd1
LP
1039static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
1040 assert(f);
1041 assert(flags);
1042
1043 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
1044 return 0;
1045
1046 /* Print a beginning new line if that's request, but only once
1047 * on the first line we print. */
1048
1049 fputc('\n', f);
1050 *flags &= ~OUTPUT_BEGIN_NEWLINE;
1051 return 0;
1052}
1053
1a6c43e9
MT
1054static int show_journal(FILE *f,
1055 sd_journal *j,
1056 OutputMode mode,
1057 unsigned n_columns,
1058 usec_t not_before,
1059 unsigned how_many,
94e0bd7d
ZJS
1060 OutputFlags flags,
1061 bool *ellipsized) {
86aa7ba4 1062
86aa7ba4 1063 int r;
df50185b
LP
1064 unsigned line = 0;
1065 bool need_seek = false;
085d7120 1066 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 1067
1a6c43e9 1068 assert(j);
df50185b
LP
1069 assert(mode >= 0);
1070 assert(mode < _OUTPUT_MODE_MAX);
1946b0bd
LP
1071
1072 /* Seek to end */
86aa7ba4
LP
1073 r = sd_journal_seek_tail(j);
1074 if (r < 0)
b56d608e 1075 return log_error_errno(r, "Failed to seek to tail: %m");
86aa7ba4 1076
df50185b
LP
1077 r = sd_journal_previous_skip(j, how_many);
1078 if (r < 0)
b56d608e 1079 return log_error_errno(r, "Failed to skip previous: %m");
86aa7ba4 1080
df50185b
LP
1081 for (;;) {
1082 for (;;) {
1083 usec_t usec;
1084
1085 if (need_seek) {
1086 r = sd_journal_next(j);
1087 if (r < 0)
b56d608e 1088 return log_error_errno(r, "Failed to iterate through journal: %m");
df50185b
LP
1089 }
1090
1091 if (r == 0)
1092 break;
86aa7ba4 1093
df50185b
LP
1094 need_seek = true;
1095
1096 if (not_before > 0) {
1097 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
1098
1099 /* -ESTALE is returned if the
1100 timestamp is not from this boot */
1101 if (r == -ESTALE)
1102 continue;
1103 else if (r < 0)
b56d608e 1104 return log_error_errno(r, "Failed to get journal time: %m");
df50185b
LP
1105
1106 if (usec < not_before)
1107 continue;
1108 }
1109
313cefa1 1110 line++;
ea6c2dd1 1111 maybe_print_begin_newline(f, &flags);
df50185b 1112
cc25a67e 1113 r = output_journal(f, j, mode, n_columns, flags, NULL, ellipsized);
df50185b 1114 if (r < 0)
b56d608e 1115 return r;
df50185b
LP
1116 }
1117
08984293
LP
1118 if (warn_cutoff && line < how_many && not_before > 0) {
1119 sd_id128_t boot_id;
a7f7d1bd 1120 usec_t cutoff = 0;
08984293
LP
1121
1122 /* Check whether the cutoff line is too early */
1123
1124 r = sd_id128_get_boot(&boot_id);
1125 if (r < 0)
b56d608e 1126 return log_error_errno(r, "Failed to get boot id: %m");
08984293
LP
1127
1128 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1129 if (r < 0)
b56d608e 1130 return log_error_errno(r, "Failed to get journal cutoff time: %m");
08984293 1131
ea6c2dd1
LP
1132 if (r > 0 && not_before < cutoff) {
1133 maybe_print_begin_newline(f, &flags);
08ace05b 1134 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
ea6c2dd1 1135 }
08984293
LP
1136
1137 warn_cutoff = false;
1138 }
1139
085d7120 1140 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
1141 break;
1142
3a43da28 1143 r = sd_journal_wait(j, USEC_INFINITY);
df50185b 1144 if (r < 0)
b56d608e 1145 return log_error_errno(r, "Failed to wait for journal: %m");
df50185b 1146
86aa7ba4
LP
1147 }
1148
b56d608e 1149 return 0;
1a6c43e9
MT
1150}
1151
886a64fe 1152int add_matches_for_unit(sd_journal *j, const char *unit) {
2b45d881 1153 const char *m1, *m2, *m3, *m4;
1a6c43e9
MT
1154 int r;
1155
886a64fe 1156 assert(j);
1a6c43e9
MT
1157 assert(unit);
1158
63c372cb
LP
1159 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1160 m2 = strjoina("COREDUMP_UNIT=", unit);
1161 m3 = strjoina("UNIT=", unit);
1162 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1a6c43e9 1163
886a64fe
ZJS
1164 (void)(
1165 /* Look for messages from the service itself */
1166 (r = sd_journal_add_match(j, m1, 0)) ||
1167
1168 /* Look for coredumps of the service */
1169 (r = sd_journal_add_disjunction(j)) ||
fdcd37df
ZJS
1170 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1171 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
886a64fe
ZJS
1172 (r = sd_journal_add_match(j, m2, 0)) ||
1173
1174 /* Look for messages from PID 1 about this service */
1175 (r = sd_journal_add_disjunction(j)) ||
1176 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
2d0b2e87
ZJS
1177 (r = sd_journal_add_match(j, m3, 0)) ||
1178
1179 /* Look for messages from authorized daemons about this service */
1180 (r = sd_journal_add_disjunction(j)) ||
1181 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1182 (r = sd_journal_add_match(j, m4, 0))
886a64fe 1183 );
2d0b2e87 1184
69ae3ee0 1185 if (r == 0 && endswith(unit, ".slice")) {
2b45d881
LP
1186 const char *m5;
1187
1188 m5 = strjoina("_SYSTEMD_SLICE=", unit);
69ae3ee0
ZJS
1189
1190 /* Show all messages belonging to a slice */
1191 (void)(
1192 (r = sd_journal_add_disjunction(j)) ||
1193 (r = sd_journal_add_match(j, m5, 0))
1194 );
1195 }
1196
886a64fe
ZJS
1197 return r;
1198}
1a6c43e9 1199
886a64fe
ZJS
1200int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1201 int r;
2d0b2e87
ZJS
1202 char *m1, *m2, *m3, *m4;
1203 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1a6c43e9 1204
886a64fe
ZJS
1205 assert(j);
1206 assert(unit);
1a6c43e9 1207
63c372cb
LP
1208 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1209 m2 = strjoina("USER_UNIT=", unit);
1210 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1211 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
de0671ee 1212 sprintf(muid, "_UID="UID_FMT, uid);
1a6c43e9 1213
886a64fe
ZJS
1214 (void) (
1215 /* Look for messages from the user service itself */
1216 (r = sd_journal_add_match(j, m1, 0)) ||
2d0b2e87 1217 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1218
1219 /* Look for messages from systemd about this service */
1220 (r = sd_journal_add_disjunction(j)) ||
1221 (r = sd_journal_add_match(j, m2, 0)) ||
2d0b2e87 1222 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1223
1224 /* Look for coredumps of the service */
1225 (r = sd_journal_add_disjunction(j)) ||
1226 (r = sd_journal_add_match(j, m3, 0)) ||
2d0b2e87
ZJS
1227 (r = sd_journal_add_match(j, muid, 0)) ||
1228 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1229
1230 /* Look for messages from authorized daemons about this service */
1231 (r = sd_journal_add_disjunction(j)) ||
fdcd37df 1232 (r = sd_journal_add_match(j, m4, 0)) ||
2d0b2e87 1233 (r = sd_journal_add_match(j, muid, 0)) ||
fdcd37df 1234 (r = sd_journal_add_match(j, "_UID=0", 0))
886a64fe 1235 );
69ae3ee0
ZJS
1236
1237 if (r == 0 && endswith(unit, ".slice")) {
2b45d881
LP
1238 const char *m5;
1239
1240 m5 = strjoina("_SYSTEMD_SLICE=", unit);
69ae3ee0
ZJS
1241
1242 /* Show all messages belonging to a slice */
1243 (void)(
1244 (r = sd_journal_add_disjunction(j)) ||
1245 (r = sd_journal_add_match(j, m5, 0)) ||
1246 (r = sd_journal_add_match(j, muid, 0))
1247 );
1248 }
1249
1a6c43e9
MT
1250 return r;
1251}
1252
b6741478 1253static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
3d94f76c 1254 _cleanup_close_pair_ int pair[2] = { -1, -1 };
a4475f57 1255 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
b6741478
LP
1256 pid_t pid, child;
1257 siginfo_t si;
1258 char buf[37];
1259 ssize_t k;
1260 int r;
1261
1262 assert(machine);
1263 assert(boot_id);
1264
affcf189 1265 if (!machine_name_is_valid(machine))
b6741478
LP
1266 return -EINVAL;
1267
e04b0cdb 1268 r = container_get_leader(machine, &pid);
b6741478
LP
1269 if (r < 0)
1270 return r;
e04b0cdb 1271
671c3419 1272 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
b6741478
LP
1273 if (r < 0)
1274 return r;
1275
e04b0cdb 1276 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
b6741478
LP
1277 return -errno;
1278
1279 child = fork();
1280 if (child < 0)
1281 return -errno;
1282
1283 if (child == 0) {
1284 int fd;
1285
03e334a1 1286 pair[0] = safe_close(pair[0]);
b6741478 1287
671c3419 1288 r = namespace_enter(pidnsfd, mntnsfd, -1, -1, rootfd);
b6741478
LP
1289 if (r < 0)
1290 _exit(EXIT_FAILURE);
1291
1292 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1293 if (fd < 0)
1294 _exit(EXIT_FAILURE);
1295
a6dcc7e5 1296 r = loop_read_exact(fd, buf, 36, false);
03e334a1 1297 safe_close(fd);
6c767d1e 1298 if (r < 0)
b6741478
LP
1299 _exit(EXIT_FAILURE);
1300
e04b0cdb 1301 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
b6741478
LP
1302 if (k != 36)
1303 _exit(EXIT_FAILURE);
1304
1305 _exit(EXIT_SUCCESS);
1306 }
1307
03e334a1 1308 pair[1] = safe_close(pair[1]);
b6741478 1309
b6741478
LP
1310 r = wait_for_terminate(child, &si);
1311 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1312 return r < 0 ? r : -EIO;
1313
fbadf045
LP
1314 k = recv(pair[0], buf, 36, 0);
1315 if (k != 36)
1316 return -EIO;
1317
b6741478
LP
1318 buf[36] = 0;
1319 r = sd_id128_from_string(buf, boot_id);
1320 if (r < 0)
1321 return r;
1322
1323 return 0;
1324}
1325
1326int add_match_this_boot(sd_journal *j, const char *machine) {
5ec76417
ZJS
1327 char match[9+32+1] = "_BOOT_ID=";
1328 sd_id128_t boot_id;
1329 int r;
1330
1331 assert(j);
1332
b6741478
LP
1333 if (machine) {
1334 r = get_boot_id_for_machine(machine, &boot_id);
f647962d
MS
1335 if (r < 0)
1336 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
b6741478
LP
1337 } else {
1338 r = sd_id128_get_boot(&boot_id);
f647962d
MS
1339 if (r < 0)
1340 return log_error_errno(r, "Failed to get boot id: %m");
5ec76417
ZJS
1341 }
1342
1343 sd_id128_to_string(boot_id, match + 9);
1344 r = sd_journal_add_match(j, match, strlen(match));
f647962d
MS
1345 if (r < 0)
1346 return log_error_errno(r, "Failed to add match: %m");
5ec76417
ZJS
1347
1348 r = sd_journal_add_conjunction(j);
1349 if (r < 0)
b56d608e 1350 return log_error_errno(r, "Failed to add conjunction: %m");
5ec76417
ZJS
1351
1352 return 0;
1353}
1354
886a64fe 1355int show_journal_by_unit(
1a6c43e9
MT
1356 FILE *f,
1357 const char *unit,
1358 OutputMode mode,
1359 unsigned n_columns,
1360 usec_t not_before,
1361 unsigned how_many,
1362 uid_t uid,
886a64fe 1363 OutputFlags flags,
3c756001
LP
1364 int journal_open_flags,
1365 bool system_unit,
94e0bd7d 1366 bool *ellipsized) {
1a6c43e9 1367
4afd3348 1368 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1a6c43e9
MT
1369 int r;
1370
1371 assert(mode >= 0);
1372 assert(mode < _OUTPUT_MODE_MAX);
1373 assert(unit);
1374
1a6c43e9
MT
1375 if (how_many <= 0)
1376 return 0;
1377
3c756001 1378 r = sd_journal_open(&j, journal_open_flags);
f9045468 1379 if (r < 0)
b56d608e 1380 return log_error_errno(r, "Failed to open journal: %m");
f9045468 1381
b6741478 1382 r = add_match_this_boot(j, NULL);
5ec76417
ZJS
1383 if (r < 0)
1384 return r;
1385
3c756001 1386 if (system_unit)
886a64fe
ZJS
1387 r = add_matches_for_unit(j, unit);
1388 else
1389 r = add_matches_for_user_unit(j, unit, uid);
1a6c43e9 1390 if (r < 0)
b56d608e 1391 return log_error_errno(r, "Failed to add unit matches: %m");
1a6c43e9 1392
553d2243 1393 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
1394 _cleanup_free_ char *filter;
1395
1396 filter = journal_make_match_string(j);
b56d608e
LP
1397 if (!filter)
1398 return log_oom();
1399
4ad16808
ZJS
1400 log_debug("Journal filter: %s", filter);
1401 }
5ec76417 1402
94e0bd7d 1403 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
86aa7ba4 1404}