]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/logs-show.c
docs: typos in loginctl.xml
[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"
86aa7ba4
LP
32
33#define PRINT_THRESHOLD 128
34
55d7bfc1
LP
35static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
36 size_t fl, nl;
37 void *buf;
38
39 assert(data);
40 assert(field);
41 assert(target);
42 assert(target_size);
43
44 fl = strlen(field);
45 if (length < fl)
46 return 0;
47
48 if (memcmp(data, field, fl))
49 return 0;
50
51 nl = length - fl;
bf967366 52 buf = malloc(nl+1);
0d0f0c50
SL
53 if (!buf)
54 return log_oom();
55d7bfc1 55
46b0d922
LP
56 memcpy(buf, (const char*) data + fl, nl);
57 ((char*)buf)[nl] = 0;
58
6c1e6b98 59 free(*target);
55d7bfc1
LP
60 *target = buf;
61 *target_size = nl;
62
63 return 1;
64}
65
66static bool shall_print(bool show_all, char *p, size_t l) {
67 if (show_all)
68 return true;
69
70 if (l > PRINT_THRESHOLD)
71 return false;
72
ba961854 73 if (!utf8_is_printable_n(p, l))
55d7bfc1
LP
74 return false;
75
76 return true;
77}
78
a6e87e90 79static int output_short(sd_journal *j, OutputMode mode, unsigned line, unsigned n_columns,
25277cd7 80 OutputFlags flags) {
86aa7ba4 81 int r;
86aa7ba4
LP
82 const void *data;
83 size_t length;
84 size_t n = 0;
49826187
LP
85 char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
86 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;
87 int p = LOG_INFO;
88 const char *color_on = "", *color_off = "";
86aa7ba4
LP
89
90 assert(j);
91
55d7bfc1
LP
92 SD_JOURNAL_FOREACH_DATA(j, data, length) {
93
49826187
LP
94 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
95 if (r < 0)
96 goto finish;
97 else if (r > 0)
98 continue;
99
55d7bfc1
LP
100 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
101 if (r < 0)
102 goto finish;
103 else if (r > 0)
104 continue;
105
4cd9a9d9 106 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
55d7bfc1
LP
107 if (r < 0)
108 goto finish;
109 else if (r > 0)
110 continue;
111
112 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
113 if (r < 0)
114 goto finish;
115 else if (r > 0)
116 continue;
117
118 r = parse_field(data, length, "_PID=", &pid, &pid_len);
119 if (r < 0)
120 goto finish;
121 else if (r > 0)
122 continue;
123
6c1e6b98
LP
124 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
125 if (r < 0)
126 goto finish;
127 else if (r > 0)
128 continue;
129
bf967366
LP
130 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
131 if (r < 0)
132 goto finish;
133 else if (r > 0)
134 continue;
135
136 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
137 if (r < 0)
138 goto finish;
139 else if (r > 0)
140 continue;
141
55d7bfc1
LP
142 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
143 if (r < 0)
144 goto finish;
145 }
146
147 if (!message) {
148 r = 0;
149 goto finish;
150 }
151
49826187
LP
152 if (priority_len == 1 && *priority >= '0' && *priority <= '7')
153 p = *priority - '0';
154
a6e87e90 155 if (mode == OUTPUT_SHORT_MONOTONIC) {
67a12205 156 uint64_t t;
3ebcdf8c
LP
157 sd_id128_t boot_id;
158
bf967366
LP
159 r = -ENOENT;
160
161 if (monotonic)
162 r = safe_atou64(monotonic, &t);
163
164 if (r < 0)
3ebcdf8c 165 r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
86aa7ba4 166
3ebcdf8c
LP
167 if (r < 0) {
168 log_error("Failed to get monotonic: %s", strerror(-r));
169 goto finish;
67a12205
LP
170 }
171
3ebcdf8c
LP
172 printf("[%5llu.%06llu]",
173 (unsigned long long) (t / USEC_PER_SEC),
174 (unsigned long long) (t % USEC_PER_SEC));
175
176 n += 1 + 5 + 1 + 6 + 1;
177
67a12205
LP
178 } else {
179 char buf[64];
bf967366 180 uint64_t x;
67a12205
LP
181 time_t t;
182 struct tm tm;
731a676c 183
bf967366
LP
184 r = -ENOENT;
185
186 if (realtime)
187 r = safe_atou64(realtime, &x);
188
189 if (r < 0)
190 r = sd_journal_get_realtime_usec(j, &x);
67a12205 191
67a12205
LP
192 if (r < 0) {
193 log_error("Failed to get realtime: %s", strerror(-r));
194 goto finish;
195 }
196
bf967366 197 t = (time_t) (x / USEC_PER_SEC);
67a12205
LP
198 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
199 log_error("Failed to format time.");
200 goto finish;
201 }
202
203 fputs(buf, stdout);
204 n += strlen(buf);
205 }
86aa7ba4 206
25277cd7
ZJS
207 if (hostname && shall_print(flags & OUTPUT_SHOW_ALL,
208 hostname, hostname_len)) {
55d7bfc1
LP
209 printf(" %.*s", (int) hostname_len, hostname);
210 n += hostname_len + 1;
211 }
212
25277cd7
ZJS
213 if (identifier && shall_print(flags & OUTPUT_SHOW_ALL,
214 identifier, identifier_len)) {
4cd9a9d9
LP
215 printf(" %.*s", (int) identifier_len, identifier);
216 n += identifier_len + 1;
25277cd7
ZJS
217 } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL,
218 comm, comm_len)) {
55d7bfc1
LP
219 printf(" %.*s", (int) comm_len, comm);
220 n += comm_len + 1;
b5936820
LP
221 } else
222 putchar(' ');
86aa7ba4 223
25277cd7 224 if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) {
55d7bfc1
LP
225 printf("[%.*s]", (int) pid_len, pid);
226 n += pid_len + 2;
25277cd7
ZJS
227 } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL,
228 fake_pid, fake_pid_len)) {
6c1e6b98
LP
229 printf("[%.*s]", (int) fake_pid_len, fake_pid);
230 n += fake_pid_len + 2;
86aa7ba4
LP
231 }
232
49826187
LP
233 if (flags & OUTPUT_COLOR) {
234 if (p <= LOG_ERR) {
235 color_on = ANSI_HIGHLIGHT_RED_ON;
236 color_off = ANSI_HIGHLIGHT_OFF;
237 } else if (p <= LOG_NOTICE) {
238 color_on = ANSI_HIGHLIGHT_ON;
239 color_off = ANSI_HIGHLIGHT_OFF;
240 }
241 }
242
25277cd7 243 if (flags & OUTPUT_SHOW_ALL)
49826187 244 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
ba961854 245 else if (!utf8_is_printable_n(message, message_len)) {
e6acda19
LP
246 char bytes[FORMAT_BYTES_MAX];
247 printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
92a1fd9e 248 } else if ((flags & OUTPUT_FULL_WIDTH) ||
193556b6 249 (message_len + n + 1 < n_columns))
49826187 250 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
b61a4660 251 else if (n < n_columns && n_columns - n - 2 >= 3) {
55d7bfc1
LP
252 char *e;
253
34a35ece 254 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
55d7bfc1
LP
255
256 if (!e)
49826187 257 printf(": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
55d7bfc1 258 else
49826187 259 printf(": %s%s%s\n", color_on, e, color_off);
55d7bfc1
LP
260
261 free(e);
262 } else
263 fputs("\n", stdout);
264
265 r = 0;
266
267finish:
268 free(hostname);
4cd9a9d9 269 free(identifier);
55d7bfc1
LP
270 free(comm);
271 free(pid);
6c1e6b98 272 free(fake_pid);
55d7bfc1 273 free(message);
bf967366
LP
274 free(monotonic);
275 free(realtime);
64825d3c 276 free(priority);
86aa7ba4 277
55d7bfc1 278 return r;
86aa7ba4
LP
279}
280
a6e87e90 281static int output_verbose(sd_journal *j, OutputMode mode, unsigned line,
25277cd7 282 unsigned n_columns, OutputFlags flags) {
86aa7ba4
LP
283 const void *data;
284 size_t length;
285 char *cursor;
286 uint64_t realtime;
287 char ts[FORMAT_TIMESTAMP_MAX];
288 int r;
289
290 assert(j);
291
292 r = sd_journal_get_realtime_usec(j, &realtime);
293 if (r < 0) {
294 log_error("Failed to get realtime timestamp: %s", strerror(-r));
295 return r;
296 }
297
298 r = sd_journal_get_cursor(j, &cursor);
299 if (r < 0) {
300 log_error("Failed to get cursor: %s", strerror(-r));
301 return r;
302 }
303
304 printf("%s [%s]\n",
305 format_timestamp(ts, sizeof(ts), realtime),
306 cursor);
307
308 free(cursor);
309
310 SD_JOURNAL_FOREACH_DATA(j, data, length) {
25277cd7 311 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
ba961854 312 !utf8_is_printable_n(data, length))) {
86aa7ba4 313 const char *c;
e6acda19 314 char bytes[FORMAT_BYTES_MAX];
86aa7ba4
LP
315
316 c = memchr(data, '=', length);
317 if (!c) {
318 log_error("Invalid field.");
319 return -EINVAL;
320 }
321
e6acda19 322 printf("\t%.*s=[%s blob data]\n",
86aa7ba4 323 (int) (c - (const char*) data),
e6acda19
LP
324 (const char*) data,
325 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
86aa7ba4
LP
326 } else
327 printf("\t%.*s\n", (int) length, (const char*) data);
328 }
329
330 return 0;
331}
332
a6e87e90 333static int output_export(sd_journal *j, OutputMode mode, unsigned line,
25277cd7 334 unsigned n_columns, OutputFlags flags) {
86aa7ba4
LP
335 sd_id128_t boot_id;
336 char sid[33];
337 int r;
338 usec_t realtime, monotonic;
339 char *cursor;
340 const void *data;
341 size_t length;
342
343 assert(j);
344
345 r = sd_journal_get_realtime_usec(j, &realtime);
346 if (r < 0) {
347 log_error("Failed to get realtime timestamp: %s", strerror(-r));
348 return r;
349 }
350
351 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
352 if (r < 0) {
353 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
354 return r;
355 }
356
357 r = sd_journal_get_cursor(j, &cursor);
358 if (r < 0) {
359 log_error("Failed to get cursor: %s", strerror(-r));
360 return r;
361 }
362
ba8d3790 363 printf("__CURSOR=%s\n"
ffa16db0
LP
364 "__REALTIME_TIMESTAMP=%llu\n"
365 "__MONOTONIC_TIMESTAMP=%llu\n"
112301ae 366 "_BOOT_ID=%s\n",
86aa7ba4
LP
367 cursor,
368 (unsigned long long) realtime,
369 (unsigned long long) monotonic,
370 sd_id128_to_string(boot_id, sid));
371
372 free(cursor);
373
374 SD_JOURNAL_FOREACH_DATA(j, data, length) {
375
112301ae
LP
376 /* We already printed the boot id, from the data in
377 * the header, hence let's suppress it here */
378 if (length >= 9 &&
379 memcmp(data, "_BOOT_ID=", 9) == 0)
380 continue;
381
ba961854 382 if (!utf8_is_printable_n(data, length)) {
86aa7ba4
LP
383 const char *c;
384 uint64_t le64;
385
386 c = memchr(data, '=', length);
387 if (!c) {
388 log_error("Invalid field.");
389 return -EINVAL;
390 }
391
392 fwrite(data, c - (const char*) data, 1, stdout);
393 fputc('\n', stdout);
394 le64 = htole64(length - (c - (const char*) data) - 1);
395 fwrite(&le64, sizeof(le64), 1, stdout);
396 fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
397 } else
398 fwrite(data, length, 1, stdout);
399
400 fputc('\n', stdout);
401 }
402
403 fputc('\n', stdout);
404
405 return 0;
406}
407
408static void json_escape(const char* p, size_t l) {
ba961854 409 if (!utf8_is_printable_n(p, l)) {
86aa7ba4
LP
410 bool not_first = false;
411
412 fputs("[ ", stdout);
413
414 while (l > 0) {
415 if (not_first)
416 printf(", %u", (uint8_t) *p);
417 else {
418 not_first = true;
419 printf("%u", (uint8_t) *p);
420 }
421
422 p++;
423 l--;
424 }
425
426 fputs(" ]", stdout);
427 } else {
428 fputc('\"', stdout);
429
430 while (l > 0) {
431 if (*p == '"' || *p == '\\') {
432 fputc('\\', stdout);
433 fputc(*p, stdout);
434 } else
435 fputc(*p, stdout);
436
437 p++;
438 l--;
439 }
440
441 fputc('\"', stdout);
442 }
443}
444
a6e87e90 445static int output_json(sd_journal *j, OutputMode mode, unsigned line,
25277cd7 446 unsigned n_columns, OutputFlags flags) {
86aa7ba4
LP
447 uint64_t realtime, monotonic;
448 char *cursor;
449 const void *data;
450 size_t length;
451 sd_id128_t boot_id;
452 char sid[33];
453 int r;
454
455 assert(j);
456
457 r = sd_journal_get_realtime_usec(j, &realtime);
458 if (r < 0) {
459 log_error("Failed to get realtime timestamp: %s", strerror(-r));
460 return r;
461 }
462
463 r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
464 if (r < 0) {
465 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
466 return r;
467 }
468
469 r = sd_journal_get_cursor(j, &cursor);
470 if (r < 0) {
471 log_error("Failed to get cursor: %s", strerror(-r));
472 return r;
473 }
474
a6e87e90
LP
475 if (mode == OUTPUT_JSON_PRETTY)
476 printf("{\n"
477 "\t\"__CURSOR\" : \"%s\",\n"
478 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
479 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
480 "\t\"_BOOT_ID\" : \"%s\"",
481 cursor,
482 (unsigned long long) realtime,
483 (unsigned long long) monotonic,
484 sd_id128_to_string(boot_id, sid));
86aa7ba4 485 else
a6e87e90
LP
486 printf("{ \"__CURSOR\" : \"%s\", "
487 "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
488 "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
489 "\"_BOOT_ID\" : \"%s\"",
490 cursor,
491 (unsigned long long) realtime,
492 (unsigned long long) monotonic,
493 sd_id128_to_string(boot_id, sid));
86aa7ba4
LP
494 free(cursor);
495
496 SD_JOURNAL_FOREACH_DATA(j, data, length) {
497 const char *c;
498
112301ae
LP
499 /* We already printed the boot id, from the data in
500 * the header, hence let's suppress it here */
501 if (length >= 9 &&
502 memcmp(data, "_BOOT_ID=", 9) == 0)
503 continue;
504
86aa7ba4
LP
505 c = memchr(data, '=', length);
506 if (!c) {
507 log_error("Invalid field.");
508 return -EINVAL;
509 }
510
a6e87e90
LP
511 if (mode == OUTPUT_JSON_PRETTY)
512 fputs(",\n\t", stdout);
513 else
514 fputs(", ", stdout);
515
86aa7ba4
LP
516 json_escape(data, c - (const char*) data);
517 fputs(" : ", stdout);
518 json_escape(c + 1, length - (c - (const char*) data) - 1);
519 }
520
a6e87e90
LP
521 if (mode == OUTPUT_JSON_PRETTY)
522 fputs("\n}\n", stdout);
523 else
524 fputs(" }\n", stdout);
86aa7ba4
LP
525
526 return 0;
527}
528
a6e87e90 529static int output_cat(sd_journal *j, OutputMode mode, unsigned line,
25277cd7 530 unsigned n_columns, OutputFlags flags) {
d3f2bdbf
LP
531 const void *data;
532 size_t l;
533 int r;
534
535 assert(j);
536
537 r = sd_journal_get_data(j, "MESSAGE", &data, &l);
538 if (r < 0) {
539 log_error("Failed to get data: %s", strerror(-r));
540 return r;
541 }
542
543 assert(l >= 8);
544
545 fwrite((const char*) data + 8, 1, l - 8, stdout);
546 putchar('\n');
547
548 return 0;
549}
550
a6e87e90 551static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, OutputMode mode, unsigned line,
25277cd7 552 unsigned n_columns, OutputFlags flags) = {
a6e87e90
LP
553 [OUTPUT_SHORT] = output_short,
554 [OUTPUT_SHORT_MONOTONIC] = output_short,
86aa7ba4
LP
555 [OUTPUT_VERBOSE] = output_verbose,
556 [OUTPUT_EXPORT] = output_export,
d3f2bdbf 557 [OUTPUT_JSON] = output_json,
a6e87e90 558 [OUTPUT_JSON_PRETTY] = output_json,
d3f2bdbf 559 [OUTPUT_CAT] = output_cat
86aa7ba4
LP
560};
561
25277cd7
ZJS
562int output_journal(sd_journal *j, OutputMode mode, unsigned line,
563 unsigned n_columns, OutputFlags flags) {
e268b81e 564 int ret;
df50185b 565 assert(mode >= 0);
86aa7ba4
LP
566 assert(mode < _OUTPUT_MODE_MAX);
567
34a35ece
LP
568 if (n_columns <= 0)
569 n_columns = columns();
570
a6e87e90 571 ret = output_funcs[mode](j, mode, line, n_columns, flags);
e268b81e
BP
572 fflush(stdout);
573 return ret;
86aa7ba4
LP
574}
575
df50185b
LP
576int show_journal_by_unit(
577 const char *unit,
578 OutputMode mode,
86aa7ba4
LP
579 unsigned n_columns,
580 usec_t not_before,
581 unsigned how_many,
085d7120 582 OutputFlags flags) {
86aa7ba4 583
1946b0bd 584 char *m1 = NULL, *m2 = NULL, *m3 = NULL;
7ea07dcd 585 sd_journal *j = NULL;
86aa7ba4 586 int r;
df50185b
LP
587 unsigned line = 0;
588 bool need_seek = false;
085d7120 589 int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
86aa7ba4 590
df50185b
LP
591 assert(mode >= 0);
592 assert(mode < _OUTPUT_MODE_MAX);
593 assert(unit);
594
595 if (!endswith(unit, ".service") &&
596 !endswith(unit, ".socket") &&
597 !endswith(unit, ".mount") &&
598 !endswith(unit, ".swap"))
599 return 0;
86aa7ba4 600
df50185b 601 if (how_many <= 0)
f4fb21c1
LP
602 return 0;
603
1946b0bd
LP
604 if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
605 asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
606 asprintf(&m3, "UNIT=%s", unit) < 0) {
86aa7ba4
LP
607 r = -ENOMEM;
608 goto finish;
609 }
610
611 r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
612 if (r < 0)
613 goto finish;
614
1946b0bd
LP
615 /* Look for messages from the service itself */
616 r = sd_journal_add_match(j, m1, 0);
86aa7ba4
LP
617 if (r < 0)
618 goto finish;
619
1946b0bd
LP
620 /* Look for coredumps of the service */
621 r = sd_journal_add_disjunction(j);
622 if (r < 0)
623 goto finish;
624 r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
625 if (r < 0)
626 goto finish;
627 r = sd_journal_add_match(j, m2, 0);
628 if (r < 0)
629 goto finish;
630
631 /* Look for messages from PID 1 about this service */
632 r = sd_journal_add_disjunction(j);
633 if (r < 0)
634 goto finish;
635 r = sd_journal_add_match(j, "_PID=1", 0);
636 if (r < 0)
637 goto finish;
638 r = sd_journal_add_match(j, m3, 0);
639 if (r < 0)
640 goto finish;
641
642 /* Seek to end */
86aa7ba4
LP
643 r = sd_journal_seek_tail(j);
644 if (r < 0)
645 goto finish;
646
df50185b
LP
647 r = sd_journal_previous_skip(j, how_many);
648 if (r < 0)
649 goto finish;
86aa7ba4 650
df50185b
LP
651 if (mode == OUTPUT_JSON) {
652 fputc('[', stdout);
653 fflush(stdout);
654 }
86aa7ba4 655
df50185b
LP
656 for (;;) {
657 for (;;) {
658 usec_t usec;
659
660 if (need_seek) {
661 r = sd_journal_next(j);
662 if (r < 0)
663 goto finish;
664 }
665
666 if (r == 0)
667 break;
86aa7ba4 668
df50185b
LP
669 need_seek = true;
670
671 if (not_before > 0) {
672 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
673
674 /* -ESTALE is returned if the
675 timestamp is not from this boot */
676 if (r == -ESTALE)
677 continue;
678 else if (r < 0)
679 goto finish;
680
681 if (usec < not_before)
682 continue;
683 }
684
685 line ++;
686
085d7120 687 r = output_journal(j, mode, line, n_columns, flags);
df50185b
LP
688 if (r < 0)
689 goto finish;
690 }
691
08984293
LP
692 if (warn_cutoff && line < how_many && not_before > 0) {
693 sd_id128_t boot_id;
694 usec_t cutoff;
695
696 /* Check whether the cutoff line is too early */
697
698 r = sd_id128_get_boot(&boot_id);
699 if (r < 0)
700 goto finish;
701
702 r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
703 if (r < 0)
704 goto finish;
705
b59866ae 706 if (r > 0 && not_before < cutoff)
08984293
LP
707 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
708
709 warn_cutoff = false;
710 }
711
085d7120 712 if (!(flags & OUTPUT_FOLLOW))
86aa7ba4
LP
713 break;
714
e02d1cf7 715 r = sd_journal_wait(j, (usec_t) -1);
df50185b
LP
716 if (r < 0)
717 goto finish;
718
86aa7ba4
LP
719 }
720
df50185b
LP
721 if (mode == OUTPUT_JSON)
722 fputs("\n]\n", stdout);
723
86aa7ba4 724finish:
1946b0bd
LP
725 free(m1);
726 free(m2);
727 free(m3);
86aa7ba4
LP
728
729 if (j)
730 sd_journal_close(j);
731
732 return r;
733}
df50185b
LP
734
735static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
736 [OUTPUT_SHORT] = "short",
67a12205 737 [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
df50185b
LP
738 [OUTPUT_VERBOSE] = "verbose",
739 [OUTPUT_EXPORT] = "export",
d3f2bdbf 740 [OUTPUT_JSON] = "json",
a6e87e90 741 [OUTPUT_JSON_PRETTY] = "json-pretty",
d3f2bdbf 742 [OUTPUT_CAT] = "cat"
df50185b
LP
743};
744
745DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);