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