/* * dmesg.c -- Print out the contents of the kernel ring buffer * * Copyright (C) 1993 Theodore Ts'o * Copyright (C) 2011 Karel Zak * * This program comes with ABSOLUTELY NO WARRANTY. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "c.h" #include "colors.h" #include "nls.h" #include "strutils.h" #include "xalloc.h" #include "widechar.h" #include "all-io.h" #include "bitops.h" #include "closestream.h" #include "optutils.h" #include "timeutils.h" #include "monotonic.h" #include "mangle.h" #include "pager.h" #include "jsonwrt.h" /* Close the log. Currently a NOP. */ #define SYSLOG_ACTION_CLOSE 0 /* Open the log. Currently a NOP. */ #define SYSLOG_ACTION_OPEN 1 /* Read from the log. */ #define SYSLOG_ACTION_READ 2 /* Read all messages remaining in the ring buffer. (allowed for non-root) */ #define SYSLOG_ACTION_READ_ALL 3 /* Read and clear all messages remaining in the ring buffer */ #define SYSLOG_ACTION_READ_CLEAR 4 /* Clear ring buffer. */ #define SYSLOG_ACTION_CLEAR 5 /* Disable printk's to console */ #define SYSLOG_ACTION_CONSOLE_OFF 6 /* Enable printk's to console */ #define SYSLOG_ACTION_CONSOLE_ON 7 /* Set level of messages printed to console */ #define SYSLOG_ACTION_CONSOLE_LEVEL 8 /* Return number of unread characters in the log buffer */ #define SYSLOG_ACTION_SIZE_UNREAD 9 /* Return size of the log buffer */ #define SYSLOG_ACTION_SIZE_BUFFER 10 /* * Color scheme */ struct dmesg_color { const char *scheme; /* name used in termina-colors.d/dmesg.scheme */ const char *dflt; /* default color ESC sequence */ }; enum { DMESG_COLOR_SUBSYS, DMESG_COLOR_TIME, DMESG_COLOR_TIMEBREAK, DMESG_COLOR_ALERT, DMESG_COLOR_CRIT, DMESG_COLOR_ERR, DMESG_COLOR_WARN, DMESG_COLOR_SEGFAULT }; static const struct dmesg_color colors[] = { [DMESG_COLOR_SUBSYS] = { "subsys", UL_COLOR_BROWN }, [DMESG_COLOR_TIME] = { "time", UL_COLOR_GREEN }, [DMESG_COLOR_TIMEBREAK] = { "timebreak",UL_COLOR_GREEN UL_COLOR_BOLD }, [DMESG_COLOR_ALERT] = { "alert", UL_COLOR_REVERSE UL_COLOR_RED }, [DMESG_COLOR_CRIT] = { "crit", UL_COLOR_BOLD UL_COLOR_RED }, [DMESG_COLOR_ERR] = { "err", UL_COLOR_RED }, [DMESG_COLOR_WARN] = { "warn", UL_COLOR_BOLD }, [DMESG_COLOR_SEGFAULT] = { "segfault", UL_COLOR_HALFBRIGHT UL_COLOR_RED } }; #define dmesg_enable_color(_id) \ color_scheme_enable(colors[_id].scheme, colors[_id].dflt); /* * Priority and facility names */ struct dmesg_name { const char *name; const char *help; }; /* * Priority names -- based on sys/syslog.h */ static const struct dmesg_name level_names[] = { [LOG_EMERG] = { "emerg", N_("system is unusable") }, [LOG_ALERT] = { "alert", N_("action must be taken immediately") }, [LOG_CRIT] = { "crit", N_("critical conditions") }, [LOG_ERR] = { "err", N_("error conditions") }, [LOG_WARNING] = { "warn", N_("warning conditions") }, [LOG_NOTICE] = { "notice",N_("normal but significant condition") }, [LOG_INFO] = { "info", N_("informational") }, [LOG_DEBUG] = { "debug", N_("debug-level messages") } }; /* * sys/syslog.h uses (f << 3) for all facility codes. * We want to use the codes as array indexes, so shift back... * * Note that libc LOG_FAC() macro returns the base codes, not the * shifted code :-) */ #define FAC_BASE(f) ((f) >> 3) static const struct dmesg_name facility_names[] = { [FAC_BASE(LOG_KERN)] = { "kern", N_("kernel messages") }, [FAC_BASE(LOG_USER)] = { "user", N_("random user-level messages") }, [FAC_BASE(LOG_MAIL)] = { "mail", N_("mail system") }, [FAC_BASE(LOG_DAEMON)] = { "daemon", N_("system daemons") }, [FAC_BASE(LOG_AUTH)] = { "auth", N_("security/authorization messages") }, [FAC_BASE(LOG_SYSLOG)] = { "syslog", N_("messages generated internally by syslogd") }, [FAC_BASE(LOG_LPR)] = { "lpr", N_("line printer subsystem") }, [FAC_BASE(LOG_NEWS)] = { "news", N_("network news subsystem") }, [FAC_BASE(LOG_UUCP)] = { "uucp", N_("UUCP subsystem") }, [FAC_BASE(LOG_CRON)] = { "cron", N_("clock daemon") }, [FAC_BASE(LOG_AUTHPRIV)] = { "authpriv", N_("security/authorization messages (private)") }, [FAC_BASE(LOG_FTP)] = { "ftp", N_("FTP daemon") }, }; /* supported methods to read message buffer */ enum { DMESG_METHOD_KMSG, /* read messages from /dev/kmsg (default) */ DMESG_METHOD_SYSLOG, /* klogctl() buffer */ DMESG_METHOD_MMAP /* mmap file with records (see --file) */ }; enum { DMESG_TIMEFTM_NONE = 0, DMESG_TIMEFTM_CTIME, /* [ctime] */ DMESG_TIMEFTM_CTIME_DELTA, /* [ctime ] */ DMESG_TIMEFTM_DELTA, /* [] */ DMESG_TIMEFTM_RELTIME, /* [relative] */ DMESG_TIMEFTM_TIME, /* [time] */ DMESG_TIMEFTM_TIME_DELTA, /* [time ] */ DMESG_TIMEFTM_ISO8601 /* 2013-06-13T22:11:00,123456+0100 */ }; #define is_timefmt(c, f) ((c)->time_fmt == (DMESG_TIMEFTM_ ##f)) struct dmesg_control { /* bit arrays -- see include/bitops.h */ char levels[ARRAY_SIZE(level_names) / NBBY + 1]; char facilities[ARRAY_SIZE(facility_names) / NBBY + 1]; struct timeval lasttime; /* last printed timestamp */ struct tm lasttm; /* last localtime */ struct timeval boot_time; /* system boot time */ time_t suspended_time; /* time spent in suspended state */ int action; /* SYSLOG_ACTION_* */ int method; /* DMESG_METHOD_* */ size_t bufsize; /* size of syslog buffer */ int kmsg; /* /dev/kmsg file descriptor */ ssize_t kmsg_first_read;/* initial read() return code */ char kmsg_buf[BUFSIZ];/* buffer to read kmsg data */ time_t since; /* filter records by time */ time_t until; /* filter records by time */ /* * For the --file option we mmap whole file. The unnecessary (already * printed) pages are always unmapped. The result is that we have in * memory only the currently used page(s). */ char *filename; char *mmap_buff; size_t pagesize; unsigned int time_fmt; /* time format */ struct ul_jsonwrt jfmt; /* -J formatting */ unsigned int follow:1, /* wait for new messages */ end:1, /* seek to the of buffer */ raw:1, /* raw mode */ noesc:1, /* no escape */ fltr_lev:1, /* filter out by levels[] */ fltr_fac:1, /* filter out by facilities[] */ decode:1, /* use "facility: level: " prefix */ pager:1, /* pipe output into a pager */ color:1, /* colorize messages */ json:1, /* JSON output */ force_prefix:1; /* force timestamp and decode prefix on each line */ int indent; /* due to timestamps if newline */ }; struct dmesg_record { const char *mesg; size_t mesg_size; int level; int facility; struct timeval tv; const char *next; /* buffer with next unparsed record */ size_t next_size; /* size of the next buffer */ }; #define INIT_DMESG_RECORD(_r) do { \ (_r)->mesg = NULL; \ (_r)->mesg_size = 0; \ (_r)->facility = -1; \ (_r)->level = -1; \ (_r)->tv.tv_sec = 0; \ (_r)->tv.tv_usec = 0; \ } while (0) static int read_kmsg(struct dmesg_control *ctl); static int set_level_color(int log_level, const char *mesg, size_t mesgsz) { int id = -1; switch (log_level) { case LOG_ALERT: id = DMESG_COLOR_ALERT; break; case LOG_CRIT: id = DMESG_COLOR_CRIT; break; case LOG_ERR: id = DMESG_COLOR_ERR; break; case LOG_WARNING: id = DMESG_COLOR_WARN; break; default: break; } /* well, sometimes the messages contains important keywords, but in * non-warning/error messages */ if (id < 0 && memmem(mesg, mesgsz, "segfault at", 11)) id = DMESG_COLOR_SEGFAULT; if (id >= 0) dmesg_enable_color(id); return id >= 0 ? 0 : -1; } static void __attribute__((__noreturn__)) usage(void) { FILE *out = stdout; size_t i; fputs(USAGE_HEADER, out); fprintf(out, _(" %s [options]\n"), program_invocation_short_name); fputs(USAGE_SEPARATOR, out); fputs(_("Display or control the kernel ring buffer.\n"), out); fputs(USAGE_OPTIONS, out); fputs(_(" -C, --clear clear the kernel ring buffer\n"), out); fputs(_(" -c, --read-clear read and clear all messages\n"), out); fputs(_(" -D, --console-off disable printing messages to console\n"), out); fputs(_(" -E, --console-on enable printing messages to console\n"), out); fputs(_(" -F, --file use the file instead of the kernel log buffer\n"), out); fputs(_(" -f, --facility restrict output to defined facilities\n"), out); fputs(_(" -H, --human human readable output\n"), out); fputs(_(" -J, --json use JSON output format\n"), out); fputs(_(" -k, --kernel display kernel messages\n"), out); fprintf(out, _(" -L, --color[=] colorize messages (%s, %s or %s)\n"), "auto", "always", "never"); fprintf(out, " %s\n", USAGE_COLORS_DEFAULT); fputs(_(" -l, --level restrict output to defined levels\n"), out); fputs(_(" -n, --console-level set level of messages printed to console\n"), out); fputs(_(" -P, --nopager do not pipe output into a pager\n"), out); fputs(_(" -p, --force-prefix force timestamp output on each line of multi-line messages\n"), out); fputs(_(" -r, --raw print the raw message buffer\n"), out); fputs(_(" --noescape don't escape unprintable character\n"), out); fputs(_(" -S, --syslog force to use syslog(2) rather than /dev/kmsg\n"), out); fputs(_(" -s, --buffer-size buffer size to query the kernel ring buffer\n"), out); fputs(_(" -u, --userspace display userspace messages\n"), out); fputs(_(" -w, --follow wait for new messages\n"), out); fputs(_(" -W, --follow-new wait and print only new messages\n"), out); fputs(_(" -x, --decode decode facility and level to readable string\n"), out); fputs(_(" -d, --show-delta show time delta between printed messages\n"), out); fputs(_(" -e, --reltime show local time and time delta in readable format\n"), out); fputs(_(" -T, --ctime show human-readable timestamp (may be inaccurate!)\n"), out); fputs(_(" -t, --notime don't show any timestamp with messages\n"), out); fputs(_(" --time-format show timestamp using the given format:\n" " [delta|reltime|ctime|notime|iso]\n" "Suspending/resume will make ctime and iso timestamps inaccurate.\n"), out); fputs(_(" --since