]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/logs-show.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2012 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
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 General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
28 #include "logs-show.h"
32 #define PRINT_THRESHOLD 128
34 static bool contains_unprintable(const void *p
, size_t l
) {
37 for (j
= p
; j
< (const char *) p
+ l
; j
++)
38 if (*j
< ' ' || *j
>= 127)
44 static int parse_field(const void *data
, size_t length
, const char *field
, char **target
, size_t *target_size
) {
57 if (memcmp(data
, field
, fl
))
62 memcpy(buf
, (const char*) data
+ fl
, nl
);
65 log_error("Out of memory");
76 static bool shall_print(bool show_all
, char *p
, size_t l
) {
80 if (l
> PRINT_THRESHOLD
)
83 if (contains_unprintable(p
, l
))
89 static int output_short(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
, bool monotonic_mode
) {
94 char *hostname
= NULL
, *identifier
= NULL
, *comm
= NULL
, *pid
= NULL
, *fake_pid
= NULL
, *message
= NULL
, *realtime
= NULL
, *monotonic
= NULL
;
95 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;
99 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
101 r
= parse_field(data
, length
, "_HOSTNAME=", &hostname
, &hostname_len
);
107 r
= parse_field(data
, length
, "SYSLOG_IDENTIFIER=", &identifier
, &identifier_len
);
113 r
= parse_field(data
, length
, "_COMM=", &comm
, &comm_len
);
119 r
= parse_field(data
, length
, "_PID=", &pid
, &pid_len
);
125 r
= parse_field(data
, length
, "SYSLOG_PID=", &fake_pid
, &fake_pid_len
);
131 r
= parse_field(data
, length
, "_SOURCE_REALTIME_TIMESTAMP=", &realtime
, &realtime_len
);
137 r
= parse_field(data
, length
, "_SOURCE_MONOTONIC_TIMESTAMP=", &monotonic
, &monotonic_len
);
143 r
= parse_field(data
, length
, "MESSAGE=", &message
, &message_len
);
153 if (monotonic_mode
) {
160 r
= safe_atou64(monotonic
, &t
);
163 r
= sd_journal_get_monotonic_usec(j
, &t
, &boot_id
);
166 log_error("Failed to get monotonic: %s", strerror(-r
));
170 printf("[%5llu.%06llu]",
171 (unsigned long long) (t
/ USEC_PER_SEC
),
172 (unsigned long long) (t
% USEC_PER_SEC
));
174 n
+= 1 + 5 + 1 + 6 + 1;
185 r
= safe_atou64(realtime
, &x
);
188 r
= sd_journal_get_realtime_usec(j
, &x
);
191 log_error("Failed to get realtime: %s", strerror(-r
));
195 t
= (time_t) (x
/ USEC_PER_SEC
);
196 if (strftime(buf
, sizeof(buf
), "%b %d %H:%M:%S", localtime_r(&t
, &tm
)) <= 0) {
197 log_error("Failed to format time.");
205 if (hostname
&& shall_print(show_all
, hostname
, hostname_len
)) {
206 printf(" %.*s", (int) hostname_len
, hostname
);
207 n
+= hostname_len
+ 1;
210 if (identifier
&& shall_print(show_all
, identifier
, identifier_len
)) {
211 printf(" %.*s", (int) identifier_len
, identifier
);
212 n
+= identifier_len
+ 1;
213 } else if (comm
&& shall_print(show_all
, comm
, comm_len
)) {
214 printf(" %.*s", (int) comm_len
, comm
);
218 if (pid
&& shall_print(show_all
, pid
, pid_len
)) {
219 printf("[%.*s]", (int) pid_len
, pid
);
221 } else if (fake_pid
&& shall_print(show_all
, fake_pid
, fake_pid_len
)) {
222 printf("[%.*s]", (int) fake_pid_len
, fake_pid
);
223 n
+= fake_pid_len
+ 2;
227 printf(": %.*s\n", (int) message_len
, message
);
228 else if (contains_unprintable(message
, message_len
)) {
229 char bytes
[FORMAT_BYTES_MAX
];
230 printf(": [%s blob data]\n", format_bytes(bytes
, sizeof(bytes
), message_len
));
231 } else if (message_len
+ n
< n_columns
)
232 printf(": %.*s\n", (int) message_len
, message
);
233 else if (n
< n_columns
) {
236 e
= ellipsize_mem(message
, message_len
, n_columns
- n
- 2, 90);
239 printf(": %.*s\n", (int) message_len
, message
);
262 static int output_short_realtime(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
263 return output_short(j
, line
, n_columns
, show_all
, false);
266 static int output_short_monotonic(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
267 return output_short(j
, line
, n_columns
, show_all
, true);
270 static int output_verbose(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
275 char ts
[FORMAT_TIMESTAMP_MAX
];
280 r
= sd_journal_get_realtime_usec(j
, &realtime
);
282 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
286 r
= sd_journal_get_cursor(j
, &cursor
);
288 log_error("Failed to get cursor: %s", strerror(-r
));
293 format_timestamp(ts
, sizeof(ts
), realtime
),
298 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
299 if (!show_all
&& (length
> PRINT_THRESHOLD
||
300 contains_unprintable(data
, length
))) {
302 char bytes
[FORMAT_BYTES_MAX
];
304 c
= memchr(data
, '=', length
);
306 log_error("Invalid field.");
310 printf("\t%.*s=[%s blob data]\n",
311 (int) (c
- (const char*) data
),
313 format_bytes(bytes
, sizeof(bytes
), length
- (c
- (const char *) data
) - 1));
315 printf("\t%.*s\n", (int) length
, (const char*) data
);
321 static int output_export(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
325 usec_t realtime
, monotonic
;
332 r
= sd_journal_get_realtime_usec(j
, &realtime
);
334 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
338 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
340 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
344 r
= sd_journal_get_cursor(j
, &cursor
);
346 log_error("Failed to get cursor: %s", strerror(-r
));
350 printf("__CURSOR=%s\n"
351 "__REALTIME_TIMESTAMP=%llu\n"
352 "__MONOTONIC_TIMESTAMP=%llu\n"
355 (unsigned long long) realtime
,
356 (unsigned long long) monotonic
,
357 sd_id128_to_string(boot_id
, sid
));
361 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
363 /* We already printed the boot id, from the data in
364 * the header, hence let's suppress it here */
366 memcmp(data
, "_BOOT_ID=", 9) == 0)
369 if (contains_unprintable(data
, length
)) {
373 c
= memchr(data
, '=', length
);
375 log_error("Invalid field.");
379 fwrite(data
, c
- (const char*) data
, 1, stdout
);
381 le64
= htole64(length
- (c
- (const char*) data
) - 1);
382 fwrite(&le64
, sizeof(le64
), 1, stdout
);
383 fwrite(c
+ 1, length
- (c
- (const char*) data
) - 1, 1, stdout
);
385 fwrite(data
, length
, 1, stdout
);
395 static void json_escape(const char* p
, size_t l
) {
397 if (contains_unprintable(p
, l
)) {
398 bool not_first
= false;
404 printf(", %u", (uint8_t) *p
);
407 printf("%u", (uint8_t) *p
);
419 if (*p
== '"' || *p
== '\\') {
433 static int output_json(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
434 uint64_t realtime
, monotonic
;
444 r
= sd_journal_get_realtime_usec(j
, &realtime
);
446 log_error("Failed to get realtime timestamp: %s", strerror(-r
));
450 r
= sd_journal_get_monotonic_usec(j
, &monotonic
, &boot_id
);
452 log_error("Failed to get monotonic timestamp: %s", strerror(-r
));
456 r
= sd_journal_get_cursor(j
, &cursor
);
458 log_error("Failed to get cursor: %s", strerror(-r
));
465 fputs(",\n", stdout
);
468 "\t\"__CURSOR\" : \"%s\",\n"
469 "\t\"__REALTIME_TIMESTAMP\" : \"%llu\",\n"
470 "\t\"__MONOTONIC_TIMESTAMP\" : \"%llu\",\n"
471 "\t\"_BOOT_ID\" : \"%s\"",
473 (unsigned long long) realtime
,
474 (unsigned long long) monotonic
,
475 sd_id128_to_string(boot_id
, sid
));
479 SD_JOURNAL_FOREACH_DATA(j
, data
, length
) {
482 /* We already printed the boot id, from the data in
483 * the header, hence let's suppress it here */
485 memcmp(data
, "_BOOT_ID=", 9) == 0)
488 c
= memchr(data
, '=', length
);
490 log_error("Invalid field.");
494 fputs(",\n\t", stdout
);
495 json_escape(data
, c
- (const char*) data
);
496 fputs(" : ", stdout
);
497 json_escape(c
+ 1, length
- (c
- (const char*) data
) - 1);
500 fputs("\n}", stdout
);
506 static int output_cat(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) {
513 r
= sd_journal_get_data(j
, "MESSAGE", &data
, &l
);
515 log_error("Failed to get data: %s", strerror(-r
));
521 fwrite((const char*) data
+ 8, 1, l
- 8, stdout
);
527 static int (*output_funcs
[_OUTPUT_MODE_MAX
])(sd_journal
*j
, unsigned line
, unsigned n_columns
, bool show_all
) = {
528 [OUTPUT_SHORT
] = output_short_realtime
,
529 [OUTPUT_SHORT_MONOTONIC
] = output_short_monotonic
,
530 [OUTPUT_VERBOSE
] = output_verbose
,
531 [OUTPUT_EXPORT
] = output_export
,
532 [OUTPUT_JSON
] = output_json
,
533 [OUTPUT_CAT
] = output_cat
536 int output_journal(sd_journal
*j
, OutputMode mode
, unsigned line
, unsigned n_columns
, bool show_all
) {
538 assert(mode
< _OUTPUT_MODE_MAX
);
541 n_columns
= columns();
543 return output_funcs
[mode
](j
, line
, n_columns
, show_all
);
546 int show_journal_by_unit(
560 bool need_seek
= false;
563 assert(mode
< _OUTPUT_MODE_MAX
);
566 if (!endswith(unit
, ".service") &&
567 !endswith(unit
, ".socket") &&
568 !endswith(unit
, ".mount") &&
569 !endswith(unit
, ".swap"))
575 if (asprintf(&m
, "_SYSTEMD_UNIT=%s", unit
) < 0) {
580 r
= sd_journal_open(&j
, SD_JOURNAL_LOCAL_ONLY
|SD_JOURNAL_SYSTEM_ONLY
);
584 fd
= sd_journal_get_fd(j
);
588 r
= sd_journal_add_match(j
, m
, strlen(m
));
592 r
= sd_journal_seek_tail(j
);
596 r
= sd_journal_previous_skip(j
, how_many
);
600 if (mode
== OUTPUT_JSON
) {
610 r
= sd_journal_next(j
);
620 if (not_before
> 0) {
621 r
= sd_journal_get_monotonic_usec(j
, &usec
, NULL
);
623 /* -ESTALE is returned if the
624 timestamp is not from this boot */
630 if (usec
< not_before
)
636 r
= output_journal(j
, mode
, line
, n_columns
, show_all
);
644 r
= fd_wait_for_event(fd
, POLLIN
, (usec_t
) -1);
648 r
= sd_journal_process(j
);
654 if (mode
== OUTPUT_JSON
)
655 fputs("\n]\n", stdout
);
667 static const char *const output_mode_table
[_OUTPUT_MODE_MAX
] = {
668 [OUTPUT_SHORT
] = "short",
669 [OUTPUT_SHORT_MONOTONIC
] = "short-monotonic",
670 [OUTPUT_VERBOSE
] = "verbose",
671 [OUTPUT_EXPORT
] = "export",
672 [OUTPUT_JSON
] = "json",
676 DEFINE_STRING_TABLE_LOOKUP(output_mode
, OutputMode
);