From 298a073c2afdeb02dd3a8dd2c6fd1f72a3916e44 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Thu, 2 Aug 2012 17:39:14 +0200 Subject: dmesg: fix kmsg usability detection On old kernels (<3.5) kernel allows to open read-only /dev/kmsg for root, but read() returns -EINVAL. It means that open() is not enough to detect /dev/kmsg usability. We have to call read() (or epoll). Reported-by: Kay Sievers Signed-off-by: Karel Zak --- sys-utils/dmesg.c | 47 +++++++++++++++++++++++++++++++++++------------ 1 file changed, 35 insertions(+), 12 deletions(-) (limited to 'sys-utils/dmesg.c') diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index 1c5de2a5e..e92904f64 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -123,8 +123,12 @@ struct dmesg_control { int action; /* SYSLOG_ACTION_* */ int method; /* DMESG_METHOD_* */ - size_t bufsize; /* size of buffer created by read_buffer() */ + + 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 */ /* * For the --file option we mmap whole file. The unnecessary (already @@ -865,6 +869,22 @@ static int init_kmsg(struct dmesg_control *ctl) * ... otherwise SYSLOG_ACTION_CLEAR will have no effect for kmsg. */ lseek(ctl->kmsg, 0, SEEK_DATA); + + /* + * Old kernels (<3.5) allow to successfully open /dev/kmsg for + * read-only, but read() returns -EINVAL :-((( + * + * Let's try to read the first record. The record is later processed in + * read_kmsg(). + */ + ctl->kmsg_first_read = read(ctl->kmsg, ctl->kmsg_buf, + sizeof(ctl->kmsg_buf) - 1); + if (ctl->kmsg_first_read < 0) { + close(ctl->kmsg); + ctl->kmsg = -1; + return -1; + } + return 0; } @@ -956,25 +976,28 @@ mesg: */ static int read_kmsg(struct dmesg_control *ctl) { - char buf[BUFSIZ]; struct dmesg_record rec; + ssize_t sz; if (ctl->method != DMESG_METHOD_KMSG || ctl->kmsg < 0) return -1; - do { - ssize_t sz = read(ctl->kmsg, buf, sizeof(buf) - 1); - - if (sz <= 0) - break; + /* + * The very first read() call is done in kmsg_init() where we test + * /dev/kmsg usability. The return code from the initial read() is + * stored in ctl->kmsg_first_read; + */ + sz = ctl->kmsg_first_read; - *(buf + sz) = '\0'; /* for debug messages */ + while (sz > 0) { + *(ctl->kmsg_buf + sz) = '\0'; /* for debug messages */ - if (parse_kmsg_record(ctl, &rec, buf, (size_t) sz) != 0) - continue; + if (parse_kmsg_record(ctl, &rec, + ctl->kmsg_buf, (size_t) sz) == 0) + print_record(ctl, &rec); - print_record(ctl, &rec); - } while (1); + sz = read(ctl->kmsg, ctl->kmsg_buf, sizeof(ctl->kmsg_buf) - 1); + } return 0; } -- cgit v1.2.3-55-g7522