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