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