]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
util: make machine_name_is_valid() a macro and move it to hostname-util.h
[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));
f02d8367
ZJS
337 if (r > 0) {
338 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
609e002e 339 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
f02d8367
ZJS
340 }
341 break;
342 default:
9fd29044 343 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
f02d8367 344 }
44bc6e1f
TT
345
346 if (r <= 0) {
67a12205 347 log_error("Failed to format time.");
44bc6e1f 348 return -EINVAL;
67a12205
LP
349 }
350
08ace05b 351 fputs(buf, f);
67a12205
LP
352 n += strlen(buf);
353 }
86aa7ba4 354
08ace05b
LP
355 if (hostname && shall_print(hostname, hostname_len, flags)) {
356 fprintf(f, " %.*s", (int) hostname_len, hostname);
55d7bfc1
LP
357 n += hostname_len + 1;
358 }
359
08ace05b
LP
360 if (identifier && shall_print(identifier, identifier_len, flags)) {
361 fprintf(f, " %.*s", (int) identifier_len, identifier);
4cd9a9d9 362 n += identifier_len + 1;
08ace05b
LP
363 } else if (comm && shall_print(comm, comm_len, flags)) {
364 fprintf(f, " %.*s", (int) comm_len, comm);
55d7bfc1 365 n += comm_len + 1;
b5936820 366 } else
1248e840 367 fputs(" unknown", f);
86aa7ba4 368
08ace05b
LP
369 if (pid && shall_print(pid, pid_len, flags)) {
370 fprintf(f, "[%.*s]", (int) pid_len, pid);
55d7bfc1 371 n += pid_len + 2;
08ace05b
LP
372 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
373 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
6c1e6b98 374 n += fake_pid_len + 2;
86aa7ba4
LP
375 }
376
31f7bf19 377 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
e6acda19 378 char bytes[FORMAT_BYTES_MAX];
08ace05b 379 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
31f7bf19
ZJS
380 } else {
381 fputs(": ", f);
94e0bd7d
ZJS
382 ellipsized |=
383 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
31f7bf19 384 }
55d7bfc1 385
d4205751
LP
386 if (flags & OUTPUT_CATALOG)
387 print_catalog(f, j);
388
94e0bd7d 389 return ellipsized;
86aa7ba4
LP
390}
391
08ace05b
LP
392static int output_verbose(
393 FILE *f,
394 sd_journal *j,
395 OutputMode mode,
396 unsigned n_columns,
397 OutputFlags flags) {
398
86aa7ba4
LP
399 const void *data;
400 size_t length;
7fd1b19b 401 _cleanup_free_ char *cursor = NULL;
86aa7ba4 402 uint64_t realtime;
f02d8367 403 char ts[FORMAT_TIMESTAMP_MAX + 7];
86aa7ba4
LP
404 int r;
405
08ace05b 406 assert(f);
86aa7ba4
LP
407 assert(j);
408
93b73b06
LP
409 sd_journal_set_data_threshold(j, 0);
410
cf40f0be
ZJS
411 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
412 if (r == -ENOENT)
413 log_debug("Source realtime timestamp not found");
b56d608e
LP
414 else if (r < 0)
415 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get source realtime timestamp: %m");
416 else {
cf40f0be
ZJS
417 _cleanup_free_ char *value = NULL;
418 size_t size;
419
420 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
421 if (r < 0)
da927ba9 422 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
cf40f0be
ZJS
423 else {
424 r = safe_atou64(value, &realtime);
425 if (r < 0)
c33b3297 426 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
cf40f0be
ZJS
427 }
428 }
429
430 if (r < 0) {
431 r = sd_journal_get_realtime_usec(j, &realtime);
b56d608e
LP
432 if (r < 0)
433 return log_full_errno(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR, r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
434 }
435
436 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
437 if (r < 0)
438 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 439
08ace05b 440 fprintf(f, "%s [%s]\n",
5ab99e07
LP
441 flags & OUTPUT_UTC ?
442 format_timestamp_us_utc(ts, sizeof(ts), realtime) :
443 format_timestamp_us(ts, sizeof(ts), realtime),
08ace05b 444 cursor);
86aa7ba4 445
a72b6353 446 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
31f7bf19
ZJS
447 const char *c;
448 int fieldlen;
7ac4fa7e
ZJS
449 const char *on = "", *off = "";
450
31f7bf19
ZJS
451 c = memchr(data, '=', length);
452 if (!c) {
453 log_error("Invalid field.");
454 return -EINVAL;
455 }
456 fieldlen = c - (const char*) data;
86aa7ba4 457
7ac4fa7e
ZJS
458 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
459 on = ANSI_HIGHLIGHT_ON;
460 off = ANSI_HIGHLIGHT_OFF;
461 }
462
463 if (flags & OUTPUT_SHOW_ALL ||
a6f0104a
ZJS
464 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
465 && utf8_is_printable(data, length))) {
7ac4fa7e 466 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
31f7bf19 467 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
7ac4fa7e 468 fputs(off, f);
31f7bf19
ZJS
469 } else {
470 char bytes[FORMAT_BYTES_MAX];
86aa7ba4 471
7ac4fa7e
ZJS
472 fprintf(f, " %s%.*s=[%s blob data]%s\n",
473 on,
31f7bf19
ZJS
474 (int) (c - (const char*) data),
475 (const char*) data,
7ac4fa7e
ZJS
476 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
477 off);
31f7bf19 478 }
86aa7ba4
LP
479 }
480
a72b6353
ZJS
481 if (r < 0)
482 return r;
483
d4205751
LP
484 if (flags & OUTPUT_CATALOG)
485 print_catalog(f, j);
486
86aa7ba4
LP
487 return 0;
488}
489
08ace05b
LP
490static int output_export(
491 FILE *f,
492 sd_journal *j,
493 OutputMode mode,
494 unsigned n_columns,
495 OutputFlags flags) {
496
86aa7ba4
LP
497 sd_id128_t boot_id;
498 char sid[33];
499 int r;
500 usec_t realtime, monotonic;
7fd1b19b 501 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
502 const void *data;
503 size_t length;
504
505 assert(j);
506
93b73b06
LP
507 sd_journal_set_data_threshold(j, 0);
508
86aa7ba4 509 r = sd_journal_get_realtime_usec(j, &realtime);
f647962d
MS
510 if (r < 0)
511 return log_error_errno(r, "Failed to get realtime timestamp: %m");
86aa7ba4
LP
512
513 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
f647962d
MS
514 if (r < 0)
515 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
86aa7ba4
LP
516
517 r = sd_journal_get_cursor(j, &cursor);
f647962d
MS
518 if (r < 0)
519 return log_error_errno(r, "Failed to get cursor: %m");
86aa7ba4 520
08ace05b
LP
521 fprintf(f,
522 "__CURSOR=%s\n"
de0671ee
ZJS
523 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
524 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
08ace05b
LP
525 "_BOOT_ID=%s\n",
526 cursor,
de0671ee
ZJS
527 realtime,
528 monotonic,
08ace05b 529 sd_id128_to_string(boot_id, sid));
86aa7ba4 530
a72b6353 531 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
86aa7ba4 532
112301ae
LP
533 /* We already printed the boot id, from the data in
534 * the header, hence let's suppress it here */
535 if (length >= 9 &&
2a0e0692 536 startswith(data, "_BOOT_ID="))
112301ae
LP
537 continue;
538
0ade5ffe
ZJS
539 if (utf8_is_printable_newline(data, length, false))
540 fwrite(data, length, 1, f);
541 else {
86aa7ba4
LP
542 const char *c;
543 uint64_t le64;
544
545 c = memchr(data, '=', length);
546 if (!c) {
547 log_error("Invalid field.");
548 return -EINVAL;
549 }
550
08ace05b
LP
551 fwrite(data, c - (const char*) data, 1, f);
552 fputc('\n', f);
86aa7ba4 553 le64 = htole64(length - (c - (const char*) data) - 1);
08ace05b
LP
554 fwrite(&le64, sizeof(le64), 1, f);
555 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
0ade5ffe 556 }
86aa7ba4 557
08ace05b 558 fputc('\n', f);
86aa7ba4
LP
559 }
560
a72b6353
ZJS
561 if (r < 0)
562 return r;
563
08ace05b 564 fputc('\n', f);
86aa7ba4
LP
565
566 return 0;
567}
568
240a5fe8 569void json_escape(
08ace05b
LP
570 FILE *f,
571 const char* p,
572 size_t l,
573 OutputFlags flags) {
574
575 assert(f);
576 assert(p);
577
93b73b06 578 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
08ace05b
LP
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);
91a8a108
DM
608 else if ((uint8_t) *p < ' ')
609 fprintf(f, "\\u%04x", (uint8_t) *p);
08ace05b
LP
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);