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