From: Michael Tremer Date: Tue, 18 Mar 2025 17:05:55 +0000 (+0000) Subject: pty: Automatically drain when the event loop finishes X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=5cf2d4d5b0f7fb283301b7d18ddf2049e179c531;p=pakfire.git pty: Automatically drain when the event loop finishes There was the problem that some content could have remained stuck in the buffers on occasion. Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/jail.c b/src/pakfire/jail.c index 065b2cf4..cf138530 100644 --- a/src/pakfire/jail.c +++ b/src/pakfire/jail.c @@ -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); } diff --git a/src/pakfire/pty.c b/src/pakfire/pty.c index a343255c..88c00ca5 100644 --- a/src/pakfire/pty.c +++ b/src/pakfire/pty.c @@ -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 */ diff --git a/src/pakfire/pty.h b/src/pakfire/pty.h index a8374def..d6fc0d1c 100644 --- a/src/pakfire/pty.h +++ b/src/pakfire/pty.h @@ -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)(