]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
treewide: a few more log_*_errno + return simplifications
[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 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
300
301 fprintf(f, "[%5llu.%06llu]",
302 (unsigned long long) (t / USEC_PER_SEC),
303 (unsigned long long) (t % USEC_PER_SEC));
304
305 n += 1 + 5 + 1 + 6 + 1;
306
307 } else {
308 char buf[64];
309 uint64_t x;
310 time_t t;
311 struct tm tm;
312 struct tm *(*gettime_r)(const time_t *, struct tm *);
313
314 r = -ENOENT;
315 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
316
317 if (realtime)
318 r = safe_atou64(realtime, &x);
319
320 if (r < 0)
321 r = sd_journal_get_realtime_usec(j, &x);
322
323 if (r < 0)
324 return log_error_errno(r, "Failed to get realtime timestamp: %m");
325
326 t = (time_t) (x / USEC_PER_SEC);
327
328 switch(mode) {
329 case OUTPUT_SHORT_ISO:
330 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
331 break;
332 case OUTPUT_SHORT_PRECISE:
333 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
334 if (r > 0) {
335 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
336 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
337 }
338 break;
339 default:
340 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
341 }
342
343 if (r <= 0) {
344 log_error("Failed to format time.");
345 return -EINVAL;
346 }
347
348 fputs(buf, f);
349 n += strlen(buf);
350 }
351
352 if (hostname && shall_print(hostname, hostname_len, flags)) {
353 fprintf(f, " %.*s", (int) hostname_len, hostname);
354 n += hostname_len + 1;
355 }
356
357 if (identifier && shall_print(identifier, identifier_len, flags)) {
358 fprintf(f, " %.*s", (int) identifier_len, identifier);
359 n += identifier_len + 1;
360 } else if (comm && shall_print(comm, comm_len, flags)) {
361 fprintf(f, " %.*s", (int) comm_len, comm);
362 n += comm_len + 1;
363 } else
364 fputs(" unknown", f);
365
366 if (pid && shall_print(pid, pid_len, flags)) {
367 fprintf(f, "[%.*s]", (int) pid_len, pid);
368 n += pid_len + 2;
369 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
370 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
371 n += fake_pid_len + 2;
372 }
373
374 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
375 char bytes[FORMAT_BYTES_MAX];
376 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
377 } else {
378 fputs(": ", f);
379 ellipsized |=
380 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
381 }
382
383 if (flags & OUTPUT_CATALOG)
384 print_catalog(f, j);
385
386 return ellipsized;
387 }
388
389 static int output_verbose(
390 FILE *f,
391 sd_journal *j,
392 OutputMode mode,
393 unsigned n_columns,
394 OutputFlags flags) {
395
396 const void *data;
397 size_t length;
398 _cleanup_free_ char *cursor = NULL;
399 uint64_t realtime;
400 char ts[FORMAT_TIMESTAMP_MAX + 7];
401 int r;
402
403 assert(f);
404 assert(j);
405
406 sd_journal_set_data_threshold(j, 0);
407
408 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
409 if (r == -ENOENT)
410 log_debug("Source realtime timestamp not found");
411 else if (r < 0) {
412 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
413 "Failed to get source realtime timestamp: %s", strerror(-r));
414 return r;
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 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
433 "Failed to get realtime timestamp: %s", strerror(-r));
434 return r;
435 }
436 }
437
438 r = sd_journal_get_cursor(j, &cursor);
439 if (r < 0)
440 return log_error_errno(r, "Failed to get cursor: %m");
441
442 fprintf(f, "%s [%s]\n",
443 flags & OUTPUT_UTC ?
444 format_timestamp_us_utc(ts, sizeof(ts), realtime) :
445 format_timestamp_us(ts, sizeof(ts), realtime),
446 cursor);
447
448 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
449 const char *c;
450 int fieldlen;
451 const char *on = "", *off = "";
452
453 c = memchr(data, '=', length);
454 if (!c) {
455 log_error("Invalid field.");
456 return -EINVAL;
457 }
458 fieldlen = c - (const char*) data;
459
460 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
461 on = ANSI_HIGHLIGHT_ON;
462 off = ANSI_HIGHLIGHT_OFF;
463 }
464
465 if (flags & OUTPUT_SHOW_ALL ||
466 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
467 && utf8_is_printable(data, length))) {
468 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
469 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
470 fputs(off, f);
471 } else {
472 char bytes[FORMAT_BYTES_MAX];
473
474 fprintf(f, " %s%.*s=[%s blob data]%s\n",
475 on,
476 (int) (c - (const char*) data),
477 (const char*) data,
478 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
479 off);
480 }
481 }
482
483 if (r < 0)
484 return r;
485
486 if (flags & OUTPUT_CATALOG)
487 print_catalog(f, j);
488
489 return 0;
490 }
491
492 static int output_export(
493 FILE *f,
494 sd_journal *j,
495 OutputMode mode,
496 unsigned n_columns,
497 OutputFlags flags) {
498
499 sd_id128_t boot_id;
500 char sid[33];
501 int r;
502 usec_t realtime, monotonic;
503 _cleanup_free_ char *cursor = NULL;
504 const void *data;
505 size_t length;
506
507 assert(j);
508
509 sd_journal_set_data_threshold(j, 0);
510
511 r = sd_journal_get_realtime_usec(j, &realtime);
512 if (r < 0)
513 return log_error_errno(r, "Failed to get realtime timestamp: %m");
514
515 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
516 if (r < 0)
517 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
518
519 r = sd_journal_get_cursor(j, &cursor);
520 if (r < 0)
521 return log_error_errno(r, "Failed to get cursor: %m");
522
523 fprintf(f,
524 "__CURSOR=%s\n"
525 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
526 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
527 "_BOOT_ID=%s\n",
528 cursor,
529 realtime,
530 monotonic,
531 sd_id128_to_string(boot_id, sid));
532
533 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
534
535 /* We already printed the boot id, from the data in
536 * the header, hence let's suppress it here */
537 if (length >= 9 &&
538 startswith(data, "_BOOT_ID="))
539 continue;
540
541 if (utf8_is_printable_newline(data, length, false))
542 fwrite(data, length, 1, f);
543 else {
544 const char *c;
545 uint64_t le64;
546
547 c = memchr(data, '=', length);
548 if (!c) {
549 log_error("Invalid field.");
550 return -EINVAL;
551 }
552
553 fwrite(data, c - (const char*) data, 1, f);
554 fputc('\n', f);
555 le64 = htole64(length - (c - (const char*) data) - 1);
556 fwrite(&le64, sizeof(le64), 1, f);
557 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
558 }
559
560 fputc('\n', f);
561 }
562
563 if (r < 0)
564 return r;
565
566 fputc('\n', f);
567
568 return 0;
569 }
570
571 void json_escape(
572 FILE *f,
573 const char* p,
574 size_t l,
575 OutputFlags flags) {
576
577 assert(f);
578 assert(p);
579
580 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
581
582 fputs("null", f);
583
584 else if (!utf8_is_printable(p, l)) {
585 bool not_first = false;
586
587 fputs("[ ", f);
588
589 while (l > 0) {
590 if (not_first)
591 fprintf(f, ", %u", (uint8_t) *p);
592 else {
593 not_first = true;
594 fprintf(f, "%u", (uint8_t) *p);
595 }
596
597 p++;
598 l--;
599 }
600
601 fputs(" ]", f);
602 } else {
603 fputc('\"', f);
604
605 while (l > 0) {
606 if (*p == '"' || *p == '\\') {
607 fputc('\\', f);
608 fputc(*p, f);
609 } else if (*p == '\n')
610 fputs("\\n", f);
611 else if (*p < ' ')
612 fprintf(f, "\\u%04x", *p);
613 else
614 fputc(*p, f);
615
616 p++;
617 l--;
618 }
619
620 fputc('\"', f);
621 }
622 }
623
624 static int output_json(
625 FILE *f,
626 sd_journal *j,
627 OutputMode mode,
628 unsigned n_columns,
629 OutputFlags flags) {
630
631 uint64_t realtime, monotonic;
632 _cleanup_free_ char *cursor = NULL;
633 const void *data;
634 size_t length;
635 sd_id128_t boot_id;
636 char sid[33], *k;
637 int r;
638 Hashmap *h = NULL;
639 bool done, separator;
640
641 assert(j);
642
643 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
644
645 r = sd_journal_get_realtime_usec(j, &realtime);
646 if (r < 0)
647 return log_error_errno(r, "Failed to get realtime timestamp: %m");
648
649 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
650 if (r < 0)
651 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
652
653 r = sd_journal_get_cursor(j, &cursor);
654 if (r < 0)
655 return log_error_errno(r, "Failed to get cursor: %m");
656
657 if (mode == OUTPUT_JSON_PRETTY)
658 fprintf(f,
659 "{\n"
660 "\t\"__CURSOR\" : \"%s\",\n"
661 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
662 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
663 "\t\"_BOOT_ID\" : \"%s\"",
664 cursor,
665 realtime,
666 monotonic,
667 sd_id128_to_string(boot_id, sid));
668 else {
669 if (mode == OUTPUT_JSON_SSE)
670 fputs("data: ", f);
671
672 fprintf(f,
673 "{ \"__CURSOR\" : \"%s\", "
674 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
675 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
676 "\"_BOOT_ID\" : \"%s\"",
677 cursor,
678 realtime,
679 monotonic,
680 sd_id128_to_string(boot_id, sid));
681 }
682
683 h = hashmap_new(&string_hash_ops);
684 if (!h)
685 return -ENOMEM;
686
687 /* First round, iterate through the entry and count how often each field appears */
688 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
689 const char *eq;
690 char *n;
691 unsigned u;
692
693 if (length >= 9 &&
694 memcmp(data, "_BOOT_ID=", 9) == 0)
695 continue;
696
697 eq = memchr(data, '=', length);
698 if (!eq)
699 continue;
700
701 n = strndup(data, eq - (const char*) data);
702 if (!n) {
703 r = -ENOMEM;
704 goto finish;
705 }
706
707 u = PTR_TO_UINT(hashmap_get(h, n));
708 if (u == 0) {
709 r = hashmap_put(h, n, UINT_TO_PTR(1));
710 if (r < 0) {
711 free(n);
712 goto finish;
713 }
714 } else {
715 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
716 free(n);
717 if (r < 0)
718 goto finish;
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 = -ENOMEM;
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 goto finish;
952
953 r = sd_journal_previous_skip(j, how_many);
954 if (r < 0)
955 goto finish;
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 goto finish;
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 goto finish;
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 goto finish;
992 }
993
994 if (warn_cutoff && line < how_many && not_before > 0) {
995 sd_id128_t boot_id;
996 usec_t cutoff;
997
998 /* Check whether the cutoff line is too early */
999
1000 r = sd_id128_get_boot(&boot_id);
1001 if (r < 0)
1002 goto finish;
1003
1004 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1005 if (r < 0)
1006 goto finish;
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 goto finish;
1022
1023 }
1024
1025 finish:
1026 return r;
1027 }
1028
1029 int add_matches_for_unit(sd_journal *j, const char *unit) {
1030 int r;
1031 char *m1, *m2, *m3, *m4;
1032
1033 assert(j);
1034 assert(unit);
1035
1036 m1 = strappenda("_SYSTEMD_UNIT=", unit);
1037 m2 = strappenda("COREDUMP_UNIT=", unit);
1038 m3 = strappenda("UNIT=", unit);
1039 m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
1040
1041 (void)(
1042 /* Look for messages from the service itself */
1043 (r = sd_journal_add_match(j, m1, 0)) ||
1044
1045 /* Look for coredumps of the service */
1046 (r = sd_journal_add_disjunction(j)) ||
1047 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1048 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1049 (r = sd_journal_add_match(j, m2, 0)) ||
1050
1051 /* Look for messages from PID 1 about this service */
1052 (r = sd_journal_add_disjunction(j)) ||
1053 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1054 (r = sd_journal_add_match(j, m3, 0)) ||
1055
1056 /* Look for messages from authorized daemons about this service */
1057 (r = sd_journal_add_disjunction(j)) ||
1058 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1059 (r = sd_journal_add_match(j, m4, 0))
1060 );
1061
1062 if (r == 0 && endswith(unit, ".slice")) {
1063 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1064
1065 /* Show all messages belonging to a slice */
1066 (void)(
1067 (r = sd_journal_add_disjunction(j)) ||
1068 (r = sd_journal_add_match(j, m5, 0))
1069 );
1070 }
1071
1072 return r;
1073 }
1074
1075 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1076 int r;
1077 char *m1, *m2, *m3, *m4;
1078 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1079
1080 assert(j);
1081 assert(unit);
1082
1083 m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
1084 m2 = strappenda("USER_UNIT=", unit);
1085 m3 = strappenda("COREDUMP_USER_UNIT=", unit);
1086 m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
1087 sprintf(muid, "_UID="UID_FMT, uid);
1088
1089 (void) (
1090 /* Look for messages from the user service itself */
1091 (r = sd_journal_add_match(j, m1, 0)) ||
1092 (r = sd_journal_add_match(j, muid, 0)) ||
1093
1094 /* Look for messages from systemd about this service */
1095 (r = sd_journal_add_disjunction(j)) ||
1096 (r = sd_journal_add_match(j, m2, 0)) ||
1097 (r = sd_journal_add_match(j, muid, 0)) ||
1098
1099 /* Look for coredumps of the service */
1100 (r = sd_journal_add_disjunction(j)) ||
1101 (r = sd_journal_add_match(j, m3, 0)) ||
1102 (r = sd_journal_add_match(j, muid, 0)) ||
1103 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1104
1105 /* Look for messages from authorized daemons about this service */
1106 (r = sd_journal_add_disjunction(j)) ||
1107 (r = sd_journal_add_match(j, m4, 0)) ||
1108 (r = sd_journal_add_match(j, muid, 0)) ||
1109 (r = sd_journal_add_match(j, "_UID=0", 0))
1110 );
1111
1112 if (r == 0 && endswith(unit, ".slice")) {
1113 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1114
1115 /* Show all messages belonging to a slice */
1116 (void)(
1117 (r = sd_journal_add_disjunction(j)) ||
1118 (r = sd_journal_add_match(j, m5, 0)) ||
1119 (r = sd_journal_add_match(j, muid, 0))
1120 );
1121 }
1122
1123 return r;
1124 }
1125
1126 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1127 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1128 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1129 pid_t pid, child;
1130 siginfo_t si;
1131 char buf[37];
1132 ssize_t k;
1133 int r;
1134
1135 assert(machine);
1136 assert(boot_id);
1137
1138 if (!machine_name_is_valid(machine))
1139 return -EINVAL;
1140
1141 r = container_get_leader(machine, &pid);
1142 if (r < 0)
1143 return r;
1144
1145 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1146 if (r < 0)
1147 return r;
1148
1149 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1150 return -errno;
1151
1152 child = fork();
1153 if (child < 0)
1154 return -errno;
1155
1156 if (child == 0) {
1157 int fd;
1158
1159 pair[0] = safe_close(pair[0]);
1160
1161 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1162 if (r < 0)
1163 _exit(EXIT_FAILURE);
1164
1165 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1166 if (fd < 0)
1167 _exit(EXIT_FAILURE);
1168
1169 k = loop_read(fd, buf, 36, false);
1170 safe_close(fd);
1171 if (k != 36)
1172 _exit(EXIT_FAILURE);
1173
1174 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1175 if (k != 36)
1176 _exit(EXIT_FAILURE);
1177
1178 _exit(EXIT_SUCCESS);
1179 }
1180
1181 pair[1] = safe_close(pair[1]);
1182
1183 r = wait_for_terminate(child, &si);
1184 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1185 return r < 0 ? r : -EIO;
1186
1187 k = recv(pair[0], buf, 36, 0);
1188 if (k != 36)
1189 return -EIO;
1190
1191 buf[36] = 0;
1192 r = sd_id128_from_string(buf, boot_id);
1193 if (r < 0)
1194 return r;
1195
1196 return 0;
1197 }
1198
1199 int add_match_this_boot(sd_journal *j, const char *machine) {
1200 char match[9+32+1] = "_BOOT_ID=";
1201 sd_id128_t boot_id;
1202 int r;
1203
1204 assert(j);
1205
1206 if (machine) {
1207 r = get_boot_id_for_machine(machine, &boot_id);
1208 if (r < 0)
1209 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
1210 } else {
1211 r = sd_id128_get_boot(&boot_id);
1212 if (r < 0)
1213 return log_error_errno(r, "Failed to get boot id: %m");
1214 }
1215
1216 sd_id128_to_string(boot_id, match + 9);
1217 r = sd_journal_add_match(j, match, strlen(match));
1218 if (r < 0)
1219 return log_error_errno(r, "Failed to add match: %m");
1220
1221 r = sd_journal_add_conjunction(j);
1222 if (r < 0)
1223 return r;
1224
1225 return 0;
1226 }
1227
1228 int show_journal_by_unit(
1229 FILE *f,
1230 const char *unit,
1231 OutputMode mode,
1232 unsigned n_columns,
1233 usec_t not_before,
1234 unsigned how_many,
1235 uid_t uid,
1236 OutputFlags flags,
1237 bool system,
1238 bool *ellipsized) {
1239
1240 _cleanup_journal_close_ sd_journal*j = NULL;
1241 int r;
1242 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1243
1244 assert(mode >= 0);
1245 assert(mode < _OUTPUT_MODE_MAX);
1246 assert(unit);
1247
1248 if (how_many <= 0)
1249 return 0;
1250
1251 r = sd_journal_open(&j, jflags);
1252 if (r < 0)
1253 return r;
1254
1255 r = add_match_this_boot(j, NULL);
1256 if (r < 0)
1257 return r;
1258
1259 if (system)
1260 r = add_matches_for_unit(j, unit);
1261 else
1262 r = add_matches_for_user_unit(j, unit, uid);
1263 if (r < 0)
1264 return r;
1265
1266 if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1267 _cleanup_free_ char *filter;
1268
1269 filter = journal_make_match_string(j);
1270 log_debug("Journal filter: %s", filter);
1271 }
1272
1273 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1274 }
1275
1276 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1277 [OUTPUT_SHORT] = "short",
1278 [OUTPUT_SHORT_ISO] = "short-iso",
1279 [OUTPUT_SHORT_PRECISE] = "short-precise",
1280 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1281 [OUTPUT_VERBOSE] = "verbose",
1282 [OUTPUT_EXPORT] = "export",
1283 [OUTPUT_JSON] = "json",
1284 [OUTPUT_JSON_PRETTY] = "json-pretty",
1285 [OUTPUT_JSON_SSE] = "json-sse",
1286 [OUTPUT_CAT] = "cat"
1287 };
1288
1289 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);