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