]> git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/dmesg.c
dmesg: highlight -T issues in docs
[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 "timeutils.h"
36 #include "monotonic.h"
37 #include "mangle.h"
38 #include "pager.h"
39
40 /* Close the log. Currently a NOP. */
41 #define SYSLOG_ACTION_CLOSE 0
42 /* Open the log. Currently a NOP. */
43 #define SYSLOG_ACTION_OPEN 1
44 /* Read from the log. */
45 #define SYSLOG_ACTION_READ 2
46 /* Read all messages remaining in the ring buffer. (allowed for non-root) */
47 #define SYSLOG_ACTION_READ_ALL 3
48 /* Read and clear all messages remaining in the ring buffer */
49 #define SYSLOG_ACTION_READ_CLEAR 4
50 /* Clear ring buffer. */
51 #define SYSLOG_ACTION_CLEAR 5
52 /* Disable printk's to console */
53 #define SYSLOG_ACTION_CONSOLE_OFF 6
54 /* Enable printk's to console */
55 #define SYSLOG_ACTION_CONSOLE_ON 7
56 /* Set level of messages printed to console */
57 #define SYSLOG_ACTION_CONSOLE_LEVEL 8
58 /* Return number of unread characters in the log buffer */
59 #define SYSLOG_ACTION_SIZE_UNREAD 9
60 /* Return size of the log buffer */
61 #define SYSLOG_ACTION_SIZE_BUFFER 10
62
63 /*
64 * Color scheme
65 */
66 struct dmesg_color {
67 const char *scheme; /* name used in termina-colors.d/dmesg.scheme */
68 const char *dflt; /* default color ESC sequence */
69 };
70
71 enum {
72 DMESG_COLOR_SUBSYS,
73 DMESG_COLOR_TIME,
74 DMESG_COLOR_TIMEBREAK,
75 DMESG_COLOR_ALERT,
76 DMESG_COLOR_CRIT,
77 DMESG_COLOR_ERR,
78 DMESG_COLOR_WARN,
79 DMESG_COLOR_SEGFAULT
80 };
81
82 static const struct dmesg_color colors[] =
83 {
84 [DMESG_COLOR_SUBSYS] = { "subsys", UL_COLOR_BROWN },
85 [DMESG_COLOR_TIME] = { "time", UL_COLOR_GREEN },
86 [DMESG_COLOR_TIMEBREAK] = { "timebreak",UL_COLOR_GREEN UL_COLOR_BOLD },
87 [DMESG_COLOR_ALERT] = { "alert", UL_COLOR_REVERSE UL_COLOR_RED },
88 [DMESG_COLOR_CRIT] = { "crit", UL_COLOR_BOLD UL_COLOR_RED },
89 [DMESG_COLOR_ERR] = { "err", UL_COLOR_RED },
90 [DMESG_COLOR_WARN] = { "warn", UL_COLOR_BOLD },
91 [DMESG_COLOR_SEGFAULT] = { "segfault", UL_COLOR_HALFBRIGHT UL_COLOR_RED }
92 };
93
94 #define dmesg_enable_color(_id) \
95 color_scheme_enable(colors[_id].scheme, colors[_id].dflt);
96
97 /*
98 * Priority and facility names
99 */
100 struct dmesg_name {
101 const char *name;
102 const char *help;
103 };
104
105 /*
106 * Priority names -- based on sys/syslog.h
107 */
108 static const struct dmesg_name level_names[] =
109 {
110 [LOG_EMERG] = { "emerg", N_("system is unusable") },
111 [LOG_ALERT] = { "alert", N_("action must be taken immediately") },
112 [LOG_CRIT] = { "crit", N_("critical conditions") },
113 [LOG_ERR] = { "err", N_("error conditions") },
114 [LOG_WARNING] = { "warn", N_("warning conditions") },
115 [LOG_NOTICE] = { "notice",N_("normal but significant condition") },
116 [LOG_INFO] = { "info", N_("informational") },
117 [LOG_DEBUG] = { "debug", N_("debug-level messages") }
118 };
119
120 /*
121 * sys/syslog.h uses (f << 3) for all facility codes.
122 * We want to use the codes as array idexes, so shift back...
123 *
124 * Note that libc LOG_FAC() macro returns the base codes, not the
125 * shifted code :-)
126 */
127 #define FAC_BASE(f) ((f) >> 3)
128
129 static const struct dmesg_name facility_names[] =
130 {
131 [FAC_BASE(LOG_KERN)] = { "kern", N_("kernel messages") },
132 [FAC_BASE(LOG_USER)] = { "user", N_("random user-level messages") },
133 [FAC_BASE(LOG_MAIL)] = { "mail", N_("mail system") },
134 [FAC_BASE(LOG_DAEMON)] = { "daemon", N_("system daemons") },
135 [FAC_BASE(LOG_AUTH)] = { "auth", N_("security/authorization messages") },
136 [FAC_BASE(LOG_SYSLOG)] = { "syslog", N_("messages generated internally by syslogd") },
137 [FAC_BASE(LOG_LPR)] = { "lpr", N_("line printer subsystem") },
138 [FAC_BASE(LOG_NEWS)] = { "news", N_("network news subsystem") },
139 [FAC_BASE(LOG_UUCP)] = { "uucp", N_("UUCP subsystem") },
140 [FAC_BASE(LOG_CRON)] = { "cron", N_("clock daemon") },
141 [FAC_BASE(LOG_AUTHPRIV)] = { "authpriv", N_("security/authorization messages (private)") },
142 [FAC_BASE(LOG_FTP)] = { "ftp", N_("FTP daemon") },
143 };
144
145 /* supported methods to read message buffer
146 */
147 enum {
148 DMESG_METHOD_KMSG, /* read messages from /dev/kmsg (default) */
149 DMESG_METHOD_SYSLOG, /* klogctl() buffer */
150 DMESG_METHOD_MMAP /* mmap file with records (see --file) */
151 };
152
153 enum {
154 DMESG_TIMEFTM_NONE = 0,
155 DMESG_TIMEFTM_CTIME, /* [ctime] */
156 DMESG_TIMEFTM_CTIME_DELTA, /* [ctime <delta>] */
157 DMESG_TIMEFTM_DELTA, /* [<delta>] */
158 DMESG_TIMEFTM_RELTIME, /* [relative] */
159 DMESG_TIMEFTM_TIME, /* [time] */
160 DMESG_TIMEFTM_TIME_DELTA, /* [time <delta>] */
161 DMESG_TIMEFTM_ISO8601 /* 2013-06-13T22:11:00,123456+0100 */
162 };
163 #define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f))
164
165 struct dmesg_control {
166 /* bit arrays -- see include/bitops.h */
167 char levels[ARRAY_SIZE(level_names) / NBBY + 1];
168 char facilities[ARRAY_SIZE(facility_names) / NBBY + 1];
169
170 struct timeval lasttime; /* last printed timestamp */
171 struct tm lasttm; /* last localtime */
172 struct timeval boot_time; /* system boot time */
173
174 int action; /* SYSLOG_ACTION_* */
175 int method; /* DMESG_METHOD_* */
176
177 size_t bufsize; /* size of syslog buffer */
178
179 int kmsg; /* /dev/kmsg file descriptor */
180 ssize_t kmsg_first_read;/* initial read() return code */
181 char kmsg_buf[BUFSIZ];/* buffer to read kmsg data */
182
183 /*
184 * For the --file option we mmap whole file. The unnecessary (already
185 * printed) pages are always unmapped. The result is that we have in
186 * memory only the currently used page(s).
187 */
188 char *filename;
189 char *mmap_buff;
190 size_t pagesize;
191 unsigned int time_fmt; /* time format */
192
193 unsigned int follow:1, /* wait for new messages */
194 raw:1, /* raw mode */
195 fltr_lev:1, /* filter out by levels[] */
196 fltr_fac:1, /* filter out by facilities[] */
197 decode:1, /* use "facility: level: " prefix */
198 pager:1, /* pipe output into a pager */
199 color:1; /* colorize messages */
200 int indent; /* due to timestamps if newline */
201 };
202
203 struct dmesg_record {
204 const char *mesg;
205 size_t mesg_size;
206
207 int level;
208 int facility;
209 struct timeval tv;
210
211 const char *next; /* buffer with next unparsed record */
212 size_t next_size; /* size of the next buffer */
213 };
214
215 #define INIT_DMESG_RECORD(_r) do { \
216 (_r)->mesg = NULL; \
217 (_r)->mesg_size = 0; \
218 (_r)->facility = -1; \
219 (_r)->level = -1; \
220 (_r)->tv.tv_sec = 0; \
221 (_r)->tv.tv_usec = 0; \
222 } while (0)
223
224 static int read_kmsg(struct dmesg_control *ctl);
225
226 static int set_level_color(int log_level, const char *mesg, size_t mesgsz)
227 {
228 int id = -1;
229
230 switch (log_level) {
231 case LOG_ALERT:
232 id = DMESG_COLOR_ALERT;
233 break;
234 case LOG_CRIT:
235 id = DMESG_COLOR_CRIT;
236 break;
237 case LOG_ERR:
238 id = DMESG_COLOR_ERR;
239 break;
240 case LOG_WARNING:
241 id = DMESG_COLOR_WARN;
242 break;
243 default:
244 break;
245 }
246
247 /* well, sometimes the messges contains important keywords, but in
248 * non-warning/error messages
249 */
250 if (id < 0 && memmem(mesg, mesgsz, "segfault at", 11))
251 id = DMESG_COLOR_SEGFAULT;
252
253 if (id >= 0)
254 dmesg_enable_color(id);
255
256 return id >= 0 ? 0 : -1;
257 }
258
259 static void __attribute__((__noreturn__)) usage(FILE *out)
260 {
261 size_t i;
262
263 fputs(USAGE_HEADER, out);
264 fprintf(out, _(" %s [options]\n"), program_invocation_short_name);
265
266 fputs(USAGE_SEPARATOR, out);
267 fputs(_("Display or control the kernel ring buffer.\n"), out);
268
269 fputs(USAGE_OPTIONS, out);
270 fputs(_(" -C, --clear clear the kernel ring buffer\n"), out);
271 fputs(_(" -c, --read-clear read and clear all messages\n"), out);
272 fputs(_(" -D, --console-off disable printing messages to console\n"), out);
273 fputs(_(" -E, --console-on enable printing messages to console\n"), out);
274 fputs(_(" -F, --file <file> use the file instead of the kernel log buffer\n"), out);
275 fputs(_(" -f, --facility <list> restrict output to defined facilities\n"), out);
276 fputs(_(" -H, --human human readable output\n"), out);
277 fputs(_(" -k, --kernel display kernel messages\n"), out);
278 fputs(_(" -L, --color[=<when>] colorize messages (auto, always or never)\n"), out);
279 fprintf(out,
280 " %s\n", USAGE_COLORS_DEFAULT);
281 fputs(_(" -l, --level <list> restrict output to defined levels\n"), out);
282 fputs(_(" -n, --console-level <level> set level of messages printed to console\n"), out);
283 fputs(_(" -P, --nopager do not pipe output into a pager\n"), out);
284 fputs(_(" -r, --raw print the raw message buffer\n"), out);
285 fputs(_(" -S, --syslog force to use syslog(2) rather than /dev/kmsg\n"), out);
286 fputs(_(" -s, --buffer-size <size> buffer size to query the kernel ring buffer\n"), out);
287 fputs(_(" -u, --userspace display userspace messages\n"), out);
288 fputs(_(" -w, --follow wait for new messages\n"), out);
289 fputs(_(" -x, --decode decode facility and level to readable string\n"), out);
290 fputs(_(" -d, --show-delta show time delta between printed messages\n"), out);
291 fputs(_(" -e, --reltime show local time and time delta in readable format\n"), out);
292 fputs(_(" -T, --ctime show human readable timestamp (may be inaccurate!)\n"), out);
293 fputs(_(" -t, --notime don't print messages timestamp\n"), out);
294 fputs(_(" --time-format <format> show time stamp using format:\n"
295 " [delta|reltime|ctime|notime|iso]\n"
296 "Suspending/resume will make ctime and iso timestamps inaccurate.\n"), out);
297 fputs(USAGE_SEPARATOR, out);
298 fputs(USAGE_HELP, out);
299 fputs(USAGE_VERSION, out);
300 fputs(_("\nSupported log facilities:\n"), out);
301 for (i = 0; i < ARRAY_SIZE(level_names); i++)
302 fprintf(out, " %7s - %s\n",
303 facility_names[i].name,
304 _(facility_names[i].help));
305
306 fputs(_("\nSupported log levels (priorities):\n"), out);
307 for (i = 0; i < ARRAY_SIZE(level_names); i++)
308 fprintf(out, " %7s - %s\n",
309 level_names[i].name,
310 _(level_names[i].help));
311 fputs(USAGE_SEPARATOR, out);
312 fprintf(out, USAGE_MAN_TAIL("dmesg(1)"));
313 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
314 }
315
316 /*
317 * LEVEL ::= <number> | <name>
318 * <number> ::= @len is set: number in range <0..N>, where N < ARRAY_SIZE(level_names)
319 * ::= @len not set: number in range <1..N>, where N <= ARRAY_SIZE(level_names)
320 * <name> ::= case-insensitive text
321 *
322 * Note that @len argument is not set when parsing "-n <level>" command line
323 * option. The console_level is intepreted as "log level less than the value".
324 *
325 * For example "dmesg -n 8" or "dmesg -n debug" enables debug console log
326 * level by klogctl(SYSLOG_ACTION_CONSOLE_LEVEL, NULL, 8). The @str argument
327 * has to be parsed to number in range <1..8>.
328 */
329 static int parse_level(const char *str, size_t len)
330 {
331 int offset = 0;
332
333 if (!str)
334 return -1;
335 if (!len) {
336 len = strlen(str);
337 offset = 1;
338 }
339 errno = 0;
340
341 if (isdigit(*str)) {
342 char *end = NULL;
343 long x = strtol(str, &end, 10) - offset;
344
345 if (!errno && end && end > str && (size_t) (end - str) == len &&
346 x >= 0 && (size_t) x < ARRAY_SIZE(level_names))
347 return x + offset;
348 } else {
349 size_t i;
350
351 for (i = 0; i < ARRAY_SIZE(level_names); i++) {
352 const char *n = level_names[i].name;
353
354 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
355 return i + offset;
356 }
357 }
358
359 if (errno)
360 err(EXIT_FAILURE, _("failed to parse level '%s'"), str);
361
362 errx(EXIT_FAILURE, _("unknown level '%s'"), str);
363 return -1;
364 }
365
366 /*
367 * FACILITY ::= <number> | <name>
368 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
369 * <name> ::= case-insensitive text
370 */
371 static int parse_facility(const char *str, size_t len)
372 {
373 if (!str)
374 return -1;
375 if (!len)
376 len = strlen(str);
377 errno = 0;
378
379 if (isdigit(*str)) {
380 char *end = NULL;
381 long x = strtol(str, &end, 10);
382
383 if (!errno && end && end > str && (size_t) (end - str) == len &&
384 x >= 0 && (size_t) x < ARRAY_SIZE(facility_names))
385 return x;
386 } else {
387 size_t i;
388
389 for (i = 0; i < ARRAY_SIZE(facility_names); i++) {
390 const char *n = facility_names[i].name;
391
392 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
393 return i;
394 }
395 }
396
397 if (errno)
398 err(EXIT_FAILURE, _("failed to parse facility '%s'"), str);
399
400 errx(EXIT_FAILURE, _("unknown facility '%s'"), str);
401 return -1;
402 }
403
404 /*
405 * Parses numerical prefix used for all messages in kernel ring buffer.
406 *
407 * Priorities/facilities are encoded into a single 32-bit quantity, where the
408 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
409 * (0-big number).
410 *
411 * Note that the number has to end with '>' or ',' char.
412 */
413 static const char *parse_faclev(const char *str, int *fac, int *lev)
414 {
415 long num;
416 char *end = NULL;
417
418 if (!str)
419 return str;
420
421 errno = 0;
422 num = strtol(str, &end, 10);
423
424 if (!errno && end && end > str) {
425 *fac = LOG_FAC(num);
426 *lev = LOG_PRI(num);
427
428 if (*lev < 0 || (size_t) *lev > ARRAY_SIZE(level_names))
429 *lev = -1;
430 if (*fac < 0 || (size_t) *fac > ARRAY_SIZE(facility_names))
431 *fac = -1;
432 return end + 1; /* skip '<' or ',' */
433 }
434
435 return str;
436 }
437
438 /*
439 * Parses timestamp from syslog message prefix, expected format:
440 *
441 * seconds.microseconds]
442 *
443 * the ']' is the timestamp field terminator.
444 */
445 static const char *parse_syslog_timestamp(const char *str0, struct timeval *tv)
446 {
447 const char *str = str0;
448 char *end = NULL;
449
450 if (!str0)
451 return str0;
452
453 errno = 0;
454 tv->tv_sec = strtol(str, &end, 10);
455
456 if (!errno && end && *end == '.' && *(end + 1)) {
457 str = end + 1;
458 end = NULL;
459 tv->tv_usec = strtol(str, &end, 10);
460 }
461 if (errno || !end || end == str || *end != ']')
462 return str0;
463
464 return end + 1; /* skip ']' */
465 }
466
467 /*
468 * Parses timestamp from /dev/kmsg, expected formats:
469 *
470 * microseconds,
471 * microseconds;
472 *
473 * the ',' is fields separators and ';' items terminator (for the last item)
474 */
475 static const char *parse_kmsg_timestamp(const char *str0, struct timeval *tv)
476 {
477 const char *str = str0;
478 char *end = NULL;
479 uint64_t usec;
480
481 if (!str0)
482 return str0;
483
484 errno = 0;
485 usec = strtoumax(str, &end, 10);
486
487 if (!errno && end && (*end == ';' || *end == ',')) {
488 tv->tv_usec = usec % 1000000;
489 tv->tv_sec = usec / 1000000;
490 } else
491 return str0;
492
493 return end + 1; /* skip separator */
494 }
495
496
497 static double time_diff(struct timeval *a, struct timeval *b)
498 {
499 return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
500 }
501
502 static int get_syslog_buffer_size(void)
503 {
504 int n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
505
506 return n > 0 ? n : 0;
507 }
508
509 /*
510 * Reads messages from regular file by mmap
511 */
512 static ssize_t mmap_file_buffer(struct dmesg_control *ctl, char **buf)
513 {
514 struct stat st;
515 int fd;
516
517 if (!ctl->filename)
518 return -1;
519
520 fd = open(ctl->filename, O_RDONLY);
521 if (fd < 0)
522 err(EXIT_FAILURE, _("cannot open %s"), ctl->filename);
523 if (fstat(fd, &st))
524 err(EXIT_FAILURE, _("stat of %s failed"), ctl->filename);
525
526 *buf = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
527 if (*buf == MAP_FAILED)
528 err(EXIT_FAILURE, _("cannot mmap: %s"), ctl->filename);
529 ctl->mmap_buff = *buf;
530 ctl->pagesize = getpagesize();
531 close(fd);
532
533 return st.st_size;
534 }
535
536 /*
537 * Reads messages from kernel ring buffer by klogctl()
538 */
539 static ssize_t read_syslog_buffer(struct dmesg_control *ctl, char **buf)
540 {
541 size_t sz;
542 int rc = -1;
543
544 if (ctl->bufsize) {
545 sz = ctl->bufsize + 8;
546 *buf = xmalloc(sz * sizeof(char));
547 rc = klogctl(ctl->action, *buf, sz);
548 } else {
549 sz = 16392;
550 while (1) {
551 *buf = xmalloc(sz * sizeof(char));
552 rc = klogctl(SYSLOG_ACTION_READ_ALL, *buf, sz);
553 if (rc < 0)
554 break;
555 if ((size_t) rc != sz || sz > (1 << 28))
556 break;
557 free(*buf);
558 *buf = NULL;
559 sz *= 4;
560 }
561
562 if (rc > 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR)
563 rc = klogctl(SYSLOG_ACTION_READ_CLEAR, *buf, sz);
564 }
565
566 return rc;
567 }
568
569 /*
570 * Top level function to read messages
571 */
572 static ssize_t read_buffer(struct dmesg_control *ctl, char **buf)
573 {
574 ssize_t n = -1;
575
576 switch (ctl->method) {
577 case DMESG_METHOD_MMAP:
578 n = mmap_file_buffer(ctl, buf);
579 break;
580 case DMESG_METHOD_SYSLOG:
581 if (!ctl->bufsize)
582 ctl->bufsize = get_syslog_buffer_size();
583
584 n = read_syslog_buffer(ctl, buf);
585 break;
586 case DMESG_METHOD_KMSG:
587 /*
588 * Since kernel 3.5.0
589 */
590 n = read_kmsg(ctl);
591 if (n == 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR)
592 n = klogctl(SYSLOG_ACTION_CLEAR, NULL, 0);
593 break;
594 }
595
596 return n;
597 }
598
599 static int fwrite_hex(const char *buf, size_t size, FILE *out)
600 {
601 size_t i;
602
603 for (i = 0; i < size; i++) {
604 int rc = fprintf(out, "\\x%02x", buf[i]);
605 if (rc < 0)
606 return rc;
607 }
608 return 0;
609 }
610
611 /*
612 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
613 */
614 static void safe_fwrite(const char *buf, size_t size, int indent, FILE *out)
615 {
616 size_t i;
617 #ifdef HAVE_WIDECHAR
618 mbstate_t s;
619 memset(&s, 0, sizeof (s));
620 #endif
621 for (i = 0; i < size; i++) {
622 const char *p = buf + i;
623 int rc, hex = 0;
624 size_t len;
625
626 #ifdef HAVE_WIDECHAR
627 wchar_t wc;
628 len = mbrtowc(&wc, p, size - i, &s);
629
630 if (len == 0) /* L'\0' */
631 return;
632
633 if (len == (size_t)-1 || len == (size_t)-2) { /* invalid sequence */
634 memset(&s, 0, sizeof (s));
635 len = hex = 1;
636 } else if (len > 1 && !iswprint(wc)) { /* non-printable multibyte */
637 hex = 1;
638 }
639 i += len - 1;
640 #else
641 len = 1;
642 if (!isprint((unsigned int) *p) &&
643 !isspace((unsigned int) *p)) /* non-printable */
644 hex = 1;
645 #endif
646 if (hex)
647 rc = fwrite_hex(p, len, out);
648 else if (*p == '\n' && *(p + 1) && indent) {
649 rc = fwrite(p, 1, len, out) != len;
650 if (fprintf(out, "%*s", indent, "") != indent)
651 rc |= 1;
652 }
653 else
654 rc = fwrite(p, 1, len, out) != len;
655 if (rc != 0) {
656 if (errno != EPIPE)
657 err(EXIT_FAILURE, _("write failed"));
658 exit(EXIT_SUCCESS);
659 }
660 }
661 }
662
663 static const char *skip_item(const char *begin, const char *end, const char *sep)
664 {
665 while (begin < end) {
666 int c = *begin++;
667
668 if (c == '\0' || strchr(sep, c))
669 break;
670 }
671
672 return begin;
673 }
674
675 /*
676 * Parses one record from syslog(2) buffer
677 */
678 static int get_next_syslog_record(struct dmesg_control *ctl,
679 struct dmesg_record *rec)
680 {
681 size_t i;
682 const char *begin = NULL;
683
684 if (ctl->method != DMESG_METHOD_MMAP &&
685 ctl->method != DMESG_METHOD_SYSLOG)
686 return -1;
687
688 if (!rec->next || !rec->next_size)
689 return 1;
690
691 INIT_DMESG_RECORD(rec);
692
693 /*
694 * Unmap already printed file data from memory
695 */
696 if (ctl->mmap_buff && (size_t) (rec->next - ctl->mmap_buff) > ctl->pagesize) {
697 void *x = ctl->mmap_buff;
698
699 ctl->mmap_buff += ctl->pagesize;
700 munmap(x, ctl->pagesize);
701 }
702
703 for (i = 0; i < rec->next_size; i++) {
704 const char *p = rec->next + i;
705 const char *end = NULL;
706
707 if (!begin)
708 begin = p;
709 if (i + 1 == rec->next_size) {
710 end = p + 1;
711 i++;
712 } else if (*p == '\n' && *(p + 1) == '<')
713 end = p;
714
715 if (begin && !*begin)
716 begin = NULL; /* zero(s) at the end of the buffer? */
717 if (!begin || !end)
718 continue;
719 if (end <= begin)
720 continue; /* error or empty line? */
721
722 if (*begin == '<') {
723 if (ctl->fltr_lev || ctl->fltr_fac || ctl->decode || ctl->color)
724 begin = parse_faclev(begin + 1, &rec->facility,
725 &rec->level);
726 else
727 begin = skip_item(begin, end, ">");
728 }
729
730 if (*begin == '[' && (*(begin + 1) == ' ' ||
731 isdigit(*(begin + 1)))) {
732
733 if (!is_timefmt(ctl, NONE))
734 begin = parse_syslog_timestamp(begin + 1, &rec->tv);
735 else
736 begin = skip_item(begin, end, "]");
737
738 if (begin < end && *begin == ' ')
739 begin++;
740 }
741
742 rec->mesg = begin;
743 rec->mesg_size = end - begin;
744
745 rec->next_size -= end - rec->next;
746 rec->next = rec->next_size > 0 ? end + 1 : NULL;
747 if (rec->next_size > 0)
748 rec->next_size--;
749
750 return 0;
751 }
752
753 return 1;
754 }
755
756 static int accept_record(struct dmesg_control *ctl, struct dmesg_record *rec)
757 {
758 if (ctl->fltr_lev && (rec->facility < 0 ||
759 !isset(ctl->levels, rec->level)))
760 return 0;
761
762 if (ctl->fltr_fac && (rec->facility < 0 ||
763 !isset(ctl->facilities, rec->facility)))
764 return 0;
765
766 return 1;
767 }
768
769 static void raw_print(struct dmesg_control *ctl, const char *buf, size_t size)
770 {
771 int lastc = '\n';
772
773 if (!ctl->mmap_buff) {
774 /*
775 * Print whole ring buffer
776 */
777 safe_fwrite(buf, size, 0, stdout);
778 lastc = buf[size - 1];
779 } else {
780 /*
781 * Print file in small chunks to save memory
782 */
783 while (size) {
784 size_t sz = size > ctl->pagesize ? ctl->pagesize : size;
785 char *x = ctl->mmap_buff;
786
787 safe_fwrite(x, sz, 0, stdout);
788 lastc = x[sz - 1];
789 size -= sz;
790 ctl->mmap_buff += sz;
791 munmap(x, sz);
792 }
793 }
794
795 if (lastc != '\n')
796 putchar('\n');
797 }
798
799 static struct tm *record_localtime(struct dmesg_control *ctl,
800 struct dmesg_record *rec,
801 struct tm *tm)
802 {
803 time_t t = ctl->boot_time.tv_sec + rec->tv.tv_sec;
804 return localtime_r(&t, tm);
805 }
806
807 static char *record_ctime(struct dmesg_control *ctl,
808 struct dmesg_record *rec,
809 char *buf, size_t bufsiz)
810 {
811 struct tm tm;
812
813 record_localtime(ctl, rec, &tm);
814
815 if (strftime(buf, bufsiz, "%a %b %e %H:%M:%S %Y", &tm) == 0)
816 *buf = '\0';
817 return buf;
818 }
819
820 static char *short_ctime(struct tm *tm, char *buf, size_t bufsiz)
821 {
822 if (strftime(buf, bufsiz, "%b%e %H:%M", tm) == 0)
823 *buf = '\0';
824 return buf;
825 }
826
827 static char *iso_8601_time(struct dmesg_control *ctl, struct dmesg_record *rec,
828 char *buf, size_t bufsiz)
829 {
830 struct tm tm;
831 size_t len;
832 record_localtime(ctl, rec, &tm);
833 if (strftime(buf, bufsiz, "%Y-%m-%dT%H:%M:%S", &tm) == 0) {
834 *buf = '\0';
835 return buf;
836 }
837 len = strlen(buf);
838 snprintf(buf + len, bufsiz - len, ",%06d", (int)rec->tv.tv_usec);
839 len = strlen(buf);
840 strftime(buf + len, bufsiz - len, "%z", &tm);
841 return buf;
842 }
843
844 static double record_count_delta(struct dmesg_control *ctl,
845 struct dmesg_record *rec)
846 {
847 double delta = 0;
848
849 if (timerisset(&ctl->lasttime))
850 delta = time_diff(&rec->tv, &ctl->lasttime);
851
852 ctl->lasttime = rec->tv;
853 return delta;
854 }
855
856 static const char *get_subsys_delimiter(const char *mesg, size_t mesg_size)
857 {
858 const char *p = mesg;
859 size_t sz = mesg_size;
860
861 while (sz > 0) {
862 const char *d = strnchr(p, sz, ':');
863 if (!d)
864 return NULL;
865 sz -= d - p;
866 if (sz) {
867 if (isblank(*(d + 1)))
868 return d;
869 p = d + 1;
870 }
871 }
872 return NULL;
873 }
874
875 static void print_record(struct dmesg_control *ctl,
876 struct dmesg_record *rec)
877 {
878 char buf[256];
879 int has_color = 0;
880 const char *mesg;
881 size_t mesg_size;
882 int indent = 0;
883
884 if (!accept_record(ctl, rec))
885 return;
886
887 if (!rec->mesg_size) {
888 putchar('\n');
889 return;
890 }
891
892 /*
893 * compose syslog(2) compatible raw output -- used for /dev/kmsg for
894 * backward compatibility with syslog(2) buffers only
895 */
896 if (ctl->raw) {
897 ctl->indent = printf("<%d>[%5d.%06d] ",
898 LOG_MAKEPRI(rec->facility, rec->level),
899 (int) rec->tv.tv_sec,
900 (int) rec->tv.tv_usec);
901
902 goto mesg;
903 }
904
905 /*
906 * facility : priority :
907 */
908 if (ctl->decode &&
909 -1 < rec->level && rec->level < (int) ARRAY_SIZE(level_names) &&
910 -1 < rec->facility && rec->facility < (int) ARRAY_SIZE(facility_names))
911 indent = printf("%-6s:%-6s: ", facility_names[rec->facility].name,
912 level_names[rec->level].name);
913
914 if (ctl->color)
915 dmesg_enable_color(DMESG_COLOR_TIME);
916
917 switch (ctl->time_fmt) {
918 double delta;
919 struct tm cur;
920 case DMESG_TIMEFTM_NONE:
921 ctl->indent = 0;
922 break;
923 case DMESG_TIMEFTM_CTIME:
924 ctl->indent = printf("[%s] ", record_ctime(ctl, rec, buf, sizeof(buf)));
925 break;
926 case DMESG_TIMEFTM_CTIME_DELTA:
927 ctl->indent = printf("[%s <%12.06f>] ",
928 record_ctime(ctl, rec, buf, sizeof(buf)),
929 record_count_delta(ctl, rec));
930 break;
931 case DMESG_TIMEFTM_DELTA:
932 ctl->indent = printf("[<%12.06f>] ", record_count_delta(ctl, rec));
933 break;
934 case DMESG_TIMEFTM_RELTIME:
935 record_localtime(ctl, rec, &cur);
936 delta = record_count_delta(ctl, rec);
937 if (cur.tm_min != ctl->lasttm.tm_min ||
938 cur.tm_hour != ctl->lasttm.tm_hour ||
939 cur.tm_yday != ctl->lasttm.tm_yday) {
940 dmesg_enable_color(DMESG_COLOR_TIMEBREAK);
941 ctl->indent = printf("[%s] ", short_ctime(&cur, buf, sizeof(buf)));
942 } else {
943 if (delta < 10)
944 ctl->indent = printf("[ %+8.06f] ", delta);
945 else
946 ctl->indent = printf("[ %+9.06f] ", delta);
947 }
948 ctl->lasttm = cur;
949 break;
950 case DMESG_TIMEFTM_TIME:
951 ctl->indent = printf("[%5d.%06d] ", (int)rec->tv.tv_sec, (int)rec->tv.tv_usec);
952 break;
953 case DMESG_TIMEFTM_TIME_DELTA:
954 ctl->indent = printf("[%5d.%06d <%12.06f>] ", (int)rec->tv.tv_sec,
955 (int)rec->tv.tv_usec, record_count_delta(ctl, rec));
956 break;
957 case DMESG_TIMEFTM_ISO8601:
958 ctl->indent = printf("%s ", iso_8601_time(ctl, rec, buf, sizeof(buf)));
959 break;
960 default:
961 abort();
962 }
963
964 ctl->indent += indent;
965
966 if (ctl->color)
967 color_disable();
968
969 mesg:
970 mesg = rec->mesg;
971 mesg_size = rec->mesg_size;
972
973 /* Colorize output */
974 if (ctl->color) {
975 /* subsystem prefix */
976 const char *subsys = get_subsys_delimiter(mesg, mesg_size);
977 if (subsys) {
978 dmesg_enable_color(DMESG_COLOR_SUBSYS);
979 safe_fwrite(mesg, subsys - mesg, ctl->indent, stdout);
980 color_disable();
981
982 mesg_size -= subsys - mesg;
983 mesg = subsys;
984 }
985 /* error, alert .. etc. colors */
986 has_color = set_level_color(rec->level, mesg, mesg_size) == 0;
987 safe_fwrite(mesg, mesg_size, ctl->indent, stdout);
988 if (has_color)
989 color_disable();
990 } else
991 safe_fwrite(mesg, mesg_size, ctl->indent, stdout);
992
993 if (*(mesg + mesg_size - 1) != '\n')
994 putchar('\n');
995 }
996
997 /*
998 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
999 * to 'levels' and 'facilities' bitarrays.
1000 */
1001 static void print_buffer(struct dmesg_control *ctl,
1002 const char *buf, size_t size)
1003 {
1004 struct dmesg_record rec = { .next = buf, .next_size = size };
1005
1006 if (ctl->raw) {
1007 raw_print(ctl, buf, size);
1008 return;
1009 }
1010
1011 while (get_next_syslog_record(ctl, &rec) == 0)
1012 print_record(ctl, &rec);
1013 }
1014
1015 static ssize_t read_kmsg_one(struct dmesg_control *ctl)
1016 {
1017 ssize_t size;
1018
1019 /* kmsg returns EPIPE if record was modified while reading */
1020 do {
1021 size = read(ctl->kmsg, ctl->kmsg_buf,
1022 sizeof(ctl->kmsg_buf) - 1);
1023 } while (size < 0 && errno == EPIPE);
1024
1025 return size;
1026 }
1027
1028 static int init_kmsg(struct dmesg_control *ctl)
1029 {
1030 int mode = O_RDONLY;
1031
1032 if (!ctl->follow)
1033 mode |= O_NONBLOCK;
1034 else
1035 setlinebuf(stdout);
1036
1037 ctl->kmsg = open("/dev/kmsg", mode);
1038 if (ctl->kmsg < 0)
1039 return -1;
1040
1041 /*
1042 * Seek after the last record available at the time
1043 * the last SYSLOG_ACTION_CLEAR was issued.
1044 *
1045 * ... otherwise SYSLOG_ACTION_CLEAR will have no effect for kmsg.
1046 */
1047 lseek(ctl->kmsg, 0, SEEK_DATA);
1048
1049 /*
1050 * Old kernels (<3.5) allow to successfully open /dev/kmsg for
1051 * read-only, but read() returns -EINVAL :-(((
1052 *
1053 * Let's try to read the first record. The record is later processed in
1054 * read_kmsg().
1055 */
1056 ctl->kmsg_first_read = read_kmsg_one(ctl);
1057 if (ctl->kmsg_first_read < 0) {
1058 close(ctl->kmsg);
1059 ctl->kmsg = -1;
1060 return -1;
1061 }
1062
1063 return 0;
1064 }
1065
1066 /*
1067 * /dev/kmsg record format:
1068 *
1069 * faclev,seqnum,timestamp[optional, ...];messgage\n
1070 * TAGNAME=value
1071 * ...
1072 *
1073 * - fields are separated by ','
1074 * - last field is terminated by ';'
1075 *
1076 */
1077 #define LAST_KMSG_FIELD(s) (!s || !*s || *(s - 1) == ';')
1078
1079 static int parse_kmsg_record(struct dmesg_control *ctl,
1080 struct dmesg_record *rec,
1081 char *buf,
1082 size_t sz)
1083 {
1084 const char *p = buf, *end;
1085
1086 if (sz == 0 || !buf || !*buf)
1087 return -1;
1088
1089 end = buf + (sz - 1);
1090 INIT_DMESG_RECORD(rec);
1091
1092 while (p < end && isspace(*p))
1093 p++;
1094
1095 /* A) priority and facility */
1096 if (ctl->fltr_lev || ctl->fltr_fac || ctl->decode ||
1097 ctl->raw || ctl->color)
1098 p = parse_faclev(p, &rec->facility, &rec->level);
1099 else
1100 p = skip_item(p, end, ",");
1101 if (LAST_KMSG_FIELD(p))
1102 goto mesg;
1103
1104 /* B) sequence number */
1105 p = skip_item(p, end, ",;");
1106 if (LAST_KMSG_FIELD(p))
1107 goto mesg;
1108
1109 /* C) timestamp */
1110 if (is_timefmt(ctl, NONE))
1111 p = skip_item(p, end, ",;");
1112 else
1113 p = parse_kmsg_timestamp(p, &rec->tv);
1114 if (LAST_KMSG_FIELD(p))
1115 goto mesg;
1116
1117 /* D) optional fields (ignore) */
1118 p = skip_item(p, end, ";");
1119 if (LAST_KMSG_FIELD(p))
1120 goto mesg;
1121
1122 mesg:
1123 /* E) message text */
1124 rec->mesg = p;
1125 p = skip_item(p, end, "\n");
1126
1127 if (!p)
1128 return -1;
1129
1130 rec->mesg_size = p - rec->mesg;
1131
1132 /*
1133 * Kernel escapes non-printable characters, unfortuately kernel
1134 * definition of "non-printable" is too strict. On UTF8 console we can
1135 * print many chars, so let's decode from kernel.
1136 */
1137 unhexmangle_to_buffer(rec->mesg, (char *) rec->mesg, rec->mesg_size + 1);
1138
1139 /* F) message tags (ignore) */
1140
1141 return 0;
1142 }
1143
1144 /*
1145 * Note that each read() call for /dev/kmsg returns always one record. It means
1146 * that we don't have to read whole message buffer before the records parsing.
1147 *
1148 * So this function does not compose one huge buffer (like read_syslog_buffer())
1149 * and print_buffer() is unnecessary. All is done in this function.
1150 *
1151 * Returns 0 on success, -1 on error.
1152 */
1153 static int read_kmsg(struct dmesg_control *ctl)
1154 {
1155 struct dmesg_record rec;
1156 ssize_t sz;
1157
1158 if (ctl->method != DMESG_METHOD_KMSG || ctl->kmsg < 0)
1159 return -1;
1160
1161 /*
1162 * The very first read() call is done in kmsg_init() where we test
1163 * /dev/kmsg usability. The return code from the initial read() is
1164 * stored in ctl->kmsg_first_read;
1165 */
1166 sz = ctl->kmsg_first_read;
1167
1168 while (sz > 0) {
1169 *(ctl->kmsg_buf + sz) = '\0'; /* for debug messages */
1170
1171 if (parse_kmsg_record(ctl, &rec,
1172 ctl->kmsg_buf, (size_t) sz) == 0)
1173 print_record(ctl, &rec);
1174
1175 sz = read_kmsg_one(ctl);
1176 }
1177
1178 return 0;
1179 }
1180
1181 static int which_time_format(const char *optarg)
1182 {
1183 if (!strcmp(optarg, "notime"))
1184 return DMESG_TIMEFTM_NONE;
1185 if (!strcmp(optarg, "ctime"))
1186 return DMESG_TIMEFTM_CTIME;
1187 if (!strcmp(optarg, "delta"))
1188 return DMESG_TIMEFTM_DELTA;
1189 if (!strcmp(optarg, "reltime"))
1190 return DMESG_TIMEFTM_RELTIME;
1191 if (!strcmp(optarg, "iso"))
1192 return DMESG_TIMEFTM_ISO8601;
1193 errx(EXIT_FAILURE, _("unknown time format: %s"), optarg);
1194 }
1195
1196 #ifdef TEST_DMESG
1197 static inline int dmesg_get_boot_time(struct timeval *tv)
1198 {
1199 char *str = getenv("DMESG_TEST_BOOTIME");
1200 uintmax_t sec, usec;
1201
1202 if (str && sscanf(str, "%ju.%ju", &sec, &usec) == 2) {
1203 tv->tv_sec = sec;
1204 tv->tv_usec = usec;
1205 return tv->tv_sec >= 0 && tv->tv_usec >= 0 ? 0 : -EINVAL;
1206 }
1207
1208 return get_boot_time(tv);
1209 }
1210 #else
1211 # define dmesg_get_boot_time get_boot_time
1212 #endif
1213
1214 int main(int argc, char *argv[])
1215 {
1216 char *buf = NULL;
1217 int c, nopager = 0;
1218 int console_level = 0;
1219 int klog_rc = 0;
1220 int delta = 0;
1221 ssize_t n;
1222 static struct dmesg_control ctl = {
1223 .filename = NULL,
1224 .action = SYSLOG_ACTION_READ_ALL,
1225 .method = DMESG_METHOD_KMSG,
1226 .kmsg = -1,
1227 .time_fmt = DMESG_TIMEFTM_TIME,
1228 .indent = 0,
1229 };
1230 int colormode = UL_COLORMODE_UNDEF;
1231 enum {
1232 OPT_TIME_FORMAT = CHAR_MAX + 1,
1233 };
1234
1235 static const struct option longopts[] = {
1236 { "buffer-size", required_argument, NULL, 's' },
1237 { "clear", no_argument, NULL, 'C' },
1238 { "color", optional_argument, NULL, 'L' },
1239 { "console-level", required_argument, NULL, 'n' },
1240 { "console-off", no_argument, NULL, 'D' },
1241 { "console-on", no_argument, NULL, 'E' },
1242 { "decode", no_argument, NULL, 'x' },
1243 { "file", required_argument, NULL, 'F' },
1244 { "facility", required_argument, NULL, 'f' },
1245 { "follow", no_argument, NULL, 'w' },
1246 { "human", no_argument, NULL, 'H' },
1247 { "help", no_argument, NULL, 'h' },
1248 { "kernel", no_argument, NULL, 'k' },
1249 { "level", required_argument, NULL, 'l' },
1250 { "syslog", no_argument, NULL, 'S' },
1251 { "raw", no_argument, NULL, 'r' },
1252 { "read-clear", no_argument, NULL, 'c' },
1253 { "reltime", no_argument, NULL, 'e' },
1254 { "show-delta", no_argument, NULL, 'd' },
1255 { "ctime", no_argument, NULL, 'T' },
1256 { "notime", no_argument, NULL, 't' },
1257 { "nopager", no_argument, NULL, 'P' },
1258 { "userspace", no_argument, NULL, 'u' },
1259 { "version", no_argument, NULL, 'V' },
1260 { "time-format", required_argument, NULL, OPT_TIME_FORMAT },
1261 { NULL, 0, NULL, 0 }
1262 };
1263
1264 static const ul_excl_t excl[] = { /* rows and cols in in ASCII order */
1265 { 'C','D','E','c','n','r' }, /* clear,off,on,read-clear,level,raw*/
1266 { 'H','r' }, /* human, raw */
1267 { 'L','r' }, /* color, raw */
1268 { 'S','w' }, /* syslog,follow */
1269 { 'T','r' }, /* ctime, raw */
1270 { 'd','r' }, /* delta, raw */
1271 { 'e','r' }, /* reltime, raw */
1272 { 'r','x' }, /* raw, decode */
1273 { 'r','t' }, /* notime, raw */
1274 { 0 }
1275 };
1276 int excl_st[ARRAY_SIZE(excl)] = UL_EXCL_STATUS_INIT;
1277
1278 setlocale(LC_ALL, "");
1279 bindtextdomain(PACKAGE, LOCALEDIR);
1280 textdomain(PACKAGE);
1281 atexit(close_stdout);
1282
1283 while ((c = getopt_long(argc, argv, "CcDdEeF:f:HhkL::l:n:iPrSs:TtuVwx",
1284 longopts, NULL)) != -1) {
1285
1286 err_exclusive_options(c, longopts, excl, excl_st);
1287
1288 switch (c) {
1289 case 'C':
1290 ctl.action = SYSLOG_ACTION_CLEAR;
1291 break;
1292 case 'c':
1293 ctl.action = SYSLOG_ACTION_READ_CLEAR;
1294 break;
1295 case 'D':
1296 ctl.action = SYSLOG_ACTION_CONSOLE_OFF;
1297 break;
1298 case 'd':
1299 delta = 1;
1300 break;
1301 case 'E':
1302 ctl.action = SYSLOG_ACTION_CONSOLE_ON;
1303 break;
1304 case 'e':
1305 ctl.time_fmt = DMESG_TIMEFTM_RELTIME;
1306 break;
1307 case 'F':
1308 ctl.filename = optarg;
1309 ctl.method = DMESG_METHOD_MMAP;
1310 break;
1311 case 'f':
1312 ctl.fltr_fac = 1;
1313 if (string_to_bitarray(optarg,
1314 ctl.facilities, parse_facility) < 0)
1315 return EXIT_FAILURE;
1316 break;
1317 case 'H':
1318 ctl.time_fmt = DMESG_TIMEFTM_RELTIME;
1319 colormode = UL_COLORMODE_AUTO;
1320 ctl.pager = 1;
1321 break;
1322 case 'h':
1323 usage(stdout);
1324 break;
1325 case 'k':
1326 ctl.fltr_fac = 1;
1327 setbit(ctl.facilities, FAC_BASE(LOG_KERN));
1328 break;
1329 case 'L':
1330 colormode = UL_COLORMODE_AUTO;
1331 if (optarg)
1332 colormode = colormode_or_err(optarg,
1333 _("unsupported color mode"));
1334 break;
1335 case 'l':
1336 ctl.fltr_lev= 1;
1337 if (string_to_bitarray(optarg,
1338 ctl.levels, parse_level) < 0)
1339 return EXIT_FAILURE;
1340 break;
1341 case 'n':
1342 ctl.action = SYSLOG_ACTION_CONSOLE_LEVEL;
1343 console_level = parse_level(optarg, 0);
1344 break;
1345 case 'P':
1346 nopager = 1;
1347 break;
1348 case 'r':
1349 ctl.raw = 1;
1350 break;
1351 case 'S':
1352 ctl.method = DMESG_METHOD_SYSLOG;
1353 break;
1354 case 's':
1355 ctl.bufsize = strtou32_or_err(optarg,
1356 _("invalid buffer size argument"));
1357 if (ctl.bufsize < 4096)
1358 ctl.bufsize = 4096;
1359 break;
1360 case 'T':
1361 ctl.time_fmt = DMESG_TIMEFTM_CTIME;
1362 break;
1363 case 't':
1364 ctl.time_fmt = DMESG_TIMEFTM_NONE;
1365 delta = 0;
1366 break;
1367 case 'u':
1368 ctl.fltr_fac = 1;
1369 for (n = 1; (size_t) n < ARRAY_SIZE(facility_names); n++)
1370 setbit(ctl.facilities, n);
1371 break;
1372 case 'V':
1373 printf(UTIL_LINUX_VERSION);
1374 return EXIT_SUCCESS;
1375 case 'w':
1376 ctl.follow = 1;
1377 break;
1378 case 'x':
1379 ctl.decode = 1;
1380 break;
1381 case OPT_TIME_FORMAT:
1382 ctl.time_fmt = which_time_format(optarg);
1383 break;
1384 case '?':
1385 default:
1386 usage(stderr);
1387 }
1388 }
1389 argc -= optind;
1390 argv += optind;
1391
1392 if (argc > 1)
1393 usage(stderr);
1394
1395 if (is_timefmt(&ctl, RELTIME) ||
1396 is_timefmt(&ctl, CTIME) ||
1397 is_timefmt(&ctl, ISO8601)) {
1398 if (dmesg_get_boot_time(&ctl.boot_time) != 0)
1399 ctl.time_fmt = DMESG_TIMEFTM_NONE;
1400 }
1401
1402 if (delta)
1403 switch (ctl.time_fmt) {
1404 case DMESG_TIMEFTM_CTIME:
1405 ctl.time_fmt = DMESG_TIMEFTM_CTIME_DELTA;
1406 break;
1407 case DMESG_TIMEFTM_TIME:
1408 ctl.time_fmt = DMESG_TIMEFTM_TIME_DELTA;
1409 break;
1410 case DMESG_TIMEFTM_ISO8601:
1411 warnx(_("--show-delta is ignored when used together with iso8601 time format"));
1412 break;
1413 default:
1414 ctl.time_fmt = DMESG_TIMEFTM_DELTA;
1415 }
1416
1417
1418 ctl.color = colors_init(colormode, "dmesg") ? 1 : 0;
1419 if (ctl.follow)
1420 nopager = 1;
1421 ctl.pager = nopager ? 0 : ctl.pager;
1422 if (ctl.pager)
1423 setup_pager();
1424
1425 switch (ctl.action) {
1426 case SYSLOG_ACTION_READ_ALL:
1427 case SYSLOG_ACTION_READ_CLEAR:
1428 if (ctl.method == DMESG_METHOD_KMSG && init_kmsg(&ctl) != 0)
1429 ctl.method = DMESG_METHOD_SYSLOG;
1430
1431 if (ctl.raw
1432 && ctl.method != DMESG_METHOD_KMSG
1433 && (ctl.fltr_lev || ctl.fltr_fac))
1434 errx(EXIT_FAILURE, _("--raw can be used together with --level or "
1435 "--facility only when reading messages from /dev/kmsg"));
1436 if (ctl.pager)
1437 setup_pager();
1438 n = read_buffer(&ctl, &buf);
1439 if (n > 0)
1440 print_buffer(&ctl, buf, n);
1441 if (!ctl.mmap_buff)
1442 free(buf);
1443 if (n < 0)
1444 err(EXIT_FAILURE, _("read kernel buffer failed"));
1445 if (ctl.kmsg >= 0)
1446 close(ctl.kmsg);
1447 break;
1448 case SYSLOG_ACTION_CLEAR:
1449 case SYSLOG_ACTION_CONSOLE_OFF:
1450 case SYSLOG_ACTION_CONSOLE_ON:
1451 klog_rc = klogctl(ctl.action, NULL, 0);
1452 break;
1453 case SYSLOG_ACTION_CONSOLE_LEVEL:
1454 klog_rc = klogctl(ctl.action, NULL, console_level);
1455 break;
1456 default:
1457 errx(EXIT_FAILURE, _("unsupported command"));
1458 break;
1459 }
1460
1461
1462 if (klog_rc)
1463 err(EXIT_FAILURE, _("klogctl failed"));
1464
1465 return EXIT_SUCCESS;
1466 }