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