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>
28 /* Close the log. Currently a NOP. */
29 #define SYSLOG_ACTION_CLOSE 0
30 /* Open the log. Currently a NOP. */
31 #define SYSLOG_ACTION_OPEN 1
32 /* Read from the log. */
33 #define SYSLOG_ACTION_READ 2
34 /* Read all messages remaining in the ring buffer. (allowed for non-root) */
35 #define SYSLOG_ACTION_READ_ALL 3
36 /* Read and clear all messages remaining in the ring buffer */
37 #define SYSLOG_ACTION_READ_CLEAR 4
38 /* Clear ring buffer. */
39 #define SYSLOG_ACTION_CLEAR 5
40 /* Disable printk's to console */
41 #define SYSLOG_ACTION_CONSOLE_OFF 6
42 /* Enable printk's to console */
43 #define SYSLOG_ACTION_CONSOLE_ON 7
44 /* Set level of messages printed to console */
45 #define SYSLOG_ACTION_CONSOLE_LEVEL 8
46 /* Return number of unread characters in the log buffer */
47 #define SYSLOG_ACTION_SIZE_UNREAD 9
48 /* Return size of the log buffer */
49 #define SYSLOG_ACTION_SIZE_BUFFER 10
52 * Priority and facility names
60 * Priority names -- based on sys/syslog.h
62 static const struct dmesg_name level_names
[] =
64 [LOG_EMERG
] = { "emerg", N_("system is unusable") },
65 [LOG_ALERT
] = { "alert", N_("action must be taken immediately") },
66 [LOG_CRIT
] = { "crit", N_("critical conditions") },
67 [LOG_ERR
] = { "err", N_("error conditions") },
68 [LOG_WARNING
] = { "warn", N_("warning conditions") },
69 [LOG_NOTICE
] = { "notice",N_("normal but significant condition") },
70 [LOG_INFO
] = { "info", N_("informational") },
71 [LOG_DEBUG
] = { "debug", N_("debug-level messages") }
75 * sys/syslog.h uses (f << 3) for all facility codes.
76 * We want to use the codes as array idexes, so shift back...
78 * Note that libc LOG_FAC() macro returns the base codes, not the
81 #define FAC_BASE(f) ((f) >> 3)
83 static const struct dmesg_name facility_names
[] =
85 [FAC_BASE(LOG_KERN
)] = { "kern", N_("kernel messages") },
86 [FAC_BASE(LOG_USER
)] = { "user", N_("random user-level messages") },
87 [FAC_BASE(LOG_MAIL
)] = { "mail", N_("mail system") },
88 [FAC_BASE(LOG_DAEMON
)] = { "daemon", N_("system daemons") },
89 [FAC_BASE(LOG_AUTH
)] = { "auth", N_("security/authorization messages") },
90 [FAC_BASE(LOG_SYSLOG
)] = { "syslog", N_("messages generated internally by syslogd") },
91 [FAC_BASE(LOG_LPR
)] = { "lpr", N_("line printer subsystem") },
92 [FAC_BASE(LOG_NEWS
)] = { "news", N_("network news subsystem") },
93 [FAC_BASE(LOG_UUCP
)] = { "uucp", N_("UUCP subsystem") },
94 [FAC_BASE(LOG_CRON
)] = { "cron", N_("clock daemon") },
95 [FAC_BASE(LOG_AUTHPRIV
)] = { "authpriv", N_("security/authorization messages (private)") },
96 [FAC_BASE(LOG_FTP
)] = { "ftp", N_("ftp daemon") },
99 struct dmesg_control
{
100 /* bit arrays -- see include/bitops.h */
101 char levels
[ARRAY_SIZE(level_names
) / NBBY
+ 1];
102 char facilities
[ARRAY_SIZE(facility_names
) / NBBY
+ 1];
104 struct timeval lasttime
; /* last printed timestamp */
105 time_t boot_time
; /* system boot time */
107 unsigned int raw
:1, /* raw mode */
108 fltr_lev
:1, /* filter out by levels[] */
109 fltr_fac
:1, /* filter out by facilities[] */
110 decode
:1, /* use "facility: level: " prefix */
111 notime
:1, /* don't print timestamp */
112 delta
:1, /* show time deltas */
113 ctime
:1; /* show human readable time */
116 struct dmesg_record
{
124 const char *next
; /* buffer with next unparsed record */
125 size_t next_size
; /* size of the next buffer */
128 static void __attribute__((__noreturn__
)) usage(FILE *out
)
134 " %s [options]\n"), program_invocation_short_name
);
138 " -C, --clear clear the kernel ring buffer\n"
139 " -c, --read-clear read and clear all messages\n"
140 " -D, --console-off disable printing messages to console\n"
141 " -d, --show-delta show time delta between printed messages\n"
142 " -E, --console-on enable printing messages to console\n"
143 " -f, --facility=LIST restrict output to defined facilities\n"
144 " -h, --help display this help and exit\n"
145 " -k, --kernel display kernel messages\n"
146 " -l, --level=LIST restrict output to defined levels\n"
147 " -n, --console-level=LEVEL set level of messages printed to console\n"
148 " -r, --raw print the raw message buffer\n"
149 " -s, --buffer-size=SIZE buffer size to query the kernel ring buffer\n"
150 " -T, --ctime show human readable timestamp (could be \n"
151 " inaccurate if you have used SUSPEND/RESUME)\n"
152 " -t, --notime don't print messages timestamp\n"
153 " -u, --userspace display userspace messages\n"
154 " -V, --version output version information and exit\n"
155 " -x, --decode decode facility and level to readable string\n\n"));
157 fprintf(out
, _("Supported log facilities:\n"));
158 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++) {
159 fprintf(stderr
, " %7s - %s\n",
160 facility_names
[i
].name
,
161 _(facility_names
[i
].help
));
164 fprintf(out
, _("\nSupported log levels (priorities):\n"));
165 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++) {
166 fprintf(stderr
, " %7s - %s\n",
168 _(level_names
[i
].help
));
173 exit(out
== stderr
? EXIT_FAILURE
: EXIT_SUCCESS
);
177 * LEVEL ::= <number> | <name>
178 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(level_names)
179 * <name> ::= case-insensitive text
181 static int parse_level(const char *str
, size_t len
)
194 i
= strtol(str
, &end
, 10);
195 if (!errno
&& end
&& end
> str
&& end
- str
== len
&&
196 i
>= 0 && i
< ARRAY_SIZE(level_names
))
199 for (i
= 0; i
< ARRAY_SIZE(level_names
); i
++) {
200 const char *n
= level_names
[i
].name
;
202 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
208 err(EXIT_FAILURE
, _("failed to parse level '%s'"), str
);
210 errx(EXIT_FAILURE
, _("unknown level '%s'"), str
);
215 * FACILITY ::= <number> | <name>
216 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
217 * <name> ::= case-insensitive text
219 static int parse_facility(const char *str
, size_t len
)
232 i
= strtol(str
, &end
, 10);
233 if (!errno
&& end
&& end
> str
&& end
- str
== len
&&
234 i
>= 0 && i
< ARRAY_SIZE(facility_names
))
237 for (i
= 0; i
< ARRAY_SIZE(facility_names
); i
++) {
238 const char *n
= facility_names
[i
].name
;
240 if (strncasecmp(str
, n
, len
) == 0 && *(n
+ len
) == '\0')
246 err(EXIT_FAILURE
, _("failed to parse facility '%s'"), str
);
248 errx(EXIT_FAILURE
, _("unknown facility '%s'"), str
);
253 * Parses numerical prefix used for all messages in kernel ring buffer.
255 * Priorities/facilities are encoded into a single 32-bit quantity, where the
256 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
259 * Note that the number has to end with '>' char.
261 static const char *parse_faclev(const char *str
, int *fac
, int *lev
)
270 num
= strtol(str
, &end
, 10);
272 if (!errno
&& end
&& end
> str
) {
276 if (*lev
> ARRAY_SIZE(level_names
))
278 if (*fac
> ARRAY_SIZE(facility_names
))
280 return end
+ 1; /* skip '<' */
286 static const char *parse_timestamp(const char *str0
, struct timeval
*tv
)
288 const char *str
= str0
;
295 tv
->tv_sec
= strtol(str
, &end
, 10);
297 if (!errno
&& end
&& *end
== '.' && *(end
+ 1)) {
300 tv
->tv_usec
= strtol(str
, &end
, 10);
302 if (errno
|| !end
|| end
== str
|| *end
!= ']')
305 return end
+ 1; /* skip ']' */
309 static double time_diff(struct timeval
*a
, struct timeval
*b
)
311 return (a
->tv_sec
- b
->tv_sec
) + (a
->tv_usec
- b
->tv_usec
) / 1E6
;
314 static int get_buffer_size()
316 int n
= klogctl(SYSLOG_ACTION_SIZE_BUFFER
, NULL
, 0);
318 return n
> 0 ? n
: 0;
321 static time_t get_boot_time(void)
326 if (sysinfo(&info
) != 0)
327 warn(_("sysinfo failed"));
328 else if (gettimeofday(&tv
, NULL
) != 0)
329 warn(_("gettimeofday failed"));
331 return tv
.tv_sec
-= info
.uptime
;
336 * Reads messages from kernel ring buffer
338 static int read_buffer(char **buf
, size_t bufsize
, int clear
)
342 int cmd
= clear
? SYSLOG_ACTION_READ_CLEAR
:
343 SYSLOG_ACTION_READ_ALL
;
347 *buf
= xmalloc(sz
* sizeof(char));
348 rc
= klogctl(cmd
, *buf
, sz
);
352 *buf
= xmalloc(sz
* sizeof(char));
353 rc
= klogctl(SYSLOG_ACTION_READ_ALL
, *buf
, sz
);
354 if (rc
!= sz
|| sz
> (1 << 28))
362 rc
= klogctl(SYSLOG_ACTION_READ_CLEAR
, *buf
, sz
);
368 static int fwrite_hex(const char *buf
, size_t size
, FILE *out
)
372 for (i
= 0; i
< size
; i
++) {
373 int rc
= fprintf(out
, "\\x%02x", buf
[i
]);
381 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
383 static void safe_fwrite(const char *buf
, size_t size
, FILE *out
)
388 memset(&s
, 0, sizeof (s
));
390 for (i
= 0; i
< size
; i
++) {
391 const char *p
= buf
+ i
;
396 size_t len
= mbrtowc(&wc
, p
, size
- i
, &s
);
398 if (len
== 0) /* L'\0' */
401 if (len
== (size_t)-1 || len
== (size_t)-2) { /* invalid sequence */
402 memset(&s
, 0, sizeof (s
));
405 } else if (len
> 1 && !iswprint(wc
)) { /* non-printable multibyte */
410 if (!isprint((unsigned int) *p
) &&
411 !isspace((unsigned int) *p
)) /* non-printable */
415 rc
= fwrite_hex(p
, len
, out
);
417 rc
= fwrite(p
, 1, len
, out
) != len
;
419 err(EXIT_FAILURE
, _("write failed"));
423 static int get_next_record(struct dmesg_control
*ctl
, struct dmesg_record
*rec
)
426 const char *begin
= NULL
;
428 if (!rec
->next
|| !rec
->next_size
)
438 for (i
= 0; i
< rec
->next_size
; i
++) {
439 const char *p
= rec
->next
+ i
;
440 const char *end
= NULL
;
446 if (i
+ 1 == rec
->next_size
) {
450 if (begin
&& !*begin
)
451 begin
= NULL
; /* zero(s) at the end of the buffer? */
455 continue; /* error or empty line? */
458 if (ctl
->fltr_lev
|| ctl
->fltr_fac
|| ctl
->decode
) {
459 begin
= parse_faclev(begin
+ 1, &rec
->facility
,
462 /* ignore facility and level */
463 while (begin
< end
) {
465 if (*(begin
- 1) == '>')
472 return -1; /* error */
474 if (*begin
== '[' && (*(begin
+ 1) == ' ' ||
475 isdigit(*(begin
+ 1)))) {
476 if (ctl
->delta
|| ctl
->ctime
) {
477 begin
= parse_timestamp(begin
+ 1, &rec
->tv
);
478 } else if (ctl
->notime
) {
479 while (begin
< end
) {
481 if (*(begin
- 1) == ']')
487 if (begin
< end
&& *begin
== ' ')
491 rec
->mesg_size
= end
- begin
;
493 rec
->next_size
-= end
- rec
->next
;
494 rec
->next
= rec
->next_size
> 0 ? end
+ 1 : NULL
;
502 static int accept_record(struct dmesg_control
*ctl
, struct dmesg_record
*rec
)
504 if (ctl
->fltr_lev
&& (rec
->facility
< 0 ||
505 !isset(ctl
->levels
, rec
->level
)))
508 if (ctl
->fltr_fac
&& (rec
->facility
< 0 ||
509 !isset(ctl
->facilities
, rec
->facility
)))
516 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
517 * to 'levels' and 'facilities' bitarrays.
519 static void print_buffer(const char *buf
, size_t size
,
520 struct dmesg_control
*ctl
)
522 struct dmesg_record rec
= { .next
= buf
, .next_size
= size
};
526 /* print whole buffer */
527 safe_fwrite(buf
, size
, stdout
);
528 if (buf
[size
- 1] != '\n')
533 while (get_next_record(ctl
, &rec
) == 0) {
537 if (!accept_record(ctl
, &rec
))
540 if (ctl
->decode
&& rec
.level
>= 0 && rec
.facility
>= 0)
541 printf("%-6s:%-6s: ", facility_names
[rec
.facility
].name
,
542 level_names
[rec
.level
].name
);
546 time_t t
= ctl
->boot_time
+ rec
.tv
.tv_sec
;
547 if (strftime(tbuf
, sizeof(tbuf
), "%a %b %e %H:%M:%S %Y",
554 if (timerisset(&ctl
->lasttime
))
555 delta
= time_diff(&rec
.tv
, &ctl
->lasttime
);
556 ctl
->lasttime
= rec
.tv
;
558 if (ctl
->ctime
&& *tbuf
)
559 printf("[%s ", tbuf
);
560 else if (ctl
->notime
)
563 printf("[%5d.%06d ", (int) rec
.tv
.tv_sec
,
564 (int) rec
.tv
.tv_usec
);
565 printf("<%12.06f>] ", delta
);
566 } else if (ctl
->ctime
&& *tbuf
) {
567 printf("[%s] ", tbuf
);
570 safe_fwrite(rec
.mesg
, rec
.mesg_size
, stdout
);
572 if (*(rec
.mesg
+ rec
.mesg_size
- 1) != '\n')
577 int main(int argc
, char *argv
[])
583 int console_level
= 0;
585 static struct dmesg_control ctl
;
587 static const struct option longopts
[] = {
588 { "buffer-size", required_argument
, NULL
, 's' },
589 { "clear", no_argument
, NULL
, 'C' },
590 { "console-level", required_argument
, NULL
, 'n' },
591 { "console-off", no_argument
, NULL
, 'D' },
592 { "console-on", no_argument
, NULL
, 'E' },
593 { "decode", no_argument
, NULL
, 'x' },
594 { "facility", required_argument
, NULL
, 'f' },
595 { "help", no_argument
, NULL
, 'h' },
596 { "kernel", no_argument
, NULL
, 'k' },
597 { "level", required_argument
, NULL
, 'l' },
598 { "raw", no_argument
, NULL
, 'r' },
599 { "read-clear", no_argument
, NULL
, 'c' },
600 { "show-delta", no_argument
, NULL
, 'd' },
601 { "ctime", no_argument
, NULL
, 'T' },
602 { "notime", no_argument
, NULL
, 't' },
603 { "userspace", no_argument
, NULL
, 'u' },
604 { "version", no_argument
, NULL
, 'V' },
608 setlocale(LC_ALL
, "");
609 bindtextdomain(PACKAGE
, LOCALEDIR
);
612 while ((c
= getopt_long(argc
, argv
, "CcDdEf:hkl:n:rs:TtuVx",
613 longopts
, NULL
)) != -1) {
615 if (cmd
!= -1 && strchr("CcnDE", c
))
616 errx(EXIT_FAILURE
, _("clear, read-clear, console-level, "
617 "console-on, and console-off options are mutually "
622 cmd
= SYSLOG_ACTION_CLEAR
;
625 cmd
= SYSLOG_ACTION_READ_CLEAR
;
628 cmd
= SYSLOG_ACTION_CONSOLE_OFF
;
634 cmd
= SYSLOG_ACTION_CONSOLE_ON
;
638 if (string_to_bitarray(optarg
,
639 ctl
.facilities
, parse_facility
) < 0)
647 setbit(ctl
.facilities
, FAC_BASE(LOG_KERN
));
651 if (string_to_bitarray(optarg
,
652 ctl
.levels
, parse_level
) < 0)
656 cmd
= SYSLOG_ACTION_CONSOLE_LEVEL
;
657 console_level
= parse_level(optarg
, 0);
663 bufsize
= strtol_or_err(optarg
,
664 _("failed to parse buffer size"));
669 ctl
.boot_time
= get_boot_time();
678 for (n
= 1; n
< ARRAY_SIZE(facility_names
); n
++)
679 setbit(ctl
.facilities
, n
);
682 printf(_("%s from %s\n"), program_invocation_short_name
,
701 cmd
= SYSLOG_ACTION_READ_ALL
; /* default */
703 if (ctl
.raw
&& (ctl
.fltr_lev
|| ctl
.fltr_fac
|| ctl
.delta
||
704 ctl
.notime
|| ctl
.ctime
|| ctl
.decode
))
705 errx(EXIT_FAILURE
, _("--raw can't be used together with level, "
706 "facility, decode, delta, ctime or notime options"));
708 if (ctl
.notime
&& ctl
.ctime
)
709 errx(EXIT_FAILURE
, _("--notime can't be used together with ctime "));
712 case SYSLOG_ACTION_READ_ALL
:
713 case SYSLOG_ACTION_READ_CLEAR
:
715 bufsize
= get_buffer_size();
716 n
= read_buffer(&buf
, bufsize
, cmd
== SYSLOG_ACTION_READ_CLEAR
);
718 print_buffer(buf
, n
, &ctl
);
721 case SYSLOG_ACTION_CLEAR
:
722 case SYSLOG_ACTION_CONSOLE_OFF
:
723 case SYSLOG_ACTION_CONSOLE_ON
:
724 n
= klogctl(cmd
, NULL
, 0);
726 case SYSLOG_ACTION_CONSOLE_LEVEL
:
727 n
= klogctl(cmd
, NULL
, console_level
);
730 errx(EXIT_FAILURE
, _("unsupported command"));
735 err(EXIT_FAILURE
, _("klogctl failed"));