]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
dmesg: fix and cleanup --read-clear
authorKarel Zak <kzak@redhat.com>
Mon, 1 Mar 2021 15:50:20 +0000 (16:50 +0100)
committerKarel Zak <kzak@redhat.com>
Mon, 1 Mar 2021 15:50:20 +0000 (16:50 +0100)
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>
sys-utils/dmesg.c

index fa1dd2dffce5a6b2da659039d600af7bdcc0417c..ba9a749b2eddc79c4fc37281e1785fe26d5f3cb1 100644 (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);