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