]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
ptyfwd: do not try to read master if already disconnected
authorYu Watanabe <watanabe.yu+github@gmail.com>
Mon, 28 Jul 2025 15:47:45 +0000 (00:47 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Tue, 29 Jul 2025 16:15:29 +0000 (01:15 +0900)
When PTYForward.done is set, the PTYForward.master is already
disconnected. Let's not try to read the already closed file descriptor.

Also, if we previously received vhangup, then it is not necessary to
re-read the device to check vhangup, as we already know.

This also make the check slightly delayed, and use a defer event source,
to make the function can be called safely in another event source.

src/shared/ptyfwd.c

index 543466ceb733378175df7b810853fec9b7dfd906..bc312f17019c52d5a486e2653e66da5680efcfc3 100644 (file)
@@ -60,6 +60,7 @@ struct PTYForward {
         sd_event_source *master_event_source;
         sd_event_source *sigwinch_event_source;
         sd_event_source *exit_event_source;
+        sd_event_source *defer_event_source;
 
         struct termios saved_stdin_attr;
         struct termios saved_stdout_attr;
@@ -122,6 +123,7 @@ static void pty_forward_disconnect(PTYForward *f) {
         f->master_event_source = sd_event_source_unref(f->master_event_source);
         f->sigwinch_event_source = sd_event_source_unref(f->sigwinch_event_source);
         f->exit_event_source = sd_event_source_unref(f->exit_event_source);
+        f->defer_event_source = sd_event_source_unref(f->defer_event_source);
         f->event = sd_event_unref(f->event);
 
         if (f->output_fd >= 0) {
@@ -892,6 +894,23 @@ static int on_exit_event(sd_event_source *e, void *userdata) {
         return pty_forward_done(f, 0);
 }
 
+static int on_defer_event(sd_event_source *s, void *userdata) {
+        PTYForward *f = ASSERT_PTR(userdata);
+        return shovel_force(f);
+}
+
+static int pty_forward_add_defer(PTYForward *f) {
+        assert(f);
+
+        if (f->done)
+                return 0;
+
+        if (f->defer_event_source)
+                return sd_event_source_set_enabled(f->defer_event_source, SD_EVENT_ONESHOT);
+
+        return sd_event_add_defer(f->event, &f->defer_event_source, on_defer_event, f);
+}
+
 int pty_forward_new(
                 sd_event *event,
                 int master,
@@ -1083,9 +1102,11 @@ int pty_forward_honor_vhangup(PTYForward *f) {
 
         f->flags &= ~(PTY_FORWARD_IGNORE_VHANGUP | PTY_FORWARD_IGNORE_INITIAL_VHANGUP);
 
-        /* We shall now react to vhangup()s? Let's check immediately if we might be in one. */
-        f->master_readable = true;
-        return shovel(f);
+        if (f->master_hangup)
+                return 0;
+
+        /* We shall now react to vhangup()s? Let's check if we might be in one. */
+        return pty_forward_add_defer(f);
 }
 
 bool pty_forward_vhangup_honored(const PTYForward *f) {