]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/dmesg.c
dmesg: move filename to control struct
[thirdparty/util-linux.git] / sys-utils / dmesg.c
CommitLineData
5ef05369
KZ
1/*
2 * dmesg.c -- Print out the contents of the kernel ring buffer
7eda085c 3 *
5ef05369
KZ
4 * Copyright (C) 1993 Theodore Ts'o <tytso@athena.mit.edu>
5 * Copyright (C) 2011 Karel Zak <kzak@redhat.com>
6 *
7 * This program comes with ABSOLUTELY NO WARRANTY.
6dbe3af9 8 */
6dbe3af9
KZ
9#include <linux/unistd.h>
10#include <stdio.h>
11#include <getopt.h>
fd6b7a7f 12#include <stdlib.h>
15673c15 13#include <sys/klog.h>
f06ec64f 14#include <sys/syslog.h>
bd304d92 15#include <sys/time.h>
42fac79a 16#include <sys/sysinfo.h>
15103c4b 17#include <ctype.h>
bd304d92 18#include <time.h>
c672220f
KZ
19#include <sys/mman.h>
20#include <sys/types.h>
21#include <sys/stat.h>
22#include <unistd.h>
23#include <fcntl.h>
5423ccb1 24
15103c4b 25#include "c.h"
5423ccb1 26#include "nls.h"
15673c15 27#include "strutils.h"
15103c4b 28#include "xalloc.h"
b8300c0a 29#include "widechar.h"
e12c9866 30#include "all-io.h"
636a6207 31#include "bitops.h"
efb8854f 32#include "closestream.h"
94920134 33#include "optutils.h"
6dbe3af9 34
59a14899
KZ
35/* Close the log. Currently a NOP. */
36#define SYSLOG_ACTION_CLOSE 0
37/* Open the log. Currently a NOP. */
38#define SYSLOG_ACTION_OPEN 1
39/* Read from the log. */
40#define SYSLOG_ACTION_READ 2
41/* Read all messages remaining in the ring buffer. (allowed for non-root) */
42#define SYSLOG_ACTION_READ_ALL 3
43/* Read and clear all messages remaining in the ring buffer */
44#define SYSLOG_ACTION_READ_CLEAR 4
45/* Clear ring buffer. */
46#define SYSLOG_ACTION_CLEAR 5
47/* Disable printk's to console */
48#define SYSLOG_ACTION_CONSOLE_OFF 6
49/* Enable printk's to console */
50#define SYSLOG_ACTION_CONSOLE_ON 7
51/* Set level of messages printed to console */
52#define SYSLOG_ACTION_CONSOLE_LEVEL 8
53/* Return number of unread characters in the log buffer */
54#define SYSLOG_ACTION_SIZE_UNREAD 9
55/* Return size of the log buffer */
56#define SYSLOG_ACTION_SIZE_BUFFER 10
57
94920134
SK
58#define EXCL_ERROR "--{clear,read-clear,console-level,console-on,console-off}"
59
f06ec64f 60/*
5ef05369 61 * Priority and facility names
f06ec64f
KZ
62 */
63struct dmesg_name {
64 const char *name;
65 const char *help;
66};
67
5ef05369
KZ
68/*
69 * Priority names -- based on sys/syslog.h
70 */
f06ec64f
KZ
71static const struct dmesg_name level_names[] =
72{
73 [LOG_EMERG] = { "emerg", N_("system is unusable") },
74 [LOG_ALERT] = { "alert", N_("action must be taken immediately") },
75 [LOG_CRIT] = { "crit", N_("critical conditions") },
76 [LOG_ERR] = { "err", N_("error conditions") },
77 [LOG_WARNING] = { "warn", N_("warning conditions") },
78 [LOG_NOTICE] = { "notice",N_("normal but significant condition") },
79 [LOG_INFO] = { "info", N_("informational") },
80 [LOG_DEBUG] = { "debug", N_("debug-level messages") }
81};
82
85f3cc55
KZ
83/*
84 * sys/syslog.h uses (f << 3) for all facility codes.
85 * We want to use the codes as array idexes, so shift back...
86 *
87 * Note that libc LOG_FAC() macro returns the base codes, not the
88 * shifted code :-)
89 */
90#define FAC_BASE(f) ((f) >> 3)
91
92static const struct dmesg_name facility_names[] =
93{
94 [FAC_BASE(LOG_KERN)] = { "kern", N_("kernel messages") },
95 [FAC_BASE(LOG_USER)] = { "user", N_("random user-level messages") },
96 [FAC_BASE(LOG_MAIL)] = { "mail", N_("mail system") },
97 [FAC_BASE(LOG_DAEMON)] = { "daemon", N_("system daemons") },
98 [FAC_BASE(LOG_AUTH)] = { "auth", N_("security/authorization messages") },
99 [FAC_BASE(LOG_SYSLOG)] = { "syslog", N_("messages generated internally by syslogd") },
100 [FAC_BASE(LOG_LPR)] = { "lpr", N_("line printer subsystem") },
101 [FAC_BASE(LOG_NEWS)] = { "news", N_("network news subsystem") },
102 [FAC_BASE(LOG_UUCP)] = { "uucp", N_("UUCP subsystem") },
103 [FAC_BASE(LOG_CRON)] = { "cron", N_("clock daemon") },
104 [FAC_BASE(LOG_AUTHPRIV)] = { "authpriv", N_("security/authorization messages (private)") },
105 [FAC_BASE(LOG_FTP)] = { "ftp", N_("ftp daemon") },
106};
107
aca1633a
KZ
108struct dmesg_control {
109 /* bit arrays -- see include/bitops.h */
110 char levels[ARRAY_SIZE(level_names) / NBBY + 1];
111 char facilities[ARRAY_SIZE(facility_names) / NBBY + 1];
112
bd304d92 113 struct timeval lasttime; /* last printed timestamp */
42fac79a 114 time_t boot_time; /* system boot time */
bd304d92 115
c672220f
KZ
116 /*
117 * For the --file option we mmap whole file. The unnecessary (already
118 * printed) pages are always unmapped. The result is that we have in
455fe9a0 119 * memory only the currently used page(s).
c672220f 120 */
9b3a6984 121 char *filename;
c672220f
KZ
122 char *mmap_buff;
123 size_t pagesize;
124
9feec79c
KZ
125 unsigned int raw:1, /* raw mode */
126 fltr_lev:1, /* filter out by levels[] */
127 fltr_fac:1, /* filter out by facilities[] */
128 decode:1, /* use "facility: level: " prefix */
129 notime:1, /* don't print timestamp */
130 delta:1, /* show time deltas */
131 ctime:1; /* show human readable time */
aca1633a 132};
f4fa5b44 133
a7ee94f2
KZ
134struct dmesg_record {
135 const char *mesg;
136 size_t mesg_size;
137
138 int level;
139 int facility;
bd304d92 140 struct timeval tv;
a7ee94f2
KZ
141
142 const char *next; /* buffer with next unparsed record */
143 size_t next_size; /* size of the next buffer */
144};
145
4a3b7949 146static void __attribute__((__noreturn__)) usage(FILE *out)
15103c4b 147{
738767b9 148 size_t i;
f06ec64f 149
dcd16b0f
KZ
150 fputs(_("\nUsage:\n"), out);
151 fprintf(out,
152 _(" %s [options]\n"), program_invocation_short_name);
153
154 fputs(_("\nOptions:\n"), out);
155 fputs(_(" -C, --clear clear the kernel ring buffer\n"
156 " -c, --read-clear read and clear all messages\n"
157 " -D, --console-off disable printing messages to console\n"
158 " -d, --show-delta show time delta between printed messages\n"
159 " -E, --console-on enable printing messages to console\n"
c672220f 160 " -F, --file <file> use the file instead of the kernel log buffer\n"
dcd16b0f
KZ
161 " -f, --facility <list> restrict output to defined facilities\n"
162 " -h, --help display this help and exit\n"
163 " -k, --kernel display kernel messages\n"
164 " -l, --level <list> restrict output to defined levels\n"
165 " -n, --console-level <level> set level of messages printed to console\n"
166 " -r, --raw print the raw message buffer\n"
167 " -s, --buffer-size <size> buffer size to query the kernel ring buffer\n"
168 " -T, --ctime show human readable timestamp (could be \n"
169 " inaccurate if you have used SUSPEND/RESUME)\n"
170 " -t, --notime don't print messages timestamp\n"
171 " -u, --userspace display userspace messages\n"
172 " -V, --version output version information and exit\n"
173 " -x, --decode decode facility and level to readable string\n"), out);
174
175 fputs(_("\nSupported log facilities:\n"), out);
f06ec64f 176 for (i = 0; i < ARRAY_SIZE(level_names); i++) {
85f3cc55
KZ
177 fprintf(stderr, " %7s - %s\n",
178 facility_names[i].name,
179 _(facility_names[i].help));
180 }
181
dcd16b0f 182 fputs(_("\nSupported log levels (priorities):\n"), out);
85f3cc55
KZ
183 for (i = 0; i < ARRAY_SIZE(level_names); i++) {
184 fprintf(stderr, " %7s - %s\n",
f06ec64f
KZ
185 level_names[i].name,
186 _(level_names[i].help));
187 }
188
189 fputc('\n', out);
190
4a3b7949 191 exit(out == stderr ? EXIT_FAILURE : EXIT_SUCCESS);
6dbe3af9
KZ
192}
193
5ef05369
KZ
194/*
195 * LEVEL ::= <number> | <name>
196 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(level_names)
197 * <name> ::= case-insensitive text
198 */
5c8f6bc6 199static int parse_level(const char *str, size_t len)
f06ec64f 200{
5c8f6bc6 201 if (!str)
f06ec64f 202 return -1;
5c8f6bc6
KZ
203 if (!len)
204 len = strlen(str);
205 errno = 0;
f06ec64f 206
5c8f6bc6
KZ
207 if (isdigit(*str)) {
208 char *end = NULL;
738767b9 209 long x = strtol(str, &end, 10);
5c8f6bc6 210
738767b9
KZ
211 if (!errno && end && end > str && (size_t) (end - str) == len &&
212 x >= 0 && (size_t) x < ARRAY_SIZE(level_names))
213 return x;
5c8f6bc6 214 } else {
738767b9
KZ
215 size_t i;
216
5c8f6bc6
KZ
217 for (i = 0; i < ARRAY_SIZE(level_names); i++) {
218 const char *n = level_names[i].name;
219
220 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
221 return i;
222 }
223 }
224
225 if (errno)
226 err(EXIT_FAILURE, _("failed to parse level '%s'"), str);
227
228 errx(EXIT_FAILURE, _("unknown level '%s'"), str);
f06ec64f
KZ
229 return -1;
230}
231
5ef05369
KZ
232/*
233 * FACILITY ::= <number> | <name>
234 * <number> ::= number in range <0..N>, where N < ARRAY_SIZE(facility_names)
235 * <name> ::= case-insensitive text
236 */
0e24df3b
KZ
237static int parse_facility(const char *str, size_t len)
238{
0e24df3b
KZ
239 if (!str)
240 return -1;
241 if (!len)
242 len = strlen(str);
243 errno = 0;
244
245 if (isdigit(*str)) {
246 char *end = NULL;
738767b9 247 long x = strtol(str, &end, 10);
0e24df3b 248
738767b9
KZ
249 if (!errno && end && end > str && (size_t) (end - str) == len &&
250 x >= 0 && (size_t) x < ARRAY_SIZE(facility_names))
251 return x;
0e24df3b 252 } else {
738767b9
KZ
253 size_t i;
254
0e24df3b
KZ
255 for (i = 0; i < ARRAY_SIZE(facility_names); i++) {
256 const char *n = facility_names[i].name;
257
258 if (strncasecmp(str, n, len) == 0 && *(n + len) == '\0')
259 return i;
260 }
261 }
262
263 if (errno)
264 err(EXIT_FAILURE, _("failed to parse facility '%s'"), str);
265
266 errx(EXIT_FAILURE, _("unknown facility '%s'"), str);
267 return -1;
268}
269
5ef05369
KZ
270/*
271 * Parses numerical prefix used for all messages in kernel ring buffer.
272 *
273 * Priorities/facilities are encoded into a single 32-bit quantity, where the
274 * bottom 3 bits are the priority (0-7) and the top 28 bits are the facility
275 * (0-big number).
276 *
277 * Note that the number has to end with '>' char.
278 */
636a6207
KZ
279static const char *parse_faclev(const char *str, int *fac, int *lev)
280{
281 long num;
282 char *end = NULL;
283
284 if (!str)
285 return str;
286
287 errno = 0;
288 num = strtol(str, &end, 10);
289
290 if (!errno && end && end > str) {
291 *fac = LOG_FAC(num);
292 *lev = LOG_PRI(num);
85f3cc55 293
738767b9 294 if (*lev < 0 || (size_t) *lev > ARRAY_SIZE(level_names))
85f3cc55 295 *lev = -1;
738767b9 296 if (*fac < 0 || (size_t) *fac > ARRAY_SIZE(facility_names))
85f3cc55 297 *fac = -1;
636a6207
KZ
298 return end + 1; /* skip '<' */
299 }
300
301 return str;
302}
303
bd304d92
KZ
304static const char *parse_timestamp(const char *str0, struct timeval *tv)
305{
306 const char *str = str0;
307 char *end = NULL;
308
309 if (!str0)
310 return str0;
311
312 errno = 0;
313 tv->tv_sec = strtol(str, &end, 10);
314
315 if (!errno && end && *end == '.' && *(end + 1)) {
316 str = end + 1;
317 end = NULL;
318 tv->tv_usec = strtol(str, &end, 10);
319 }
320 if (errno || !end || end == str || *end != ']')
321 return str0;
322
323 return end + 1; /* skip ']' */
324}
325
326
327static double time_diff(struct timeval *a, struct timeval *b)
328{
329 return (a->tv_sec - b->tv_sec) + (a->tv_usec - b->tv_usec) / 1E6;
330}
331
8cfd1ffb 332static int get_buffer_size(void)
eed99b2a
KZ
333{
334 int n = klogctl(SYSLOG_ACTION_SIZE_BUFFER, NULL, 0);
335
336 return n > 0 ? n : 0;
337}
338
42fac79a
KZ
339static time_t get_boot_time(void)
340{
341 struct sysinfo info;
342 struct timeval tv;
343
344 if (sysinfo(&info) != 0)
345 warn(_("sysinfo failed"));
346 else if (gettimeofday(&tv, NULL) != 0)
347 warn(_("gettimeofday failed"));
348 else
349 return tv.tv_sec -= info.uptime;
350 return 0;
351}
352
c672220f
KZ
353/*
354 * mmap file with the log
355 */
9b3a6984 356static ssize_t read_file_buffer(struct dmesg_control *ctl, char **buf)
c672220f
KZ
357{
358 struct stat st;
9b3a6984 359 int fd;
c672220f 360
9b3a6984
KZ
361 if (!ctl->filename)
362 return -1;
363
364 fd = open(ctl->filename, O_RDONLY);
c672220f 365 if (fd < 0)
9b3a6984 366 err(EXIT_FAILURE, _("cannot open %s"), ctl->filename);
c672220f 367 if (fstat(fd, &st))
9b3a6984 368 err(EXIT_FAILURE, _("stat failed %s"), ctl->filename);
c672220f
KZ
369
370 *buf = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
371 if (*buf == MAP_FAILED)
9b3a6984 372 err(EXIT_FAILURE, _("cannot mmap: %s"), ctl->filename);
c672220f
KZ
373 ctl->mmap_buff = *buf;
374 ctl->pagesize = getpagesize();
375 close(fd);
376
377 return st.st_size;
378}
379
5ef05369
KZ
380/*
381 * Reads messages from kernel ring buffer
382 */
c672220f 383static int read_kernel_buffer(char **buf, size_t bufsize, int clear)
65e3eed9
KZ
384{
385 size_t sz;
386 int rc = -1;
387 int cmd = clear ? SYSLOG_ACTION_READ_CLEAR :
388 SYSLOG_ACTION_READ_ALL;
389
390 if (bufsize) {
391 sz = bufsize + 8;
392 *buf = xmalloc(sz * sizeof(char));
393 rc = klogctl(cmd, *buf, sz);
394 } else {
395 sz = 16392;
396 while (1) {
397 *buf = xmalloc(sz * sizeof(char));
398 rc = klogctl(SYSLOG_ACTION_READ_ALL, *buf, sz);
738767b9
KZ
399 if (rc < 0)
400 break;
401 if ((size_t) rc != sz || sz > (1 << 28))
65e3eed9
KZ
402 break;
403 free(*buf);
404 *buf = NULL;
405 sz *= 4;
406 }
407
408 if (rc > 0 && clear)
409 rc = klogctl(SYSLOG_ACTION_READ_CLEAR, *buf, sz);
410 }
411
412 return rc;
413}
414
b8300c0a
KZ
415static int fwrite_hex(const char *buf, size_t size, FILE *out)
416{
738767b9 417 size_t i;
b8300c0a
KZ
418
419 for (i = 0; i < size; i++) {
420 int rc = fprintf(out, "\\x%02x", buf[i]);
421 if (rc < 0)
422 return rc;
423 }
424 return 0;
425}
426
5ef05369
KZ
427/*
428 * Prints to 'out' and non-printable chars are replaced with \x<hex> sequences.
429 */
b8300c0a
KZ
430static void safe_fwrite(const char *buf, size_t size, FILE *out)
431{
738767b9 432 size_t i;
b8300c0a
KZ
433#ifdef HAVE_WIDECHAR
434 mbstate_t s;
435 memset(&s, 0, sizeof (s));
436#endif
437 for (i = 0; i < size; i++) {
438 const char *p = buf + i;
439 int rc, hex = 0;
0720766e 440 size_t len = 1;
b8300c0a
KZ
441
442#ifdef HAVE_WIDECHAR
443 wchar_t wc;
0720766e 444 len = mbrtowc(&wc, p, size - i, &s);
b8300c0a
KZ
445
446 if (len == 0) /* L'\0' */
447 return;
448
730d5e77 449 if (len == (size_t)-1 || len == (size_t)-2) { /* invalid sequence */
b8300c0a
KZ
450 memset(&s, 0, sizeof (s));
451 len = hex = 1;
b8300c0a
KZ
452 } else if (len > 1 && !iswprint(wc)) { /* non-printable multibyte */
453 hex = 1;
b8300c0a 454 }
0720766e
PU
455 i += len - 1;
456#else
457 if (!isprint((unsigned int) *p) &&
458 !isspace((unsigned int) *p)) /* non-printable */
459 hex = 1;
460#endif
b8300c0a
KZ
461 if (hex)
462 rc = fwrite_hex(p, len, out);
463 else
85f3cc55 464 rc = fwrite(p, 1, len, out) != len;
b8300c0a
KZ
465 if (rc != 0)
466 err(EXIT_FAILURE, _("write failed"));
467 }
468}
469
a7ee94f2 470static int get_next_record(struct dmesg_control *ctl, struct dmesg_record *rec)
f4fa5b44 471{
738767b9 472 size_t i;
b8300c0a
KZ
473 const char *begin = NULL;
474
a7ee94f2
KZ
475 if (!rec->next || !rec->next_size)
476 return 1;
f4fa5b44 477
a7ee94f2
KZ
478 rec->mesg = NULL;
479 rec->mesg_size = 0;
480 rec->facility = -1;
481 rec->level = -1;
bd304d92
KZ
482 rec->tv.tv_sec = 0;
483 rec->tv.tv_usec = 0;
a7ee94f2 484
c672220f
KZ
485 /*
486 * Unmap already printed file data from memory
487 */
488 if (ctl->mmap_buff && (size_t) (rec->next - ctl->mmap_buff) > ctl->pagesize) {
489 void *x = ctl->mmap_buff;
490
491 ctl->mmap_buff += ctl->pagesize;
492 munmap(x, ctl->pagesize);
493 }
494
a7ee94f2
KZ
495 for (i = 0; i < rec->next_size; i++) {
496 const char *p = rec->next + i;
497 const char *end = NULL;
b8300c0a
KZ
498
499 if (!begin)
500 begin = p;
a7ee94f2 501 if (i + 1 == rec->next_size) {
b8300c0a 502 end = p + 1;
f4fa5b44 503 i++;
22f69825
KZ
504 } else if (*p == '\n' && *(p + 1) == '<')
505 end = p;
506
a7ee94f2
KZ
507 if (begin && !*begin)
508 begin = NULL; /* zero(s) at the end of the buffer? */
b8300c0a
KZ
509 if (!begin || !end)
510 continue;
511 if (end <= begin)
512 continue; /* error or empty line? */
513
636a6207 514 if (*begin == '<') {
aca1633a 515 if (ctl->fltr_lev || ctl->fltr_fac || ctl->decode) {
a7ee94f2
KZ
516 begin = parse_faclev(begin + 1, &rec->facility,
517 &rec->level);
636a6207
KZ
518 } else {
519 /* ignore facility and level */
520 while (begin < end) {
521 begin++;
522 if (*(begin - 1) == '>')
523 break;
524 }
b8300c0a
KZ
525 }
526 }
527
bd304d92
KZ
528 if (*begin == '[' && (*(begin + 1) == ' ' ||
529 isdigit(*(begin + 1)))) {
608d4501
KZ
530 if (ctl->delta || ctl->ctime) {
531 begin = parse_timestamp(begin + 1, &rec->tv);
532 } else if (ctl->notime) {
bd304d92
KZ
533 while (begin < end) {
534 begin++;
535 if (*(begin - 1) == ']')
536 break;
537 }
d74b8dfc 538 }
31c9099a
KZ
539 if (begin < end && *begin == ' ')
540 begin++;
a7ee94f2 541 }
d74b8dfc 542
a7ee94f2
KZ
543 rec->mesg = begin;
544 rec->mesg_size = end - begin;
b8300c0a 545
a7ee94f2
KZ
546 rec->next_size -= end - rec->next;
547 rec->next = rec->next_size > 0 ? end + 1 : NULL;
59202950
PU
548 if (rec->next_size > 0)
549 rec->next_size--;
a7ee94f2
KZ
550
551 return 0;
552 }
553
554 return 1;
555}
556
557static int accept_record(struct dmesg_control *ctl, struct dmesg_record *rec)
558{
559 if (ctl->fltr_lev && (rec->facility < 0 ||
560 !isset(ctl->levels, rec->level)))
561 return 0;
562
563 if (ctl->fltr_fac && (rec->facility < 0 ||
564 !isset(ctl->facilities, rec->facility)))
565 return 0;
566
567 return 1;
568}
569
c672220f
KZ
570static void raw_print(const char *buf, size_t size,
571 struct dmesg_control *ctl)
572{
573 int lastc = '\n';
574
575 if (!ctl->mmap_buff) {
576 /*
577 * Print whole ring buffer
578 */
579 safe_fwrite(buf, size, stdout);
580 lastc = buf[size - 1];
581 } else {
582 /*
583 * Print file in small chunks to save memory
584 */
585 while (size) {
586 size_t sz = size > ctl->pagesize ? ctl->pagesize : size;
587 char *x = ctl->mmap_buff;
588
589 safe_fwrite(x, sz, stdout);
590 lastc = x[sz - 1];
591 size -= sz;
592 ctl->mmap_buff += sz;
593 munmap(x, sz);
594 }
595 }
596
597 if (lastc != '\n')
598 putchar('\n');
599}
600
a7ee94f2
KZ
601/*
602 * Prints the 'buf' kernel ring buffer; the messages are filtered out according
603 * to 'levels' and 'facilities' bitarrays.
604 */
605static void print_buffer(const char *buf, size_t size,
606 struct dmesg_control *ctl)
607{
608 struct dmesg_record rec = { .next = buf, .next_size = size };
42fac79a 609 char tbuf[256];
a7ee94f2
KZ
610
611 if (ctl->raw) {
c672220f 612 raw_print(buf, size, ctl);
a7ee94f2
KZ
613 return;
614 }
615
bd304d92 616 while (get_next_record(ctl, &rec) == 0) {
a7ee94f2
KZ
617
618 if (!accept_record(ctl, &rec))
619 continue;
620
22f69825
KZ
621 if (!rec.mesg_size) {
622 putchar('\n');
623 continue;
624 }
625
a7ee94f2
KZ
626 if (ctl->decode && rec.level >= 0 && rec.facility >= 0)
627 printf("%-6s:%-6s: ", facility_names[rec.facility].name,
628 level_names[rec.level].name);
629
42fac79a
KZ
630 *tbuf = '\0';
631 if (ctl->ctime) {
632 time_t t = ctl->boot_time + rec.tv.tv_sec;
633 if (strftime(tbuf, sizeof(tbuf), "%a %b %e %H:%M:%S %Y",
634 localtime(&t)) == 0)
635 *tbuf = '\0';
636 }
bd304d92
KZ
637 if (ctl->delta) {
638 double delta = 0;
639
42fac79a 640 if (timerisset(&ctl->lasttime))
bd304d92
KZ
641 delta = time_diff(&rec.tv, &ctl->lasttime);
642 ctl->lasttime = rec.tv;
643
42fac79a
KZ
644 if (ctl->ctime && *tbuf)
645 printf("[%s ", tbuf);
608d4501
KZ
646 else if (ctl->notime)
647 putchar('[');
42fac79a
KZ
648 else
649 printf("[%5d.%06d ", (int) rec.tv.tv_sec,
650 (int) rec.tv.tv_usec);
651 printf("<%12.06f>] ", delta);
652 } else if (ctl->ctime && *tbuf) {
653 printf("[%s] ", tbuf);
bd304d92
KZ
654 }
655
a7ee94f2
KZ
656 safe_fwrite(rec.mesg, rec.mesg_size, stdout);
657
658 if (*(rec.mesg + rec.mesg_size - 1) != '\n')
659 putchar('\n');
f4fa5b44 660 }
f4fa5b44
KZ
661}
662
15103c4b
MP
663int main(int argc, char *argv[])
664{
665 char *buf = NULL;
c129767e 666 int bufsize = 0;
c672220f 667 ssize_t n;
df1dddf9 668 int c;
48c5c662 669 int console_level = 0;
0506537a 670 int cmd = -1;
9b3a6984
KZ
671 static struct dmesg_control ctl = {
672 .filename = NULL
673 };
6dbe3af9 674
94920134
SK
675 enum {
676 EXCL_NONE,
677 EXCL_CLEAR,
678 EXCL_READ_CLEAR,
679 EXCL_CONSOLE_LEVEL,
680 EXCL_CONSOLE_ON,
681 EXCL_CONSOLE_OFF
682 };
683 int excl_any = EXCL_NONE;
684
4a3b7949 685 static const struct option longopts[] = {
4a3b7949 686 { "buffer-size", required_argument, NULL, 's' },
5ef05369 687 { "clear", no_argument, NULL, 'C' },
4a3b7949 688 { "console-level", required_argument, NULL, 'n' },
bd304d92
KZ
689 { "console-off", no_argument, NULL, 'D' },
690 { "console-on", no_argument, NULL, 'E' },
5ef05369 691 { "decode", no_argument, NULL, 'x' },
c672220f 692 { "file", required_argument, NULL, 'F' },
0e24df3b 693 { "facility", required_argument, NULL, 'f' },
4a3b7949 694 { "help", no_argument, NULL, 'h' },
25000180 695 { "kernel", no_argument, NULL, 'k' },
5ef05369
KZ
696 { "level", required_argument, NULL, 'l' },
697 { "raw", no_argument, NULL, 'r' },
698 { "read-clear", no_argument, NULL, 'c' },
bd304d92 699 { "show-delta", no_argument, NULL, 'd' },
42fac79a 700 { "ctime", no_argument, NULL, 'T' },
d74b8dfc 701 { "notime", no_argument, NULL, 't' },
25000180 702 { "userspace", no_argument, NULL, 'u' },
5ef05369 703 { "version", no_argument, NULL, 'V' },
4a3b7949
KZ
704 { NULL, 0, NULL, 0 }
705 };
706
df1dddf9
KZ
707 setlocale(LC_ALL, "");
708 bindtextdomain(PACKAGE, LOCALEDIR);
709 textdomain(PACKAGE);
efb8854f 710 atexit(close_stdout);
7eda085c 711
c672220f 712 while ((c = getopt_long(argc, argv, "CcDdEF:f:hkl:n:rs:TtuVx",
aca1633a 713 longopts, NULL)) != -1) {
df1dddf9 714 switch (c) {
04199860 715 case 'C':
94920134 716 exclusive_option(&excl_any, EXCL_CLEAR, EXCL_ERROR);
04199860
KZ
717 cmd = SYSLOG_ACTION_CLEAR;
718 break;
df1dddf9 719 case 'c':
94920134 720 exclusive_option(&excl_any, EXCL_READ_CLEAR, EXCL_ERROR);
59a14899 721 cmd = SYSLOG_ACTION_READ_CLEAR;
df1dddf9 722 break;
bd304d92 723 case 'D':
94920134 724 exclusive_option(&excl_any, EXCL_CONSOLE_OFF, EXCL_ERROR);
2170174e
KZ
725 cmd = SYSLOG_ACTION_CONSOLE_OFF;
726 break;
bd304d92
KZ
727 case 'd':
728 ctl.delta = 1;
729 break;
730 case 'E':
94920134 731 exclusive_option(&excl_any, EXCL_CONSOLE_ON, EXCL_ERROR);
2170174e
KZ
732 cmd = SYSLOG_ACTION_CONSOLE_ON;
733 break;
c672220f 734 case 'F':
9b3a6984 735 ctl.filename = optarg;
c672220f 736 break;
0e24df3b 737 case 'f':
aca1633a 738 ctl.fltr_fac = 1;
c87638ad
KZ
739 if (string_to_bitarray(optarg,
740 ctl.facilities, parse_facility) < 0)
741 return EXIT_FAILURE;
0e24df3b 742 break;
5ef05369
KZ
743 case 'h':
744 usage(stdout);
df1dddf9 745 break;
25000180 746 case 'k':
aca1633a
KZ
747 ctl.fltr_fac = 1;
748 setbit(ctl.facilities, FAC_BASE(LOG_KERN));
25000180 749 break;
636a6207 750 case 'l':
aca1633a 751 ctl.fltr_lev= 1;
c87638ad
KZ
752 if (string_to_bitarray(optarg,
753 ctl.levels, parse_level) < 0)
754 return EXIT_FAILURE;
636a6207 755 break;
5ef05369 756 case 'n':
94920134 757 exclusive_option(&excl_any, EXCL_CONSOLE_LEVEL, EXCL_ERROR);
5ef05369
KZ
758 cmd = SYSLOG_ACTION_CONSOLE_LEVEL;
759 console_level = parse_level(optarg, 0);
760 break;
11ea22d5 761 case 'r':
aca1633a 762 ctl.raw = 1;
11ea22d5 763 break;
df1dddf9 764 case 's':
20a39982 765 bufsize = strtou32_or_err(optarg, _("invalid buffer size argument"));
c129767e
KZ
766 if (bufsize < 4096)
767 bufsize = 4096;
df1dddf9 768 break;
42fac79a
KZ
769 case 'T':
770 ctl.boot_time = get_boot_time();
771 if (ctl.boot_time)
772 ctl.ctime = 1;
773 break;
d74b8dfc 774 case 't':
aca1633a 775 ctl.notime = 1;
d74b8dfc 776 break;
25000180 777 case 'u':
aca1633a 778 ctl.fltr_fac = 1;
738767b9 779 for (n = 1; (size_t) n < ARRAY_SIZE(facility_names); n++)
aca1633a 780 setbit(ctl.facilities, n);
25000180 781 break;
4a3b7949
KZ
782 case 'V':
783 printf(_("%s from %s\n"), program_invocation_short_name,
784 PACKAGE_STRING);
785 return EXIT_SUCCESS;
5ef05369 786 case 'x':
aca1633a 787 ctl.decode = 1;
4a3b7949 788 break;
df1dddf9
KZ
789 case '?':
790 default:
4a3b7949 791 usage(stderr);
df1dddf9
KZ
792 }
793 }
794 argc -= optind;
795 argv += optind;
25000180 796 n = 0;
e6c379eb 797
15103c4b 798 if (argc > 1)
4a3b7949 799 usage(stderr);
6dbe3af9 800
0506537a
KZ
801 if (cmd == -1)
802 cmd = SYSLOG_ACTION_READ_ALL; /* default */
803
641986cf
KZ
804 if (ctl.raw && (ctl.fltr_lev || ctl.fltr_fac || ctl.delta ||
805 ctl.notime || ctl.ctime || ctl.decode))
806 errx(EXIT_FAILURE, _("--raw can't be used together with level, "
807 "facility, decode, delta, ctime or notime options"));
808
608d4501
KZ
809 if (ctl.notime && ctl.ctime)
810 errx(EXIT_FAILURE, _("--notime can't be used together with ctime "));
85f3cc55 811
48c5c662
KZ
812 switch (cmd) {
813 case SYSLOG_ACTION_READ_ALL:
814 case SYSLOG_ACTION_READ_CLEAR:
9b3a6984
KZ
815 if (ctl.filename)
816 n = read_file_buffer(&ctl, &buf);
c672220f
KZ
817 else {
818 if (!bufsize)
819 bufsize = get_buffer_size();
820 n = read_kernel_buffer(&buf, bufsize,
821 cmd == SYSLOG_ACTION_READ_CLEAR);
822 }
48c5c662 823 if (n > 0)
aca1633a 824 print_buffer(buf, n, &ctl);
9b3a6984 825 if (!ctl.filename)
c672220f 826 free(buf);
48c5c662 827 break;
04199860 828 case SYSLOG_ACTION_CLEAR:
2170174e
KZ
829 case SYSLOG_ACTION_CONSOLE_OFF:
830 case SYSLOG_ACTION_CONSOLE_ON:
04199860
KZ
831 n = klogctl(cmd, NULL, 0);
832 break;
48c5c662
KZ
833 case SYSLOG_ACTION_CONSOLE_LEVEL:
834 n = klogctl(cmd, NULL, console_level);
835 break;
836 default:
837 errx(EXIT_FAILURE, _("unsupported command"));
838 break;
df1dddf9 839 }
6dbe3af9 840
9b3a6984 841 if (n < 0 && !ctl.filename)
15103c4b 842 err(EXIT_FAILURE, _("klogctl failed"));
6dbe3af9 843
15103c4b 844 return EXIT_SUCCESS;
6dbe3af9 845}