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