]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/shared/logs-show.c
shared: add process-util.[ch]
[thirdparty/systemd.git] / src / shared / logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4 This file is part of systemd.
5
6 Copyright 2012 Lennart Poettering
7
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
12
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <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
37 /* up to three lines (each up to 100 characters),
38 or 300 characters, whichever is less */
39 #define PRINT_LINE_THRESHOLD 3
40 #define PRINT_CHAR_THRESHOLD 300
41
42 #define JSON_THRESHOLD 4096
43
44 static int print_catalog(FILE *f, sd_journal *j) {
45 int r;
46 _cleanup_free_ char *t = NULL, *z = NULL;
47
48
49 r = sd_journal_get_catalog(j, &t);
50 if (r < 0)
51 return r;
52
53 z = strreplace(strstrip(t), "\n", "\n-- ");
54 if (!z)
55 return log_oom();
56
57 fputs("-- ", f);
58 fputs(z, f);
59 fputc('\n', f);
60
61 return 0;
62 }
63
64 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
65 size_t fl, nl;
66 void *buf;
67
68 assert(data);
69 assert(field);
70 assert(target);
71 assert(target_size);
72
73 fl = strlen(field);
74 if (length < fl)
75 return 0;
76
77 if (memcmp(data, field, fl))
78 return 0;
79
80 nl = length - fl;
81 buf = malloc(nl+1);
82 if (!buf)
83 return log_oom();
84
85 memcpy(buf, (const char*) data + fl, nl);
86 ((char*)buf)[nl] = 0;
87
88 free(*target);
89 *target = buf;
90 *target_size = nl;
91
92 return 1;
93 }
94
95 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
96 assert(p);
97
98 if (flags & OUTPUT_SHOW_ALL)
99 return true;
100
101 if (l >= PRINT_CHAR_THRESHOLD)
102 return false;
103
104 if (!utf8_is_printable(p, l))
105 return false;
106
107 return true;
108 }
109
110 static bool print_multiline(FILE *f, unsigned prefix, unsigned n_columns, OutputFlags flags, int priority, const char* message, size_t message_len) {
111 const char *color_on = "", *color_off = "";
112 const char *pos, *end;
113 bool ellipsized = false;
114 int line = 0;
115
116 if (flags & OUTPUT_COLOR) {
117 if (priority <= LOG_ERR) {
118 color_on = ANSI_HIGHLIGHT_RED_ON;
119 color_off = ANSI_HIGHLIGHT_OFF;
120 } else if (priority <= LOG_NOTICE) {
121 color_on = ANSI_HIGHLIGHT_ON;
122 color_off = ANSI_HIGHLIGHT_OFF;
123 }
124 }
125
126 /* A special case: make sure that we print a newline when
127 the message is empty. */
128 if (message_len == 0)
129 fputs("\n", f);
130
131 for (pos = message;
132 pos < message + message_len;
133 pos = end + 1, line++) {
134 bool continuation = line > 0;
135 bool tail_line;
136 int len;
137 for (end = pos; end < message + message_len && *end != '\n'; end++)
138 ;
139 len = end - pos;
140 assert(len >= 0);
141
142 /* We need to figure out when we are showing not-last line, *and*
143 * will skip subsequent lines. In that case, we will put the dots
144 * at the end of the line, instead of putting dots in the middle
145 * or not at all.
146 */
147 tail_line =
148 line + 1 == PRINT_LINE_THRESHOLD ||
149 end + 1 >= message + PRINT_CHAR_THRESHOLD;
150
151 if (flags & (OUTPUT_FULL_WIDTH | OUTPUT_SHOW_ALL) ||
152 (prefix + len + 1 < n_columns && !tail_line)) {
153 fprintf(f, "%*s%s%.*s%s\n",
154 continuation * prefix, "",
155 color_on, len, pos, color_off);
156 continue;
157 }
158
159 /* Beyond this point, ellipsization will happen. */
160 ellipsized = true;
161
162 if (prefix < n_columns && n_columns - prefix >= 3) {
163 if (n_columns - prefix > (unsigned) len + 3)
164 fprintf(f, "%*s%s%.*s...%s\n",
165 continuation * prefix, "",
166 color_on, len, pos, color_off);
167 else {
168 _cleanup_free_ char *e;
169
170 e = ellipsize_mem(pos, len, n_columns - prefix,
171 tail_line ? 100 : 90);
172 if (!e)
173 fprintf(f, "%*s%s%.*s%s\n",
174 continuation * prefix, "",
175 color_on, len, pos, color_off);
176 else
177 fprintf(f, "%*s%s%s%s\n",
178 continuation * prefix, "",
179 color_on, e, color_off);
180 }
181 } else
182 fputs("...\n", f);
183
184 if (tail_line)
185 break;
186 }
187
188 return ellipsized;
189 }
190
191 static int output_short(
192 FILE *f,
193 sd_journal *j,
194 OutputMode mode,
195 unsigned n_columns,
196 OutputFlags flags) {
197
198 int r;
199 const void *data;
200 size_t length;
201 size_t n = 0;
202 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
203 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;
204 int p = LOG_INFO;
205 bool ellipsized = false;
206
207 assert(f);
208 assert(j);
209
210 /* Set the threshold to one bigger than the actual print
211 * threshold, so that if the line is actually longer than what
212 * we're willing to print, ellipsization will occur. This way
213 * we won't output a misleading line without any indication of
214 * truncation.
215 */
216 sd_journal_set_data_threshold(j, flags & (OUTPUT_SHOW_ALL|OUTPUT_FULL_WIDTH) ? 0 : PRINT_CHAR_THRESHOLD + 1);
217
218 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
219
220 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
221 if (r < 0)
222 return r;
223 else if (r > 0)
224 continue;
225
226 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
227 if (r < 0)
228 return r;
229 else if (r > 0)
230 continue;
231
232 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
233 if (r < 0)
234 return r;
235 else if (r > 0)
236 continue;
237
238 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
239 if (r < 0)
240 return r;
241 else if (r > 0)
242 continue;
243
244 r = parse_field(data, length, "_PID=", &pid, &pid_len);
245 if (r < 0)
246 return r;
247 else if (r > 0)
248 continue;
249
250 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
251 if (r < 0)
252 return r;
253 else if (r > 0)
254 continue;
255
256 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
257 if (r < 0)
258 return r;
259 else if (r > 0)
260 continue;
261
262 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
263 if (r < 0)
264 return r;
265 else if (r > 0)
266 continue;
267
268 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
269 if (r < 0)
270 return r;
271 }
272
273 if (r < 0)
274 return r;
275
276 if (!message)
277 return 0;
278
279 if (!(flags & OUTPUT_SHOW_ALL))
280 strip_tab_ansi(&message, &message_len);
281
282 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
283 p = *priority - '0';
284
285 if (mode == OUTPUT_SHORT_MONOTONIC) {
286 uint64_t t;
287 sd_id128_t boot_id;
288
289 r = -ENOENT;
290
291 if (monotonic)
292 r = safe_atou64(monotonic, &t);
293
294 if (r < 0)
295 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
296
297 if (r < 0)
298 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
299
300 fprintf(f, "[%5llu.%06llu]",
301 (unsigned long long) (t / USEC_PER_SEC),
302 (unsigned long long) (t % USEC_PER_SEC));
303
304 n += 1 + 5 + 1 + 6 + 1;
305
306 } else {
307 char buf[64];
308 uint64_t x;
309 time_t t;
310 struct tm tm;
311 struct tm *(*gettime_r)(const time_t *, struct tm *);
312
313 r = -ENOENT;
314 gettime_r = (flags & OUTPUT_UTC) ? gmtime_r : localtime_r;
315
316 if (realtime)
317 r = safe_atou64(realtime, &x);
318
319 if (r < 0)
320 r = sd_journal_get_realtime_usec(j, &x);
321
322 if (r < 0)
323 return log_error_errno(r, "Failed to get realtime timestamp: %m");
324
325 t = (time_t) (x / USEC_PER_SEC);
326
327 switch(mode) {
328 case OUTPUT_SHORT_ISO:
329 r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", gettime_r(&t, &tm));
330 break;
331 case OUTPUT_SHORT_PRECISE:
332 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
333 if (r > 0) {
334 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
335 ".%06llu", (unsigned long long) (x % USEC_PER_SEC));
336 }
337 break;
338 default:
339 r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", gettime_r(&t, &tm));
340 }
341
342 if (r <= 0) {
343 log_error("Failed to format time.");
344 return -EINVAL;
345 }
346
347 fputs(buf, f);
348 n += strlen(buf);
349 }
350
351 if (hostname && shall_print(hostname, hostname_len, flags)) {
352 fprintf(f, " %.*s", (int) hostname_len, hostname);
353 n += hostname_len + 1;
354 }
355
356 if (identifier && shall_print(identifier, identifier_len, flags)) {
357 fprintf(f, " %.*s", (int) identifier_len, identifier);
358 n += identifier_len + 1;
359 } else if (comm && shall_print(comm, comm_len, flags)) {
360 fprintf(f, " %.*s", (int) comm_len, comm);
361 n += comm_len + 1;
362 } else
363 fputs(" unknown", f);
364
365 if (pid && shall_print(pid, pid_len, flags)) {
366 fprintf(f, "[%.*s]", (int) pid_len, pid);
367 n += pid_len + 2;
368 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
369 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
370 n += fake_pid_len + 2;
371 }
372
373 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
374 char bytes[FORMAT_BYTES_MAX];
375 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
376 } else {
377 fputs(": ", f);
378 ellipsized |=
379 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
380 }
381
382 if (flags & OUTPUT_CATALOG)
383 print_catalog(f, j);
384
385 return ellipsized;
386 }
387
388 static int output_verbose(
389 FILE *f,
390 sd_journal *j,
391 OutputMode mode,
392 unsigned n_columns,
393 OutputFlags flags) {
394
395 const void *data;
396 size_t length;
397 _cleanup_free_ char *cursor = NULL;
398 uint64_t realtime;
399 char ts[FORMAT_TIMESTAMP_MAX + 7];
400 int r;
401
402 assert(f);
403 assert(j);
404
405 sd_journal_set_data_threshold(j, 0);
406
407 r = sd_journal_get_data(j, "_SOURCE_REALTIME_TIMESTAMP", &data, &length);
408 if (r == -ENOENT)
409 log_debug("Source realtime timestamp not found");
410 else if (r < 0) {
411 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
412 "Failed to get source realtime timestamp: %s", strerror(-r));
413 return r;
414 } else {
415 _cleanup_free_ char *value = NULL;
416 size_t size;
417
418 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &value, &size);
419 if (r < 0)
420 log_debug_errno(r, "_SOURCE_REALTIME_TIMESTAMP invalid: %m");
421 else {
422 r = safe_atou64(value, &realtime);
423 if (r < 0)
424 log_debug_errno(r, "Failed to parse realtime timestamp: %m");
425 }
426 }
427
428 if (r < 0) {
429 r = sd_journal_get_realtime_usec(j, &realtime);
430 if (r < 0) {
431 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
432 "Failed to get realtime timestamp: %s", strerror(-r));
433 return r;
434 }
435 }
436
437 r = sd_journal_get_cursor(j, &cursor);
438 if (r < 0)
439 return log_error_errno(r, "Failed to get cursor: %m");
440
441 fprintf(f, "%s [%s]\n",
442 flags & OUTPUT_UTC ?
443 format_timestamp_us_utc(ts, sizeof(ts), realtime) :
444 format_timestamp_us(ts, sizeof(ts), realtime),
445 cursor);
446
447 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
448 const char *c;
449 int fieldlen;
450 const char *on = "", *off = "";
451
452 c = memchr(data, '=', length);
453 if (!c) {
454 log_error("Invalid field.");
455 return -EINVAL;
456 }
457 fieldlen = c - (const char*) data;
458
459 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
460 on = ANSI_HIGHLIGHT_ON;
461 off = ANSI_HIGHLIGHT_OFF;
462 }
463
464 if (flags & OUTPUT_SHOW_ALL ||
465 (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
466 && utf8_is_printable(data, length))) {
467 fprintf(f, " %s%.*s=", on, fieldlen, (const char*)data);
468 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
469 fputs(off, f);
470 } else {
471 char bytes[FORMAT_BYTES_MAX];
472
473 fprintf(f, " %s%.*s=[%s blob data]%s\n",
474 on,
475 (int) (c - (const char*) data),
476 (const char*) data,
477 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
478 off);
479 }
480 }
481
482 if (r < 0)
483 return r;
484
485 if (flags & OUTPUT_CATALOG)
486 print_catalog(f, j);
487
488 return 0;
489 }
490
491 static int output_export(
492 FILE *f,
493 sd_journal *j,
494 OutputMode mode,
495 unsigned n_columns,
496 OutputFlags flags) {
497
498 sd_id128_t boot_id;
499 char sid[33];
500 int r;
501 usec_t realtime, monotonic;
502 _cleanup_free_ char *cursor = NULL;
503 const void *data;
504 size_t length;
505
506 assert(j);
507
508 sd_journal_set_data_threshold(j, 0);
509
510 r = sd_journal_get_realtime_usec(j, &realtime);
511 if (r < 0)
512 return log_error_errno(r, "Failed to get realtime timestamp: %m");
513
514 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
515 if (r < 0)
516 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
517
518 r = sd_journal_get_cursor(j, &cursor);
519 if (r < 0)
520 return log_error_errno(r, "Failed to get cursor: %m");
521
522 fprintf(f,
523 "__CURSOR=%s\n"
524 "__REALTIME_TIMESTAMP="USEC_FMT"\n"
525 "__MONOTONIC_TIMESTAMP="USEC_FMT"\n"
526 "_BOOT_ID=%s\n",
527 cursor,
528 realtime,
529 monotonic,
530 sd_id128_to_string(boot_id, sid));
531
532 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
533
534 /* We already printed the boot id, from the data in
535 * the header, hence let's suppress it here */
536 if (length >= 9 &&
537 startswith(data, "_BOOT_ID="))
538 continue;
539
540 if (utf8_is_printable_newline(data, length, false))
541 fwrite(data, length, 1, f);
542 else {
543 const char *c;
544 uint64_t le64;
545
546 c = memchr(data, '=', length);
547 if (!c) {
548 log_error("Invalid field.");
549 return -EINVAL;
550 }
551
552 fwrite(data, c - (const char*) data, 1, f);
553 fputc('\n', f);
554 le64 = htole64(length - (c - (const char*) data) - 1);
555 fwrite(&le64, sizeof(le64), 1, f);
556 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
557 }
558
559 fputc('\n', f);
560 }
561
562 if (r < 0)
563 return r;
564
565 fputc('\n', f);
566
567 return 0;
568 }
569
570 void json_escape(
571 FILE *f,
572 const char* p,
573 size_t l,
574 OutputFlags flags) {
575
576 assert(f);
577 assert(p);
578
579 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
580
581 fputs("null", f);
582
583 else if (!utf8_is_printable(p, l)) {
584 bool not_first = false;
585
586 fputs("[ ", f);
587
588 while (l > 0) {
589 if (not_first)
590 fprintf(f, ", %u", (uint8_t) *p);
591 else {
592 not_first = true;
593 fprintf(f, "%u", (uint8_t) *p);
594 }
595
596 p++;
597 l--;
598 }
599
600 fputs(" ]", f);
601 } else {
602 fputc('\"', f);
603
604 while (l > 0) {
605 if (*p == '"' || *p == '\\') {
606 fputc('\\', f);
607 fputc(*p, f);
608 } else if (*p == '\n')
609 fputs("\\n", f);
610 else if (*p < ' ')
611 fprintf(f, "\\u%04x", *p);
612 else
613 fputc(*p, f);
614
615 p++;
616 l--;
617 }
618
619 fputc('\"', f);
620 }
621 }
622
623 static int output_json(
624 FILE *f,
625 sd_journal *j,
626 OutputMode mode,
627 unsigned n_columns,
628 OutputFlags flags) {
629
630 uint64_t realtime, monotonic;
631 _cleanup_free_ char *cursor = NULL;
632 const void *data;
633 size_t length;
634 sd_id128_t boot_id;
635 char sid[33], *k;
636 int r;
637 Hashmap *h = NULL;
638 bool done, separator;
639
640 assert(j);
641
642 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
643
644 r = sd_journal_get_realtime_usec(j, &realtime);
645 if (r < 0)
646 return log_error_errno(r, "Failed to get realtime timestamp: %m");
647
648 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
649 if (r < 0)
650 return log_error_errno(r, "Failed to get monotonic timestamp: %m");
651
652 r = sd_journal_get_cursor(j, &cursor);
653 if (r < 0)
654 return log_error_errno(r, "Failed to get cursor: %m");
655
656 if (mode == OUTPUT_JSON_PRETTY)
657 fprintf(f,
658 "{\n"
659 "\t\"__CURSOR\" : \"%s\",\n"
660 "\t\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\",\n"
661 "\t\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\",\n"
662 "\t\"_BOOT_ID\" : \"%s\"",
663 cursor,
664 realtime,
665 monotonic,
666 sd_id128_to_string(boot_id, sid));
667 else {
668 if (mode == OUTPUT_JSON_SSE)
669 fputs("data: ", f);
670
671 fprintf(f,
672 "{ \"__CURSOR\" : \"%s\", "
673 "\"__REALTIME_TIMESTAMP\" : \""USEC_FMT"\", "
674 "\"__MONOTONIC_TIMESTAMP\" : \""USEC_FMT"\", "
675 "\"_BOOT_ID\" : \"%s\"",
676 cursor,
677 realtime,
678 monotonic,
679 sd_id128_to_string(boot_id, sid));
680 }
681
682 h = hashmap_new(&string_hash_ops);
683 if (!h)
684 return -ENOMEM;
685
686 /* First round, iterate through the entry and count how often each field appears */
687 JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
688 const char *eq;
689 char *n;
690 unsigned u;
691
692 if (length >= 9 &&
693 memcmp(data, "_BOOT_ID=", 9) == 0)
694 continue;
695
696 eq = memchr(data, '=', length);
697 if (!eq)
698 continue;
699
700 n = strndup(data, eq - (const char*) data);
701 if (!n) {
702 r = -ENOMEM;
703 goto finish;
704 }
705
706 u = PTR_TO_UINT(hashmap_get(h, n));
707 if (u == 0) {
708 r = hashmap_put(h, n, UINT_TO_PTR(1));
709 if (r < 0) {
710 free(n);
711 goto finish;
712 }
713 } else {
714 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
715 free(n);
716 if (r < 0)
717 goto finish;
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 = -ENOMEM;
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 goto finish;
951
952 r = sd_journal_previous_skip(j, how_many);
953 if (r < 0)
954 goto finish;
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 goto finish;
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 goto finish;
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 goto finish;
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 goto finish;
1002
1003 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
1004 if (r < 0)
1005 goto finish;
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 goto finish;
1021
1022 }
1023
1024 finish:
1025 return r;
1026 }
1027
1028 int add_matches_for_unit(sd_journal *j, const char *unit) {
1029 int r;
1030 char *m1, *m2, *m3, *m4;
1031
1032 assert(j);
1033 assert(unit);
1034
1035 m1 = strjoina("_SYSTEMD_UNIT=", unit);
1036 m2 = strjoina("COREDUMP_UNIT=", unit);
1037 m3 = strjoina("UNIT=", unit);
1038 m4 = strjoina("OBJECT_SYSTEMD_UNIT=", unit);
1039
1040 (void)(
1041 /* Look for messages from the service itself */
1042 (r = sd_journal_add_match(j, m1, 0)) ||
1043
1044 /* Look for coredumps of the service */
1045 (r = sd_journal_add_disjunction(j)) ||
1046 (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1047 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1048 (r = sd_journal_add_match(j, m2, 0)) ||
1049
1050 /* Look for messages from PID 1 about this service */
1051 (r = sd_journal_add_disjunction(j)) ||
1052 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1053 (r = sd_journal_add_match(j, m3, 0)) ||
1054
1055 /* Look for messages from authorized daemons about this service */
1056 (r = sd_journal_add_disjunction(j)) ||
1057 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1058 (r = sd_journal_add_match(j, m4, 0))
1059 );
1060
1061 if (r == 0 && endswith(unit, ".slice")) {
1062 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1063
1064 /* Show all messages belonging to a slice */
1065 (void)(
1066 (r = sd_journal_add_disjunction(j)) ||
1067 (r = sd_journal_add_match(j, m5, 0))
1068 );
1069 }
1070
1071 return r;
1072 }
1073
1074 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1075 int r;
1076 char *m1, *m2, *m3, *m4;
1077 char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1078
1079 assert(j);
1080 assert(unit);
1081
1082 m1 = strjoina("_SYSTEMD_USER_UNIT=", unit);
1083 m2 = strjoina("USER_UNIT=", unit);
1084 m3 = strjoina("COREDUMP_USER_UNIT=", unit);
1085 m4 = strjoina("OBJECT_SYSTEMD_USER_UNIT=", unit);
1086 sprintf(muid, "_UID="UID_FMT, uid);
1087
1088 (void) (
1089 /* Look for messages from the user service itself */
1090 (r = sd_journal_add_match(j, m1, 0)) ||
1091 (r = sd_journal_add_match(j, muid, 0)) ||
1092
1093 /* Look for messages from systemd about this service */
1094 (r = sd_journal_add_disjunction(j)) ||
1095 (r = sd_journal_add_match(j, m2, 0)) ||
1096 (r = sd_journal_add_match(j, muid, 0)) ||
1097
1098 /* Look for coredumps of the service */
1099 (r = sd_journal_add_disjunction(j)) ||
1100 (r = sd_journal_add_match(j, m3, 0)) ||
1101 (r = sd_journal_add_match(j, muid, 0)) ||
1102 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1103
1104 /* Look for messages from authorized daemons about this service */
1105 (r = sd_journal_add_disjunction(j)) ||
1106 (r = sd_journal_add_match(j, m4, 0)) ||
1107 (r = sd_journal_add_match(j, muid, 0)) ||
1108 (r = sd_journal_add_match(j, "_UID=0", 0))
1109 );
1110
1111 if (r == 0 && endswith(unit, ".slice")) {
1112 char *m5 = strappend("_SYSTEMD_SLICE=", unit);
1113
1114 /* Show all messages belonging to a slice */
1115 (void)(
1116 (r = sd_journal_add_disjunction(j)) ||
1117 (r = sd_journal_add_match(j, m5, 0)) ||
1118 (r = sd_journal_add_match(j, muid, 0))
1119 );
1120 }
1121
1122 return r;
1123 }
1124
1125 static int get_boot_id_for_machine(const char *machine, sd_id128_t *boot_id) {
1126 _cleanup_close_pair_ int pair[2] = { -1, -1 };
1127 _cleanup_close_ int pidnsfd = -1, mntnsfd = -1, rootfd = -1;
1128 pid_t pid, child;
1129 siginfo_t si;
1130 char buf[37];
1131 ssize_t k;
1132 int r;
1133
1134 assert(machine);
1135 assert(boot_id);
1136
1137 if (!machine_name_is_valid(machine))
1138 return -EINVAL;
1139
1140 r = container_get_leader(machine, &pid);
1141 if (r < 0)
1142 return r;
1143
1144 r = namespace_open(pid, &pidnsfd, &mntnsfd, NULL, &rootfd);
1145 if (r < 0)
1146 return r;
1147
1148 if (socketpair(AF_UNIX, SOCK_DGRAM, 0, pair) < 0)
1149 return -errno;
1150
1151 child = fork();
1152 if (child < 0)
1153 return -errno;
1154
1155 if (child == 0) {
1156 int fd;
1157
1158 pair[0] = safe_close(pair[0]);
1159
1160 r = namespace_enter(pidnsfd, mntnsfd, -1, rootfd);
1161 if (r < 0)
1162 _exit(EXIT_FAILURE);
1163
1164 fd = open("/proc/sys/kernel/random/boot_id", O_RDONLY|O_CLOEXEC|O_NOCTTY);
1165 if (fd < 0)
1166 _exit(EXIT_FAILURE);
1167
1168 r = loop_read_exact(fd, buf, 36, false);
1169 safe_close(fd);
1170 if (r < 0)
1171 _exit(EXIT_FAILURE);
1172
1173 k = send(pair[1], buf, 36, MSG_NOSIGNAL);
1174 if (k != 36)
1175 _exit(EXIT_FAILURE);
1176
1177 _exit(EXIT_SUCCESS);
1178 }
1179
1180 pair[1] = safe_close(pair[1]);
1181
1182 r = wait_for_terminate(child, &si);
1183 if (r < 0 || si.si_code != CLD_EXITED || si.si_status != EXIT_SUCCESS)
1184 return r < 0 ? r : -EIO;
1185
1186 k = recv(pair[0], buf, 36, 0);
1187 if (k != 36)
1188 return -EIO;
1189
1190 buf[36] = 0;
1191 r = sd_id128_from_string(buf, boot_id);
1192 if (r < 0)
1193 return r;
1194
1195 return 0;
1196 }
1197
1198 int add_match_this_boot(sd_journal *j, const char *machine) {
1199 char match[9+32+1] = "_BOOT_ID=";
1200 sd_id128_t boot_id;
1201 int r;
1202
1203 assert(j);
1204
1205 if (machine) {
1206 r = get_boot_id_for_machine(machine, &boot_id);
1207 if (r < 0)
1208 return log_error_errno(r, "Failed to get boot id of container %s: %m", machine);
1209 } else {
1210 r = sd_id128_get_boot(&boot_id);
1211 if (r < 0)
1212 return log_error_errno(r, "Failed to get boot id: %m");
1213 }
1214
1215 sd_id128_to_string(boot_id, match + 9);
1216 r = sd_journal_add_match(j, match, strlen(match));
1217 if (r < 0)
1218 return log_error_errno(r, "Failed to add match: %m");
1219
1220 r = sd_journal_add_conjunction(j);
1221 if (r < 0)
1222 return r;
1223
1224 return 0;
1225 }
1226
1227 int show_journal_by_unit(
1228 FILE *f,
1229 const char *unit,
1230 OutputMode mode,
1231 unsigned n_columns,
1232 usec_t not_before,
1233 unsigned how_many,
1234 uid_t uid,
1235 OutputFlags flags,
1236 int journal_open_flags,
1237 bool system_unit,
1238 bool *ellipsized) {
1239
1240 _cleanup_journal_close_ sd_journal*j = NULL;
1241 int r;
1242
1243 assert(mode >= 0);
1244 assert(mode < _OUTPUT_MODE_MAX);
1245 assert(unit);
1246
1247 if (how_many <= 0)
1248 return 0;
1249
1250 r = sd_journal_open(&j, journal_open_flags);
1251 if (r < 0)
1252 return r;
1253
1254 r = add_match_this_boot(j, NULL);
1255 if (r < 0)
1256 return r;
1257
1258 if (system_unit)
1259 r = add_matches_for_unit(j, unit);
1260 else
1261 r = add_matches_for_user_unit(j, unit, uid);
1262 if (r < 0)
1263 return r;
1264
1265 if (_unlikely_(log_get_max_level() >= LOG_DEBUG)) {
1266 _cleanup_free_ char *filter;
1267
1268 filter = journal_make_match_string(j);
1269 log_debug("Journal filter: %s", filter);
1270 }
1271
1272 return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1273 }
1274
1275 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1276 [OUTPUT_SHORT] = "short",
1277 [OUTPUT_SHORT_ISO] = "short-iso",
1278 [OUTPUT_SHORT_PRECISE] = "short-precise",
1279 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1280 [OUTPUT_VERBOSE] = "verbose",
1281 [OUTPUT_EXPORT] = "export",
1282 [OUTPUT_JSON] = "json",
1283 [OUTPUT_JSON_PRETTY] = "json-pretty",
1284 [OUTPUT_JSON_SSE] = "json-sse",
1285 [OUTPUT_CAT] = "cat"
1286 };
1287
1288 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);