const char* t = pakfire_scriptlet_get_type(scriptlet);
if (strcmp(t, type) == 0)
- return scriptlet;
+ return pakfire_scriptlet_ref(scriptlet);
}
return NULL;
#include <pakfire/packager.h>
#include <pakfire/parser.h>
#include <pakfire/private.h>
+#include <pakfire/scriptlet.h>
#include <pakfire/types.h>
#include <pakfire/util.h>
return r;
}
+static int pakfire_build_add_scriptlet_requires(Pakfire pakfire, PakfirePackage pkg,
+ struct pakfire_scriptlet* scriptlet) {
+ char** prerequires = NULL;
+ char path[PATH_MAX];
+ size_t size;
+ int r;
+
+ const char* root = pakfire_get_path(pakfire);
+
+ // Make filename
+ r = pakfire_make_path(pakfire, path, "tmp/.pakfire-scriptlet.XXXXXX");
+ if (r < 0)
+ return r;
+
+ // Fetch scriptlet payload
+ const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
+
+ // Create a temporary file
+ FILE* f = pakfire_mktemp(path);
+ if (!f)
+ return 1;
+
+ // Write scriptlet
+ ssize_t bytes_written = fwrite(data, 1, size, f);
+ if (bytes_written < 0) {
+ ERROR(pakfire, "Could not write to %s: %m\n", path);
+ fclose(f);
+ goto ERROR;
+ }
+
+ // Close file
+ fclose(f);
+
+ // Build commandline
+ const char* args[] = {
+ pakfire_path_relpath(root, path),
+ NULL,
+ };
+
+ // Find all pre-requires
+ r = pakfire_build_run_script(pakfire, "find-prerequires", args,
+ pakfire_execute_capture_stdout_to_array, &prerequires);
+ if (r)
+ goto ERROR;
+
+ // Add all pre-requires to the package
+ if (prerequires) {
+ for (char** element = prerequires; *element; element++) {
+ DEBUG(pakfire, "Adding pre-requires: %s\n", *element);
+ pakfire_package_add_prerequires(pkg, *element);
+ }
+ }
+
+ERROR:
+ if (r && *path)
+ unlink(path);
+ if (prerequires) {
+ for (char** element = prerequires; *element; element++)
+ free(*element);
+ free(prerequires);
+ }
+ return r;
+}
+
+static int pakfire_build_package_add_scriptlet(Pakfire pakfire, PakfirePackage pkg,
+ struct pakfire_packager* packager, const char* type, const char* data) {
+ struct pakfire_scriptlet* scriptlet = NULL;
+ char* shell = NULL;
+ int r;
+
+ // Wrap scriptlet into a shell script
+ r = asprintf(&shell, "#!/bin/sh\n\nset -e\n\n%s\n\nexit 0\n", data);
+ if (r < 0)
+ goto ERROR;
+
+ // Create a scriptlet
+ r = pakfire_scriptlet_create(&scriptlet, pakfire, type, shell, 0);
+ if (r)
+ goto ERROR;
+
+ // Add it to the package
+ r = pakfire_packager_add_scriptlet(packager, scriptlet);
+ if (r) {
+ ERROR(pakfire, "Could not add scriptlet %s\n", type);
+ goto ERROR;
+ }
+
+ // Add scriptlet requirements
+ r = pakfire_build_add_scriptlet_requires(pakfire, pkg, scriptlet);
+ if (r) {
+ ERROR(pakfire, "Could not add scriptlet requirements: %s\n", strerror(errno));
+ goto ERROR;
+ }
+
+ // Success
+ r = 0;
+
+ERROR:
+ if (scriptlet)
+ pakfire_scriptlet_unref(scriptlet);
+ if (shell)
+ free(shell);
+
+ return r;
+}
+
+static int pakfire_build_package_add_scriptlets(Pakfire pakfire, PakfireParser makefile,
+ const char* namespace, PakfirePackage pkg, struct pakfire_packager* packager) {
+ char name[NAME_MAX];
+ int r;
+
+ for (const char** type = pakfire_scriptlet_types; *type; type++) {
+ r = pakfire_string_format(name, "scriptlet:%s", *type);
+ if (r < 0)
+ return r;
+
+ // Fetch the scriptlet
+ char* data = pakfire_parser_get(makefile, namespace, name);
+ if (!data)
+ continue;
+
+ // Add it to the package
+ r = pakfire_build_package_add_scriptlet(pakfire, pkg, packager, *type, data);
+ if (r) {
+ free(data);
+ return r;
+ }
+
+ free(data);
+ }
+
+ return 0;
+}
+
static int pakfire_build_package(Pakfire pakfire, PakfireParser makefile,
const char* buildroot, const char* namespace, const char* target) {
PakfireRepo repo = NULL;
if (r)
goto ERROR;
+ // Add scriptlets
+ r = pakfire_build_package_add_scriptlets(pakfire, makefile, namespace, pkg, packager);
+ if (r)
+ goto ERROR;
+
// Write the finished package
r = pakfire_packager_finish_to_directory(packager, target);
if (r) {
for (const char** type = pakfire_scriptlet_types; *type; type++) {
// Fetch the scriptlet
- struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type);
+ struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type);
if (!scriptlet)
continue;
#ifndef PAKFIRE_PACKAGER_H
#define PAKFIRE_PACKAGER_H
+#include <pakfire/scriptlet.h>
#include <pakfire/types.h>
struct pakfire_packager;
int pakfire_packager_add(struct pakfire_packager* packager,
const char* sourcepath, const char* path);
+int pakfire_packager_add_scriptlet(struct pakfire_packager* packager,
+ struct pakfire_scriptlet* scriptlet);
+
#endif /* PAKFIRE_PACKAGER_H */
struct archive* mtree;
FILE* fmtree;
size_t installsize;
+
+ struct pakfire_scriptlet** scriptlets;
+ unsigned int num_scriptlets;
};
static int pakfire_packager_create_mtree(Pakfire pakfire, struct archive** mtree,
}
static void pakfire_packager_free(struct pakfire_packager* packager) {
+ // Scriptlets
+ if (packager->scriptlets) {
+ for (unsigned int i = 0; i < packager->num_scriptlets; i++)
+ free(packager->scriptlets[i]);
+ free(packager->scriptlets);
+ }
+
// Payload
if (packager->payload)
archive_write_free(packager->payload);
return r;
}
+static int pakfire_packager_write_scriptlet(struct pakfire_packager* packager,
+ struct archive* a, struct archive* mtree, struct pakfire_scriptlet* scriptlet) {
+ char filename[PATH_MAX];
+ size_t size;
+ int r;
+
+ // Fetch type
+ const char* type = pakfire_scriptlet_get_type(scriptlet);
+
+ DEBUG(packager->pakfire, "Writing scriptlet '%s' to package\n", type);
+
+ // Make filename
+ r = pakfire_string_format(filename, "scriptlet/%s", type);
+ if (r < 0)
+ return r;
+
+ // Fetch scriptlet
+ const char* data = pakfire_scriptlet_get_data(scriptlet, &size);
+
+ // Write file
+ return pakfire_packager_write_file_from_buffer(packager, a, mtree, filename, data);
+}
+
/*
This function is being called at the end when all data has been added to the package.
goto ERROR;
}
+ // Write scriptlets
+ for (unsigned int i = 0; i < packager->num_scriptlets; i++) {
+ r = pakfire_packager_write_scriptlet(packager, a, mtree, packager->scriptlets[i]);
+ if (r) {
+ ERROR(packager->pakfire, "Could not add scriptlet to the archive: %s\n",
+ strerror(errno));
+ goto ERROR;
+ }
+ }
+
// Finish checksums
r = archive_write_finish_entry(mtree);
if (r) {
return r;
}
+
+int pakfire_packager_add_scriptlet(struct pakfire_packager* packager,
+ struct pakfire_scriptlet* scriptlet) {
+ if (!scriptlet) {
+ errno = EINVAL;
+ return 1;
+ }
+
+ // Extend array
+ packager->scriptlets = reallocarray(packager->scriptlets,
+ packager->num_scriptlets + 1, sizeof(*packager->scriptlets));
+ if (!packager->scriptlets)
+ return 1;
+
+ // Append scriptlet
+ packager->scriptlets[packager->num_scriptlets++] = pakfire_scriptlet_ref(scriptlet);
+
+ return 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/>. #
+# #
+###############################################################################
-if [ -z "${1}" ]; then
- echo >&2 "No input file passed!"
- exit 1
-fi
-
-prereqs=$(bash --rpm-requires < ${1} | sort | uniq | sed -e 's/^bash(//' -e 's/)$//' -e 's/^executable(//' -e 's/)$//')
-[ -z "${prereqs}" ] && exit 0
-
-for prereq in ${prereqs}; do
- case "${prereq}" in
- /*)
- echo ${prereq}
- ;;
- *)
- which ${prereq} 2>/dev/null
- ;;
- esac
-done | sort | uniq
+error() {
+ echo "${0#/}: $@" >&2
+}
+
+set -x
+
+main() {
+ local scriptlet="${1}"
+
+ if [ ! -r "${scriptlet}" ]; then
+ error "Input file is not readable"
+ return 1
+ fi
+
+ cat "${scriptlet}" >&2
+
+ # We require a shell
+ echo "/bin/sh"
+
+ local req
+ while read -r req; do
+ case "${req}" in
+ /*)
+ echo "${req}"
+ ;;
+ *)
+ which "${req}"
+ ;;
+ esac
+ done < <(bash --rpm-requires < "${scriptlet}" | sed -e "s/^.*(//;s/)$//" | sort -u)
+
+ return 0
+}
+
+main "$@" || exit $?