From: Michael Tremer Date: Mon, 24 Mar 2025 19:27:24 +0000 (+0000) Subject: jail: Refactor the output callback X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=46d42bd169f2c11b19f6a446eac82ccaaae52cac;p=pakfire.git jail: Refactor the output callback Signed-off-by: Michael Tremer --- diff --git a/src/pakfire/build.c b/src/pakfire/build.c index 613889cb..4ac34784 100644 --- a/src/pakfire/build.c +++ b/src/pakfire/build.c @@ -44,6 +44,7 @@ #include #include #include +#include #include #include #include @@ -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; diff --git a/src/pakfire/jail.c b/src/pakfire/jail.c index 3692929e..6d88b8d7 100644 --- a/src/pakfire/jail.c +++ b/src/pakfire/jail.c @@ -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) diff --git a/src/pakfire/jail.h b/src/pakfire/jail.h index 16829960..a54c3bb3 100644 --- a/src/pakfire/jail.h +++ b/src/pakfire/jail.h @@ -25,13 +25,21 @@ #include #include #include -#include 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); diff --git a/src/python/pakfire.c b/src/python/pakfire.c index e5358716..77f91eb8 100644 --- a/src/python/pakfire.c +++ b/src/python/pakfire.c @@ -34,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -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 diff --git a/tests/libpakfire/jail.c b/tests/libpakfire/jail.c index d10e3912..689a1406 100644 --- a/tests/libpakfire/jail.c +++ b/tests/libpakfire/jail.c @@ -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); }