]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
8edf4087c68f337ab76aed2c85f9d9a9dd0448e7
[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("Failed to get monotonic timestamp: %s", strerror(-r));
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
315 r = -ENOENT;
316
317 if (realtime)
318 r = safe_atou64(realtime, &x);
319
320 if (r < 0)
321 r = sd_journal_get_realtime_usec(j, &x);
322
323 if (r < 0) {
324 log_error("Failed to get realtime timestamp: %s", strerror(-r));
325 return r;
326 }
327
328 t = (time_t) (x / USEC_PER_SEC);
329
330 switch(mode) {
331 case OUTPUT_SHORT_ISO:
332 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
333 break;
334 case OUTPUT_SHORT_PRECISE:
335 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
336 if (r > 0) {
337 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
338 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
339 }
340 break;
341 default:
342 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
343 }
344
345 if (r <= 0) {
346 log_error("Failed to format time.");
347 return -EINVAL;
348 }
349
350 fputs(buf, f);
351 n += strlen(buf);
352 }
353
354 if (hostname && shall_print(hostname, hostname_len, flags)) {
355 fprintf(f, " %.*s", (int) hostname_len, hostname);
356 n += hostname_len + 1;
357 }
358
359 if (identifier && shall_print(identifier, identifier_len, flags)) {
360 fprintf(f, " %.*s", (int) identifier_len, identifier);
361 n += identifier_len + 1;
362 } else if (comm && shall_print(comm, comm_len, flags)) {
363 fprintf(f, " %.*s", (int) comm_len, comm);
364 n += comm_len + 1;
365 } else
366 fputc(' ', f);
367
368 if (pid && shall_print(pid, pid_len, flags)) {
369 fprintf(f, "[%.*s]", (int) pid_len, pid);
370 n += pid_len + 2;
371 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
372 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
373 n += fake_pid_len + 2;
374 }
375
376 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
377 char bytes[FORMAT_BYTES_MAX];
378 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
379 } else {
380 fputs(": ", f);
381 ellipsized |=
382 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
383 }
384
385 if (flags & OUTPUT_CATALOG)
386 print_catalog(f, j);
387
388 return ellipsized;
389 }
390
391 static int output_verbose(
392 FILE *f,
393 sd_journal *j,
394 OutputMode mode,
395 unsigned n_columns,
396 OutputFlags flags) {
397
398 const void *data;
399 size_t length;
400 _cleanup_free_ char *cursor = NULL;
401 uint64_t realtime;
402 char ts[FORMAT_TIMESTAMP_MAX + 7];
403 int r;
404
405 assert(f);
406 assert(j);
407
408 sd_journal_set_data_threshold(j, 0);
409
410 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
411 if (r == -ENOENT)
412 log_debug("Source realtime timestamp not found");
413 else if (r < 0) {
414 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
415 "Failed to get source realtime timestamp: %s", strerror(-r));
416 return r;
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("_SOURCE_REALTIME_TIMESTAMP invalid: %s", strerror(-r));
424 else {
425 r = safe_atou64(value, &realtime);
426 if (r < 0)
427 log_debug("Failed to parse realtime timestamp: %s",
428 strerror(-r));
429 }
430 }
431
432 if (r < 0) {
433 r = sd_journal_get_realtime_usec(j, &realtime);
434 if (r < 0) {
435 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
436 "Failed to get realtime timestamp: %s", strerror(-r));
437 return r;
438 }
439 }
440
441 r = sd_journal_get_cursor(j, &cursor);
442 if (r < 0) {
443 log_error("Failed to get cursor: %s", strerror(-r));
444 return r;
445 }
446
447 fprintf(f, "%s [%s]\n",
448 format_timestamp_us(ts, sizeof(ts), realtime),
449 cursor);
450
451 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
452 const char *c;
453 int fieldlen;
454 const char *on = "", *off = "";
455
456 c = memchr(data, '=', length);
457 if (!c) {
458 log_error("Invalid field.");
459 return -EINVAL;
460 }
461 fieldlen = c - (const char*) data;
462
463 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
464 on = ANSI_HIGHLIGHT_ON;
465 off = ANSI_HIGHLIGHT_OFF;
466 }
467
468 if (flags & OUTPUT_SHOW_ALL ||
469 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
470 && utf8_is_printable(data, length))) {
471 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
472 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
473 fputs(off, f);
474 } else {
475 char bytes[FORMAT_BYTES_MAX];
476
477 fprintf(f, " %s%.*s=[%s blob data]%s\n",
478 on,
479 (int) (c - (const char*) data),
480 (const char*) data,
481 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
482 off);
483 }
484 }
485
486 if (r < 0)
487 return r;
488
489 if (flags & OUTPUT_CATALOG)
490 print_catalog(f, j);
491
492 return 0;
493 }
494
495 static int output_export(
496 FILE *f,
497 sd_journal *j,
498 OutputMode mode,
499 unsigned n_columns,
500 OutputFlags flags) {
501
502 sd_id128_t boot_id;
503 char sid[33];
504 int r;
505 usec_t realtime, monotonic;
506 _cleanup_free_ char *cursor = NULL;
507 const void *data;
508 size_t length;
509
510 assert(j);
511
512 sd_journal_set_data_threshold(j, 0);
513
514 r = sd_journal_get_realtime_usec(j, &realtime);
515 if (r < 0) {
516 log_error("Failed to get realtime timestamp: %s", strerror(-r));
517 return r;
518 }
519
520 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
521 if (r < 0) {
522 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
523 return r;
524 }
525
526 r = sd_journal_get_cursor(j, &cursor);
527 if (r < 0) {
528 log_error("Failed to get cursor: %s", strerror(-r));
529 return r;
530 }
531
532 fprintf(f,
533 "__CURSOR=%s\n"
534 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
535 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
536 "_BOOT_ID=%s\n",
537 cursor,
538 realtime,
539 monotonic,
540 sd_id128_to_string(boot_id, sid));
541
542 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
543
544 /* We already printed the boot id, from the data in
545 * the header, hence let's suppress it here */
546 if (length >= 9 &&
547 startswith(data, "_BOOT_ID="))
548 continue;
549
550 if (utf8_is_printable_newline(data, length, false))
551 fwrite(data, length, 1, f);
552 else {
553 const char *c;
554 uint64_t le64;
555
556 c = memchr(data, '=', length);
557 if (!c) {
558 log_error("Invalid field.");
559 return -EINVAL;
560 }
561
562 fwrite(data, c - (const char*) data, 1, f);
563 fputc('\n', f);
564 le64 = htole64(length - (c - (const char*) data) - 1);
565 fwrite(&le64, sizeof(le64), 1, f);
566 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
567 }
568
569 fputc('\n', f);
570 }
571
572 if (r < 0)
573 return r;
574
575 fputc('\n', f);
576
577 return 0;
578 }
579
580 void json_escape(
581 FILE *f,
582 const char* p,
583 size_t l,
584 OutputFlags flags) {
585
586 assert(f);
587 assert(p);
588
589 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
590
591 fputs("null", f);
592
593 else if (!utf8_is_printable(p, l)) {
594 bool not_first = false;
595
596 fputs("[ ", f);
597
598 while (l > 0) {
599 if (not_first)
600 fprintf(f, ", %u", (uint8_t) *p);
601 else {
602 not_first = true;
603 fprintf(f, "%u", (uint8_t) *p);
604 }
605
606 p++;
607 l--;
608 }
609
610 fputs(" ]", f);
611 } else {
612 fputc('\"', f);
613
614 while (l > 0) {
615 if (*p == '"' || *p == '\\') {
616 fputc('\\', f);
617 fputc(*p, f);
618 } else if (*p == '\n')
619 fputs("\\n", f);
620 else if (*p < ' ')
621 fprintf(f, "\\u%04x", *p);
622 else
623 fputc(*p, f);
624
625 p++;
626 l--;
627 }
628
629 fputc('\"', f);
630 }
631 }
632
633 static int output_json(
634 FILE *f,
635 sd_journal *j,
636 OutputMode mode,
637 unsigned n_columns,
638 OutputFlags flags) {
639
640 uint64_t realtime, monotonic;
641 _cleanup_free_ char *cursor = NULL;
642 const void *data;
643 size_t length;
644 sd_id128_t boot_id;
645 char sid[33], *k;
646 int r;
647 Hashmap *h = NULL;
648 bool done, separator;
649
650 assert(j);
651
652 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
653
654 r = sd_journal_get_realtime_usec(j, &realtime);
655 if (r < 0) {
656 log_error("Failed to get realtime timestamp: %s", strerror(-r));
657 return r;
658 }
659
660 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
661 if (r < 0) {
662 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
663 return r;
664 }
665
666 r = sd_journal_get_cursor(j, &cursor);
667 if (r < 0) {
668 log_error("Failed to get cursor: %s", strerror(-r));
669 return r;
670 }
671
672 if (mode == OUTPUT_JSON_PRETTY)
673 fprintf(f,
674 "{\n"
675 "\t\"__CURSOR\" : \"%s\",\n"
676 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
677 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
678 "\t\"_BOOT_ID\" : \"%s\"",
679 cursor,
680 realtime,
681 monotonic,
682 sd_id128_to_string(boot_id, sid));
683 else {
684 if (mode == OUTPUT_JSON_SSE)
685 fputs("data: ", f);
686
687 fprintf(f,
688 "{ \"__CURSOR\" : \"%s\", "
689 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
690 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
691 "\"_BOOT_ID\" : \"%s\"",
692 cursor,
693 realtime,
694 monotonic,
695 sd_id128_to_string(boot_id, sid));
696 }
697
698 h = hashmap_new(string_hash_func, string_compare_func);
699 if (!h)
700 return -ENOMEM;
701
702 /* First round, iterate through the entry and count how often each field appears */
703 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
704 const char *eq;
705 char *n;
706 unsigned u;
707
708 if (length >= 9 &&
709 memcmp(data, "_BOOT_ID=", 9) == 0)
710 continue;
711
712 eq = memchr(data, '=', length);
713 if (!eq)
714 continue;
715
716 n = strndup(data, eq - (const char*) data);
717 if (!n) {
718 r = -ENOMEM;
719 goto finish;
720 }
721
722 u = PTR_TO_UINT(hashmap_get(h, n));
723 if (u == 0) {
724 r = hashmap_put(h, n, UINT_TO_PTR(1));
725 if (r < 0) {
726 free(n);
727 goto finish;
728 }
729 } else {
730 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
731 free(n);
732 if (r < 0)
733 goto finish;
734 }
735 }
736
737 if (r < 0)
738 return r;
739
740 separator = true;
741 do {
742 done = true;
743
744 SD_JOURNAL_FOREACH_DATA(j, data, length) {
745 const char *eq;
746 char *kk, *n;
747 size_t m;
748 unsigned u;
749
750 /* We already printed the boot id, from the data in
751 * the header, hence let's suppress it here */
752 if (length >= 9 &&
753 memcmp(data, "_BOOT_ID=", 9) == 0)
754 continue;
755
756 eq = memchr(data, '=', length);
757 if (!eq)
758 continue;
759
760 if (separator) {
761 if (mode == OUTPUT_JSON_PRETTY)
762 fputs(",\n\t", f);
763 else
764 fputs(", ", f);
765 }
766
767 m = eq - (const char*) data;
768
769 n = strndup(data, m);
770 if (!n) {
771 r = -ENOMEM;
772 goto finish;
773 }
774
775 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
776 if (u == 0) {
777 /* We already printed this, let's jump to the next */
778 free(n);
779 separator = false;
780
781 continue;
782 } else if (u == 1) {
783 /* Field only appears once, output it directly */
784
785 json_escape(f, data, m, flags);
786 fputs(" : ", f);
787
788 json_escape(f, eq + 1, length - m - 1, flags);
789
790 hashmap_remove(h, n);
791 free(kk);
792 free(n);
793
794 separator = true;
795
796 continue;
797
798 } else {
799 /* Field appears multiple times, output it as array */
800 json_escape(f, data, m, flags);
801 fputs(" : [ ", f);
802 json_escape(f, eq + 1, length - m - 1, flags);
803
804 /* Iterate through the end of the list */
805
806 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
807 if (length < m + 1)
808 continue;
809
810 if (memcmp(data, n, m) != 0)
811 continue;
812
813 if (((const char*) data)[m] != '=')
814 continue;
815
816 fputs(", ", f);
817 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
818 }
819
820 fputs(" ]", f);
821
822 hashmap_remove(h, n);
823 free(kk);
824 free(n);
825
826 /* Iterate data fields form the beginning */
827 done = false;
828 separator = true;
829
830 break;
831 }
832 }
833
834 } while (!done);
835
836 if (mode == OUTPUT_JSON_PRETTY)
837 fputs("\n}\n", f);
838 else if (mode == OUTPUT_JSON_SSE)
839 fputs("}\n\n", f);
840 else
841 fputs(" }\n", f);
842
843 r = 0;
844
845 finish:
846 while ((k = hashmap_steal_first_key(h)))
847 free(k);
848
849 hashmap_free(h);
850
851 return r;
852 }
853
854 static int output_cat(
855 FILE *f,
856 sd_journal *j,
857 OutputMode mode,
858 unsigned n_columns,
859 OutputFlags flags) {
860
861 const void *data;
862 size_t l;
863 int r;
864
865 assert(j);
866 assert(f);
867
868 sd_journal_set_data_threshold(j, 0);
869
870 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
871 if (r < 0) {
872 /* An entry without MESSAGE=? */
873 if (r == -ENOENT)
874 return 0;
875
876 log_error("Failed to get data: %s", strerror(-r));
877 return r;
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 goto finish;
968
969 r = sd_journal_previous_skip(j, how_many);
970 if (r < 0)
971 goto finish;
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 goto finish;
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 goto finish;
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 goto finish;
1008 }
1009
1010 if (warn_cutoff && line < how_many && not_before > 0) {
1011 sd_id128_t boot_id;
1012 usec_t cutoff;
1013
1014 /* Check whether the cutoff line is too early */
1015
1016 r = sd_id128_get_boot(&boot_id);
1017 if (r < 0)
1018 goto finish;
1019
1020 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1021 if (r < 0)
1022 goto finish;
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_t) -1);
1036 if (r < 0)
1037 goto finish;
1038
1039 }
1040
1041 finish:
1042 return r;
1043 }
1044
1045 int add_matches_for_unit(sd_journal *j, const char *unit) {
1046 int r;
1047 char *m1, *m2, *m3, *m4;
1048
1049 assert(j);
1050 assert(unit);
1051
1052 m1 = strappenda("_SYSTEMD_UNIT=", unit);
1053 m2 = strappenda("COREDUMP_UNIT=", unit);
1054 m3 = strappenda("UNIT=", unit);
1055 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
1056
1057 (void)(
1058 /* Look for messages from the service itself */
1059 (r = sd_journal_add_match(j, m1, 0)) ||
1060
1061 /* Look for coredumps of the service */
1062 (r = sd_journal_add_disjunction(j)) ||
1063 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1064 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1065 (r = sd_journal_add_match(j, m2, 0)) ||
1066
1067 /* Look for messages from PID 1 about this service */
1068 (r = sd_journal_add_disjunction(j)) ||
1069 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1070 (r = sd_journal_add_match(j, m3, 0)) ||
1071
1072 /* Look for messages from authorized daemons about this service */
1073 (r = sd_journal_add_disjunction(j)) ||
1074 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1075 (r = sd_journal_add_match(j, m4, 0))
1076 );
1077
1078 if (r == 0 && endswith(unit, ".slice")) {
1079 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1080
1081 /* Show all messages belonging to a slice */
1082 (void)(
1083 (r = sd_journal_add_disjunction(j)) ||
1084 (r = sd_journal_add_match(j, m5, 0))
1085 );
1086 }
1087
1088 return r;
1089 }
1090
1091 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1092 int r;
1093 char *m1, *m2, *m3, *m4;
1094 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1095
1096 assert(j);
1097 assert(unit);
1098
1099 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
1100 m2 = strappenda("USER_UNIT=", unit);
1101 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
1102 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
1103 sprintf(muid, "_UID="UID_FMT, uid);
1104
1105 (void) (
1106 /* Look for messages from the user service itself */
1107 (r = sd_journal_add_match(j, m1, 0)) ||
1108 (r = sd_journal_add_match(j, muid, 0)) ||
1109
1110 /* Look for messages from systemd about this service */
1111 (r = sd_journal_add_disjunction(j)) ||
1112 (r = sd_journal_add_match(j, m2, 0)) ||
1113 (r = sd_journal_add_match(j, muid, 0)) ||
1114
1115 /* Look for coredumps of the service */
1116 (r = sd_journal_add_disjunction(j)) ||
1117 (r = sd_journal_add_match(j, m3, 0)) ||
1118 (r = sd_journal_add_match(j, muid, 0)) ||
1119 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1120
1121 /* Look for messages from authorized daemons about this service */
1122 (r = sd_journal_add_disjunction(j)) ||
1123 (r = sd_journal_add_match(j, m4, 0)) ||
1124 (r = sd_journal_add_match(j, muid, 0)) ||
1125 (r = sd_journal_add_match(j, "_UID=0", 0))
1126 );
1127
1128 if (r == 0 && endswith(unit, ".slice")) {
1129 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1130
1131 /* Show all messages belonging to a slice */
1132 (void)(
1133 (r = sd_journal_add_disjunction(j)) ||
1134 (r = sd_journal_add_match(j, m5, 0)) ||
1135 (r = sd_journal_add_match(j, muid, 0))
1136 );
1137 }
1138
1139 return r;
1140 }
1141
1142 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1143 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1144 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1145 pid_t pid, child;
1146 siginfo_t si;
1147 char buf[37];
1148 ssize_t k;
1149 int r;
1150
1151 assert(machine);
1152 assert(boot_id);
1153
1154 if (!filename_is_safe(machine))
1155 return -EINVAL;
1156
1157 r = container_get_leader(machine, &pid);
1158 if (r < 0)
1159 return r;
1160
1161 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1162 if (r < 0)
1163 return r;
1164
1165 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1166 return -errno;
1167
1168 child = fork();
1169 if (child < 0)
1170 return -errno;
1171
1172 if (child == 0) {
1173 int fd;
1174
1175 pair[0] = safe_close(pair[0]);
1176
1177 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1178 if (r < 0)
1179 _exit(EXIT_FAILURE);
1180
1181 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1182 if (fd < 0)
1183 _exit(EXIT_FAILURE);
1184
1185 k = loop_read(fd, buf, 36, false);
1186 safe_close(fd);
1187 if (k != 36)
1188 _exit(EXIT_FAILURE);
1189
1190 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1191 if (k != 36)
1192 _exit(EXIT_FAILURE);
1193
1194 _exit(EXIT_SUCCESS);
1195 }
1196
1197 pair[1] = safe_close(pair[1]);
1198
1199 r = wait_for_terminate(child, &si);
1200 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1201 return r < 0 ? r : -EIO;
1202
1203 k = recv(pair[0], buf, 36, 0);
1204 if (k != 36)
1205 return -EIO;
1206
1207 buf[36] = 0;
1208 r = sd_id128_from_string(buf, boot_id);
1209 if (r < 0)
1210 return r;
1211
1212 return 0;
1213 }
1214
1215 int add_match_this_boot(sd_journal *j, const char *machine) {
1216 char match[9+32+1] = "_BOOT_ID=";
1217 sd_id128_t boot_id;
1218 int r;
1219
1220 assert(j);
1221
1222 if (machine) {
1223 r = get_boot_id_for_machine(machine, &boot_id);
1224 if (r < 0) {
1225 log_error("Failed to get boot id of container %s: %s", machine, strerror(-r));
1226 return r;
1227 }
1228 } else {
1229 r = sd_id128_get_boot(&boot_id);
1230 if (r < 0) {
1231 log_error("Failed to get boot id: %s", strerror(-r));
1232 return r;
1233 }
1234 }
1235
1236 sd_id128_to_string(boot_id, match + 9);
1237 r = sd_journal_add_match(j, match, strlen(match));
1238 if (r < 0) {
1239 log_error("Failed to add match: %s", strerror(-r));
1240 return r;
1241 }
1242
1243 r = sd_journal_add_conjunction(j);
1244 if (r < 0)
1245 return r;
1246
1247 return 0;
1248 }
1249
1250 int show_journal_by_unit(
1251 FILE *f,
1252 const char *unit,
1253 OutputMode mode,
1254 unsigned n_columns,
1255 usec_t not_before,
1256 unsigned how_many,
1257 uid_t uid,
1258 OutputFlags flags,
1259 bool system,
1260 bool *ellipsized) {
1261
1262 _cleanup_journal_close_ sd_journal*j = NULL;
1263 int r;
1264 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1265
1266 assert(mode >= 0);
1267 assert(mode < _OUTPUT_MODE_MAX);
1268 assert(unit);
1269
1270 if (how_many <= 0)
1271 return 0;
1272
1273 r = sd_journal_open(&j, jflags);
1274 if (r < 0)
1275 return r;
1276
1277 r = add_match_this_boot(j, NULL);
1278 if (r < 0)
1279 return r;
1280
1281 if (system)
1282 r = add_matches_for_unit(j, unit);
1283 else
1284 r = add_matches_for_user_unit(j, unit, uid);
1285 if (r < 0)
1286 return r;
1287
1288 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1289 _cleanup_free_ char *filter;
1290
1291 filter = journal_make_match_string(j);
1292 log_debug("Journal filter: %s", filter);
1293 }
1294
1295 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1296 }
1297
1298 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1299 [OUTPUT_SHORT] = "short",
1300 [OUTPUT_SHORT_ISO] = "short-iso",
1301 [OUTPUT_SHORT_PRECISE] = "short-precise",
1302 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1303 [OUTPUT_VERBOSE] = "verbose",
1304 [OUTPUT_EXPORT] = "export",
1305 [OUTPUT_JSON] = "json",
1306 [OUTPUT_JSON_PRETTY] = "json-pretty",
1307 [OUTPUT_JSON_SSE] = "json-sse",
1308 [OUTPUT_CAT] = "cat"
1309 };
1310
1311 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);