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