From 279513bfbe8f0f37c6fb7f38dc331f0290b19b2f Mon Sep 17 00:00:00 2001 From: Timo Teras Date: Thu, 13 Aug 2009 14:10:30 +0300 Subject: db: implement triggers (fixes #45) --- src/apk_blob.h | 2 + src/apk_database.h | 12 +++-- src/apk_defines.h | 2 +- src/apk_package.h | 7 +-- src/database.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++------ src/package.c | 8 +-- src/state.c | 4 +- 7 files changed, 155 insertions(+), 32 deletions(-) diff --git a/src/apk_blob.h b/src/apk_blob.h index 06cd8b2..5a5e381 100644 --- a/src/apk_blob.h +++ b/src/apk_blob.h @@ -29,6 +29,8 @@ typedef int (*apk_blob_cb)(void *ctx, apk_blob_t blob); #define APK_CHECKSUM_SHA1 20 #define APK_CHECKSUM_DEFAULT APK_CHECKSUM_SHA1 +#define APK_BLOB_CHECKSUM_BUF 34 + /* Internal cointainer for MD5 or SHA1 */ struct apk_checksum { unsigned char data[20]; diff --git a/src/apk_database.h b/src/apk_database.h index 42e214a..dfaf0d3 100644 --- a/src/apk_database.h +++ b/src/apk_database.h @@ -36,9 +36,9 @@ struct apk_db_file { char name[]; }; -#define APK_DBDIRF_PROTECTED 0x0001 -#define APK_DBDIRF_SYMLINKS_ONLY 0x0002 -#define APK_DBDIRF_MODIFIED 0x0100 +#define APK_DBDIRF_PROTECTED 0x01 +#define APK_DBDIRF_SYMLINKS_ONLY 0x02 +#define APK_DBDIRF_MODIFIED 0x04 struct apk_db_dir { apk_hash_node hash_node; @@ -48,8 +48,9 @@ struct apk_db_dir { struct apk_db_dir *parent; unsigned short refs; - unsigned short flags; unsigned short namelen; + unsigned char flags; + char rooted_name[1]; char name[]; }; @@ -149,8 +150,9 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, APK_OPENF_NO_WORLD) int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts); -int apk_db_write_config(struct apk_database *db); void apk_db_close(struct apk_database *db); +int apk_db_write_config(struct apk_database *db); +int apk_db_run_triggers(struct apk_database *db); int apk_db_permanent(struct apk_database *db); struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg); diff --git a/src/apk_defines.h b/src/apk_defines.h index 0ecade4..a0b297a 100644 --- a/src/apk_defines.h +++ b/src/apk_defines.h @@ -254,7 +254,7 @@ static inline void list_del(struct list_head *entry) static inline int list_hashed(const struct list_head *n) { - return n->next != n->prev; + return n->next != n && n->next != NULL; } #define list_entry(ptr, type, member) container_of(ptr,type,member) diff --git a/src/apk_package.h b/src/apk_package.h index 6bca03d..dbd469c 100644 --- a/src/apk_package.h +++ b/src/apk_package.h @@ -29,9 +29,6 @@ struct apk_name; #define APK_SCRIPT_TRIGGER 6 #define APK_SCRIPT_MAX 7 -#define APK_PKG_NOT_INSTALLED 0 -#define APK_PKG_INSTALLED 1 - #define APK_SIGN_NONE 0 #define APK_SIGN_VERIFY 1 #define APK_SIGN_VERIFY_IDENTITY 2 @@ -71,13 +68,17 @@ struct apk_dependency { }; APK_ARRAY(apk_dependency_array, struct apk_dependency); +#define APK_IPKGF_RUN_ALL_TRIGGERS 0x00000001 + struct apk_installed_package { struct apk_package *pkg; + unsigned int flags; struct list_head installed_pkgs_list; struct list_head trigger_pkgs_list; struct hlist_head owned_dirs; apk_blob_t script[APK_SCRIPT_MAX]; struct apk_string_array *triggers; + struct apk_string_array *pending_triggers; }; struct apk_package { diff --git a/src/database.c b/src/database.c index dfaf343..23bed5a 100644 --- a/src/database.c +++ b/src/database.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include "apk_defines.h" @@ -225,6 +226,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, dir = malloc(sizeof(*dir) + name.len + 1); memset(dir, 0, sizeof(*dir)); dir->refs = 1; + dir->rooted_name[0] = '/'; memcpy(dir->name, name.ptr, name.len); dir->name[name.len] = 0; dir->namelen = name.len; @@ -740,6 +742,59 @@ static int apk_read_script_archive_entry(void *ctx, return 0; } +static int parse_triggers(void *ctx, apk_blob_t blob) +{ + struct apk_installed_package *ipkg = ctx; + + if (blob.len == 0) + return 0; + + *apk_string_array_add(&ipkg->triggers) = apk_blob_cstr(blob); + return 0; +} + +static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os) +{ + struct apk_installed_package *ipkg; + char buf[APK_BLOB_CHECKSUM_BUF]; + apk_blob_t bfn; + int i; + + list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) { + bfn = APK_BLOB_BUF(buf); + apk_blob_push_csum(&bfn, &ipkg->pkg->csum); + os->write(os, buf, buf - bfn.ptr); + for (i = 0; i < ipkg->triggers->num; i++) { + os->write(os, " ", 1); + apk_ostream_write_string(os, ipkg->triggers->item[i]); + } + os->write(os, "\n", 1); + } +} + +static void apk_db_triggers_read(struct apk_database *db, struct apk_bstream *bs) +{ + struct apk_checksum csum; + struct apk_package *pkg; + struct apk_installed_package *ipkg; + apk_blob_t l; + + while (!APK_BLOB_IS_NULL(l = bs->read(bs, APK_BLOB_STR("\n")))) { + apk_blob_pull_csum(&l, &csum); + apk_blob_pull_char(&l, ' '); + + pkg = apk_db_get_pkg(db, &csum); + if (pkg == NULL || pkg->ipkg == NULL) + continue; + + ipkg = pkg->ipkg; + apk_blob_for_each_segment(l, " ", parse_triggers, ipkg); + if (ipkg->triggers && !list_hashed(&ipkg->trigger_pkgs_list)) + list_add_tail(&ipkg->trigger_pkgs_list, + &db->installed.triggers); + } +} + static int apk_db_read_state(struct apk_database *db, int flags) { struct apk_istream *is; @@ -780,6 +835,12 @@ static int apk_db_read_state(struct apk_database *db, int flags) bs->close(bs, NULL); } } + + bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/triggers"); + if (bs != NULL) { + apk_db_triggers_read(db, bs); + bs->close(bs, NULL); + } } if (!(flags & APK_OPENF_NO_SCRIPTS)) { @@ -921,6 +982,7 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) apk_hash_init(&db->installed.dirs, &dir_hash_ops, 2000); apk_hash_init(&db->installed.files, &file_hash_ops, 10000); list_init(&db->installed.packages); + list_init(&db->installed.triggers); db->cache_dir = apk_static_cache_dir; db->permanent = 1; @@ -1046,7 +1108,7 @@ int apk_db_write_config(struct apk_database *db) struct apk_ostream *os; int r; - if (db->root == NULL) + if ((apk_flags & APK_SIMULATE) || db->root == NULL) return 0; if (db->lock_fd == 0) { @@ -1092,6 +1154,17 @@ int apk_db_write_config(struct apk_database *db) unlinkat(db->root_fd, "var/lib/apk/scripts", 0); apk_db_index_write_nr_cache(db); + os = apk_ostream_to_file(db->root_fd, + "var/lib/apk/triggers", + "var/lib/apk/triggers.new", + 0644); + if (os == NULL) + return -1; + apk_db_triggers_write(db, os); + r = os->close(os); + if (r < 0) + return r; + return 0; } @@ -1138,6 +1211,57 @@ void apk_db_close(struct apk_database *db) free(db->root); } +static int fire_triggers(apk_hash_item item, void *ctx) +{ + struct apk_database *db = (struct apk_database *) ctx; + struct apk_db_dir *dbd = (struct apk_db_dir *) item; + struct apk_installed_package *ipkg; + int i; + + list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) { + if (((ipkg->flags & APK_IPKGF_RUN_ALL_TRIGGERS) == 0) && + ((dbd->flags & APK_DBDIRF_MODIFIED) == 0)) + continue; + + for (i = 0; i < ipkg->triggers->num; i++) { + if (ipkg->triggers->item[i][0] != '/') + continue; + + if (fnmatch(ipkg->triggers->item[i], dbd->rooted_name, + FNM_PATHNAME) != 0) + continue; + + *apk_string_array_add(&ipkg->pending_triggers) = + dbd->rooted_name; + break; + } + } + + return 0; +} + +int apk_db_run_triggers(struct apk_database *db) +{ + struct apk_installed_package *ipkg; + + apk_hash_foreach(&db->installed.dirs, fire_triggers, db); + + list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) { + if (ipkg->pending_triggers == NULL) + continue; + + fprintf(stderr, "run triggers: %s\n", ipkg->pkg->name->name); + + *apk_string_array_add(&ipkg->pending_triggers) = NULL; + apk_ipkg_run_script(ipkg, db->root_fd, APK_SCRIPT_TRIGGER, + ipkg->pending_triggers->item); + free(ipkg->pending_triggers); + ipkg->pending_triggers = NULL; + } + + return 0; +} + int apk_db_cache_active(struct apk_database *db) { return db->cache_dir != apk_static_cache_dir; @@ -1452,18 +1576,6 @@ static int parse_replaces(void *_ctx, apk_blob_t blob) return 0; } -static int parse_triggers(void *_ctx, apk_blob_t blob) -{ - struct install_ctx *ctx = (struct install_ctx *) _ctx; - struct apk_installed_package *ipkg = ctx->ipkg; - - if (blob.len == 0) - return 0; - - *apk_string_array_add(&ipkg->triggers) = apk_blob_cstr(blob); - return 0; -} - static int read_info_line(void *_ctx, apk_blob_t line) { struct install_ctx *ctx = (struct install_ctx *) _ctx; @@ -1484,10 +1596,10 @@ static int read_info_line(void *_ctx, apk_blob_t line) free(ipkg->triggers); ipkg->triggers = NULL; } - if (!list_hashed(&ipkg->trigger_pkgs_list)) - list_add(&ipkg->trigger_pkgs_list, - &db->installed.triggers); - apk_blob_for_each_segment(r, " ", parse_triggers, ctx); + apk_blob_for_each_segment(r, " ", parse_triggers, ctx->ipkg); + if (ctx->ipkg->triggers && !list_hashed(&ipkg->trigger_pkgs_list)) + list_add_tail(&ipkg->trigger_pkgs_list, + &db->installed.triggers); } else { apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line); } @@ -1924,6 +2036,12 @@ int apk_db_install_pkg(struct apk_database *db, /* Install the new stuff */ ipkg = apk_pkg_install(db, newpkg); + ipkg->flags |= APK_IPKGF_RUN_ALL_TRIGGERS; + if (ipkg->triggers) { + list_del(&ipkg->trigger_pkgs_list); + free(ipkg->triggers); + ipkg->triggers = NULL; + } if (newpkg->installed_size != 0) { r = apk_db_unpack_pkg(db, ipkg, (oldpkg != NULL), (oldpkg == newpkg), cb, cb_ctx, diff --git a/src/package.c b/src/package.c index 24faaaf..4445aa6 100644 --- a/src/package.c +++ b/src/package.c @@ -66,8 +66,6 @@ struct apk_installed_package *apk_pkg_install(struct apk_database *db, pkg->ipkg = ipkg = calloc(1, sizeof(struct apk_installed_package)); ipkg->pkg = pkg; - list_init(&ipkg->installed_pkgs_list); - db->installed.stats.packages++; list_add_tail(&ipkg->installed_pkgs_list, &db->installed.packages); @@ -869,6 +867,10 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, pkg->name->name, pkg->version, apk_script_types[type]); + apk_message("Executing %s", &fn[15]); + if (apk_flags & APK_SIMULATE) + return 0; + fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755); if (fd < 0) { mkdirat(root_fd, "var/cache/misc", 0755); @@ -879,8 +881,6 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, write(fd, ipkg->script[type].ptr, ipkg->script[type].len); close(fd); - apk_message("Executing %s", &fn[15]); - pid = fork(); if (pid == -1) return -1; diff --git a/src/state.c b/src/state.c index a33a13e..7a5ab73 100644 --- a/src/state.c +++ b/src/state.c @@ -801,8 +801,8 @@ int apk_state_commit(struct apk_state *state, apk_draw_progress(20, 1); update_state: - if (!(apk_flags & APK_SIMULATE)) - apk_db_write_config(db); + apk_db_run_triggers(db); + apk_db_write_config(db); if (r == 0) apk_message("OK: %d packages, %d dirs, %d files", -- cgit v1.2.3