chiark / gitweb /
journal: implement message catalog
[elogind.git] / src / shared / logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <time.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <sys/poll.h>
26 #include <string.h>
27
28 #include "logs-show.h"
29 #include "log.h"
30 #include "util.h"
31 #include "utf8.h"
32 #include "hashmap.h"
33
34 #define PRINT_THRESHOLD 128
35 #define JSON_THRESHOLD 4096
36
37 static 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
57 static 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;
74         buf = malloc(nl+1);
75         if (!buf)
76                 return log_oom();
77
78         memcpy(buf, (const char*) data + fl, nl);
79         ((char*)buf)[nl] = 0;
80
81         free(*target);
82         *target = buf;
83         *target_size = nl;
84
85         return 1;
86 }
87
88 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
89         assert(p);
90
91         if (flags & OUTPUT_SHOW_ALL)
92                 return true;
93
94         if (l > PRINT_THRESHOLD)
95                 return false;
96
97         if (!utf8_is_printable_n(p, l))
98                 return false;
99
100         return true;
101 }
102
103 static int output_short(
104                 FILE *f,
105                 sd_journal *j,
106                 OutputMode mode,
107                 unsigned n_columns,
108                 OutputFlags flags) {
109
110         int r;
111         const void *data;
112         size_t length;
113         size_t n = 0;
114         _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
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 = "";
118
119         assert(f);
120         assert(j);
121
122         SD_JOURNAL_FOREACH_DATA(j, data, length) {
123
124                 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
125                 if (r < 0)
126                         return r;
127                 else if (r > 0)
128                         continue;
129
130                 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
131                 if (r < 0)
132                         return r;
133                 else if (r > 0)
134                         continue;
135
136                 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
137                 if (r < 0)
138                         return r;
139                 else if (r > 0)
140                         continue;
141
142                 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
143                 if (r < 0)
144                         return r;
145                 else if (r > 0)
146                         continue;
147
148                 r = parse_field(data, length, "_PID=", &pid, &pid_len);
149                 if (r < 0)
150                         return r;
151                 else if (r > 0)
152                         continue;
153
154                 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
155                 if (r < 0)
156                         return r;
157                 else if (r > 0)
158                         continue;
159
160                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
161                 if (r < 0)
162                         return r;
163                 else if (r > 0)
164                         continue;
165
166                 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
167                 if (r < 0)
168                         return r;
169                 else if (r > 0)
170                         continue;
171
172                 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
173                 if (r < 0)
174                         return r;
175         }
176
177         if (!message)
178                 return 0;
179
180         if (priority_len == 1 && *priority >= '0' && *priority <= '7')
181                 p = *priority - '0';
182
183         if (mode == OUTPUT_SHORT_MONOTONIC) {
184                 uint64_t t;
185                 sd_id128_t boot_id;
186
187                 r = -ENOENT;
188
189                 if (monotonic)
190                         r = safe_atou64(monotonic, &t);
191
192                 if (r < 0)
193                         r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
194
195                 if (r < 0) {
196                         log_error("Failed to get monotonic: %s", strerror(-r));
197                         return r;
198                 }
199
200                 fprintf(f, "[%5llu.%06llu]",
201                         (unsigned long long) (t / USEC_PER_SEC),
202                         (unsigned long long) (t % USEC_PER_SEC));
203
204                 n += 1 + 5 + 1 + 6 + 1;
205
206         } else {
207                 char buf[64];
208                 uint64_t x;
209                 time_t t;
210                 struct tm tm;
211
212                 r = -ENOENT;
213
214                 if (realtime)
215                         r = safe_atou64(realtime, &x);
216
217                 if (r < 0)
218                         r = sd_journal_get_realtime_usec(j, &x);
219
220                 if (r < 0) {
221                         log_error("Failed to get realtime: %s", strerror(-r));
222                         return r;
223                 }
224
225                 t = (time_t) (x / USEC_PER_SEC);
226                 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
227                         log_error("Failed to format time.");
228                         return r;
229                 }
230
231                 fputs(buf, f);
232                 n += strlen(buf);
233         }
234
235         if (hostname && shall_print(hostname, hostname_len, flags)) {
236                 fprintf(f, " %.*s", (int) hostname_len, hostname);
237                 n += hostname_len + 1;
238         }
239
240         if (identifier && shall_print(identifier, identifier_len, flags)) {
241                 fprintf(f, " %.*s", (int) identifier_len, identifier);
242                 n += identifier_len + 1;
243         } else if (comm && shall_print(comm, comm_len, flags)) {
244                 fprintf(f, " %.*s", (int) comm_len, comm);
245                 n += comm_len + 1;
246         } else
247                 fputc(' ', f);
248
249         if (pid && shall_print(pid, pid_len, flags)) {
250                 fprintf(f, "[%.*s]", (int) pid_len, pid);
251                 n += pid_len + 2;
252         } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
253                 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
254                 n += fake_pid_len + 2;
255         }
256
257         if (flags & OUTPUT_COLOR) {
258                 if (p <= LOG_ERR) {
259                         color_on = ANSI_HIGHLIGHT_RED_ON;
260                         color_off = ANSI_HIGHLIGHT_OFF;
261                 } else if (p <= LOG_NOTICE) {
262                         color_on = ANSI_HIGHLIGHT_ON;
263                         color_off = ANSI_HIGHLIGHT_OFF;
264                 }
265         }
266
267         if (flags & OUTPUT_SHOW_ALL)
268                 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
269         else if (!utf8_is_printable_n(message, message_len)) {
270                 char bytes[FORMAT_BYTES_MAX];
271                 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
272         } else if ((flags & OUTPUT_FULL_WIDTH) || (message_len + n + 1 < n_columns))
273                 fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
274         else if (n < n_columns && n_columns - n - 2 >= 3) {
275                 char *e;
276
277                 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
278
279                 if (!e)
280                         fprintf(f, ": %s%.*s%s\n", color_on, (int) message_len, message, color_off);
281                 else
282                         fprintf(f, ": %s%s%s\n", color_on, e, color_off);
283
284                 free(e);
285         } else
286                 fputs("\n", f);
287
288         if (flags & OUTPUT_CATALOG)
289                 print_catalog(f, j);
290
291         return 0;
292 }
293
294 static int output_verbose(
295                 FILE *f,
296                 sd_journal *j,
297                 OutputMode mode,
298                 unsigned n_columns,
299                 OutputFlags flags) {
300
301         const void *data;
302         size_t length;
303         char *cursor;
304         uint64_t realtime;
305         char ts[FORMAT_TIMESTAMP_MAX];
306         int r;
307
308         assert(f);
309         assert(j);
310
311         r = sd_journal_get_realtime_usec(j, &realtime);
312         if (r < 0) {
313                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
314                 return r;
315         }
316
317         r = sd_journal_get_cursor(j, &cursor);
318         if (r < 0) {
319                 log_error("Failed to get cursor: %s", strerror(-r));
320                 return r;
321         }
322
323         fprintf(f, "%s [%s]\n",
324                 format_timestamp(ts, sizeof(ts), realtime),
325                 cursor);
326
327         free(cursor);
328
329         SD_JOURNAL_FOREACH_DATA(j, data, length) {
330                 if (!shall_print(data, length, flags)) {
331                         const char *c;
332                         char bytes[FORMAT_BYTES_MAX];
333
334                         c = memchr(data, '=', length);
335                         if (!c) {
336                                 log_error("Invalid field.");
337                                 return -EINVAL;
338                         }
339
340                         fprintf(f, "\t%.*s=[%s blob data]\n",
341                                (int) (c - (const char*) data),
342                                (const char*) data,
343                                format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
344                 } else
345                         fprintf(f, "\t%.*s\n", (int) length, (const char*) data);
346         }
347
348         if (flags & OUTPUT_CATALOG)
349                 print_catalog(f, j);
350
351         return 0;
352 }
353
354 static int output_export(
355                 FILE *f,
356                 sd_journal *j,
357                 OutputMode mode,
358                 unsigned n_columns,
359                 OutputFlags flags) {
360
361         sd_id128_t boot_id;
362         char sid[33];
363         int r;
364         usec_t realtime, monotonic;
365         char *cursor;
366         const void *data;
367         size_t length;
368
369         assert(j);
370
371         r = sd_journal_get_realtime_usec(j, &realtime);
372         if (r < 0) {
373                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
374                 return r;
375         }
376
377         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
378         if (r < 0) {
379                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
380                 return r;
381         }
382
383         r = sd_journal_get_cursor(j, &cursor);
384         if (r < 0) {
385                 log_error("Failed to get cursor: %s", strerror(-r));
386                 return r;
387         }
388
389         fprintf(f,
390                 "__CURSOR=%s\n"
391                 "__REALTIME_TIMESTAMP=%llu\n"
392                 "__MONOTONIC_TIMESTAMP=%llu\n"
393                 "_BOOT_ID=%s\n",
394                 cursor,
395                 (unsigned long long) realtime,
396                 (unsigned long long) monotonic,
397                 sd_id128_to_string(boot_id, sid));
398
399         free(cursor);
400
401         SD_JOURNAL_FOREACH_DATA(j, data, length) {
402
403                 /* We already printed the boot id, from the data in
404                  * the header, hence let's suppress it here */
405                 if (length >= 9 &&
406                     memcmp(data, "_BOOT_ID=", 9) == 0)
407                         continue;
408
409                 if (!utf8_is_printable_n(data, length)) {
410                         const char *c;
411                         uint64_t le64;
412
413                         c = memchr(data, '=', length);
414                         if (!c) {
415                                 log_error("Invalid field.");
416                                 return -EINVAL;
417                         }
418
419                         fwrite(data, c - (const char*) data, 1, f);
420                         fputc('\n', f);
421                         le64 = htole64(length - (c - (const char*) data) - 1);
422                         fwrite(&le64, sizeof(le64), 1, f);
423                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
424                 } else
425                         fwrite(data, length, 1, f);
426
427                 fputc('\n', f);
428         }
429
430         fputc('\n', f);
431
432         return 0;
433 }
434
435 void json_escape(
436                 FILE *f,
437                 const char* p,
438                 size_t l,
439                 OutputFlags flags) {
440
441         assert(f);
442         assert(p);
443
444         if (!(flags & OUTPUT_SHOW_ALL) && l > JSON_THRESHOLD)
445
446                 fputs("null", f);
447
448         else if (!utf8_is_printable_n(p, l)) {
449                 bool not_first = false;
450
451                 fputs("[ ", f);
452
453                 while (l > 0) {
454                         if (not_first)
455                                 fprintf(f, ", %u", (uint8_t) *p);
456                         else {
457                                 not_first = true;
458                                 fprintf(f, "%u", (uint8_t) *p);
459                         }
460
461                         p++;
462                         l--;
463                 }
464
465                 fputs(" ]", f);
466         } else {
467                 fputc('\"', f);
468
469                 while (l > 0) {
470                         if (*p == '"' || *p == '\\') {
471                                 fputc('\\', f);
472                                 fputc(*p, f);
473                         } else if (*p < ' ')
474                                 fprintf(f, "\\u%04x", *p);
475                         else
476                                 fputc(*p, f);
477
478                         p++;
479                         l--;
480                 }
481
482                 fputc('\"', f);
483         }
484 }
485
486 static int output_json(
487                 FILE *f,
488                 sd_journal *j,
489                 OutputMode mode,
490                 unsigned n_columns,
491                 OutputFlags flags) {
492
493         uint64_t realtime, monotonic;
494         char *cursor, *k;
495         const void *data;
496         size_t length;
497         sd_id128_t boot_id;
498         char sid[33];
499         int r;
500         Hashmap *h = NULL;
501         bool done, separator;
502
503         assert(j);
504
505         r = sd_journal_get_realtime_usec(j, &realtime);
506         if (r < 0) {
507                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
508                 return r;
509         }
510
511         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
512         if (r < 0) {
513                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
514                 return r;
515         }
516
517         r = sd_journal_get_cursor(j, &cursor);
518         if (r < 0) {
519                 log_error("Failed to get cursor: %s", strerror(-r));
520                 return r;
521         }
522
523         if (mode == OUTPUT_JSON_PRETTY)
524                 fprintf(f,
525                         "{\n"
526                         "\t\"__CURSOR\" : \"%s\",\n"
527                         "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
528                         "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
529                         "\t\"_BOOT_ID\" : \"%s\"",
530                         cursor,
531                         (unsigned long long) realtime,
532                         (unsigned long long) monotonic,
533                         sd_id128_to_string(boot_id, sid));
534         else {
535                 if (mode == OUTPUT_JSON_SSE)
536                         fputs("data: ", f);
537
538                 fprintf(f,
539                         "{ \"__CURSOR\" : \"%s\", "
540                         "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
541                         "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
542                         "\"_BOOT_ID\" : \"%s\"",
543                         cursor,
544                         (unsigned long long) realtime,
545                         (unsigned long long) monotonic,
546                         sd_id128_to_string(boot_id, sid));
547         }
548         free(cursor);
549
550         h = hashmap_new(string_hash_func, string_compare_func);
551         if (!h)
552                 return -ENOMEM;
553
554         /* First round, iterate through the entry and count how often each field appears */
555         SD_JOURNAL_FOREACH_DATA(j, data, length) {
556                 const char *eq;
557                 char *n;
558                 unsigned u;
559
560                 if (length >= 9 &&
561                     memcmp(data, "_BOOT_ID=", 9) == 0)
562                         continue;
563
564                 eq = memchr(data, '=', length);
565                 if (!eq)
566                         continue;
567
568                 n = strndup(data, eq - (const char*) data);
569                 if (!n) {
570                         r = -ENOMEM;
571                         goto finish;
572                 }
573
574                 u = PTR_TO_UINT(hashmap_get(h, n));
575                 if (u == 0) {
576                         r = hashmap_put(h, n, UINT_TO_PTR(1));
577                         if (r < 0) {
578                                 free(n);
579                                 goto finish;
580                         }
581                 } else {
582                         r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
583                         free(n);
584                         if (r < 0)
585                                 goto finish;
586                 }
587         }
588
589         separator = true;
590         do {
591                 done = true;
592
593                 SD_JOURNAL_FOREACH_DATA(j, data, length) {
594                         const char *eq;
595                         char *kk, *n;
596                         size_t m;
597                         unsigned u;
598
599                         /* We already printed the boot id, from the data in
600                          * the header, hence let's suppress it here */
601                         if (length >= 9 &&
602                             memcmp(data, "_BOOT_ID=", 9) == 0)
603                                 continue;
604
605                         eq = memchr(data, '=', length);
606                         if (!eq)
607                                 continue;
608
609                         if (separator) {
610                                 if (mode == OUTPUT_JSON_PRETTY)
611                                         fputs(",\n\t", f);
612                                 else
613                                         fputs(", ", f);
614                         }
615
616                         m = eq - (const char*) data;
617
618                         n = strndup(data, m);
619                         if (!n) {
620                                 r = -ENOMEM;
621                                 goto finish;
622                         }
623
624                         u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
625                         if (u == 0) {
626                                 /* We already printed this, let's jump to the next */
627                                 free(n);
628                                 separator = false;
629
630                                 continue;
631                         } else if (u == 1) {
632                                 /* Field only appears once, output it directly */
633
634                                 json_escape(f, data, m, flags);
635                                 fputs(" : ", f);
636
637                                 json_escape(f, eq + 1, length - m - 1, flags);
638
639                                 hashmap_remove(h, n);
640                                 free(kk);
641                                 free(n);
642
643                                 separator = true;
644
645                                 continue;
646
647                         } else {
648                                 /* Field appears multiple times, output it as array */
649                                 json_escape(f, data, m, flags);
650                                 fputs(" : [ ", f);
651                                 json_escape(f, eq + 1, length - m - 1, flags);
652
653                                 /* Iterate through the end of the list */
654
655                                 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
656                                         if (length < m + 1)
657                                                 continue;
658
659                                         if (memcmp(data, n, m) != 0)
660                                                 continue;
661
662                                         if (((const char*) data)[m] != '=')
663                                                 continue;
664
665                                         fputs(", ", f);
666                                         json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
667                                 }
668
669                                 fputs(" ]", f);
670
671                                 hashmap_remove(h, n);
672                                 free(kk);
673                                 free(n);
674
675                                 /* Iterate data fields form the beginning */
676                                 done = false;
677                                 separator = true;
678
679                                 break;
680                         }
681                 }
682
683         } while (!done);
684
685         if (mode == OUTPUT_JSON_PRETTY)
686                 fputs("\n}\n", f);
687         else if (mode == OUTPUT_JSON_SSE)
688                 fputs("}\n\n", f);
689         else
690                 fputs(" }\n", f);
691
692         r = 0;
693
694 finish:
695         while ((k = hashmap_steal_first_key(h)))
696                 free(k);
697
698         hashmap_free(h);
699
700         return r;
701 }
702
703 static int output_cat(
704                 FILE *f,
705                 sd_journal *j,
706                 OutputMode mode,
707                 unsigned n_columns,
708                 OutputFlags flags) {
709
710         const void *data;
711         size_t l;
712         int r;
713
714         assert(j);
715         assert(f);
716
717         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
718         if (r < 0) {
719                 /* An entry without MESSAGE=? */
720                 if (r == -ENOENT)
721                         return 0;
722
723                 log_error("Failed to get data: %s", strerror(-r));
724                 return r;
725         }
726
727         assert(l >= 8);
728
729         fwrite((const char*) data + 8, 1, l - 8, f);
730         fputc('\n', f);
731
732         return 0;
733 }
734
735 static int (*output_funcs[_OUTPUT_MODE_MAX])(
736                 FILE *f,
737                 sd_journal*j,
738                 OutputMode mode,
739                 unsigned n_columns,
740                 OutputFlags flags) = {
741
742         [OUTPUT_SHORT] = output_short,
743         [OUTPUT_SHORT_MONOTONIC] = output_short,
744         [OUTPUT_VERBOSE] = output_verbose,
745         [OUTPUT_EXPORT] = output_export,
746         [OUTPUT_JSON] = output_json,
747         [OUTPUT_JSON_PRETTY] = output_json,
748         [OUTPUT_JSON_SSE] = output_json,
749         [OUTPUT_CAT] = output_cat
750 };
751
752 int output_journal(
753                 FILE *f,
754                 sd_journal *j,
755                 OutputMode mode,
756                 unsigned n_columns,
757                 OutputFlags flags) {
758
759         int ret;
760         assert(mode >= 0);
761         assert(mode < _OUTPUT_MODE_MAX);
762
763         if (n_columns <= 0)
764                 n_columns = columns();
765
766         ret = output_funcs[mode](f, j, mode, n_columns, flags);
767         fflush(stdout);
768         return ret;
769 }
770
771 int show_journal_by_unit(
772                 FILE *f,
773                 const char *unit,
774                 OutputMode mode,
775                 unsigned n_columns,
776                 usec_t not_before,
777                 unsigned how_many,
778                 OutputFlags flags) {
779
780         _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
781         sd_journal *j = NULL;
782         int r;
783         unsigned line = 0;
784         bool need_seek = false;
785         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
786
787         assert(mode >= 0);
788         assert(mode < _OUTPUT_MODE_MAX);
789         assert(unit);
790
791         if (!endswith(unit, ".service") &&
792             !endswith(unit, ".socket") &&
793             !endswith(unit, ".mount") &&
794             !endswith(unit, ".swap"))
795                 return 0;
796
797         if (how_many <= 0)
798                 return 0;
799
800         if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
801             asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
802             asprintf(&m3, "UNIT=%s", unit) < 0) {
803                 r = -ENOMEM;
804                 goto finish;
805         }
806
807         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
808         if (r < 0)
809                 goto finish;
810
811         /* Look for messages from the service itself */
812         r = sd_journal_add_match(j, m1, 0);
813         if (r < 0)
814                 goto finish;
815
816         /* Look for coredumps of the service */
817         r = sd_journal_add_disjunction(j);
818         if (r < 0)
819                 goto finish;
820         r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
821         if (r < 0)
822                 goto finish;
823         r = sd_journal_add_match(j, m2, 0);
824         if (r < 0)
825                 goto finish;
826
827         /* Look for messages from PID 1 about this service */
828         r = sd_journal_add_disjunction(j);
829         if (r < 0)
830                 goto finish;
831         r = sd_journal_add_match(j, "_PID=1", 0);
832         if (r < 0)
833                 goto finish;
834         r = sd_journal_add_match(j, m3, 0);
835         if (r < 0)
836                 goto finish;
837
838         /* Seek to end */
839         r = sd_journal_seek_tail(j);
840         if (r < 0)
841                 goto finish;
842
843         r = sd_journal_previous_skip(j, how_many);
844         if (r < 0)
845                 goto finish;
846
847         for (;;) {
848                 for (;;) {
849                         usec_t usec;
850
851                         if (need_seek) {
852                                 r = sd_journal_next(j);
853                                 if (r < 0)
854                                         goto finish;
855                         }
856
857                         if (r == 0)
858                                 break;
859
860                         need_seek = true;
861
862                         if (not_before > 0) {
863                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
864
865                                 /* -ESTALE is returned if the
866                                    timestamp is not from this boot */
867                                 if (r == -ESTALE)
868                                         continue;
869                                 else if (r < 0)
870                                         goto finish;
871
872                                 if (usec < not_before)
873                                         continue;
874                         }
875
876                         line ++;
877
878                         r = output_journal(f, j, mode, n_columns, flags);
879                         if (r < 0)
880                                 goto finish;
881                 }
882
883                 if (warn_cutoff && line < how_many && not_before > 0) {
884                         sd_id128_t boot_id;
885                         usec_t cutoff;
886
887                         /* Check whether the cutoff line is too early */
888
889                         r = sd_id128_get_boot(&boot_id);
890                         if (r < 0)
891                                 goto finish;
892
893                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
894                         if (r < 0)
895                                 goto finish;
896
897                         if (r > 0 && not_before < cutoff)
898                                 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
899
900                         warn_cutoff = false;
901                 }
902
903                 if (!(flags & OUTPUT_FOLLOW))
904                         break;
905
906                 r = sd_journal_wait(j, (usec_t) -1);
907                 if (r < 0)
908                         goto finish;
909
910         }
911
912 finish:
913         if (j)
914                 sd_journal_close(j);
915
916         return r;
917 }
918
919 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
920         [OUTPUT_SHORT] = "short",
921         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
922         [OUTPUT_VERBOSE] = "verbose",
923         [OUTPUT_EXPORT] = "export",
924         [OUTPUT_JSON] = "json",
925         [OUTPUT_JSON_PRETTY] = "json-pretty",
926         [OUTPUT_JSON_SSE] = "json-sse",
927         [OUTPUT_CAT] = "cat"
928 };
929
930 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);