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