From: Michael Tremer Date: Thu, 29 Apr 2021 10:09:13 +0000 (+0000) Subject: transaction: Move steps into transactions X-Git-Tag: 0.9.28~1285^2~199 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f52c8e7cc718bd0c5c22344146099967a5ca12cb;p=pakfire.git transaction: Move steps into transactions There is no point to separate this into multiple files since we no longer export the steps Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index 6c12e603c..ef9038756 100644 --- a/Makefile.am +++ b/Makefile.am @@ -269,7 +269,6 @@ libpakfire_la_SOURCES = \ src/libpakfire/scriptlet.c \ src/libpakfire/snapshot.c \ src/libpakfire/solution.c \ - src/libpakfire/step.c \ src/libpakfire/transaction.c \ src/libpakfire/util.c @@ -306,7 +305,6 @@ pkginclude_HEADERS += \ src/libpakfire/include/pakfire/scriptlet.h \ src/libpakfire/include/pakfire/snapshot.h \ src/libpakfire/include/pakfire/solution.h \ - src/libpakfire/include/pakfire/step.h \ src/libpakfire/include/pakfire/transaction.h \ src/libpakfire/include/pakfire/types.h \ src/libpakfire/include/pakfire/util.h diff --git a/src/libpakfire/execute.c b/src/libpakfire/execute.c index 6e85872a3..eb9ec7589 100644 --- a/src/libpakfire/execute.c +++ b/src/libpakfire/execute.c @@ -43,6 +43,7 @@ #define BUFFER_SIZE 1024 * 64 #define EPOLL_MAX_EVENTS 2 +#define LDCONFIG "/sbin/ldconfig" static char* envp_empty[1] = { NULL }; @@ -551,3 +552,22 @@ out: return r; } + +int pakfire_execute_ldconfig(Pakfire pakfire) { + char path[PATH_MAX]; + + // Check if ldconfig exists before calling it to avoid overhead + int r = pakfire_make_path(pakfire, path, LDCONFIG); + if (r < 0) + return 1; + + r = -1; + + if (access(path, X_OK) == 0) { + r = pakfire_execute_command(pakfire, LDCONFIG, NULL, 0, NULL, NULL); + + DEBUG(pakfire, "ldconfig returned %d\n", r); + } + + return r; +} diff --git a/src/libpakfire/include/pakfire/execute.h b/src/libpakfire/include/pakfire/execute.h index 09e688ced..e90680503 100644 --- a/src/libpakfire/include/pakfire/execute.h +++ b/src/libpakfire/include/pakfire/execute.h @@ -39,4 +39,10 @@ enum { PAKFIRE_EXECUTE_INTERACTIVE = (1 << 1), }; +#ifdef PAKFIRE_PRIVATE + +int pakfire_execute_ldconfig(Pakfire pakfire); + +#endif + #endif /* PAKFIRE_EXECUTE_H */ diff --git a/src/libpakfire/include/pakfire/scriptlet.h b/src/libpakfire/include/pakfire/scriptlet.h index e70d5ab3b..79e481093 100644 --- a/src/libpakfire/include/pakfire/scriptlet.h +++ b/src/libpakfire/include/pakfire/scriptlet.h @@ -64,6 +64,7 @@ void pakfire_scriptlet_free(struct pakfire_scriptlet* scriptlet); pakfire_scriptlet_type pakfire_scriptlet_type_from_filename(const char* filename); const char* pakfire_scriptlet_handle_from_type(pakfire_scriptlet_type type); +int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet); #endif diff --git a/src/libpakfire/include/pakfire/step.h b/src/libpakfire/include/pakfire/step.h deleted file mode 100644 index 56e80a804..000000000 --- a/src/libpakfire/include/pakfire/step.h +++ /dev/null @@ -1,45 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2013 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 . # -# # -#############################################################################*/ - -#ifndef PAKFIRE_STEP_H -#define PAKFIRE_STEP_H - -#ifdef PAKFIRE_PRIVATE - -#include -#include - -int pakfire_step_create(PakfireStep* step, Pakfire pakfire, - pakfire_step_type_t type, PakfirePackage pkg); -PakfireStep pakfire_step_ref(PakfireStep step); -PakfireStep pakfire_step_unref(PakfireStep step); - -PakfirePackage pakfire_step_get_package(PakfireStep step); -pakfire_step_type_t pakfire_step_get_type(PakfireStep step); - -size_t pakfire_step_get_downloadsize(PakfireStep step); - -int pakfire_step_needs_download(PakfireStep step); - -int pakfire_step_run(PakfireStep step, struct pakfire_db* db, pakfire_action_type_t action); - -#endif - -#endif /* PAKFIRE_STEP_H */ diff --git a/src/libpakfire/scriptlet.c b/src/libpakfire/scriptlet.c index 7ef72679d..d475bc960 100644 --- a/src/libpakfire/scriptlet.c +++ b/src/libpakfire/scriptlet.c @@ -106,3 +106,17 @@ const char* pakfire_scriptlet_handle_from_type(pakfire_scriptlet_type type) { return NULL; } + +int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet) { + const char* interpreter = "#!/bin/sh"; + + // data must be long enough + if (scriptlet->size <= strlen(interpreter)) + return 0; + + // If the string begins with the interpreter, this is a match + if (strncmp(scriptlet->data, interpreter, strlen(interpreter)) == 0) + return 1; + + return 0; +} diff --git a/src/libpakfire/step.c b/src/libpakfire/step.c deleted file mode 100644 index 0008260d5..000000000 --- a/src/libpakfire/step.c +++ /dev/null @@ -1,431 +0,0 @@ -/*############################################################################# -# # -# Pakfire - The IPFire package management system # -# Copyright (C) 2013 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 . # -# # -#############################################################################*/ - -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#define LDCONFIG "/sbin/ldconfig" - -struct _PakfireStep { - Pakfire pakfire; - PakfirePackage package; - PakfireArchive archive; - pakfire_step_type_t type; - int nrefs; -}; - -int pakfire_step_create(PakfireStep* step, Pakfire pakfire, - pakfire_step_type_t type, PakfirePackage pkg) { - PakfireStep s = calloc(1, sizeof(*s)); - if (!s) - return ENOMEM; - - // Store a reference to Pakfire - s->pakfire = pakfire_ref(pakfire); - - // Initialize the reference counter - s->nrefs = 1; - - // Store a reference to the package - s->package = pakfire_package_ref(pkg); - - // Store type - s->type = type; - - *step = s; - return 0; -} - -PakfireStep pakfire_step_ref(PakfireStep step) { - step->nrefs++; - - return step; -} - -static void pakfire_step_free(PakfireStep step) { - DEBUG(step->pakfire, "Releasing Step at %p\n", step); - - pakfire_package_unref(step->package); - if (step->archive) - pakfire_archive_unref(step->archive); - pakfire_unref(step->pakfire); - free(step); -} - -PakfireStep pakfire_step_unref(PakfireStep step) { - if (--step->nrefs > 0) - return step; - - pakfire_step_free(step); - return NULL; -} - -PakfirePackage pakfire_step_get_package(PakfireStep step) { - return pakfire_package_ref(step->package); -} - -pakfire_step_type_t pakfire_step_get_type(PakfireStep step) { - return step->type; -} - -static int pakfire_step_get_downloadtype(PakfireStep step) { - int type = pakfire_step_get_type(step); - - switch (type) { - case PAKFIRE_STEP_INSTALL: - case PAKFIRE_STEP_REINSTALL: - case PAKFIRE_STEP_DOWNGRADE: - case PAKFIRE_STEP_UPGRADE: - return 1; - - default: - break; - } - - return 0; -} - -size_t pakfire_step_get_downloadsize(PakfireStep step) { - if (pakfire_step_get_downloadtype(step)) - return pakfire_package_get_downloadsize(step->package); - - return 0; -} - -int pakfire_step_needs_download(PakfireStep step) { - if (!pakfire_step_get_downloadtype(step)) - return false; - - PakfireRepo repo = pakfire_package_get_repo(step->package); - if (pakfire_repo_is_installed_repo(repo) == 0) - return false; - - const char* path = pakfire_package_get_path(step->package); - - // Does the file exist? - int r = access(path, R_OK); - if (r == 0) - return false; - - return true; -} - -static int pakfire_step_verify(PakfireStep step) { - // The package must have been downloaded - if (pakfire_step_needs_download(step)) - return 1; - - // Fetch the archive - step->archive = pakfire_package_get_archive(step->package); - if (!step->archive) { - const char* nevra = pakfire_package_get_nevra(step->package); - ERROR(step->pakfire, "Could not open package archive for %s: %s\n", - nevra, strerror(errno)); - - return -1; - } - - // Verify the archive - pakfire_archive_verify_status_t status = pakfire_archive_verify(step->archive); - - // Log error - if (status) { - const char* error = pakfire_archive_verify_strerror(status); - ERROR(step->pakfire, "Archive verification failed: %s\n", error); - } - - return status; -} - -static int pakfire_script_check_shell(struct pakfire_scriptlet* scriptlet) { - const char* interpreter = "#!/bin/sh"; - - // data must be long enough - if (scriptlet->size <= strlen(interpreter)) - return 0; - - // If the string begins with the interpreter, this is a match - if (strncmp(scriptlet->data, interpreter, strlen(interpreter)) == 0) - return 1; - - return 0; -} - -static int pakfire_step_run_shell_script(PakfireStep step, struct pakfire_scriptlet* scriptlet) { - return pakfire_execute_script(step->pakfire, scriptlet->data, scriptlet->size, NULL, 0, NULL, NULL); -} - -static int pakfire_step_run_script(PakfireStep step, - struct pakfire_db* db, pakfire_scriptlet_type type) { - struct pakfire_scriptlet* scriptlet = NULL; - - // Fetch scriptlet from archive if possible - if (step->archive) - scriptlet = pakfire_archive_get_scriptlet(step->archive, type); - else - scriptlet = pakfire_db_get_scriptlet(db, step->package, type); - - // Nothing to do if there are no scriptlets - if (!scriptlet) - return 0; - - // Found a script! - DEBUG(step->pakfire, "Found scriptlet:\n%.*s", - (int)scriptlet->size, (const char*)scriptlet->data); - - // Detect what kind of script this is and run it - if (pakfire_script_check_shell(scriptlet)) { - pakfire_step_run_shell_script(step, scriptlet); - } else { - ERROR(step->pakfire, "Scriptlet is of an unknown kind\n"); - } - - return 0; -} - -static int pakfire_run_ldconfig(PakfireStep step) { - char path[PATH_MAX]; - - // Check if ldconfig exists before calling it to avoid overhead - int r = pakfire_make_path(step->pakfire, path, LDCONFIG); - if (r < 0) - return 1; - - r = -1; - - if (access(path, X_OK) == 0) { - r = pakfire_execute_command(step->pakfire, LDCONFIG, NULL, 0, NULL, NULL); - - DEBUG(step->pakfire, "ldconfig returned %d\n", r); - } - - return r; -} - -static int pakfire_step_extract(PakfireStep step) { - if (!step->archive) { - ERROR(step->pakfire, "Archive was not opened\n"); - return -1; - } - - // Extract payload to the root of the Pakfire instance - int r = pakfire_archive_extract(step->archive, NULL); - if (r) { - const char* nevra = pakfire_package_get_nevra(step->package); - ERROR(step->pakfire, "Could not extract package %s: %d\n", nevra, r); - } - - // Is it necessary to call ldconfig? - PakfireFilelist filelist = pakfire_archive_get_filelist(step->archive); - if (filelist) { - int need_ldconfig = pakfire_filelist_contains(filelist, "*/lib*.so.?"); - - // Update the runtime linker cache - if (need_ldconfig) - pakfire_run_ldconfig(step); - - pakfire_filelist_unref(filelist); - } - - return r; -} - -static int pakfire_step_erase(PakfireStep step) { - // Update the runtime linker cache after all files have been removed - pakfire_run_ldconfig(step); - - return 0; // TODO -} - - -static const char* pakfire_action_type_string(pakfire_action_type_t type) { - switch (type) { - case PAKFIRE_ACTION_NOOP: - return "NOOP"; - - case PAKFIRE_ACTION_VERIFY: - return "VERIFY"; - - case PAKFIRE_ACTION_EXECUTE: - return "EXECUTE"; - - case PAKFIRE_ACTION_PRETRANS: - return "PRETRANS"; - - case PAKFIRE_ACTION_POSTTRANS: - return "POSTTRANS"; - } - - return NULL; -} - -int pakfire_step_run(PakfireStep step, - struct pakfire_db* db, const pakfire_action_type_t action) { - DEBUG(step->pakfire, "Running Step %p (%s)\n", step, pakfire_action_type_string(action)); - - pakfire_step_type_t type = pakfire_step_get_type(step); - - int r = 0; - switch (action) { - // Verify this step - case PAKFIRE_ACTION_VERIFY: - r = pakfire_step_verify(step); - break; - - // Run the pre-transaction scripts - case PAKFIRE_ACTION_PRETRANS: - switch (type) { - case PAKFIRE_STEP_INSTALL: - case PAKFIRE_STEP_REINSTALL: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PRETRANSIN); - break; - - case PAKFIRE_STEP_UPGRADE: - case PAKFIRE_STEP_DOWNGRADE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PRETRANSUP); - break; - - case PAKFIRE_STEP_ERASE: - case PAKFIRE_STEP_OBSOLETE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PRETRANSUN); - break; - - case PAKFIRE_STEP_IGNORE: - break; - } - break; - - // Run the post-transaction scripts - case PAKFIRE_ACTION_POSTTRANS: - switch (type) { - case PAKFIRE_STEP_INSTALL: - case PAKFIRE_STEP_REINSTALL: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTTRANSIN); - break; - - case PAKFIRE_STEP_UPGRADE: - case PAKFIRE_STEP_DOWNGRADE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTTRANSUP); - break; - - case PAKFIRE_STEP_ERASE: - case PAKFIRE_STEP_OBSOLETE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTTRANSUN); - break; - - case PAKFIRE_STEP_IGNORE: - break; - } - break; - - // Execute the action of this script - case PAKFIRE_ACTION_EXECUTE: - switch (type) { - case PAKFIRE_STEP_INSTALL: - case PAKFIRE_STEP_REINSTALL: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PREIN); - if (r) - break; - - r = pakfire_step_extract(step); - if (r) - break; - - // Remove package metadata first when reinstalling - if (type == PAKFIRE_STEP_REINSTALL) { - r = pakfire_db_remove_package(db, step->package); - if (r) - break; - } - - r = pakfire_db_add_package(db, step->package, step->archive); - if (r) - break; - - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTIN); - break; - - case PAKFIRE_STEP_UPGRADE: - case PAKFIRE_STEP_DOWNGRADE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PREUP); - if (r) - break; - - r = pakfire_step_extract(step); - if (r) - break; - - r = pakfire_db_add_package(db, step->package, step->archive); - if (r) - break; - - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTUP); - break; - - case PAKFIRE_STEP_ERASE: - case PAKFIRE_STEP_OBSOLETE: - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_PREUN); - if (r) - break; - - r = pakfire_step_erase(step); - if (r) - break; - - r = pakfire_db_remove_package(db, step->package); - if (r) - break; - - r = pakfire_step_run_script(step, db, PAKFIRE_SCRIPTLET_POSTUN); - break; - - case PAKFIRE_STEP_IGNORE: - break; - } - break; - - // Do nothing - case PAKFIRE_ACTION_NOOP: - break; - } - - if (r) - ERROR(step->pakfire, "Step has failed: %s\n", strerror(r)); - - return r; -} diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index 945836038..3cbab27b5 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -23,15 +23,16 @@ #include +#include #include #include +#include #include #include #include #include #include #include -#include #include #include #include @@ -42,12 +43,14 @@ struct pakfire_transaction { Transaction* transaction; - PakfireStep* steps; - size_t num_steps; + PakfireArchive* archives; + PakfirePackage* packages; + size_t num; }; -static pakfire_step_type_t transaction_get_step_type(struct pakfire_transaction* transaction, Id id) { - int type = transaction_type(transaction->transaction, id, 0); +static pakfire_step_type_t pakfire_transaction_get_step_type( + struct pakfire_transaction* transaction, PakfirePackage pkg) { + int type = transaction_type(transaction->transaction, pakfire_package_id(pkg), 0); // Translate solver types into our own types switch (type) { @@ -80,52 +83,64 @@ static pakfire_step_type_t transaction_get_step_type(struct pakfire_transaction* } } -static void pakfire_transaction_free(struct pakfire_transaction* transaction) { - // Release all steps - if (transaction->steps) { - for (unsigned int i = 0; i < transaction->num_steps; i++) - pakfire_step_unref(transaction->steps[i]); - free(transaction->steps); +static void pakfire_transaction_free_archives_and_packages( + struct pakfire_transaction* transaction) { + if (transaction->archives) { + for (unsigned int i = 0; i < transaction->num; i++) + if (transaction->archives[i]) + pakfire_archive_unref(transaction->archives[i]); + free(transaction->archives); + + transaction->archives = NULL; } + if (transaction->packages) { + for (unsigned int i = 0; i < transaction->num; i++) + if (transaction->packages[i]) + pakfire_package_unref(transaction->packages[i]); + free(transaction->packages); + + transaction->packages = NULL; + } +} + +static void pakfire_transaction_free(struct pakfire_transaction* transaction) { + pakfire_transaction_free_archives_and_packages(transaction); + transaction_free(transaction->transaction); pakfire_unref(transaction->pakfire); free(transaction); } -static int pakfire_transaction_add_step(struct pakfire_transaction* transaction, Id id) { - int type = transaction_get_step_type(transaction, id); +static int pakfire_transaction_import_transaction( + struct pakfire_transaction* transaction, Transaction* t) { + // Free any previous content + pakfire_transaction_free_archives_and_packages(transaction); - // Do not add ignored steps - if (type == PAKFIRE_STEP_IGNORE) - return 0; + // Order the transaction + transaction_order(t, 0); - // Allocate more space - transaction->steps = reallocarray(transaction->steps, sizeof(*transaction->steps), - transaction->num_steps + 1); - if (!transaction->steps) - return 1; + // How many steps? + transaction->num = t->steps.count; - PakfirePackage pkg = pakfire_package_create_from_solvable(transaction->pakfire, id); - if (!pkg) + // Allocate space for packages + transaction->packages = calloc(transaction->num, sizeof(*transaction->packages)); + if (!transaction->packages) return 1; - PakfireStep step; - int r = pakfire_step_create(&step, transaction->pakfire, type, pkg); - if (r) - goto ERROR; - - transaction->steps[transaction->num_steps++] = step; - - // Success - r = 0; + // Allocate space for archives + transaction->archives = calloc(transaction->num, sizeof(*transaction->archives)); + if (!transaction->archives) + return 1; -ERROR: - if (pkg) - pakfire_package_unref(pkg); + // Create all packages + for (unsigned int i = 0; i < transaction->num; i++) { + transaction->packages[i] = pakfire_package_create_from_solvable( + transaction->pakfire, t->steps.elements[i]); + } - return r; + return 0; } int pakfire_transaction_create(struct pakfire_transaction** transaction, @@ -145,15 +160,10 @@ int pakfire_transaction_create(struct pakfire_transaction** transaction, if (!t->transaction) goto ERROR; - // Order the transaction - transaction_order(t->transaction, 0); - - // Import steps - for (int i = 0; i < t->transaction->steps.count; i++) { - int r = pakfire_transaction_add_step(t, t->transaction->steps.elements[i]); - if (r) - goto ERROR; - } + // Import transaction + int r = pakfire_transaction_import_transaction(t, t->transaction); + if (r) + goto ERROR; *transaction = t; return 0; @@ -164,13 +174,15 @@ ERROR: return 1; } -PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref(struct pakfire_transaction* transaction) { +PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_ref( + struct pakfire_transaction* transaction) { transaction->nrefs++; return transaction; } -PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref(struct pakfire_transaction* transaction) { +PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref( + struct pakfire_transaction* transaction) { if (--transaction->nrefs > 0) return transaction; @@ -179,7 +191,7 @@ PAKFIRE_EXPORT struct pakfire_transaction* pakfire_transaction_unref(struct pakf } PAKFIRE_EXPORT size_t pakfire_transaction_count(struct pakfire_transaction* transaction) { - return transaction->num_steps; + return transaction->num; } static ssize_t pakfire_transaction_installsizechange(struct pakfire_transaction* transaction) { @@ -192,8 +204,8 @@ static ssize_t pakfire_transaction_installsizechange(struct pakfire_transaction* PAKFIRE_EXPORT ssize_t pakfire_transaction_downloadsize(struct pakfire_transaction* transaction) { ssize_t size = 0; - for (unsigned int i = 0; i < transaction->num_steps; i++) - size += pakfire_step_get_downloadsize(transaction->steps[i]); + for (unsigned int i = 0; i < transaction->num; i++) + size += pakfire_package_get_downloadsize(transaction->packages[i]); return size; } @@ -425,20 +437,273 @@ PAKFIRE_EXPORT char* pakfire_transaction_dump(struct pakfire_transaction* transa return string; } +static int pakfire_transaction_verify(struct pakfire_transaction* transaction, + PakfirePackage pkg, PakfireArchive archive) { + // Nothing to do if this step does not have an archive + if (!archive) + return 0; + + // Verify the archive + pakfire_archive_verify_status_t status = pakfire_archive_verify(archive); + + // Log error + if (status) { + const char* error = pakfire_archive_verify_strerror(status); + ERROR(transaction->pakfire, "Archive verification failed: %s\n", error); + } + + return status; +} + +static int pakfire_transaction_run_script(struct pakfire_transaction* transaction, + struct pakfire_db* db, pakfire_scriptlet_type type, PakfirePackage pkg, PakfireArchive archive) { + struct pakfire_scriptlet* scriptlet = NULL; + + // Fetch scriptlet from archive if possible + if (archive) + scriptlet = pakfire_archive_get_scriptlet(archive, type); + else + scriptlet = pakfire_db_get_scriptlet(db, pkg, type); + + // Nothing to do if there are no scriptlets + if (!scriptlet) + return 0; + + // Found a script! + DEBUG(transaction->pakfire, "Found scriptlet:\n%.*s", + (int)scriptlet->size, (const char*)scriptlet->data); + + // Detect what kind of script this is and run it + if (pakfire_scriptlet_is_shell_script(scriptlet)) { + pakfire_execute_script(transaction->pakfire, scriptlet->data, scriptlet->size, + NULL, 0, NULL, NULL); + } else { + ERROR(transaction->pakfire, "Scriptlet is of an unknown kind\n"); + } + + return 0; +} + +static int pakfire_transaction_extract(struct pakfire_transaction* transaction, + PakfirePackage pkg, PakfireArchive archive) { + // Extract payload to the root of the Pakfire instance + int r = pakfire_archive_extract(archive, NULL); + if (r) { + ERROR(transaction->pakfire, "Could not extract package %s: %s\n", + pakfire_package_get_nevra(pkg), strerror(errno)); + return r; + } + + // Is it necessary to call ldconfig? + PakfireFilelist filelist = pakfire_archive_get_filelist(archive); + if (filelist) { + int need_ldconfig = pakfire_filelist_contains(filelist, "*/lib*.so.?"); + + // Update the runtime linker cache + if (need_ldconfig) + pakfire_execute_ldconfig(transaction->pakfire); + + pakfire_filelist_unref(filelist); + } + + return r; +} + +static int pakfire_transaction_erase(struct pakfire_transaction* transaction, + PakfirePackage pkg, PakfireArchive archive) { + // Update the runtime linker cache after all files have been removed + pakfire_execute_ldconfig(transaction->pakfire); + + return 0; // TODO +} + +static const char* pakfire_action_type_string(pakfire_action_type_t type) { + switch (type) { + case PAKFIRE_ACTION_NOOP: + return "NOOP"; + + case PAKFIRE_ACTION_VERIFY: + return "VERIFY"; + + case PAKFIRE_ACTION_EXECUTE: + return "EXECUTE"; + + case PAKFIRE_ACTION_PRETRANS: + return "PRETRANS"; + + case PAKFIRE_ACTION_POSTTRANS: + return "POSTTRANS"; + } + + return NULL; +} + +static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, + struct pakfire_db* db, const pakfire_action_type_t action, PakfirePackage pkg, PakfireArchive archive) { + if (!pkg) { + errno = EINVAL; + return 1; + } + + DEBUG(transaction->pakfire, "Running %s for %s\n", + pakfire_action_type_string(action), pakfire_package_get_nevra(pkg)); + + pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg); + + int r = 0; + switch (action) { + // Verify this step + case PAKFIRE_ACTION_VERIFY: + r = pakfire_transaction_verify(transaction, pkg, archive); + break; + + // Run the pre-transaction scripts + case PAKFIRE_ACTION_PRETRANS: + switch (type) { + case PAKFIRE_STEP_INSTALL: + case PAKFIRE_STEP_REINSTALL: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PRETRANSIN, pkg, archive); + break; + + case PAKFIRE_STEP_UPGRADE: + case PAKFIRE_STEP_DOWNGRADE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PRETRANSUP, pkg, archive); + break; + + case PAKFIRE_STEP_ERASE: + case PAKFIRE_STEP_OBSOLETE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PRETRANSUN, pkg, archive); + break; + + case PAKFIRE_STEP_IGNORE: + break; + } + break; + + // Run the post-transaction scripts + case PAKFIRE_ACTION_POSTTRANS: + switch (type) { + case PAKFIRE_STEP_INSTALL: + case PAKFIRE_STEP_REINSTALL: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTTRANSIN, pkg, archive); + break; + + case PAKFIRE_STEP_UPGRADE: + case PAKFIRE_STEP_DOWNGRADE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTTRANSUP, pkg, archive); + break; + + case PAKFIRE_STEP_ERASE: + case PAKFIRE_STEP_OBSOLETE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTTRANSUN, pkg, archive); + break; + + case PAKFIRE_STEP_IGNORE: + break; + } + break; + + // Execute the action of this script + case PAKFIRE_ACTION_EXECUTE: + switch (type) { + case PAKFIRE_STEP_INSTALL: + case PAKFIRE_STEP_REINSTALL: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PREIN, pkg, archive); + if (r) + break; + + r = pakfire_transaction_extract(transaction, pkg, archive); + if (r) + break; + + // Remove package metadata first when reinstalling + if (type == PAKFIRE_STEP_REINSTALL) { + r = pakfire_db_remove_package(db, pkg); + if (r) + break; + } + + r = pakfire_db_add_package(db, pkg, archive); + if (r) + break; + + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTIN, pkg, archive); + break; + + case PAKFIRE_STEP_UPGRADE: + case PAKFIRE_STEP_DOWNGRADE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PREUP, pkg, archive); + if (r) + break; + + r = pakfire_transaction_extract(transaction, pkg, archive); + if (r) + break; + + r = pakfire_db_add_package(db, pkg, archive); + if (r) + break; + + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTUP, pkg, archive); + break; + + case PAKFIRE_STEP_ERASE: + case PAKFIRE_STEP_OBSOLETE: + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_PREUN, pkg, archive); + if (r) + break; + + r = pakfire_transaction_erase(transaction, pkg, archive); + if (r) + break; + + r = pakfire_db_remove_package(db, pkg); + if (r) + break; + + r = pakfire_transaction_run_script(transaction, db, + PAKFIRE_SCRIPTLET_POSTUN, pkg, archive); + break; + + case PAKFIRE_STEP_IGNORE: + break; + } + break; + + // Do nothing + case PAKFIRE_ACTION_NOOP: + break; + } + + if (r) + ERROR(transaction->pakfire, "Step has failed: %s\n", strerror(r)); + + return r; +} + static int pakfire_transaction_run_steps(struct pakfire_transaction* transaction, struct pakfire_db* db, const pakfire_action_type_t action) { int r = 0; // Walk through all steps - for (unsigned int i = 0; i < transaction->num_steps; i++) { - PakfireStep step = transaction->steps[i]; - - // Verify the step - r = pakfire_step_run(step, db, action); + for (unsigned int i = 0; i < transaction->num; i++) { + r = pakfire_transaction_run_step(transaction, db, action, + transaction->packages[i], transaction->archives[i]); // End loop if action was unsuccessful if (r) { - DEBUG(transaction->pakfire, "Step %p failed with code %d\n", step, r); + DEBUG(transaction->pakfire, "Step %d failed: %s\n", i, strerror(errno)); break; } } @@ -446,12 +711,49 @@ static int pakfire_transaction_run_steps(struct pakfire_transaction* transaction return r; } +static int pakfire_transaction_open_archives(struct pakfire_transaction* transaction) { + for (unsigned int i = 0; i < transaction->num; i++) { + PakfirePackage pkg = transaction->packages[i]; + + // Fetch the type + pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg); + + // Do we need the archive? + switch (type) { + case PAKFIRE_STEP_INSTALL: + case PAKFIRE_STEP_REINSTALL: + case PAKFIRE_STEP_UPGRADE: + case PAKFIRE_STEP_DOWNGRADE: + case PAKFIRE_STEP_OBSOLETE: + break; + + case PAKFIRE_STEP_ERASE: + case PAKFIRE_STEP_IGNORE: + continue; + } + + transaction->archives[i] = pakfire_package_get_archive(pkg); + if (!transaction->archives[i]) { + ERROR(transaction->pakfire, "Could not open archive for %s: %s\n", + pakfire_package_get_nevra(pkg), strerror(errno)); + return 1; + } + } + + return 0; +} + PAKFIRE_EXPORT int pakfire_transaction_run(struct pakfire_transaction* transaction) { struct pakfire_db* db; int r; DEBUG(transaction->pakfire, "Running Transaction %p\n", transaction); + // Open all archives + r = pakfire_transaction_open_archives(transaction); + if (r) + return r; + // Open the database r = pakfire_db_open(&db, transaction->pakfire, PAKFIRE_DB_READWRITE); if (r) { @@ -544,20 +846,23 @@ PAKFIRE_EXPORT int pakfire_transaction_download(struct pakfire_transaction* tran } // Add all packages that need to be downloaded - for (unsigned int i = 0; i < transaction->num_steps; i++) { - PakfireStep step = transaction->steps[i]; - - // Skip all steps that do not require a download - if (!pakfire_step_needs_download(step)) - continue; + for (unsigned int i = 0; i < transaction->num; i++) { + PakfirePackage pkg = transaction->packages[i]; + + pakfire_step_type_t type = pakfire_transaction_get_step_type(transaction, pkg); + switch (type) { + case PAKFIRE_STEP_INSTALL: + case PAKFIRE_STEP_REINSTALL: + case PAKFIRE_STEP_DOWNGRADE: + case PAKFIRE_STEP_UPGRADE: + break; - // Fetch the package - PakfirePackage pkg = pakfire_step_get_package(step); + default: + continue; + } // Enqueue download r = pakfire_transaction_download_package(transaction, downloader, pkg); - pakfire_package_unref(pkg); - if (r) goto ERROR; }