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