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