chiark / gitweb /
logs-show: add short-precise mode with us timestamps
[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
322                 switch(mode) {
323                 case OUTPUT_SHORT_ISO:
324                         r = strftime(buf, sizeof(buf), "%Y-%m-%dT%H:%M:%S%z", localtime_r(&t, &tm));
325                         break;
326                 case OUTPUT_SHORT_PRECISE:
327                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
328                         if (r > 0) {
329                                 snprintf(buf + strlen(buf), sizeof(buf) - strlen(buf),
330                                          ".%06llu", x % USEC_PER_SEC);
331                         }
332                         break;
333                 default:
334                         r = strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm));
335                 }
336
337                 if (r <= 0) {
338                         log_error("Failed to format time.");
339                         return -EINVAL;
340                 }
341
342                 fputs(buf, f);
343                 n += strlen(buf);
344         }
345
346         if (hostname && shall_print(hostname, hostname_len, flags)) {
347                 fprintf(f, " %.*s", (int) hostname_len, hostname);
348                 n += hostname_len + 1;
349         }
350
351         if (identifier && shall_print(identifier, identifier_len, flags)) {
352                 fprintf(f, " %.*s", (int) identifier_len, identifier);
353                 n += identifier_len + 1;
354         } else if (comm && shall_print(comm, comm_len, flags)) {
355                 fprintf(f, " %.*s", (int) comm_len, comm);
356                 n += comm_len + 1;
357         } else
358                 fputc(' ', f);
359
360         if (pid && shall_print(pid, pid_len, flags)) {
361                 fprintf(f, "[%.*s]", (int) pid_len, pid);
362                 n += pid_len + 2;
363         } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
364                 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
365                 n += fake_pid_len + 2;
366         }
367
368         if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
369                 char bytes[FORMAT_BYTES_MAX];
370                 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
371         } else {
372                 fputs(": ", f);
373                 ellipsized |=
374                         print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
375         }
376
377         if (flags & OUTPUT_CATALOG)
378                 print_catalog(f, j);
379
380         return ellipsized;
381 }
382
383 static int output_verbose(
384                 FILE *f,
385                 sd_journal *j,
386                 OutputMode mode,
387                 unsigned n_columns,
388                 OutputFlags flags) {
389
390         const void *data;
391         size_t length;
392         _cleanup_free_ char *cursor = NULL;
393         uint64_t realtime;
394         char ts[FORMAT_TIMESTAMP_MAX + 7];
395         int r;
396
397         assert(f);
398         assert(j);
399
400         sd_journal_set_data_threshold(j, 0);
401
402         r = sd_journal_get_realtime_usec(j, &realtime);
403         if (r < 0) {
404                 log_full(r == -EADDRNOTAVAIL ? LOG_DEBUG : LOG_ERR,
405                          "Failed to get realtime timestamp: %s", strerror(-r));
406                 return r;
407         }
408
409         r = sd_journal_get_cursor(j, &cursor);
410         if (r < 0) {
411                 log_error("Failed to get cursor: %s", strerror(-r));
412                 return r;
413         }
414
415         fprintf(f, "%s [%s]\n",
416                 format_timestamp_us(ts, sizeof(ts), realtime),
417                 cursor);
418
419         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
420                 const char *c;
421                 int fieldlen;
422                 const char *on = "", *off = "";
423
424                 c = memchr(data, '=', length);
425                 if (!c) {
426                         log_error("Invalid field.");
427                         return -EINVAL;
428                 }
429                 fieldlen = c - (const char*) data;
430
431                 if (flags & OUTPUT_COLOR && startswith(data, "MESSAGE=")) {
432                         on = ANSI_HIGHLIGHT_ON;
433                         off = ANSI_HIGHLIGHT_OFF;
434                 }
435
436                 if (flags & OUTPUT_SHOW_ALL ||
437                     (((length < PRINT_CHAR_THRESHOLD) || flags & OUTPUT_FULL_WIDTH)
438                      && utf8_is_printable(data, length))) {
439                         fprintf(f, "    %s%.*s=", on, fieldlen, (const char*)data);
440                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
441                         fputs(off, f);
442                 } else {
443                         char bytes[FORMAT_BYTES_MAX];
444
445                         fprintf(f, "    %s%.*s=[%s blob data]%s\n",
446                                 on,
447                                 (int) (c - (const char*) data),
448                                 (const char*) data,
449                                 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1),
450                                 off);
451                 }
452         }
453
454         if (r < 0)
455                 return r;
456
457         if (flags & OUTPUT_CATALOG)
458                 print_catalog(f, j);
459
460         return 0;
461 }
462
463 static int output_export(
464                 FILE *f,
465                 sd_journal *j,
466                 OutputMode mode,
467                 unsigned n_columns,
468                 OutputFlags flags) {
469
470         sd_id128_t boot_id;
471         char sid[33];
472         int r;
473         usec_t realtime, monotonic;
474         _cleanup_free_ char *cursor = NULL;
475         const void *data;
476         size_t length;
477
478         assert(j);
479
480         sd_journal_set_data_threshold(j, 0);
481
482         r = sd_journal_get_realtime_usec(j, &realtime);
483         if (r < 0) {
484                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
485                 return r;
486         }
487
488         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
489         if (r < 0) {
490                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
491                 return r;
492         }
493
494         r = sd_journal_get_cursor(j, &cursor);
495         if (r < 0) {
496                 log_error("Failed to get cursor: %s", strerror(-r));
497                 return r;
498         }
499
500         fprintf(f,
501                 "__CURSOR=%s\n"
502                 "__REALTIME_TIMESTAMP=%llu\n"
503                 "__MONOTONIC_TIMESTAMP=%llu\n"
504                 "_BOOT_ID=%s\n",
505                 cursor,
506                 (unsigned long long) realtime,
507                 (unsigned long long) monotonic,
508                 sd_id128_to_string(boot_id, sid));
509
510         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
511
512                 /* We already printed the boot id, from the data in
513                  * the header, hence let's suppress it here */
514                 if (length >= 9 &&
515                     hasprefix(data, "_BOOT_ID="))
516                         continue;
517
518                 if (!utf8_is_printable(data, length)) {
519                         const char *c;
520                         uint64_t le64;
521
522                         c = memchr(data, '=', length);
523                         if (!c) {
524                                 log_error("Invalid field.");
525                                 return -EINVAL;
526                         }
527
528                         fwrite(data, c - (const char*) data, 1, f);
529                         fputc('\n', f);
530                         le64 = htole64(length - (c - (const char*) data) - 1);
531                         fwrite(&le64, sizeof(le64), 1, f);
532                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
533                 } else
534                         fwrite(data, length, 1, f);
535
536                 fputc('\n', f);
537         }
538
539         if (r < 0)
540                 return r;
541
542         fputc('\n', f);
543
544         return 0;
545 }
546
547 void json_escape(
548                 FILE *f,
549                 const char* p,
550                 size_t l,
551                 OutputFlags flags) {
552
553         assert(f);
554         assert(p);
555
556         if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
557
558                 fputs("null", f);
559
560         else if (!utf8_is_printable(p, l)) {
561                 bool not_first = false;
562
563                 fputs("[ ", f);
564
565                 while (l > 0) {
566                         if (not_first)
567                                 fprintf(f, ", %u", (uint8_t) *p);
568                         else {
569                                 not_first = true;
570                                 fprintf(f, "%u", (uint8_t) *p);
571                         }
572
573                         p++;
574                         l--;
575                 }
576
577                 fputs(" ]", f);
578         } else {
579                 fputc('\"', f);
580
581                 while (l > 0) {
582                         if (*p == '"' || *p == '\\') {
583                                 fputc('\\', f);
584                                 fputc(*p, f);
585                         } else if (*p == '\n')
586                                 fputs("\\n", f);
587                         else if (*p < ' ')
588                                 fprintf(f, "\\u%04x", *p);
589                         else
590                                 fputc(*p, f);
591
592                         p++;
593                         l--;
594                 }
595
596                 fputc('\"', f);
597         }
598 }
599
600 static int output_json(
601                 FILE *f,
602                 sd_journal *j,
603                 OutputMode mode,
604                 unsigned n_columns,
605                 OutputFlags flags) {
606
607         uint64_t realtime, monotonic;
608         _cleanup_free_ char *cursor = NULL;
609         const void *data;
610         size_t length;
611         sd_id128_t boot_id;
612         char sid[33], *k;
613         int r;
614         Hashmap *h = NULL;
615         bool done, separator;
616
617         assert(j);
618
619         sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
620
621         r = sd_journal_get_realtime_usec(j, &realtime);
622         if (r < 0) {
623                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
624                 return r;
625         }
626
627         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
628         if (r < 0) {
629                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
630                 return r;
631         }
632
633         r = sd_journal_get_cursor(j, &cursor);
634         if (r < 0) {
635                 log_error("Failed to get cursor: %s", strerror(-r));
636                 return r;
637         }
638
639         if (mode == OUTPUT_JSON_PRETTY)
640                 fprintf(f,
641                         "{\n"
642                         "\t\"__CURSOR\" : \"%s\",\n"
643                         "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
644                         "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
645                         "\t\"_BOOT_ID\" : \"%s\"",
646                         cursor,
647                         (unsigned long long) realtime,
648                         (unsigned long long) monotonic,
649                         sd_id128_to_string(boot_id, sid));
650         else {
651                 if (mode == OUTPUT_JSON_SSE)
652                         fputs("data: ", f);
653
654                 fprintf(f,
655                         "{ \"__CURSOR\" : \"%s\", "
656                         "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
657                         "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
658                         "\"_BOOT_ID\" : \"%s\"",
659                         cursor,
660                         (unsigned long long) realtime,
661                         (unsigned long long) monotonic,
662                         sd_id128_to_string(boot_id, sid));
663         }
664
665         h = hashmap_new(string_hash_func, string_compare_func);
666         if (!h)
667                 return -ENOMEM;
668
669         /* First round, iterate through the entry and count how often each field appears */
670         JOURNAL_FOREACH_DATA_RETVAL(j, data, length, r) {
671                 const char *eq;
672                 char *n;
673                 unsigned u;
674
675                 if (length >= 9 &&
676                     memcmp(data, "_BOOT_ID=", 9) == 0)
677                         continue;
678
679                 eq = memchr(data, '=', length);
680                 if (!eq)
681                         continue;
682
683                 n = strndup(data, eq - (const char*) data);
684                 if (!n) {
685                         r = -ENOMEM;
686                         goto finish;
687                 }
688
689                 u = PTR_TO_UINT(hashmap_get(h, n));
690                 if (u == 0) {
691                         r = hashmap_put(h, n, UINT_TO_PTR(1));
692                         if (r < 0) {
693                                 free(n);
694                                 goto finish;
695                         }
696                 } else {
697                         r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
698                         free(n);
699                         if (r < 0)
700                                 goto finish;
701                 }
702         }
703
704         if (r < 0)
705                 return r;
706
707         separator = true;
708         do {
709                 done = true;
710
711                 SD_JOURNAL_FOREACH_DATA(j, data, length) {
712                         const char *eq;
713                         char *kk, *n;
714                         size_t m;
715                         unsigned u;
716
717                         /* We already printed the boot id, from the data in
718                          * the header, hence let's suppress it here */
719                         if (length >= 9 &&
720                             memcmp(data, "_BOOT_ID=", 9) == 0)
721                                 continue;
722
723                         eq = memchr(data, '=', length);
724                         if (!eq)
725                                 continue;
726
727                         if (separator) {
728                                 if (mode == OUTPUT_JSON_PRETTY)
729                                         fputs(",\n\t", f);
730                                 else
731                                         fputs(", ", f);
732                         }
733
734                         m = eq - (const char*) data;
735
736                         n = strndup(data, m);
737                         if (!n) {
738                                 r = -ENOMEM;
739                                 goto finish;
740                         }
741
742                         u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
743                         if (u == 0) {
744                                 /* We already printed this, let's jump to the next */
745                                 free(n);
746                                 separator = false;
747
748                                 continue;
749                         } else if (u == 1) {
750                                 /* Field only appears once, output it directly */
751
752                                 json_escape(f, data, m, flags);
753                                 fputs(" : ", f);
754
755                                 json_escape(f, eq + 1, length - m - 1, flags);
756
757                                 hashmap_remove(h, n);
758                                 free(kk);
759                                 free(n);
760
761                                 separator = true;
762
763                                 continue;
764
765                         } else {
766                                 /* Field appears multiple times, output it as array */
767                                 json_escape(f, data, m, flags);
768                                 fputs(" : [ ", f);
769                                 json_escape(f, eq + 1, length - m - 1, flags);
770
771                                 /* Iterate through the end of the list */
772
773                                 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
774                                         if (length < m + 1)
775                                                 continue;
776
777                                         if (memcmp(data, n, m) != 0)
778                                                 continue;
779
780                                         if (((const char*) data)[m] != '=')
781                                                 continue;
782
783                                         fputs(", ", f);
784                                         json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
785                                 }
786
787                                 fputs(" ]", f);
788
789                                 hashmap_remove(h, n);
790                                 free(kk);
791                                 free(n);
792
793                                 /* Iterate data fields form the beginning */
794                                 done = false;
795                                 separator = true;
796
797                                 break;
798                         }
799                 }
800
801         } while (!done);
802
803         if (mode == OUTPUT_JSON_PRETTY)
804                 fputs("\n}\n", f);
805         else if (mode == OUTPUT_JSON_SSE)
806                 fputs("}\n\n", f);
807         else
808                 fputs(" }\n", f);
809
810         r = 0;
811
812 finish:
813         while ((k = hashmap_steal_first_key(h)))
814                 free(k);
815
816         hashmap_free(h);
817
818         return r;
819 }
820
821 static int output_cat(
822                 FILE *f,
823                 sd_journal *j,
824                 OutputMode mode,
825                 unsigned n_columns,
826                 OutputFlags flags) {
827
828         const void *data;
829         size_t l;
830         int r;
831
832         assert(j);
833         assert(f);
834
835         sd_journal_set_data_threshold(j, 0);
836
837         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
838         if (r < 0) {
839                 /* An entry without MESSAGE=? */
840                 if (r == -ENOENT)
841                         return 0;
842
843                 log_error("Failed to get data: %s", strerror(-r));
844                 return r;
845         }
846
847         assert(l >= 8);
848
849         fwrite((const char*) data + 8, 1, l - 8, f);
850         fputc('\n', f);
851
852         return 0;
853 }
854
855 static int (*output_funcs[_OUTPUT_MODE_MAX])(
856                 FILE *f,
857                 sd_journal*j,
858                 OutputMode mode,
859                 unsigned n_columns,
860                 OutputFlags flags) = {
861
862         [OUTPUT_SHORT] = output_short,
863         [OUTPUT_SHORT_ISO] = output_short,
864         [OUTPUT_SHORT_PRECISE] = output_short,
865         [OUTPUT_SHORT_MONOTONIC] = output_short,
866         [OUTPUT_VERBOSE] = output_verbose,
867         [OUTPUT_EXPORT] = output_export,
868         [OUTPUT_JSON] = output_json,
869         [OUTPUT_JSON_PRETTY] = output_json,
870         [OUTPUT_JSON_SSE] = output_json,
871         [OUTPUT_CAT] = output_cat
872 };
873
874 int output_journal(
875                 FILE *f,
876                 sd_journal *j,
877                 OutputMode mode,
878                 unsigned n_columns,
879                 OutputFlags flags,
880                 bool *ellipsized) {
881
882         int ret;
883         assert(mode >= 0);
884         assert(mode < _OUTPUT_MODE_MAX);
885
886         if (n_columns <= 0)
887                 n_columns = columns();
888
889         ret = output_funcs[mode](f, j, mode, n_columns, flags);
890         fflush(stdout);
891
892         if (ellipsized && ret > 0)
893                 *ellipsized = true;
894
895         return ret;
896 }
897
898 static int show_journal(FILE *f,
899                         sd_journal *j,
900                         OutputMode mode,
901                         unsigned n_columns,
902                         usec_t not_before,
903                         unsigned how_many,
904                         OutputFlags flags,
905                         bool *ellipsized) {
906
907         int r;
908         unsigned line = 0;
909         bool need_seek = false;
910         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
911
912         assert(j);
913         assert(mode >= 0);
914         assert(mode < _OUTPUT_MODE_MAX);
915
916         /* Seek to end */
917         r = sd_journal_seek_tail(j);
918         if (r < 0)
919                 goto finish;
920
921         r = sd_journal_previous_skip(j, how_many);
922         if (r < 0)
923                 goto finish;
924
925         for (;;) {
926                 for (;;) {
927                         usec_t usec;
928
929                         if (need_seek) {
930                                 r = sd_journal_next(j);
931                                 if (r < 0)
932                                         goto finish;
933                         }
934
935                         if (r == 0)
936                                 break;
937
938                         need_seek = true;
939
940                         if (not_before > 0) {
941                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
942
943                                 /* -ESTALE is returned if the
944                                    timestamp is not from this boot */
945                                 if (r == -ESTALE)
946                                         continue;
947                                 else if (r < 0)
948                                         goto finish;
949
950                                 if (usec < not_before)
951                                         continue;
952                         }
953
954                         line ++;
955
956                         r = output_journal(f, j, mode, n_columns, flags, ellipsized);
957                         if (r < 0)
958                                 goto finish;
959                 }
960
961                 if (warn_cutoff && line < how_many && not_before > 0) {
962                         sd_id128_t boot_id;
963                         usec_t cutoff;
964
965                         /* Check whether the cutoff line is too early */
966
967                         r = sd_id128_get_boot(&boot_id);
968                         if (r < 0)
969                                 goto finish;
970
971                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
972                         if (r < 0)
973                                 goto finish;
974
975                         if (r > 0 && not_before < cutoff)
976                                 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
977
978                         warn_cutoff = false;
979                 }
980
981                 if (!(flags & OUTPUT_FOLLOW))
982                         break;
983
984                 r = sd_journal_wait(j, (usec_t) -1);
985                 if (r < 0)
986                         goto finish;
987
988         }
989
990 finish:
991         return r;
992 }
993
994 int add_matches_for_unit(sd_journal *j, const char *unit) {
995         int r;
996         char *m1, *m2, *m3, *m4;
997
998         assert(j);
999         assert(unit);
1000
1001         m1 = strappenda("_SYSTEMD_UNIT=", unit);
1002         m2 = strappenda("COREDUMP_UNIT=", unit);
1003         m3 = strappenda("UNIT=", unit);
1004         m4 = strappenda("OBJECT_SYSTEMD_UNIT=", unit);
1005
1006         (void)(
1007             /* Look for messages from the service itself */
1008             (r = sd_journal_add_match(j, m1, 0)) ||
1009
1010             /* Look for coredumps of the service */
1011             (r = sd_journal_add_disjunction(j)) ||
1012             (r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
1013             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1014             (r = sd_journal_add_match(j, m2, 0)) ||
1015
1016              /* Look for messages from PID 1 about this service */
1017             (r = sd_journal_add_disjunction(j)) ||
1018             (r = sd_journal_add_match(j, "_PID=1", 0)) ||
1019             (r = sd_journal_add_match(j, m3, 0)) ||
1020
1021             /* Look for messages from authorized daemons about this service */
1022             (r = sd_journal_add_disjunction(j)) ||
1023             (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1024             (r = sd_journal_add_match(j, m4, 0))
1025         );
1026
1027         return r;
1028 }
1029
1030 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
1031         int r;
1032         char *m1, *m2, *m3, *m4;
1033         char muid[sizeof("_UID=") + DECIMAL_STR_MAX(uid_t)];
1034
1035         assert(j);
1036         assert(unit);
1037
1038         m1 = strappenda("_SYSTEMD_USER_UNIT=", unit);
1039         m2 = strappenda("USER_UNIT=", unit);
1040         m3 = strappenda("COREDUMP_USER_UNIT=", unit);
1041         m4 = strappenda("OBJECT_SYSTEMD_USER_UNIT=", unit);
1042         sprintf(muid, "_UID=%lu", (unsigned long) uid);
1043
1044         (void) (
1045                 /* Look for messages from the user service itself */
1046                 (r = sd_journal_add_match(j, m1, 0)) ||
1047                 (r = sd_journal_add_match(j, muid, 0)) ||
1048
1049                 /* Look for messages from systemd about this service */
1050                 (r = sd_journal_add_disjunction(j)) ||
1051                 (r = sd_journal_add_match(j, m2, 0)) ||
1052                 (r = sd_journal_add_match(j, muid, 0)) ||
1053
1054                 /* Look for coredumps of the service */
1055                 (r = sd_journal_add_disjunction(j)) ||
1056                 (r = sd_journal_add_match(j, m3, 0)) ||
1057                 (r = sd_journal_add_match(j, muid, 0)) ||
1058                 (r = sd_journal_add_match(j, "_UID=0", 0)) ||
1059
1060                 /* Look for messages from authorized daemons about this service */
1061                 (r = sd_journal_add_disjunction(j)) ||
1062                 (r = sd_journal_add_match(j, m4, 0)) ||
1063                 (r = sd_journal_add_match(j, muid, 0)) ||
1064                 (r = sd_journal_add_match(j, "_UID=0", 0))
1065         );
1066         return r;
1067 }
1068
1069 int add_match_this_boot(sd_journal *j) {
1070         char match[9+32+1] = "_BOOT_ID=";
1071         sd_id128_t boot_id;
1072         int r;
1073
1074         assert(j);
1075
1076         r = sd_id128_get_boot(&boot_id);
1077         if (r < 0) {
1078                 log_error("Failed to get boot id: %s", strerror(-r));
1079                 return r;
1080         }
1081
1082         sd_id128_to_string(boot_id, match + 9);
1083         r = sd_journal_add_match(j, match, strlen(match));
1084         if (r < 0) {
1085                 log_error("Failed to add match: %s", strerror(-r));
1086                 return r;
1087         }
1088
1089         r = sd_journal_add_conjunction(j);
1090         if (r < 0)
1091                 return r;
1092
1093         return 0;
1094 }
1095
1096 int show_journal_by_unit(
1097                 FILE *f,
1098                 const char *unit,
1099                 OutputMode mode,
1100                 unsigned n_columns,
1101                 usec_t not_before,
1102                 unsigned how_many,
1103                 uid_t uid,
1104                 OutputFlags flags,
1105                 bool system,
1106                 bool *ellipsized) {
1107
1108         _cleanup_journal_close_ sd_journal*j = NULL;
1109         int r;
1110         int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM;
1111
1112         assert(mode >= 0);
1113         assert(mode < _OUTPUT_MODE_MAX);
1114         assert(unit);
1115
1116         if (how_many <= 0)
1117                 return 0;
1118
1119         r = sd_journal_open(&j, jflags);
1120         if (r < 0)
1121                 return r;
1122
1123         r = add_match_this_boot(j);
1124         if (r < 0)
1125                 return r;
1126
1127         if (system)
1128                 r = add_matches_for_unit(j, unit);
1129         else
1130                 r = add_matches_for_user_unit(j, unit, uid);
1131         if (r < 0)
1132                 return r;
1133
1134         if (_unlikely_(log_get_max_level() >= LOG_PRI(LOG_DEBUG))) {
1135                 _cleanup_free_ char *filter;
1136
1137                 filter = journal_make_match_string(j);
1138                 log_debug("Journal filter: %s", filter);
1139         }
1140
1141         return show_journal(f, j, mode, n_columns, not_before, how_many, flags, ellipsized);
1142 }
1143
1144 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1145         [OUTPUT_SHORT] = "short",
1146         [OUTPUT_SHORT_ISO] = "short-iso",
1147         [OUTPUT_SHORT_PRECISE] = "short-precise",
1148         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1149         [OUTPUT_VERBOSE] = "verbose",
1150         [OUTPUT_EXPORT] = "export",
1151         [OUTPUT_JSON] = "json",
1152         [OUTPUT_JSON_PRETTY] = "json-pretty",
1153         [OUTPUT_JSON_SSE] = "json-sse",
1154         [OUTPUT_CAT] = "cat"
1155 };
1156
1157 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);