From a0097ba209867f9cc8258de61be20331d07dbacb Mon Sep 17 00:00:00 2001 From: Michael Tremer Date: Thu, 3 Jun 2021 16:43:25 +0000 Subject: [PATCH] scriptlets: Refactor and extend to full type This was supposed to be a "light" object but that turns out to be more complicated than it should. This patch extends scriptlets to be regular (but private) type and makes it easier to use in the remaining code. Signed-off-by: Michael Tremer --- src/libpakfire/archive.c | 49 ++++--- src/libpakfire/db.c | 43 +++--- src/libpakfire/include/pakfire/archive.h | 2 +- src/libpakfire/include/pakfire/db.h | 2 +- src/libpakfire/include/pakfire/scriptlet.h | 43 ++---- src/libpakfire/scriptlet.c | 152 ++++++++++++++------- src/libpakfire/transaction.c | 39 +++--- 7 files changed, 184 insertions(+), 146 deletions(-) diff --git a/src/libpakfire/archive.c b/src/libpakfire/archive.c index efe27729c..879c12d37 100644 --- a/src/libpakfire/archive.c +++ b/src/libpakfire/archive.c @@ -412,7 +412,7 @@ static void pakfire_archive_free(PakfireArchive archive) { // Free scriptlets if (archive->scriptlets) { for (unsigned int i = 0; i < archive->nscriptlets; i++) - pakfire_scriptlet_free(archive->scriptlets[i]); + pakfire_scriptlet_unref(archive->scriptlets[i]); free(archive->scriptlets); } @@ -586,31 +586,46 @@ ERROR: static int pakfire_archive_parse_entry_scriptlet(PakfireArchive archive, struct archive* a, struct archive_entry* e, const char* filename) { - // Allocate a scriptlet - struct pakfire_scriptlet* scriptlet = pakfire_scriptlet_create(archive->pakfire, NULL, 0); - if (!scriptlet) - return -ENOMEM; + struct pakfire_scriptlet* scriptlet; + char* data = NULL; + size_t size = 0; + int r; - // Set the type - scriptlet->type = pakfire_scriptlet_type_from_filename(filename); + // Check if the filename matches + if (!pakfire_string_startswith(filename, "scriptlet/")) { + errno = EINVAL; + return 1; + } + + const char* type = filename + strlen("scriptlet/"); - int r = pakfire_archive_copy_data_to_buffer(archive->pakfire, a, e, - &scriptlet->data, &scriptlet->size); + // Fetch scriptlet + r = pakfire_archive_copy_data_to_buffer(archive->pakfire, a, e, &data, &size); if (r) return r; + // Allocate a scriptlet + r = pakfire_scriptlet_create(&scriptlet, archive->pakfire, type, data, size); + if (r) + goto ERROR; + // Make space for the new scriptlet - archive->scriptlets = realloc(archive->scriptlets, - sizeof(*archive->scriptlets) * (archive->nscriptlets + 1)); + archive->scriptlets = reallocarray(archive->scriptlets, archive->nscriptlets + 1, + sizeof(*archive->scriptlets)); if (!archive->scriptlets) { - pakfire_scriptlet_free(scriptlet); - return -ENOMEM; + pakfire_scriptlet_unref(scriptlet); + r = 1; + goto ERROR; } // Append the new scriptlet archive->scriptlets[archive->nscriptlets++] = scriptlet; - return 0; +ERROR: + if (data) + free(data); + + return r; } static int pakfire_archive_walk_entries(PakfireArchive archive, struct archive* a, @@ -1649,13 +1664,15 @@ PAKFIRE_EXPORT PakfirePackage pakfire_archive_make_package(PakfireArchive archiv } struct pakfire_scriptlet* pakfire_archive_get_scriptlet( - PakfireArchive archive, pakfire_scriptlet_type type) { + PakfireArchive archive, const char* type) { struct pakfire_scriptlet* scriptlet; for (unsigned int i = 0; i < archive->nscriptlets; i++) { scriptlet = archive->scriptlets[i]; - if (scriptlet->type == type) + const char* t = pakfire_scriptlet_get_type(scriptlet); + + if (strcmp(t, type) == 0) return scriptlet; } diff --git a/src/libpakfire/db.c b/src/libpakfire/db.c index abe649699..5a64f3f39 100644 --- a/src/libpakfire/db.c +++ b/src/libpakfire/db.c @@ -921,11 +921,9 @@ END: static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, PakfireArchive archive) { sqlite3_stmt* stmt = NULL; + size_t size; int r = 1; - const struct pakfire_scriptlet_type* scriptlet_type = PAKFIRE_SCRIPTLET_TYPES; - struct pakfire_scriptlet* scriptlet; - const char* sql = "INSERT INTO scriptlets(pkg, type, scriptlet) VALUES(?, ?, ?)"; // Prepare the statement @@ -936,34 +934,35 @@ static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, Pa goto END; } - while (scriptlet_type->type) { + for (const char** type = pakfire_scriptlet_types; *type; type++) { // Fetch the scriptlet - scriptlet = pakfire_archive_get_scriptlet(archive, scriptlet_type->type); - - // Go to next one if the archive does not have a scriptlet of the given type - if (!scriptlet) { - scriptlet_type++; + struct pakfire_scriptlet* scriptlet = pakfire_archive_get_scriptlet(archive, *type); + if (!scriptlet) continue; - } // Bind package ID r = sqlite3_bind_int64(stmt, 1, id); if (r) { ERROR(db->pakfire, "Could not bind id: %s\n", sqlite3_errmsg(db->handle)); + pakfire_scriptlet_unref(scriptlet); goto END; } // Bind handle - r = sqlite3_bind_text(stmt, 2, scriptlet_type->handle, -1, NULL); + r = sqlite3_bind_text(stmt, 2, *type, -1, NULL); if (r) { ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle)); + pakfire_scriptlet_unref(scriptlet); goto END; } + const char* data = pakfire_scriptlet_get_data(scriptlet, &size); + // Bind scriptlet - r = sqlite3_bind_text(stmt, 3, scriptlet->data, scriptlet->size, NULL); + r = sqlite3_bind_text(stmt, 3, data, size, NULL); if (r) { ERROR(db->pakfire, "Could not bind scriptlet: %s\n", sqlite3_errmsg(db->handle)); + pakfire_scriptlet_unref(scriptlet); goto END; } @@ -976,13 +975,14 @@ static int pakfire_db_add_scriptlets(struct pakfire_db* db, unsigned long id, Pa if (r != SQLITE_DONE) { ERROR(db->pakfire, "Could not add scriptlet to database: %s\n", sqlite3_errmsg(db->handle)); + pakfire_scriptlet_unref(scriptlet); goto END; } + pakfire_scriptlet_unref(scriptlet); + // Reset bound values sqlite3_reset(stmt); - - scriptlet_type++; } // All okay @@ -1283,7 +1283,7 @@ ERROR: } struct pakfire_scriptlet* pakfire_db_get_scriptlet(struct pakfire_db* db, - PakfirePackage pkg, pakfire_scriptlet_type type) { + PakfirePackage pkg, const char* type) { struct pakfire_scriptlet* scriptlet = NULL; sqlite3_stmt* stmt = NULL; int r = 1; @@ -1313,18 +1313,13 @@ struct pakfire_scriptlet* pakfire_db_get_scriptlet(struct pakfire_db* db, goto ERROR; } - // Bind type - const char* handle = pakfire_scriptlet_handle_from_type(type); - if (!handle) - goto ERROR; - - r = sqlite3_bind_text(stmt, 2, handle, -1, NULL); + r = sqlite3_bind_text(stmt, 2, type, -1, NULL); if (r) { ERROR(db->pakfire, "Could not bind type: %s\n", sqlite3_errmsg(db->handle)); goto ERROR; } - DEBUG(db->pakfire, "Searching for scriptlet for package %s of type %s\n", uuid, handle); + DEBUG(db->pakfire, "Searching for scriptlet for package %s of type %s\n", uuid, type); // Execute query do { @@ -1337,8 +1332,8 @@ struct pakfire_scriptlet* pakfire_db_get_scriptlet(struct pakfire_db* db, ssize_t size = sqlite3_column_bytes(stmt, 1); // Create a scriptlet object - scriptlet = pakfire_scriptlet_create(db->pakfire, data, size); - if (!scriptlet) + r = pakfire_scriptlet_create(&scriptlet, db->pakfire, type, data, size); + if (r) goto ERROR; } diff --git a/src/libpakfire/include/pakfire/archive.h b/src/libpakfire/include/pakfire/archive.h index bb6d041d7..2975543cf 100644 --- a/src/libpakfire/include/pakfire/archive.h +++ b/src/libpakfire/include/pakfire/archive.h @@ -76,7 +76,7 @@ PakfirePackage pakfire_archive_make_package(PakfireArchive archive, PakfireRepo #ifdef PAKFIRE_PRIVATE struct pakfire_scriptlet* pakfire_archive_get_scriptlet( - PakfireArchive archive, pakfire_scriptlet_type type); + PakfireArchive archive, const char* type); typedef enum archive_checksum_algo { PAKFIRE_CHECKSUM_UNKNOWN = 0, diff --git a/src/libpakfire/include/pakfire/db.h b/src/libpakfire/include/pakfire/db.h index e88645b4c..8873e651d 100644 --- a/src/libpakfire/include/pakfire/db.h +++ b/src/libpakfire/include/pakfire/db.h @@ -51,7 +51,7 @@ int pakfire_db_remove_package(struct pakfire_db* db, PakfirePackage pkg); int pakfire_db_load(struct pakfire_db* db, PakfireRepo repo); struct pakfire_scriptlet* pakfire_db_get_scriptlet( - struct pakfire_db* db, PakfirePackage pkg, pakfire_scriptlet_type type); + struct pakfire_db* db, PakfirePackage pkg, const char* type); #endif diff --git a/src/libpakfire/include/pakfire/scriptlet.h b/src/libpakfire/include/pakfire/scriptlet.h index 79e481093..ca678c7e0 100644 --- a/src/libpakfire/include/pakfire/scriptlet.h +++ b/src/libpakfire/include/pakfire/scriptlet.h @@ -27,44 +27,19 @@ #include -typedef enum _pakfire_script_types { - PAKFIRE_SCRIPTLET_UNDEFINED = 0, - PAKFIRE_SCRIPTLET_PREIN, - PAKFIRE_SCRIPTLET_PREUN, - PAKFIRE_SCRIPTLET_PREUP, - PAKFIRE_SCRIPTLET_POSTIN, - PAKFIRE_SCRIPTLET_POSTUN, - PAKFIRE_SCRIPTLET_POSTUP, - PAKFIRE_SCRIPTLET_PRETRANSIN, - PAKFIRE_SCRIPTLET_PRETRANSUN, - PAKFIRE_SCRIPTLET_PRETRANSUP, - PAKFIRE_SCRIPTLET_POSTTRANSIN, - PAKFIRE_SCRIPTLET_POSTTRANSUN, - PAKFIRE_SCRIPTLET_POSTTRANSUP, -} pakfire_scriptlet_type; +const char* pakfire_scriptlet_types[13]; -#define NUM_PAKFIRE_SCRIPTLET_TYPES 13 +struct pakfire_scriptlet; -struct pakfire_scriptlet_type { - pakfire_scriptlet_type type; - const char* filename; - const char* handle; -}; +int pakfire_scriptlet_create(struct pakfire_scriptlet** scriptlet, Pakfire pakfire, + const char* type, const char* data, size_t size); +struct pakfire_scriptlet* pakfire_scriptlet_ref(struct pakfire_scriptlet* scriptlet); +struct pakfire_scriptlet* pakfire_scriptlet_unref(struct pakfire_scriptlet* scriptlet); -const struct pakfire_scriptlet_type PAKFIRE_SCRIPTLET_TYPES[NUM_PAKFIRE_SCRIPTLET_TYPES + 1]; +const char* pakfire_scriptlet_get_type(struct pakfire_scriptlet* scriptlet); +const char* pakfire_scriptlet_get_data(struct pakfire_scriptlet* scriptlet, size_t* size); -struct pakfire_scriptlet { - pakfire_scriptlet_type type; - char* data; - size_t size; -}; - -struct pakfire_scriptlet* pakfire_scriptlet_create(Pakfire pakfire, const char* data, size_t size); -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); +int pakfire_scriptlet_execute(struct pakfire_scriptlet* scriptlet); #endif diff --git a/src/libpakfire/scriptlet.c b/src/libpakfire/scriptlet.c index 5e1c3c427..ded8db6ec 100644 --- a/src/libpakfire/scriptlet.c +++ b/src/libpakfire/scriptlet.c @@ -18,33 +18,61 @@ # # #############################################################################*/ +#include #include #include +#include #include #include #include +#include + +const char* pakfire_scriptlet_types[] = { + "prein", + "preun", + "preup", + "postin", + "postun", + "postup", + "pretransin", + "pretransun", + "pretransup", + "posttransin", + "posttransun", + "posttransup", + NULL, +}; + +struct pakfire_scriptlet { + Pakfire pakfire; + int nrefs; + + // Type + char type[NAME_MAX]; -const struct pakfire_scriptlet_type PAKFIRE_SCRIPTLET_TYPES[NUM_PAKFIRE_SCRIPTLET_TYPES + 1] = { - { PAKFIRE_SCRIPTLET_PREIN, "scriptlets/prein", "prein" }, - { PAKFIRE_SCRIPTLET_PREUN, "scriptlets/preun", "preun" }, - { PAKFIRE_SCRIPTLET_PREUP, "scriptlets/preup", "preup" }, - { PAKFIRE_SCRIPTLET_POSTIN, "scriptlets/postin", "postin" }, - { PAKFIRE_SCRIPTLET_POSTUN, "scriptlets/postun", "postun" }, - { PAKFIRE_SCRIPTLET_POSTUP, "scriptlets/postup", "postup" }, - { PAKFIRE_SCRIPTLET_PRETRANSIN, "scriptlets/pretransin", "pretransin" }, - { PAKFIRE_SCRIPTLET_PRETRANSUN, "scriptlets/pretransun", "pretransun" }, - { PAKFIRE_SCRIPTLET_PRETRANSUP, "scriptlets/pretransup", "pretransup" }, - { PAKFIRE_SCRIPTLET_POSTTRANSIN, "scriptlets/posttransin", "posttransin" }, - { PAKFIRE_SCRIPTLET_POSTTRANSUN, "scriptlets/posttransun", "posttransun" }, - { PAKFIRE_SCRIPTLET_POSTTRANSUP, "scriptlets/posttransup", "posttransup" }, - { PAKFIRE_SCRIPTLET_UNDEFINED, NULL, NULL }, + // Data and size + char* data; + size_t size; }; +static int pakfire_scriptlet_valid_type(const char* type) { + for (const char** t = pakfire_scriptlet_types; *t; t++) { + if (strcmp(*t, type) == 0) + return 1; + } + + return 0; +} + static int pakfire_scriptlet_set(struct pakfire_scriptlet* scriptlet, const char* data, size_t size) { if (scriptlet->data) free(scriptlet->data); + // Fill size if unset + if (!size) + size = strlen(data); + // Allocate space for data scriptlet->data = malloc(size); if (!scriptlet->data) @@ -52,60 +80,79 @@ static int pakfire_scriptlet_set(struct pakfire_scriptlet* scriptlet, const char // Copy data memcpy(scriptlet->data, data, size); + scriptlet->size = size; return 0; } -struct pakfire_scriptlet* pakfire_scriptlet_create(Pakfire pakfire, const char* data, size_t size) { - struct pakfire_scriptlet* scriptlet = calloc(1, sizeof(*scriptlet)); - if (!scriptlet) - return NULL; - - if (data && size) { - int r = pakfire_scriptlet_set(scriptlet, data, size); - if (r) { - pakfire_scriptlet_free(scriptlet); - return NULL; - } - } - - return scriptlet; -}; - -void pakfire_scriptlet_free(struct pakfire_scriptlet* scriptlet) { +static void pakfire_scriptlet_free(struct pakfire_scriptlet* scriptlet) { if (scriptlet->data) free(scriptlet->data); + pakfire_unref(scriptlet->pakfire); free(scriptlet); } -pakfire_scriptlet_type pakfire_scriptlet_type_from_filename(const char* filename) { - const struct pakfire_scriptlet_type* t = PAKFIRE_SCRIPTLET_TYPES; - - while (t->type) { - if (strcmp(t->filename, filename) == 0) - return t->type; +int pakfire_scriptlet_create(struct pakfire_scriptlet** scriptlet, Pakfire pakfire, + const char* type, const char* data, size_t size) { + if (!type || !data) { + errno = EINVAL; + return 1; + } - t++; + // Do we know this type? + if (!pakfire_scriptlet_valid_type(type)) { + errno = ENOTSUP; + return 1; } - return PAKFIRE_SCRIPTLET_UNDEFINED; -} + struct pakfire_scriptlet* s = calloc(1, sizeof(*s)); + if (!s) + return 1; -const char* pakfire_scriptlet_handle_from_type(pakfire_scriptlet_type type) { - const struct pakfire_scriptlet_type* t = PAKFIRE_SCRIPTLET_TYPES; + // Store reference to Pakfire + s->pakfire = pakfire_ref(pakfire); + s->nrefs = 1; - while (t->type) { - if (t->type == type) - return t->handle; + // Set type + pakfire_string_set(s->type, type); - t++; + int r = pakfire_scriptlet_set(s, data, size); + if (r) { + pakfire_scriptlet_free(s); + return 1; } + *scriptlet = s; + return 0; +}; + +struct pakfire_scriptlet* pakfire_scriptlet_ref(struct pakfire_scriptlet* scriptlet) { + scriptlet->nrefs++; + + return scriptlet; +} + +struct pakfire_scriptlet* pakfire_scriptlet_unref(struct pakfire_scriptlet* scriptlet) { + if (--scriptlet->nrefs > 0) + return scriptlet; + + pakfire_scriptlet_free(scriptlet); return NULL; } -int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet) { +const char* pakfire_scriptlet_get_type(struct pakfire_scriptlet* scriptlet) { + return scriptlet->type; +} + +const char* pakfire_scriptlet_get_data(struct pakfire_scriptlet* scriptlet, size_t* size) { + if (size) + *size = scriptlet->size; + + return scriptlet->data; +} + +static int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet) { const char* interpreter = "#!/bin/sh"; // data must be long enough @@ -118,3 +165,14 @@ int pakfire_scriptlet_is_shell_script(struct pakfire_scriptlet* scriptlet) { return 0; } + +int pakfire_scriptlet_execute(struct pakfire_scriptlet* scriptlet) { + // Detect what kind of script this is and run it + if (pakfire_scriptlet_is_shell_script(scriptlet)) + return pakfire_execute_script(scriptlet->pakfire, scriptlet->data, scriptlet->size, + NULL, NULL, 0, NULL, NULL); + + ERROR(scriptlet->pakfire, "Scriptlet is of an unknown kind\n"); + errno = ENOTSUP; + return 1; +} diff --git a/src/libpakfire/transaction.c b/src/libpakfire/transaction.c index e67e792be..ed203d95a 100644 --- a/src/libpakfire/transaction.c +++ b/src/libpakfire/transaction.c @@ -457,7 +457,7 @@ static int pakfire_transaction_verify(struct pakfire_transaction* transaction, } static int pakfire_transaction_run_script(struct pakfire_transaction* transaction, - struct pakfire_db* db, pakfire_scriptlet_type type, PakfirePackage pkg, PakfireArchive archive) { + struct pakfire_db* db, const char* type, PakfirePackage pkg, PakfireArchive archive) { struct pakfire_scriptlet* scriptlet = NULL; // Fetch scriptlet from archive if possible @@ -470,17 +470,10 @@ static int pakfire_transaction_run_script(struct pakfire_transaction* transactio if (!scriptlet) return 0; - // Found a script! - DEBUG(transaction->pakfire, "Found scriptlet:\n%.*s", - (int)scriptlet->size, (const char*)scriptlet->data); + // Execute the scriptlet + pakfire_scriptlet_execute(scriptlet); - // 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, NULL, 0, NULL, NULL); - } else { - ERROR(transaction->pakfire, "Scriptlet is of an unknown kind\n"); - } + pakfire_scriptlet_unref(scriptlet); return 0; } @@ -564,19 +557,19 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, case PAKFIRE_STEP_INSTALL: case PAKFIRE_STEP_REINSTALL: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PRETRANSIN, pkg, archive); + "pretransin", pkg, archive); break; case PAKFIRE_STEP_UPGRADE: case PAKFIRE_STEP_DOWNGRADE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PRETRANSUP, pkg, archive); + "pretransup", pkg, archive); break; case PAKFIRE_STEP_ERASE: case PAKFIRE_STEP_OBSOLETE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PRETRANSUN, pkg, archive); + "pretransun", pkg, archive); break; case PAKFIRE_STEP_IGNORE: @@ -590,19 +583,19 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, case PAKFIRE_STEP_INSTALL: case PAKFIRE_STEP_REINSTALL: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTTRANSIN, pkg, archive); + "posttransin", pkg, archive); break; case PAKFIRE_STEP_UPGRADE: case PAKFIRE_STEP_DOWNGRADE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTTRANSUP, pkg, archive); + "posttransup", pkg, archive); break; case PAKFIRE_STEP_ERASE: case PAKFIRE_STEP_OBSOLETE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTTRANSUN, pkg, archive); + "posttransun", pkg, archive); break; case PAKFIRE_STEP_IGNORE: @@ -616,7 +609,7 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, case PAKFIRE_STEP_INSTALL: case PAKFIRE_STEP_REINSTALL: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PREIN, pkg, archive); + "prein", pkg, archive); if (r) break; @@ -636,13 +629,13 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, break; r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTIN, pkg, archive); + "postin", pkg, archive); break; case PAKFIRE_STEP_UPGRADE: case PAKFIRE_STEP_DOWNGRADE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PREUP, pkg, archive); + "preup", pkg, archive); if (r) break; @@ -655,13 +648,13 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, break; r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTUP, pkg, archive); + "postup", pkg, archive); break; case PAKFIRE_STEP_ERASE: case PAKFIRE_STEP_OBSOLETE: r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_PREUN, pkg, archive); + "preun", pkg, archive); if (r) break; @@ -674,7 +667,7 @@ static int pakfire_transaction_run_step(struct pakfire_transaction* transaction, break; r = pakfire_transaction_run_script(transaction, db, - PAKFIRE_SCRIPTLET_POSTUN, pkg, archive); + "postun", pkg, archive); break; case PAKFIRE_STEP_IGNORE: -- 2.47.2