]> git.ipfire.org Git - thirdparty/util-linux.git/commitdiff
more: make sure we have data on stderr
authorKarel Zak <kzak@redhat.com>
Thu, 22 Aug 2024 06:56:52 +0000 (08:56 +0200)
committerKarel Zak <kzak@redhat.com>
Fri, 3 Jan 2025 11:21:42 +0000 (12:21 +0100)
more(1) uses more_poll() to monitor data on stdin, stderr, and
signals. It is used before read_command(), but this function only
reads from stderr. Therefore, if any other non-stderr event occurs,
this function will wait on read(). In this case, more(1) will not
react to signals anymore. We need to ensure that more(1) only waits in
more_poll().

Try

 for x in {1..1000}; do echo "line $x"; done | more

to reproduce.

Reported-by: Radka Skvarilova <rskvaril@redhat.com>
Signed-off-by: Karel Zak <kzak@redhat.com>
(cherry picked from commit 640b9480bd3efc0f4bc7f38a785d02cda70ec5c3)

text-utils/more.c

index 1badf67d55dbc59fe95e7f1e4b5a5fd3bfd3de94..38a2266381695c70133493724da34490df00d0dc 100644 (file)
@@ -1350,7 +1350,7 @@ static void read_line(struct more_control *ctl)
 }
 
 /* returns: 0 timeout or nothing; <0 error, >0 success */
-static int more_poll(struct more_control *ctl, int timeout)
+static int more_poll(struct more_control *ctl, int timeout, int *stderr_active)
 {
        enum {
                POLLFD_SIGNAL = 0,
@@ -1364,6 +1364,9 @@ static int more_poll(struct more_control *ctl, int timeout)
        };
        int has_data = 0;
 
+       if (stderr_active)
+               *stderr_active = 0;
+
        while (!has_data) {
                int rc;
 
@@ -1430,8 +1433,11 @@ static int more_poll(struct more_control *ctl, int timeout)
                }
 
                /* event on stderr (we reads user commands from stderr!) */
-               if (pfd[POLLFD_STDERR].revents)
+               if (pfd[POLLFD_STDERR].revents) {
                        has_data++;
+                       if (stderr_active)
+                               *stderr_active = 1;
+               }
        }
 
        return has_data;
@@ -1502,7 +1508,7 @@ static void search(struct more_control *ctl, char buf[], int n)
                        }
                        break;
                }
-               more_poll(ctl, 0);
+               more_poll(ctl, 0, NULL);
        }
        /* Move ctrl+c signal handling back to more_key_command(). */
        signal(SIGINT, SIG_DFL);
@@ -1656,7 +1662,7 @@ static int skip_forwards(struct more_control *ctl, int nlines, cc_t comchar)
 static int more_key_command(struct more_control *ctl, char *filename)
 {
        int retval = 0;
-       int done = 0, search_again = 0;
+       int done = 0, search_again = 0, stderr_active = 0;
        char cmdbuf[INIT_BUF];
        struct number_command cmd;
 
@@ -1666,7 +1672,9 @@ static int more_key_command(struct more_control *ctl, char *filename)
                ctl->report_errors = 0;
        ctl->search_called = 0;
        for (;;) {
-               if (more_poll(ctl, -1) <= 0)
+               if (more_poll(ctl, -1, &stderr_active) <= 0)
+                       continue;
+               if (stderr_active == 0)
                        continue;
                cmd = read_command(ctl);
                if (cmd.key == more_kc_unknown_command)