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