]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
Merge pull request #7637 from yuwata/transient-path
[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
fbd0b64f
LP
509 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=",
510 STRLEN("_SOURCE_REALTIME_TIMESTAMP="), &value,
511 NULL);
cf40f0be 512 if (r < 0)
e64c53fd 513 return r;
d813d7a3
LP
514 assert(r > 0);
515
516 r = safe_atou64(value, &realtime);
517 if (r < 0)
518 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
cf40f0be
ZJS
519 }
520
521 if (r < 0) {
522 r = sd_journal_get_realtime_usec(j, &realtime);
b56d608e
LP
523 if (r < 0)
524 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
525 }
526
527 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
528 if (r < 0)
529 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 530
8924973a
ZJS
531 timestamp = flags & OUTPUT_UTC ? format_timestamp_us_utc(ts, sizeof ts, realtime)
532 : format_timestamp_us(ts, sizeof ts, realtime);
08ace05b 533 fprintf(f, "%s [%s]\n",
8924973a 534 timestamp ?: "(no timestamp)",
08ace05b 535 cursor);
86aa7ba4 536
a72b6353 537 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
31f7bf19
ZJS
538 const char *c;
539 int fieldlen;
7ac4fa7e
ZJS
540 const char *on = "", *off = "";
541
31f7bf19
ZJS
542 c = memchr(data, '=', length);
543 if (!c) {
544 log_error("Invalid field.");
545 return -EINVAL;
546 }
547 fieldlen = c - (const char*) data;
86aa7ba4 548
cc25a67e
LK
549 r = field_set_test(output_fields, data, fieldlen);
550 if (r < 0)
551 return r;
552 if (!r)
553 continue;
554
7ac4fa7e 555 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
1fc464f6
LP
556 on = ANSI_HIGHLIGHT;
557 off = ANSI_NORMAL;
7ac4fa7e
ZJS
558 }
559
8980058a 560 if ((flags & OUTPUT_SHOW_ALL) ||
a6f0104a
ZJS
561 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
562 && utf8_is_printable(data, length))) {
7ac4fa7e 563 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
31f7bf19 564 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
7ac4fa7e 565 fputs(off, f);
31f7bf19
ZJS
566 } else {
567 char bytes[FORMAT_BYTES_MAX];
86aa7ba4 568
7ac4fa7e
ZJS
569 fprintf(f, " %s%.*s=[%s blob data]%s\n",
570 on,
31f7bf19
ZJS
571 (int) (c - (const char*) data),
572 (const char*) data,
7ac4fa7e
ZJS
573 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
574 off);
31f7bf19 575 }
86aa7ba4
LP
576 }
577
a72b6353
ZJS
578 if (r < 0)
579 return r;
580
d4205751
LP
581 if (flags & OUTPUT_CATALOG)
582 print_catalog(f, j);
583
86aa7ba4
LP
584 return 0;
585}
586
08ace05b
LP
587static int output_export(
588 FILE *f,
589 sd_journal *j,
590 OutputMode mode,
591 unsigned n_columns,
cc25a67e
LK
592 OutputFlags flags,
593 Set *output_fields) {
08ace05b 594
86aa7ba4
LP
595 sd_id128_t boot_id;
596 char sid[33];
597 int r;
598 usec_t realtime, monotonic;
7fd1b19b 599 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
600 const void *data;
601 size_t length;
602
603 assert(j);
604
93b73b06
LP
605 sd_journal_set_data_threshold(j, 0);
606
86aa7ba4 607 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
608 if (r < 0)
609 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
610
611 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
612 if (r < 0)
613 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
614
615 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
616 if (r < 0)
617 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 618
08ace05b
LP
619 fprintf(f,
620 "__CURSOR=%s\n"
de0671ee
ZJS
621 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
622 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
08ace05b
LP
623 "_BOOT_ID=%s\n",
624 cursor,
de0671ee
ZJS
625 realtime,
626 monotonic,
08ace05b 627 sd_id128_to_string(boot_id, sid));
86aa7ba4 628
a72b6353 629 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
cc25a67e 630 const char *c;
86aa7ba4 631
112301ae
LP
632 /* We already printed the boot id, from the data in
633 * the header, hence let's suppress it here */
634 if (length >= 9 &&
2a0e0692 635 startswith(data, "_BOOT_ID="))
112301ae
LP
636 continue;
637
cc25a67e
LK
638 c = memchr(data, '=', length);
639 if (!c) {
640 log_error("Invalid field.");
641 return -EINVAL;
642 }
643
644 r = field_set_test(output_fields, data, c - (const char *) data);
645 if (r < 0)
646 return r;
647 if (!r)
648 continue;
649
0ade5ffe
ZJS
650 if (utf8_is_printable_newline(data, length, false))
651 fwrite(data, length, 1, f);
652 else {
86aa7ba4
LP
653 uint64_t le64;
654
08ace05b
LP
655 fwrite(data, c - (const char*) data, 1, f);
656 fputc('\n', f);
86aa7ba4 657 le64 = htole64(length - (c - (const char*) data) - 1);
08ace05b
LP
658 fwrite(&le64, sizeof(le64), 1, f);
659 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
0ade5ffe 660 }
86aa7ba4 661
08ace05b 662 fputc('\n', f);
86aa7ba4
LP
663 }
664
a72b6353
ZJS
665 if (r < 0)
666 return r;
667
08ace05b 668 fputc('\n', f);
86aa7ba4
LP
669
670 return 0;
671}
672
240a5fe8 673void json_escape(
08ace05b
LP
674 FILE *f,
675 const char* p,
676 size_t l,
677 OutputFlags flags) {
678
679 assert(f);
680 assert(p);
681
93b73b06 682 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
08ace05b
LP
683 fputs("null", f);
684
8980058a 685 else if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(p, l)) {
86aa7ba4
LP
686 bool not_first = false;
687
08ace05b 688 fputs("[ ", f);
86aa7ba4
LP
689
690 while (l > 0) {
691 if (not_first)
08ace05b 692 fprintf(f, ", %u", (uint8_t) *p);
86aa7ba4
LP
693 else {
694 not_first = true;
08ace05b 695 fprintf(f, "%u", (uint8_t) *p);
86aa7ba4
LP
696 }
697
698 p++;
699 l--;
700 }
701
08ace05b 702 fputs(" ]", f);
86aa7ba4 703 } else {
08ace05b 704 fputc('\"', f);
86aa7ba4
LP
705
706 while (l > 0) {
4c701096 707 if (IN_SET(*p, '"', '\\')) {
08ace05b
LP
708 fputc('\\', f);
709 fputc(*p, f);
31f7bf19
ZJS
710 } else if (*p == '\n')
711 fputs("\\n", f);
91a8a108
DM
712 else if ((uint8_t) *p < ' ')
713 fprintf(f, "\\u%04x", (uint8_t) *p);
08ace05b
LP
714 else
715 fputc(*p, f);
86aa7ba4
LP
716
717 p++;
718 l--;
719 }
720
08ace05b 721 fputc('\"', f);
86aa7ba4
LP
722 }
723}
724
08ace05b
LP
725static int output_json(
726 FILE *f,
727 sd_journal *j,
728 OutputMode mode,
729 unsigned n_columns,
cc25a67e
LK
730 OutputFlags flags,
731 Set *output_fields) {
08ace05b 732
86aa7ba4 733 uint64_t realtime, monotonic;
7fd1b19b 734 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
735 const void *data;
736 size_t length;
737 sd_id128_t boot_id;
2e729834 738 char sid[33], *k;
86aa7ba4 739 int r;
d99ae53a
LP
740 Hashmap *h = NULL;
741 bool done, separator;
86aa7ba4
LP
742
743 assert(j);
744
93b73b06
LP
745 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
746
86aa7ba4 747 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
748 if (r < 0)
749 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
750
751 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
752 if (r < 0)
753 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
754
755 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
756 if (r < 0)
757 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 758
a6e87e90 759 if (mode == OUTPUT_JSON_PRETTY)
08ace05b
LP
760 fprintf(f,
761 "{\n"
762 "\t\"__CURSOR\" : \"%s\",\n"
de0671ee
ZJS
763 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
764 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
08ace05b
LP
765 "\t\"_BOOT_ID\" : \"%s\"",
766 cursor,
de0671ee
ZJS
767 realtime,
768 monotonic,
08ace05b 769 sd_id128_to_string(boot_id, sid));
48383c25
LP
770 else {
771 if (mode == OUTPUT_JSON_SSE)
772 fputs("data: ", f);
773
08ace05b
LP
774 fprintf(f,
775 "{ \"__CURSOR\" : \"%s\", "
de0671ee
ZJS
776 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
777 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
08ace05b
LP
778 "\"_BOOT_ID\" : \"%s\"",
779 cursor,
de0671ee
ZJS
780 realtime,
781 monotonic,
08ace05b 782 sd_id128_to_string(boot_id, sid));
48383c25 783 }
86aa7ba4 784
d5099efc 785 h = hashmap_new(&string_hash_ops);
d99ae53a 786 if (!h)
b56d608e 787 return log_oom();
d99ae53a
LP
788
789 /* First round, iterate through the entry and count how often each field appears */
a72b6353 790 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
d99ae53a
LP
791 const char *eq;
792 char *n;
793 unsigned u;
86aa7ba4 794
112301ae
LP
795 if (length >= 9 &&
796 memcmp(data, "_BOOT_ID=", 9) == 0)
797 continue;
798
d99ae53a
LP
799 eq = memchr(data, '=', length);
800 if (!eq)
801 continue;
86aa7ba4 802
d99ae53a
LP
803 n = strndup(data, eq - (const char*) data);
804 if (!n) {
b56d608e 805 r = log_oom();
d99ae53a
LP
806 goto finish;
807 }
a6e87e90 808
d99ae53a
LP
809 u = PTR_TO_UINT(hashmap_get(h, n));
810 if (u == 0) {
811 r = hashmap_put(h, n, UINT_TO_PTR(1));
812 if (r < 0) {
813 free(n);
b56d608e 814 log_oom();
d99ae53a
LP
815 goto finish;
816 }
817 } else {
818 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
819 free(n);
b56d608e
LP
820 if (r < 0) {
821 log_oom();
d99ae53a 822 goto finish;
b56d608e 823 }
d99ae53a 824 }
86aa7ba4
LP
825 }
826
a72b6353
ZJS
827 if (r < 0)
828 return r;
829
d99ae53a
LP
830 separator = true;
831 do {
832 done = true;
833
834 SD_JOURNAL_FOREACH_DATA(j, data, length) {
835 const char *eq;
836 char *kk, *n;
837 size_t m;
838 unsigned u;
839
840 /* We already printed the boot id, from the data in
841 * the header, hence let's suppress it here */
842 if (length >= 9 &&
843 memcmp(data, "_BOOT_ID=", 9) == 0)
844 continue;
845
846 eq = memchr(data, '=', length);
847 if (!eq)
848 continue;
849
d99ae53a
LP
850 m = eq - (const char*) data;
851
852 n = strndup(data, m);
853 if (!n) {
b56d608e 854 r = log_oom();
d99ae53a
LP
855 goto finish;
856 }
857
cc25a67e
LK
858 if (output_fields && !set_get(output_fields, n)) {
859 free(n);
860 continue;
861 }
862
863 if (separator) {
864 if (mode == OUTPUT_JSON_PRETTY)
865 fputs(",\n\t", f);
866 else
867 fputs(", ", f);
868 }
869
d99ae53a
LP
870 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
871 if (u == 0) {
872 /* We already printed this, let's jump to the next */
873 free(n);
874 separator = false;
875
876 continue;
877 } else if (u == 1) {
878 /* Field only appears once, output it directly */
879
880 json_escape(f, data, m, flags);
881 fputs(" : ", f);
882
883 json_escape(f, eq + 1, length - m - 1, flags);
884
885 hashmap_remove(h, n);
886 free(kk);
887 free(n);
888
889 separator = true;
890
891 continue;
892
893 } else {
894 /* Field appears multiple times, output it as array */
895 json_escape(f, data, m, flags);
896 fputs(" : [ ", f);
897 json_escape(f, eq + 1, length - m - 1, flags);
898
899 /* Iterate through the end of the list */
900
901 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
902 if (length < m + 1)
903 continue;
904
905 if (memcmp(data, n, m) != 0)
906 continue;
907
908 if (((const char*) data)[m] != '=')
909 continue;
910
911 fputs(", ", f);
912 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
913 }
914
915 fputs(" ]", f);
916
917 hashmap_remove(h, n);
918 free(kk);
919 free(n);
920
921 /* Iterate data fields form the beginning */
922 done = false;
923 separator = true;
924
925 break;
926 }
927 }
928
929 } while (!done);
930
a6e87e90 931 if (mode == OUTPUT_JSON_PRETTY)
08ace05b 932 fputs("\n}\n", f);
48383c25
LP
933 else if (mode == OUTPUT_JSON_SSE)
934 fputs("}\n\n", f);
a6e87e90 935 else
08ace05b 936 fputs(" }\n", f);
86aa7ba4 937
d99ae53a
LP
938 r = 0;
939
940finish:
941 while ((k = hashmap_steal_first_key(h)))
942 free(k);
943
944 hashmap_free(h);
945
946 return r;
86aa7ba4
LP
947}
948
08ace05b
LP
949static int output_cat(
950 FILE *f,
951 sd_journal *j,
952 OutputMode mode,
953 unsigned n_columns,
cc25a67e
LK
954 OutputFlags flags,
955 Set *output_fields) {
08ace05b 956
d3f2bdbf
LP
957 const void *data;
958 size_t l;
959 int r;
960
961 assert(j);
08ace05b 962 assert(f);
d3f2bdbf 963
93b73b06
LP
964 sd_journal_set_data_threshold(j, 0);
965
d3f2bdbf
LP
966 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
967 if (r < 0) {
c198300f
LP
968 /* An entry without MESSAGE=? */
969 if (r == -ENOENT)
970 return 0;
971
8d3d7072 972 return log_error_errno(r, "Failed to get data: %m");
d3f2bdbf
LP
973 }
974
975 assert(l >= 8);
976
08ace05b
LP
977 fwrite((const char*) data + 8, 1, l - 8, f);
978 fputc('\n', f);
d3f2bdbf
LP
979
980 return 0;
981}
982
08ace05b
LP
983static int (*output_funcs[_OUTPUT_MODE_MAX])(
984 FILE *f,
985 sd_journal*j,
986 OutputMode mode,
987 unsigned n_columns,
cc25a67e
LK
988 OutputFlags flags,
989 Set *output_fields) = {
08ace05b 990
a6e87e90 991 [OUTPUT_SHORT] = output_short,
44bc6e1f 992 [OUTPUT_SHORT_ISO] = output_short,
7e563bfc 993 [OUTPUT_SHORT_ISO_PRECISE] = output_short,
f02d8367
ZJS
994 [OUTPUT_SHORT_PRECISE] = output_short,
995 [OUTPUT_SHORT_MONOTONIC] = output_short,
bb321ed9 996 [OUTPUT_SHORT_UNIX] = output_short,
29a753df 997 [OUTPUT_SHORT_FULL] = output_short,
86aa7ba4
LP
998 [OUTPUT_VERBOSE] = output_verbose,
999 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 1000 [OUTPUT_JSON] = output_json,
a6e87e90 1001 [OUTPUT_JSON_PRETTY] = output_json,
48383c25 1002 [OUTPUT_JSON_SSE] = output_json,
d3f2bdbf 1003 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
1004};
1005
08ace05b
LP
1006int output_journal(
1007 FILE *f,
1008 sd_journal *j,
1009 OutputMode mode,
1010 unsigned n_columns,
94e0bd7d 1011 OutputFlags flags,
cc25a67e 1012 char **output_fields,
94e0bd7d 1013 bool *ellipsized) {
08ace05b 1014
e268b81e 1015 int ret;
cc25a67e 1016 _cleanup_set_free_free_ Set *fields = NULL;
df50185b 1017 assert(mode >= 0);
86aa7ba4
LP
1018 assert(mode < _OUTPUT_MODE_MAX);
1019
34a35ece
LP
1020 if (n_columns <= 0)
1021 n_columns = columns();
1022
cc25a67e
LK
1023 if (output_fields) {
1024 fields = set_new(&string_hash_ops);
1025 if (!fields)
1026 return log_oom();
1027
1028 ret = set_put_strdupv(fields, output_fields);
1029 if (ret < 0)
1030 return ret;
1031 }
1032
1033 ret = output_funcs[mode](f, j, mode, n_columns, flags, fields);
94e0bd7d
ZJS
1034
1035 if (ellipsized && ret > 0)
1036 *ellipsized = true;
1037
e268b81e 1038 return ret;
86aa7ba4
LP
1039}
1040
ea6c2dd1
LP
1041static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
1042 assert(f);
1043 assert(flags);
1044
1045 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
1046 return 0;
1047
1048 /* Print a beginning new line if that's request, but only once
1049 * on the first line we print. */
1050
1051 fputc('\n', f);
1052 *flags &= ~OUTPUT_BEGIN_NEWLINE;
1053 return 0;
1054}
1055
1a6c43e9
MT
1056static int show_journal(FILE *f,
1057 sd_journal *j,
1058 OutputMode mode,
1059 unsigned n_columns,
1060 usec_t not_before,
1061 unsigned how_many,
94e0bd7d
ZJS
1062 OutputFlags flags,
1063 bool *ellipsized) {
86aa7ba4 1064
86aa7ba4 1065 int r;
df50185b
LP
1066 unsigned line = 0;
1067 bool need_seek = false;
085d7120 1068 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 1069
1a6c43e9 1070 assert(j);
df50185b
LP
1071 assert(mode >= 0);
1072 assert(mode < _OUTPUT_MODE_MAX);
1946b0bd
LP
1073
1074 /* Seek to end */
86aa7ba4
LP
1075 r = sd_journal_seek_tail(j);
1076 if (r < 0)
b56d608e 1077 return log_error_errno(r, "Failed to seek to tail: %m");
86aa7ba4 1078
df50185b
LP
1079 r = sd_journal_previous_skip(j, how_many);
1080 if (r < 0)
b56d608e 1081 return log_error_errno(r, "Failed to skip previous: %m");
86aa7ba4 1082
df50185b
LP
1083 for (;;) {
1084 for (;;) {
1085 usec_t usec;
1086
1087 if (need_seek) {
1088 r = sd_journal_next(j);
1089 if (r < 0)
b56d608e 1090 return log_error_errno(r, "Failed to iterate through journal: %m");
df50185b
LP
1091 }
1092
1093 if (r == 0)
1094 break;
86aa7ba4 1095
df50185b
LP
1096 need_seek = true;
1097
1098 if (not_before > 0) {
1099 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
1100
1101 /* -ESTALE is returned if the
1102 timestamp is not from this boot */
1103 if (r == -ESTALE)
1104 continue;
1105 else if (r < 0)
b56d608e 1106 return log_error_errno(r, "Failed to get journal time: %m");
df50185b
LP
1107
1108 if (usec < not_before)
1109 continue;
1110 }
1111
313cefa1 1112 line++;
ea6c2dd1 1113 maybe_print_begin_newline(f, &flags);
df50185b 1114
cc25a67e 1115 r = output_journal(f, j, mode, n_columns, flags, NULL, ellipsized);
df50185b 1116 if (r < 0)
b56d608e 1117 return r;
df50185b
LP
1118 }
1119
08984293
LP
1120 if (warn_cutoff && line < how_many && not_before > 0) {
1121 sd_id128_t boot_id;
a7f7d1bd 1122 usec_t cutoff = 0;
08984293
LP
1123
1124 /* Check whether the cutoff line is too early */
1125
1126 r = sd_id128_get_boot(&boot_id);
1127 if (r < 0)
b56d608e 1128 return log_error_errno(r, "Failed to get boot id: %m");
08984293
LP
1129
1130 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1131 if (r < 0)
b56d608e 1132 return log_error_errno(r, "Failed to get journal cutoff time: %m");
08984293 1133
ea6c2dd1
LP
1134 if (r > 0 && not_before < cutoff) {
1135 maybe_print_begin_newline(f, &flags);
08ace05b 1136 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
ea6c2dd1 1137 }
08984293
LP
1138
1139 warn_cutoff = false;
1140 }
1141
085d7120 1142 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
1143 break;
1144
3a43da28 1145 r = sd_journal_wait(j, USEC_INFINITY);
df50185b 1146 if (r < 0)
b56d608e 1147 return log_error_errno(r, "Failed to wait for journal: %m");
df50185b 1148
86aa7ba4
LP
1149 }
1150
b56d608e 1151 return 0;
1a6c43e9
MT
1152}
1153
886a64fe 1154int add_matches_for_unit(sd_journal *j, const char *unit) {
2b45d881 1155 const char *m1, *m2, *m3, *m4;
1a6c43e9
MT
1156 int r;
1157
886a64fe 1158 assert(j);
1a6c43e9
MT
1159 assert(unit);
1160
63c372cb
LP
1161 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1162 m2 = strjoina("COREDUMP_UNIT=", unit);
1163 m3 = strjoina("UNIT=", unit);
1164 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1a6c43e9 1165
886a64fe
ZJS
1166 (void)(
1167 /* Look for messages from the service itself */
1168 (r = sd_journal_add_match(j, m1, 0)) ||
1169
1170 /* Look for coredumps of the service */
1171 (r = sd_journal_add_disjunction(j)) ||
fdcd37df
ZJS
1172 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1173 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
886a64fe
ZJS
1174 (r = sd_journal_add_match(j, m2, 0)) ||
1175
1176 /* Look for messages from PID 1 about this service */
1177 (r = sd_journal_add_disjunction(j)) ||
1178 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
2d0b2e87
ZJS
1179 (r = sd_journal_add_match(j, m3, 0)) ||
1180
1181 /* Look for messages from authorized daemons about this service */
1182 (r = sd_journal_add_disjunction(j)) ||
1183 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1184 (r = sd_journal_add_match(j, m4, 0))
886a64fe 1185 );
2d0b2e87 1186
69ae3ee0 1187 if (r == 0 && endswith(unit, ".slice")) {
2b45d881
LP
1188 const char *m5;
1189
1190 m5 = strjoina("_SYSTEMD_SLICE=", unit);
69ae3ee0
ZJS
1191
1192 /* Show all messages belonging to a slice */
1193 (void)(
1194 (r = sd_journal_add_disjunction(j)) ||
1195 (r = sd_journal_add_match(j, m5, 0))
1196 );
1197 }
1198
886a64fe
ZJS
1199 return r;
1200}
1a6c43e9 1201
886a64fe
ZJS
1202int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1203 int r;
2d0b2e87
ZJS
1204 char *m1, *m2, *m3, *m4;
1205 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1a6c43e9 1206
886a64fe
ZJS
1207 assert(j);
1208 assert(unit);
1a6c43e9 1209
63c372cb
LP
1210 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1211 m2 = strjoina("USER_UNIT=", unit);
1212 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1213 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
de0671ee 1214 sprintf(muid, "_UID="UID_FMT, uid);
1a6c43e9 1215
886a64fe
ZJS
1216 (void) (
1217 /* Look for messages from the user service itself */
1218 (r = sd_journal_add_match(j, m1, 0)) ||
2d0b2e87 1219 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1220
1221 /* Look for messages from systemd about this service */
1222 (r = sd_journal_add_disjunction(j)) ||
1223 (r = sd_journal_add_match(j, m2, 0)) ||
2d0b2e87 1224 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1225
1226 /* Look for coredumps of the service */
1227 (r = sd_journal_add_disjunction(j)) ||
1228 (r = sd_journal_add_match(j, m3, 0)) ||
2d0b2e87
ZJS
1229 (r = sd_journal_add_match(j, muid, 0)) ||
1230 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1231
1232 /* Look for messages from authorized daemons about this service */
1233 (r = sd_journal_add_disjunction(j)) ||
fdcd37df 1234 (r = sd_journal_add_match(j, m4, 0)) ||
2d0b2e87 1235 (r = sd_journal_add_match(j, muid, 0)) ||
fdcd37df 1236 (r = sd_journal_add_match(j, "_UID=0", 0))
886a64fe 1237 );
69ae3ee0
ZJS
1238
1239 if (r == 0 && endswith(unit, ".slice")) {
2b45d881
LP
1240 const char *m5;
1241
1242 m5 = strjoina("_SYSTEMD_SLICE=", unit);
69ae3ee0
ZJS
1243
1244 /* Show all messages belonging to a slice */
1245 (void)(
1246 (r = sd_journal_add_disjunction(j)) ||
1247 (r = sd_journal_add_match(j, m5, 0)) ||
1248 (r = sd_journal_add_match(j, muid, 0))
1249 );
1250 }
1251
1a6c43e9
MT
1252 return r;
1253}
1254
b6741478 1255static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
3d94f76c 1256 _cleanup_close_pair_ int pair[2] = { -1, -1 };
a4475f57 1257 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
b6741478
LP
1258 pid_t pid, child;
1259 siginfo_t si;
1260 char buf[37];
1261 ssize_t k;
1262 int r;
1263
1264 assert(machine);
1265 assert(boot_id);
1266
affcf189 1267 if (!machine_name_is_valid(machine))
b6741478
LP
1268 return -EINVAL;
1269
e04b0cdb 1270 r = container_get_leader(machine, &pid);
b6741478
LP
1271 if (r < 0)
1272 return r;
e04b0cdb 1273
671c3419 1274 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
b6741478
LP
1275 if (r < 0)
1276 return r;
1277
e04b0cdb 1278 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
b6741478
LP
1279 return -errno;
1280
1281 child = fork();
1282 if (child < 0)
1283 return -errno;
1284
1285 if (child == 0) {
1286 int fd;
1287
03e334a1 1288 pair[0] = safe_close(pair[0]);
b6741478 1289
671c3419 1290 r = namespace_enter(pidnsfd, mntnsfd, -1, -1, rootfd);
b6741478
LP
1291 if (r < 0)
1292 _exit(EXIT_FAILURE);
1293
1294 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1295 if (fd < 0)
1296 _exit(EXIT_FAILURE);
1297
a6dcc7e5 1298 r = loop_read_exact(fd, buf, 36, false);
03e334a1 1299 safe_close(fd);
6c767d1e 1300 if (r < 0)
b6741478
LP
1301 _exit(EXIT_FAILURE);
1302
e04b0cdb 1303 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
b6741478
LP
1304 if (k != 36)
1305 _exit(EXIT_FAILURE);
1306
1307 _exit(EXIT_SUCCESS);
1308 }
1309
03e334a1 1310 pair[1] = safe_close(pair[1]);
b6741478 1311
b6741478
LP
1312 r = wait_for_terminate(child, &si);
1313 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1314 return r < 0 ? r : -EIO;
1315
fbadf045
LP
1316 k = recv(pair[0], buf, 36, 0);
1317 if (k != 36)
1318 return -EIO;
1319
b6741478
LP
1320 buf[36] = 0;
1321 r = sd_id128_from_string(buf, boot_id);
1322 if (r < 0)
1323 return r;
1324
1325 return 0;
1326}
1327
1328int add_match_this_boot(sd_journal *j, const char *machine) {
5ec76417
ZJS
1329 char match[9+32+1] = "_BOOT_ID=";
1330 sd_id128_t boot_id;
1331 int r;
1332
1333 assert(j);
1334
b6741478
LP
1335 if (machine) {
1336 r = get_boot_id_for_machine(machine, &boot_id);
f647962d
MS
1337 if (r < 0)
1338 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
b6741478
LP
1339 } else {
1340 r = sd_id128_get_boot(&boot_id);
f647962d
MS
1341 if (r < 0)
1342 return log_error_errno(r, "Failed to get boot id: %m");
5ec76417
ZJS
1343 }
1344
1345 sd_id128_to_string(boot_id, match + 9);
1346 r = sd_journal_add_match(j, match, strlen(match));
f647962d
MS
1347 if (r < 0)
1348 return log_error_errno(r, "Failed to add match: %m");
5ec76417
ZJS
1349
1350 r = sd_journal_add_conjunction(j);
1351 if (r < 0)
b56d608e 1352 return log_error_errno(r, "Failed to add conjunction: %m");
5ec76417
ZJS
1353
1354 return 0;
1355}
1356
886a64fe 1357int show_journal_by_unit(
1a6c43e9
MT
1358 FILE *f,
1359 const char *unit,
1360 OutputMode mode,
1361 unsigned n_columns,
1362 usec_t not_before,
1363 unsigned how_many,
1364 uid_t uid,
886a64fe 1365 OutputFlags flags,
3c756001
LP
1366 int journal_open_flags,
1367 bool system_unit,
94e0bd7d 1368 bool *ellipsized) {
1a6c43e9 1369
4afd3348 1370 _cleanup_(sd_journal_closep) sd_journal *j = NULL;
1a6c43e9
MT
1371 int r;
1372
1373 assert(mode >= 0);
1374 assert(mode < _OUTPUT_MODE_MAX);
1375 assert(unit);
1376
1a6c43e9
MT
1377 if (how_many <= 0)
1378 return 0;
1379
3c756001 1380 r = sd_journal_open(&j, journal_open_flags);
f9045468 1381 if (r < 0)
b56d608e 1382 return log_error_errno(r, "Failed to open journal: %m");
f9045468 1383
b6741478 1384 r = add_match_this_boot(j, NULL);
5ec76417
ZJS
1385 if (r < 0)
1386 return r;
1387
3c756001 1388 if (system_unit)
886a64fe
ZJS
1389 r = add_matches_for_unit(j, unit);
1390 else
1391 r = add_matches_for_user_unit(j, unit, uid);
1a6c43e9 1392 if (r < 0)
b56d608e 1393 return log_error_errno(r, "Failed to add unit matches: %m");
1a6c43e9 1394
553d2243 1395 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
1396 _cleanup_free_ char *filter;
1397
1398 filter = journal_make_match_string(j);
b56d608e
LP
1399 if (!filter)
1400 return log_oom();
1401
4ad16808
ZJS
1402 log_debug("Journal filter: %s", filter);
1403 }
5ec76417 1404
94e0bd7d 1405 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
86aa7ba4 1406}