]> git.ipfire.org Git - pakfire.git/commitdiff
jail: Refactor the output callback
authorMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Mar 2025 19:27:24 +0000 (19:27 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Mon, 24 Mar 2025 19:27:24 +0000 (19:27 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
src/pakfire/build.c
src/pakfire/jail.c
src/pakfire/jail.h
src/python/pakfire.c
tests/libpakfire/jail.c

index 613889cb1f1f1d409e340bb75f3497317c3f7a23..4ac347844191bdd0b63dc2cdcc66e0956e0faa68 100644 (file)
@@ -44,6 +44,7 @@
 #include <pakfire/parser.h>
 #include <pakfire/path.h>
 #include <pakfire/problem.h>
+#include <pakfire/pty.h>
 #include <pakfire/repo.h>
 #include <pakfire/scriptlet.h>
 #include <pakfire/solution.h>
@@ -126,8 +127,8 @@ static double pakfire_build_duration(struct pakfire_build* build) {
        return pakfire_timespec_delta(&now, &build->time_start);
 }
 
-static int pakfire_build_output_callback(
-               struct pakfire_ctx* ctx, void* data, const char* buffer, size_t length) {
+static int pakfire_build_output_callback(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, size_t length) {
        struct pakfire_build* build = data;
 
        // Get the runtime of the build
@@ -140,14 +141,29 @@ static int pakfire_build_output_callback(
        const unsigned int s  = (unsigned int)t % 60;
        const unsigned int ms = (unsigned int)(t * 1000.0) % 1000;
 
-       if (h)
-               INFO(ctx, "[%02u:%02u:%02u.%04u] %.*s", h, m, s, ms, (int)length, buffer);
+       switch (stream) {
+               case PAKFIRE_STDOUT:
+                       if (h)
+                               INFO(ctx, "[%02u:%02u:%02u.%04u] %.*s", h, m, s, ms, (int)length, line);
 
-       else if (m)
-               INFO(ctx, "[   %02u:%02u.%04u] %.*s", m, s, ms, (int)length, buffer);
+                       else if (m)
+                               INFO(ctx, "[   %02u:%02u.%04u] %.*s", m, s, ms, (int)length, line);
 
-       else
-               INFO(ctx, "[      %02u.%04u] %.*s", s, ms, (int)length, buffer);
+                       else
+                               INFO(ctx, "[      %02u.%04u] %.*s", s, ms, (int)length, line);
+                       break;
+
+               case PAKFIRE_STDERR:
+                       if (h)
+                               ERROR(ctx, "[%02u:%02u:%02u.%04u] %.*s", h, m, s, ms, (int)length, line);
+
+                       else if (m)
+                               ERROR(ctx, "[   %02u:%02u.%04u] %.*s", m, s, ms, (int)length, line);
+
+                       else
+                               ERROR(ctx, "[      %02u.%04u] %.*s", s, ms, (int)length, line);
+                       break;
+       }
 
        return 0;
 }
@@ -267,7 +283,7 @@ static int pakfire_build_run_script(
                const char* filename,
                const char* args[],
                pakfire_jail_input_callback input_callback, void* input_data,
-               pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
+               pakfire_jail_output_callback output_callback, void* output_data) {
        char* script = NULL;
        size_t length = 0;
        int r;
@@ -283,7 +299,7 @@ static int pakfire_build_run_script(
 
        // Execute the script
        r = pakfire_jail_exec_script(build->jail, script, length, args, build->env,
-                       input_callback, input_data, stdout_callback, stdout_data);
+                       input_callback, input_data, output_callback, output_data);
        if (r)
                ERROR(build->ctx, "Script '%s' failed with status %d\n", filename, r);
 
@@ -360,18 +376,42 @@ static int pakfire_build_process_pkgconfig_dep(struct pakfire_package* pkg,
        return 0;
 }
 
-static int pakfire_build_process_pkgconfig_provides(
-               struct pakfire_ctx* ctx, void* data, const char* line, const size_t length) {
+static int pakfire_build_process_pkgconfig_provides(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, const size_t length) {
        struct pakfire_find_deps_ctx* deps = data;
+       struct pakfire_build* self = deps->build;
+
+       switch (stream) {
+               // Process any output
+               case PAKFIRE_STDOUT:
+                       return pakfire_build_process_pkgconfig_dep(deps->pkg, PAKFIRE_PKG_PROVIDES, line, length);
 
-       return pakfire_build_process_pkgconfig_dep(deps->pkg, PAKFIRE_PKG_PROVIDES, line, length);
+               // Log any errors
+               case PAKFIRE_STDERR:
+                       ERROR(self->ctx, "%.*s", (int)length, line);
+                       break;
+       }
+
+       return 0;
 }
 
-static int pakfire_build_process_pkgconfig_requires(
-               struct pakfire_ctx* ctx, void* data, const char* line, const size_t length) {
+static int pakfire_build_process_pkgconfig_requires(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, const size_t length) {
        struct pakfire_find_deps_ctx* deps = data;
+       struct pakfire_build* self = deps->build;
+
+       switch (stream) {
+               // Process any output
+               case PAKFIRE_STDOUT:
+                       return pakfire_build_process_pkgconfig_dep(deps->pkg, PAKFIRE_PKG_REQUIRES, line, length);
 
-       return pakfire_build_process_pkgconfig_dep(deps->pkg, PAKFIRE_PKG_REQUIRES, line, length);
+               // Log any errors
+               case PAKFIRE_STDERR:
+                       ERROR(self->ctx, "%.*s", (int)length, line);
+                       break;
+       }
+
+       return 0;
 }
 
 static int pakfire_build_find_pkgconfig_provides(
@@ -721,18 +761,40 @@ static int pakfire_build_add_perl_dep(struct pakfire_ctx* ctx, struct pakfire_pa
        return pakfire_package_add_dep(pkg, key, "%.*s", (int)length, line);
 }
 
-static int pakfire_build_add_perl_provides(struct pakfire_ctx* ctx,
-               void* data, const char* line, size_t length) {
+static int pakfire_build_add_perl_provides(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, size_t length) {
        struct pakfire_package* pkg = data;
 
-       return pakfire_build_add_perl_dep(ctx, pkg, PAKFIRE_PKG_PROVIDES, line, length);
+       switch (stream) {
+               // Process output
+               case PAKFIRE_STDOUT:
+                       return pakfire_build_add_perl_dep(ctx, pkg, PAKFIRE_PKG_PROVIDES, line, length);
+
+               // Log errors
+               case PAKFIRE_STDERR:
+                       ERROR(ctx, "%.*s", (int)length, line);
+                       break;
+       }
+
+       return 0;
 }
 
-static int pakfire_build_add_perl_requires(struct pakfire_ctx* ctx,
-               void* data, const char* line, size_t length) {
+static int pakfire_build_add_perl_requires(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, size_t length) {
        struct pakfire_package* pkg = data;
 
-       return pakfire_build_add_perl_dep(ctx, pkg, PAKFIRE_PKG_REQUIRES, line, length);
+       switch (stream) {
+               // Process output
+               case PAKFIRE_STDOUT:
+                       return pakfire_build_add_perl_dep(ctx, pkg, PAKFIRE_PKG_REQUIRES, line, length);
+
+               // Log errors
+               case PAKFIRE_STDERR:
+                       ERROR(ctx, "%.*s", (int)length, line);
+                       break;
+       }
+
+       return 0;
 }
 
 static int pakfire_build_find_perl_deps(struct pakfire_build* build,
@@ -992,47 +1054,58 @@ static int pakfire_build_extract_command(
        return __pakfire_string_setn(command, lcommand, s, l);
 }
 
-static int pakfire_build_process_scriptlet_dep(
-               struct pakfire_ctx* ctx, void* data, const char* line, const size_t length) {
+static int pakfire_build_process_scriptlet_dep(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, const size_t length) {
        struct pakfire_find_deps_ctx* deps = data;
+       struct pakfire_build* self = deps->build;
        char command[PATH_MAX];
        char path[PATH_MAX];
        int r;
 
-       // Try to extract the command
-       r = pakfire_build_extract_command(command, sizeof(command), line, length);
-       if (r < 0) {
-               switch (-r) {
-                       // Ignore if the string was presumed to be invalid (some other format)
-                       case EINVAL:
-                               DEBUG(ctx, "Ignoring invalid line %.*s\n", (int)length, line);
-                               return 0;
+       switch (stream) {
+               // Process output
+               case PAKFIRE_STDOUT:
+                       // Try to extract the command
+                       r = pakfire_build_extract_command(command, sizeof(command), line, length);
+                       if (r < 0) {
+                               switch (-r) {
+                                       // Ignore if the string was presumed to be invalid (some other format)
+                                       case EINVAL:
+                                               DEBUG(ctx, "Ignoring invalid line %.*s\n", (int)length, line);
+                                               return 0;
+
+                                       default:
+                                               return r;
+                               }
+                       }
 
-                       default:
-                               return r;
-               }
-       }
+                       DEBUG(ctx, "Found '%s' as a dependency of the scriptlet\n", command);
 
-       DEBUG(ctx, "Found '%s' as a dependency of the scriptlet\n", command);
+                       // Add absolute paths just like that
+                       if (pakfire_path_is_absolute(command)) {
+                               r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PREREQUIRES, "%s", command);
+                               if (r < 0)
+                                       return r;
 
-       // Add absolute paths just like that
-       if (pakfire_path_is_absolute(command)) {
-               r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PREREQUIRES, "%s", command);
-               if (r < 0)
-                       return r;
+                       // Otherwise, we will have to resolve the command
+                       } else {
+                               r = pakfire_which(deps->build->pakfire, path, command);
+                               if (r < 0)
+                                       return r;
 
-       // Otherwise, we will have to resolve the command
-       } else {
-               r = pakfire_which(deps->build->pakfire, path, command);
-               if (r < 0)
-                       return r;
+                               // If we could resolve the command, we add the full path
+                               if (*path) {
+                                       r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PREREQUIRES, "%s", path);
+                                       if (r < 0)
+                                               return r;
+                               }
+                       }
+                       break;
 
-               // If we could resolve the command, we add the full path
-               if (*path) {
-                       r = pakfire_package_add_dep(deps->pkg, PAKFIRE_PKG_PREREQUIRES, "%s", path);
-                       if (r < 0)
-                               return r;
-               }
+               // Log errors
+               case PAKFIRE_STDERR:
+                       ERROR(self->ctx, "%.*s", (int)length, line);
+                       break;
        }
 
        return 0;
index 3692929e313b94dccfd0049a0ab53b930ac54559..6d88b8d7e91794c1f07636adac47dfed9a0bae51 100644 (file)
@@ -578,6 +578,26 @@ static int pakfire_jail_DEBUG(struct pakfire_ctx* ctx, void* data, const char* l
 }
 #endif /* ENABLE_DEBUG */
 
+static int pakfire_jail_output_stdout(struct pakfire_ctx* ctx, void* data, const char* line, size_t length) {
+       struct pakfire_jail_exec* exec = data;
+
+       // Do nothing if we don't have a callback
+       if (!exec->callbacks.output)
+               return 0;
+
+       return exec->callbacks.output(ctx, exec->callbacks.output_data, PAKFIRE_STDOUT, line, length);
+}
+
+static int pakfire_jail_output_stderr(struct pakfire_ctx* ctx, void* data, const char* line, size_t length) {
+       struct pakfire_jail_exec* exec = data;
+
+       // Do nothing if we don't have a callback
+       if (!exec->callbacks.output)
+               return 0;
+
+       return exec->callbacks.output(ctx, exec->callbacks.output_data, PAKFIRE_STDERR, line, length);
+}
+
 // Capabilities
 
 // Logs all capabilities of the current process
@@ -1673,14 +1693,14 @@ static int pakfire_jail_child(struct pakfire_jail* jail, struct pakfire_jail_exe
 static int __pakfire_jail_exec(struct pakfire_jail* jail,
                pakfire_jail_callback callback, void* data, int flags,
                pakfire_jail_input_callback input_callback, void* input_data,
-               pakfire_pty_stdout_callback stdout_callback, void* stdout_data,
+               pakfire_jail_output_callback output_callback, void* output_data,
                char** output, size_t* output_length) {
        struct pakfire_log_stream* stdout = NULL;
        struct pakfire_log_stream* stderr = NULL;
        int r;
 
        // We cannot have both, an output callback and buffer
-       if (stdout_callback && output)
+       if (output_callback && output)
                return -EINVAL;
 
        // Initialize context for this call
@@ -1779,9 +1799,13 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                        }
 
                // Otherwise send the output to the log streamer
-               } else {
+               } else if (output_callback) {
+                       // Store the callback
+                       ctx.callbacks.output      = output_callback;
+                       ctx.callbacks.output_data = output_data;
+
                        // Create a new stream
-                       r = pakfire_log_stream_create(&stdout, jail->ctx, stdout_callback, stdout_data);
+                       r = pakfire_log_stream_create(&stdout, jail->ctx, pakfire_jail_output_stdout, &ctx);
                        if (r < 0) {
                                ERROR(jail->ctx, "Failed to create standard output stream: %s\n", strerror(-r));
                                goto ERROR;
@@ -1794,21 +1818,21 @@ static int __pakfire_jail_exec(struct pakfire_jail* jail,
                                r = -errno;
                                goto ERROR;
                        }
-               }
 
-               // Send the standard error output to a log streamer, too
-               r = pakfire_log_stream_create(&stderr, jail->ctx, stdout_callback, stdout_data);
-               if (r < 0) {
-                       ERROR(jail->ctx, "Failed to create standard error stream: %s\n", strerror(-r));
-                       goto ERROR;
-               }
+                       // Send the standard error output to a log streamer, too
+                       r = pakfire_log_stream_create(&stderr, jail->ctx, pakfire_jail_output_stderr, &ctx);
+                       if (r < 0) {
+                               ERROR(jail->ctx, "Failed to create standard error stream: %s\n", strerror(-r));
+                               goto ERROR;
+                       }
 
-               // Ask to stream our output into this
-               ctx.streams.stderr = pakfire_log_stream_as_file(stderr);
-               if (!ctx.streams.stderr) {
-                       ERROR(jail->ctx, "Failed to open file stream for standard output: %m\n");
-                       r = -errno;
-                       goto ERROR;
+                       // Ask to stream our output into this
+                       ctx.streams.stderr = pakfire_log_stream_as_file(stderr);
+                       if (!ctx.streams.stderr) {
+                               ERROR(jail->ctx, "Failed to open file stream for standard output: %m\n");
+                               r = -errno;
+                               goto ERROR;
+                       }
                }
        }
 
@@ -2009,7 +2033,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_jail_input_callback input_callback, void* input_data,
-               pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
+               pakfire_jail_output_callback output_callback, void* output_data) {
        struct pakfire_jail_command command = {
                .jail = jail,
                .argv = argv,
@@ -2017,13 +2041,13 @@ int pakfire_jail_communicate(
        };
 
        return __pakfire_jail_exec(jail, pakfire_jail_launch_command, &command, flags,
-               input_callback, input_data, stdout_callback, stdout_data, NULL, NULL);
+               input_callback, input_data, output_callback, output_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_jail_input_callback input_callback, void* input_data,
-               pakfire_pty_stdout_callback stdout_callback, void* stdout_data) {
+               pakfire_jail_output_callback output_callback, void* output_data) {
        char path[PATH_MAX];
        const char** argv = NULL;
        FILE* f = NULL;
@@ -2083,7 +2107,7 @@ int pakfire_jail_exec_script(struct pakfire_jail* jail,
 
        // Run the script
        r = pakfire_jail_communicate(jail, argv, env, 0,
-               input_callback, input_data, stdout_callback, stdout_data);
+               input_callback, input_data, output_callback, output_data);
 
 ERROR:
        if (argv)
index 16829960294abfcbce8df7a45d6d3f8c264332d2..a54c3bb3ca304f0b9108f62d4ac54d319a8930dc 100644 (file)
 #include <pakfire/cgroup.h>
 #include <pakfire/env.h>
 #include <pakfire/pakfire.h>
-#include <pakfire/pty.h>
 
 struct pakfire_jail;
 
 // Input callback
 typedef pakfire_buffer_input_callback pakfire_jail_input_callback;
 
+// Output callback
+enum pakfire_jail_output_stream {
+       PAKFIRE_STDOUT,
+       PAKFIRE_STDERR,
+};
+
+typedef int (*pakfire_jail_output_callback)(struct pakfire_ctx* ctx, void* data,
+       const enum pakfire_jail_output_stream stream, const char* line, size_t length);
+
 int pakfire_jail_create(struct pakfire_jail** jail, struct pakfire* pakfire);
 
 struct pakfire_jail* pakfire_jail_ref(struct pakfire_jail* jail);
@@ -71,7 +79,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_jail_input_callback input_callback, void* input_data,
-       pakfire_log_stream_callback stdout_callback, void* stdout_data);
+       pakfire_jail_output_callback output_callback, void* output_data);
 
 // Convenience functions
 int pakfire_jail_run(struct pakfire* pakfire,
@@ -82,7 +90,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_jail_input_callback input_callback, void* input_data,
-       pakfire_pty_stdout_callback stdout_callback, void* stdout_data);
+       pakfire_jail_output_callback output_callback, void* output_data);
 
 int pakfire_jail_shell(struct pakfire_jail* jail, struct pakfire_env* env);
 int pakfire_jail_ldconfig(struct pakfire* pakfire);
index e53587166e92228ef39937108ad8ff703dac0fb3..77f91eb8234829d26244de9a845ceb819f4470e6 100644 (file)
@@ -34,6 +34,7 @@
 #include <pakfire/mount.h>
 #include <pakfire/packagelist.h>
 #include <pakfire/pakfire.h>
+#include <pakfire/pty.h>
 #include <pakfire/key.h>
 #include <pakfire/repo.h>
 #include <pakfire/repolist.h>
@@ -533,11 +534,15 @@ ERROR:
  * Execute
  */
 
-static int Pakfire_execute_stdout_callback(
-               struct pakfire_ctx* ctx, void* data, const char* line, const size_t length) {
+static int Pakfire_execute_stdout_callback(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, const size_t length) {
        PyObject** output = data;
        PyObject* chunk = NULL;
 
+       // Don't do anything for any error output
+       if (stream == PAKFIRE_STDERR)
+               return 0;
+
        // Allocate a new chunk
        chunk = PyBytes_FromStringAndSize(line, length);
        if (!chunk)
@@ -560,7 +565,7 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
        Py_ssize_t p = 0;
        int r;
 
-       pakfire_pty_stdin_callback stdin_callback = NULL;
+       pakfire_jail_input_callback input_callback = NULL;
 
        PyObject* command = NULL;
        PyObject* environ = NULL;
@@ -656,7 +661,7 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
 
        // Register the input callback
        if (input.data)
-               stdin_callback = pakfire_pty_send_buffer;
+               input_callback = pakfire_pty_send_buffer;
 
        // Create a new jail
        r = pakfire_jail_create(&jail, self->pakfire);
@@ -680,7 +685,7 @@ static PyObject* Pakfire_execute(PakfireObject* self, PyObject* args, PyObject*
 
        // Execute command
        r = pakfire_jail_communicate(jail, argv, env, 0,
-                       stdin_callback, &input, Pakfire_execute_stdout_callback, &output);
+                       input_callback, &input, Pakfire_execute_stdout_callback, &output);
 
        Py_END_ALLOW_THREADS
 
index d10e391225e3fd62a17185159a634643d846b007..689a140676462392ea38a17e91a84426e400e3d4 100644 (file)
@@ -348,7 +348,8 @@ static ssize_t callback_stdin(struct pakfire_ctx* ctx, void* data, char* buffer,
 }
 
 // Just consume the entire line
-static int callback_stdout(struct pakfire_ctx* ctx, void* data, const char* line, size_t length) {
+static int callback_stdout(struct pakfire_ctx* ctx, void* data,
+               const enum pakfire_jail_output_stream stream, const char* line, size_t length) {
        return fwrite(line, 1, length, stdout);
 }