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