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