chiark / gitweb /
logs-show: print multiline messages
[elogind.git] / src / shared / logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2012 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include <time.h>
23 #include <assert.h>
24 #include <errno.h>
25 #include <sys/poll.h>
26 #include <string.h>
27
28 #include "logs-show.h"
29 #include "log.h"
30 #include "util.h"
31 #include "utf8.h"
32 #include "hashmap.h"
33 #include "journal-internal.h"
34
35 #define PRINT_THRESHOLD 128
36 #define JSON_THRESHOLD 4096
37
38 static int print_catalog(FILE *f, sd_journal *j) {
39         int r;
40         _cleanup_free_ char *t = NULL, *z = NULL;
41
42
43         r = sd_journal_get_catalog(j, &t);
44         if (r < 0)
45                 return r;
46
47         z = strreplace(strstrip(t), "\n", "\n-- ");
48         if (!z)
49                 return log_oom();
50
51         fputs("-- ", f);
52         fputs(z, f);
53         fputc('\n', f);
54
55         return 0;
56 }
57
58 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
59         size_t fl, nl;
60         void *buf;
61
62         assert(data);
63         assert(field);
64         assert(target);
65         assert(target_size);
66
67         fl = strlen(field);
68         if (length < fl)
69                 return 0;
70
71         if (memcmp(data, field, fl))
72                 return 0;
73
74         nl = length - fl;
75         buf = malloc(nl+1);
76         if (!buf)
77                 return log_oom();
78
79         memcpy(buf, (const char*) data + fl, nl);
80         ((char*)buf)[nl] = 0;
81
82         free(*target);
83         *target = buf;
84         *target_size = nl;
85
86         return 1;
87 }
88
89 static bool shall_print(const char *p, size_t l, OutputFlags flags) {
90         assert(p);
91
92         if (flags & OUTPUT_SHOW_ALL)
93                 return true;
94
95         if (l >= PRINT_THRESHOLD)
96                 return false;
97
98         if (!utf8_is_printable(p, l))
99                 return false;
100
101         return true;
102 }
103
104 static void print_multiline(FILE *f, unsigned prefix, unsigned n_columns, int flags, int priority, const char* message, size_t message_len) {
105         const char *color_on = "", *color_off = "";
106         const char *pos, *end;
107         bool continuation = false;
108
109         if (flags & OUTPUT_COLOR) {
110                 if (priority <= LOG_ERR) {
111                         color_on = ANSI_HIGHLIGHT_RED_ON;
112                         color_off = ANSI_HIGHLIGHT_OFF;
113                 } else if (priority <= LOG_NOTICE) {
114                         color_on = ANSI_HIGHLIGHT_ON;
115                         color_off = ANSI_HIGHLIGHT_OFF;
116                 }
117         }
118
119         for (pos = message; pos < message + message_len; pos = end + 1) {
120                 int len;
121                 for (end = pos; end < message + message_len && *end != '\n'; end++)
122                         ;
123                 len = end - pos;
124                 assert(len >= 0);
125
126                 if ((flags & OUTPUT_FULL_WIDTH) || (prefix + len + 1 < n_columns))
127                         fprintf(f, "%*s%s%.*s%s\n",
128                                 continuation * prefix, "",
129                                 color_on, len, pos, color_off);
130                 else if (prefix < n_columns && n_columns - prefix >= 3) {
131                         _cleanup_free_ char *e;
132
133                         e = ellipsize_mem(pos, len, n_columns - prefix, 90);
134
135                         if (!e)
136                                 fprintf(f, "%s%.*s%s\n", color_on, len, pos, color_off);
137                         else
138                                 fprintf(f, "%s%s%s\n", color_on, e, color_off);
139                 } else
140                         fputs("...\n", f);
141
142                 continuation = true;
143         }
144 }
145
146 static int output_short(
147                 FILE *f,
148                 sd_journal *j,
149                 OutputMode mode,
150                 unsigned n_columns,
151                 OutputFlags flags) {
152
153         int r;
154         const void *data;
155         size_t length;
156         size_t n = 0;
157         _cleanup_free_ char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL, *priority = NULL;
158         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;
159         int p = LOG_INFO;
160
161         assert(f);
162         assert(j);
163
164         sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : PRINT_THRESHOLD);
165
166         SD_JOURNAL_FOREACH_DATA(j, data, length) {
167
168                 r = parse_field(data, length, "PRIORITY=", &priority, &priority_len);
169                 if (r < 0)
170                         return r;
171                 else if (r > 0)
172                         continue;
173
174                 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
175                 if (r < 0)
176                         return r;
177                 else if (r > 0)
178                         continue;
179
180                 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
181                 if (r < 0)
182                         return r;
183                 else if (r > 0)
184                         continue;
185
186                 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
187                 if (r < 0)
188                         return r;
189                 else if (r > 0)
190                         continue;
191
192                 r = parse_field(data, length, "_PID=", &pid, &pid_len);
193                 if (r < 0)
194                         return r;
195                 else if (r > 0)
196                         continue;
197
198                 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
199                 if (r < 0)
200                         return r;
201                 else if (r > 0)
202                         continue;
203
204                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
205                 if (r < 0)
206                         return r;
207                 else if (r > 0)
208                         continue;
209
210                 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
211                 if (r < 0)
212                         return r;
213                 else if (r > 0)
214                         continue;
215
216                 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
217                 if (r < 0)
218                         return r;
219         }
220
221         if (!message)
222                 return 0;
223
224         if (!(flags & OUTPUT_SHOW_ALL))
225                 strip_tab_ansi(&message, &message_len);
226
227         if (priority_len == 1 && *priority >= '0' && *priority <= '7')
228                 p = *priority - '0';
229
230         if (mode == OUTPUT_SHORT_MONOTONIC) {
231                 uint64_t t;
232                 sd_id128_t boot_id;
233
234                 r = -ENOENT;
235
236                 if (monotonic)
237                         r = safe_atou64(monotonic, &t);
238
239                 if (r < 0)
240                         r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
241
242                 if (r < 0) {
243                         log_error("Failed to get monotonic: %s", strerror(-r));
244                         return r;
245                 }
246
247                 fprintf(f, "[%5llu.%06llu]",
248                         (unsigned long long) (t / USEC_PER_SEC),
249                         (unsigned long long) (t % USEC_PER_SEC));
250
251                 n += 1 + 5 + 1 + 6 + 1;
252
253         } else {
254                 char buf[64];
255                 uint64_t x;
256                 time_t t;
257                 struct tm tm;
258
259                 r = -ENOENT;
260
261                 if (realtime)
262                         r = safe_atou64(realtime, &x);
263
264                 if (r < 0)
265                         r = sd_journal_get_realtime_usec(j, &x);
266
267                 if (r < 0) {
268                         log_error("Failed to get realtime: %s", strerror(-r));
269                         return r;
270                 }
271
272                 t = (time_t) (x / USEC_PER_SEC);
273                 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
274                         log_error("Failed to format time.");
275                         return r;
276                 }
277
278                 fputs(buf, f);
279                 n += strlen(buf);
280         }
281
282         if (hostname && shall_print(hostname, hostname_len, flags)) {
283                 fprintf(f, " %.*s", (int) hostname_len, hostname);
284                 n += hostname_len + 1;
285         }
286
287         if (identifier && shall_print(identifier, identifier_len, flags)) {
288                 fprintf(f, " %.*s", (int) identifier_len, identifier);
289                 n += identifier_len + 1;
290         } else if (comm && shall_print(comm, comm_len, flags)) {
291                 fprintf(f, " %.*s", (int) comm_len, comm);
292                 n += comm_len + 1;
293         } else
294                 fputc(' ', f);
295
296         if (pid && shall_print(pid, pid_len, flags)) {
297                 fprintf(f, "[%.*s]", (int) pid_len, pid);
298                 n += pid_len + 2;
299         } else if (fake_pid && shall_print(fake_pid, fake_pid_len, flags)) {
300                 fprintf(f, "[%.*s]", (int) fake_pid_len, fake_pid);
301                 n += fake_pid_len + 2;
302         }
303
304         if (!(flags & OUTPUT_SHOW_ALL) && !utf8_is_printable(message, message_len)) {
305                 char bytes[FORMAT_BYTES_MAX];
306                 fprintf(f, ": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
307         } else {
308                 fputs(": ", f);
309                 print_multiline(f, n + 2, n_columns, flags, p, message, message_len);
310         }
311
312         if (flags & OUTPUT_CATALOG)
313                 print_catalog(f, j);
314
315         return 0;
316 }
317
318 static int output_verbose(
319                 FILE *f,
320                 sd_journal *j,
321                 OutputMode mode,
322                 unsigned n_columns,
323                 OutputFlags flags) {
324
325         const void *data;
326         size_t length;
327         _cleanup_free_ char *cursor = NULL;
328         uint64_t realtime;
329         char ts[FORMAT_TIMESTAMP_MAX];
330         int r;
331
332         assert(f);
333         assert(j);
334
335         sd_journal_set_data_threshold(j, 0);
336
337         r = sd_journal_get_realtime_usec(j, &realtime);
338         if (r < 0) {
339                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
340                 return r;
341         }
342
343         r = sd_journal_get_cursor(j, &cursor);
344         if (r < 0) {
345                 log_error("Failed to get cursor: %s", strerror(-r));
346                 return r;
347         }
348
349         fprintf(f, "%s [%s]\n",
350                 format_timestamp(ts, sizeof(ts), realtime),
351                 cursor);
352
353         SD_JOURNAL_FOREACH_DATA(j, data, length) {
354                 const char *c;
355                 int fieldlen;
356                 c = memchr(data, '=', length);
357                 if (!c) {
358                         log_error("Invalid field.");
359                         return -EINVAL;
360                 }
361                 fieldlen = c - (const char*) data;
362
363                 if ((flags & OUTPUT_SHOW_ALL) || (length < PRINT_THRESHOLD && utf8_is_printable(data, length))) {
364                         fprintf(f, "    %.*s=", fieldlen, (const char*)data);
365                         print_multiline(f, 4 + fieldlen + 1, 0, OUTPUT_FULL_WIDTH, 0, c + 1, length - fieldlen - 1);
366                 } else {
367                         char bytes[FORMAT_BYTES_MAX];
368
369                         fprintf(f, "    %.*s=[%s blob data]\n",
370                                 (int) (c - (const char*) data),
371                                 (const char*) data,
372                                 format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
373                 }
374         }
375
376         if (flags & OUTPUT_CATALOG)
377                 print_catalog(f, j);
378
379         return 0;
380 }
381
382 static int output_export(
383                 FILE *f,
384                 sd_journal *j,
385                 OutputMode mode,
386                 unsigned n_columns,
387                 OutputFlags flags) {
388
389         sd_id128_t boot_id;
390         char sid[33];
391         int r;
392         usec_t realtime, monotonic;
393         _cleanup_free_ char *cursor = NULL;
394         const void *data;
395         size_t length;
396
397         assert(j);
398
399         sd_journal_set_data_threshold(j, 0);
400
401         r = sd_journal_get_realtime_usec(j, &realtime);
402         if (r < 0) {
403                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
404                 return r;
405         }
406
407         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
408         if (r < 0) {
409                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
410                 return r;
411         }
412
413         r = sd_journal_get_cursor(j, &cursor);
414         if (r < 0) {
415                 log_error("Failed to get cursor: %s", strerror(-r));
416                 return r;
417         }
418
419         fprintf(f,
420                 "__CURSOR=%s\n"
421                 "__REALTIME_TIMESTAMP=%llu\n"
422                 "__MONOTONIC_TIMESTAMP=%llu\n"
423                 "_BOOT_ID=%s\n",
424                 cursor,
425                 (unsigned long long) realtime,
426                 (unsigned long long) monotonic,
427                 sd_id128_to_string(boot_id, sid));
428
429         SD_JOURNAL_FOREACH_DATA(j, data, length) {
430
431                 /* We already printed the boot id, from the data in
432                  * the header, hence let's suppress it here */
433                 if (length >= 9 &&
434                     memcmp(data, "_BOOT_ID=", 9) == 0)
435                         continue;
436
437                 if (!utf8_is_printable(data, length)) {
438                         const char *c;
439                         uint64_t le64;
440
441                         c = memchr(data, '=', length);
442                         if (!c) {
443                                 log_error("Invalid field.");
444                                 return -EINVAL;
445                         }
446
447                         fwrite(data, c - (const char*) data, 1, f);
448                         fputc('\n', f);
449                         le64 = htole64(length - (c - (const char*) data) - 1);
450                         fwrite(&le64, sizeof(le64), 1, f);
451                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, f);
452                 } else
453                         fwrite(data, length, 1, f);
454
455                 fputc('\n', f);
456         }
457
458         fputc('\n', f);
459
460         return 0;
461 }
462
463 void json_escape(
464                 FILE *f,
465                 const char* p,
466                 size_t l,
467                 OutputFlags flags) {
468
469         assert(f);
470         assert(p);
471
472         if (!(flags & OUTPUT_SHOW_ALL) && l >= JSON_THRESHOLD)
473
474                 fputs("null", f);
475
476         else if (!utf8_is_printable(p, l)) {
477                 bool not_first = false;
478
479                 fputs("[ ", f);
480
481                 while (l > 0) {
482                         if (not_first)
483                                 fprintf(f, ", %u", (uint8_t) *p);
484                         else {
485                                 not_first = true;
486                                 fprintf(f, "%u", (uint8_t) *p);
487                         }
488
489                         p++;
490                         l--;
491                 }
492
493                 fputs(" ]", f);
494         } else {
495                 fputc('\"', f);
496
497                 while (l > 0) {
498                         if (*p == '"' || *p == '\\') {
499                                 fputc('\\', f);
500                                 fputc(*p, f);
501                         } else if (*p == '\n')
502                                 fputs("\\n", f);
503                         else if (*p < ' ')
504                                 fprintf(f, "\\u%04x", *p);
505                         else
506                                 fputc(*p, f);
507
508                         p++;
509                         l--;
510                 }
511
512                 fputc('\"', f);
513         }
514 }
515
516 static int output_json(
517                 FILE *f,
518                 sd_journal *j,
519                 OutputMode mode,
520                 unsigned n_columns,
521                 OutputFlags flags) {
522
523         uint64_t realtime, monotonic;
524         _cleanup_free_ char *cursor = NULL;
525         const void *data;
526         size_t length;
527         sd_id128_t boot_id;
528         char sid[33], *k;
529         int r;
530         Hashmap *h = NULL;
531         bool done, separator;
532
533         assert(j);
534
535         sd_journal_set_data_threshold(j, flags & OUTPUT_SHOW_ALL ? 0 : JSON_THRESHOLD);
536
537         r = sd_journal_get_realtime_usec(j, &realtime);
538         if (r < 0) {
539                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
540                 return r;
541         }
542
543         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
544         if (r < 0) {
545                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
546                 return r;
547         }
548
549         r = sd_journal_get_cursor(j, &cursor);
550         if (r < 0) {
551                 log_error("Failed to get cursor: %s", strerror(-r));
552                 return r;
553         }
554
555         if (mode == OUTPUT_JSON_PRETTY)
556                 fprintf(f,
557                         "{\n"
558                         "\t\"__CURSOR\" : \"%s\",\n"
559                         "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
560                         "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
561                         "\t\"_BOOT_ID\" : \"%s\"",
562                         cursor,
563                         (unsigned long long) realtime,
564                         (unsigned long long) monotonic,
565                         sd_id128_to_string(boot_id, sid));
566         else {
567                 if (mode == OUTPUT_JSON_SSE)
568                         fputs("data: ", f);
569
570                 fprintf(f,
571                         "{ \"__CURSOR\" : \"%s\", "
572                         "\"__REALTIME_TIMESTAMP\" : \"%llu\", "
573                         "\"__MONOTONIC_TIMESTAMP\" : \"%llu\", "
574                         "\"_BOOT_ID\" : \"%s\"",
575                         cursor,
576                         (unsigned long long) realtime,
577                         (unsigned long long) monotonic,
578                         sd_id128_to_string(boot_id, sid));
579         }
580
581         h = hashmap_new(string_hash_func, string_compare_func);
582         if (!h)
583                 return -ENOMEM;
584
585         /* First round, iterate through the entry and count how often each field appears */
586         SD_JOURNAL_FOREACH_DATA(j, data, length) {
587                 const char *eq;
588                 char *n;
589                 unsigned u;
590
591                 if (length >= 9 &&
592                     memcmp(data, "_BOOT_ID=", 9) == 0)
593                         continue;
594
595                 eq = memchr(data, '=', length);
596                 if (!eq)
597                         continue;
598
599                 n = strndup(data, eq - (const char*) data);
600                 if (!n) {
601                         r = -ENOMEM;
602                         goto finish;
603                 }
604
605                 u = PTR_TO_UINT(hashmap_get(h, n));
606                 if (u == 0) {
607                         r = hashmap_put(h, n, UINT_TO_PTR(1));
608                         if (r < 0) {
609                                 free(n);
610                                 goto finish;
611                         }
612                 } else {
613                         r = hashmap_update(h, n, UINT_TO_PTR(u + 1));
614                         free(n);
615                         if (r < 0)
616                                 goto finish;
617                 }
618         }
619
620         separator = true;
621         do {
622                 done = true;
623
624                 SD_JOURNAL_FOREACH_DATA(j, data, length) {
625                         const char *eq;
626                         char *kk, *n;
627                         size_t m;
628                         unsigned u;
629
630                         /* We already printed the boot id, from the data in
631                          * the header, hence let's suppress it here */
632                         if (length >= 9 &&
633                             memcmp(data, "_BOOT_ID=", 9) == 0)
634                                 continue;
635
636                         eq = memchr(data, '=', length);
637                         if (!eq)
638                                 continue;
639
640                         if (separator) {
641                                 if (mode == OUTPUT_JSON_PRETTY)
642                                         fputs(",\n\t", f);
643                                 else
644                                         fputs(", ", f);
645                         }
646
647                         m = eq - (const char*) data;
648
649                         n = strndup(data, m);
650                         if (!n) {
651                                 r = -ENOMEM;
652                                 goto finish;
653                         }
654
655                         u = PTR_TO_UINT(hashmap_get2(h, n, (void**) &kk));
656                         if (u == 0) {
657                                 /* We already printed this, let's jump to the next */
658                                 free(n);
659                                 separator = false;
660
661                                 continue;
662                         } else if (u == 1) {
663                                 /* Field only appears once, output it directly */
664
665                                 json_escape(f, data, m, flags);
666                                 fputs(" : ", f);
667
668                                 json_escape(f, eq + 1, length - m - 1, flags);
669
670                                 hashmap_remove(h, n);
671                                 free(kk);
672                                 free(n);
673
674                                 separator = true;
675
676                                 continue;
677
678                         } else {
679                                 /* Field appears multiple times, output it as array */
680                                 json_escape(f, data, m, flags);
681                                 fputs(" : [ ", f);
682                                 json_escape(f, eq + 1, length - m - 1, flags);
683
684                                 /* Iterate through the end of the list */
685
686                                 while (sd_journal_enumerate_data(j, &data, &length) > 0) {
687                                         if (length < m + 1)
688                                                 continue;
689
690                                         if (memcmp(data, n, m) != 0)
691                                                 continue;
692
693                                         if (((const char*) data)[m] != '=')
694                                                 continue;
695
696                                         fputs(", ", f);
697                                         json_escape(f, (const char*) data + m + 1, length - m - 1, flags);
698                                 }
699
700                                 fputs(" ]", f);
701
702                                 hashmap_remove(h, n);
703                                 free(kk);
704                                 free(n);
705
706                                 /* Iterate data fields form the beginning */
707                                 done = false;
708                                 separator = true;
709
710                                 break;
711                         }
712                 }
713
714         } while (!done);
715
716         if (mode == OUTPUT_JSON_PRETTY)
717                 fputs("\n}\n", f);
718         else if (mode == OUTPUT_JSON_SSE)
719                 fputs("}\n\n", f);
720         else
721                 fputs(" }\n", f);
722
723         r = 0;
724
725 finish:
726         while ((k = hashmap_steal_first_key(h)))
727                 free(k);
728
729         hashmap_free(h);
730
731         return r;
732 }
733
734 static int output_cat(
735                 FILE *f,
736                 sd_journal *j,
737                 OutputMode mode,
738                 unsigned n_columns,
739                 OutputFlags flags) {
740
741         const void *data;
742         size_t l;
743         int r;
744
745         assert(j);
746         assert(f);
747
748         sd_journal_set_data_threshold(j, 0);
749
750         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
751         if (r < 0) {
752                 /* An entry without MESSAGE=? */
753                 if (r == -ENOENT)
754                         return 0;
755
756                 log_error("Failed to get data: %s", strerror(-r));
757                 return r;
758         }
759
760         assert(l >= 8);
761
762         fwrite((const char*) data + 8, 1, l - 8, f);
763         fputc('\n', f);
764
765         return 0;
766 }
767
768 static int (*output_funcs[_OUTPUT_MODE_MAX])(
769                 FILE *f,
770                 sd_journal*j,
771                 OutputMode mode,
772                 unsigned n_columns,
773                 OutputFlags flags) = {
774
775         [OUTPUT_SHORT] = output_short,
776         [OUTPUT_SHORT_MONOTONIC] = output_short,
777         [OUTPUT_VERBOSE] = output_verbose,
778         [OUTPUT_EXPORT] = output_export,
779         [OUTPUT_JSON] = output_json,
780         [OUTPUT_JSON_PRETTY] = output_json,
781         [OUTPUT_JSON_SSE] = output_json,
782         [OUTPUT_CAT] = output_cat
783 };
784
785 int output_journal(
786                 FILE *f,
787                 sd_journal *j,
788                 OutputMode mode,
789                 unsigned n_columns,
790                 OutputFlags flags) {
791
792         int ret;
793         assert(mode >= 0);
794         assert(mode < _OUTPUT_MODE_MAX);
795
796         if (n_columns <= 0)
797                 n_columns = columns();
798
799         ret = output_funcs[mode](f, j, mode, n_columns, flags);
800         fflush(stdout);
801         return ret;
802 }
803
804 static int show_journal(FILE *f,
805                         sd_journal *j,
806                         OutputMode mode,
807                         unsigned n_columns,
808                         usec_t not_before,
809                         unsigned how_many,
810                         OutputFlags flags) {
811
812         int r;
813         unsigned line = 0;
814         bool need_seek = false;
815         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
816
817         assert(j);
818         assert(mode >= 0);
819         assert(mode < _OUTPUT_MODE_MAX);
820
821         /* Seek to end */
822         r = sd_journal_seek_tail(j);
823         if (r < 0)
824                 goto finish;
825
826         r = sd_journal_previous_skip(j, how_many);
827         if (r < 0)
828                 goto finish;
829
830         for (;;) {
831                 for (;;) {
832                         usec_t usec;
833
834                         if (need_seek) {
835                                 r = sd_journal_next(j);
836                                 if (r < 0)
837                                         goto finish;
838                         }
839
840                         if (r == 0)
841                                 break;
842
843                         need_seek = true;
844
845                         if (not_before > 0) {
846                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
847
848                                 /* -ESTALE is returned if the
849                                    timestamp is not from this boot */
850                                 if (r == -ESTALE)
851                                         continue;
852                                 else if (r < 0)
853                                         goto finish;
854
855                                 if (usec < not_before)
856                                         continue;
857                         }
858
859                         line ++;
860
861                         r = output_journal(f, j, mode, n_columns, flags);
862                         if (r < 0)
863                                 goto finish;
864                 }
865
866                 if (warn_cutoff && line < how_many && not_before > 0) {
867                         sd_id128_t boot_id;
868                         usec_t cutoff;
869
870                         /* Check whether the cutoff line is too early */
871
872                         r = sd_id128_get_boot(&boot_id);
873                         if (r < 0)
874                                 goto finish;
875
876                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
877                         if (r < 0)
878                                 goto finish;
879
880                         if (r > 0 && not_before < cutoff)
881                                 fprintf(f, "Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
882
883                         warn_cutoff = false;
884                 }
885
886                 if (!(flags & OUTPUT_FOLLOW))
887                         break;
888
889                 r = sd_journal_wait(j, (usec_t) -1);
890                 if (r < 0)
891                         goto finish;
892
893         }
894
895 finish:
896         return r;
897 }
898
899 int add_matches_for_unit(sd_journal *j, const char *unit) {
900         int r;
901         _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL;
902
903         assert(j);
904         assert(unit);
905
906         if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
907             asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
908             asprintf(&m3, "UNIT=%s", unit) < 0)
909                 return -ENOMEM;
910
911         (void)(
912             /* Look for messages from the service itself */
913             (r = sd_journal_add_match(j, m1, 0)) ||
914
915             /* Look for coredumps of the service */
916             (r = sd_journal_add_disjunction(j)) ||
917             (r = sd_journal_add_match(j,
918                         "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0)) ||
919             (r = sd_journal_add_match(j, m2, 0)) ||
920
921              /* Look for messages from PID 1 about this service */
922             (r = sd_journal_add_disjunction(j)) ||
923             (r = sd_journal_add_match(j, "_PID=1", 0)) ||
924             (r = sd_journal_add_match(j, m3, 0))
925         );
926         return r;
927 }
928
929 int add_matches_for_user_unit(sd_journal *j, const char *unit, uid_t uid) {
930         int r;
931         _cleanup_free_ char *m1 = NULL, *m2 = NULL, *m3 = NULL, *m4 = NULL;
932
933         assert(j);
934         assert(unit);
935
936         if (asprintf(&m1, "_SYSTEMD_USER_UNIT=%s", unit) < 0 ||
937             asprintf(&m2, "USER_UNIT=%s", unit) < 0 ||
938             asprintf(&m3, "COREDUMP_USER_UNIT=%s", unit) < 0 ||
939             asprintf(&m4, "_UID=%d", uid) < 0)
940                 return -ENOMEM;
941
942         (void) (
943                 /* Look for messages from the user service itself */
944                 (r = sd_journal_add_match(j, m1, 0)) ||
945                 (r = sd_journal_add_match(j, m4, 0)) ||
946
947                 /* Look for messages from systemd about this service */
948                 (r = sd_journal_add_disjunction(j)) ||
949                 (r = sd_journal_add_match(j, m2, 0)) ||
950                 (r = sd_journal_add_match(j, m4, 0)) ||
951
952                 /* Look for coredumps of the service */
953                 (r = sd_journal_add_disjunction(j)) ||
954                 (r = sd_journal_add_match(j, m3, 0)) ||
955                 (r = sd_journal_add_match(j, m4, 0))
956         );
957         return r;
958 }
959
960 int add_match_this_boot(sd_journal *j) {
961         char match[9+32+1] = "_BOOT_ID=";
962         sd_id128_t boot_id;
963         int r;
964
965         assert(j);
966
967         r = sd_id128_get_boot(&boot_id);
968         if (r < 0) {
969                 log_error("Failed to get boot id: %s", strerror(-r));
970                 return r;
971         }
972
973         sd_id128_to_string(boot_id, match + 9);
974         r = sd_journal_add_match(j, match, strlen(match));
975         if (r < 0) {
976                 log_error("Failed to add match: %s", strerror(-r));
977                 return r;
978         }
979
980         r = sd_journal_add_conjunction(j);
981         if (r < 0)
982                 return r;
983
984         return 0;
985 }
986
987 int show_journal_by_unit(
988                 FILE *f,
989                 const char *unit,
990                 OutputMode mode,
991                 unsigned n_columns,
992                 usec_t not_before,
993                 unsigned how_many,
994                 uid_t uid,
995                 OutputFlags flags,
996                 bool system) {
997
998         _cleanup_journal_close_ sd_journal*j = NULL;
999         int r;
1000         int jflags = SD_JOURNAL_LOCAL_ONLY | system * SD_JOURNAL_SYSTEM_ONLY;
1001
1002         assert(mode >= 0);
1003         assert(mode < _OUTPUT_MODE_MAX);
1004         assert(unit);
1005
1006         if (how_many <= 0)
1007                 return 0;
1008
1009         r = sd_journal_open(&j, jflags);
1010         if (r < 0)
1011                 return r;
1012
1013         r = add_match_this_boot(j);
1014         if (r < 0)
1015                 return r;
1016
1017         if (system)
1018                 r = add_matches_for_unit(j, unit);
1019         else
1020                 r = add_matches_for_user_unit(j, unit, uid);
1021         if (r < 0)
1022                 return r;
1023
1024         log_debug("Journal filter: %s", journal_make_match_string(j));
1025
1026         r = show_journal(f, j, mode, n_columns, not_before, how_many, flags);
1027         if (r < 0)
1028                 return r;
1029
1030         return 0;
1031 }
1032
1033 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
1034         [OUTPUT_SHORT] = "short",
1035         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
1036         [OUTPUT_VERBOSE] = "verbose",
1037         [OUTPUT_EXPORT] = "export",
1038         [OUTPUT_JSON] = "json",
1039         [OUTPUT_JSON_PRETTY] = "json-pretty",
1040         [OUTPUT_JSON_SSE] = "json-sse",
1041         [OUTPUT_CAT] = "cat"
1042 };
1043
1044 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);