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