chiark / gitweb /
journalctl: do not ellipsize when using pager
[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
33 #define PRINT_THRESHOLD 128
34
35 static int parse_field(const void *data, size_t length, const char *field, char **target, size_t *target_size) {
36         size_t fl, nl;
37         void *buf;
38
39         assert(data);
40         assert(field);
41         assert(target);
42         assert(target_size);
43
44         fl = strlen(field);
45         if (length < fl)
46                 return 0;
47
48         if (memcmp(data, field, fl))
49                 return 0;
50
51         nl = length - fl;
52         buf = malloc(nl+1);
53         memcpy(buf, (const char*) data + fl, nl);
54         ((char*)buf)[nl] = 0;
55         if (!buf) {
56                 log_error("Out of memory");
57                 return -ENOMEM;
58         }
59
60         free(*target);
61         *target = buf;
62         *target_size = nl;
63
64         return 1;
65 }
66
67 static bool shall_print(bool show_all, char *p, size_t l) {
68         if (show_all)
69                 return true;
70
71         if (l > PRINT_THRESHOLD)
72                 return false;
73
74         if (!utf8_is_printable_n(p, l))
75                 return false;
76
77         return true;
78 }
79
80 static int output_short(sd_journal *j, unsigned line, unsigned n_columns,
81                         OutputFlags flags) {
82         int r;
83         const void *data;
84         size_t length;
85         size_t n = 0;
86         char *hostname = NULL, *identifier = NULL, *comm = NULL, *pid = NULL, *fake_pid = NULL, *message = NULL, *realtime = NULL, *monotonic = NULL;
87         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;
88
89         assert(j);
90
91         SD_JOURNAL_FOREACH_DATA(j, data, length) {
92
93                 r = parse_field(data, length, "_HOSTNAME=", &hostname, &hostname_len);
94                 if (r < 0)
95                         goto finish;
96                 else if (r > 0)
97                         continue;
98
99                 r = parse_field(data, length, "SYSLOG_IDENTIFIER=", &identifier, &identifier_len);
100                 if (r < 0)
101                         goto finish;
102                 else if (r > 0)
103                         continue;
104
105                 r = parse_field(data, length, "_COMM=", &comm, &comm_len);
106                 if (r < 0)
107                         goto finish;
108                 else if (r > 0)
109                         continue;
110
111                 r = parse_field(data, length, "_PID=", &pid, &pid_len);
112                 if (r < 0)
113                         goto finish;
114                 else if (r > 0)
115                         continue;
116
117                 r = parse_field(data, length, "SYSLOG_PID=", &fake_pid, &fake_pid_len);
118                 if (r < 0)
119                         goto finish;
120                 else if (r > 0)
121                         continue;
122
123                 r = parse_field(data, length, "_SOURCE_REALTIME_TIMESTAMP=", &realtime, &realtime_len);
124                 if (r < 0)
125                         goto finish;
126                 else if (r > 0)
127                         continue;
128
129                 r = parse_field(data, length, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic, &monotonic_len);
130                 if (r < 0)
131                         goto finish;
132                 else if (r > 0)
133                         continue;
134
135                 r = parse_field(data, length, "MESSAGE=", &message, &message_len);
136                 if (r < 0)
137                         goto finish;
138         }
139
140         if (!message) {
141                 r = 0;
142                 goto finish;
143         }
144
145         if (flags & OUTPUT_MONOTONIC_MODE) {
146                 uint64_t t;
147                 sd_id128_t boot_id;
148
149                 r = -ENOENT;
150
151                 if (monotonic)
152                         r = safe_atou64(monotonic, &t);
153
154                 if (r < 0)
155                         r = sd_journal_get_monotonic_usec(j, &t, &boot_id);
156
157                 if (r < 0) {
158                         log_error("Failed to get monotonic: %s", strerror(-r));
159                         goto finish;
160                 }
161
162                 printf("[%5llu.%06llu]",
163                        (unsigned long long) (t / USEC_PER_SEC),
164                        (unsigned long long) (t % USEC_PER_SEC));
165
166                 n += 1 + 5 + 1 + 6 + 1;
167
168         } else {
169                 char buf[64];
170                 uint64_t x;
171                 time_t t;
172                 struct tm tm;
173
174                 r = -ENOENT;
175
176                 if (realtime)
177                         r = safe_atou64(realtime, &x);
178
179                 if (r < 0)
180                         r = sd_journal_get_realtime_usec(j, &x);
181
182                 if (r < 0) {
183                         log_error("Failed to get realtime: %s", strerror(-r));
184                         goto finish;
185                 }
186
187                 t = (time_t) (x / USEC_PER_SEC);
188                 if (strftime(buf, sizeof(buf), "%b %d %H:%M:%S", localtime_r(&t, &tm)) <= 0) {
189                         log_error("Failed to format time.");
190                         goto finish;
191                 }
192
193                 fputs(buf, stdout);
194                 n += strlen(buf);
195         }
196
197         if (hostname && shall_print(flags & OUTPUT_SHOW_ALL,
198                                     hostname, hostname_len)) {
199                 printf(" %.*s", (int) hostname_len, hostname);
200                 n += hostname_len + 1;
201         }
202
203         if (identifier && shall_print(flags & OUTPUT_SHOW_ALL,
204                                       identifier, identifier_len)) {
205                 printf(" %.*s", (int) identifier_len, identifier);
206                 n += identifier_len + 1;
207         } else if (comm && shall_print(flags & OUTPUT_SHOW_ALL,
208                                        comm, comm_len)) {
209                 printf(" %.*s", (int) comm_len, comm);
210                 n += comm_len + 1;
211         } else
212                 putchar(' ');
213
214         if (pid && shall_print(flags & OUTPUT_SHOW_ALL, pid, pid_len)) {
215                 printf("[%.*s]", (int) pid_len, pid);
216                 n += pid_len + 2;
217         } else if (fake_pid && shall_print(flags & OUTPUT_SHOW_ALL,
218                                            fake_pid, fake_pid_len)) {
219                 printf("[%.*s]", (int) fake_pid_len, fake_pid);
220                 n += fake_pid_len + 2;
221         }
222
223         if (flags & OUTPUT_SHOW_ALL)
224                 printf(": %.*s\n", (int) message_len, message);
225         else if (!utf8_is_printable_n(message, message_len)) {
226                 char bytes[FORMAT_BYTES_MAX];
227                 printf(": [%s blob data]\n", format_bytes(bytes, sizeof(bytes), message_len));
228         } else if ((flags & OUTPUT_FULL_WIDTH) ||
229                    (message_len + n < n_columns))
230                 printf(": %.*s\n", (int) message_len, message);
231         else if (n < n_columns) {
232                 char *e;
233
234                 e = ellipsize_mem(message, message_len, n_columns - n - 2, 90);
235
236                 if (!e)
237                         printf(": %.*s\n", (int) message_len, message);
238                 else
239                         printf(": %s\n", e);
240
241                 free(e);
242         } else
243                 fputs("\n", stdout);
244
245         r = 0;
246
247 finish:
248         free(hostname);
249         free(identifier);
250         free(comm);
251         free(pid);
252         free(fake_pid);
253         free(message);
254         free(monotonic);
255         free(realtime);
256
257         return r;
258 }
259
260 static int output_short_realtime(sd_journal *j, unsigned line,
261                                  unsigned n_columns, OutputFlags flags) {
262         return output_short(j, line, n_columns, flags & ~OUTPUT_MONOTONIC_MODE);
263 }
264
265 static int output_short_monotonic(sd_journal *j, unsigned line,
266                                   unsigned n_columns, OutputFlags flags) {
267         return output_short(j, line, n_columns, flags | OUTPUT_MONOTONIC_MODE);
268 }
269
270 static int output_verbose(sd_journal *j, unsigned line,
271                           unsigned n_columns, OutputFlags flags) {
272         const void *data;
273         size_t length;
274         char *cursor;
275         uint64_t realtime;
276         char ts[FORMAT_TIMESTAMP_MAX];
277         int r;
278
279         assert(j);
280
281         r = sd_journal_get_realtime_usec(j, &realtime);
282         if (r < 0) {
283                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
284                 return r;
285         }
286
287         r = sd_journal_get_cursor(j, &cursor);
288         if (r < 0) {
289                 log_error("Failed to get cursor: %s", strerror(-r));
290                 return r;
291         }
292
293         printf("%s [%s]\n",
294                format_timestamp(ts, sizeof(ts), realtime),
295                cursor);
296
297         free(cursor);
298
299         SD_JOURNAL_FOREACH_DATA(j, data, length) {
300                 if (!(flags & OUTPUT_SHOW_ALL) && (length > PRINT_THRESHOLD ||
301                                   !utf8_is_printable_n(data, length))) {
302                         const char *c;
303                         char bytes[FORMAT_BYTES_MAX];
304
305                         c = memchr(data, '=', length);
306                         if (!c) {
307                                 log_error("Invalid field.");
308                                 return -EINVAL;
309                         }
310
311                         printf("\t%.*s=[%s blob data]\n",
312                                (int) (c - (const char*) data),
313                                (const char*) data,
314                                format_bytes(bytes, sizeof(bytes), length - (c - (const char *) data) - 1));
315                 } else
316                         printf("\t%.*s\n", (int) length, (const char*) data);
317         }
318
319         return 0;
320 }
321
322 static int output_export(sd_journal *j, unsigned line,
323                          unsigned n_columns, OutputFlags flags) {
324         sd_id128_t boot_id;
325         char sid[33];
326         int r;
327         usec_t realtime, monotonic;
328         char *cursor;
329         const void *data;
330         size_t length;
331
332         assert(j);
333
334         r = sd_journal_get_realtime_usec(j, &realtime);
335         if (r < 0) {
336                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
337                 return r;
338         }
339
340         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
341         if (r < 0) {
342                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
343                 return r;
344         }
345
346         r = sd_journal_get_cursor(j, &cursor);
347         if (r < 0) {
348                 log_error("Failed to get cursor: %s", strerror(-r));
349                 return r;
350         }
351
352         printf("__CURSOR=%s\n"
353                "__REALTIME_TIMESTAMP=%llu\n"
354                "__MONOTONIC_TIMESTAMP=%llu\n"
355                "_BOOT_ID=%s\n",
356                cursor,
357                (unsigned long long) realtime,
358                (unsigned long long) monotonic,
359                sd_id128_to_string(boot_id, sid));
360
361         free(cursor);
362
363         SD_JOURNAL_FOREACH_DATA(j, data, length) {
364
365                 /* We already printed the boot id, from the data in
366                  * the header, hence let's suppress it here */
367                 if (length >= 9 &&
368                     memcmp(data, "_BOOT_ID=", 9) == 0)
369                         continue;
370
371                 if (!utf8_is_printable_n(data, length)) {
372                         const char *c;
373                         uint64_t le64;
374
375                         c = memchr(data, '=', length);
376                         if (!c) {
377                                 log_error("Invalid field.");
378                                 return -EINVAL;
379                         }
380
381                         fwrite(data, c - (const char*) data, 1, stdout);
382                         fputc('\n', stdout);
383                         le64 = htole64(length - (c - (const char*) data) - 1);
384                         fwrite(&le64, sizeof(le64), 1, stdout);
385                         fwrite(c + 1, length - (c - (const char*) data) - 1, 1, stdout);
386                 } else
387                         fwrite(data, length, 1, stdout);
388
389                 fputc('\n', stdout);
390         }
391
392         fputc('\n', stdout);
393
394         return 0;
395 }
396
397 static void json_escape(const char* p, size_t l) {
398         if (!utf8_is_printable_n(p, l)) {
399                 bool not_first = false;
400
401                 fputs("[ ", stdout);
402
403                 while (l > 0) {
404                         if (not_first)
405                                 printf(", %u", (uint8_t) *p);
406                         else {
407                                 not_first = true;
408                                 printf("%u", (uint8_t) *p);
409                         }
410
411                         p++;
412                         l--;
413                 }
414
415                 fputs(" ]", stdout);
416         } else {
417                 fputc('\"', stdout);
418
419                 while (l > 0) {
420                         if (*p == '"' || *p == '\\') {
421                                 fputc('\\', stdout);
422                                 fputc(*p, stdout);
423                         } else
424                                 fputc(*p, stdout);
425
426                         p++;
427                         l--;
428                 }
429
430                 fputc('\"', stdout);
431         }
432 }
433
434 static int output_json(sd_journal *j, unsigned line,
435                        unsigned n_columns, OutputFlags flags) {
436         uint64_t realtime, monotonic;
437         char *cursor;
438         const void *data;
439         size_t length;
440         sd_id128_t boot_id;
441         char sid[33];
442         int r;
443
444         assert(j);
445
446         r = sd_journal_get_realtime_usec(j, &realtime);
447         if (r < 0) {
448                 log_error("Failed to get realtime timestamp: %s", strerror(-r));
449                 return r;
450         }
451
452         r = sd_journal_get_monotonic_usec(j, &monotonic, &boot_id);
453         if (r < 0) {
454                 log_error("Failed to get monotonic timestamp: %s", strerror(-r));
455                 return r;
456         }
457
458         r = sd_journal_get_cursor(j, &cursor);
459         if (r < 0) {
460                 log_error("Failed to get cursor: %s", strerror(-r));
461                 return r;
462         }
463
464         if (line == 1)
465                 fputc('\n', stdout);
466         else
467                 fputs(",\n", stdout);
468
469         printf("{\n"
470                "\t\"__CURSOR\" : \"%s\",\n"
471                "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
472                "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
473                "\t\"_BOOT_ID\" : \"%s\"",
474                cursor,
475                (unsigned long long) realtime,
476                (unsigned long long) monotonic,
477                sd_id128_to_string(boot_id, sid));
478
479         free(cursor);
480
481         SD_JOURNAL_FOREACH_DATA(j, data, length) {
482                 const char *c;
483
484                 /* We already printed the boot id, from the data in
485                  * the header, hence let's suppress it here */
486                 if (length >= 9 &&
487                     memcmp(data, "_BOOT_ID=", 9) == 0)
488                         continue;
489
490                 c = memchr(data, '=', length);
491                 if (!c) {
492                         log_error("Invalid field.");
493                         return -EINVAL;
494                 }
495
496                 fputs(",\n\t", stdout);
497                 json_escape(data, c - (const char*) data);
498                 fputs(" : ", stdout);
499                 json_escape(c + 1, length - (c - (const char*) data) - 1);
500         }
501
502         fputs("\n}", stdout);
503         fflush(stdout);
504
505         return 0;
506 }
507
508 static int output_cat(sd_journal *j, unsigned line,
509                       unsigned n_columns, OutputFlags flags) {
510         const void *data;
511         size_t l;
512         int r;
513
514         assert(j);
515
516         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
517         if (r < 0) {
518                 log_error("Failed to get data: %s", strerror(-r));
519                 return r;
520         }
521
522         assert(l >= 8);
523
524         fwrite((const char*) data + 8, 1, l - 8, stdout);
525         putchar('\n');
526
527         return 0;
528 }
529
530 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line,
531                                              unsigned n_columns, OutputFlags flags) = {
532         [OUTPUT_SHORT] = output_short_realtime,
533         [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
534         [OUTPUT_VERBOSE] = output_verbose,
535         [OUTPUT_EXPORT] = output_export,
536         [OUTPUT_JSON] = output_json,
537         [OUTPUT_CAT] = output_cat
538 };
539
540 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
541                    unsigned n_columns, OutputFlags flags) {
542         assert(mode >= 0);
543         assert(mode < _OUTPUT_MODE_MAX);
544
545         if (n_columns <= 0)
546                 n_columns = columns();
547
548         return output_funcs[mode](j, line, n_columns, flags);
549 }
550
551 int show_journal_by_unit(
552                 const char *unit,
553                 OutputMode mode,
554                 unsigned n_columns,
555                 usec_t not_before,
556                 unsigned how_many,
557                 OutputFlags flags) {
558
559         char *m = NULL;
560         sd_journal *j = NULL;
561         int r;
562         unsigned line = 0;
563         bool need_seek = false;
564         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
565
566         assert(mode >= 0);
567         assert(mode < _OUTPUT_MODE_MAX);
568         assert(unit);
569
570         if (!endswith(unit, ".service") &&
571             !endswith(unit, ".socket") &&
572             !endswith(unit, ".mount") &&
573             !endswith(unit, ".swap"))
574                 return 0;
575
576         if (how_many <= 0)
577                 return 0;
578
579         if (asprintf(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
580                 r = -ENOMEM;
581                 goto finish;
582         }
583
584         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
585         if (r < 0)
586                 goto finish;
587
588         r = sd_journal_add_match(j, m, strlen(m));
589         if (r < 0)
590                 goto finish;
591
592         r = sd_journal_seek_tail(j);
593         if (r < 0)
594                 goto finish;
595
596         r = sd_journal_previous_skip(j, how_many);
597         if (r < 0)
598                 goto finish;
599
600         if (mode == OUTPUT_JSON) {
601                 fputc('[', stdout);
602                 fflush(stdout);
603         }
604
605         for (;;) {
606                 for (;;) {
607                         usec_t usec;
608
609                         if (need_seek) {
610                                 r = sd_journal_next(j);
611                                 if (r < 0)
612                                         goto finish;
613                         }
614
615                         if (r == 0)
616                                 break;
617
618                         need_seek = true;
619
620                         if (not_before > 0) {
621                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
622
623                                 /* -ESTALE is returned if the
624                                    timestamp is not from this boot */
625                                 if (r == -ESTALE)
626                                         continue;
627                                 else if (r < 0)
628                                         goto finish;
629
630                                 if (usec < not_before)
631                                         continue;
632                         }
633
634                         line ++;
635
636                         r = output_journal(j, mode, line, n_columns, flags);
637                         if (r < 0)
638                                 goto finish;
639                 }
640
641                 if (warn_cutoff && line < how_many && not_before > 0) {
642                         sd_id128_t boot_id;
643                         usec_t cutoff;
644
645                         /* Check whether the cutoff line is too early */
646
647                         r = sd_id128_get_boot(&boot_id);
648                         if (r < 0)
649                                 goto finish;
650
651                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
652                         if (r < 0)
653                                 goto finish;
654
655                         if (r > 0 && not_before < cutoff)
656                                 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
657
658                         warn_cutoff = false;
659                 }
660
661                 if (!(flags & OUTPUT_FOLLOW))
662                         break;
663
664                 r = sd_journal_wait(j, (usec_t) -1);
665                 if (r < 0)
666                         goto finish;
667
668         }
669
670         if (mode == OUTPUT_JSON)
671                 fputs("\n]\n", stdout);
672
673 finish:
674         if (m)
675                 free(m);
676
677         if (j)
678                 sd_journal_close(j);
679
680         return r;
681 }
682
683 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
684         [OUTPUT_SHORT] = "short",
685         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
686         [OUTPUT_VERBOSE] = "verbose",
687         [OUTPUT_EXPORT] = "export",
688         [OUTPUT_JSON] = "json",
689         [OUTPUT_CAT] = "cat"
690 };
691
692 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);