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