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