]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
treewide: yet 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
da927ba9 861 log_error_errno(r, "Failed to get data: %m");
d3f2bdbf
LP
862 return r;
863 }
864
865 assert(l >= 8);
866
08ace05b
LP
867 fwrite((const char*) data + 8, 1, l - 8, f);
868 fputc('\n', f);
d3f2bdbf
LP
869
870 return 0;
871}
872
08ace05b
LP
873static int (*output_funcs[_OUTPUT_MODE_MAX])(
874 FILE *f,
875 sd_journal*j,
876 OutputMode mode,
877 unsigned n_columns,
878 OutputFlags flags) = {
879
a6e87e90 880 [OUTPUT_SHORT] = output_short,
44bc6e1f 881 [OUTPUT_SHORT_ISO] = output_short,
f02d8367
ZJS
882 [OUTPUT_SHORT_PRECISE] = output_short,
883 [OUTPUT_SHORT_MONOTONIC] = output_short,
86aa7ba4
LP
884 [OUTPUT_VERBOSE] = output_verbose,
885 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 886 [OUTPUT_JSON] = output_json,
a6e87e90 887 [OUTPUT_JSON_PRETTY] = output_json,
48383c25 888 [OUTPUT_JSON_SSE] = output_json,
d3f2bdbf 889 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
890};
891
08ace05b
LP
892int output_journal(
893 FILE *f,
894 sd_journal *j,
895 OutputMode mode,
896 unsigned n_columns,
94e0bd7d
ZJS
897 OutputFlags flags,
898 bool *ellipsized) {
08ace05b 899
e268b81e 900 int ret;
df50185b 901 assert(mode >= 0);
86aa7ba4
LP
902 assert(mode < _OUTPUT_MODE_MAX);
903
34a35ece
LP
904 if (n_columns <= 0)
905 n_columns = columns();
906
08ace05b 907 ret = output_funcs[mode](f, j, mode, n_columns, flags);
e268b81e 908 fflush(stdout);
94e0bd7d
ZJS
909
910 if (ellipsized && ret > 0)
911 *ellipsized = true;
912
e268b81e 913 return ret;
86aa7ba4
LP
914}
915
ea6c2dd1
LP
916static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
917 assert(f);
918 assert(flags);
919
920 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
921 return 0;
922
923 /* Print a beginning new line if that's request, but only once
924 * on the first line we print. */
925
926 fputc('\n', f);
927 *flags &= ~OUTPUT_BEGIN_NEWLINE;
928 return 0;
929}
930
1a6c43e9
MT
931static int show_journal(FILE *f,
932 sd_journal *j,
933 OutputMode mode,
934 unsigned n_columns,
935 usec_t not_before,
936 unsigned how_many,
94e0bd7d
ZJS
937 OutputFlags flags,
938 bool *ellipsized) {
86aa7ba4 939
86aa7ba4 940 int r;
df50185b
LP
941 unsigned line = 0;
942 bool need_seek = false;
085d7120 943 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 944
1a6c43e9 945 assert(j);
df50185b
LP
946 assert(mode >= 0);
947 assert(mode < _OUTPUT_MODE_MAX);
1946b0bd
LP
948
949 /* Seek to end */
86aa7ba4
LP
950 r = sd_journal_seek_tail(j);
951 if (r < 0)
952 goto finish;
953
df50185b
LP
954 r = sd_journal_previous_skip(j, how_many);
955 if (r < 0)
956 goto finish;
86aa7ba4 957
df50185b
LP
958 for (;;) {
959 for (;;) {
960 usec_t usec;
961
962 if (need_seek) {
963 r = sd_journal_next(j);
964 if (r < 0)
965 goto finish;
966 }
967
968 if (r == 0)
969 break;
86aa7ba4 970
df50185b
LP
971 need_seek = true;
972
973 if (not_before > 0) {
974 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
975
976 /* -ESTALE is returned if the
977 timestamp is not from this boot */
978 if (r == -ESTALE)
979 continue;
980 else if (r < 0)
981 goto finish;
982
983 if (usec < not_before)
984 continue;
985 }
986
987 line ++;
ea6c2dd1 988 maybe_print_begin_newline(f, &flags);
df50185b 989
94e0bd7d 990 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
df50185b
LP
991 if (r < 0)
992 goto finish;
993 }
994
08984293
LP
995 if (warn_cutoff && line < how_many && not_before > 0) {
996 sd_id128_t boot_id;
997 usec_t cutoff;
998
999 /* Check whether the cutoff line is too early */
1000
1001 r = sd_id128_get_boot(&boot_id);
1002 if (r < 0)
1003 goto finish;
1004
1005 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1006 if (r < 0)
1007 goto finish;
1008
ea6c2dd1
LP
1009 if (r > 0 && not_before < cutoff) {
1010 maybe_print_begin_newline(f, &flags);
08ace05b 1011 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
ea6c2dd1 1012 }
08984293
LP
1013
1014 warn_cutoff = false;
1015 }
1016
085d7120 1017 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
1018 break;
1019
3a43da28 1020 r = sd_journal_wait(j, USEC_INFINITY);
df50185b
LP
1021 if (r < 0)
1022 goto finish;
1023
86aa7ba4
LP
1024 }
1025
1a6c43e9
MT
1026finish:
1027 return r;
1028}
1029
886a64fe 1030int add_matches_for_unit(sd_journal *j, const char *unit) {
1a6c43e9 1031 int r;
2d0b2e87 1032 char *m1, *m2, *m3, *m4;
1a6c43e9 1033
886a64fe 1034 assert(j);
1a6c43e9
MT
1035 assert(unit);
1036
2d0b2e87
ZJS
1037 m1 = strappenda("_SYSTEMD_UNIT=", unit);
1038 m2 = strappenda("COREDUMP_UNIT=", unit);
1039 m3 = strappenda("UNIT=", unit);
1040 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
1a6c43e9 1041
886a64fe
ZJS
1042 (void)(
1043 /* Look for messages from the service itself */
1044 (r = sd_journal_add_match(j, m1, 0)) ||
1045
1046 /* Look for coredumps of the service */
1047 (r = sd_journal_add_disjunction(j)) ||
fdcd37df
ZJS
1048 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1049 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
886a64fe
ZJS
1050 (r = sd_journal_add_match(j, m2, 0)) ||
1051
1052 /* Look for messages from PID 1 about this service */
1053 (r = sd_journal_add_disjunction(j)) ||
1054 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
2d0b2e87
ZJS
1055 (r = sd_journal_add_match(j, m3, 0)) ||
1056
1057 /* Look for messages from authorized daemons about this service */
1058 (r = sd_journal_add_disjunction(j)) ||
1059 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1060 (r = sd_journal_add_match(j, m4, 0))
886a64fe 1061 );
2d0b2e87 1062
69ae3ee0
ZJS
1063 if (r == 0 && endswith(unit, ".slice")) {
1064 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1065
1066 /* Show all messages belonging to a slice */
1067 (void)(
1068 (r = sd_journal_add_disjunction(j)) ||
1069 (r = sd_journal_add_match(j, m5, 0))
1070 );
1071 }
1072
886a64fe
ZJS
1073 return r;
1074}
1a6c43e9 1075
886a64fe
ZJS
1076int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1077 int r;
2d0b2e87
ZJS
1078 char *m1, *m2, *m3, *m4;
1079 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1a6c43e9 1080
886a64fe
ZJS
1081 assert(j);
1082 assert(unit);
1a6c43e9 1083
2d0b2e87
ZJS
1084 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
1085 m2 = strappenda("USER_UNIT=", unit);
1086 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
1087 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
de0671ee 1088 sprintf(muid, "_UID="UID_FMT, uid);
1a6c43e9 1089
886a64fe
ZJS
1090 (void) (
1091 /* Look for messages from the user service itself */
1092 (r = sd_journal_add_match(j, m1, 0)) ||
2d0b2e87 1093 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1094
1095 /* Look for messages from systemd about this service */
1096 (r = sd_journal_add_disjunction(j)) ||
1097 (r = sd_journal_add_match(j, m2, 0)) ||
2d0b2e87 1098 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1099
1100 /* Look for coredumps of the service */
1101 (r = sd_journal_add_disjunction(j)) ||
1102 (r = sd_journal_add_match(j, m3, 0)) ||
2d0b2e87
ZJS
1103 (r = sd_journal_add_match(j, muid, 0)) ||
1104 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1105
1106 /* Look for messages from authorized daemons about this service */
1107 (r = sd_journal_add_disjunction(j)) ||
fdcd37df 1108 (r = sd_journal_add_match(j, m4, 0)) ||
2d0b2e87 1109 (r = sd_journal_add_match(j, muid, 0)) ||
fdcd37df 1110 (r = sd_journal_add_match(j, "_UID=0", 0))
886a64fe 1111 );
69ae3ee0
ZJS
1112
1113 if (r == 0 && endswith(unit, ".slice")) {
1114 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1115
1116 /* Show all messages belonging to a slice */
1117 (void)(
1118 (r = sd_journal_add_disjunction(j)) ||
1119 (r = sd_journal_add_match(j, m5, 0)) ||
1120 (r = sd_journal_add_match(j, muid, 0))
1121 );
1122 }
1123
1a6c43e9
MT
1124 return r;
1125}
1126
b6741478 1127static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
3d94f76c 1128 _cleanup_close_pair_ int pair[2] = { -1, -1 };
a4475f57 1129 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
b6741478
LP
1130 pid_t pid, child;
1131 siginfo_t si;
1132 char buf[37];
1133 ssize_t k;
1134 int r;
1135
1136 assert(machine);
1137 assert(boot_id);
1138
affcf189 1139 if (!machine_name_is_valid(machine))
b6741478
LP
1140 return -EINVAL;
1141
e04b0cdb 1142 r = container_get_leader(machine, &pid);
b6741478
LP
1143 if (r < 0)
1144 return r;
e04b0cdb 1145
878cd7e9 1146 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
b6741478
LP
1147 if (r < 0)
1148 return r;
1149
e04b0cdb 1150 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
b6741478
LP
1151 return -errno;
1152
1153 child = fork();
1154 if (child < 0)
1155 return -errno;
1156
1157 if (child == 0) {
1158 int fd;
1159
03e334a1 1160 pair[0] = safe_close(pair[0]);
b6741478 1161
878cd7e9 1162 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
b6741478
LP
1163 if (r < 0)
1164 _exit(EXIT_FAILURE);
1165
1166 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1167 if (fd < 0)
1168 _exit(EXIT_FAILURE);
1169
1170 k = loop_read(fd, buf, 36, false);
03e334a1 1171 safe_close(fd);
b6741478
LP
1172 if (k != 36)
1173 _exit(EXIT_FAILURE);
1174
e04b0cdb 1175 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
b6741478
LP
1176 if (k != 36)
1177 _exit(EXIT_FAILURE);
1178
1179 _exit(EXIT_SUCCESS);
1180 }
1181
03e334a1 1182 pair[1] = safe_close(pair[1]);
b6741478 1183
b6741478
LP
1184 r = wait_for_terminate(child, &si);
1185 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1186 return r < 0 ? r : -EIO;
1187
fbadf045
LP
1188 k = recv(pair[0], buf, 36, 0);
1189 if (k != 36)
1190 return -EIO;
1191
b6741478
LP
1192 buf[36] = 0;
1193 r = sd_id128_from_string(buf, boot_id);
1194 if (r < 0)
1195 return r;
1196
1197 return 0;
1198}
1199
1200int add_match_this_boot(sd_journal *j, const char *machine) {
5ec76417
ZJS
1201 char match[9+32+1] = "_BOOT_ID=";
1202 sd_id128_t boot_id;
1203 int r;
1204
1205 assert(j);
1206
b6741478
LP
1207 if (machine) {
1208 r = get_boot_id_for_machine(machine, &boot_id);
f647962d
MS
1209 if (r < 0)
1210 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
b6741478
LP
1211 } else {
1212 r = sd_id128_get_boot(&boot_id);
f647962d
MS
1213 if (r < 0)
1214 return log_error_errno(r, "Failed to get boot id: %m");
5ec76417
ZJS
1215 }
1216
1217 sd_id128_to_string(boot_id, match + 9);
1218 r = sd_journal_add_match(j, match, strlen(match));
f647962d
MS
1219 if (r < 0)
1220 return log_error_errno(r, "Failed to add match: %m");
5ec76417
ZJS
1221
1222 r = sd_journal_add_conjunction(j);
1223 if (r < 0)
1224 return r;
1225
1226 return 0;
1227}
1228
886a64fe 1229int show_journal_by_unit(
1a6c43e9
MT
1230 FILE *f,
1231 const char *unit,
1232 OutputMode mode,
1233 unsigned n_columns,
1234 usec_t not_before,
1235 unsigned how_many,
1236 uid_t uid,
886a64fe 1237 OutputFlags flags,
94e0bd7d
ZJS
1238 bool system,
1239 bool *ellipsized) {
1a6c43e9 1240
7fd1b19b 1241 _cleanup_journal_close_ sd_journal*j = NULL;
1a6c43e9 1242 int r;
a688baa8 1243 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1a6c43e9
MT
1244
1245 assert(mode >= 0);
1246 assert(mode < _OUTPUT_MODE_MAX);
1247 assert(unit);
1248
1a6c43e9
MT
1249 if (how_many <= 0)
1250 return 0;
1251
886a64fe 1252 r = sd_journal_open(&j, jflags);
f9045468 1253 if (r < 0)
763c7aa2 1254 return r;
f9045468 1255
b6741478 1256 r = add_match_this_boot(j, NULL);
5ec76417
ZJS
1257 if (r < 0)
1258 return r;
1259
886a64fe
ZJS
1260 if (system)
1261 r = add_matches_for_unit(j, unit);
1262 else
1263 r = add_matches_for_user_unit(j, unit, uid);
1a6c43e9 1264 if (r < 0)
763c7aa2 1265 return r;
1a6c43e9 1266
4ad16808
ZJS
1267 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1268 _cleanup_free_ char *filter;
1269
1270 filter = journal_make_match_string(j);
1271 log_debug("Journal filter: %s", filter);
1272 }
5ec76417 1273
94e0bd7d 1274 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
86aa7ba4 1275}
df50185b
LP
1276
1277static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1278 [OUTPUT_SHORT] = "short",
44bc6e1f 1279 [OUTPUT_SHORT_ISO] = "short-iso",
f02d8367
ZJS
1280 [OUTPUT_SHORT_PRECISE] = "short-precise",
1281 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
df50185b
LP
1282 [OUTPUT_VERBOSE] = "verbose",
1283 [OUTPUT_EXPORT] = "export",
d3f2bdbf 1284 [OUTPUT_JSON] = "json",
a6e87e90 1285 [OUTPUT_JSON_PRETTY] = "json-pretty",
48383c25 1286 [OUTPUT_JSON_SSE] = "json-sse",
d3f2bdbf 1287 [OUTPUT_CAT] = "cat"
df50185b
LP
1288};
1289
1290DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);