From 50cc633257aa0844dd01e9572d6b0ddbfb19f6d5 Mon Sep 17 00:00:00 2001 From: Karel Zak Date: Mon, 1 Mar 2021 16:50:20 +0100 Subject: [PATCH] dmesg: fix and cleanup --read-clear The function read_buffer() implements read and clear functionally, but we do not differentiate between these actions in main() for error messages, and one generic "dmesg: read kernel buffer failed" is used in all cases. That's a bug. This patch removes the "clear" action from read_buffer() and keeps it for buffer reading only. The "clear" action is implemented in main() by separate klogctl(SYSLOG_ACTION_CLEAR) for cases. It means also for "dmesg --read-clear"; we do not use SYSLOG_ACTION_READ_CLEAR anymore. Now "clear+read" is: * syslog: SYSLOG_ACTION_READ_ALL + SYSLOG_ACTION_CLEAR * kmsg: /dev/kmsg read() + SYSLOG_ACTION_CLEAR In old versions "dmesg --syslog --read-clear" (syalog backed) was implemented by logctl(SYSLOG_ACTION_READ_CLEAR) and it returns no data for non-root users (due to EPERM), "dmesg --read-clear" (kmsg) returns data and EPERM for the "clear" action. Now the command "dmesg --syslog --read-clear" and "dmesg --read-clear" behaves in the same way -- returns data and EPERM for the "clear" action. Fixes: https://github.com/karelzak/util-linux/issues/1255 Signed-off-by: Karel Zak --- sys-utils/dmesg.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/sys-utils/dmesg.c b/sys-utils/dmesg.c index fa1dd2dff..ba9a749b2 100644 --- a/sys-utils/dmesg.c +++ b/sys-utils/dmesg.c @@ -558,7 +558,7 @@ static ssize_t read_syslog_buffer(struct dmesg_control *ctl, char **buf) if (ctl->bufsize) { sz = ctl->bufsize + 8; *buf = xmalloc(sz * sizeof(char)); - rc = klogctl(ctl->action, *buf, sz); + rc = klogctl(SYSLOG_ACTION_READ_ALL, *buf, sz); } else { sz = 16392; while (1) { @@ -572,9 +572,6 @@ static ssize_t read_syslog_buffer(struct dmesg_control *ctl, char **buf) *buf = NULL; sz *= 4; } - - if (rc > 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR) - rc = klogctl(SYSLOG_ACTION_READ_CLEAR, *buf, sz); } return rc; @@ -602,8 +599,6 @@ static ssize_t read_buffer(struct dmesg_control *ctl, char **buf) * Since kernel 3.5.0 */ n = read_kmsg(ctl); - if (n == 0 && ctl->action == SYSLOG_ACTION_READ_CLEAR) - n = klogctl(SYSLOG_ACTION_CLEAR, NULL, 0); break; default: abort(); /* impossible method -> drop core */ @@ -1597,12 +1592,19 @@ int main(int argc, char *argv[]) print_buffer(&ctl, buf, n); if (!ctl.mmap_buff) free(buf); - if (n < 0) - err(EXIT_FAILURE, _("read kernel buffer failed")); if (ctl.kmsg >= 0) close(ctl.kmsg); - break; + if (n < 0) + err(EXIT_FAILURE, _("read kernel buffer failed")); + if (n >= 0 + && ctl.action == SYSLOG_ACTION_READ_CLEAR) + ; /* fallthrough */ + else + break; case SYSLOG_ACTION_CLEAR: + if (klogctl(SYSLOG_ACTION_CLEAR, NULL, 0) < 0) + err(EXIT_FAILURE, _("clear kernel buffer failed")); + break; case SYSLOG_ACTION_CONSOLE_OFF: case SYSLOG_ACTION_CONSOLE_ON: klog_rc = klogctl(ctl.action, NULL, 0);