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