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