]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
util-lib: split out IO related calls to io-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
86aa7ba4 22#include <errno.h>
b6741478 23#include <fcntl.h>
07630cea
LP
24#include <string.h>
25#include <sys/socket.h>
26#include <time.h>
86aa7ba4 27
3ffd4af2 28#include "fd-util.h"
07630cea 29#include "formats-util.h"
d99ae53a 30#include "hashmap.h"
07630cea 31#include "hostname-util.h"
c004493c 32#include "io-util.h"
dfb33a97 33#include "journal-internal.h"
07630cea 34#include "log.h"
3ffd4af2 35#include "logs-show.h"
0b452006 36#include "process-util.h"
07630cea 37#include "string-util.h"
288a74cc 38#include "terminal-util.h"
07630cea
LP
39#include "utf8.h"
40#include "util.h"
86aa7ba4 41
07630cea 42/* up to three lines (each up to 100 characters) or 300 characters, whichever is less */
a6f0104a
ZJS
43#define PRINT_LINE_THRESHOLD 3
44#define PRINT_CHAR_THRESHOLD 300
45
08ace05b 46#define JSON_THRESHOLD 4096
86aa7ba4 47
d4205751
LP
48static int print_catalog(FILE *f, sd_journal *j) {
49 int r;
50 _cleanup_free_ char *t = NULL, *z = NULL;
51
52
53 r = sd_journal_get_catalog(j, &t);
54 if (r < 0)
55 return r;
56
57 z = strreplace(strstrip(t), "\n", "\n-- ");
58 if (!z)
59 return log_oom();
60
61 fputs("-- ", f);
62 fputs(z, f);
63 fputc('\n', f);
64
65 return 0;
66}
67
55d7bfc1
LP
68static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
69 size_t fl, nl;
70 void *buf;
71
72 assert(data);
73 assert(field);
74 assert(target);
75 assert(target_size);
76
77 fl = strlen(field);
78 if (length < fl)
79 return 0;
80
81 if (memcmp(data, field, fl))
82 return 0;
83
84 nl = length - fl;
bf967366 85 buf = malloc(nl+1);
0d0f0c50
SL
86 if (!buf)
87 return log_oom();
55d7bfc1 88
46b0d922
LP
89 memcpy(buf, (const char*) data + fl, nl);
90 ((char*)buf)[nl] = 0;
91
6c1e6b98 92 free(*target);
55d7bfc1
LP
93 *target = buf;
94 *target_size = nl;
95
96 return 1;
97}
98
08ace05b
LP
99static bool shall_print(const char *p, size_t l, OutputFlags flags) {
100 assert(p);
101
102 if (flags & OUTPUT_SHOW_ALL)
55d7bfc1
LP
103 return true;
104
a6f0104a 105 if (l >= PRINT_CHAR_THRESHOLD)
55d7bfc1
LP
106 return false;
107
31f7bf19 108 if (!utf8_is_printable(p, l))
55d7bfc1
LP
109 return false;
110
111 return true;
112}
113
00f117a5 114static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
31f7bf19
ZJS
115 const char *color_on = "", *color_off = "";
116 const char *pos, *end;
94e0bd7d 117 bool ellipsized = false;
a6f0104a 118 int line = 0;
31f7bf19
ZJS
119
120 if (flags & OUTPUT_COLOR) {
121 if (priority <= LOG_ERR) {
1fc464f6
LP
122 color_on = ANSI_HIGHLIGHT_RED;
123 color_off = ANSI_NORMAL;
31f7bf19 124 } else if (priority <= LOG_NOTICE) {
1fc464f6
LP
125 color_on = ANSI_HIGHLIGHT;
126 color_off = ANSI_NORMAL;
31f7bf19
ZJS
127 }
128 }
129
47d80904
UU
130 /* A special case: make sure that we print a newline when
131 the message is empty. */
132 if (message_len == 0)
133 fputs("\n", f);
134
a6f0104a
ZJS
135 for (pos = message;
136 pos < message + message_len;
137 pos = end + 1, line++) {
138 bool continuation = line > 0;
139 bool tail_line;
31f7bf19
ZJS
140 int len;
141 for (end = pos; end < message + message_len && *end != '\n'; end++)
142 ;
143 len = end - pos;
144 assert(len >= 0);
145
2526d626 146 /* We need to figure out when we are showing not-last line, *and*
a6f0104a
ZJS
147 * will skip subsequent lines. In that case, we will put the dots
148 * at the end of the line, instead of putting dots in the middle
149 * or not at all.
150 */
151 tail_line =
152 line + 1 == PRINT_LINE_THRESHOLD ||
2526d626 153 end + 1 >= message + PRINT_CHAR_THRESHOLD;
a6f0104a
ZJS
154
155 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
156 (prefix + len + 1 < n_columns && !tail_line)) {
31f7bf19
ZJS
157 fprintf(f, "%*s%s%.*s%s\n",
158 continuation * prefix, "",
159 color_on, len, pos, color_off);
a6f0104a
ZJS
160 continue;
161 }
31f7bf19 162
a6f0104a
ZJS
163 /* Beyond this point, ellipsization will happen. */
164 ellipsized = true;
31f7bf19 165
a6f0104a
ZJS
166 if (prefix < n_columns && n_columns - prefix >= 3) {
167 if (n_columns - prefix > (unsigned) len + 3)
168 fprintf(f, "%*s%s%.*s...%s\n",
b4b02cbe
ZJS
169 continuation * prefix, "",
170 color_on, len, pos, color_off);
a6f0104a
ZJS
171 else {
172 _cleanup_free_ char *e;
173
174 e = ellipsize_mem(pos, len, n_columns - prefix,
175 tail_line ? 100 : 90);
176 if (!e)
177 fprintf(f, "%*s%s%.*s%s\n",
178 continuation * prefix, "",
179 color_on, len, pos, color_off);
180 else
181 fprintf(f, "%*s%s%s%s\n",
182 continuation * prefix, "",
183 color_on, e, color_off);
184 }
185 } else
31f7bf19
ZJS
186 fputs("...\n", f);
187
a6f0104a
ZJS
188 if (tail_line)
189 break;
31f7bf19 190 }
94e0bd7d
ZJS
191
192 return ellipsized;
31f7bf19
ZJS
193}
194
08ace05b
LP
195static int output_short(
196 FILE *f,
197 sd_journal *j,
198 OutputMode mode,
199 unsigned n_columns,
200 OutputFlags flags) {
201
86aa7ba4 202 int r;
86aa7ba4
LP
203 const void *data;
204 size_t length;
205 size_t n = 0;
08ace05b 206 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
49826187
LP
207 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;
208 int p = LOG_INFO;
94e0bd7d 209 bool ellipsized = false;
86aa7ba4 210
08ace05b 211 assert(f);
86aa7ba4
LP
212 assert(j);
213
a6f0104a 214 /* Set the threshold to one bigger than the actual print
69ab8088 215 * threshold, so that if the line is actually longer than what
a6f0104a
ZJS
216 * we're willing to print, ellipsization will occur. This way
217 * we won't output a misleading line without any indication of
218 * truncation.
219 */
220 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
93b73b06 221
a72b6353 222 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
55d7bfc1 223
49826187
LP
224 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
225 if (r < 0)
08ace05b 226 return r;
49826187
LP
227 else if (r > 0)
228 continue;
229
55d7bfc1
LP
230 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
231 if (r < 0)
08ace05b 232 return r;
55d7bfc1
LP
233 else if (r > 0)
234 continue;
235
4cd9a9d9 236 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
55d7bfc1 237 if (r < 0)
08ace05b 238 return r;
55d7bfc1
LP
239 else if (r > 0)
240 continue;
241
242 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
243 if (r < 0)
08ace05b 244 return r;
55d7bfc1
LP
245 else if (r > 0)
246 continue;
247
248 r = parse_field(data, length, "_PID=", &pid, &pid_len);
249 if (r < 0)
08ace05b 250 return r;
55d7bfc1
LP
251 else if (r > 0)
252 continue;
253
6c1e6b98
LP
254 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
255 if (r < 0)
08ace05b 256 return r;
6c1e6b98
LP
257 else if (r > 0)
258 continue;
259
bf967366
LP
260 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
261 if (r < 0)
08ace05b 262 return r;
bf967366
LP
263 else if (r > 0)
264 continue;
265
266 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
267 if (r < 0)
08ace05b 268 return r;
bf967366
LP
269 else if (r > 0)
270 continue;
271
55d7bfc1
LP
272 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
273 if (r < 0)
08ace05b 274 return r;
55d7bfc1
LP
275 }
276
a72b6353 277 if (r < 0)
b56d608e 278 return log_error_errno(r, "Failed to get journal fields: %m");
a72b6353 279
07d21025
LP
280 if (!message) {
281 log_debug("Skipping message without MESSAGE= field.");
08ace05b 282 return 0;
07d21025 283 }
55d7bfc1 284
e8bc0ea2
LP
285 if (!(flags & OUTPUT_SHOW_ALL))
286 strip_tab_ansi(&message, &message_len);
287
49826187
LP
288 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
289 p = *priority - '0';
290
a6e87e90 291 if (mode == OUTPUT_SHORT_MONOTONIC) {
67a12205 292 uint64_t t;
3ebcdf8c
LP
293 sd_id128_t boot_id;
294
bf967366
LP
295 r = -ENOENT;
296
297 if (monotonic)
298 r = safe_atou64(monotonic, &t);
299
300 if (r < 0)
3ebcdf8c 301 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
86aa7ba4 302
f647962d
MS
303 if (r < 0)
304 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
67a12205 305
08ace05b 306 fprintf(f, "[%5llu.%06llu]",
609e002e
LP
307 (unsigned long long) (t / USEC_PER_SEC),
308 (unsigned long long) (t % USEC_PER_SEC));
3ebcdf8c
LP
309
310 n += 1 + 5 + 1 + 6 + 1;
311
67a12205
LP
312 } else {
313 char buf[64];
bf967366 314 uint64_t x;
67a12205
LP
315 time_t t;
316 struct tm tm;
9fd29044 317 struct tm *(*gettime_r)(const time_t *, struct tm *);
731a676c 318
bf967366 319 r = -ENOENT;
9fd29044 320 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
bf967366
LP
321
322 if (realtime)
323 r = safe_atou64(realtime, &x);
324
325 if (r < 0)
326 r = sd_journal_get_realtime_usec(j, &x);
67a12205 327
f647962d
MS
328 if (r < 0)
329 return log_error_errno(r, "Failed to get realtime timestamp: %m");
67a12205 330
bf967366 331 t = (time_t) (x / USEC_PER_SEC);
f02d8367
ZJS
332
333 switch(mode) {
334 case OUTPUT_SHORT_ISO:
9fd29044 335 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
f02d8367
ZJS
336 break;
337 case OUTPUT_SHORT_PRECISE:
9fd29044 338 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
ece174c5 339 if (r > 0)
f02d8367 340 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
609e002e 341 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
f02d8367
ZJS
342 break;
343 default:
9fd29044 344 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
f02d8367 345 }
44bc6e1f
TT
346
347 if (r <= 0) {
67a12205 348 log_error("Failed to format time.");
44bc6e1f 349 return -EINVAL;
67a12205
LP
350 }
351
08ace05b 352 fputs(buf, f);
67a12205
LP
353 n += strlen(buf);
354 }
86aa7ba4 355
08ace05b
LP
356 if (hostname && shall_print(hostname, hostname_len, flags)) {
357 fprintf(f, " %.*s", (int) hostname_len, hostname);
55d7bfc1
LP
358 n += hostname_len + 1;
359 }
360
08ace05b
LP
361 if (identifier && shall_print(identifier, identifier_len, flags)) {
362 fprintf(f, " %.*s", (int) identifier_len, identifier);
4cd9a9d9 363 n += identifier_len + 1;
08ace05b
LP
364 } else if (comm && shall_print(comm, comm_len, flags)) {
365 fprintf(f, " %.*s", (int) comm_len, comm);
55d7bfc1 366 n += comm_len + 1;
b5936820 367 } else
1248e840 368 fputs(" unknown", f);
86aa7ba4 369
08ace05b
LP
370 if (pid && shall_print(pid, pid_len, flags)) {
371 fprintf(f, "[%.*s]", (int) pid_len, pid);
55d7bfc1 372 n += pid_len + 2;
08ace05b
LP
373 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
374 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
6c1e6b98 375 n += fake_pid_len + 2;
86aa7ba4
LP
376 }
377
31f7bf19 378 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
e6acda19 379 char bytes[FORMAT_BYTES_MAX];
08ace05b 380 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
31f7bf19
ZJS
381 } else {
382 fputs(": ", f);
94e0bd7d
ZJS
383 ellipsized |=
384 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
31f7bf19 385 }
55d7bfc1 386
d4205751
LP
387 if (flags & OUTPUT_CATALOG)
388 print_catalog(f, j);
389
94e0bd7d 390 return ellipsized;
86aa7ba4
LP
391}
392
08ace05b
LP
393static int output_verbose(
394 FILE *f,
395 sd_journal *j,
396 OutputMode mode,
397 unsigned n_columns,
398 OutputFlags flags) {
399
86aa7ba4
LP
400 const void *data;
401 size_t length;
7fd1b19b 402 _cleanup_free_ char *cursor = NULL;
86aa7ba4 403 uint64_t realtime;
f02d8367 404 char ts[FORMAT_TIMESTAMP_MAX + 7];
86aa7ba4
LP
405 int r;
406
08ace05b 407 assert(f);
86aa7ba4
LP
408 assert(j);
409
93b73b06
LP
410 sd_journal_set_data_threshold(j, 0);
411
cf40f0be
ZJS
412 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
413 if (r == -ENOENT)
414 log_debug("Source realtime timestamp not found");
b56d608e
LP
415 else if (r < 0)
416 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
417 else {
cf40f0be
ZJS
418 _cleanup_free_ char *value = NULL;
419 size_t size;
420
421 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
422 if (r < 0)
da927ba9 423 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
cf40f0be
ZJS
424 else {
425 r = safe_atou64(value, &realtime);
426 if (r < 0)
c33b3297 427 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
cf40f0be
ZJS
428 }
429 }
430
431 if (r < 0) {
432 r = sd_journal_get_realtime_usec(j, &realtime);
b56d608e
LP
433 if (r < 0)
434 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
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 459 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
1fc464f6
LP
460 on = ANSI_HIGHLIGHT;
461 off = ANSI_NORMAL;
7ac4fa7e
ZJS
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 fputs("null", f);
581
31f7bf19 582 else if (!utf8_is_printable(p, l)) {
86aa7ba4
LP
583 bool not_first = false;
584
08ace05b 585 fputs("[ ", f);
86aa7ba4
LP
586
587 while (l > 0) {
588 if (not_first)
08ace05b 589 fprintf(f, ", %u", (uint8_t) *p);
86aa7ba4
LP
590 else {
591 not_first = true;
08ace05b 592 fprintf(f, "%u", (uint8_t) *p);
86aa7ba4
LP
593 }
594
595 p++;
596 l--;
597 }
598
08ace05b 599 fputs(" ]", f);
86aa7ba4 600 } else {
08ace05b 601 fputc('\"', f);
86aa7ba4
LP
602
603 while (l > 0) {
604 if (*p == '"' || *p == '\\') {
08ace05b
LP
605 fputc('\\', f);
606 fputc(*p, f);
31f7bf19
ZJS
607 } else if (*p == '\n')
608 fputs("\\n", f);
91a8a108
DM
609 else if ((uint8_t) *p < ' ')
610 fprintf(f, "\\u%04x", (uint8_t) *p);
08ace05b
LP
611 else
612 fputc(*p, f);
86aa7ba4
LP
613
614 p++;
615 l--;
616 }
617
08ace05b 618 fputc('\"', f);
86aa7ba4
LP
619 }
620}
621
08ace05b
LP
622static int output_json(
623 FILE *f,
624 sd_journal *j,
625 OutputMode mode,
626 unsigned n_columns,
627 OutputFlags flags) {
628
86aa7ba4 629 uint64_t realtime, monotonic;
7fd1b19b 630 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
631 const void *data;
632 size_t length;
633 sd_id128_t boot_id;
2e729834 634 char sid[33], *k;
86aa7ba4 635 int r;
d99ae53a
LP
636 Hashmap *h = NULL;
637 bool done, separator;
86aa7ba4
LP
638
639 assert(j);
640
93b73b06
LP
641 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
642
86aa7ba4 643 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
644 if (r < 0)
645 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
646
647 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
648 if (r < 0)
649 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
650
651 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
652 if (r < 0)
653 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 654
a6e87e90 655 if (mode == OUTPUT_JSON_PRETTY)
08ace05b
LP
656 fprintf(f,
657 "{\n"
658 "\t\"__CURSOR\" : \"%s\",\n"
de0671ee
ZJS
659 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
660 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
08ace05b
LP
661 "\t\"_BOOT_ID\" : \"%s\"",
662 cursor,
de0671ee
ZJS
663 realtime,
664 monotonic,
08ace05b 665 sd_id128_to_string(boot_id, sid));
48383c25
LP
666 else {
667 if (mode == OUTPUT_JSON_SSE)
668 fputs("data: ", f);
669
08ace05b
LP
670 fprintf(f,
671 "{ \"__CURSOR\" : \"%s\", "
de0671ee
ZJS
672 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
673 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
08ace05b
LP
674 "\"_BOOT_ID\" : \"%s\"",
675 cursor,
de0671ee
ZJS
676 realtime,
677 monotonic,
08ace05b 678 sd_id128_to_string(boot_id, sid));
48383c25 679 }
86aa7ba4 680
d5099efc 681 h = hashmap_new(&string_hash_ops);
d99ae53a 682 if (!h)
b56d608e 683 return log_oom();
d99ae53a
LP
684
685 /* First round, iterate through the entry and count how often each field appears */
a72b6353 686 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
d99ae53a
LP
687 const char *eq;
688 char *n;
689 unsigned u;
86aa7ba4 690
112301ae
LP
691 if (length >= 9 &&
692 memcmp(data, "_BOOT_ID=", 9) == 0)
693 continue;
694
d99ae53a
LP
695 eq = memchr(data, '=', length);
696 if (!eq)
697 continue;
86aa7ba4 698
d99ae53a
LP
699 n = strndup(data, eq - (const char*) data);
700 if (!n) {
b56d608e 701 r = log_oom();
d99ae53a
LP
702 goto finish;
703 }
a6e87e90 704
d99ae53a
LP
705 u = PTR_TO_UINT(hashmap_get(h, n));
706 if (u == 0) {
707 r = hashmap_put(h, n, UINT_TO_PTR(1));
708 if (r < 0) {
709 free(n);
b56d608e 710 log_oom();
d99ae53a
LP
711 goto finish;
712 }
713 } else {
714 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
715 free(n);
b56d608e
LP
716 if (r < 0) {
717 log_oom();
d99ae53a 718 goto finish;
b56d608e 719 }
d99ae53a 720 }
86aa7ba4
LP
721 }
722
a72b6353
ZJS
723 if (r < 0)
724 return r;
725
d99ae53a
LP
726 separator = true;
727 do {
728 done = true;
729
730 SD_JOURNAL_FOREACH_DATA(j, data, length) {
731 const char *eq;
732 char *kk, *n;
733 size_t m;
734 unsigned u;
735
736 /* We already printed the boot id, from the data in
737 * the header, hence let's suppress it here */
738 if (length >= 9 &&
739 memcmp(data, "_BOOT_ID=", 9) == 0)
740 continue;
741
742 eq = memchr(data, '=', length);
743 if (!eq)
744 continue;
745
746 if (separator) {
747 if (mode == OUTPUT_JSON_PRETTY)
748 fputs(",\n\t", f);
749 else
750 fputs(", ", f);
751 }
752
753 m = eq - (const char*) data;
754
755 n = strndup(data, m);
756 if (!n) {
b56d608e 757 r = log_oom();
d99ae53a
LP
758 goto finish;
759 }
760
761 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
762 if (u == 0) {
763 /* We already printed this, let's jump to the next */
764 free(n);
765 separator = false;
766
767 continue;
768 } else if (u == 1) {
769 /* Field only appears once, output it directly */
770
771 json_escape(f, data, m, flags);
772 fputs(" : ", f);
773
774 json_escape(f, eq + 1, length - m - 1, flags);
775
776 hashmap_remove(h, n);
777 free(kk);
778 free(n);
779
780 separator = true;
781
782 continue;
783
784 } else {
785 /* Field appears multiple times, output it as array */
786 json_escape(f, data, m, flags);
787 fputs(" : [ ", f);
788 json_escape(f, eq + 1, length - m - 1, flags);
789
790 /* Iterate through the end of the list */
791
792 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
793 if (length < m + 1)
794 continue;
795
796 if (memcmp(data, n, m) != 0)
797 continue;
798
799 if (((const char*) data)[m] != '=')
800 continue;
801
802 fputs(", ", f);
803 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
804 }
805
806 fputs(" ]", f);
807
808 hashmap_remove(h, n);
809 free(kk);
810 free(n);
811
812 /* Iterate data fields form the beginning */
813 done = false;
814 separator = true;
815
816 break;
817 }
818 }
819
820 } while (!done);
821
a6e87e90 822 if (mode == OUTPUT_JSON_PRETTY)
08ace05b 823 fputs("\n}\n", f);
48383c25
LP
824 else if (mode == OUTPUT_JSON_SSE)
825 fputs("}\n\n", f);
a6e87e90 826 else
08ace05b 827 fputs(" }\n", f);
86aa7ba4 828
d99ae53a
LP
829 r = 0;
830
831finish:
832 while ((k = hashmap_steal_first_key(h)))
833 free(k);
834
835 hashmap_free(h);
836
837 return r;
86aa7ba4
LP
838}
839
08ace05b
LP
840static int output_cat(
841 FILE *f,
842 sd_journal *j,
843 OutputMode mode,
844 unsigned n_columns,
845 OutputFlags flags) {
846
d3f2bdbf
LP
847 const void *data;
848 size_t l;
849 int r;
850
851 assert(j);
08ace05b 852 assert(f);
d3f2bdbf 853
93b73b06
LP
854 sd_journal_set_data_threshold(j, 0);
855
d3f2bdbf
LP
856 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
857 if (r < 0) {
c198300f
LP
858 /* An entry without MESSAGE=? */
859 if (r == -ENOENT)
860 return 0;
861
8d3d7072 862 return log_error_errno(r, "Failed to get data: %m");
d3f2bdbf
LP
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)
b56d608e 952 return log_error_errno(r, "Failed to seek to tail: %m");
86aa7ba4 953
df50185b
LP
954 r = sd_journal_previous_skip(j, how_many);
955 if (r < 0)
b56d608e 956 return log_error_errno(r, "Failed to skip previous: %m");
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)
b56d608e 965 return log_error_errno(r, "Failed to iterate through journal: %m");
df50185b
LP
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)
b56d608e 981 return log_error_errno(r, "Failed to get journal time: %m");
df50185b
LP
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 991 if (r < 0)
b56d608e 992 return r;
df50185b
LP
993 }
994
08984293
LP
995 if (warn_cutoff && line < how_many && not_before > 0) {
996 sd_id128_t boot_id;
a7f7d1bd 997 usec_t cutoff = 0;
08984293
LP
998
999 /* Check whether the cutoff line is too early */
1000
1001 r = sd_id128_get_boot(&boot_id);
1002 if (r < 0)
b56d608e 1003 return log_error_errno(r, "Failed to get boot id: %m");
08984293
LP
1004
1005 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1006 if (r < 0)
b56d608e 1007 return log_error_errno(r, "Failed to get journal cutoff time: %m");
08984293 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 1021 if (r < 0)
b56d608e 1022 return log_error_errno(r, "Failed to wait for journal: %m");
df50185b 1023
86aa7ba4
LP
1024 }
1025
b56d608e 1026 return 0;
1a6c43e9
MT
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
63c372cb
LP
1036 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1037 m2 = strjoina("COREDUMP_UNIT=", unit);
1038 m3 = strjoina("UNIT=", unit);
1039 m4 = strjoina("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
63c372cb
LP
1083 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1084 m2 = strjoina("USER_UNIT=", unit);
1085 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1086 m4 = strjoina("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
671c3419 1145 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, 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
671c3419 1161 r = namespace_enter(pidnsfd, mntnsfd, -1, -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
a6dcc7e5 1169 r = loop_read_exact(fd, buf, 36, false);
03e334a1 1170 safe_close(fd);
6c767d1e 1171 if (r < 0)
b6741478
LP
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)
b56d608e 1223 return log_error_errno(r, "Failed to add conjunction: %m");
5ec76417
ZJS
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,
3c756001
LP
1237 int journal_open_flags,
1238 bool system_unit,
94e0bd7d 1239 bool *ellipsized) {
1a6c43e9 1240
7fd1b19b 1241 _cleanup_journal_close_ sd_journal*j = NULL;
1a6c43e9
MT
1242 int r;
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
3c756001 1251 r = sd_journal_open(&j, journal_open_flags);
f9045468 1252 if (r < 0)
b56d608e 1253 return log_error_errno(r, "Failed to open journal: %m");
f9045468 1254
b6741478 1255 r = add_match_this_boot(j, NULL);
5ec76417
ZJS
1256 if (r < 0)
1257 return r;
1258
3c756001 1259 if (system_unit)
886a64fe
ZJS
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)
b56d608e 1264 return log_error_errno(r, "Failed to add unit matches: %m");
1a6c43e9 1265
553d2243 1266 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
1267 _cleanup_free_ char *filter;
1268
1269 filter = journal_make_match_string(j);
b56d608e
LP
1270 if (!filter)
1271 return log_oom();
1272
4ad16808
ZJS
1273 log_debug("Journal filter: %s", filter);
1274 }
5ec76417 1275
94e0bd7d 1276 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
86aa7ba4 1277}
df50185b
LP
1278
1279static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1280 [OUTPUT_SHORT] = "short",
44bc6e1f 1281 [OUTPUT_SHORT_ISO] = "short-iso",
f02d8367
ZJS
1282 [OUTPUT_SHORT_PRECISE] = "short-precise",
1283 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
df50185b
LP
1284 [OUTPUT_VERBOSE] = "verbose",
1285 [OUTPUT_EXPORT] = "export",
d3f2bdbf 1286 [OUTPUT_JSON] = "json",
a6e87e90 1287 [OUTPUT_JSON_PRETTY] = "json-pretty",
48383c25 1288 [OUTPUT_JSON_SSE] = "json-sse",
d3f2bdbf 1289 [OUTPUT_CAT] = "cat"
df50185b
LP
1290};
1291
1292DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);