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