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