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