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