db: implement triggers (fixes #45)
parent
b71606dbf4
commit
279513bfbe
|
@ -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 {
|
||||
|
|
152
src/database.c
152
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,
|
||||
|
|
|
@ -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,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",
|
||||
|
|
Loading…
Reference in New Issue