From: Michael Tremer Date: Wed, 8 Jan 2025 11:11:58 +0000 (+0000) Subject: build: Find pre-requirements without a shell script X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=c9e23df69e3edcc41853edd97d5382fec2fa5669;p=people%2Fric9%2Fpakfire.git build: Find pre-requirements without a shell script Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index a8dc9caf7..8856020b1 100644 --- a/Makefile.am +++ b/Makefile.am @@ -1015,7 +1015,6 @@ tests_parser_test_LDADD = \ dist_scripts_SCRIPTS = \ src/scripts/compress-man-pages \ - src/scripts/find-prerequires \ src/scripts/mkimage \ src/scripts/perl.prov \ src/scripts/perl.req diff --git a/src/pakfire/build.c b/src/pakfire/build.c index 47451bdcb..89b6e24cd 100644 --- a/src/pakfire/build.c +++ b/src/pakfire/build.c @@ -1040,66 +1040,117 @@ ERROR: return r; } -struct pakfire_build_send_scriptlet_state { - struct pakfire_scriptlet* scriptlet; +static int pakfire_build_extract_command( + char* command, size_t lcommand, const char* line, const size_t lline) { + const char* s = NULL; + const char* e = NULL; - const char* p; - size_t l; -}; + // Line must at least have a certain length + if (lline <= strlen("executable()")) + return -EINVAL; -static ssize_t pakfire_build_send_scriptlet( - struct pakfire_ctx* ctx, void* data, char* buffer, size_t length) { - struct pakfire_build_send_scriptlet_state* state = data; - - // Fetch the scriptlet unless already done - if (!state->p) { - state->p = pakfire_scriptlet_get_data(state->scriptlet, &state->l); - if (!state->p) { - ERROR(ctx, "Could not fetch scriptlet: %m\n"); - return -errno; + // Check if we begin with "executable(" + if (!pakfire_string_startswith(line, "executable(")) + return -EINVAL; + + // Find the closing bracket + e = memrchr(line, ')', lline); + if (!e) + return -EINVAL; + + // Find the opening bracket + s = memchr(line, '(', lline); + if (!s) + return -EINVAL; + + // Skip the opening bracket + s++; + + // Check if we have seen the opening bracket first and then the closing bracket + ssize_t l = e - s; + if (l <= 0) + return -EINVAL; + + // Copy the text to the buffer + 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) { + struct pakfire_find_deps_ctx* deps = data; + 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); + + // Consume the entire line + return length; + + default: + return r; } } - // Return if we have nothing left to send - if (state->l == 0) - return 0; + DEBUG(ctx, "Found '%s' as a dependency of the scriptlet\n", command); - // Cap the buffer to the maximum size of the scriptlet - if (state->l < length) - length = state->l; + // 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; - // Copy the scriptlet into the buffer - memcpy(buffer, state->p, length); + // Otherwise, we will have to resolve the command + } else { + r = pakfire_which(deps->build->pakfire, path, command); + if (r < 0) + return r; - // Forward the pointer by how much we have written - state->p += length; - state->l -= length; + // 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; + } + } + // Consume the entire line return length; } static int pakfire_build_add_scriptlet_requires(struct pakfire_build* build, struct pakfire_package* pkg, struct pakfire_scriptlet* scriptlet) { + struct pakfire_pty_buffer buffer = {}; int r; - struct pakfire_build_send_scriptlet_state send_scriptlet_state = { - .scriptlet = scriptlet, - }; - struct pakfire_find_deps_ctx ctx = { - .build = build, - .pkg = pkg, - .dep = PAKFIRE_PKG_PREREQUIRES, + .build = build, + .pkg = pkg, }; - // Find all pre-requires - r = pakfire_build_run_script(build, "find-prerequires", NULL, - pakfire_build_send_scriptlet, &send_scriptlet_state, pakfire_build_process_deps, &ctx); - if (r) - goto ERROR; + // Fetch the scriptlet data + buffer.data = pakfire_scriptlet_get_data(scriptlet, &buffer.length); + if (!buffer.data) + return -errno; -ERROR: - return r; + // To execute the scriptlet we require /bin/bash + r = pakfire_package_add_dep(pkg, PAKFIRE_PKG_PREREQUIRES, "/bin/sh"); + if (r < 0) + return r; + + // We pass /dev/stdin as a script name to prevent bash from running in interactive mode + const char* argv[] = { + "bash", "--rpm-requires", "/dev/stdin", NULL, + }; + + return pakfire_jail_communicate(build->jail, argv, NULL, 0, + pakfire_pty_send_buffer, &buffer, pakfire_build_process_scriptlet_dep, &ctx); } static int pakfire_build_package_add_scriptlet(struct pakfire_build* build, diff --git a/src/pakfire/file.c b/src/pakfire/file.c index c7a254908..6e1be494e 100644 --- a/src/pakfire/file.c +++ b/src/pakfire/file.c @@ -1184,6 +1184,10 @@ int pakfire_file_contains(struct pakfire_file* file, const char* needle, ssize_t if (!S_ISREG(mode)) return 0; + // If the file is empty it cannot contain anything + if (!pakfire_file_get_size(file)) + return 0; + // Map the file into memory r = pakfire_file_mmap(file, &haystack, &l); if (r < 0) diff --git a/src/scripts/find-prerequires b/src/scripts/find-prerequires deleted file mode 100644 index b79308aae..000000000 --- a/src/scripts/find-prerequires +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash -############################################################################### -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2021 Pakfire development team # -# # -# This program is free software: you can redistribute it and/or modify # -# it under the terms of the GNU General Public License as published by # -# the Free Software Foundation, either version 3 of the License, or # -# (at your option) any later version. # -# # -# This program is distributed in the hope that it will be useful, # -# but WITHOUT ANY WARRANTY; without even the implied warranty of # -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # -# GNU General Public License for more details. # -# # -# You should have received a copy of the GNU General Public License # -# along with this program. If not, see . # -# # -############################################################################### - -main() { - # We require a shell - echo "/bin/sh" - - local req - while read -r req; do - case "${req}" in - /*) - echo "${req}" - ;; - *) - which "${req}" 2>/dev/null - ;; - esac - done < <(bash --rpm-requires | sed -e "s/^.*(//;s/)$//" | sort -u) - - return 0 -} - -main "$@" || exit $?