// SIGWINCH Event
sd_event_source* sigwinch_event;
+
+ // State
+ enum {
+ PAKFIRE_PTY_STATE_INIT = 0,
+ PAKFIRE_PTY_STATE_FORWARDING,
+ PAKFIRE_PTY_STATE_DRAINING,
+ PAKFIRE_PTY_STATE_DONE,
+ } state;
};
+static int pakfire_pty_drained(struct pakfire_pty* pty) {
+ int q;
+ int r;
+
+ // We still have data in the buffer
+ if (pty->stdout.buffered)
+ return 0;
+
+ // There is still data in the PTY buffer
+ if (pty->master.io & PAKFIRE_PTY_READY_TO_READ)
+ return 0;
+
+ // Is there anything in the input buffer?
+ r = ioctl(pty->master.fd, TIOCINQ, &q);
+ if (r < 0) {
+ CTX_DEBUG(pty->ctx, "TIOCINQ failed on master fd %d: %m\n", pty->master.fd);
+ return -errno;
+ }
+
+ if (q)
+ return 0;
+
+ // Is there anything in the output buffer?
+ r = ioctl(pty->master.fd, TIOCOUTQ, &q);
+ if (r < 0) {
+ CTX_DEBUG(pty->ctx, "TIOCOUTQ failed on master fd %d: %m\n", pty->master.fd);
+ return -errno;
+ }
+
+ if (q)
+ return 0;
+
+ // We are fully drained
+ return 1;
+}
+
+static int pakfire_pty_done(struct pakfire_pty* pty, int code) {
+ sd_event* loop = NULL;
+
+ // Don't run this more than once
+ if (pty->state == PAKFIRE_PTY_STATE_DONE)
+ return 0;
+
+ // Fetch a reference to the event loop
+ loop = sd_event_ref(pty->loop);
+
+ // Terminate the event loop
+ return sd_event_exit(loop, code < 0 ? EXIT_FAILURE : code);
+}
+
/*
Reads as much data as possible into the buffer
*/
static int pakfire_pty_forward(struct pakfire_pty* pty) {
int r;
+ // Make sure we are in the correct state
+ switch (pty->state) {
+ case PAKFIRE_PTY_STATE_FORWARDING:
+ case PAKFIRE_PTY_STATE_DRAINING:
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
while (pty->master.io || pty->stdin.io || pty->stdout.io) {
// Read from standard input
if (pty->stdin.io & PAKFIRE_PTY_READY_TO_READ) {
}
}
+ // If we have been requested to drain, and are fully drained, we are done
+ if (pty->state == PAKFIRE_PTY_STATE_DRAINING && pakfire_pty_drained(pty))
+ return pakfire_pty_done(pty, 0);
+
return 0;
}
CTX_DEBUG(pty->ctx, "Setting up PTY Forwarding...\n");
+ // Mark as forwarding
+ pty->state = PAKFIRE_PTY_STATE_FORWARDING;
+
// Connect to standard input/output
pty->stdin.fd = STDIN_FILENO;
pty->stdout.fd = STDOUT_FILENO;
return 0;
}
+
+int pakfire_pty_drain(struct pakfire_pty* pty) {
+ pty->state = PAKFIRE_PTY_STATE_DRAINING;
+
+ return pakfire_pty_drained(pty);
+}