]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
service: don't report alien child as alive when it's not
[thirdparty/systemd.git] / src / shared / logs-show.c
CommitLineData
86aa7ba4
LP
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
5430f7f2
LP
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
86aa7ba4
LP
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
5430f7f2 16 Lesser General Public License for more details.
86aa7ba4 17
5430f7f2 18 You should have received a copy of the GNU Lesser General Public License
86aa7ba4
LP
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>
df50185b 25#include <sys/poll.h>
55d7bfc1 26#include <string.h>
86aa7ba4
LP
27
28#include "logs-show.h"
29#include "log.h"
30#include "util.h"
ba961854 31#include "utf8.h"
d99ae53a 32#include "hashmap.h"
dfb33a97 33#include "journal-internal.h"
86aa7ba4
LP
34
35#define PRINT_THRESHOLD 128
08ace05b 36#define JSON_THRESHOLD 4096
86aa7ba4 37
d4205751
LP
38static int print_catalog(FILE *f, sd_journal *j) {
39 int r;
40 _cleanup_free_ char *t = NULL, *z = NULL;
41
42
43 r = sd_journal_get_catalog(j, &t);
44 if (r < 0)
45 return r;
46
47 z = strreplace(strstrip(t), "\n", "\n-- ");
48 if (!z)
49 return log_oom();
50
51 fputs("-- ", f);
52 fputs(z, f);
53 fputc('\n', f);
54
55 return 0;
56}
57
55d7bfc1
LP
58static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
59 size_t fl, nl;
60 void *buf;
61
62 assert(data);
63 assert(field);
64 assert(target);
65 assert(target_size);
66
67 fl = strlen(field);
68 if (length < fl)
69 return 0;
70
71 if (memcmp(data, field, fl))
72 return 0;
73
74 nl = length - fl;
bf967366 75 buf = malloc(nl+1);
0d0f0c50
SL
76 if (!buf)
77 return log_oom();
55d7bfc1 78
46b0d922
LP
79 memcpy(buf, (const char*) data + fl, nl);
80 ((char*)buf)[nl] = 0;
81
6c1e6b98 82 free(*target);
55d7bfc1
LP
83 *target = buf;
84 *target_size = nl;
85
86 return 1;
87}
88
08ace05b
LP
89static bool shall_print(const char *p, size_t l, OutputFlags flags) {
90 assert(p);
91
92 if (flags & OUTPUT_SHOW_ALL)
55d7bfc1
LP
93 return true;
94
93b73b06 95 if (l >= PRINT_THRESHOLD)
55d7bfc1
LP
96 return false;
97
31f7bf19 98 if (!utf8_is_printable(p, l))
55d7bfc1
LP
99 return false;
100
101 return true;
102}
103
31f7bf19
ZJS
104static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, int flags, int priority, const char* message, size_t message_len) {
105 const char *color_on = "", *color_off = "";
106 const char *pos, *end;
107 bool continuation = false;
108
109 if (flags & OUTPUT_COLOR) {
110 if (priority <= LOG_ERR) {
111 color_on = ANSI_HIGHLIGHT_RED_ON;
112 color_off = ANSI_HIGHLIGHT_OFF;
113 } else if (priority <= LOG_NOTICE) {
114 color_on = ANSI_HIGHLIGHT_ON;
115 color_off = ANSI_HIGHLIGHT_OFF;
116 }
117 }
118
119 for (pos = message; pos < message + message_len; pos = end + 1) {
120 int len;
121 for (end = pos; end < message + message_len && *end != '\n'; end++)
122 ;
123 len = end - pos;
124 assert(len >= 0);
125
126 if ((flags & OUTPUT_FULL_WIDTH) || (prefix + len + 1 < n_columns))
127 fprintf(f, "%*s%s%.*s%s\n",
128 continuation * prefix, "",
129 color_on, len, pos, color_off);
130 else if (prefix < n_columns && n_columns - prefix >= 3) {
131 _cleanup_free_ char *e;
132
133 e = ellipsize_mem(pos, len, n_columns - prefix, 90);
134
135 if (!e)
136 fprintf(f, "%s%.*s%s\n", color_on, len, pos, color_off);
137 else
138 fprintf(f, "%s%s%s\n", color_on, e, color_off);
139 } else
140 fputs("...\n", f);
141
142 continuation = true;
143 }
144}
145
08ace05b
LP
146static int output_short(
147 FILE *f,
148 sd_journal *j,
149 OutputMode mode,
150 unsigned n_columns,
151 OutputFlags flags) {
152
86aa7ba4 153 int r;
86aa7ba4
LP
154 const void *data;
155 size_t length;
156 size_t n = 0;
08ace05b 157 _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
49826187
LP
158 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;
159 int p = LOG_INFO;
86aa7ba4 160
08ace05b 161 assert(f);
86aa7ba4
LP
162 assert(j);
163
93b73b06
LP
164 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
165
55d7bfc1
LP
166 SD_JOURNAL_FOREACH_DATA(j, data, length) {
167
49826187
LP
168 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
169 if (r < 0)
08ace05b 170 return r;
49826187
LP
171 else if (r > 0)
172 continue;
173
55d7bfc1
LP
174 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
175 if (r < 0)
08ace05b 176 return r;
55d7bfc1
LP
177 else if (r > 0)
178 continue;
179
4cd9a9d9 180 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
55d7bfc1 181 if (r < 0)
08ace05b 182 return r;
55d7bfc1
LP
183 else if (r > 0)
184 continue;
185
186 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
187 if (r < 0)
08ace05b 188 return r;
55d7bfc1
LP
189 else if (r > 0)
190 continue;
191
192 r = parse_field(data, length, "_PID=", &pid, &pid_len);
193 if (r < 0)
08ace05b 194 return r;
55d7bfc1
LP
195 else if (r > 0)
196 continue;
197
6c1e6b98
LP
198 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
199 if (r < 0)
08ace05b 200 return r;
6c1e6b98
LP
201 else if (r > 0)
202 continue;
203
bf967366
LP
204 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
205 if (r < 0)
08ace05b 206 return r;
bf967366
LP
207 else if (r > 0)
208 continue;
209
210 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
211 if (r < 0)
08ace05b 212 return r;
bf967366
LP
213 else if (r > 0)
214 continue;
215
55d7bfc1
LP
216 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
217 if (r < 0)
08ace05b 218 return r;
55d7bfc1
LP
219 }
220
08ace05b
LP
221 if (!message)
222 return 0;
55d7bfc1 223
e8bc0ea2
LP
224 if (!(flags & OUTPUT_SHOW_ALL))
225 strip_tab_ansi(&message, &message_len);
226
49826187
LP
227 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
228 p = *priority - '0';
229
a6e87e90 230 if (mode == OUTPUT_SHORT_MONOTONIC) {
67a12205 231 uint64_t t;
3ebcdf8c
LP
232 sd_id128_t boot_id;
233
bf967366
LP
234 r = -ENOENT;
235
236 if (monotonic)
237 r = safe_atou64(monotonic, &t);
238
239 if (r < 0)
3ebcdf8c 240 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
86aa7ba4 241
3ebcdf8c
LP
242 if (r < 0) {
243 log_error("Failed to get monotonic: %s", strerror(-r));
08ace05b 244 return r;
67a12205
LP
245 }
246
08ace05b
LP
247 fprintf(f, "[%5llu.%06llu]",
248 (unsigned long long) (t / USEC_PER_SEC),
249 (unsigned long long) (t % USEC_PER_SEC));
3ebcdf8c
LP
250
251 n += 1 + 5 + 1 + 6 + 1;
252
67a12205
LP
253 } else {
254 char buf[64];
bf967366 255 uint64_t x;
67a12205
LP
256 time_t t;
257 struct tm tm;
731a676c 258
bf967366
LP
259 r = -ENOENT;
260
261 if (realtime)
262 r = safe_atou64(realtime, &x);
263
264 if (r < 0)
265 r = sd_journal_get_realtime_usec(j, &x);
67a12205 266
67a12205
LP
267 if (r < 0) {
268 log_error("Failed to get realtime: %s", strerror(-r));
08ace05b 269 return r;
67a12205
LP
270 }
271
bf967366 272 t = (time_t) (x / USEC_PER_SEC);
67a12205
LP
273 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
274 log_error("Failed to format time.");
08ace05b 275 return r;
67a12205
LP
276 }
277
08ace05b 278 fputs(buf, f);
67a12205
LP
279 n += strlen(buf);
280 }
86aa7ba4 281
08ace05b
LP
282 if (hostname && shall_print(hostname, hostname_len, flags)) {
283 fprintf(f, " %.*s", (int) hostname_len, hostname);
55d7bfc1
LP
284 n += hostname_len + 1;
285 }
286
08ace05b
LP
287 if (identifier && shall_print(identifier, identifier_len, flags)) {
288 fprintf(f, " %.*s", (int) identifier_len, identifier);
4cd9a9d9 289 n += identifier_len + 1;
08ace05b
LP
290 } else if (comm && shall_print(comm, comm_len, flags)) {
291 fprintf(f, " %.*s", (int) comm_len, comm);
55d7bfc1 292 n += comm_len + 1;
b5936820 293 } else
08ace05b 294 fputc(' ', f);
86aa7ba4 295
08ace05b
LP
296 if (pid && shall_print(pid, pid_len, flags)) {
297 fprintf(f, "[%.*s]", (int) pid_len, pid);
55d7bfc1 298 n += pid_len + 2;
08ace05b
LP
299 } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
300 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
6c1e6b98 301 n += fake_pid_len + 2;
86aa7ba4
LP
302 }
303
31f7bf19 304 if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
e6acda19 305 char bytes[FORMAT_BYTES_MAX];
08ace05b 306 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
31f7bf19
ZJS
307 } else {
308 fputs(": ", f);
309 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
310 }
55d7bfc1 311
d4205751
LP
312 if (flags & OUTPUT_CATALOG)
313 print_catalog(f, j);
314
08ace05b 315 return 0;
86aa7ba4
LP
316}
317
08ace05b
LP
318static int output_verbose(
319 FILE *f,
320 sd_journal *j,
321 OutputMode mode,
322 unsigned n_columns,
323 OutputFlags flags) {
324
86aa7ba4
LP
325 const void *data;
326 size_t length;
7fd1b19b 327 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
328 uint64_t realtime;
329 char ts[FORMAT_TIMESTAMP_MAX];
330 int r;
331
08ace05b 332 assert(f);
86aa7ba4
LP
333 assert(j);
334
93b73b06
LP
335 sd_journal_set_data_threshold(j, 0);
336
86aa7ba4
LP
337 r = sd_journal_get_realtime_usec(j, &realtime);
338 if (r < 0) {
339 log_error("Failed to get realtime timestamp: %s", strerror(-r));
340 return r;
341 }
342
343 r = sd_journal_get_cursor(j, &cursor);
344 if (r < 0) {
345 log_error("Failed to get cursor: %s", strerror(-r));
346 return r;
347 }
348
08ace05b
LP
349 fprintf(f, "%s [%s]\n",
350 format_timestamp(ts, sizeof(ts), realtime),
351 cursor);
86aa7ba4 352
86aa7ba4 353 SD_JOURNAL_FOREACH_DATA(j, data, length) {
31f7bf19
ZJS
354 const char *c;
355 int fieldlen;
356 c = memchr(data, '=', length);
357 if (!c) {
358 log_error("Invalid field.");
359 return -EINVAL;
360 }
361 fieldlen = c - (const char*) data;
86aa7ba4 362
31f7bf19
ZJS
363 if ((flags & OUTPUT_SHOW_ALL) || (length < PRINT_THRESHOLD && utf8_is_printable(data, length))) {
364 fprintf(f, " %.*s=", fieldlen, (const char*)data);
365 print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
366 } else {
367 char bytes[FORMAT_BYTES_MAX];
86aa7ba4 368
31f7bf19
ZJS
369 fprintf(f, " %.*s=[%s blob data]\n",
370 (int) (c - (const char*) data),
371 (const char*) data,
372 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
373 }
86aa7ba4
LP
374 }
375
d4205751
LP
376 if (flags & OUTPUT_CATALOG)
377 print_catalog(f, j);
378
86aa7ba4
LP
379 return 0;
380}
381
08ace05b
LP
382static int output_export(
383 FILE *f,
384 sd_journal *j,
385 OutputMode mode,
386 unsigned n_columns,
387 OutputFlags flags) {
388
86aa7ba4
LP
389 sd_id128_t boot_id;
390 char sid[33];
391 int r;
392 usec_t realtime, monotonic;
7fd1b19b 393 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
394 const void *data;
395 size_t length;
396
397 assert(j);
398
93b73b06
LP
399 sd_journal_set_data_threshold(j, 0);
400
86aa7ba4
LP
401 r = sd_journal_get_realtime_usec(j, &realtime);
402 if (r < 0) {
403 log_error("Failed to get realtime timestamp: %s", strerror(-r));
404 return r;
405 }
406
407 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
408 if (r < 0) {
409 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
410 return r;
411 }
412
413 r = sd_journal_get_cursor(j, &cursor);
414 if (r < 0) {
415 log_error("Failed to get cursor: %s", strerror(-r));
416 return r;
417 }
418
08ace05b
LP
419 fprintf(f,
420 "__CURSOR=%s\n"
421 "__REALTIME_TIMESTAMP=%llu\n"
422 "__MONOTONIC_TIMESTAMP=%llu\n"
423 "_BOOT_ID=%s\n",
424 cursor,
425 (unsigned long long) realtime,
426 (unsigned long long) monotonic,
427 sd_id128_to_string(boot_id, sid));
86aa7ba4 428
86aa7ba4
LP
429 SD_JOURNAL_FOREACH_DATA(j, data, length) {
430
112301ae
LP
431 /* We already printed the boot id, from the data in
432 * the header, hence let's suppress it here */
433 if (length >= 9 &&
434 memcmp(data, "_BOOT_ID=", 9) == 0)
435 continue;
436
31f7bf19 437 if (!utf8_is_printable(data, length)) {
86aa7ba4
LP
438 const char *c;
439 uint64_t le64;
440
441 c = memchr(data, '=', length);
442 if (!c) {
443 log_error("Invalid field.");
444 return -EINVAL;
445 }
446
08ace05b
LP
447 fwrite(data, c - (const char*) data, 1, f);
448 fputc('\n', f);
86aa7ba4 449 le64 = htole64(length - (c - (const char*) data) - 1);
08ace05b
LP
450 fwrite(&le64, sizeof(le64), 1, f);
451 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
86aa7ba4 452 } else
08ace05b 453 fwrite(data, length, 1, f);
86aa7ba4 454
08ace05b 455 fputc('\n', f);
86aa7ba4
LP
456 }
457
08ace05b 458 fputc('\n', f);
86aa7ba4
LP
459
460 return 0;
461}
462
240a5fe8 463void json_escape(
08ace05b
LP
464 FILE *f,
465 const char* p,
466 size_t l,
467 OutputFlags flags) {
468
469 assert(f);
470 assert(p);
471
93b73b06 472 if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
08ace05b
LP
473
474 fputs("null", f);
475
31f7bf19 476 else if (!utf8_is_printable(p, l)) {
86aa7ba4
LP
477 bool not_first = false;
478
08ace05b 479 fputs("[ ", f);
86aa7ba4
LP
480
481 while (l > 0) {
482 if (not_first)
08ace05b 483 fprintf(f, ", %u", (uint8_t) *p);
86aa7ba4
LP
484 else {
485 not_first = true;
08ace05b 486 fprintf(f, "%u", (uint8_t) *p);
86aa7ba4
LP
487 }
488
489 p++;
490 l--;
491 }
492
08ace05b 493 fputs(" ]", f);
86aa7ba4 494 } else {
08ace05b 495 fputc('\"', f);
86aa7ba4
LP
496
497 while (l > 0) {
498 if (*p == '"' || *p == '\\') {
08ace05b
LP
499 fputc('\\', f);
500 fputc(*p, f);
31f7bf19
ZJS
501 } else if (*p == '\n')
502 fputs("\\n", f);
503 else if (*p < ' ')
08ace05b
LP
504 fprintf(f, "\\u%04x", *p);
505 else
506 fputc(*p, f);
86aa7ba4
LP
507
508 p++;
509 l--;
510 }
511
08ace05b 512 fputc('\"', f);
86aa7ba4
LP
513 }
514}
515
08ace05b
LP
516static int output_json(
517 FILE *f,
518 sd_journal *j,
519 OutputMode mode,
520 unsigned n_columns,
521 OutputFlags flags) {
522
86aa7ba4 523 uint64_t realtime, monotonic;
7fd1b19b 524 _cleanup_free_ char *cursor = NULL;
86aa7ba4
LP
525 const void *data;
526 size_t length;
527 sd_id128_t boot_id;
2e729834 528 char sid[33], *k;
86aa7ba4 529 int r;
d99ae53a
LP
530 Hashmap *h = NULL;
531 bool done, separator;
86aa7ba4
LP
532
533 assert(j);
534
93b73b06
LP
535 sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
536
86aa7ba4
LP
537 r = sd_journal_get_realtime_usec(j, &realtime);
538 if (r < 0) {
539 log_error("Failed to get realtime timestamp: %s", strerror(-r));
540 return r;
541 }
542
543 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
544 if (r < 0) {
545 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
546 return r;
547 }
548
549 r = sd_journal_get_cursor(j, &cursor);
550 if (r < 0) {
551 log_error("Failed to get cursor: %s", strerror(-r));
552 return r;
553 }
554
a6e87e90 555 if (mode == OUTPUT_JSON_PRETTY)
08ace05b
LP
556 fprintf(f,
557 "{\n"
558 "\t\"__CURSOR\" : \"%s\",\n"
559 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
560 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
561 "\t\"_BOOT_ID\" : \"%s\"",
562 cursor,
563 (unsigned long long) realtime,
564 (unsigned long long) monotonic,
565 sd_id128_to_string(boot_id, sid));
48383c25
LP
566 else {
567 if (mode == OUTPUT_JSON_SSE)
568 fputs("data: ", f);
569
08ace05b
LP
570 fprintf(f,
571 "{ \"__CURSOR\" : \"%s\", "
572 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
573 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
574 "\"_BOOT_ID\" : \"%s\"",
575 cursor,
576 (unsigned long long) realtime,
577 (unsigned long long) monotonic,
578 sd_id128_to_string(boot_id, sid));
48383c25 579 }
86aa7ba4 580
d99ae53a
LP
581 h = hashmap_new(string_hash_func, string_compare_func);
582 if (!h)
583 return -ENOMEM;
584
585 /* First round, iterate through the entry and count how often each field appears */
86aa7ba4 586 SD_JOURNAL_FOREACH_DATA(j, data, length) {
d99ae53a
LP
587 const char *eq;
588 char *n;
589 unsigned u;
86aa7ba4 590
112301ae
LP
591 if (length >= 9 &&
592 memcmp(data, "_BOOT_ID=", 9) == 0)
593 continue;
594
d99ae53a
LP
595 eq = memchr(data, '=', length);
596 if (!eq)
597 continue;
86aa7ba4 598
d99ae53a
LP
599 n = strndup(data, eq - (const char*) data);
600 if (!n) {
601 r = -ENOMEM;
602 goto finish;
603 }
a6e87e90 604
d99ae53a
LP
605 u = PTR_TO_UINT(hashmap_get(h, n));
606 if (u == 0) {
607 r = hashmap_put(h, n, UINT_TO_PTR(1));
608 if (r < 0) {
609 free(n);
610 goto finish;
611 }
612 } else {
613 r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
614 free(n);
615 if (r < 0)
616 goto finish;
617 }
86aa7ba4
LP
618 }
619
d99ae53a
LP
620 separator = true;
621 do {
622 done = true;
623
624 SD_JOURNAL_FOREACH_DATA(j, data, length) {
625 const char *eq;
626 char *kk, *n;
627 size_t m;
628 unsigned u;
629
630 /* We already printed the boot id, from the data in
631 * the header, hence let's suppress it here */
632 if (length >= 9 &&
633 memcmp(data, "_BOOT_ID=", 9) == 0)
634 continue;
635
636 eq = memchr(data, '=', length);
637 if (!eq)
638 continue;
639
640 if (separator) {
641 if (mode == OUTPUT_JSON_PRETTY)
642 fputs(",\n\t", f);
643 else
644 fputs(", ", f);
645 }
646
647 m = eq - (const char*) data;
648
649 n = strndup(data, m);
650 if (!n) {
651 r = -ENOMEM;
652 goto finish;
653 }
654
655 u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
656 if (u == 0) {
657 /* We already printed this, let's jump to the next */
658 free(n);
659 separator = false;
660
661 continue;
662 } else if (u == 1) {
663 /* Field only appears once, output it directly */
664
665 json_escape(f, data, m, flags);
666 fputs(" : ", f);
667
668 json_escape(f, eq + 1, length - m - 1, flags);
669
670 hashmap_remove(h, n);
671 free(kk);
672 free(n);
673
674 separator = true;
675
676 continue;
677
678 } else {
679 /* Field appears multiple times, output it as array */
680 json_escape(f, data, m, flags);
681 fputs(" : [ ", f);
682 json_escape(f, eq + 1, length - m - 1, flags);
683
684 /* Iterate through the end of the list */
685
686 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
687 if (length < m + 1)
688 continue;
689
690 if (memcmp(data, n, m) != 0)
691 continue;
692
693 if (((const char*) data)[m] != '=')
694 continue;
695
696 fputs(", ", f);
697 json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
698 }
699
700 fputs(" ]", f);
701
702 hashmap_remove(h, n);
703 free(kk);
704 free(n);
705
706 /* Iterate data fields form the beginning */
707 done = false;
708 separator = true;
709
710 break;
711 }
712 }
713
714 } while (!done);
715
a6e87e90 716 if (mode == OUTPUT_JSON_PRETTY)
08ace05b 717 fputs("\n}\n", f);
48383c25
LP
718 else if (mode == OUTPUT_JSON_SSE)
719 fputs("}\n\n", f);
a6e87e90 720 else
08ace05b 721 fputs(" }\n", f);
86aa7ba4 722
d99ae53a
LP
723 r = 0;
724
725finish:
726 while ((k = hashmap_steal_first_key(h)))
727 free(k);
728
729 hashmap_free(h);
730
731 return r;
86aa7ba4
LP
732}
733
08ace05b
LP
734static int output_cat(
735 FILE *f,
736 sd_journal *j,
737 OutputMode mode,
738 unsigned n_columns,
739 OutputFlags flags) {
740
d3f2bdbf
LP
741 const void *data;
742 size_t l;
743 int r;
744
745 assert(j);
08ace05b 746 assert(f);
d3f2bdbf 747
93b73b06
LP
748 sd_journal_set_data_threshold(j, 0);
749
d3f2bdbf
LP
750 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
751 if (r < 0) {
c198300f
LP
752 /* An entry without MESSAGE=? */
753 if (r == -ENOENT)
754 return 0;
755
d3f2bdbf
LP
756 log_error("Failed to get data: %s", strerror(-r));
757 return r;
758 }
759
760 assert(l >= 8);
761
08ace05b
LP
762 fwrite((const char*) data + 8, 1, l - 8, f);
763 fputc('\n', f);
d3f2bdbf
LP
764
765 return 0;
766}
767
08ace05b
LP
768static int (*output_funcs[_OUTPUT_MODE_MAX])(
769 FILE *f,
770 sd_journal*j,
771 OutputMode mode,
772 unsigned n_columns,
773 OutputFlags flags) = {
774
a6e87e90
LP
775 [OUTPUT_SHORT] = output_short,
776 [OUTPUT_SHORT_MONOTONIC] = output_short,
86aa7ba4
LP
777 [OUTPUT_VERBOSE] = output_verbose,
778 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 779 [OUTPUT_JSON] = output_json,
a6e87e90 780 [OUTPUT_JSON_PRETTY] = output_json,
48383c25 781 [OUTPUT_JSON_SSE] = output_json,
d3f2bdbf 782 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
783};
784
08ace05b
LP
785int output_journal(
786 FILE *f,
787 sd_journal *j,
788 OutputMode mode,
789 unsigned n_columns,
790 OutputFlags flags) {
791
e268b81e 792 int ret;
df50185b 793 assert(mode >= 0);
86aa7ba4
LP
794 assert(mode < _OUTPUT_MODE_MAX);
795
34a35ece
LP
796 if (n_columns <= 0)
797 n_columns = columns();
798
08ace05b 799 ret = output_funcs[mode](f, j, mode, n_columns, flags);
e268b81e
BP
800 fflush(stdout);
801 return ret;
86aa7ba4
LP
802}
803
1a6c43e9
MT
804static int show_journal(FILE *f,
805 sd_journal *j,
806 OutputMode mode,
807 unsigned n_columns,
808 usec_t not_before,
809 unsigned how_many,
810 OutputFlags flags) {
86aa7ba4 811
86aa7ba4 812 int r;
df50185b
LP
813 unsigned line = 0;
814 bool need_seek = false;
085d7120 815 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 816
1a6c43e9 817 assert(j);
df50185b
LP
818 assert(mode >= 0);
819 assert(mode < _OUTPUT_MODE_MAX);
1946b0bd
LP
820
821 /* Seek to end */
86aa7ba4
LP
822 r = sd_journal_seek_tail(j);
823 if (r < 0)
824 goto finish;
825
df50185b
LP
826 r = sd_journal_previous_skip(j, how_many);
827 if (r < 0)
828 goto finish;
86aa7ba4 829
df50185b
LP
830 for (;;) {
831 for (;;) {
832 usec_t usec;
833
834 if (need_seek) {
835 r = sd_journal_next(j);
836 if (r < 0)
837 goto finish;
838 }
839
840 if (r == 0)
841 break;
86aa7ba4 842
df50185b
LP
843 need_seek = true;
844
845 if (not_before > 0) {
846 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
847
848 /* -ESTALE is returned if the
849 timestamp is not from this boot */
850 if (r == -ESTALE)
851 continue;
852 else if (r < 0)
853 goto finish;
854
855 if (usec < not_before)
856 continue;
857 }
858
859 line ++;
860
08ace05b 861 r = output_journal(f, j, mode, n_columns, flags);
df50185b
LP
862 if (r < 0)
863 goto finish;
864 }
865
08984293
LP
866 if (warn_cutoff && line < how_many && not_before > 0) {
867 sd_id128_t boot_id;
868 usec_t cutoff;
869
870 /* Check whether the cutoff line is too early */
871
872 r = sd_id128_get_boot(&boot_id);
873 if (r < 0)
874 goto finish;
875
876 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
877 if (r < 0)
878 goto finish;
879
b59866ae 880 if (r > 0 && not_before < cutoff)
08ace05b 881 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
08984293
LP
882
883 warn_cutoff = false;
884 }
885
085d7120 886 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
887 break;
888
e02d1cf7 889 r = sd_journal_wait(j, (usec_t) -1);
df50185b
LP
890 if (r < 0)
891 goto finish;
892
86aa7ba4
LP
893 }
894
1a6c43e9
MT
895finish:
896 return r;
897}
898
886a64fe 899int add_matches_for_unit(sd_journal *j, const char *unit) {
1a6c43e9 900 int r;
886a64fe 901 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
1a6c43e9 902
886a64fe 903 assert(j);
1a6c43e9
MT
904 assert(unit);
905
1a6c43e9
MT
906 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
907 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
886a64fe
ZJS
908 asprintf(&m3, "UNIT=%s", unit) < 0)
909 return -ENOMEM;
1a6c43e9 910
886a64fe
ZJS
911 (void)(
912 /* Look for messages from the service itself */
913 (r = sd_journal_add_match(j, m1, 0)) ||
914
915 /* Look for coredumps of the service */
916 (r = sd_journal_add_disjunction(j)) ||
917 (r = sd_journal_add_match(j,
918 "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
919 (r = sd_journal_add_match(j, m2, 0)) ||
920
921 /* Look for messages from PID 1 about this service */
922 (r = sd_journal_add_disjunction(j)) ||
923 (r = sd_journal_add_match(j, "_PID=1", 0)) ||
924 (r = sd_journal_add_match(j, m3, 0))
925 );
926 return r;
927}
1a6c43e9 928
886a64fe
ZJS
929int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
930 int r;
931 _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
1a6c43e9 932
886a64fe
ZJS
933 assert(j);
934 assert(unit);
1a6c43e9 935
886a64fe
ZJS
936 if (asprintf(&m1, "_SYSTEMD_USER_UNIT=%s", unit) < 0 ||
937 asprintf(&m2, "USER_UNIT=%s", unit) < 0 ||
938 asprintf(&m3, "COREDUMP_USER_UNIT=%s", unit) < 0 ||
939 asprintf(&m4, "_UID=%d", uid) < 0)
940 return -ENOMEM;
1a6c43e9 941
886a64fe
ZJS
942 (void) (
943 /* Look for messages from the user service itself */
944 (r = sd_journal_add_match(j, m1, 0)) ||
945 (r = sd_journal_add_match(j, m4, 0)) ||
946
947 /* Look for messages from systemd about this service */
948 (r = sd_journal_add_disjunction(j)) ||
949 (r = sd_journal_add_match(j, m2, 0)) ||
950 (r = sd_journal_add_match(j, m4, 0)) ||
951
952 /* Look for coredumps of the service */
953 (r = sd_journal_add_disjunction(j)) ||
954 (r = sd_journal_add_match(j, m3, 0)) ||
955 (r = sd_journal_add_match(j, m4, 0))
956 );
1a6c43e9
MT
957 return r;
958}
959
5ec76417
ZJS
960int add_match_this_boot(sd_journal *j) {
961 char match[9+32+1] = "_BOOT_ID=";
962 sd_id128_t boot_id;
963 int r;
964
965 assert(j);
966
967 r = sd_id128_get_boot(&boot_id);
968 if (r < 0) {
969 log_error("Failed to get boot id: %s", strerror(-r));
970 return r;
971 }
972
973 sd_id128_to_string(boot_id, match + 9);
974 r = sd_journal_add_match(j, match, strlen(match));
975 if (r < 0) {
976 log_error("Failed to add match: %s", strerror(-r));
977 return r;
978 }
979
980 r = sd_journal_add_conjunction(j);
981 if (r < 0)
982 return r;
983
984 return 0;
985}
986
886a64fe 987int show_journal_by_unit(
1a6c43e9
MT
988 FILE *f,
989 const char *unit,
990 OutputMode mode,
991 unsigned n_columns,
992 usec_t not_before,
993 unsigned how_many,
994 uid_t uid,
886a64fe
ZJS
995 OutputFlags flags,
996 bool system) {
1a6c43e9 997
7fd1b19b 998 _cleanup_journal_close_ sd_journal*j = NULL;
1a6c43e9 999 int r;
886a64fe 1000 int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM_ONLY;
1a6c43e9
MT
1001
1002 assert(mode >= 0);
1003 assert(mode < _OUTPUT_MODE_MAX);
1004 assert(unit);
1005
1a6c43e9
MT
1006 if (how_many <= 0)
1007 return 0;
1008
886a64fe 1009 r = sd_journal_open(&j, jflags);
f9045468 1010 if (r < 0)
763c7aa2 1011 return r;
f9045468 1012
5ec76417
ZJS
1013 r = add_match_this_boot(j);
1014 if (r < 0)
1015 return r;
1016
886a64fe
ZJS
1017 if (system)
1018 r = add_matches_for_unit(j, unit);
1019 else
1020 r = add_matches_for_user_unit(j, unit, uid);
1a6c43e9 1021 if (r < 0)
763c7aa2 1022 return r;
1a6c43e9 1023
5ec76417
ZJS
1024 log_debug("Journal filter: %s", journal_make_match_string(j));
1025
1a6c43e9
MT
1026 r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
1027 if (r < 0)
763c7aa2 1028 return r;
86aa7ba4 1029
763c7aa2 1030 return 0;
86aa7ba4 1031}
df50185b
LP
1032
1033static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1034 [OUTPUT_SHORT] = "short",
67a12205 1035 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
df50185b
LP
1036 [OUTPUT_VERBOSE] = "verbose",
1037 [OUTPUT_EXPORT] = "export",
d3f2bdbf 1038 [OUTPUT_JSON] = "json",
a6e87e90 1039 [OUTPUT_JSON_PRETTY] = "json-pretty",
48383c25 1040 [OUTPUT_JSON_SSE] = "json-sse",
d3f2bdbf 1041 [OUTPUT_CAT] = "cat"
df50185b
LP
1042};
1043
1044DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);