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