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