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