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