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