chiark / gitweb /
dev-setup: allow a path prefix for use in chroots
[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 *m = 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(&m, "_SYSTEMD_UNIT=%s", unit) < 0) {
601                 r = -ENOMEM;
602                 goto finish;
603         }
604
605         r = sd_journal_open(&j, SD_JOURNAL_LOCAL_ONLY|SD_JOURNAL_SYSTEM_ONLY);
606         if (r < 0)
607                 goto finish;
608
609         r = sd_journal_add_match(j, m, strlen(m));
610         if (r < 0)
611                 goto finish;
612
613         r = sd_journal_seek_tail(j);
614         if (r < 0)
615                 goto finish;
616
617         r = sd_journal_previous_skip(j, how_many);
618         if (r < 0)
619                 goto finish;
620
621         if (mode == OUTPUT_JSON) {
622                 fputc('[', stdout);
623                 fflush(stdout);
624         }
625
626         for (;;) {
627                 for (;;) {
628                         usec_t usec;
629
630                         if (need_seek) {
631                                 r = sd_journal_next(j);
632                                 if (r < 0)
633                                         goto finish;
634                         }
635
636                         if (r == 0)
637                                 break;
638
639                         need_seek = true;
640
641                         if (not_before > 0) {
642                                 r = sd_journal_get_monotonic_usec(j, &usec, NULL);
643
644                                 /* -ESTALE is returned if the
645                                    timestamp is not from this boot */
646                                 if (r == -ESTALE)
647                                         continue;
648                                 else if (r < 0)
649                                         goto finish;
650
651                                 if (usec < not_before)
652                                         continue;
653                         }
654
655                         line ++;
656
657                         r = output_journal(j, mode, line, n_columns, flags);
658                         if (r < 0)
659                                 goto finish;
660                 }
661
662                 if (warn_cutoff && line < how_many && not_before > 0) {
663                         sd_id128_t boot_id;
664                         usec_t cutoff;
665
666                         /* Check whether the cutoff line is too early */
667
668                         r = sd_id128_get_boot(&boot_id);
669                         if (r < 0)
670                                 goto finish;
671
672                         r = sd_journal_get_cutoff_monotonic_usec(j, boot_id, &cutoff, NULL);
673                         if (r < 0)
674                                 goto finish;
675
676                         if (r > 0 && not_before < cutoff)
677                                 printf("Warning: Journal has been rotated since unit was started. Log output is incomplete or unavailable.\n");
678
679                         warn_cutoff = false;
680                 }
681
682                 if (!(flags & OUTPUT_FOLLOW))
683                         break;
684
685                 r = sd_journal_wait(j, (usec_t) -1);
686                 if (r < 0)
687                         goto finish;
688
689         }
690
691         if (mode == OUTPUT_JSON)
692                 fputs("\n]\n", stdout);
693
694 finish:
695         if (m)
696                 free(m);
697
698         if (j)
699                 sd_journal_close(j);
700
701         return r;
702 }
703
704 static const char *const output_mode_table[_OUTPUT_MODE_MAX] = {
705         [OUTPUT_SHORT] = "short",
706         [OUTPUT_SHORT_MONOTONIC] = "short-monotonic",
707         [OUTPUT_VERBOSE] = "verbose",
708         [OUTPUT_EXPORT] = "export",
709         [OUTPUT_JSON] = "json",
710         [OUTPUT_CAT] = "cat"
711 };
712
713 DEFINE_STRING_TABLE_LOOKUP(output_mode, OutputMode);