chiark / gitweb /
path-util: in path_is_mount_point() fall back to the classic stat() test if fs does...
[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
525         return 0;
526 }
527
528 static int output_cat(sd_journal *j, unsigned line,
529                       unsigned n_columns, OutputFlags flags) {
530         const void *data;
531         size_t l;
532         int r;
533
534         assert(j);
535
536         r = sd_journal_get_data(j, "MESSAGE", &data, &l);
537         if (r < 0) {
538                 log_error("Failed to get data: %s", strerror(-r));
539                 return r;
540         }
541
542         assert(l >= 8);
543
544         fwrite((const char*) data + 8, 1, l - 8, stdout);
545         putchar('\n');
546
547         return 0;
548 }
549
550 static int (*output_funcs[_OUTPUT_MODE_MAX])(sd_journal*j, unsigned line,
551                                              unsigned n_columns, OutputFlags flags) = {
552         [OUTPUT_SHORT] = output_short_realtime,
553         [OUTPUT_SHORT_MONOTONIC] = output_short_monotonic,
554         [OUTPUT_VERBOSE] = output_verbose,
555         [OUTPUT_EXPORT] = output_export,
556         [OUTPUT_JSON] = output_json,
557         [OUTPUT_CAT] = output_cat
558 };
559
560 int output_journal(sd_journal *j, OutputMode mode, unsigned line,
561                    unsigned n_columns, OutputFlags flags) {
562         int ret;
563         assert(mode >= 0);
564         assert(mode < _OUTPUT_MODE_MAX);
565
566         if (n_columns <= 0)
567                 n_columns = columns();
568
569         ret = output_funcs[mode](j, line, n_columns, flags);
570         fflush(stdout);
571         return ret;
572 }
573
574 int show_journal_by_unit(
575                 const char *unit,
576                 OutputMode mode,
577                 unsigned n_columns,
578                 usec_t not_before,
579                 unsigned how_many,
580                 OutputFlags flags) {
581
582         char *m1 = NULL, *m2 = NULL, *m3 = NULL;
583         sd_journal *j = NULL;
584         int r;
585         unsigned line = 0;
586         bool need_seek = false;
587         int warn_cutoff = flags & OUTPUT_WARN_CUTOFF;
588
589         assert(mode >= 0);
590         assert(mode < _OUTPUT_MODE_MAX);
591         assert(unit);
592
593         if (!endswith(unit, ".service") &&
594             !endswith(unit, ".socket") &&
595             !endswith(unit, ".mount") &&
596             !endswith(unit, ".swap"))
597                 return 0;
598
599         if (how_many <= 0)
600                 return 0;
601
602         if (asprintf(&m1, "_SYSTEMD_UNIT=%s", unit) < 0 ||
603             asprintf(&m2, "COREDUMP_UNIT=%s", unit) < 0 ||
604             asprintf(&m3, "UNIT=%s", unit) < 0) {
605                 r = -ENOMEM;
606                 goto finish;
607         }
608
609         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
610         if (r < 0)
611                 goto finish;
612
613         /* Look for messages from the service itself */
614         r = sd_journal_add_match(j, m1, 0);
615         if (r < 0)
616                 goto finish;
617
618         /* Look for coredumps of the service */
619         r = sd_journal_add_disjunction(j);
620         if (r < 0)
621                 goto finish;
622         r = sd_journal_add_match(j, "MESSAGE_ID=fc2e22bc6ee647b6b90729ab34a250b1", 0);
623         if (r < 0)
624                 goto finish;
625         r = sd_journal_add_match(j, m2, 0);
626         if (r < 0)
627                 goto finish;
628
629         /* Look for messages from PID 1 about this service */
630         r = sd_journal_add_disjunction(j);
631         if (r < 0)
632                 goto finish;
633         r = sd_journal_add_match(j, "_PID=1", 0);
634         if (r < 0)
635                 goto finish;
636         r = sd_journal_add_match(j, m3, 0);
637         if (r < 0)
638                 goto finish;
639
640         /* Seek to end */
641         r = sd_journal_seek_tail(j);
642         if (r < 0)
643                 goto finish;
644
645         r = sd_journal_previous_skip(j, how_many);
646         if (r < 0)
647                 goto finish;
648
649         if (mode == OUTPUT_JSON) {
650                 fputc('[', stdout);
651                 fflush(stdout);
652         }
653
654         for (;;) {
655                 for (;;) {
656                         usec_t usec;
657
658                         if (need_seek) {
659                                 r = sd_journal_next(j);
660                                 if (r < 0)
661                                         goto finish;
662                         }
663
664                         if (r == 0)
665                                 break;
666
667                         need_seek = true;
668
669                         if (not_before > 0) {
670                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
671
672                                 /* -ESTALE is returned if the
673                                    timestamp is not from this boot */
674                                 if (r == -ESTALE)
675                                         continue;
676                                 else if (r < 0)
677                                         goto finish;
678
679                                 if (usec < not_before)
680                                         continue;
681                         }
682
683                         line ++;
684
685                         r = output_journal(j, mode, line, n_columns, flags);
686                         if (r < 0)
687                                 goto finish;
688                 }
689
690                 if (warn_cutoff && line < how_many && not_before > 0) {
691                         sd_id128_t boot_id;
692                         usec_t cutoff;
693
694                         /* Check whether the cutoff line is too early */
695
696                         r = sd_id128_get_boot(&boot_id);
697                         if (r < 0)
698                                 goto finish;
699
700                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
701                         if (r < 0)
702                                 goto finish;
703
704                         if (r > 0 && not_before < cutoff)
705                                 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
706
707                         warn_cutoff = false;
708                 }
709
710                 if (!(flags & OUTPUT_FOLLOW))
711                         break;
712
713                 r = sd_journal_wait(j, (usec_t) -1);
714                 if (r < 0)
715                         goto finish;
716
717         }
718
719         if (mode == OUTPUT_JSON)
720                 fputs("\n]\n", stdout);
721
722 finish:
723         free(m1);
724         free(m2);
725         free(m3);
726
727         if (j)
728                 sd_journal_close(j);
729
730         return r;
731 }
732
733 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
734         [OUTPUT_SHORT] = "short",
735         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
736         [OUTPUT_VERBOSE] = "verbose",
737         [OUTPUT_EXPORT] = "export",
738         [OUTPUT_JSON] = "json",
739         [OUTPUT_CAT] = "cat"
740 };
741
742 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);