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