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 <kzak@redhat.com>
This commit is contained in:
Karel Zak 2021-03-01 16:50:20 +01:00
parent 66134b5c2b
commit 50cc633257
1 changed files with 11 additions and 9 deletions

View File

@ -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);