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