summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorTimo Teras <timo.teras@iki.fi>2009-08-13 14:10:30 +0300
committerTimo Teras <timo.teras@iki.fi>2009-08-13 14:10:30 +0300
commit279513bfbe8f0f37c6fb7f38dc331f0290b19b2f (patch)
treecd6a5aef78391be52fcfb18d95fe6b1ab5ec3f17
parentb71606dbf42815cc82b5792eb53438673111a4d5 (diff)
downloadapk-tools-279513bfbe8f0f37c6fb7f38dc331f0290b19b2f.tar.bz2
apk-tools-279513bfbe8f0f37c6fb7f38dc331f0290b19b2f.tar.xz
db: implement triggers (fixes #45)
-rw-r--r--src/apk_blob.h2
-rw-r--r--src/apk_database.h12
-rw-r--r--src/apk_defines.h2
-rw-r--r--src/apk_package.h7
-rw-r--r--src/database.c152
-rw-r--r--src/package.c8
-rw-r--r--src/state.c4
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 <string.h>
#include <stdlib.h>
#include <signal.h>
+#include <fnmatch.h>
#include <sys/file.h>
#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",