]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/dmesg.c
Merge branch 'pg-manual-page-long-options' of https://github.com/jaalto/util-linux
[thirdparty/util-linux.git] / sys-utils / dmesg.c
1 /*
2 * dmesg.c -- Print out the contents of the kernel ring buffer
3 *
4 * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu>
5 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
6 *
7 * This program comes with ABSOLUTELY NO WARRANTY.
8 */
9 #include <linux/unistd.h>
10 #include <stdio.h>
11 #include <getopt.h>
12 #include <stdlib.h>
13 #include <sys/klog.h>
14 #include <sys/syslog.h>
15 #include <sys/time.h>
16 #include <sys/sysinfo.h>
17 #include <ctype.h>
18 #include <time.h>
19 #include <sys/mman.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <unistd.h>
23 #include <fcntl.h>
24
25 #include "c.h"
26 #include "colors.h"
27 #include "nls.h"
28 #include "strutils.h"
29 #include "xalloc.h"
30 #include "widechar.h"
31 #include "all-io.h"
32 #include "bitops.h"
33 #include "closestream.h"
34 #include "optutils.h"
35 #include "mangle.h"
36 #include "pager.h"
37
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
60
61 /*
62 * Colors
63 */
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
72
73 /*
74 * Priority and facility names
75 */
76 struct dmesg_name {
77 const char *name;
78 const char *help;
79 };
80
81 /*
82 * Priority names -- based on sys/syslog.h
83 */
84 static const struct dmesg_name level_names[] =
85 {
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") }
94 };
95
96 /*
97 * sys/syslog.h uses (f << 3) for all facility codes.
98 * We want to use the codes as array idexes, so shift back...
99 *
100 * Note that libc LOG_FAC() macro returns the base codes, not the
101 * shifted code :-)
102 */
103 #define FAC_BASE(f) ((f) >> 3)
104
105 static const struct dmesg_name facility_names[] =
106 {
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") },
119 };
120
121 /* supported methods to read message buffer
122 */
123 enum {
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) */
127 };
128
129 enum {
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 */
138 };
139 #define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f))
140
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];
145
146 struct timeval lasttime; /* last printed timestamp */
147 struct tm lasttm; /* last localtime */
148 struct timeval boot_time; /* system boot time */
149
150 int action; /* SYSLOG_ACTION_* */
151 int method; /* DMESG_METHOD_* */
152
153 size_t bufsize; /* size of syslog buffer */
154
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 */
158
159 /*
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).
163 */
164 char *filename;
165 char *mmap_buff;
166 size_t pagesize;
167 unsigned int time_fmt; /* time format */
168
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 */
176 };
177
178 struct dmesg_record {
179 const char *mesg;
180 size_t mesg_size;
181
182 int level;
183 int facility;
184 struct timeval tv;
185
186 const char *next; /* buffer with next unparsed record */
187 size_t next_size; /* size of the next buffer */
188 };
189
190 #define INIT_DMESG_RECORD(_r) do { \
191 (_r)->mesg = NULL; \
192 (_r)->mesg_size = 0; \
193 (_r)->facility = -1; \
194 (_r)->level = -1; \
195 (_r)->tv.tv_sec = 0; \
196 (_r)->tv.tv_usec = 0; \
197 } while (0)
198
199 static int read_kmsg(struct dmesg_control *ctl);
200
201 static int set_level_color(int log_level, const char *mesg, size_t mesgsz)
202 {
203 switch (log_level) {
204 case LOG_ALERT:
205 color_enable(DMESG_COLOR_ALERT);
206 return 0;
207 case LOG_CRIT:
208 color_enable(DMESG_COLOR_CRIT);
209 return 0;
210 case LOG_ERR:
211 color_enable(DMESG_COLOR_ERR);
212 return 0;
213 case LOG_WARNING:
214 color_enable(DMESG_COLOR_WARN);
215 return 0;
216 default:
217 break;
218 }
219
220 /* well, sometimes the messges contains important keywords, but in
221 * non-warning/error messages
222 */
223 if (memmem(mesg, mesgsz, "segfault at", 11)) {
224 color_enable(DMESG_COLOR_SEGFAULT);
225 return 0;
226 }
227
228 return 1;
229 }
230
231 static void __attribute__((__noreturn__)) usage(FILE *out)
232 {
233 size_t i;
234
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));
271
272 fputs(_("\nSupported log levels (priorities):\n"), out);
273 for (i = 0; i < ARRAY_SIZE(level_names); i++)
274 fprintf(out, " %7s - %s\n",
275 level_names[i].name,
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);
280 }
281
282 /*
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
287 *
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".
290 *
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>.
294 */
295 static int parse_level(const char *str, size_t len)
296 {
297 int offset = 0;
298
299 if (!str)
300 return -1;
301 if (!len) {
302 len = strlen(str);
303 offset = 1;
304 }
305 errno = 0;
306
307 if (isdigit(*str)) {
308 char *end = NULL;
309 long x = strtol(str, &end, 10) - offset;
310
311 if (!errno && end && end > str && (size_t) (end - str) == len &&
312 x >= 0 && (size_t) x < ARRAY_SIZE(level_names))
313 return x + offset;
314 } else {
315 size_t i;
316
317 for (i = 0; i < ARRAY_SIZE(level_names); i++) {
318 const char *n = level_names[i].name;
319
320 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
321 return i + offset;
322 }
323 }
324
325 if (errno)
326 err(EXIT_FAILURE, _("failed to parse level '%s'"), str);
327
328 errx(EXIT_FAILURE, _("unknown level '%s'"), str);
329 return -1;
330 }
331
332 /*
333 * FACILITY ::= <number> | <name>
334 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
335 * <name> ::= case-insensitive text
336 */
337 static int parse_facility(const char *str, size_t len)
338 {
339 if (!str)
340 return -1;
341 if (!len)
342 len = strlen(str);
343 errno = 0;
344
345 if (isdigit(*str)) {
346 char *end = NULL;
347 long x = strtol(str, &end, 10);
348
349 if (!errno && end && end > str && (size_t) (end - str) == len &&
350 x >= 0 && (size_t) x < ARRAY_SIZE(facility_names))
351 return x;
352 } else {
353 size_t i;
354
355 for (i = 0; i < ARRAY_SIZE(facility_names); i++) {
356 const char *n = facility_names[i].name;
357
358 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
359 return i;
360 }
361 }
362
363 if (errno)
364 err(EXIT_FAILURE, _("failed to parse facility '%s'"), str);
365
366 errx(EXIT_FAILURE, _("unknown facility '%s'"), str);
367 return -1;
368 }
369
370 /*
371 * Parses numerical prefix used for all messages in kernel ring buffer.
372 *
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
375 * (0-big number).
376 *
377 * Note that the number has to end with '>' or ',' char.
378 */
379 static const char *parse_faclev(const char *str, int *fac, int *lev)
380 {
381 long num;
382 char *end = NULL;
383
384 if (!str)
385 return str;
386
387 errno = 0;
388 num = strtol(str, &end, 10);
389
390 if (!errno && end && end > str) {
391 *fac = LOG_FAC(num);
392 *lev = LOG_PRI(num);
393
394 if (*lev < 0 || (size_t) *lev > ARRAY_SIZE(level_names))
395 *lev = -1;
396 if (*fac < 0 || (size_t) *fac > ARRAY_SIZE(facility_names))
397 *fac = -1;
398 return end + 1; /* skip '<' or ',' */
399 }
400
401 return str;
402 }
403
404 /*
405 * Parses timestamp from syslog message prefix, expected format:
406 *
407 * seconds.microseconds]
408 *
409 * the ']' is the timestamp field terminator.
410 */
411 static const char *parse_syslog_timestamp(const char *str0, struct timeval *tv)
412 {
413 const char *str = str0;
414 char *end = NULL;
415
416 if (!str0)
417 return str0;
418
419 errno = 0;
420 tv->tv_sec = strtol(str, &end, 10);
421
422 if (!errno && end && *end == '.' && *(end + 1)) {
423 str = end + 1;
424 end = NULL;
425 tv->tv_usec = strtol(str, &end, 10);
426 }
427 if (errno || !end || end == str || *end != ']')
428 return str0;
429
430 return end + 1; /* skip ']' */
431 }
432
433 /*
434 * Parses timestamp from /dev/kmsg, expected formats:
435 *
436 * microseconds,
437 * microseconds;
438 *
439 * the ',' is fields separators and ';' items terminator (for the last item)
440 */
441 static const char *parse_kmsg_timestamp(const char *str0, struct timeval *tv)
442 {
443 const char *str = str0;
444 char *end = NULL;
445 uint64_t usec;
446
447 if (!str0)
448 return str0;
449
450 errno = 0;
451 usec = strtoumax(str, &end, 10);
452
453 if (!errno && end && (*end == ';' || *end == ',')) {
454 tv->tv_usec = usec % 1000000;
455 tv->tv_sec = usec / 1000000;
456 } else
457 return str0;
458
459 return end + 1; /* skip separator */
460 }
461
462
463 static double time_diff(struct timeval *a, struct timeval *b)
464 {
465 return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
466 }
467
468 static int get_syslog_buffer_size(void)
469 {
470 int n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
471
472 return n > 0 ? n : 0;
473 }
474
475 static int get_boot_time(struct timeval *boot_time)
476 {
477 struct timespec hires_uptime;
478 struct timeval lores_uptime, now;
479 struct sysinfo info;
480
481 if (gettimeofday(&now, NULL) != 0) {
482 warn(_("gettimeofday failed"));
483 return -errno;
484 }
485
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);
490 return 0;
491 }
492 #endif
493 /* fallback */
494 if (sysinfo(&info) != 0)
495 warn(_("sysinfo failed"));
496
497 boot_time->tv_sec = now.tv_sec - info.uptime;
498 boot_time->tv_usec = 0;
499 return 0;
500 }
501
502 /*
503 * Reads messages from regular file by mmap
504 */
505 static ssize_t mmap_file_buffer(struct dmesg_control *ctl, char **buf)
506 {
507 struct stat st;
508 int fd;
509
510 if (!ctl->filename)
511 return -1;
512
513 fd = open(ctl->filename, O_RDONLY);
514 if (fd < 0)
515 err(EXIT_FAILURE, _("cannot open %s"), ctl->filename);
516 if (fstat(fd, &st))
517 err(EXIT_FAILURE, _("stat failed %s"), ctl->filename);
518
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();
524 close(fd);
525
526 return st.st_size;
527 }
528
529 /*
530 * Reads messages from kernel ring buffer by klogctl()
531 */
532 static ssize_t read_syslog_buffer(struct dmesg_control *ctl, char **buf)
533 {
534 size_t sz;
535 int rc = -1;
536
537 if (ctl->bufsize) {
538 sz = ctl->bufsize + 8;
539 *buf = xmalloc(sz * sizeof(char));
540 rc = klogctl(ctl->action, *buf, sz);
541 } else {
542 sz = 16392;
543 while (1) {
544 *buf = xmalloc(sz * sizeof(char));
545 rc = klogctl(SYSLOG_ACTION_READ_ALL, *buf, sz);
546 if (rc < 0)
547 break;
548 if ((size_t) rc != sz || sz > (1 << 28))
549 break;
550 free(*buf);
551 *buf = NULL;
552 sz *= 4;
553 }
554
555 if (rc > 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR)
556 rc = klogctl(SYSLOG_ACTION_READ_CLEAR, *buf, sz);
557 }
558
559 return rc;
560 }
561
562 /*
563 * Top level function to read messages
564 */
565 static ssize_t read_buffer(struct dmesg_control *ctl, char **buf)
566 {
567 ssize_t n = -1;
568
569 switch (ctl->method) {
570 case DMESG_METHOD_MMAP:
571 n = mmap_file_buffer(ctl, buf);
572 break;
573 case DMESG_METHOD_SYSLOG:
574 if (!ctl->bufsize)
575 ctl->bufsize = get_syslog_buffer_size();
576
577 n = read_syslog_buffer(ctl, buf);
578 break;
579 case DMESG_METHOD_KMSG:
580 /*
581 * Since kernel 3.5.0
582 */
583 n = read_kmsg(ctl);
584 if (n == 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR)
585 n = klogctl(SYSLOG_ACTION_CLEAR, NULL, 0);
586 break;
587 }
588
589 return n;
590 }
591
592 static int fwrite_hex(const char *buf, size_t size, FILE *out)
593 {
594 size_t i;
595
596 for (i = 0; i < size; i++) {
597 int rc = fprintf(out, "\\x%02x", buf[i]);
598 if (rc < 0)
599 return rc;
600 }
601 return 0;
602 }
603
604 /*
605 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
606 */
607 static void safe_fwrite(const char *buf, size_t size, FILE *out)
608 {
609 size_t i;
610 #ifdef HAVE_WIDECHAR
611 mbstate_t s;
612 memset(&s, 0, sizeof (s));
613 #endif
614 for (i = 0; i < size; i++) {
615 const char *p = buf + i;
616 int rc, hex = 0;
617 size_t len = 1;
618
619 #ifdef HAVE_WIDECHAR
620 wchar_t wc;
621 len = mbrtowc(&wc, p, size - i, &s);
622
623 if (len == 0) /* L'\0' */
624 return;
625
626 if (len == (size_t)-1 || len == (size_t)-2) { /* invalid sequence */
627 memset(&s, 0, sizeof (s));
628 len = hex = 1;
629 } else if (len > 1 && !iswprint(wc)) { /* non-printable multibyte */
630 hex = 1;
631 }
632 i += len - 1;
633 #else
634 if (!isprint((unsigned int) *p) &&
635 !isspace((unsigned int) *p)) /* non-printable */
636 hex = 1;
637 #endif
638 if (hex)
639 rc = fwrite_hex(p, len, out);
640 else
641 rc = fwrite(p, 1, len, out) != len;
642 if (rc != 0) {
643 if (errno != EPIPE)
644 err(EXIT_FAILURE, _("write failed"));
645 exit(EXIT_SUCCESS);
646 }
647 }
648 }
649
650 static const char *skip_item(const char *begin, const char *end, const char *sep)
651 {
652 while (begin < end) {
653 int c = *begin++;
654
655 if (c == '\0' || strchr(sep, c))
656 break;
657 }
658
659 return begin;
660 }
661
662 /*
663 * Parses one record from syslog(2) buffer
664 */
665 static int get_next_syslog_record(struct dmesg_control *ctl,
666 struct dmesg_record *rec)
667 {
668 size_t i;
669 const char *begin = NULL;
670
671 if (ctl->method != DMESG_METHOD_MMAP &&
672 ctl->method != DMESG_METHOD_SYSLOG)
673 return -1;
674
675 if (!rec->next || !rec->next_size)
676 return 1;
677
678 INIT_DMESG_RECORD(rec);
679
680 /*
681 * Unmap already printed file data from memory
682 */
683 if (ctl->mmap_buff && (size_t) (rec->next - ctl->mmap_buff) > ctl->pagesize) {
684 void *x = ctl->mmap_buff;
685
686 ctl->mmap_buff += ctl->pagesize;
687 munmap(x, ctl->pagesize);
688 }
689
690 for (i = 0; i < rec->next_size; i++) {
691 const char *p = rec->next + i;
692 const char *end = NULL;
693
694 if (!begin)
695 begin = p;
696 if (i + 1 == rec->next_size) {
697 end = p + 1;
698 i++;
699 } else if (*p == '\n' && *(p + 1) == '<')
700 end = p;
701
702 if (begin && !*begin)
703 begin = NULL; /* zero(s) at the end of the buffer? */
704 if (!begin || !end)
705 continue;
706 if (end <= begin)
707 continue; /* error or empty line? */
708
709 if (*begin == '<') {
710 if (ctl->fltr_lev || ctl->fltr_fac || ctl->decode || ctl->color)
711 begin = parse_faclev(begin + 1, &rec->facility,
712 &rec->level);
713 else
714 begin = skip_item(begin, end, ">");
715 }
716
717 if (*begin == '[' && (*(begin + 1) == ' ' ||
718 isdigit(*(begin + 1)))) {
719
720 if (!is_timefmt(ctl, NONE))
721 begin = parse_syslog_timestamp(begin + 1, &rec->tv);
722 else
723 begin = skip_item(begin, end, "]");
724
725 if (begin < end && *begin == ' ')
726 begin++;
727 }
728
729 rec->mesg = begin;
730 rec->mesg_size = end - begin;
731
732 rec->next_size -= end - rec->next;
733 rec->next = rec->next_size > 0 ? end + 1 : NULL;
734 if (rec->next_size > 0)
735 rec->next_size--;
736
737 return 0;
738 }
739
740 return 1;
741 }
742
743 static int accept_record(struct dmesg_control *ctl, struct dmesg_record *rec)
744 {
745 if (ctl->fltr_lev && (rec->facility < 0 ||
746 !isset(ctl->levels, rec->level)))
747 return 0;
748
749 if (ctl->fltr_fac && (rec->facility < 0 ||
750 !isset(ctl->facilities, rec->facility)))
751 return 0;
752
753 return 1;
754 }
755
756 static void raw_print(struct dmesg_control *ctl, const char *buf, size_t size)
757 {
758 int lastc = '\n';
759
760 if (!ctl->mmap_buff) {
761 /*
762 * Print whole ring buffer
763 */
764 safe_fwrite(buf, size, stdout);
765 lastc = buf[size - 1];
766 } else {
767 /*
768 * Print file in small chunks to save memory
769 */
770 while (size) {
771 size_t sz = size > ctl->pagesize ? ctl->pagesize : size;
772 char *x = ctl->mmap_buff;
773
774 safe_fwrite(x, sz, stdout);
775 lastc = x[sz - 1];
776 size -= sz;
777 ctl->mmap_buff += sz;
778 munmap(x, sz);
779 }
780 }
781
782 if (lastc != '\n')
783 putchar('\n');
784 }
785
786 static struct tm *record_localtime(struct dmesg_control *ctl,
787 struct dmesg_record *rec,
788 struct tm *tm)
789 {
790 time_t t = ctl->boot_time.tv_sec + rec->tv.tv_sec;
791 return localtime_r(&t, tm);
792 }
793
794 static char *record_ctime(struct dmesg_control *ctl,
795 struct dmesg_record *rec,
796 char *buf, size_t bufsiz)
797 {
798 struct tm tm;
799
800 record_localtime(ctl, rec, &tm);
801
802 if (strftime(buf, bufsiz, "%a %b %e %H:%M:%S %Y", &tm) == 0)
803 *buf = '\0';
804 return buf;
805 }
806
807 static char *short_ctime(struct tm *tm, char *buf, size_t bufsiz)
808 {
809 if (strftime(buf, bufsiz, "%b%e %H:%M", tm) == 0)
810 *buf = '\0';
811 return buf;
812 }
813
814 static char *iso_8601_time(struct dmesg_control *ctl, struct dmesg_record *rec,
815 char *buf, size_t bufsiz)
816 {
817 struct tm tm;
818 size_t len;
819 record_localtime(ctl, rec, &tm);
820 if (strftime(buf, bufsiz, "%Y-%m-%dT%H:%M:%S", &tm) == 0) {
821 *buf = '\0';
822 return buf;
823 }
824 len = strlen(buf);
825 snprintf(buf + len, bufsiz - len, ",%06d", (int)rec->tv.tv_usec);
826 len = strlen(buf);
827 strftime(buf + len, bufsiz - len, "%z", &tm);
828 return buf;
829 }
830
831 static double record_count_delta(struct dmesg_control *ctl,
832 struct dmesg_record *rec)
833 {
834 double delta = 0;
835
836 if (timerisset(&ctl->lasttime))
837 delta = time_diff(&rec->tv, &ctl->lasttime);
838
839 ctl->lasttime = rec->tv;
840 return delta;
841 }
842
843 static const char *get_subsys_delimiter(const char *mesg, size_t mesg_size)
844 {
845 const char *p = mesg;
846 size_t sz = mesg_size;
847
848 while (sz > 0) {
849 const char *d = strnchr(p, sz, ':');
850 if (!d)
851 return NULL;
852 sz -= d - p;
853 if (sz) {
854 if (isblank(*(d + 1)))
855 return d;
856 p = d + 1;
857 }
858 }
859 return NULL;
860 }
861
862 static void print_record(struct dmesg_control *ctl,
863 struct dmesg_record *rec)
864 {
865 char buf[256];
866 int has_color = 0;
867 const char *mesg;
868 size_t mesg_size;
869
870 if (!accept_record(ctl, rec))
871 return;
872
873 if (!rec->mesg_size) {
874 putchar('\n');
875 return;
876 }
877
878 /*
879 * compose syslog(2) compatible raw output -- used for /dev/kmsg for
880 * backward compatibility with syslog(2) buffers only
881 */
882 if (ctl->raw) {
883 printf("<%d>[%5d.%06d] ",
884 LOG_MAKEPRI(rec->facility, rec->level),
885 (int) rec->tv.tv_sec,
886 (int) rec->tv.tv_usec);
887
888 goto mesg;
889 }
890
891 /*
892 * facility : priority :
893 */
894 if (ctl->decode &&
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);
899
900 if (ctl->color)
901 color_enable(DMESG_COLOR_TIME);
902
903 switch (ctl->time_fmt) {
904 double delta;
905 struct tm cur;
906 case DMESG_TIMEFTM_NONE:
907 break;
908 case DMESG_TIMEFTM_CTIME:
909 printf("[%s] ", record_ctime(ctl, rec, buf, sizeof(buf)));
910 break;
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));
915 break;
916 case DMESG_TIMEFTM_DELTA:
917 printf("[<%12.06f>] ", record_count_delta(ctl, rec));
918 break;
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)));
926 } else {
927 if (delta < 10)
928 printf("[ %+8.06f] ", delta);
929 else
930 printf("[ %+9.06f] ", delta);
931 }
932 ctl->lasttm = cur;
933 break;
934 case DMESG_TIMEFTM_TIME:
935 printf("[%5d.%06d] ", (int)rec->tv.tv_sec, (int)rec->tv.tv_usec);
936 break;
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));
940 break;
941 case DMESG_TIMEFTM_ISO8601:
942 printf("%s ", iso_8601_time(ctl, rec, buf, sizeof(buf)));
943 break;
944 default:
945 abort();
946 }
947
948 if (ctl->color)
949 color_disable();
950
951 mesg:
952 mesg = rec->mesg;
953 mesg_size = rec->mesg_size;
954
955 /* Colorize output */
956 if (ctl->color) {
957 /* subsystem prefix */
958 const char *subsys = get_subsys_delimiter(mesg, mesg_size);
959 if (subsys) {
960 color_enable(DMESG_COLOR_SUBSYS);
961 safe_fwrite(mesg, subsys - mesg, stdout);
962 color_disable();
963
964 mesg_size -= subsys - mesg;
965 mesg = subsys;
966 }
967 /* error, alert .. etc. colors */
968 has_color = set_level_color(rec->level, mesg, mesg_size) == 0;
969 safe_fwrite(mesg, mesg_size, stdout);
970 if (has_color)
971 color_disable();
972 } else
973 safe_fwrite(mesg, mesg_size, stdout);
974
975 if (*(mesg + mesg_size - 1) != '\n')
976 putchar('\n');
977 }
978
979 /*
980 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
981 * to 'levels' and 'facilities' bitarrays.
982 */
983 static void print_buffer(struct dmesg_control *ctl,
984 const char *buf, size_t size)
985 {
986 struct dmesg_record rec = { .next = buf, .next_size = size };
987
988 if (ctl->raw) {
989 raw_print(ctl, buf, size);
990 return;
991 }
992
993 while (get_next_syslog_record(ctl, &rec) == 0)
994 print_record(ctl, &rec);
995 }
996
997 static ssize_t read_kmsg_one(struct dmesg_control *ctl)
998 {
999 ssize_t size;
1000
1001 /* kmsg returns EPIPE if record was modified while reading */
1002 do {
1003 size = read(ctl->kmsg, ctl->kmsg_buf,
1004 sizeof(ctl->kmsg_buf) - 1);
1005 } while (size < 0 && errno == EPIPE);
1006
1007 return size;
1008 }
1009
1010 static int init_kmsg(struct dmesg_control *ctl)
1011 {
1012 int mode = O_RDONLY;
1013
1014 if (!ctl->follow)
1015 mode |= O_NONBLOCK;
1016 else
1017 setlinebuf(stdout);
1018
1019 ctl->kmsg = open("/dev/kmsg", mode);
1020 if (ctl->kmsg < 0)
1021 return -1;
1022
1023 /*
1024 * Seek after the last record available at the time
1025 * the last SYSLOG_ACTION_CLEAR was issued.
1026 *
1027 * ... otherwise SYSLOG_ACTION_CLEAR will have no effect for kmsg.
1028 */
1029 lseek(ctl->kmsg, 0, SEEK_DATA);
1030
1031 /*
1032 * Old kernels (<3.5) allow to successfully open /dev/kmsg for
1033 * read-only, but read() returns -EINVAL :-(((
1034 *
1035 * Let's try to read the first record. The record is later processed in
1036 * read_kmsg().
1037 */
1038 ctl->kmsg_first_read = read_kmsg_one(ctl);
1039 if (ctl->kmsg_first_read < 0) {
1040 close(ctl->kmsg);
1041 ctl->kmsg = -1;
1042 return -1;
1043 }
1044
1045 return 0;
1046 }
1047
1048 /*
1049 * /dev/kmsg record format:
1050 *
1051 * faclev,seqnum,timestamp[optional, ...];messgage\n
1052 * TAGNAME=value
1053 * ...
1054 *
1055 * - fields are separated by ','
1056 * - last field is terminated by ';'
1057 *
1058 */
1059 #define LAST_KMSG_FIELD(s) (!s || !*s || *(s - 1) == ';')
1060
1061 static int parse_kmsg_record(struct dmesg_control *ctl,
1062 struct dmesg_record *rec,
1063 char *buf,
1064 size_t sz)
1065 {
1066 const char *p = buf, *end;
1067
1068 if (sz == 0 || !buf || !*buf)
1069 return -1;
1070
1071 end = buf + (sz - 1);
1072 INIT_DMESG_RECORD(rec);
1073
1074 while (p < end && isspace(*p))
1075 p++;
1076
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);
1081 else
1082 p = skip_item(p, end, ",");
1083 if (LAST_KMSG_FIELD(p))
1084 goto mesg;
1085
1086 /* B) sequence number */
1087 p = skip_item(p, end, ",;");
1088 if (LAST_KMSG_FIELD(p))
1089 goto mesg;
1090
1091 /* C) timestamp */
1092 if (is_timefmt(ctl, NONE))
1093 p = skip_item(p, end, ",;");
1094 else
1095 p = parse_kmsg_timestamp(p, &rec->tv);
1096 if (LAST_KMSG_FIELD(p))
1097 goto mesg;
1098
1099 /* D) optional fields (ignore) */
1100 p = skip_item(p, end, ";");
1101 if (LAST_KMSG_FIELD(p))
1102 goto mesg;
1103
1104 mesg:
1105 /* E) message text */
1106 rec->mesg = p;
1107 p = skip_item(p, end, "\n");
1108
1109 if (!p)
1110 return -1;
1111
1112 rec->mesg_size = p - rec->mesg;
1113
1114 /*
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.
1118 */
1119 unhexmangle_to_buffer(rec->mesg, (char *) rec->mesg, rec->mesg_size + 1);
1120
1121 /* F) message tags (ignore) */
1122
1123 return 0;
1124 }
1125
1126 /*
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.
1129 *
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.
1132 *
1133 * Returns 0 on success, -1 on error.
1134 */
1135 static int read_kmsg(struct dmesg_control *ctl)
1136 {
1137 struct dmesg_record rec;
1138 ssize_t sz;
1139
1140 if (ctl->method != DMESG_METHOD_KMSG || ctl->kmsg < 0)
1141 return -1;
1142
1143 /*
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;
1147 */
1148 sz = ctl->kmsg_first_read;
1149
1150 while (sz > 0) {
1151 *(ctl->kmsg_buf + sz) = '\0'; /* for debug messages */
1152
1153 if (parse_kmsg_record(ctl, &rec,
1154 ctl->kmsg_buf, (size_t) sz) == 0)
1155 print_record(ctl, &rec);
1156
1157 sz = read_kmsg_one(ctl);
1158 }
1159
1160 return 0;
1161 }
1162
1163 static int which_time_format(const char *optarg)
1164 {
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);
1176 }
1177
1178 int main(int argc, char *argv[])
1179 {
1180 char *buf = NULL;
1181 int c, nopager = 0;
1182 int console_level = 0;
1183 int klog_rc = 0;
1184 int delta = 0;
1185 ssize_t n;
1186 static struct dmesg_control ctl = {
1187 .filename = NULL,
1188 .action = SYSLOG_ACTION_READ_ALL,
1189 .method = DMESG_METHOD_KMSG,
1190 .kmsg = -1,
1191 .time_fmt = DMESG_TIMEFTM_TIME,
1192 };
1193 int colormode = UL_COLORMODE_UNDEF;
1194 enum {
1195 OPT_TIME_FORMAT = CHAR_MAX + 1,
1196 };
1197
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 }
1225 };
1226
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 */
1237 { 0 }
1238 };
1239 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1240
1241 setlocale(LC_ALL, "");
1242 bindtextdomain(PACKAGE, LOCALEDIR);
1243 textdomain(PACKAGE);
1244 atexit(close_stdout);
1245
1246 while ((c = getopt_long(argc, argv, "CcDdEeF:f:HhkL::l:n:iPrSs:TtuVwx",
1247 longopts, NULL)) != -1) {
1248
1249 err_exclusive_options(c, longopts, excl, excl_st);
1250
1251 switch (c) {
1252 case 'C':
1253 ctl.action = SYSLOG_ACTION_CLEAR;
1254 break;
1255 case 'c':
1256 ctl.action = SYSLOG_ACTION_READ_CLEAR;
1257 break;
1258 case 'D':
1259 ctl.action = SYSLOG_ACTION_CONSOLE_OFF;
1260 break;
1261 case 'd':
1262 delta = 1;
1263 break;
1264 case 'E':
1265 ctl.action = SYSLOG_ACTION_CONSOLE_ON;
1266 break;
1267 case 'e':
1268 ctl.time_fmt = DMESG_TIMEFTM_RELTIME;
1269 break;
1270 case 'F':
1271 ctl.filename = optarg;
1272 ctl.method = DMESG_METHOD_MMAP;
1273 break;
1274 case 'f':
1275 ctl.fltr_fac = 1;
1276 if (string_to_bitarray(optarg,
1277 ctl.facilities, parse_facility) < 0)
1278 return EXIT_FAILURE;
1279 break;
1280 case 'H':
1281 ctl.time_fmt = DMESG_TIMEFTM_RELTIME;
1282 colormode = UL_COLORMODE_AUTO;
1283 ctl.pager = 1;
1284 break;
1285 case 'h':
1286 usage(stdout);
1287 break;
1288 case 'k':
1289 ctl.fltr_fac = 1;
1290 setbit(ctl.facilities, FAC_BASE(LOG_KERN));
1291 break;
1292 case 'L':
1293 colormode = UL_COLORMODE_AUTO;
1294 if (optarg)
1295 colormode = colormode_or_err(optarg,
1296 _("unsupported color mode"));
1297 break;
1298 case 'l':
1299 ctl.fltr_lev= 1;
1300 if (string_to_bitarray(optarg,
1301 ctl.levels, parse_level) < 0)
1302 return EXIT_FAILURE;
1303 break;
1304 case 'n':
1305 ctl.action = SYSLOG_ACTION_CONSOLE_LEVEL;
1306 console_level = parse_level(optarg, 0);
1307 break;
1308 case 'P':
1309 nopager = 1;
1310 break;
1311 case 'r':
1312 ctl.raw = 1;
1313 break;
1314 case 'S':
1315 ctl.method = DMESG_METHOD_SYSLOG;
1316 break;
1317 case 's':
1318 ctl.bufsize = strtou32_or_err(optarg,
1319 _("invalid buffer size argument"));
1320 if (ctl.bufsize < 4096)
1321 ctl.bufsize = 4096;
1322 break;
1323 case 'T':
1324 ctl.time_fmt = DMESG_TIMEFTM_CTIME;
1325 break;
1326 case 't':
1327 ctl.time_fmt = DMESG_TIMEFTM_NONE;
1328 delta = 0;
1329 break;
1330 case 'u':
1331 ctl.fltr_fac = 1;
1332 for (n = 1; (size_t) n < ARRAY_SIZE(facility_names); n++)
1333 setbit(ctl.facilities, n);
1334 break;
1335 case 'V':
1336 printf(_("%s from %s\n"), program_invocation_short_name,
1337 PACKAGE_STRING);
1338 return EXIT_SUCCESS;
1339 case 'w':
1340 ctl.follow = 1;
1341 break;
1342 case 'x':
1343 ctl.decode = 1;
1344 break;
1345 case OPT_TIME_FORMAT:
1346 ctl.time_fmt = which_time_format(optarg);
1347 break;
1348 case '?':
1349 default:
1350 usage(stderr);
1351 }
1352 }
1353 argc -= optind;
1354 argv += optind;
1355
1356 if (argc > 1)
1357 usage(stderr);
1358
1359 if (is_timefmt(&ctl, RELTIME) ||
1360 is_timefmt(&ctl, CTIME) ||
1361 is_timefmt(&ctl, ISO8601)) {
1362
1363 if (get_boot_time(&ctl.boot_time) != 0)
1364 ctl.time_fmt = DMESG_TIMEFTM_NONE;
1365 }
1366
1367 if (delta)
1368 switch (ctl.time_fmt) {
1369 case DMESG_TIMEFTM_CTIME:
1370 ctl.time_fmt = DMESG_TIMEFTM_CTIME_DELTA;
1371 break;
1372 case DMESG_TIMEFTM_TIME:
1373 ctl.time_fmt = DMESG_TIMEFTM_TIME_DELTA;
1374 break;
1375 case DMESG_TIMEFTM_ISO8601:
1376 warnx(_("--show-delta is ignored when used together with iso8601 time format"));
1377 break;
1378 default:
1379 ctl.time_fmt = DMESG_TIMEFTM_DELTA;
1380 }
1381
1382
1383 ctl.color = colors_init(colormode, "dmesg") ? 1 : 0;
1384 if (ctl.follow)
1385 nopager = 1;
1386 ctl.pager = nopager ? 0 : ctl.pager;
1387 if (ctl.pager)
1388 setup_pager();
1389
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;
1395
1396 if (ctl.raw
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"));
1401 if (ctl.pager)
1402 setup_pager();
1403 n = read_buffer(&ctl, &buf);
1404 if (n > 0)
1405 print_buffer(&ctl, buf, n);
1406 if (!ctl.mmap_buff)
1407 free(buf);
1408 if (n < 0)
1409 err(EXIT_FAILURE, _("read kernel buffer failed"));
1410 if (ctl.kmsg >= 0)
1411 close(ctl.kmsg);
1412 break;
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);
1417 break;
1418 case SYSLOG_ACTION_CONSOLE_LEVEL:
1419 klog_rc = klogctl(ctl.action, NULL, console_level);
1420 break;
1421 default:
1422 errx(EXIT_FAILURE, _("unsupported command"));
1423 break;
1424 }
1425
1426
1427 if (klog_rc)
1428 err(EXIT_FAILURE, _("klogctl failed"));
1429
1430 return EXIT_SUCCESS;
1431 }