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