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