]> git.ipfire.org Git - pakfire.git/commitdiff
transaction: Move steps into transactions
authorMichael Tremer <michael.tremer@ipfire.org>
Thu, 29 Apr 2021 10:09:13 +0000 (10:09 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Thu, 29 Apr 2021 10:09:13 +0000 (10:09 +0000)
There is no point to separate this into multiple files since we no
longer export the steps

Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
src/libpakfire/execute.c
src/libpakfire/include/pakfire/execute.h
src/libpakfire/include/pakfire/scriptlet.h
src/libpakfire/include/pakfire/step.h [deleted file]
src/libpakfire/scriptlet.c
src/libpakfire/step.c [deleted file]
src/libpakfire/transaction.c

index 6c12e603cf7bf8647287aac7cdbb771093afa817..ef90387567fdf6feb2903b2b2671d7b637ba6a9e 100644 (file)
@@ -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
index 6e85872a3b2f11e61b7d8ad22ac207d81baa9854..eb9ec758924501b9fe3d0146cf60e572d221daa3 100644 (file)
@@ -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;
+}
index 09e688ced7661c7c4aa92c68c7e5f71cae507889..e9068050301942aabeec1bf29a32effe3fadca31 100644 (file)
@@ -39,4 +39,10 @@ enum {
        PAKFIRE_EXECUTE_INTERACTIVE     = (1 << 1),
 };
 
+#ifdef PAKFIRE_PRIVATE
+
+int pakfire_execute_ldconfig(Pakfire pakfire);
+
+#endif
+
 #endif /* PAKFIRE_EXECUTE_H */
index e70d5ab3b5abb98cb8122bb6ae1a3c2d1369bb66..79e481093c109bc866d1b855b84ac4590e67200f 100644 (file)
@@ -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 (file)
index 56e80a8..0000000
+++ /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 <http://www.gnu.org/licenses/>.       #
-#                                                                             #
-#############################################################################*/
-
-#ifndef PAKFIRE_STEP_H
-#define PAKFIRE_STEP_H
-
-#ifdef PAKFIRE_PRIVATE
-
-#include <pakfire/db.h>
-#include <pakfire/types.h>
-
-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 */
index 7ef72679d4968bb7eee44a3e4ce93c6b3a5ece1e..d475bc960f6ae1794ab8584662b6359ed76a4e22 100644 (file)
@@ -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 (file)
index 0008260..0000000
+++ /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 <http://www.gnu.org/licenses/>.       #
-#                                                                             #
-#############################################################################*/
-
-#include <errno.h>
-#include <linux/limits.h>
-#include <stdbool.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include <pakfire/archive.h>
-#include <pakfire/constants.h>
-#include <pakfire/db.h>
-#include <pakfire/execute.h>
-#include <pakfire/logging.h>
-#include <pakfire/package.h>
-#include <pakfire/pakfire.h>
-#include <pakfire/private.h>
-#include <pakfire/repo.h>
-#include <pakfire/scriptlet.h>
-#include <pakfire/step.h>
-#include <pakfire/transaction.h>
-#include <pakfire/types.h>
-#include <pakfire/util.h>
-
-#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;
-}
index 945836038f818cbd51f63577cdfe79e4b9a48ce8..3cbab27b547bba01dea4bee2321883b92a5c428e 100644 (file)
 
 #include <solv/transaction.h>
 
+#include <pakfire/archive.h>
 #include <pakfire/db.h>
 #include <pakfire/downloader.h>
+#include <pakfire/execute.h>
 #include <pakfire/i18n.h>
 #include <pakfire/logging.h>
 #include <pakfire/package.h>
 #include <pakfire/pakfire.h>
 #include <pakfire/private.h>
 #include <pakfire/repo.h>
-#include <pakfire/step.h>
 #include <pakfire/transaction.h>
 #include <pakfire/types.h>
 #include <pakfire/util.h>
@@ -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;
        }