]> git.ipfire.org Git - pakfire.git/commitdiff
jail: Refactor streaming data into the jail
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Mar 2025 18:46:34 +0000 (18:46 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Mar 2025 18:46:34 +0000 (18:46 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/jail.c
src/pakfire/jail.h

index 2e66363da42ed2cdc2af7477537f91821e6766d0..3692929e313b94dccfd0049a0ab53b930ac54559 100644 (file)
@@ -49,6 +49,7 @@
 #include <systemd/sd-event.h>
 
 #include <pakfire/arch.h>
+#include <pakfire/buffer.h>
 #include <pakfire/cgroup.h>
 #include <pakfire/env.h>
 #include <pakfire/jail.h>
@@ -152,6 +153,10 @@ struct pakfire_jail_exec {
 #endif /* ENABLE_DEBUG */
        } streams;
 
+       // Standard Input Buffer
+       struct pakfire_buffer stdin;
+       int stdin_done;
+
        // Timeout
        sd_event_source* timeout;
 
@@ -401,6 +406,7 @@ static int pakfire_jail_stdin(sd_event_source* source, int fd, unsigned int even
        struct pakfire_jail_exec* exec = data;
        struct pakfire_jail* self = exec->jail;
        ssize_t bytes_written = 0;
+       ssize_t bytes_read = 0;
 
        // Fail if no callback is set
        if (unlikely(!exec->callbacks.input)) {
@@ -408,22 +414,46 @@ static int pakfire_jail_stdin(sd_event_source* source, int fd, unsigned int even
                goto CLOSE;
        }
 
-       // Call the callback
-       bytes_written = exec->callbacks.input(self->ctx, fd, exec->callbacks.input_data);
-       if (bytes_written < 0) {
-               ERROR(self->ctx, "The input callback failed: %s\n", strerror(-bytes_written));
-               return bytes_written;
+       for (;;) {
+               if (!exec->stdin_done) {
+                       bytes_read = pakfire_buffer_fill(&exec->stdin, self->ctx,
+                                       exec->callbacks.input, exec->callbacks.input_data);
+                       if (bytes_read < 0) {
+                               ERROR(self->ctx, "The input callback failed: %s\n", strerror(-bytes_read));
+                               return bytes_read;
+                       }
 
-       // Close the file descriptor if we are done reading
-       } else if (bytes_written == 0) {
-               goto CLOSE;
+                       // If we could not read any more from the callback, we are done
+                       if (bytes_read == 0)
+                               exec->stdin_done = 1;
+               }
+
+               // Write buffered data to the pipe
+               bytes_written = pakfire_buffer_write(&exec->stdin, fd);
+               if (bytes_written < 0) {
+                       switch (-bytes_written) {
+                               case EAGAIN:
+                                       return 0;
+
+                               default:
+                                       ERROR(self->ctx, "Failed to write to standard input: %s\n", strerror(-bytes_written));
+                                       return bytes_written;
+                       }
+               }
+
+               // Close if we have read all input data and flushed the entire buffer
+               if (exec->stdin_done && pakfire_buffer_is_empty(&exec->stdin))
+                       goto CLOSE;
        }
 
        return 0;
 
 CLOSE:
+       // Close the standard input file descriptors
        pakfire_jail_close_pipe(self, exec->pipes.stdin);
 
+       DEBUG(self->ctx, "Closed standard input\n");
+
        return 0;
 }
 
@@ -1642,7 +1672,7 @@ static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exe
 // Run a command in the jail
 static int __pakfire_jail_exec(struct pakfire_jail* jail,
                pakfire_jail_callback callback, void* data, int flags,
-               pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+               pakfire_jail_input_callback input_callback, void* input_data,
                pakfire_pty_stdout_callback stdout_callback, void* stdout_data,
                char** output, size_t* output_length) {
        struct pakfire_log_stream* stdout = NULL;
@@ -1696,6 +1726,9 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                goto ERROR;
        }
 
+       // Set the size for the input buffer
+       pakfire_buffer_set_max_length(&ctx.stdin, 4096);
+
        // Are we running in interactive mode?
        if (pakfire_jail_exec_has_flag(&ctx, PAKFIRE_JAIL_INTERACTIVE)) {
                // Setup the PTY
@@ -1720,6 +1753,10 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                        r = pakfire_jail_setup_pipe(jail, &ctx.pipes.stdin, 0);
                        if (r < 0)
                                goto ERROR;
+
+                       // Store the callback
+                       ctx.callbacks.input      = input_callback;
+                       ctx.callbacks.input_data = input_data;
                }
 
                // Create a pipe for standard output
@@ -1785,12 +1822,6 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                goto ERROR;
        }
 
-#if 0
-       // Configure the callbacks
-       if (stdin_callback)
-               pakfire_pty_set_stdin_callback(ctx.pty, stdin_callback, stdin_data);
-#endif
-
        // Setup pipes for logging
        // INFO
        r = pakfire_log_stream_create(&ctx.streams.INFO, jail->ctx, pakfire_jail_INFO, jail);
@@ -1977,7 +2008,7 @@ int pakfire_jail_exec_capture_output(struct pakfire_jail* jail,
 
 int pakfire_jail_communicate(
                struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
-               pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+               pakfire_jail_input_callback input_callback, void* input_data,
                pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
        struct pakfire_jail_command command = {
                .jail = jail,
@@ -1986,12 +2017,12 @@ int pakfire_jail_communicate(
        };
 
        return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
-               stdin_callback, stdin_data, stdout_callback, stdout_data, NULL, NULL);
+               input_callback, input_data, stdout_callback, stdout_data, NULL, NULL);
 }
 
 int pakfire_jail_exec_script(struct pakfire_jail* jail,
                const char* script, const size_t size, const char* args[], struct pakfire_env* env,
-               pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+               pakfire_jail_input_callback input_callback, void* input_data,
                pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
        char path[PATH_MAX];
        const char** argv = NULL;
@@ -2052,7 +2083,7 @@ int pakfire_jail_exec_script(struct pakfire_jail* jail,
 
        // Run the script
        r = pakfire_jail_communicate(jail, argv, env, 0,
-               stdin_callback, stdin_data, stdout_callback, stdout_data);
+               input_callback, input_data, stdout_callback, stdout_data);
 
 ERROR:
        if (argv)
index bfb5c490b908d7838cb2d9a38a3163435325d87b..16829960294abfcbce8df7a45d6d3f8c264332d2 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef PAKFIRE_JAIL_H
 #define PAKFIRE_JAIL_H
 
+#include <pakfire/buffer.h>
 #include <pakfire/cgroup.h>
 #include <pakfire/env.h>
 #include <pakfire/pakfire.h>
@@ -28,6 +29,9 @@
 
 struct pakfire_jail;
 
+// Input callback
+typedef pakfire_buffer_input_callback pakfire_jail_input_callback;
+
 int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire);
 
 struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail);
@@ -66,7 +70,7 @@ int pakfire_jail_set_cgroup(struct pakfire_jail* jail, struct pakfire_cgroup* cg
 
 int pakfire_jail_communicate(
        struct pakfire_jail* jail, const char* argv[], struct pakfire_env* env, int flags,
-       pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+       pakfire_jail_input_callback input_callback, void* input_data,
        pakfire_log_stream_callback stdout_callback, void* stdout_data);
 
 // Convenience functions
@@ -77,7 +81,7 @@ int pakfire_jail_run_script(struct pakfire* pakfire,
 
 int pakfire_jail_exec_script(struct pakfire_jail* jail,
        const char* script, const size_t size, const char* args[], struct pakfire_env* env,
-       pakfire_pty_stdin_callback stdin_callback, void* stdin_data,
+       pakfire_jail_input_callback input_callback, void* input_data,
        pakfire_pty_stdout_callback stdout_callback, void* stdout_data);
 
 int pakfire_jail_shell(struct pakfire_jail* jail, struct pakfire_env* env);