]> git.ipfire.org Git - people/ric9/pakfire.git/commitdiff
build: Find pre-requirements without a shell script
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Jan 2025 11:11:58 +0000 (11:11 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 8 Jan 2025 11:11:58 +0000 (11:11 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/pakfire/build.c
src/pakfire/file.c
src/scripts/find-prerequires [deleted file]

index a8dc9caf7ce82554f354afc7d1e19bf792fec979..8856020b1ee88de6cf0d96c173b62c1cb302694e 100644 (file)
@@ -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
index 47451bdcb3bb3a344188dd26ac9e12d5a4a77ef1..89b6e24cdeeb0789e96097ba599e1de6c7da1e80 100644 (file)
@@ -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,
index c7a25490896c45e4a3e7d60a1c301446aa2c9854..6e1be494e3202c330135e85557bbab76a66a3214 100644 (file)
@@ -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 (file)
index b79308a..0000000
+++ /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 <http://www.gnu.org/licenses/>.       #
-#                                                                             #
-###############################################################################
-
-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 $?