]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
namespace helpers: Allow entering a UID namespace
[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"
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 274 if (r < 0)
b56d608e 275 return log_error_errno(r, "Failed to get journal fields: %m");
a72b6353 276
07d21025
LP
277 if (!message) {
278 log_debug("Skipping message without MESSAGE= field.");
08ace05b 279 return 0;
07d21025 280 }
55d7bfc1 281
e8bc0ea2
LP
282 if (!(flags & OUTPUT_SHOW_ALL))
283 strip_tab_ansi(&message, &message_len);
284
49826187
LP
285 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
286 p = *priority - '0';
287
a6e87e90 288 if (mode == OUTPUT_SHORT_MONOTONIC) {
67a12205 289 uint64_t t;
3ebcdf8c
LP
290 sd_id128_t boot_id;
291
bf967366
LP
292 r = -ENOENT;
293
294 if (monotonic)
295 r = safe_atou64(monotonic, &t);
296
297 if (r < 0)
3ebcdf8c 298 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
86aa7ba4 299
f647962d
MS
300 if (r < 0)
301 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
67a12205 302
08ace05b 303 fprintf(f, "[%5llu.%06llu]",
609e002e
LP
304 (unsigned long long) (t / USEC_PER_SEC),
305 (unsigned long long) (t % USEC_PER_SEC));
3ebcdf8c
LP
306
307 n += 1 + 5 + 1 + 6 + 1;
308
67a12205
LP
309 } else {
310 char buf[64];
bf967366 311 uint64_t x;
67a12205
LP
312 time_t t;
313 struct tm tm;
9fd29044 314 struct tm *(*gettime_r)(const time_t *, struct tm *);
731a676c 315
bf967366 316 r = -ENOENT;
9fd29044 317 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
bf967366
LP
318
319 if (realtime)
320 r = safe_atou64(realtime, &x);
321
322 if (r < 0)
323 r = sd_journal_get_realtime_usec(j, &x);
67a12205 324
f647962d
MS
325 if (r < 0)
326 return log_error_errno(r, "Failed to get realtime timestamp: %m");
67a12205 327
bf967366 328 t = (time_t) (x / USEC_PER_SEC);
f02d8367
ZJS
329
330 switch(mode) {
331 case OUTPUT_SHORT_ISO:
9fd29044 332 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
f02d8367
ZJS
333 break;
334 case OUTPUT_SHORT_PRECISE:
9fd29044 335 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
f02d8367
ZJS
336 if (r > 0) {
337 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
609e002e 338 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
f02d8367
ZJS
339 }
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
579 fputs("null", f);
580
31f7bf19 581 else if (!utf8_is_printable(p, l)) {
86aa7ba4
LP
582 bool not_first = false;
583
08ace05b 584 fputs("[ ", f);
86aa7ba4
LP
585
586 while (l > 0) {
587 if (not_first)
08ace05b 588 fprintf(f, ", %u", (uint8_t) *p);
86aa7ba4
LP
589 else {
590 not_first = true;
08ace05b 591 fprintf(f, "%u", (uint8_t) *p);
86aa7ba4
LP
592 }
593
594 p++;
595 l--;
596 }
597
08ace05b 598 fputs(" ]", f);
86aa7ba4 599 } else {
08ace05b 600 fputc('\"', f);
86aa7ba4
LP
601
602 while (l > 0) {
603 if (*p == '"' || *p == '\\') {
08ace05b
LP
604 fputc('\\', f);
605 fputc(*p, f);
31f7bf19
ZJS
606 } else if (*p == '\n')
607 fputs("\\n", f);
608 else if (*p < ' ')
08ace05b
LP
609 fprintf(f, "\\u%04x", *p);
610 else
611 fputc(*p, f);
86aa7ba4
LP
612
613 p++;
614 l--;
615 }
616
08ace05b 617 fputc('\"', f);
86aa7ba4
LP
618 }
619}
620
08ace05b
LP
621static int output_json(
622 FILE *f,
623 sd_journal *j,
624 OutputMode mode,
625 unsigned n_columns,
626 OutputFlags flags) {
627
86aa7ba4 628 uint64_t realtime, monotonic;
7fd1b19b 629 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
630 const void *data;
631 size_t length;
632 sd_id128_t boot_id;
2e729834 633 char sid[33], *k;
86aa7ba4 634 int r;
d99ae53a
LP
635 Hashmap *h = NULL;
636 bool done, separator;
86aa7ba4
LP
637
638 assert(j);
639
93b73b06
LP
640 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
641
86aa7ba4 642 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
643 if (r < 0)
644 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
645
646 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
647 if (r < 0)
648 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
649
650 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
651 if (r < 0)
652 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 653
a6e87e90 654 if (mode == OUTPUT_JSON_PRETTY)
08ace05b
LP
655 fprintf(f,
656 "{\n"
657 "\t\"__CURSOR\" : \"%s\",\n"
de0671ee
ZJS
658 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
659 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
08ace05b
LP
660 "\t\"_BOOT_ID\" : \"%s\"",
661 cursor,
de0671ee
ZJS
662 realtime,
663 monotonic,
08ace05b 664 sd_id128_to_string(boot_id, sid));
48383c25
LP
665 else {
666 if (mode == OUTPUT_JSON_SSE)
667 fputs("data: ", f);
668
08ace05b
LP
669 fprintf(f,
670 "{ \"__CURSOR\" : \"%s\", "
de0671ee
ZJS
671 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
672 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
08ace05b
LP
673 "\"_BOOT_ID\" : \"%s\"",
674 cursor,
de0671ee
ZJS
675 realtime,
676 monotonic,
08ace05b 677 sd_id128_to_string(boot_id, sid));
48383c25 678 }
86aa7ba4 679
d5099efc 680 h = hashmap_new(&string_hash_ops);
d99ae53a 681 if (!h)
b56d608e 682 return log_oom();
d99ae53a
LP
683
684 /* First round, iterate through the entry and count how often each field appears */
a72b6353 685 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
d99ae53a
LP
686 const char *eq;
687 char *n;
688 unsigned u;
86aa7ba4 689
112301ae
LP
690 if (length >= 9 &&
691 memcmp(data, "_BOOT_ID=", 9) == 0)
692 continue;
693
d99ae53a
LP
694 eq = memchr(data, '=', length);
695 if (!eq)
696 continue;
86aa7ba4 697
d99ae53a
LP
698 n = strndup(data, eq - (const char*) data);
699 if (!n) {
b56d608e 700 r = log_oom();
d99ae53a
LP
701 goto finish;
702 }
a6e87e90 703
d99ae53a
LP
704 u = PTR_TO_UINT(hashmap_get(h, n));
705 if (u == 0) {
706 r = hashmap_put(h, n, UINT_TO_PTR(1));
707 if (r < 0) {
708 free(n);
b56d608e 709 log_oom();
d99ae53a
LP
710 goto finish;
711 }
712 } else {
713 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
714 free(n);
b56d608e
LP
715 if (r < 0) {
716 log_oom();
d99ae53a 717 goto finish;
b56d608e 718 }
d99ae53a 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) {
b56d608e 756 r = log_oom();
d99ae53a
LP
757 goto finish;
758 }
759
760 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
761 if (u == 0) {
762 /* We already printed this, let's jump to the next */
763 free(n);
764 separator = false;
765
766 continue;
767 } else if (u == 1) {
768 /* Field only appears once, output it directly */
769
770 json_escape(f, data, m, flags);
771 fputs(" : ", f);
772
773 json_escape(f, eq + 1, length - m - 1, flags);
774
775 hashmap_remove(h, n);
776 free(kk);
777 free(n);
778
779 separator = true;
780
781 continue;
782
783 } else {
784 /* Field appears multiple times, output it as array */
785 json_escape(f, data, m, flags);
786 fputs(" : [ ", f);
787 json_escape(f, eq + 1, length - m - 1, flags);
788
789 /* Iterate through the end of the list */
790
791 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
792 if (length < m + 1)
793 continue;
794
795 if (memcmp(data, n, m) != 0)
796 continue;
797
798 if (((const char*) data)[m] != '=')
799 continue;
800
801 fputs(", ", f);
802 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
803 }
804
805 fputs(" ]", f);
806
807 hashmap_remove(h, n);
808 free(kk);
809 free(n);
810
811 /* Iterate data fields form the beginning */
812 done = false;
813 separator = true;
814
815 break;
816 }
817 }
818
819 } while (!done);
820
a6e87e90 821 if (mode == OUTPUT_JSON_PRETTY)
08ace05b 822 fputs("\n}\n", f);
48383c25
LP
823 else if (mode == OUTPUT_JSON_SSE)
824 fputs("}\n\n", f);
a6e87e90 825 else
08ace05b 826 fputs(" }\n", f);
86aa7ba4 827
d99ae53a
LP
828 r = 0;
829
830finish:
831 while ((k = hashmap_steal_first_key(h)))
832 free(k);
833
834 hashmap_free(h);
835
836 return r;
86aa7ba4
LP
837}
838
08ace05b
LP
839static int output_cat(
840 FILE *f,
841 sd_journal *j,
842 OutputMode mode,
843 unsigned n_columns,
844 OutputFlags flags) {
845
d3f2bdbf
LP
846 const void *data;
847 size_t l;
848 int r;
849
850 assert(j);
08ace05b 851 assert(f);
d3f2bdbf 852
93b73b06
LP
853 sd_journal_set_data_threshold(j, 0);
854
d3f2bdbf
LP
855 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
856 if (r < 0) {
c198300f
LP
857 /* An entry without MESSAGE=? */
858 if (r == -ENOENT)
859 return 0;
860
8d3d7072 861 return log_error_errno(r, "Failed to get data: %m");
d3f2bdbf
LP
862 }
863
864 assert(l >= 8);
865
08ace05b
LP
866 fwrite((const char*) data + 8, 1, l - 8, f);
867 fputc('\n', f);
d3f2bdbf
LP
868
869 return 0;
870}
871
08ace05b
LP
872static int (*output_funcs[_OUTPUT_MODE_MAX])(
873 FILE *f,
874 sd_journal*j,
875 OutputMode mode,
876 unsigned n_columns,
877 OutputFlags flags) = {
878
a6e87e90 879 [OUTPUT_SHORT] = output_short,
44bc6e1f 880 [OUTPUT_SHORT_ISO] = output_short,
f02d8367
ZJS
881 [OUTPUT_SHORT_PRECISE] = output_short,
882 [OUTPUT_SHORT_MONOTONIC] = output_short,
86aa7ba4
LP
883 [OUTPUT_VERBOSE] = output_verbose,
884 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 885 [OUTPUT_JSON] = output_json,
a6e87e90 886 [OUTPUT_JSON_PRETTY] = output_json,
48383c25 887 [OUTPUT_JSON_SSE] = output_json,
d3f2bdbf 888 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
889};
890
08ace05b
LP
891int output_journal(
892 FILE *f,
893 sd_journal *j,
894 OutputMode mode,
895 unsigned n_columns,
94e0bd7d
ZJS
896 OutputFlags flags,
897 bool *ellipsized) {
08ace05b 898
e268b81e 899 int ret;
df50185b 900 assert(mode >= 0);
86aa7ba4
LP
901 assert(mode < _OUTPUT_MODE_MAX);
902
34a35ece
LP
903 if (n_columns <= 0)
904 n_columns = columns();
905
08ace05b 906 ret = output_funcs[mode](f, j, mode, n_columns, flags);
e268b81e 907 fflush(stdout);
94e0bd7d
ZJS
908
909 if (ellipsized && ret > 0)
910 *ellipsized = true;
911
e268b81e 912 return ret;
86aa7ba4
LP
913}
914
ea6c2dd1
LP
915static int maybe_print_begin_newline(FILE *f, OutputFlags *flags) {
916 assert(f);
917 assert(flags);
918
919 if (!(*flags & OUTPUT_BEGIN_NEWLINE))
920 return 0;
921
922 /* Print a beginning new line if that's request, but only once
923 * on the first line we print. */
924
925 fputc('\n', f);
926 *flags &= ~OUTPUT_BEGIN_NEWLINE;
927 return 0;
928}
929
1a6c43e9
MT
930static int show_journal(FILE *f,
931 sd_journal *j,
932 OutputMode mode,
933 unsigned n_columns,
934 usec_t not_before,
935 unsigned how_many,
94e0bd7d
ZJS
936 OutputFlags flags,
937 bool *ellipsized) {
86aa7ba4 938
86aa7ba4 939 int r;
df50185b
LP
940 unsigned line = 0;
941 bool need_seek = false;
085d7120 942 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 943
1a6c43e9 944 assert(j);
df50185b
LP
945 assert(mode >= 0);
946 assert(mode < _OUTPUT_MODE_MAX);
1946b0bd
LP
947
948 /* Seek to end */
86aa7ba4
LP
949 r = sd_journal_seek_tail(j);
950 if (r < 0)
b56d608e 951 return log_error_errno(r, "Failed to seek to tail: %m");
86aa7ba4 952
df50185b
LP
953 r = sd_journal_previous_skip(j, how_many);
954 if (r < 0)
b56d608e 955 return log_error_errno(r, "Failed to skip previous: %m");
86aa7ba4 956
df50185b
LP
957 for (;;) {
958 for (;;) {
959 usec_t usec;
960
961 if (need_seek) {
962 r = sd_journal_next(j);
963 if (r < 0)
b56d608e 964 return log_error_errno(r, "Failed to iterate through journal: %m");
df50185b
LP
965 }
966
967 if (r == 0)
968 break;
86aa7ba4 969
df50185b
LP
970 need_seek = true;
971
972 if (not_before > 0) {
973 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
974
975 /* -ESTALE is returned if the
976 timestamp is not from this boot */
977 if (r == -ESTALE)
978 continue;
979 else if (r < 0)
b56d608e 980 return log_error_errno(r, "Failed to get journal time: %m");
df50185b
LP
981
982 if (usec < not_before)
983 continue;
984 }
985
986 line ++;
ea6c2dd1 987 maybe_print_begin_newline(f, &flags);
df50185b 988
94e0bd7d 989 r = output_journal(f, j, mode, n_columns, flags, ellipsized);
df50185b 990 if (r < 0)
b56d608e 991 return r;
df50185b
LP
992 }
993
08984293
LP
994 if (warn_cutoff && line < how_many && not_before > 0) {
995 sd_id128_t boot_id;
a7f7d1bd 996 usec_t cutoff = 0;
08984293
LP
997
998 /* Check whether the cutoff line is too early */
999
1000 r = sd_id128_get_boot(&boot_id);
1001 if (r < 0)
b56d608e 1002 return log_error_errno(r, "Failed to get boot id: %m");
08984293
LP
1003
1004 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1005 if (r < 0)
b56d608e 1006 return log_error_errno(r, "Failed to get journal cutoff time: %m");
08984293 1007
ea6c2dd1
LP
1008 if (r > 0 && not_before < cutoff) {
1009 maybe_print_begin_newline(f, &flags);
08ace05b 1010 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
ea6c2dd1 1011 }
08984293
LP
1012
1013 warn_cutoff = false;
1014 }
1015
085d7120 1016 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
1017 break;
1018
3a43da28 1019 r = sd_journal_wait(j, USEC_INFINITY);
df50185b 1020 if (r < 0)
b56d608e 1021 return log_error_errno(r, "Failed to wait for journal: %m");
df50185b 1022
86aa7ba4
LP
1023 }
1024
b56d608e 1025 return 0;
1a6c43e9
MT
1026}
1027
886a64fe 1028int add_matches_for_unit(sd_journal *j, const char *unit) {
1a6c43e9 1029 int r;
2d0b2e87 1030 char *m1, *m2, *m3, *m4;
1a6c43e9 1031
886a64fe 1032 assert(j);
1a6c43e9
MT
1033 assert(unit);
1034
63c372cb
LP
1035 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1036 m2 = strjoina("COREDUMP_UNIT=", unit);
1037 m3 = strjoina("UNIT=", unit);
1038 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1a6c43e9 1039
886a64fe
ZJS
1040 (void)(
1041 /* Look for messages from the service itself */
1042 (r = sd_journal_add_match(j, m1, 0)) ||
1043
1044 /* Look for coredumps of the service */
1045 (r = sd_journal_add_disjunction(j)) ||
fdcd37df
ZJS
1046 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1047 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
886a64fe
ZJS
1048 (r = sd_journal_add_match(j, m2, 0)) ||
1049
1050 /* Look for messages from PID 1 about this service */
1051 (r = sd_journal_add_disjunction(j)) ||
1052 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
2d0b2e87
ZJS
1053 (r = sd_journal_add_match(j, m3, 0)) ||
1054
1055 /* Look for messages from authorized daemons about this service */
1056 (r = sd_journal_add_disjunction(j)) ||
1057 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1058 (r = sd_journal_add_match(j, m4, 0))
886a64fe 1059 );
2d0b2e87 1060
69ae3ee0
ZJS
1061 if (r == 0 && endswith(unit, ".slice")) {
1062 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1063
1064 /* Show all messages belonging to a slice */
1065 (void)(
1066 (r = sd_journal_add_disjunction(j)) ||
1067 (r = sd_journal_add_match(j, m5, 0))
1068 );
1069 }
1070
886a64fe
ZJS
1071 return r;
1072}
1a6c43e9 1073
886a64fe
ZJS
1074int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1075 int r;
2d0b2e87
ZJS
1076 char *m1, *m2, *m3, *m4;
1077 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1a6c43e9 1078
886a64fe
ZJS
1079 assert(j);
1080 assert(unit);
1a6c43e9 1081
63c372cb
LP
1082 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1083 m2 = strjoina("USER_UNIT=", unit);
1084 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1085 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
de0671ee 1086 sprintf(muid, "_UID="UID_FMT, uid);
1a6c43e9 1087
886a64fe
ZJS
1088 (void) (
1089 /* Look for messages from the user service itself */
1090 (r = sd_journal_add_match(j, m1, 0)) ||
2d0b2e87 1091 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1092
1093 /* Look for messages from systemd about this service */
1094 (r = sd_journal_add_disjunction(j)) ||
1095 (r = sd_journal_add_match(j, m2, 0)) ||
2d0b2e87 1096 (r = sd_journal_add_match(j, muid, 0)) ||
886a64fe
ZJS
1097
1098 /* Look for coredumps of the service */
1099 (r = sd_journal_add_disjunction(j)) ||
1100 (r = sd_journal_add_match(j, m3, 0)) ||
2d0b2e87
ZJS
1101 (r = sd_journal_add_match(j, muid, 0)) ||
1102 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1103
1104 /* Look for messages from authorized daemons about this service */
1105 (r = sd_journal_add_disjunction(j)) ||
fdcd37df 1106 (r = sd_journal_add_match(j, m4, 0)) ||
2d0b2e87 1107 (r = sd_journal_add_match(j, muid, 0)) ||
fdcd37df 1108 (r = sd_journal_add_match(j, "_UID=0", 0))
886a64fe 1109 );
69ae3ee0
ZJS
1110
1111 if (r == 0 && endswith(unit, ".slice")) {
1112 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1113
1114 /* Show all messages belonging to a slice */
1115 (void)(
1116 (r = sd_journal_add_disjunction(j)) ||
1117 (r = sd_journal_add_match(j, m5, 0)) ||
1118 (r = sd_journal_add_match(j, muid, 0))
1119 );
1120 }
1121
1a6c43e9
MT
1122 return r;
1123}
1124
b6741478 1125static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
3d94f76c 1126 _cleanup_close_pair_ int pair[2] = { -1, -1 };
a4475f57 1127 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
b6741478
LP
1128 pid_t pid, child;
1129 siginfo_t si;
1130 char buf[37];
1131 ssize_t k;
1132 int r;
1133
1134 assert(machine);
1135 assert(boot_id);
1136
affcf189 1137 if (!machine_name_is_valid(machine))
b6741478
LP
1138 return -EINVAL;
1139
e04b0cdb 1140 r = container_get_leader(machine, &pid);
b6741478
LP
1141 if (r < 0)
1142 return r;
e04b0cdb 1143
671c3419 1144 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, NULL, &rootfd);
b6741478
LP
1145 if (r < 0)
1146 return r;
1147
e04b0cdb 1148 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
b6741478
LP
1149 return -errno;
1150
1151 child = fork();
1152 if (child < 0)
1153 return -errno;
1154
1155 if (child == 0) {
1156 int fd;
1157
03e334a1 1158 pair[0] = safe_close(pair[0]);
b6741478 1159
671c3419 1160 r = namespace_enter(pidnsfd, mntnsfd, -1, -1, rootfd);
b6741478
LP
1161 if (r < 0)
1162 _exit(EXIT_FAILURE);
1163
1164 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1165 if (fd < 0)
1166 _exit(EXIT_FAILURE);
1167
a6dcc7e5 1168 r = loop_read_exact(fd, buf, 36, false);
03e334a1 1169 safe_close(fd);
6c767d1e 1170 if (r < 0)
b6741478
LP
1171 _exit(EXIT_FAILURE);
1172
e04b0cdb 1173 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
b6741478
LP
1174 if (k != 36)
1175 _exit(EXIT_FAILURE);
1176
1177 _exit(EXIT_SUCCESS);
1178 }
1179
03e334a1 1180 pair[1] = safe_close(pair[1]);
b6741478 1181
b6741478
LP
1182 r = wait_for_terminate(child, &si);
1183 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1184 return r < 0 ? r : -EIO;
1185
fbadf045
LP
1186 k = recv(pair[0], buf, 36, 0);
1187 if (k != 36)
1188 return -EIO;
1189
b6741478
LP
1190 buf[36] = 0;
1191 r = sd_id128_from_string(buf, boot_id);
1192 if (r < 0)
1193 return r;
1194
1195 return 0;
1196}
1197
1198int add_match_this_boot(sd_journal *j, const char *machine) {
5ec76417
ZJS
1199 char match[9+32+1] = "_BOOT_ID=";
1200 sd_id128_t boot_id;
1201 int r;
1202
1203 assert(j);
1204
b6741478
LP
1205 if (machine) {
1206 r = get_boot_id_for_machine(machine, &boot_id);
f647962d
MS
1207 if (r < 0)
1208 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
b6741478
LP
1209 } else {
1210 r = sd_id128_get_boot(&boot_id);
f647962d
MS
1211 if (r < 0)
1212 return log_error_errno(r, "Failed to get boot id: %m");
5ec76417
ZJS
1213 }
1214
1215 sd_id128_to_string(boot_id, match + 9);
1216 r = sd_journal_add_match(j, match, strlen(match));
f647962d
MS
1217 if (r < 0)
1218 return log_error_errno(r, "Failed to add match: %m");
5ec76417
ZJS
1219
1220 r = sd_journal_add_conjunction(j);
1221 if (r < 0)
b56d608e 1222 return log_error_errno(r, "Failed to add conjunction: %m");
5ec76417
ZJS
1223
1224 return 0;
1225}
1226
886a64fe 1227int show_journal_by_unit(
1a6c43e9
MT
1228 FILE *f,
1229 const char *unit,
1230 OutputMode mode,
1231 unsigned n_columns,
1232 usec_t not_before,
1233 unsigned how_many,
1234 uid_t uid,
886a64fe 1235 OutputFlags flags,
3c756001
LP
1236 int journal_open_flags,
1237 bool system_unit,
94e0bd7d 1238 bool *ellipsized) {
1a6c43e9 1239
7fd1b19b 1240 _cleanup_journal_close_ sd_journal*j = NULL;
1a6c43e9
MT
1241 int r;
1242
1243 assert(mode >= 0);
1244 assert(mode < _OUTPUT_MODE_MAX);
1245 assert(unit);
1246
1a6c43e9
MT
1247 if (how_many <= 0)
1248 return 0;
1249
3c756001 1250 r = sd_journal_open(&j, journal_open_flags);
f9045468 1251 if (r < 0)
b56d608e 1252 return log_error_errno(r, "Failed to open journal: %m");
f9045468 1253
b6741478 1254 r = add_match_this_boot(j, NULL);
5ec76417
ZJS
1255 if (r < 0)
1256 return r;
1257
3c756001 1258 if (system_unit)
886a64fe
ZJS
1259 r = add_matches_for_unit(j, unit);
1260 else
1261 r = add_matches_for_user_unit(j, unit, uid);
1a6c43e9 1262 if (r < 0)
b56d608e 1263 return log_error_errno(r, "Failed to add unit matches: %m");
1a6c43e9 1264
553d2243 1265 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
4ad16808
ZJS
1266 _cleanup_free_ char *filter;
1267
1268 filter = journal_make_match_string(j);
b56d608e
LP
1269 if (!filter)
1270 return log_oom();
1271
4ad16808
ZJS
1272 log_debug("Journal filter: %s", filter);
1273 }
5ec76417 1274
94e0bd7d 1275 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
86aa7ba4 1276}
df50185b
LP
1277
1278static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1279 [OUTPUT_SHORT] = "short",
44bc6e1f 1280 [OUTPUT_SHORT_ISO] = "short-iso",
f02d8367
ZJS
1281 [OUTPUT_SHORT_PRECISE] = "short-precise",
1282 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
df50185b
LP
1283 [OUTPUT_VERBOSE] = "verbose",
1284 [OUTPUT_EXPORT] = "export",
d3f2bdbf 1285 [OUTPUT_JSON] = "json",
a6e87e90 1286 [OUTPUT_JSON_PRETTY] = "json-pretty",
48383c25 1287 [OUTPUT_JSON_SSE] = "json-sse",
d3f2bdbf 1288 [OUTPUT_CAT] = "cat"
df50185b
LP
1289};
1290
1291DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);