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