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