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); ...@@ -29,6 +29,8 @@ typedef int (*apk_blob_cb)(void *ctx, apk_blob_t blob);
#define APK_CHECKSUM_SHA1 20 #define APK_CHECKSUM_SHA1 20
#define APK_CHECKSUM_DEFAULT APK_CHECKSUM_SHA1 #define APK_CHECKSUM_DEFAULT APK_CHECKSUM_SHA1
#define APK_BLOB_CHECKSUM_BUF 34
/* Internal cointainer for MD5 or SHA1 */ /* Internal cointainer for MD5 or SHA1 */
struct apk_checksum { struct apk_checksum {
unsigned char data[20]; unsigned char data[20];
......
...@@ -36,9 +36,9 @@ struct apk_db_file { ...@@ -36,9 +36,9 @@ struct apk_db_file {
char name[]; char name[];
}; };
#define APK_DBDIRF_PROTECTED 0x0001 #define APK_DBDIRF_PROTECTED 0x01
#define APK_DBDIRF_SYMLINKS_ONLY 0x0002 #define APK_DBDIRF_SYMLINKS_ONLY 0x02
#define APK_DBDIRF_MODIFIED 0x0100 #define APK_DBDIRF_MODIFIED 0x04
struct apk_db_dir { struct apk_db_dir {
apk_hash_node hash_node; apk_hash_node hash_node;
...@@ -48,8 +48,9 @@ struct apk_db_dir { ...@@ -48,8 +48,9 @@ struct apk_db_dir {
struct apk_db_dir *parent; struct apk_db_dir *parent;
unsigned short refs; unsigned short refs;
unsigned short flags;
unsigned short namelen; unsigned short namelen;
unsigned char flags;
char rooted_name[1];
char name[]; char name[];
}; };
...@@ -149,8 +150,9 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, ...@@ -149,8 +150,9 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
APK_OPENF_NO_WORLD) APK_OPENF_NO_WORLD)
int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts); 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); 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); int apk_db_permanent(struct apk_database *db);
struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg); 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) ...@@ -254,7 +254,7 @@ static inline void list_del(struct list_head *entry)
static inline int list_hashed(const struct list_head *n) 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) #define list_entry(ptr, type, member) container_of(ptr,type,member)
......
...@@ -29,9 +29,6 @@ struct apk_name; ...@@ -29,9 +29,6 @@ struct apk_name;
#define APK_SCRIPT_TRIGGER 6 #define APK_SCRIPT_TRIGGER 6
#define APK_SCRIPT_MAX 7 #define APK_SCRIPT_MAX 7
#define APK_PKG_NOT_INSTALLED 0
#define APK_PKG_INSTALLED 1
#define APK_SIGN_NONE 0 #define APK_SIGN_NONE 0
#define APK_SIGN_VERIFY 1 #define APK_SIGN_VERIFY 1
#define APK_SIGN_VERIFY_IDENTITY 2 #define APK_SIGN_VERIFY_IDENTITY 2
...@@ -71,13 +68,17 @@ struct apk_dependency { ...@@ -71,13 +68,17 @@ struct apk_dependency {
}; };
APK_ARRAY(apk_dependency_array, struct apk_dependency); APK_ARRAY(apk_dependency_array, struct apk_dependency);
#define APK_IPKGF_RUN_ALL_TRIGGERS 0x00000001
struct apk_installed_package { struct apk_installed_package {
struct apk_package *pkg; struct apk_package *pkg;
unsigned int flags;
struct list_head installed_pkgs_list; struct list_head installed_pkgs_list;
struct list_head trigger_pkgs_list; struct list_head trigger_pkgs_list;
struct hlist_head owned_dirs; struct hlist_head owned_dirs;
apk_blob_t script[APK_SCRIPT_MAX]; apk_blob_t script[APK_SCRIPT_MAX];
struct apk_string_array *triggers; struct apk_string_array *triggers;
struct apk_string_array *pending_triggers;
}; };
struct apk_package { struct apk_package {
......
...@@ -18,6 +18,7 @@ ...@@ -18,6 +18,7 @@
#include <string.h> #include <string.h>
#include <stdlib.h> #include <stdlib.h>
#include <signal.h> #include <signal.h>
#include <fnmatch.h>
#include <sys/file.h> #include <sys/file.h>
#include "apk_defines.h" #include "apk_defines.h"
...@@ -225,6 +226,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db, ...@@ -225,6 +226,7 @@ static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
dir = malloc(sizeof(*dir) + name.len + 1); dir = malloc(sizeof(*dir) + name.len + 1);
memset(dir, 0, sizeof(*dir)); memset(dir, 0, sizeof(*dir));
dir->refs = 1; dir->refs = 1;
dir->rooted_name[0] = '/';
memcpy(dir->name, name.ptr, name.len); memcpy(dir->name, name.ptr, name.len);
dir->name[name.len] = 0; dir->name[name.len] = 0;
dir->namelen = name.len; dir->namelen = name.len;
...@@ -740,6 +742,59 @@ static int apk_read_script_archive_entry(void *ctx, ...@@ -740,6 +742,59 @@ static int apk_read_script_archive_entry(void *ctx,
return 0; 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) static int apk_db_read_state(struct apk_database *db, int flags)
{ {
struct apk_istream *is; struct apk_istream *is;
...@@ -780,6 +835,12 @@ static int apk_db_read_state(struct apk_database *db, int flags) ...@@ -780,6 +835,12 @@ static int apk_db_read_state(struct apk_database *db, int flags)
bs->close(bs, NULL); 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)) { if (!(flags & APK_OPENF_NO_SCRIPTS)) {
...@@ -921,6 +982,7 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) ...@@ -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.dirs, &dir_hash_ops, 2000);
apk_hash_init(&db->installed.files, &file_hash_ops, 10000); apk_hash_init(&db->installed.files, &file_hash_ops, 10000);
list_init(&db->installed.packages); list_init(&db->installed.packages);
list_init(&db->installed.triggers);
db->cache_dir = apk_static_cache_dir; db->cache_dir = apk_static_cache_dir;
db->permanent = 1; db->permanent = 1;
...@@ -1046,7 +1108,7 @@ int apk_db_write_config(struct apk_database *db) ...@@ -1046,7 +1108,7 @@ int apk_db_write_config(struct apk_database *db)
struct apk_ostream *os; struct apk_ostream *os;
int r; int r;
if (db->root == NULL) if ((apk_flags & APK_SIMULATE) || db->root == NULL)
return 0; return 0;
if (db->lock_fd == 0) { if (db->lock_fd == 0) {
...@@ -1092,6 +1154,17 @@ int apk_db_write_config(struct apk_database *db) ...@@ -1092,6 +1154,17 @@ int apk_db_write_config(struct apk_database *db)
unlinkat(db->root_fd, "var/lib/apk/scripts", 0); unlinkat(db->root_fd, "var/lib/apk/scripts", 0);
apk_db_index_write_nr_cache(db); 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; return 0;
} }
...@@ -1138,6 +1211,57 @@ void apk_db_close(struct apk_database *db) ...@@ -1138,6 +1211,57 @@ void apk_db_close(struct apk_database *db)
free(db->root); 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) int apk_db_cache_active(struct apk_database *db)
{ {
return db->cache_dir != apk_static_cache_dir; return db->cache_dir != apk_static_cache_dir;
...@@ -1452,18 +1576,6 @@ static int parse_replaces(void *_ctx, apk_blob_t blob) ...@@ -1452,18 +1576,6 @@ static int parse_replaces(void *_ctx, apk_blob_t blob)
return 0; 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) static int read_info_line(void *_ctx, apk_blob_t line)
{ {
struct install_ctx *ctx = (struct install_ctx *) _ctx; struct install_ctx *ctx = (struct install_ctx *) _ctx;
...@@ -1484,10 +1596,10 @@ static int read_info_line(void *_ctx, apk_blob_t line) ...@@ -1484,10 +1596,10 @@ static int read_info_line(void *_ctx, apk_blob_t line)
free(ipkg->triggers); free(ipkg->triggers);
ipkg->triggers = NULL; ipkg->triggers = NULL;
} }
if (!list_hashed(&ipkg->trigger_pkgs_list)) apk_blob_for_each_segment(r, " ", parse_triggers, ctx->ipkg);
list_add(&ipkg->trigger_pkgs_list, if (ctx->ipkg->triggers && !list_hashed(&ipkg->trigger_pkgs_list))
&db->installed.triggers); list_add_tail(&ipkg->trigger_pkgs_list,
apk_blob_for_each_segment(r, " ", parse_triggers, ctx); &db->installed.triggers);
} else { } else {
apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line); apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line);
} }
...@@ -1924,6 +2036,12 @@ int apk_db_install_pkg(struct apk_database *db, ...@@ -1924,6 +2036,12 @@ int apk_db_install_pkg(struct apk_database *db,
/* Install the new stuff */ /* Install the new stuff */
ipkg = apk_pkg_install(db, newpkg); 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) { if (newpkg->installed_size != 0) {
r = apk_db_unpack_pkg(db, ipkg, (oldpkg != NULL), r = apk_db_unpack_pkg(db, ipkg, (oldpkg != NULL),
(oldpkg == newpkg), cb, cb_ctx, (oldpkg == newpkg), cb, cb_ctx,
......
...@@ -66,8 +66,6 @@ struct apk_installed_package *apk_pkg_install(struct apk_database *db, ...@@ -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)); pkg->ipkg = ipkg = calloc(1, sizeof(struct apk_installed_package));
ipkg->pkg = pkg; ipkg->pkg = pkg;
list_init(&ipkg->installed_pkgs_list);
db->installed.stats.packages++; db->installed.stats.packages++;
list_add_tail(&ipkg->installed_pkgs_list, &db->installed.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, ...@@ -869,6 +867,10 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd,
pkg->name->name, pkg->version, pkg->name->name, pkg->version,
apk_script_types[type]); 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); fd = openat(root_fd, fn, O_CREAT|O_RDWR|O_TRUNC, 0755);
if (fd < 0) { if (fd < 0) {
mkdirat(root_fd, "var/cache/misc", 0755); mkdirat(root_fd, "var/cache/misc", 0755);
...@@ -879,8 +881,6 @@ int apk_ipkg_run_script(struct apk_installed_package *ipkg, int root_fd, ...@@ -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); write(fd, ipkg->script[type].ptr, ipkg->script[type].len);
close(fd); close(fd);
apk_message("Executing %s", &fn[15]);
pid = fork(); pid = fork();
if (pid == -1) if (pid == -1)
return -1; return -1;
......
...@@ -801,8 +801,8 @@ int apk_state_commit(struct apk_state *state, ...@@ -801,8 +801,8 @@ int apk_state_commit(struct apk_state *state,
apk_draw_progress(20, 1); apk_draw_progress(20, 1);
update_state: update_state:
if (!(apk_flags & APK_SIMULATE)) apk_db_run_triggers(db);
apk_db_write_config(db); apk_db_write_config(db);
if (r == 0) if (r == 0)
apk_message("OK: %d packages, %d dirs, %d files", apk_message("OK: %d packages, %d dirs, %d files",
......
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