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