2 * dmesg.c -- Print out the contents of the kernel ring buffer
4 * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu>
5 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
7 * This program comes with ABSOLUTELY NO WARRANTY.
9 #include <linux/unistd.h>
14 #include <sys/syslog.h>
16 #include <sys/sysinfo.h>
20 #include <sys/types.h>
33 #include "closestream.h"
38 /* Close the log. Currently a NOP. */
39 #define SYSLOG_ACTION_CLOSE 0
40 /* Open the log. Currently a NOP. */
41 #define SYSLOG_ACTION_OPEN 1
42 /* Read from the log. */
43 #define SYSLOG_ACTION_READ 2
44 /* Read all messages remaining in the ring buffer. (allowed for non-root) */
45 #define SYSLOG_ACTION_READ_ALL 3
46 /* Read and clear all messages remaining in the ring buffer */
47 #define SYSLOG_ACTION_READ_CLEAR 4
48 /* Clear ring buffer. */
49 #define SYSLOG_ACTION_CLEAR 5
50 /* Disable printk's to console */
51 #define SYSLOG_ACTION_CONSOLE_OFF 6
52 /* Enable printk's to console */
53 #define SYSLOG_ACTION_CONSOLE_ON 7
54 /* Set level of messages printed to console */
55 #define SYSLOG_ACTION_CONSOLE_LEVEL 8
56 /* Return number of unread characters in the log buffer */
57 #define SYSLOG_ACTION_SIZE_UNREAD 9
58 /* Return size of the log buffer */
59 #define SYSLOG_ACTION_SIZE_BUFFER 10
64 #define DMESG_COLOR_SUBSYS UL_COLOR_BROWN
65 #define DMESG_COLOR_TIME UL_COLOR_GREEN
66 #define DMESG_COLOR_RELTIME UL_COLOR_BOLD_GREEN
67 #define DMESG_COLOR_ALERT UL_COLOR_REVERSE UL_COLOR_RED
68 #define DMESG_COLOR_CRIT UL_COLOR_BOLD_RED
69 #define DMESG_COLOR_ERR UL_COLOR_RED
70 #define DMESG_COLOR_WARN UL_COLOR_BOLD
71 #define DMESG_COLOR_SEGFAULT UL_COLOR_HALFBRIGHT UL_COLOR_RED
74 * Priority and facility names
82 * Priority names -- based on sys/syslog.h
84 static const struct dmesg_name level_names
[] =
86 [LOG_EMERG
] = { "emerg", N_("system is unusable") },
87 [LOG_ALERT
] = { "alert", N_("action must be taken immediately") },
88 [LOG_CRIT
] = { "crit", N_("critical conditions") },
89 [LOG_ERR
] = { "err", N_("error conditions") },
90 [LOG_WARNING
] = { "warn", N_("warning conditions") },
91 [LOG_NOTICE
] = { "notice",N_("normal but significant condition") },
92 [LOG_INFO
] = { "info", N_("informational") },
93 [LOG_DEBUG
] = { "debug", N_("debug-level messages") }
97 * sys/syslog.h uses (f << 3) for all facility codes.
98 * We want to use the codes as array idexes, so shift back...
100 * Note that libc LOG_FAC() macro returns the base codes, not the
103 #define FAC_BASE(f) ((f) >> 3)
105 static const struct dmesg_name facility_names
[] =
107 [FAC_BASE(LOG_KERN
)] = { "kern", N_("kernel messages") },
108 [FAC_BASE(LOG_USER
)] = { "user", N_("random user-level messages") },
109 [FAC_BASE(LOG_MAIL
)] = { "mail", N_("mail system") },
110 [FAC_BASE(LOG_DAEMON
)] = { "daemon", N_("system daemons") },
111 [FAC_BASE(LOG_AUTH
)] = { "auth", N_("security/authorization messages") },
112 [FAC_BASE(LOG_SYSLOG
)] = { "syslog", N_("messages generated internally by syslogd") },
113 [FAC_BASE(LOG_LPR
)] = { "lpr", N_("line printer subsystem") },
114 [FAC_BASE(LOG_NEWS
)] = { "news", N_("network news subsystem") },
115 [FAC_BASE(LOG_UUCP
)] = { "uucp", N_("UUCP subsystem") },
116 [FAC_BASE(LOG_CRON
)] = { "cron", N_("clock daemon") },
117 [FAC_BASE(LOG_AUTHPRIV
)] = { "authpriv", N_("security/authorization messages (private)") },
118 [FAC_BASE(LOG_FTP
)] = { "ftp", N_("FTP daemon") },
121 /* supported methods to read message buffer
124 DMESG_METHOD_KMSG
, /* read messages from /dev/kmsg (default) */
125 DMESG_METHOD_SYSLOG
, /* klogctl() buffer */
126 DMESG_METHOD_MMAP
/* mmap file with records (see --file) */
130 DMESG_TIMEFTM_NONE
= 0,
131 DMESG_TIMEFTM_CTIME
, /* [ctime] */
132 DMESG_TIMEFTM_CTIME_DELTA
, /* [ctime <delta>] */
133 DMESG_TIMEFTM_DELTA
, /* [<delta>] */
134 DMESG_TIMEFTM_RELTIME
, /* [relative] */
135 DMESG_TIMEFTM_TIME
, /* [time] */
136 DMESG_TIMEFTM_TIME_DELTA
, /* [time <delta>] */
137 DMESG_TIMEFTM_ISO8601
/* 2013-06-13T22:11:00,123456+0100 */
139 #define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f))
141 struct dmesg_control
{
142 /* bit arrays -- see include/bitops.h */
143 char levels
[ARRAY_SIZE(level_names
) / NBBY
+ 1];
144 char facilities
[ARRAY_SIZE(facility_names
) / NBBY
+ 1];
146 struct timeval lasttime
; /* last printed timestamp */
147 struct tm lasttm
; /* last localtime */
148 struct timeval boot_time
; /* system boot time */
150 int action
; /* SYSLOG_ACTION_* */
151 int method
; /* DMESG_METHOD_* */
153 size_t bufsize
; /* size of syslog buffer */
155 int kmsg
; /* /dev/kmsg file descriptor */
156 ssize_t kmsg_first_read
;/* initial read() return code */
157 char kmsg_buf
[BUFSIZ
];/* buffer to read kmsg data */
160 * For the --file option we mmap whole file. The unnecessary (already
161 * printed) pages are always unmapped. The result is that we have in
162 * memory only the currently used page(s).
167 unsigned int time_fmt
; /* time format */
169 unsigned int follow
:1, /* wait for new messages */
170 raw
:1, /* raw mode */
171 fltr_lev
:1, /* filter out by levels[] */
172 fltr_fac
:1, /* filter out by facilities[] */
173 decode
:1, /* use "facility: level: " prefix */
174 pager
:1, /* pipe output into a pager */
175 color
:1; /* colorize messages */
178 struct dmesg_record
{
186 const char *next
; /* buffer with next unparsed record */
187 size_t next_size
; /* size of the next buffer */
190 #define INIT_DMESG_RECORD(_r) do { \
192 (_r)->mesg_size = 0; \
193 (_r)->facility = -1; \
195 (_r)->tv.tv_sec = 0; \
196 (_r)->tv.tv_usec = 0; \
199 static int read_kmsg(struct dmesg_control
*ctl
);
201 static int set_level_color(int log_level
, const char *mesg
, size_t mesgsz
)
205 color_enable(DMESG_COLOR_ALERT
);
208 color_enable(DMESG_COLOR_CRIT
);
211 color_enable(DMESG_COLOR_ERR
);
214 color_enable(DMESG_COLOR_WARN
);
220 /* well, sometimes the messges contains important keywords, but in
221 * non-warning/error messages
223 if (memmem(mesg
, mesgsz
, "segfault at", 11)) {
224 color_enable(DMESG_COLOR_SEGFAULT
);
231 static void __attribute__((__noreturn__
)) usage(FILE *out
)
235 fputs(USAGE_HEADER
, out
);
236 fprintf(out
, _(" %s [options]\n"), program_invocation_short_name
);
237 fputs(USAGE_OPTIONS
, out
);
238 fputs(_(" -C, --clear clear the kernel ring buffer\n"), out
);
239 fputs(_(" -c, --read-clear read and clear all messages\n"), out
);
240 fputs(_(" -D, --console-off disable printing messages to console\n"), out
);
241 fputs(_(" -E, --console-on enable printing messages to console\n"), out
);
242 fputs(_(" -F, --file <file> use the file instead of the kernel log buffer\n"), out
);
243 fputs(_(" -f, --facility <list> restrict output to defined facilities\n"), out
);
244 fputs(_(" -H, --human human readable output\n"), out
);
245 fputs(_(" -k, --kernel display kernel messages\n"), out
);
246 fputs(_(" -L, --color[=<when>] colorize messages (auto, always or never)\n"), out
);
247 fputs(_(" -l, --level <list> restrict output to defined levels\n"), out
);
248 fputs(_(" -n, --console-level <level> set level of messages printed to console\n"), out
);
249 fputs(_(" -P, --nopager do not pipe output into a pager\n"), out
);
250 fputs(_(" -r, --raw print the raw message buffer\n"), out
);
251 fputs(_(" -S, --syslog force to use syslog(2) rather than /dev/kmsg\n"), out
);
252 fputs(_(" -s, --buffer-size <size> buffer size to query the kernel ring buffer\n"), out
);
253 fputs(_(" -u, --userspace display userspace messages\n"), out
);
254 fputs(_(" -w, --follow wait for new messages\n"), out
);
255 fputs(_(" -x, --decode decode facility and level to readable string\n"), out
);
256 fputs(_(" -d, --show-delta show time delta between printed messages\n"), out
);
257 fputs(_(" -e, --reltime show local time and time delta in readable format\n"), out
);
258 fputs(_(" -T, --ctime show human readable timestamp\n"), out
);
259 fputs(_(" -t, --notime don't print messages timestamp\n"), out
);
260 fputs(_(" --time-format <format> show time stamp using format:\n"
261 " [delta|reltime|ctime|notime|iso]\n"
262 "Suspending/resume will make ctime and iso timestamps inaccurate.\n"), out
);
263 fputs(USAGE_SEPARATOR
, out
);
264 fputs(USAGE_HELP
, out
);
265 fputs(USAGE_VERSION
, out
);
266 fputs(_("\nSupported log facilities:\n"), out
);
267 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++)
268 fprintf(out
, " %7s - %s\n",
269 facility_names
[i
].name
,
270 _(facility_names
[i
].help
));
272 fputs(_("\nSupported log levels (priorities):\n"), out
);
273 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++)
274 fprintf(out
, " %7s - %s\n",
276 _(level_names
[i
].help
));
277 fputs(USAGE_SEPARATOR
, out
);
278 fprintf(out
, USAGE_MAN_TAIL("dmesg(1)"));
279 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
283 * LEVEL ::= <number> | <name>
284 * <number> ::= @len is set: number in range <0..N>, where N < ARRAY_SIZE(level_names)
285 * ::= @len not set: number in range <1..N>, where N <= ARRAY_SIZE(level_names)
286 * <name> ::= case-insensitive text
288 * Note that @len argument is not set when parsing "-n <level>" command line
289 * option. The console_level is intepreted as "log level less than the value".
291 * For example "dmesg -n 8" or "dmesg -n debug" enables debug console log
292 * level by klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, 8). The @str argument
293 * has to be parsed to number in range <1..8>.
295 static int parse_level(const char *str
, size_t len
)
309 long x
= strtol(str
, &end
, 10) - offset
;
311 if (!errno
&& end
&& end
> str
&& (size_t) (end
- str
) == len
&&
312 x
>= 0 && (size_t) x
< ARRAY_SIZE(level_names
))
317 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++) {
318 const char *n
= level_names
[i
].name
;
320 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
326 err(EXIT_FAILURE
, _("failed to parse level '%s'"), str
);
328 errx(EXIT_FAILURE
, _("unknown level '%s'"), str
);
333 * FACILITY ::= <number> | <name>
334 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
335 * <name> ::= case-insensitive text
337 static int parse_facility(const char *str
, size_t len
)
347 long x
= strtol(str
, &end
, 10);
349 if (!errno
&& end
&& end
> str
&& (size_t) (end
- str
) == len
&&
350 x
>= 0 && (size_t) x
< ARRAY_SIZE(facility_names
))
355 for (i
= 0; i
< ARRAY_SIZE(facility_names
); i
++) {
356 const char *n
= facility_names
[i
].name
;
358 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
364 err(EXIT_FAILURE
, _("failed to parse facility '%s'"), str
);
366 errx(EXIT_FAILURE
, _("unknown facility '%s'"), str
);
371 * Parses numerical prefix used for all messages in kernel ring buffer.
373 * Priorities/facilities are encoded into a single 32-bit quantity, where the
374 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
377 * Note that the number has to end with '>' or ',' char.
379 static const char *parse_faclev(const char *str
, int *fac
, int *lev
)
388 num
= strtol(str
, &end
, 10);
390 if (!errno
&& end
&& end
> str
) {
394 if (*lev
< 0 || (size_t) *lev
> ARRAY_SIZE(level_names
))
396 if (*fac
< 0 || (size_t) *fac
> ARRAY_SIZE(facility_names
))
398 return end
+ 1; /* skip '<' or ',' */
405 * Parses timestamp from syslog message prefix, expected format:
407 * seconds.microseconds]
409 * the ']' is the timestamp field terminator.
411 static const char *parse_syslog_timestamp(const char *str0
, struct timeval
*tv
)
413 const char *str
= str0
;
420 tv
->tv_sec
= strtol(str
, &end
, 10);
422 if (!errno
&& end
&& *end
== '.' && *(end
+ 1)) {
425 tv
->tv_usec
= strtol(str
, &end
, 10);
427 if (errno
|| !end
|| end
== str
|| *end
!= ']')
430 return end
+ 1; /* skip ']' */
434 * Parses timestamp from /dev/kmsg, expected formats:
439 * the ',' is fields separators and ';' items terminator (for the last item)
441 static const char *parse_kmsg_timestamp(const char *str0
, struct timeval
*tv
)
443 const char *str
= str0
;
451 usec
= strtoumax(str
, &end
, 10);
453 if (!errno
&& end
&& (*end
== ';' || *end
== ',')) {
454 tv
->tv_usec
= usec
% 1000000;
455 tv
->tv_sec
= usec
/ 1000000;
459 return end
+ 1; /* skip separator */
463 static double time_diff(struct timeval
*a
, struct timeval
*b
)
465 return (a
->tv_sec
- b
->tv_sec
) + (a
->tv_usec
- b
->tv_usec
) / 1E6
;
468 static int get_syslog_buffer_size(void)
470 int n
= klogctl(SYSLOG_ACTION_SIZE_BUFFER
, NULL
, 0);
472 return n
> 0 ? n
: 0;
475 static int get_boot_time(struct timeval
*boot_time
)
477 struct timespec hires_uptime
;
478 struct timeval lores_uptime
, now
;
481 if (gettimeofday(&now
, NULL
) != 0) {
482 warn(_("gettimeofday failed"));
486 #ifdef CLOCK_BOOTTIME
487 if (clock_gettime(CLOCK_BOOTTIME
, &hires_uptime
) == 0) {
488 TIMESPEC_TO_TIMEVAL(&lores_uptime
, &hires_uptime
);
489 timersub(&now
, &lores_uptime
, boot_time
);
494 if (sysinfo(&info
) != 0)
495 warn(_("sysinfo failed"));
497 boot_time
->tv_sec
= now
.tv_sec
- info
.uptime
;
498 boot_time
->tv_usec
= 0;
503 * Reads messages from regular file by mmap
505 static ssize_t
mmap_file_buffer(struct dmesg_control
*ctl
, char **buf
)
513 fd
= open(ctl
->filename
, O_RDONLY
);
515 err(EXIT_FAILURE
, _("cannot open %s"), ctl
->filename
);
517 err(EXIT_FAILURE
, _("stat failed %s"), ctl
->filename
);
519 *buf
= mmap(NULL
, st
.st_size
, PROT_READ
, MAP_SHARED
, fd
, 0);
520 if (*buf
== MAP_FAILED
)
521 err(EXIT_FAILURE
, _("cannot mmap: %s"), ctl
->filename
);
522 ctl
->mmap_buff
= *buf
;
523 ctl
->pagesize
= getpagesize();
530 * Reads messages from kernel ring buffer by klogctl()
532 static ssize_t
read_syslog_buffer(struct dmesg_control
*ctl
, char **buf
)
538 sz
= ctl
->bufsize
+ 8;
539 *buf
= xmalloc(sz
* sizeof(char));
540 rc
= klogctl(ctl
->action
, *buf
, sz
);
544 *buf
= xmalloc(sz
* sizeof(char));
545 rc
= klogctl(SYSLOG_ACTION_READ_ALL
, *buf
, sz
);
548 if ((size_t) rc
!= sz
|| sz
> (1 << 28))
555 if (rc
> 0 && ctl
->action
== SYSLOG_ACTION_READ_CLEAR
)
556 rc
= klogctl(SYSLOG_ACTION_READ_CLEAR
, *buf
, sz
);
563 * Top level function to read messages
565 static ssize_t
read_buffer(struct dmesg_control
*ctl
, char **buf
)
569 switch (ctl
->method
) {
570 case DMESG_METHOD_MMAP
:
571 n
= mmap_file_buffer(ctl
, buf
);
573 case DMESG_METHOD_SYSLOG
:
575 ctl
->bufsize
= get_syslog_buffer_size();
577 n
= read_syslog_buffer(ctl
, buf
);
579 case DMESG_METHOD_KMSG
:
584 if (n
== 0 && ctl
->action
== SYSLOG_ACTION_READ_CLEAR
)
585 n
= klogctl(SYSLOG_ACTION_CLEAR
, NULL
, 0);
592 static int fwrite_hex(const char *buf
, size_t size
, FILE *out
)
596 for (i
= 0; i
< size
; i
++) {
597 int rc
= fprintf(out
, "\\x%02x", buf
[i
]);
605 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
607 static void safe_fwrite(const char *buf
, size_t size
, FILE *out
)
612 memset(&s
, 0, sizeof (s
));
614 for (i
= 0; i
< size
; i
++) {
615 const char *p
= buf
+ i
;
621 len
= mbrtowc(&wc
, p
, size
- i
, &s
);
623 if (len
== 0) /* L'\0' */
626 if (len
== (size_t)-1 || len
== (size_t)-2) { /* invalid sequence */
627 memset(&s
, 0, sizeof (s
));
629 } else if (len
> 1 && !iswprint(wc
)) { /* non-printable multibyte */
634 if (!isprint((unsigned int) *p
) &&
635 !isspace((unsigned int) *p
)) /* non-printable */
639 rc
= fwrite_hex(p
, len
, out
);
641 rc
= fwrite(p
, 1, len
, out
) != len
;
644 err(EXIT_FAILURE
, _("write failed"));
650 static const char *skip_item(const char *begin
, const char *end
, const char *sep
)
652 while (begin
< end
) {
655 if (c
== '\0' || strchr(sep
, c
))
663 * Parses one record from syslog(2) buffer
665 static int get_next_syslog_record(struct dmesg_control
*ctl
,
666 struct dmesg_record
*rec
)
669 const char *begin
= NULL
;
671 if (ctl
->method
!= DMESG_METHOD_MMAP
&&
672 ctl
->method
!= DMESG_METHOD_SYSLOG
)
675 if (!rec
->next
|| !rec
->next_size
)
678 INIT_DMESG_RECORD(rec
);
681 * Unmap already printed file data from memory
683 if (ctl
->mmap_buff
&& (size_t) (rec
->next
- ctl
->mmap_buff
) > ctl
->pagesize
) {
684 void *x
= ctl
->mmap_buff
;
686 ctl
->mmap_buff
+= ctl
->pagesize
;
687 munmap(x
, ctl
->pagesize
);
690 for (i
= 0; i
< rec
->next_size
; i
++) {
691 const char *p
= rec
->next
+ i
;
692 const char *end
= NULL
;
696 if (i
+ 1 == rec
->next_size
) {
699 } else if (*p
== '\n' && *(p
+ 1) == '<')
702 if (begin
&& !*begin
)
703 begin
= NULL
; /* zero(s) at the end of the buffer? */
707 continue; /* error or empty line? */
710 if (ctl
->fltr_lev
|| ctl
->fltr_fac
|| ctl
->decode
|| ctl
->color
)
711 begin
= parse_faclev(begin
+ 1, &rec
->facility
,
714 begin
= skip_item(begin
, end
, ">");
717 if (*begin
== '[' && (*(begin
+ 1) == ' ' ||
718 isdigit(*(begin
+ 1)))) {
720 if (!is_timefmt(ctl
, NONE
))
721 begin
= parse_syslog_timestamp(begin
+ 1, &rec
->tv
);
723 begin
= skip_item(begin
, end
, "]");
725 if (begin
< end
&& *begin
== ' ')
730 rec
->mesg_size
= end
- begin
;
732 rec
->next_size
-= end
- rec
->next
;
733 rec
->next
= rec
->next_size
> 0 ? end
+ 1 : NULL
;
734 if (rec
->next_size
> 0)
743 static int accept_record(struct dmesg_control
*ctl
, struct dmesg_record
*rec
)
745 if (ctl
->fltr_lev
&& (rec
->facility
< 0 ||
746 !isset(ctl
->levels
, rec
->level
)))
749 if (ctl
->fltr_fac
&& (rec
->facility
< 0 ||
750 !isset(ctl
->facilities
, rec
->facility
)))
756 static void raw_print(struct dmesg_control
*ctl
, const char *buf
, size_t size
)
760 if (!ctl
->mmap_buff
) {
762 * Print whole ring buffer
764 safe_fwrite(buf
, size
, stdout
);
765 lastc
= buf
[size
- 1];
768 * Print file in small chunks to save memory
771 size_t sz
= size
> ctl
->pagesize
? ctl
->pagesize
: size
;
772 char *x
= ctl
->mmap_buff
;
774 safe_fwrite(x
, sz
, stdout
);
777 ctl
->mmap_buff
+= sz
;
786 static struct tm
*record_localtime(struct dmesg_control
*ctl
,
787 struct dmesg_record
*rec
,
790 time_t t
= ctl
->boot_time
.tv_sec
+ rec
->tv
.tv_sec
;
791 return localtime_r(&t
, tm
);
794 static char *record_ctime(struct dmesg_control
*ctl
,
795 struct dmesg_record
*rec
,
796 char *buf
, size_t bufsiz
)
800 record_localtime(ctl
, rec
, &tm
);
802 if (strftime(buf
, bufsiz
, "%a %b %e %H:%M:%S %Y", &tm
) == 0)
807 static char *short_ctime(struct tm
*tm
, char *buf
, size_t bufsiz
)
809 if (strftime(buf
, bufsiz
, "%b%e %H:%M", tm
) == 0)
814 static char *iso_8601_time(struct dmesg_control
*ctl
, struct dmesg_record
*rec
,
815 char *buf
, size_t bufsiz
)
819 record_localtime(ctl
, rec
, &tm
);
820 if (strftime(buf
, bufsiz
, "%Y-%m-%dT%H:%M:%S", &tm
) == 0) {
825 snprintf(buf
+ len
, bufsiz
- len
, ",%06d", (int)rec
->tv
.tv_usec
);
827 strftime(buf
+ len
, bufsiz
- len
, "%z", &tm
);
831 static double record_count_delta(struct dmesg_control
*ctl
,
832 struct dmesg_record
*rec
)
836 if (timerisset(&ctl
->lasttime
))
837 delta
= time_diff(&rec
->tv
, &ctl
->lasttime
);
839 ctl
->lasttime
= rec
->tv
;
843 static const char *get_subsys_delimiter(const char *mesg
, size_t mesg_size
)
845 const char *p
= mesg
;
846 size_t sz
= mesg_size
;
849 const char *d
= strnchr(p
, sz
, ':');
854 if (isblank(*(d
+ 1)))
862 static void print_record(struct dmesg_control
*ctl
,
863 struct dmesg_record
*rec
)
870 if (!accept_record(ctl
, rec
))
873 if (!rec
->mesg_size
) {
879 * compose syslog(2) compatible raw output -- used for /dev/kmsg for
880 * backward compatibility with syslog(2) buffers only
883 printf("<%d>[%5d.%06d] ",
884 LOG_MAKEPRI(rec
->facility
, rec
->level
),
885 (int) rec
->tv
.tv_sec
,
886 (int) rec
->tv
.tv_usec
);
892 * facility : priority :
895 -1 < rec
->level
&& rec
->level
< (int) ARRAY_SIZE(level_names
) &&
896 -1 < rec
->facility
&& rec
->facility
< (int) ARRAY_SIZE(facility_names
))
897 printf("%-6s:%-6s: ", facility_names
[rec
->facility
].name
,
898 level_names
[rec
->level
].name
);
901 color_enable(DMESG_COLOR_TIME
);
903 switch (ctl
->time_fmt
) {
906 case DMESG_TIMEFTM_NONE
:
908 case DMESG_TIMEFTM_CTIME
:
909 printf("[%s] ", record_ctime(ctl
, rec
, buf
, sizeof(buf
)));
911 case DMESG_TIMEFTM_CTIME_DELTA
:
912 printf("[%s <%12.06f>] ",
913 record_ctime(ctl
, rec
, buf
, sizeof(buf
)),
914 record_count_delta(ctl
, rec
));
916 case DMESG_TIMEFTM_DELTA
:
917 printf("[<%12.06f>] ", record_count_delta(ctl
, rec
));
919 case DMESG_TIMEFTM_RELTIME
:
920 record_localtime(ctl
, rec
, &cur
);
921 delta
= record_count_delta(ctl
, rec
);
922 if (cur
.tm_min
!= ctl
->lasttm
.tm_min
||
923 cur
.tm_hour
!= ctl
->lasttm
.tm_hour
||
924 cur
.tm_yday
!= ctl
->lasttm
.tm_yday
) {
925 printf("[%s] ", short_ctime(&cur
, buf
, sizeof(buf
)));
928 printf("[ %+8.06f] ", delta
);
930 printf("[ %+9.06f] ", delta
);
934 case DMESG_TIMEFTM_TIME
:
935 printf("[%5d.%06d] ", (int)rec
->tv
.tv_sec
, (int)rec
->tv
.tv_usec
);
937 case DMESG_TIMEFTM_TIME_DELTA
:
938 printf("[%5d.%06d <%12.06f>] ", (int)rec
->tv
.tv_sec
,
939 (int)rec
->tv
.tv_usec
, record_count_delta(ctl
, rec
));
941 case DMESG_TIMEFTM_ISO8601
:
942 printf("%s ", iso_8601_time(ctl
, rec
, buf
, sizeof(buf
)));
953 mesg_size
= rec
->mesg_size
;
955 /* Colorize output */
957 /* subsystem prefix */
958 const char *subsys
= get_subsys_delimiter(mesg
, mesg_size
);
960 color_enable(DMESG_COLOR_SUBSYS
);
961 safe_fwrite(mesg
, subsys
- mesg
, stdout
);
964 mesg_size
-= subsys
- mesg
;
967 /* error, alert .. etc. colors */
968 has_color
= set_level_color(rec
->level
, mesg
, mesg_size
) == 0;
969 safe_fwrite(mesg
, mesg_size
, stdout
);
973 safe_fwrite(mesg
, mesg_size
, stdout
);
975 if (*(mesg
+ mesg_size
- 1) != '\n')
980 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
981 * to 'levels' and 'facilities' bitarrays.
983 static void print_buffer(struct dmesg_control
*ctl
,
984 const char *buf
, size_t size
)
986 struct dmesg_record rec
= { .next
= buf
, .next_size
= size
};
989 raw_print(ctl
, buf
, size
);
993 while (get_next_syslog_record(ctl
, &rec
) == 0)
994 print_record(ctl
, &rec
);
997 static ssize_t
read_kmsg_one(struct dmesg_control
*ctl
)
1001 /* kmsg returns EPIPE if record was modified while reading */
1003 size
= read(ctl
->kmsg
, ctl
->kmsg_buf
,
1004 sizeof(ctl
->kmsg_buf
) - 1);
1005 } while (size
< 0 && errno
== EPIPE
);
1010 static int init_kmsg(struct dmesg_control
*ctl
)
1012 int mode
= O_RDONLY
;
1019 ctl
->kmsg
= open("/dev/kmsg", mode
);
1024 * Seek after the last record available at the time
1025 * the last SYSLOG_ACTION_CLEAR was issued.
1027 * ... otherwise SYSLOG_ACTION_CLEAR will have no effect for kmsg.
1029 lseek(ctl
->kmsg
, 0, SEEK_DATA
);
1032 * Old kernels (<3.5) allow to successfully open /dev/kmsg for
1033 * read-only, but read() returns -EINVAL :-(((
1035 * Let's try to read the first record. The record is later processed in
1038 ctl
->kmsg_first_read
= read_kmsg_one(ctl
);
1039 if (ctl
->kmsg_first_read
< 0) {
1049 * /dev/kmsg record format:
1051 * faclev,seqnum,timestamp[optional, ...];messgage\n
1055 * - fields are separated by ','
1056 * - last field is terminated by ';'
1059 #define LAST_KMSG_FIELD(s) (!s || !*s || *(s - 1) == ';')
1061 static int parse_kmsg_record(struct dmesg_control
*ctl
,
1062 struct dmesg_record
*rec
,
1066 const char *p
= buf
, *end
;
1068 if (sz
== 0 || !buf
|| !*buf
)
1071 end
= buf
+ (sz
- 1);
1072 INIT_DMESG_RECORD(rec
);
1074 while (p
< end
&& isspace(*p
))
1077 /* A) priority and facility */
1078 if (ctl
->fltr_lev
|| ctl
->fltr_fac
|| ctl
->decode
||
1079 ctl
->raw
|| ctl
->color
)
1080 p
= parse_faclev(p
, &rec
->facility
, &rec
->level
);
1082 p
= skip_item(p
, end
, ",");
1083 if (LAST_KMSG_FIELD(p
))
1086 /* B) sequence number */
1087 p
= skip_item(p
, end
, ",;");
1088 if (LAST_KMSG_FIELD(p
))
1092 if (is_timefmt(ctl
, NONE
))
1093 p
= skip_item(p
, end
, ",;");
1095 p
= parse_kmsg_timestamp(p
, &rec
->tv
);
1096 if (LAST_KMSG_FIELD(p
))
1099 /* D) optional fields (ignore) */
1100 p
= skip_item(p
, end
, ";");
1101 if (LAST_KMSG_FIELD(p
))
1105 /* E) message text */
1107 p
= skip_item(p
, end
, "\n");
1112 rec
->mesg_size
= p
- rec
->mesg
;
1115 * Kernel escapes non-printable characters, unfortuately kernel
1116 * definition of "non-printable" is too strict. On UTF8 console we can
1117 * print many chars, so let's decode from kernel.
1119 unhexmangle_to_buffer(rec
->mesg
, (char *) rec
->mesg
, rec
->mesg_size
+ 1);
1121 /* F) message tags (ignore) */
1127 * Note that each read() call for /dev/kmsg returns always one record. It means
1128 * that we don't have to read whole message buffer before the records parsing.
1130 * So this function does not compose one huge buffer (like read_syslog_buffer())
1131 * and print_buffer() is unnecessary. All is done in this function.
1133 * Returns 0 on success, -1 on error.
1135 static int read_kmsg(struct dmesg_control
*ctl
)
1137 struct dmesg_record rec
;
1140 if (ctl
->method
!= DMESG_METHOD_KMSG
|| ctl
->kmsg
< 0)
1144 * The very first read() call is done in kmsg_init() where we test
1145 * /dev/kmsg usability. The return code from the initial read() is
1146 * stored in ctl->kmsg_first_read;
1148 sz
= ctl
->kmsg_first_read
;
1151 *(ctl
->kmsg_buf
+ sz
) = '\0'; /* for debug messages */
1153 if (parse_kmsg_record(ctl
, &rec
,
1154 ctl
->kmsg_buf
, (size_t) sz
) == 0)
1155 print_record(ctl
, &rec
);
1157 sz
= read_kmsg_one(ctl
);
1163 static int which_time_format(const char *optarg
)
1165 if (!strcmp(optarg
, "notime"))
1166 return DMESG_TIMEFTM_NONE
;
1167 if (!strcmp(optarg
, "ctime"))
1168 return DMESG_TIMEFTM_CTIME
;
1169 if (!strcmp(optarg
, "delta"))
1170 return DMESG_TIMEFTM_DELTA
;
1171 if (!strcmp(optarg
, "reltime"))
1172 return DMESG_TIMEFTM_RELTIME
;
1173 if (!strcmp(optarg
, "iso"))
1174 return DMESG_TIMEFTM_ISO8601
;
1175 errx(EXIT_FAILURE
, _("unknown time format: %s"), optarg
);
1178 int main(int argc
, char *argv
[])
1182 int console_level
= 0;
1186 static struct dmesg_control ctl
= {
1188 .action
= SYSLOG_ACTION_READ_ALL
,
1189 .method
= DMESG_METHOD_KMSG
,
1191 .time_fmt
= DMESG_TIMEFTM_TIME
,
1193 int colormode
= UL_COLORMODE_UNDEF
;
1195 OPT_TIME_FORMAT
= CHAR_MAX
+ 1,
1198 static const struct option longopts
[] = {
1199 { "buffer-size", required_argument
, NULL
, 's' },
1200 { "clear", no_argument
, NULL
, 'C' },
1201 { "color", optional_argument
, NULL
, 'L' },
1202 { "console-level", required_argument
, NULL
, 'n' },
1203 { "console-off", no_argument
, NULL
, 'D' },
1204 { "console-on", no_argument
, NULL
, 'E' },
1205 { "decode", no_argument
, NULL
, 'x' },
1206 { "file", required_argument
, NULL
, 'F' },
1207 { "facility", required_argument
, NULL
, 'f' },
1208 { "follow", no_argument
, NULL
, 'w' },
1209 { "human", no_argument
, NULL
, 'H' },
1210 { "help", no_argument
, NULL
, 'h' },
1211 { "kernel", no_argument
, NULL
, 'k' },
1212 { "level", required_argument
, NULL
, 'l' },
1213 { "syslog", no_argument
, NULL
, 'S' },
1214 { "raw", no_argument
, NULL
, 'r' },
1215 { "read-clear", no_argument
, NULL
, 'c' },
1216 { "reltime", no_argument
, NULL
, 'e' },
1217 { "show-delta", no_argument
, NULL
, 'd' },
1218 { "ctime", no_argument
, NULL
, 'T' },
1219 { "notime", no_argument
, NULL
, 't' },
1220 { "nopager", no_argument
, NULL
, 'P' },
1221 { "userspace", no_argument
, NULL
, 'u' },
1222 { "version", no_argument
, NULL
, 'V' },
1223 { "time-format", required_argument
, NULL
, OPT_TIME_FORMAT
},
1224 { NULL
, 0, NULL
, 0 }
1227 static const ul_excl_t excl
[] = { /* rows and cols in in ASCII order */
1228 { 'C','D','E','c','n','r' }, /* clear,off,on,read-clear,level,raw*/
1229 { 'H','r' }, /* human, raw */
1230 { 'L','r' }, /* color, raw */
1231 { 'S','w' }, /* syslog,follow */
1232 { 'T','r' }, /* ctime, raw */
1233 { 'd','r' }, /* delta, raw */
1234 { 'e','r' }, /* reltime, raw */
1235 { 'r','x' }, /* raw, decode */
1236 { 'r','t' }, /* notime, raw */
1239 int excl_st
[ARRAY_SIZE(excl
)] = UL_EXCL_STATUS_INIT
;
1241 setlocale(LC_ALL
, "");
1242 bindtextdomain(PACKAGE
, LOCALEDIR
);
1243 textdomain(PACKAGE
);
1244 atexit(close_stdout
);
1246 while ((c
= getopt_long(argc
, argv
, "CcDdEeF:f:HhkL::l:n:iPrSs:TtuVwx",
1247 longopts
, NULL
)) != -1) {
1249 err_exclusive_options(c
, longopts
, excl
, excl_st
);
1253 ctl
.action
= SYSLOG_ACTION_CLEAR
;
1256 ctl
.action
= SYSLOG_ACTION_READ_CLEAR
;
1259 ctl
.action
= SYSLOG_ACTION_CONSOLE_OFF
;
1265 ctl
.action
= SYSLOG_ACTION_CONSOLE_ON
;
1268 ctl
.time_fmt
= DMESG_TIMEFTM_RELTIME
;
1271 ctl
.filename
= optarg
;
1272 ctl
.method
= DMESG_METHOD_MMAP
;
1276 if (string_to_bitarray(optarg
,
1277 ctl
.facilities
, parse_facility
) < 0)
1278 return EXIT_FAILURE
;
1281 ctl
.time_fmt
= DMESG_TIMEFTM_RELTIME
;
1282 colormode
= UL_COLORMODE_AUTO
;
1290 setbit(ctl
.facilities
, FAC_BASE(LOG_KERN
));
1293 colormode
= UL_COLORMODE_AUTO
;
1295 colormode
= colormode_or_err(optarg
,
1296 _("unsupported color mode"));
1300 if (string_to_bitarray(optarg
,
1301 ctl
.levels
, parse_level
) < 0)
1302 return EXIT_FAILURE
;
1305 ctl
.action
= SYSLOG_ACTION_CONSOLE_LEVEL
;
1306 console_level
= parse_level(optarg
, 0);
1315 ctl
.method
= DMESG_METHOD_SYSLOG
;
1318 ctl
.bufsize
= strtou32_or_err(optarg
,
1319 _("invalid buffer size argument"));
1320 if (ctl
.bufsize
< 4096)
1324 ctl
.time_fmt
= DMESG_TIMEFTM_CTIME
;
1327 ctl
.time_fmt
= DMESG_TIMEFTM_NONE
;
1332 for (n
= 1; (size_t) n
< ARRAY_SIZE(facility_names
); n
++)
1333 setbit(ctl
.facilities
, n
);
1336 printf(_("%s from %s\n"), program_invocation_short_name
,
1338 return EXIT_SUCCESS
;
1345 case OPT_TIME_FORMAT
:
1346 ctl
.time_fmt
= which_time_format(optarg
);
1359 if (is_timefmt(&ctl
, RELTIME
) ||
1360 is_timefmt(&ctl
, CTIME
) ||
1361 is_timefmt(&ctl
, ISO8601
)) {
1363 if (get_boot_time(&ctl
.boot_time
) != 0)
1364 ctl
.time_fmt
= DMESG_TIMEFTM_NONE
;
1368 switch (ctl
.time_fmt
) {
1369 case DMESG_TIMEFTM_CTIME
:
1370 ctl
.time_fmt
= DMESG_TIMEFTM_CTIME_DELTA
;
1372 case DMESG_TIMEFTM_TIME
:
1373 ctl
.time_fmt
= DMESG_TIMEFTM_TIME_DELTA
;
1375 case DMESG_TIMEFTM_ISO8601
:
1376 warnx(_("--show-delta is ignored when used together with iso8601 time format"));
1379 ctl
.time_fmt
= DMESG_TIMEFTM_DELTA
;
1383 ctl
.color
= colors_init(colormode
, "dmesg") ? 1 : 0;
1386 ctl
.pager
= nopager
? 0 : ctl
.pager
;
1390 switch (ctl
.action
) {
1391 case SYSLOG_ACTION_READ_ALL
:
1392 case SYSLOG_ACTION_READ_CLEAR
:
1393 if (ctl
.method
== DMESG_METHOD_KMSG
&& init_kmsg(&ctl
) != 0)
1394 ctl
.method
= DMESG_METHOD_SYSLOG
;
1397 && ctl
.method
!= DMESG_METHOD_KMSG
1398 && (ctl
.fltr_lev
|| ctl
.fltr_fac
))
1399 errx(EXIT_FAILURE
, _("--raw could be used together with --level or "
1400 "--facility only when read messages from /dev/kmsg"));
1403 n
= read_buffer(&ctl
, &buf
);
1405 print_buffer(&ctl
, buf
, n
);
1409 err(EXIT_FAILURE
, _("read kernel buffer failed"));
1413 case SYSLOG_ACTION_CLEAR
:
1414 case SYSLOG_ACTION_CONSOLE_OFF
:
1415 case SYSLOG_ACTION_CONSOLE_ON
:
1416 klog_rc
= klogctl(ctl
.action
, NULL
, 0);
1418 case SYSLOG_ACTION_CONSOLE_LEVEL
:
1419 klog_rc
= klogctl(ctl
.action
, NULL
, console_level
);
1422 errx(EXIT_FAILURE
, _("unsupported command"));
1428 err(EXIT_FAILURE
, _("klogctl failed"));
1430 return EXIT_SUCCESS
;