Commit 279513bf authored by Timo Teräs's avatar Timo Teräs

db: implement triggers (fixes #45)

parent b71606db
......@@ -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];
......
......@@ -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);
......
......@@ -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)
......
......@@ -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 {
......
......@@ -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,
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);
apk_blob_for_each_segment(r, " ", parse_triggers, ctx);
} 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,
......
......@@ -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;
......
......@@ -801,7 +801,7 @@ int apk_state_commit(struct apk_state *state,
apk_draw_progress(20, 1);
update_state:
if (!(apk_flags & APK_SIMULATE))
apk_db_run_triggers(db);
apk_db_write_config(db);
if (r == 0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment