From 2cf87464d468ac9055d2d3aab69a5c4906a05f8c Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 20 Mar 2025 11:30:38 +0000 Subject: [PATCH] pty: Add a function to set up interactive mode This way we can split off the initialization code a little bit better from the main initialization of the PTY object. Signed-off-by: Michael Tremer --- src/pakfire/jail.c | 32 +++++++------- src/pakfire/pty.c | 108 ++++++++++++++++++--------------------------- src/pakfire/pty.h | 10 +---- 3 files changed, 60 insertions(+), 90 deletions(-) diff --git a/src/pakfire/jail.c b/src/pakfire/jail.c index d1d992dd..b9da3124 100644 --- a/src/pakfire/jail.c +++ b/src/pakfire/jail.c @@ -1344,7 +1344,6 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail, pakfire_pty_stdin_callback stdin_callback, void* stdin_data, pakfire_pty_stdout_callback stdout_callback, void* stdout_data, char** output, size_t* output_length) { - int pty_flags = 0; int r; // We cannot have both, an output callback and buffer @@ -1390,10 +1389,17 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail, goto ERROR; } + // Setup the PTY + r = pakfire_pty_create(&ctx.pty, jail->ctx, ctx.loop); + if (r < 0) + goto ERROR; + // Are we running in interactive mode? if (pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_INTERACTIVE)) { // Make the PTY interactive - pty_flags |= PAKFIRE_PTY_INTERACTIVE; + r = pakfire_pty_interactive(ctx.pty); + if (r < 0) + goto ERROR; // Enable networking ctx.flags |= PAKFIRE_JAIL_HAS_NETWORKING; @@ -1409,6 +1415,14 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail, } else if (stdout_callback) { // Nothing + // Capture Output? + } else if (output) { + r = pakfire_pty_capture_output(ctx.pty, output, output_length); + if (r < 0) { + ERROR(jail->ctx, "Failed to set up output capture: %s\n", strerror(-r)); + goto ERROR; + } + // Otherwise we dump everything to the console } else { // XXX Need to find a solution about what to do here... @@ -1424,20 +1438,6 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail, goto ERROR; } - // Setup the PTY - r = pakfire_pty_create(&ctx.pty, jail->ctx, ctx.loop, pty_flags); - if (r) - goto ERROR; - - // Capture Output? - if (output) { - r = pakfire_pty_capture_output(ctx.pty, output, output_length); - if (r < 0) { - ERROR(jail->ctx, "Failed to set up output capture: %s\n", strerror(-r)); - goto ERROR; - } - } - // Configure the callbacks if (stdin_callback) pakfire_pty_set_stdin_callback(ctx.pty, stdin_callback, stdin_data); diff --git a/src/pakfire/pty.c b/src/pakfire/pty.c index edbb100d..b565a6b8 100644 --- a/src/pakfire/pty.c +++ b/src/pakfire/pty.c @@ -76,9 +76,6 @@ struct pakfire_pty { struct pakfire_ctx* ctx; int nrefs; - // Flags - int flags; - // Event Loop sd_event* loop; @@ -113,10 +110,6 @@ struct pakfire_pty { FILE* output; }; -static int pakfire_pty_has_flag(struct pakfire_pty* pty, int flag) { - return pty->flags & flag; -} - static int pakfire_pty_same_inode(struct pakfire_pty* pty, int fd1, int fd2) { struct stat stat1; struct stat stat2; @@ -1034,50 +1027,6 @@ static int pakfire_pty_setup_forwarding(struct pakfire_pty* pty) { // Mark as forwarding pty->state = PAKFIRE_PTY_STATE_FORWARDING; - // Connect to standard input - if (pakfire_pty_has_flag(pty, PAKFIRE_PTY_INTERACTIVE)) { - pty->stdin.fd = pakfire_pty_reopen(pty, STDIN_FILENO, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); - if (pty->stdin.fd < 0) { - DEBUG(pty->ctx, "Could not re-open standard input: %s. Ignoring.\n", strerror(-pty->stdin.fd)); - - // Use the original file descriptor - pty->stdin.fd = STDIN_FILENO; - - // Request to close the file descriptor afterwards - } else { - pty->stdin.close_fd = 1; - } - } - - // Create a buffer to capture the output in - if (pakfire_pty_has_flag(pty, PAKFIRE_PTY_CAPTURE_OUTPUT)) { - pty->stdout.fd = memfd_create("pty-output", MFD_CLOEXEC); - if (pty->stdout.fd < 0) { - ERROR(pty->ctx, "Could not create the output buffer: %m\n"); - return -errno; - } - - // Map any CRNL to NL - pty->stdout.io |= PAKFIRE_PTY_MAP_CRNL; - - // Close the buffer in the end - pty->stdout.close_fd = 1; - - // Connect to standard output - } else if (pakfire_pty_has_flag(pty, PAKFIRE_PTY_INTERACTIVE)) { - pty->stdout.fd = pakfire_pty_reopen(pty, STDOUT_FILENO, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); - if (pty->stdout.fd < 0) { - DEBUG(pty->ctx, "Could not re-open standard output: %s. Ignoring.\n", strerror(-pty->stdout.fd)); - - // Use the original file descriptor - pty->stdout.fd = STDOUT_FILENO; - - // Request to close the file descriptor afterwards - } else { - pty->stdout.close_fd = 1; - } - } - // Copy the terminal dimensions to the PTY if (isatty(pty->stdout.fd)) { // Fetch dimensions @@ -1275,8 +1224,7 @@ static void pakfire_pty_free(struct pakfire_pty* pty) { free(pty); } -int pakfire_pty_create(struct pakfire_pty** pty, struct pakfire_ctx* ctx, - sd_event* loop, int flags) { +int pakfire_pty_create(struct pakfire_pty** pty, struct pakfire_ctx* ctx, sd_event* loop) { struct pakfire_pty* p = NULL; int r; @@ -1294,19 +1242,6 @@ int pakfire_pty_create(struct pakfire_pty** pty, struct pakfire_ctx* ctx, // Store a reference to the event loop p->loop = sd_event_ref(loop); - // Store the flags - p->flags = flags; - - // Connect stdout if we want to capture the output - if (pakfire_pty_has_flag(p, PAKFIRE_PTY_CAPTURE_OUTPUT)) - p->stdout.io |= PAKFIRE_PTY_CONNECT; - - // Connect everything when we are in interactive mode - else if (pakfire_pty_has_flag(p, PAKFIRE_PTY_INTERACTIVE)) { - p->stdin.io |= PAKFIRE_PTY_CONNECT; - p->stdout.io |= PAKFIRE_PTY_CONNECT; - } - // Initialize the master file descriptor p->master.fd = -EBADF; @@ -1541,6 +1476,47 @@ int pakfire_pty_capture_output(struct pakfire_pty* self, char** output, size_t* return 0; } +/* + Interactive Mode +*/ +int pakfire_pty_interactive(struct pakfire_pty* self) { + // Fail if something is already open + if (self->stdin.fd >= 0 || self->stdout.fd >= 0) + return -ENOTSUP; + + // Open standard input + self->stdin.fd = pakfire_pty_reopen(self, STDIN_FILENO, O_RDONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (self->stdin.fd < 0) { + DEBUG(self->ctx, "Could not re-open standard input: %s. Ignoring.\n", strerror(-self->stdin.fd)); + + // Use the original file descriptor + self->stdin.fd = STDIN_FILENO; + + // Request to close the file descriptor afterwards + } else { + self->stdin.close_fd = 1; + } + + // Open standard output + self->stdout.fd = pakfire_pty_reopen(self, STDOUT_FILENO, O_WRONLY|O_CLOEXEC|O_NOCTTY|O_NONBLOCK); + if (self->stdout.fd < 0) { + DEBUG(self->ctx, "Could not re-open standard output: %s. Ignoring.\n", strerror(-self->stdout.fd)); + + // Use the original file descriptor + self->stdout.fd = STDOUT_FILENO; + + // Request to close the file descriptor afterwards + } else { + self->stdout.close_fd = 1; + } + + // Connect everything + self->stdin.io |= PAKFIRE_PTY_CONNECT; + self->stdout.io |= PAKFIRE_PTY_CONNECT; + + return 0; +} + /* Standard Input/Output Callbacks */ diff --git a/src/pakfire/pty.h b/src/pakfire/pty.h index c4af39b4..a45e53f0 100644 --- a/src/pakfire/pty.h +++ b/src/pakfire/pty.h @@ -29,20 +29,14 @@ struct pakfire_pty; -enum pakfire_pty_flags { - PAKFIRE_PTY_NONE = 0, - PAKFIRE_PTY_INTERACTIVE = (1 << 0), - PAKFIRE_PTY_CAPTURE_OUTPUT = (1 << 1), -}; - -int pakfire_pty_create(struct pakfire_pty** pty, - struct pakfire_ctx* ctx, sd_event* loop, int flags); +int pakfire_pty_create(struct pakfire_pty** pty, struct pakfire_ctx* ctx, sd_event* loop); struct pakfire_pty* pakfire_pty_ref(struct pakfire_pty* pty); struct pakfire_pty* pakfire_pty_unref(struct pakfire_pty* pty); int pakfire_pty_open(struct pakfire_pty* pty); +int pakfire_pty_interactive(struct pakfire_pty* pty); int pakfire_pty_capture_output(struct pakfire_pty* pty, char** output, size_t* length); typedef ssize_t (*pakfire_pty_stdin_callback)( -- 2.39.5