]> git.ipfire.org Git - pakfire.git/commitdiff
pty: Automatically drain when the event loop finishes
authorMichael Tremer <michael.tremer@ipfire.org>
Tue, 18 Mar 2025 17:05:55 +0000 (17:05 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Tue, 18 Mar 2025 17:05:55 +0000 (17:05 +0000)
There was the problem that some content could have remained stuck in the
buffers on occasion.

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/jail.c
src/pakfire/pty.c
src/pakfire/pty.h

index 065b2cf41608c1cd61971fd727a8a3d88a93288d..cf13853068fc47855c7a4c71c7565bdf6e05d6d1 100644 (file)
@@ -982,9 +982,6 @@ static int pakfire_jail_exited(sd_event_source* source, const siginfo_t* si, voi
                        break;
        }
 
-       // Drain the PTY
-       pakfire_pty_drain(ctx->pty);
-
        // Terminate the event loop
        return sd_event_exit(ctx->loop, 0);
 }
index a343255ce5befde4e0e9751e7b0a4f1719b9129f..88c00ca545f4f073f6be77c58160cdf5e65d8f95 100644 (file)
@@ -97,6 +97,9 @@ struct pakfire_pty {
        // SIGWINCH Event
        sd_event_source* sigwinch_event;
 
+       // Exit Event
+       sd_event_source* exit_event;
+
        // State
        enum {
                PAKFIRE_PTY_STATE_INIT = 0,
@@ -257,6 +260,8 @@ static int pakfire_pty_disconnect(struct pakfire_pty* pty) {
                pty->stdout.event = sd_event_source_unref(pty->stdout.event);
        if (pty->sigwinch_event)
                pty->sigwinch_event = sd_event_source_unref(pty->sigwinch_event);
+       if (pty->exit_event)
+               pty->exit_event = sd_event_source_unref(pty->exit_event);
 
        // Close the PTY
        if (pty->master.fd >= 0) {
@@ -796,6 +801,42 @@ static int pakfire_pty_SIGWINCH(sd_event_source* source, const struct signalfd_s
        return 0;
 }
 
+static int pakfire_pty_drain(struct pakfire_pty* pty) {
+       // Log action
+       DEBUG(pty->ctx, "Draining requested\n");
+
+       // Update state
+       pty->state = PAKFIRE_PTY_STATE_DRAINING;
+
+       return pakfire_pty_drained(pty);
+}
+
+static int pakfire_pty_exit(sd_event_source* source, void* data) {
+       struct pakfire_pty* self = data;
+       int r;
+
+       DEBUG(self->ctx, "Exiting the PTY...\n");
+
+       // Unless we are already drained, try to drain all buffers
+       if (!pakfire_pty_drain(self)) {
+               if (!(self->master.io & PAKFIRE_PTY_HANGUP))
+                       self->master.io |= PAKFIRE_PTY_READY_TO_READ | PAKFIRE_PTY_READY_TO_WRITE;
+
+               if (!(self->stdin.io & PAKFIRE_PTY_HANGUP))
+                       self->stdin.io |= PAKFIRE_PTY_READY_TO_READ;
+
+               if (!(self->stdout.io & PAKFIRE_PTY_HANGUP))
+                       self->stdout.io |= PAKFIRE_PTY_READY_TO_WRITE;
+
+               // Keep forwarding...
+               r = pakfire_pty_forward(self);
+               if (r < 0)
+                       return r;
+       }
+
+       return pakfire_pty_done(self, 0);
+}
+
 static int pakfire_pty_activity(struct pakfire_pty* pty, struct pakfire_pty_stdio* stdio, uint32_t events) {
        // Do we have data to read?
        if (events & (EPOLLIN|EPOLLHUP))
@@ -1231,6 +1272,13 @@ static int pakfire_pty_setup(sd_event_source* source, int fd, uint32_t events, v
                return -errno;
        }
 
+       // Drain all buffers on exit
+       r = sd_event_add_exit(pty->loop, &pty->exit_event, pakfire_pty_exit, pty);
+       if (r < 0) {
+               ERROR(pty->ctx, "Could not register exit callback: %s\n", strerror(-r));
+               return r;
+       }
+
        // Setup forwarding
        r = pakfire_pty_setup_forwarding(pty);
        if (r < 0)
@@ -1495,12 +1543,6 @@ int pakfire_pty_open(struct pakfire_pty* pty) {
        return 0;
 }
 
-int pakfire_pty_drain(struct pakfire_pty* pty) {
-       pty->state = PAKFIRE_PTY_STATE_DRAINING;
-
-       return pakfire_pty_drained(pty);
-}
-
 /*
        Creates an independent copy of the output buffer
 */
index a8374def06836b85967f0e4db6d26924193891df..d6fc0d1c9f5ee8492513af679a94e3753d2d95fd 100644 (file)
@@ -48,8 +48,6 @@ struct pakfire_pty* pakfire_pty_unref(struct pakfire_pty* pty);
 
 int pakfire_pty_open(struct pakfire_pty* pty);
 
-int pakfire_pty_drain(struct pakfire_pty* pty);
-
 char* pakfire_pty_output(struct pakfire_pty* pty, size_t* length);
 
 typedef ssize_t (*pakfire_pty_stdin_callback)(