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