summaryrefslogtreecommitdiffstats
path: root/sys-utils/dmesg.c
diff options
context:
space:
mode:
authorKarel Zak2012-08-02 17:39:14 +0200
committerKarel Zak2012-08-02 17:39:14 +0200
commit298a073c2afdeb02dd3a8dd2c6fd1f72a3916e44 (patch)
tree116c240ee26b4312ddfa42ee8508cf0407f9d69d /sys-utils/dmesg.c
parenttests: add libmount optstr deduplicate (diff)
downloadkernel-qcow2-util-linux-298a073c2afdeb02dd3a8dd2c6fd1f72a3916e44.tar.gz
kernel-qcow2-util-linux-298a073c2afdeb02dd3a8dd2c6fd1f72a3916e44.tar.xz
kernel-qcow2-util-linux-298a073c2afdeb02dd3a8dd2c6fd1f72a3916e44.zip
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 <kay.sievers@vrfy.org> Signed-off-by: Karel Zak <kzak@redhat.com>
Diffstat (limited to 'sys-utils/dmesg.c')
-rw-r--r--sys-utils/dmesg.c47
1 files changed, 35 insertions, 12 deletions
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;
}