2 * SPDX-License-Identifier: GPL-2.0-or-later
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * dmesg.c -- Print out the contents of the kernel ring buffer
11 * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu>
12 * Copyright (C) 2011-2023 Karel Zak <kzak@redhat.com>
18 #include <sys/syslog.h>
20 #include <sys/sysinfo.h>
24 #include <sys/types.h>
37 #include "closestream.h"
39 #include "timeutils.h"
40 #include "monotonic.h"
45 /* Close the log. Currently a NOP. */
46 #define SYSLOG_ACTION_CLOSE 0
47 /* Open the log. Currently a NOP. */
48 #define SYSLOG_ACTION_OPEN 1
49 /* Read from the log. */
50 #define SYSLOG_ACTION_READ 2
51 /* Read all messages remaining in the ring buffer. (allowed for non-root) */
52 #define SYSLOG_ACTION_READ_ALL 3
53 /* Read and clear all messages remaining in the ring buffer */
54 #define SYSLOG_ACTION_READ_CLEAR 4
55 /* Clear ring buffer. */
56 #define SYSLOG_ACTION_CLEAR 5
57 /* Disable printk's to console */
58 #define SYSLOG_ACTION_CONSOLE_OFF 6
59 /* Enable printk's to console */
60 #define SYSLOG_ACTION_CONSOLE_ON 7
61 /* Set level of messages printed to console */
62 #define SYSLOG_ACTION_CONSOLE_LEVEL 8
63 /* Return number of unread characters in the log buffer */
64 #define SYSLOG_ACTION_SIZE_UNREAD 9
65 /* Return size of the log buffer */
66 #define SYSLOG_ACTION_SIZE_BUFFER 10
72 const char *scheme
; /* name used in termina-colors.d/dmesg.scheme */
73 const char *dflt
; /* default color ESC sequence */
79 DMESG_COLOR_TIMEBREAK
,
87 static const struct dmesg_color colors
[] =
89 [DMESG_COLOR_SUBSYS
] = { "subsys", UL_COLOR_BROWN
},
90 [DMESG_COLOR_TIME
] = { "time", UL_COLOR_GREEN
},
91 [DMESG_COLOR_TIMEBREAK
] = { "timebreak",UL_COLOR_GREEN UL_COLOR_BOLD
},
92 [DMESG_COLOR_ALERT
] = { "alert", UL_COLOR_REVERSE UL_COLOR_RED
},
93 [DMESG_COLOR_CRIT
] = { "crit", UL_COLOR_BOLD UL_COLOR_RED
},
94 [DMESG_COLOR_ERR
] = { "err", UL_COLOR_RED
},
95 [DMESG_COLOR_WARN
] = { "warn", UL_COLOR_BOLD
},
96 [DMESG_COLOR_SEGFAULT
] = { "segfault", UL_COLOR_HALFBRIGHT UL_COLOR_RED
}
99 #define dmesg_enable_color(_id) \
100 color_scheme_enable(colors[_id].scheme, colors[_id].dflt);
103 * Priority and facility names
111 * Priority names -- based on sys/syslog.h
113 static const struct dmesg_name level_names
[] =
115 [LOG_EMERG
] = { "emerg", N_("system is unusable") },
116 [LOG_ALERT
] = { "alert", N_("action must be taken immediately") },
117 [LOG_CRIT
] = { "crit", N_("critical conditions") },
118 [LOG_ERR
] = { "err", N_("error conditions") },
119 [LOG_WARNING
] = { "warn", N_("warning conditions") },
120 [LOG_NOTICE
] = { "notice",N_("normal but significant condition") },
121 [LOG_INFO
] = { "info", N_("informational") },
122 [LOG_DEBUG
] = { "debug", N_("debug-level messages") }
126 * sys/syslog.h uses (f << 3) for all facility codes.
127 * We want to use the codes as array indexes, so shift back...
129 * Note that libc LOG_FAC() macro returns the base codes, not the
132 #define FAC_BASE(f) ((f) >> 3)
133 #define LOG_RAW_FAC_PRI(fac, pri) LOG_MAKEPRI((fac << 3), (pri))
135 static const struct dmesg_name facility_names
[] =
137 [FAC_BASE(LOG_KERN
)] = { "kern", N_("kernel messages") },
138 [FAC_BASE(LOG_USER
)] = { "user", N_("random user-level messages") },
139 [FAC_BASE(LOG_MAIL
)] = { "mail", N_("mail system") },
140 [FAC_BASE(LOG_DAEMON
)] = { "daemon", N_("system daemons") },
141 [FAC_BASE(LOG_AUTH
)] = { "auth", N_("security/authorization messages") },
142 [FAC_BASE(LOG_SYSLOG
)] = { "syslog", N_("messages generated internally by syslogd") },
143 [FAC_BASE(LOG_LPR
)] = { "lpr", N_("line printer subsystem") },
144 [FAC_BASE(LOG_NEWS
)] = { "news", N_("network news subsystem") },
145 [FAC_BASE(LOG_UUCP
)] = { "uucp", N_("UUCP subsystem") },
146 [FAC_BASE(LOG_CRON
)] = { "cron", N_("clock daemon") },
147 [FAC_BASE(LOG_AUTHPRIV
)] = { "authpriv", N_("security/authorization messages (private)") },
148 [FAC_BASE(LOG_FTP
)] = { "ftp", N_("FTP daemon") },
151 /* supported methods to read message buffer
154 DMESG_METHOD_KMSG
, /* read messages from /dev/kmsg (default) */
155 DMESG_METHOD_SYSLOG
, /* klogctl() buffer */
156 DMESG_METHOD_MMAP
/* mmap file with records (see --file) */
160 DMESG_TIMEFTM_NONE
= 0,
161 DMESG_TIMEFTM_CTIME
, /* [ctime] */
162 DMESG_TIMEFTM_CTIME_DELTA
, /* [ctime <delta>] */
163 DMESG_TIMEFTM_DELTA
, /* [<delta>] */
164 DMESG_TIMEFTM_RELTIME
, /* [relative] */
165 DMESG_TIMEFTM_TIME
, /* [time] */
166 DMESG_TIMEFTM_TIME_DELTA
, /* [time <delta>] */
167 DMESG_TIMEFTM_ISO8601
/* 2013-06-13T22:11:00,123456+0100 */
169 #define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f))
171 struct dmesg_control
{
172 /* bit arrays -- see include/bitops.h */
173 char levels
[ARRAY_SIZE(level_names
) / NBBY
+ 1];
174 char facilities
[ARRAY_SIZE(facility_names
) / NBBY
+ 1];
176 struct timeval lasttime
; /* last printed timestamp */
177 struct tm lasttm
; /* last localtime */
178 struct timeval boot_time
; /* system boot time */
179 usec_t suspended_time
; /* time spent in suspended state */
181 int action
; /* SYSLOG_ACTION_* */
182 int method
; /* DMESG_METHOD_* */
184 size_t bufsize
; /* size of syslog buffer */
186 int kmsg
; /* /dev/kmsg file descriptor */
187 ssize_t kmsg_first_read
;/* initial read() return code */
189 * the kernel will give EINVAL if we do read() on /proc/kmsg with
190 * length insufficient for the next message. messages may be up to
191 * PRINTK_MESSAGE_MAX, which is defined as 2048, so we must be
192 * able to buffer at least that much in one call
194 char kmsg_buf
[2048]; /* buffer to read kmsg data */
196 usec_t since
; /* filter records by time */
197 usec_t until
; /* filter records by time */
200 * For the --file option we mmap whole file. The unnecessary (already
201 * printed) pages are always unmapped. The result is that we have in
202 * memory only the currently used page(s).
207 unsigned int time_fmt
; /* time format */
209 struct ul_jsonwrt jfmt
; /* -J formatting */
211 unsigned int follow
:1, /* wait for new messages */
212 end
:1, /* seek to the of buffer */
213 raw
:1, /* raw mode */
214 noesc
:1, /* no escape */
215 fltr_lev
:1, /* filter out by levels[] */
216 fltr_fac
:1, /* filter out by facilities[] */
217 decode
:1, /* use "facility: level: " prefix */
218 pager
:1, /* pipe output into a pager */
219 color
:1, /* colorize messages */
220 json
:1, /* JSON output */
221 force_prefix
:1; /* force timestamp and decode prefix
223 int indent
; /* due to timestamps if newline */
226 struct dmesg_record
{
234 const char *next
; /* buffer with next unparsed record */
235 size_t next_size
; /* size of the next buffer */
238 #define INIT_DMESG_RECORD(_r) do { \
240 (_r)->mesg_size = 0; \
241 (_r)->facility = -1; \
243 (_r)->tv.tv_sec = 0; \
244 (_r)->tv.tv_usec = 0; \
247 static int process_kmsg(struct dmesg_control
*ctl
);
249 static int set_level_color(int log_level
, const char *mesg
, size_t mesgsz
)
255 id
= DMESG_COLOR_ALERT
;
258 id
= DMESG_COLOR_CRIT
;
261 id
= DMESG_COLOR_ERR
;
264 id
= DMESG_COLOR_WARN
;
270 /* well, sometimes the messages contains important keywords, but in
271 * non-warning/error messages
273 if (id
< 0 && memmem(mesg
, mesgsz
, "segfault at", 11))
274 id
= DMESG_COLOR_SEGFAULT
;
277 dmesg_enable_color(id
);
279 return id
>= 0 ? 0 : -1;
282 static void __attribute__((__noreturn__
)) usage(void)
287 fputs(USAGE_HEADER
, out
);
288 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
290 fputs(USAGE_SEPARATOR
, out
);
291 fputs(_("Display or control the kernel ring buffer.\n"), out
);
293 fputs(USAGE_OPTIONS
, out
);
294 fputs(_(" -C, --clear clear the kernel ring buffer\n"), out
);
295 fputs(_(" -c, --read-clear read and clear all messages\n"), out
);
296 fputs(_(" -D, --console-off disable printing messages to console\n"), out
);
297 fputs(_(" -E, --console-on enable printing messages to console\n"), out
);
298 fputs(_(" -F, --file <file> use the file instead of the kernel log buffer\n"), out
);
299 fputs(_(" -f, --facility <list> restrict output to defined facilities\n"), out
);
300 fputs(_(" -H, --human human readable output\n"), out
);
301 fputs(_(" -J, --json use JSON output format\n"), out
);
302 fputs(_(" -k, --kernel display kernel messages\n"), out
);
304 _(" -L, --color[=<when>] colorize messages (%s, %s or %s)\n"), "auto", "always", "never");
306 " %s\n", USAGE_COLORS_DEFAULT
);
307 fputs(_(" -l, --level <list> restrict output to defined levels\n"), out
);
308 fputs(_(" -n, --console-level <level> set level of messages printed to console\n"), out
);
309 fputs(_(" -P, --nopager do not pipe output into a pager\n"), out
);
310 fputs(_(" -p, --force-prefix force timestamp output on each line of multi-line messages\n"), out
);
311 fputs(_(" -r, --raw print the raw message buffer\n"), out
);
312 fputs(_(" --noescape don't escape unprintable character\n"), out
);
313 fputs(_(" -S, --syslog force to use syslog(2) rather than /dev/kmsg\n"), out
);
314 fputs(_(" -s, --buffer-size <size> buffer size to query the kernel ring buffer\n"), out
);
315 fputs(_(" -u, --userspace display userspace messages\n"), out
);
316 fputs(_(" -w, --follow wait for new messages\n"), out
);
317 fputs(_(" -W, --follow-new wait and print only new messages\n"), out
);
318 fputs(_(" -x, --decode decode facility and level to readable string\n"), out
);
319 fputs(_(" -d, --show-delta show time delta between printed messages\n"), out
);
320 fputs(_(" -e, --reltime show local time and time delta in readable format\n"), out
);
321 fputs(_(" -T, --ctime show human-readable timestamp (may be inaccurate!)\n"), out
);
322 fputs(_(" -t, --notime don't show any timestamp with messages\n"), out
);
323 fputs(_(" --time-format <format> show timestamp using the given format:\n"
324 " [delta|reltime|ctime|notime|iso]\n"
325 "Suspending/resume will make ctime and iso timestamps inaccurate.\n"), out
);
326 fputs(_(" --since <time> display the lines since the specified time\n"), out
);
327 fputs(_(" --until <time> display the lines until the specified time\n"), out
);
329 fputs(USAGE_SEPARATOR
, out
);
330 fprintf(out
, USAGE_HELP_OPTIONS(29));
331 fputs(_("\nSupported log facilities:\n"), out
);
332 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++)
333 fprintf(out
, " %7s - %s\n",
334 facility_names
[i
].name
,
335 _(facility_names
[i
].help
));
337 fputs(_("\nSupported log levels (priorities):\n"), out
);
338 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++)
339 fprintf(out
, " %7s - %s\n",
341 _(level_names
[i
].help
));
343 fprintf(out
, USAGE_MAN_TAIL("dmesg(1)"));
348 * LEVEL ::= <number> | <name>
349 * <number> ::= @len is set: number in range <0..N>, where N < ARRAY_SIZE(level_names)
350 * ::= @len not set: number in range <1..N>, where N <= ARRAY_SIZE(level_names)
351 * <name> ::= case-insensitive text
353 * Note that @len argument is not set when parsing "-n <level>" command line
354 * option. The console_level is interpreted as "log level less than the value".
356 * For example "dmesg -n 8" or "dmesg -n debug" enables debug console log
357 * level by klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, 8). The @str argument
358 * has to be parsed to number in range <1..8>.
360 static int parse_level(const char *str
, size_t len
)
374 long x
= strtol(str
, &end
, 10) - offset
;
376 if (!errno
&& end
&& end
> str
&& (size_t) (end
- str
) == len
&&
377 x
>= 0 && (size_t) x
< ARRAY_SIZE(level_names
))
382 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++) {
383 const char *n
= level_names
[i
].name
;
385 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
391 err(EXIT_FAILURE
, _("failed to parse level '%s'"), str
);
393 errx(EXIT_FAILURE
, _("unknown level '%s'"), str
);
398 * FACILITY ::= <number> | <name>
399 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
400 * <name> ::= case-insensitive text
402 static int parse_facility(const char *str
, size_t len
)
412 long x
= strtol(str
, &end
, 10);
414 if (!errno
&& end
&& end
> str
&& (size_t) (end
- str
) == len
&&
415 x
>= 0 && (size_t) x
< ARRAY_SIZE(facility_names
))
420 for (i
= 0; i
< ARRAY_SIZE(facility_names
); i
++) {
421 const char *n
= facility_names
[i
].name
;
423 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
429 err(EXIT_FAILURE
, _("failed to parse facility '%s'"), str
);
431 errx(EXIT_FAILURE
, _("unknown facility '%s'"), str
);
436 * Parses numerical prefix used for all messages in kernel ring buffer.
438 * Priorities/facilities are encoded into a single 32-bit quantity, where the
439 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
442 * Note that the number has to end with '>' or ',' char.
444 static const char *parse_faclev(const char *str
, int *fac
, int *lev
)
453 num
= strtol(str
, &end
, 10);
455 if (!errno
&& end
&& end
> str
) {
459 if (*lev
< 0 || (size_t) *lev
> ARRAY_SIZE(level_names
))
461 if (*fac
< 0 || (size_t) *fac
> ARRAY_SIZE(facility_names
))
463 return end
+ 1; /* skip '<' or ',' */
470 * Parses timestamp from syslog message prefix, expected format:
472 * seconds.microseconds]
474 * the ']' is the timestamp field terminator.
476 static const char *parse_syslog_timestamp(const char *str0
, struct timeval
*tv
)
478 const char *str
= str0
;
485 tv
->tv_sec
= strtol(str
, &end
, 10);
487 if (!errno
&& end
&& *end
== '.' && *(end
+ 1)) {
490 tv
->tv_usec
= strtol(str
, &end
, 10);
492 if (errno
|| !end
|| end
== str
|| *end
!= ']')
495 return end
+ 1; /* skip ']' */
499 * Parses timestamp from /dev/kmsg, expected formats:
504 * the ',' is fields separators and ';' items terminator (for the last item)
506 static const char *parse_kmsg_timestamp(const char *str0
, struct timeval
*tv
)
508 const char *str
= str0
;
516 usec
= strtoumax(str
, &end
, 10);
518 if (!errno
&& end
&& (*end
== ';' || *end
== ',')) {
519 tv
->tv_usec
= usec
% 1000000;
520 tv
->tv_sec
= usec
/ 1000000;
524 return end
+ 1; /* skip separator */
528 static double time_diff(struct timeval
*a
, struct timeval
*b
)
530 return (a
->tv_sec
- b
->tv_sec
) + (a
->tv_usec
- b
->tv_usec
) / 1E6
;
533 static int get_syslog_buffer_size(void)
535 int n
= klogctl(SYSLOG_ACTION_SIZE_BUFFER
, NULL
, 0);
537 return n
> 0 ? n
: 0;
541 * Reads messages from regular file by mmap
543 static ssize_t
mmap_file_buffer(struct dmesg_control
*ctl
, char **buf
)
551 fd
= open(ctl
->filename
, O_RDONLY
);
553 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->filename
);
555 err(EXIT_FAILURE
, _("stat of %s failed"), ctl
->filename
);
557 *buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
558 if (*buf
== MAP_FAILED
)
559 err(EXIT_FAILURE
, _("cannot mmap: %s"), ctl
->filename
);
560 ctl
->mmap_buff
= *buf
;
561 ctl
->pagesize
= getpagesize();
568 * Reads messages from kernel ring buffer by klogctl()
570 static ssize_t
read_syslog_buffer(struct dmesg_control
*ctl
, char **buf
)
576 sz
= ctl
->bufsize
+ 8;
577 *buf
= xmalloc(sz
* sizeof(char));
578 rc
= klogctl(SYSLOG_ACTION_READ_ALL
, *buf
, sz
);
582 *buf
= xmalloc(sz
* sizeof(char));
583 rc
= klogctl(SYSLOG_ACTION_READ_ALL
, *buf
, sz
);
586 if ((size_t) rc
!= sz
|| sz
> (1 << 28))
598 * Top level function to read (and print in case of kmesg) messages
600 static ssize_t
process_buffer(struct dmesg_control
*ctl
, char **buf
)
604 switch (ctl
->method
) {
605 case DMESG_METHOD_MMAP
:
606 n
= mmap_file_buffer(ctl
, buf
);
608 case DMESG_METHOD_SYSLOG
:
610 ctl
->bufsize
= get_syslog_buffer_size();
612 n
= read_syslog_buffer(ctl
, buf
);
614 case DMESG_METHOD_KMSG
:
618 n
= process_kmsg(ctl
);
621 abort(); /* impossible method -> drop core */
627 static int fwrite_hex(const char *buf
, size_t size
, FILE *out
)
631 for (i
= 0; i
< size
; i
++) {
632 int rc
= fprintf(out
, "\\x%02hhx", buf
[i
]);
640 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
642 static void safe_fwrite(struct dmesg_control
*ctl
, const char *buf
, size_t size
, int indent
, FILE *out
)
648 memset(&s
, 0, sizeof (s
));
650 for (i
= 0; i
< size
; i
++) {
651 const char *p
= buf
+ i
;
661 len
= mbrtowc(&wc
, p
, size
- i
, &s
);
663 if (len
== 0) /* L'\0' */
666 if (len
== (size_t)-1 || len
== (size_t)-2) { /* invalid sequence */
667 memset(&s
, 0, sizeof (s
));
670 } else if (len
> 1) {
671 if (!iswprint(wc
) && !iswspace(wc
)) /* non-printable multibyte */
678 if (!isprint((unsigned char) *p
) &&
679 !isspace((unsigned char) *p
)) /* non-printable */
686 rc
= fwrite_hex(p
, len
, out
);
687 else if (*p
== '\n' && *(p
+ 1) && indent
) {
688 rc
= fwrite(p
, 1, len
, out
) != len
;
689 if (fprintf(out
, "%*s", indent
, "") != indent
)
692 rc
= fwrite(p
, 1, len
, out
) != len
;
696 err(EXIT_FAILURE
, _("write failed"));
702 static const char *skip_item(const char *begin
, const char *end
, const char *sep
)
704 while (begin
< end
) {
707 if (c
== '\0' || strchr(sep
, c
))
715 * Parses one record from syslog(2) buffer
717 static int get_next_syslog_record(struct dmesg_control
*ctl
,
718 struct dmesg_record
*rec
)
721 const char *begin
= NULL
;
723 if (ctl
->method
!= DMESG_METHOD_MMAP
&&
724 ctl
->method
!= DMESG_METHOD_SYSLOG
)
727 if (!rec
->next
|| !rec
->next_size
)
730 INIT_DMESG_RECORD(rec
);
733 * Unmap already printed file data from memory
735 if (ctl
->mmap_buff
&& (size_t) (rec
->next
- ctl
->mmap_buff
) > ctl
->pagesize
) {
736 void *x
= ctl
->mmap_buff
;
738 ctl
->mmap_buff
+= ctl
->pagesize
;
739 munmap(x
, ctl
->pagesize
);
742 for (i
= 0; i
< rec
->next_size
; i
++) {
743 const char *p
= rec
->next
+ i
;
744 const char *end
= NULL
;
748 if (i
+ 1 == rec
->next_size
) {
751 } else if (*p
== '\n' && *(p
+ 1) == '<')
754 if (begin
&& !*begin
)
755 begin
= NULL
; /* zero(s) at the end of the buffer? */
759 continue; /* error or empty line? */
762 if (ctl
->fltr_lev
|| ctl
->fltr_fac
|| ctl
->decode
|| ctl
->color
|| ctl
->json
)
763 begin
= parse_faclev(begin
+ 1, &rec
->facility
,
766 begin
= skip_item(begin
, end
, ">");
769 if (*begin
== '[' && (*(begin
+ 1) == ' ' ||
770 isdigit(*(begin
+ 1)))) {
772 if (!is_timefmt(ctl
, NONE
))
773 begin
= parse_syslog_timestamp(begin
+ 1, &rec
->tv
);
775 begin
= skip_item(begin
, end
, "]");
777 if (begin
< end
&& *begin
== ' ')
782 rec
->mesg_size
= end
- begin
;
784 /* Don't count \n from the last message to the message size */
785 if (*end
!= '\n' && *(end
- 1) == '\n')
788 rec
->next_size
-= end
- rec
->next
;
789 rec
->next
= rec
->next_size
> 0 ? end
+ 1 : NULL
;
790 if (rec
->next_size
> 0)
799 static usec_t
record_time(struct dmesg_control
*ctl
, struct dmesg_record
*rec
)
801 return timeval_to_usec(&ctl
->boot_time
) +
802 ctl
->suspended_time
+
803 timeval_to_usec(&rec
->tv
);
806 static int accept_record(struct dmesg_control
*ctl
, struct dmesg_record
*rec
)
808 if (ctl
->fltr_lev
&& (rec
->facility
< 0 ||
809 !isset(ctl
->levels
, rec
->level
)))
812 if (ctl
->fltr_fac
&& (rec
->facility
< 0 ||
813 !isset(ctl
->facilities
, rec
->facility
)))
816 if (ctl
->since
&& ctl
->since
>= record_time(ctl
, rec
))
819 if (ctl
->until
&& ctl
->until
<= record_time(ctl
, rec
))
825 static void raw_print(struct dmesg_control
*ctl
, const char *buf
, size_t size
)
829 if (!ctl
->mmap_buff
) {
831 * Print whole ring buffer
833 safe_fwrite(ctl
, buf
, size
, 0, stdout
);
834 lastc
= buf
[size
- 1];
837 * Print file in small chunks to save memory
840 size_t sz
= size
> ctl
->pagesize
? ctl
->pagesize
: size
;
841 char *x
= ctl
->mmap_buff
;
843 safe_fwrite(ctl
, x
, sz
, 0, stdout
);
846 ctl
->mmap_buff
+= sz
;
855 static struct tm
*record_localtime(struct dmesg_control
*ctl
,
856 struct dmesg_record
*rec
,
859 time_t t
= record_time(ctl
, rec
) / USEC_PER_SEC
;
860 return localtime_r(&t
, tm
);
863 static char *record_ctime(struct dmesg_control
*ctl
,
864 struct dmesg_record
*rec
,
865 char *buf
, size_t bufsiz
)
869 record_localtime(ctl
, rec
, &tm
);
871 /* TRANSLATORS: dmesg uses strftime() fo generate date-time string
872 where %a is abbreviated name of the day, %b is abbreviated month
873 name and %e is day of the month as a decimal number. Please, set
874 proper month/day order here */
875 if (strftime(buf
, bufsiz
, _("%a %b %e %H:%M:%S %Y"), &tm
) == 0)
880 static char *short_ctime(struct tm
*tm
, char *buf
, size_t bufsiz
)
882 /* TRANSLATORS: dmesg uses strftime() fo generate date-time string
883 where: %b is abbreviated month and %e is day of the month as a
884 decimal number. Please, set proper month/day order here. */
885 if (strftime(buf
, bufsiz
, _("%b%e %H:%M"), tm
) == 0)
890 static char *iso_8601_time(struct dmesg_control
*ctl
, struct dmesg_record
*rec
,
891 char *buf
, size_t bufsz
)
893 struct timeval tv
= usec_to_timeval(
894 timeval_to_usec(&ctl
->boot_time
) + ctl
->suspended_time
+
895 timeval_to_usec(&rec
->tv
)
898 if (strtimeval_iso(&tv
, ISO_TIMESTAMP_COMMA_T
, buf
, bufsz
) != 0)
904 static double record_count_delta(struct dmesg_control
*ctl
,
905 struct dmesg_record
*rec
)
909 if (timerisset(&ctl
->lasttime
))
910 delta
= time_diff(&rec
->tv
, &ctl
->lasttime
);
912 ctl
->lasttime
= rec
->tv
;
916 static const char *get_subsys_delimiter(const char *mesg
, size_t mesg_size
)
918 const char *p
= mesg
;
919 size_t sz
= mesg_size
;
922 const char *d
= strnchr(p
, sz
, ':');
927 if (sz
>= 2 && isblank(*(d
+ 1)))
935 #define is_facpri_valid(_r) \
936 (((_r)->level > -1) && ((_r)->level < (int) ARRAY_SIZE(level_names)) && \
937 ((_r)->facility > -1) && \
938 ((_r)->facility < (int) ARRAY_SIZE(facility_names)))
941 static void print_record(struct dmesg_control
*ctl
,
942 struct dmesg_record
*rec
)
945 char fpbuf
[32] = "\0";
946 char tsbuf
[64] = "\0";
947 size_t mesg_size
= rec
->mesg_size
;
949 char *mesg_copy
= NULL
;
950 const char *line
= NULL
;
952 if (!accept_record(ctl
, rec
))
955 if (!rec
->mesg_size
) {
962 if (!ul_jsonwrt_is_ready(&ctl
->jfmt
)) {
963 ul_jsonwrt_init(&ctl
->jfmt
, stdout
, 0);
964 ul_jsonwrt_root_open(&ctl
->jfmt
);
965 ul_jsonwrt_array_open(&ctl
->jfmt
, "dmesg");
967 ul_jsonwrt_object_open(&ctl
->jfmt
, NULL
);
971 * Compose syslog(2) compatible raw output -- used for /dev/kmsg for
972 * backward compatibility with syslog(2) buffers only
975 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
),
977 LOG_RAW_FAC_PRI(rec
->facility
, rec
->level
),
978 (long) rec
->tv
.tv_sec
,
979 (long) rec
->tv
.tv_usec
);
983 /* Store decode information (facility & priority level) in a buffer */
984 if (!ctl
->json
&& ctl
->decode
&& is_facpri_valid(rec
))
985 snprintf(fpbuf
, sizeof(fpbuf
), "%-6s:%-6s: ",
986 facility_names
[rec
->facility
].name
,
987 level_names
[rec
->level
].name
);
989 /* Store the timestamp in a buffer */
990 switch (ctl
->time_fmt
) {
993 case DMESG_TIMEFTM_NONE
:
996 case DMESG_TIMEFTM_CTIME
:
997 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "[%s] ",
998 record_ctime(ctl
, rec
, buf
, sizeof(buf
)));
1000 case DMESG_TIMEFTM_CTIME_DELTA
:
1001 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "[%s <%12.06f>] ",
1002 record_ctime(ctl
, rec
, buf
, sizeof(buf
)),
1003 record_count_delta(ctl
, rec
));
1005 case DMESG_TIMEFTM_DELTA
:
1006 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "[<%12.06f>] ",
1007 record_count_delta(ctl
, rec
));
1009 case DMESG_TIMEFTM_RELTIME
:
1010 record_localtime(ctl
, rec
, &cur
);
1011 delta
= record_count_delta(ctl
, rec
);
1012 if (cur
.tm_min
!= ctl
->lasttm
.tm_min
||
1013 cur
.tm_hour
!= ctl
->lasttm
.tm_hour
||
1014 cur
.tm_yday
!= ctl
->lasttm
.tm_yday
) {
1016 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "[%s] ",
1017 short_ctime(&cur
, buf
,
1021 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
),
1022 "[ %+8.06f] ", delta
);
1024 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
),
1025 "[ %+9.06f] ", delta
);
1029 case DMESG_TIMEFTM_TIME
:
1030 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
),
1031 ctl
->json
? "%5ld.%06ld" : "[%5ld.%06ld] ",
1032 (long)rec
->tv
.tv_sec
,
1033 (long)rec
->tv
.tv_usec
);
1035 case DMESG_TIMEFTM_TIME_DELTA
:
1036 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "[%5ld.%06ld <%12.06f>] ",
1037 (long)rec
->tv
.tv_sec
,
1038 (long)rec
->tv
.tv_usec
,
1039 record_count_delta(ctl
, rec
));
1041 case DMESG_TIMEFTM_ISO8601
:
1042 ctl
->indent
= snprintf(tsbuf
, sizeof(tsbuf
), "%s ",
1043 iso_8601_time(ctl
, rec
, buf
,
1050 ctl
->indent
+= strlen(fpbuf
);
1053 /* Output the decode information */
1055 fputs(fpbuf
, stdout
);
1056 } else if (ctl
->json
&& is_facpri_valid(rec
)) {
1058 ul_jsonwrt_value_s(&ctl
->jfmt
, "fac", facility_names
[rec
->facility
].name
);
1059 ul_jsonwrt_value_s(&ctl
->jfmt
, "pri", level_names
[rec
->level
].name
);
1061 ul_jsonwrt_value_u64(&ctl
->jfmt
, "pri", LOG_RAW_FAC_PRI(rec
->facility
, rec
->level
));
1064 /* Output the timestamp buffer */
1066 /* Colorize the timestamp */
1068 dmesg_enable_color(timebreak
? DMESG_COLOR_TIMEBREAK
:
1070 if (ctl
->time_fmt
!= DMESG_TIMEFTM_RELTIME
) {
1072 ul_jsonwrt_value_raw(&ctl
->jfmt
, "time", tsbuf
);
1074 fputs(tsbuf
, stdout
);
1077 * For relative timestamping, the first line's
1078 * timestamp is the offset and all other lines will
1079 * report an offset of 0.000000.
1081 fputs(!line
? tsbuf
: "[ +0.000000] ", stdout
);
1088 * A kernel message may contain several lines of output, separated
1089 * by '\n'. If the timestamp and decode outputs are forced then each
1090 * line of the message must be displayed with that information.
1092 if (ctl
->force_prefix
) {
1094 mesg_copy
= xstrdup(rec
->mesg
);
1095 line
= strtok(mesg_copy
, "\n");
1097 goto done
; /* only when something is wrong */
1098 mesg_size
= strlen(line
);
1102 mesg_size
= rec
->mesg_size
;
1105 /* Colorize kernel message output */
1107 /* Subsystem prefix */
1108 const char *subsys
= get_subsys_delimiter(line
, mesg_size
);
1112 dmesg_enable_color(DMESG_COLOR_SUBSYS
);
1113 safe_fwrite(ctl
, line
, subsys
- line
, ctl
->indent
, stdout
);
1116 mesg_size
-= subsys
- line
;
1119 /* Error, alert .. etc. colors */
1120 has_color
= set_level_color(rec
->level
, line
, mesg_size
) == 0;
1121 safe_fwrite(ctl
, line
, mesg_size
, ctl
->indent
, stdout
);
1126 ul_jsonwrt_value_s(&ctl
->jfmt
, "msg", line
);
1128 safe_fwrite(ctl
, line
, mesg_size
, ctl
->indent
, stdout
);
1131 /* Get the next line */
1132 if (ctl
->force_prefix
) {
1133 line
= strtok(NULL
, "\n");
1134 if (line
&& *line
) {
1136 mesg_size
= strlen(line
);
1144 ul_jsonwrt_object_close(&ctl
->jfmt
);
1150 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
1151 * to 'levels' and 'facilities' bitarrays.
1153 static void print_buffer(struct dmesg_control
*ctl
,
1154 const char *buf
, size_t size
)
1156 struct dmesg_record rec
= { .next
= buf
, .next_size
= size
};
1159 raw_print(ctl
, buf
, size
);
1163 while (get_next_syslog_record(ctl
, &rec
) == 0)
1164 print_record(ctl
, &rec
);
1167 static ssize_t
read_kmsg_one(struct dmesg_control
*ctl
)
1171 /* kmsg returns EPIPE if record was modified while reading */
1173 size
= read(ctl
->kmsg
, ctl
->kmsg_buf
,
1174 sizeof(ctl
->kmsg_buf
) - 1);
1175 } while (size
< 0 && errno
== EPIPE
);
1180 static int init_kmsg(struct dmesg_control
*ctl
)
1182 int mode
= O_RDONLY
;
1189 ctl
->kmsg
= open("/dev/kmsg", mode
);
1194 * Seek after the last record available at the time
1195 * the last SYSLOG_ACTION_CLEAR was issued.
1197 * ... otherwise SYSLOG_ACTION_CLEAR will have no effect for kmsg.
1199 lseek(ctl
->kmsg
, 0, ctl
->end
? SEEK_END
: SEEK_DATA
);
1202 * Old kernels (<3.5) can successfully open /dev/kmsg for read-only,
1203 * but read() returns -EINVAL :-(((
1205 * Let's try to read the first record. The record is later processed in
1208 ctl
->kmsg_first_read
= read_kmsg_one(ctl
);
1209 if (ctl
->kmsg_first_read
< 0) {
1219 * /dev/kmsg record format:
1221 * faclev,seqnum,timestamp[optional, ...];message\n
1225 * - fields are separated by ','
1226 * - last field is terminated by ';'
1229 #define LAST_KMSG_FIELD(s) (!s || !*s || *(s - 1) == ';')
1231 static int parse_kmsg_record(struct dmesg_control
*ctl
,
1232 struct dmesg_record
*rec
,
1236 const char *p
= buf
, *end
;
1238 if (sz
== 0 || !buf
|| !*buf
)
1241 end
= buf
+ (sz
- 1);
1242 INIT_DMESG_RECORD(rec
);
1244 while (p
< end
&& isspace(*p
))
1247 /* A) priority and facility */
1248 if (ctl
->fltr_lev
|| ctl
->fltr_fac
|| ctl
->decode
||
1249 ctl
->raw
|| ctl
->color
|| ctl
->json
)
1250 p
= parse_faclev(p
, &rec
->facility
, &rec
->level
);
1252 p
= skip_item(p
, end
, ",");
1253 if (LAST_KMSG_FIELD(p
))
1256 /* B) sequence number */
1257 p
= skip_item(p
, end
, ",;");
1258 if (LAST_KMSG_FIELD(p
))
1262 if (is_timefmt(ctl
, NONE
))
1263 p
= skip_item(p
, end
, ",;");
1265 p
= parse_kmsg_timestamp(p
, &rec
->tv
);
1266 if (LAST_KMSG_FIELD(p
))
1269 /* D) optional fields (ignore) */
1270 p
= skip_item(p
, end
, ";");
1273 /* E) message text */
1275 p
= skip_item(p
, end
, "\n");
1279 /* The message text is terminated by \n, but it's possible that the
1280 * message contains another stuff behind this linebreak; in this case
1281 * the previous skip_item() returns pointer to the stuff behind \n.
1282 * Let's normalize all these situations and make sure we always point to
1285 * Note that the next unhexmangle_to_buffer() will replace \n by \0.
1287 if (*p
&& *p
!= '\n')
1291 * Kernel escapes non-printable characters, unfortunately kernel
1292 * definition of "non-printable" is too strict. On UTF8 console we can
1293 * print many chars, so let's decode from kernel.
1295 rec
->mesg_size
= unhexmangle_to_buffer(rec
->mesg
,
1296 (char *) rec
->mesg
, p
- rec
->mesg
+ 1);
1298 rec
->mesg_size
--; /* don't count \0 */
1300 /* F) message tags (ignore) */
1306 * Note that each read() call for /dev/kmsg returns always one record. It means
1307 * that we don't have to read whole message buffer before the records parsing.
1309 * So this function does not compose one huge buffer (like read_syslog_buffer())
1310 * and print_buffer() is unnecessary. All is done in this function.
1312 * Returns 0 on success, -1 on error.
1314 static int process_kmsg(struct dmesg_control
*ctl
)
1316 struct dmesg_record rec
;
1319 if (ctl
->method
!= DMESG_METHOD_KMSG
|| ctl
->kmsg
< 0)
1323 * The very first read() call is done in kmsg_init() where we test
1324 * /dev/kmsg usability. The return code from the initial read() is
1325 * stored in ctl->kmsg_first_read;
1327 sz
= ctl
->kmsg_first_read
;
1330 *(ctl
->kmsg_buf
+ sz
) = '\0'; /* for debug messages */
1332 if (parse_kmsg_record(ctl
, &rec
,
1333 ctl
->kmsg_buf
, (size_t) sz
) == 0)
1334 print_record(ctl
, &rec
);
1336 sz
= read_kmsg_one(ctl
);
1342 static int which_time_format(const char *s
)
1344 if (!strcmp(s
, "notime"))
1345 return DMESG_TIMEFTM_NONE
;
1346 if (!strcmp(s
, "ctime"))
1347 return DMESG_TIMEFTM_CTIME
;
1348 if (!strcmp(s
, "delta"))
1349 return DMESG_TIMEFTM_DELTA
;
1350 if (!strcmp(s
, "reltime"))
1351 return DMESG_TIMEFTM_RELTIME
;
1352 if (!strcmp(s
, "iso"))
1353 return DMESG_TIMEFTM_ISO8601
;
1354 errx(EXIT_FAILURE
, _("unknown time format: %s"), s
);
1358 static inline int dmesg_get_boot_time(struct timeval
*tv
)
1360 char *str
= getenv("DMESG_TEST_BOOTIME");
1361 uintmax_t sec
, usec
;
1363 if (str
&& sscanf(str
, "%ju.%ju", &sec
, &usec
) == 2) {
1366 return tv
->tv_sec
>= 0 && tv
->tv_usec
>= 0 ? 0 : -EINVAL
;
1369 return get_boot_time(tv
);
1372 static inline usec_t
dmesg_get_suspended_time(void)
1374 if (getenv("DMESG_TEST_BOOTIME"))
1376 return get_suspended_time();
1379 # define dmesg_get_boot_time get_boot_time
1380 # define dmesg_get_suspended_time get_suspended_time
1383 int main(int argc
, char *argv
[])
1387 int console_level
= 0;
1391 static struct dmesg_control ctl
= {
1393 .action
= SYSLOG_ACTION_READ_ALL
,
1394 .method
= DMESG_METHOD_KMSG
,
1396 .time_fmt
= DMESG_TIMEFTM_TIME
,
1399 int colormode
= UL_COLORMODE_UNDEF
;
1401 OPT_TIME_FORMAT
= CHAR_MAX
+ 1,
1407 static const struct option longopts
[] = {
1408 { "buffer-size", required_argument
, NULL
, 's' },
1409 { "clear", no_argument
, NULL
, 'C' },
1410 { "color", optional_argument
, NULL
, 'L' },
1411 { "console-level", required_argument
, NULL
, 'n' },
1412 { "console-off", no_argument
, NULL
, 'D' },
1413 { "console-on", no_argument
, NULL
, 'E' },
1414 { "decode", no_argument
, NULL
, 'x' },
1415 { "file", required_argument
, NULL
, 'F' },
1416 { "facility", required_argument
, NULL
, 'f' },
1417 { "follow", no_argument
, NULL
, 'w' },
1418 { "follow-new", no_argument
, NULL
, 'W' },
1419 { "human", no_argument
, NULL
, 'H' },
1420 { "help", no_argument
, NULL
, 'h' },
1421 { "json", no_argument
, NULL
, 'J' },
1422 { "kernel", no_argument
, NULL
, 'k' },
1423 { "level", required_argument
, NULL
, 'l' },
1424 { "since", required_argument
, NULL
, OPT_SINCE
},
1425 { "syslog", no_argument
, NULL
, 'S' },
1426 { "raw", no_argument
, NULL
, 'r' },
1427 { "read-clear", no_argument
, NULL
, 'c' },
1428 { "reltime", no_argument
, NULL
, 'e' },
1429 { "show-delta", no_argument
, NULL
, 'd' },
1430 { "ctime", no_argument
, NULL
, 'T' },
1431 { "noescape", no_argument
, NULL
, OPT_NOESC
},
1432 { "notime", no_argument
, NULL
, 't' },
1433 { "nopager", no_argument
, NULL
, 'P' },
1434 { "until", required_argument
, NULL
, OPT_UNTIL
},
1435 { "userspace", no_argument
, NULL
, 'u' },
1436 { "version", no_argument
, NULL
, 'V' },
1437 { "time-format", required_argument
, NULL
, OPT_TIME_FORMAT
},
1438 { "force-prefix", no_argument
, NULL
, 'p' },
1439 { NULL
, 0, NULL
, 0 }
1442 static const ul_excl_t excl
[] = { /* rows and cols in ASCII order */
1443 { 'C','D','E','c','n','r' }, /* clear,off,on,read-clear,level,raw*/
1444 { 'H','r' }, /* human, raw */
1445 { 'L','r' }, /* color, raw */
1446 { 'S','w' }, /* syslog,follow */
1447 { 'T','r' }, /* ctime, raw */
1448 { 'd','r' }, /* delta, raw */
1449 { 'e','r' }, /* reltime, raw */
1450 { 'r','x' }, /* raw, decode */
1451 { 'r','t' }, /* notime, raw */
1454 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1456 setlocale(LC_ALL
, "");
1457 bindtextdomain(PACKAGE
, LOCALEDIR
);
1458 textdomain(PACKAGE
);
1459 close_stdout_atexit();
1461 while ((c
= getopt_long(argc
, argv
, "CcDdEeF:f:HhJkL::l:n:iPprSs:TtuVWwx",
1462 longopts
, NULL
)) != -1) {
1464 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1468 ctl
.action
= SYSLOG_ACTION_CLEAR
;
1471 ctl
.action
= SYSLOG_ACTION_READ_CLEAR
;
1474 ctl
.action
= SYSLOG_ACTION_CONSOLE_OFF
;
1480 ctl
.action
= SYSLOG_ACTION_CONSOLE_ON
;
1483 ctl
.time_fmt
= DMESG_TIMEFTM_RELTIME
;
1486 ctl
.filename
= optarg
;
1487 ctl
.method
= DMESG_METHOD_MMAP
;
1491 if (string_to_bitarray(optarg
,
1492 ctl
.facilities
, parse_facility
, 0) < 0)
1493 return EXIT_FAILURE
;
1496 ctl
.time_fmt
= DMESG_TIMEFTM_RELTIME
;
1497 colormode
= UL_COLORMODE_AUTO
;
1505 setbit(ctl
.facilities
, FAC_BASE(LOG_KERN
));
1508 colormode
= UL_COLORMODE_AUTO
;
1510 colormode
= colormode_or_err(optarg
,
1511 _("unsupported color mode"));
1515 if (string_to_bitarray(optarg
,
1516 ctl
.levels
, parse_level
,
1517 ARRAY_SIZE(level_names
)) < 0)
1518 return EXIT_FAILURE
;
1521 ctl
.action
= SYSLOG_ACTION_CONSOLE_LEVEL
;
1522 console_level
= parse_level(optarg
, 0);
1528 ctl
.force_prefix
= 1;
1534 ctl
.method
= DMESG_METHOD_SYSLOG
;
1537 ctl
.bufsize
= strtou32_or_err(optarg
,
1538 _("invalid buffer size argument"));
1539 if (ctl
.bufsize
< 4096)
1543 ctl
.time_fmt
= DMESG_TIMEFTM_CTIME
;
1546 ctl
.time_fmt
= DMESG_TIMEFTM_NONE
;
1550 for (n
= 1; (size_t) n
< ARRAY_SIZE(facility_names
); n
++)
1551 setbit(ctl
.facilities
, n
);
1563 case OPT_TIME_FORMAT
:
1564 ctl
.time_fmt
= which_time_format(optarg
);
1571 if (parse_timestamp(optarg
, &ctl
.since
) < 0)
1572 errx(EXIT_FAILURE
, _("invalid time value \"%s\""), optarg
);
1577 if (parse_timestamp(optarg
, &ctl
.until
) < 0)
1578 errx(EXIT_FAILURE
, _("invalid time value \"%s\""), optarg
);
1584 print_version(EXIT_SUCCESS
);
1586 errtryhelp(EXIT_FAILURE
);
1590 if (argc
!= optind
) {
1591 warnx(_("bad usage"));
1592 errtryhelp(EXIT_FAILURE
);
1596 ctl
.time_fmt
= DMESG_TIMEFTM_TIME
;
1598 ctl
.force_prefix
= 0;
1604 if ((is_timefmt(&ctl
, RELTIME
) ||
1605 is_timefmt(&ctl
, CTIME
) ||
1606 is_timefmt(&ctl
, ISO8601
)) ||
1609 if (dmesg_get_boot_time(&ctl
.boot_time
) != 0)
1610 ctl
.time_fmt
= DMESG_TIMEFTM_NONE
;
1612 ctl
.suspended_time
= dmesg_get_suspended_time();
1616 switch (ctl
.time_fmt
) {
1617 case DMESG_TIMEFTM_CTIME
:
1618 ctl
.time_fmt
= DMESG_TIMEFTM_CTIME_DELTA
;
1620 case DMESG_TIMEFTM_TIME
:
1621 ctl
.time_fmt
= DMESG_TIMEFTM_TIME_DELTA
;
1623 case DMESG_TIMEFTM_ISO8601
:
1624 warnx(_("--show-delta is ignored when used together with iso8601 time format"));
1627 ctl
.time_fmt
= DMESG_TIMEFTM_DELTA
;
1632 ctl
.color
= colors_init(colormode
, "dmesg") ? 1 : 0;
1635 ctl
.pager
= nopager
? 0 : ctl
.pager
;
1637 switch (ctl
.action
) {
1638 case SYSLOG_ACTION_READ_ALL
:
1639 case SYSLOG_ACTION_READ_CLEAR
:
1640 if (ctl
.method
== DMESG_METHOD_KMSG
&& init_kmsg(&ctl
) != 0)
1641 ctl
.method
= DMESG_METHOD_SYSLOG
;
1644 && ctl
.method
!= DMESG_METHOD_KMSG
1645 && (ctl
.fltr_lev
|| ctl
.fltr_fac
))
1646 errx(EXIT_FAILURE
, _("--raw can be used together with --level or "
1647 "--facility only when reading messages from /dev/kmsg"));
1649 /* only kmsg supports multi-line messages */
1650 if (ctl
.force_prefix
&& ctl
.method
!= DMESG_METHOD_KMSG
)
1651 ctl
.force_prefix
= 0;
1654 n
= process_buffer(&ctl
, &buf
);
1656 print_buffer(&ctl
, buf
, n
);
1661 if (ctl
.json
&& ul_jsonwrt_is_ready(&ctl
.jfmt
)) {
1662 ul_jsonwrt_array_close(&ctl
.jfmt
);
1663 ul_jsonwrt_root_close(&ctl
.jfmt
);
1666 err(EXIT_FAILURE
, _("read kernel buffer failed"));
1667 else if (ctl
.action
== SYSLOG_ACTION_READ_CLEAR
)
1672 case SYSLOG_ACTION_CLEAR
:
1673 if (klogctl(SYSLOG_ACTION_CLEAR
, NULL
, 0) < 0)
1674 err(EXIT_FAILURE
, _("clear kernel buffer failed"));
1676 case SYSLOG_ACTION_CONSOLE_OFF
:
1677 case SYSLOG_ACTION_CONSOLE_ON
:
1678 klog_rc
= klogctl(ctl
.action
, NULL
, 0);
1680 case SYSLOG_ACTION_CONSOLE_LEVEL
:
1681 klog_rc
= klogctl(ctl
.action
, NULL
, console_level
);
1684 errx(EXIT_FAILURE
, _("unsupported command"));
1690 err(EXIT_FAILURE
, _("klogctl failed"));
1692 return EXIT_SUCCESS
;