Newer
Older
/* database.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008-2009 Timo Teräs <timo.teras@iki.fi>
* All rights reserved.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 as published
* by the Free Software Foundation. See http://www.gnu.org/ for details.
*/
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#include <mntent.h>
#include <unistd.h>
#include <malloc.h>
#include <string.h>
#include <stdlib.h>
#include <signal.h>
#include <sys/file.h>
#include <sys/wait.h>
#include <sys/statvfs.h>
#include "apk_defines.h"
#include "apk_package.h"
#include "apk_database.h"
#include "apk_state.h"
#if defined(__x86_64__)
#define APK_DEFAULT_ARCH "x86_64"
#elif defined(__i386__)
#define APK_DEFAULT_ARCH "x86"
#else
#define APK_DEFAULT_ARCH "noarch"
#endif
enum {
APK_DISALLOW_RMDIR = 0,
APK_ALLOW_RMDIR = 1
};
int apk_verbosity = 1;
unsigned int apk_flags = 0;
const char *apk_arch = APK_DEFAULT_ARCH;
const char * const apkindex_tar_gz = "APKINDEX.tar.gz";
static const char * const apk_static_cache_dir = "var/lib/apk";
static const char * const apk_linked_cache_dir = "etc/apk/cache";
struct install_ctx {
struct apk_database *db;
struct apk_package *pkg;
struct apk_installed_package *ipkg;
int script;
char **script_args;
int script_pending : 1;
struct apk_sign_ctx sctx;
struct apk_name_array *replaces;
apk_progress_cb cb;
void *cb_ctx;
size_t installed_size;
size_t current_file_size;
struct hlist_node **diri_node;
struct hlist_node **file_diri_node;
};
static apk_blob_t pkg_name_get_key(apk_hash_item item)
{
return APK_BLOB_STR(((struct apk_name *) item)->name);
}
static void pkg_name_free(struct apk_name *name)
{
free(name->name);
apk_package_array_free(&name->pkgs);
apk_name_array_free(&name->rdepends);
static const struct apk_hash_ops pkg_name_hash_ops = {
.node_offset = offsetof(struct apk_name, hash_node),
.get_key = pkg_name_get_key,
.hash_key = apk_blob_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) pkg_name_free,
};
static apk_blob_t pkg_info_get_key(apk_hash_item item)
{
return APK_BLOB_CSUM(((struct apk_package *) item)->csum);
}
static unsigned long csum_hash(apk_blob_t csum)
{
/* Checksum's highest bits have the most "randomness", use that
* directly as hash */
}
static const struct apk_hash_ops pkg_info_hash_ops = {
.node_offset = offsetof(struct apk_package, hash_node),
.get_key = pkg_info_get_key,
.hash_key = csum_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) apk_pkg_free,
};
static apk_blob_t apk_db_dir_get_key(apk_hash_item item)
{
struct apk_db_dir *dir = (struct apk_db_dir *) item;
return APK_BLOB_PTR_LEN(dir->name, dir->namelen);
}
static const struct apk_hash_ops dir_hash_ops = {
.node_offset = offsetof(struct apk_db_dir, hash_node),
.get_key = apk_db_dir_get_key,
.hash_key = apk_blob_hash,
.compare = apk_blob_compare,
.delete_item = (apk_hash_delete_f) free,
};
struct apk_db_file_hash_key {
apk_blob_t dirname;
apk_blob_t filename;
};
static unsigned long apk_db_file_hash_key(apk_blob_t _key)
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
return apk_blob_hash_seed(key->filename, apk_blob_hash(key->dirname));
}
static unsigned long apk_db_file_hash_item(apk_hash_item item)
{
struct apk_db_file *dbf = (struct apk_db_file *) item;
return apk_blob_hash_seed(APK_BLOB_PTR_LEN(dbf->name, dbf->namelen),
dbf->diri->dir->hash);
}
static int apk_db_file_compare_item(apk_hash_item item, apk_blob_t _key)
{
struct apk_db_file *dbf = (struct apk_db_file *) item;
struct apk_db_file_hash_key *key = (struct apk_db_file_hash_key *) _key.ptr;
int r;
r = apk_blob_compare(key->filename,
APK_BLOB_PTR_LEN(dbf->name, dbf->namelen));
if (r != 0)
return r;
r = apk_blob_compare(key->dirname,
APK_BLOB_PTR_LEN(dir->name, dir->namelen));
return r;
}
static const struct apk_hash_ops file_hash_ops = {
.node_offset = offsetof(struct apk_db_file, hash_node),
.hash_key = apk_db_file_hash_key,
.hash_item = apk_db_file_hash_item,
.compare_item = apk_db_file_compare_item,
.delete_item = (apk_hash_delete_f) free,
};
struct apk_name *apk_db_query_name(struct apk_database *db, apk_blob_t name)
{
return (struct apk_name *) apk_hash_get(&db->available.names, name);
}
struct apk_name *apk_db_get_name(struct apk_database *db, apk_blob_t name)
{
struct apk_name *pn;
unsigned long hash = apk_hash_from_key(&db->available.names, name);
pn = (struct apk_name *) apk_hash_get_hashed(&db->available.names, name, hash);
if (pn != NULL)
return pn;
pn = calloc(1, sizeof(struct apk_name));
if (pn == NULL)
return NULL;
apk_package_array_init(&pn->pkgs);
apk_name_array_init(&pn->rdepends);
apk_hash_insert_hashed(&db->available.names, pn, hash);
return pn;
}
static void apk_db_dir_unref(struct apk_database *db, struct apk_db_dir *dir,
int allow_rmdir)
{
dir->refs--;
if (dir->refs > 0)
return;
db->installed.stats.dirs--;
if (allow_rmdir)
unlinkat(db->root_fd, dir->name, AT_REMOVEDIR);
if (dir->parent != NULL)
apk_db_dir_unref(db, dir->parent, allow_rmdir);
}
static struct apk_db_dir *apk_db_dir_ref(struct apk_db_dir *dir)
{
dir->refs++;
return dir;
}
struct apk_db_dir *apk_db_dir_query(struct apk_database *db,
apk_blob_t name)
{
return (struct apk_db_dir *) apk_hash_get(&db->installed.dirs, name);
}
static struct apk_db_dir *apk_db_dir_get(struct apk_database *db,
apk_blob_t name)
{
struct apk_db_dir *dir;
apk_blob_t bparent;
unsigned long hash = apk_hash_from_key(&db->installed.dirs, name);
if (name.len && name.ptr[name.len-1] == '/')
name.len--;
dir = (struct apk_db_dir *) apk_hash_get_hashed(&db->installed.dirs, name, hash);
if (dir != NULL)
return apk_db_dir_ref(dir);
dir = malloc(sizeof(*dir) + name.len + 1);
memset(dir, 0, sizeof(*dir));
memcpy(dir->name, name.ptr, name.len);
dir->name[name.len] = 0;
dir->namelen = name.len;
dir->hash = hash;
apk_hash_insert_hashed(&db->installed.dirs, dir, hash);
if (name.len == 0)
dir->parent = NULL;
else if (apk_blob_rsplit(name, '/', &bparent, NULL))
dir->parent = apk_db_dir_get(db, bparent);
dir->parent = apk_db_dir_get(db, APK_BLOB_NULL);
if (dir->parent != NULL)
dir->flags = dir->parent->flags;
for (i = 0; i < db->protected_paths->num; i++) {
int flags = dir->flags, j;
flags |= APK_DBDIRF_PROTECTED;
for (j = 0; ; j++) {
switch (db->protected_paths->item[i][j]) {
case '-':
flags &= ~(APK_DBDIRF_PROTECTED |
APK_DBDIRF_SYMLINKS_ONLY);
continue;
case '*':
flags |= APK_DBDIRF_SYMLINKS_ONLY |
APK_DBDIRF_PROTECTED;
continue;
}
break;
}
if (strcmp(&db->protected_paths->item[i][j], dir->name) == 0)
dir->flags = flags;
return dir;
}
static struct apk_db_dir_instance *apk_db_diri_new(struct apk_database *db,
struct apk_package *pkg,
apk_blob_t name,
struct hlist_node ***after)
{
struct apk_db_dir_instance *diri;
diri = calloc(1, sizeof(struct apk_db_dir_instance));
hlist_add_after(&diri->pkg_dirs_list, *after);
*after = &diri->pkg_dirs_list.next;
diri->dir = apk_db_dir_get(db, name);
return diri;
}
static void apk_db_diri_set(struct apk_db_dir_instance *diri, mode_t mode,
uid_t uid, gid_t gid)
{
diri->mode = mode;
diri->uid = uid;
diri->gid = gid;
}
static void apk_db_diri_mkdir(struct apk_database *db, struct apk_db_dir_instance *diri)
if (mkdirat(db->root_fd, diri->dir->name, diri->mode) == 0) {
if (fchownat(db->root_fd, diri->dir->name, diri->uid, diri->gid, 0) != 0)
;
}
static void apk_db_diri_free(struct apk_database *db,
struct apk_db_dir_instance *diri,
int allow_rmdir)
apk_db_dir_unref(db, diri->dir, allow_rmdir);
struct apk_db_file *apk_db_file_query(struct apk_database *db,
apk_blob_t dir,
apk_blob_t name)
{
struct apk_db_file_hash_key key;
key = (struct apk_db_file_hash_key) {
.dirname = dir,
.filename = name,
};
return (struct apk_db_file *) apk_hash_get(&db->installed.files,
APK_BLOB_BUF(&key));
}
static struct apk_db_file *apk_db_file_new(struct apk_db_dir_instance *diri,
apk_blob_t name,
struct hlist_node ***after)
{
struct apk_db_file *file;
file = malloc(sizeof(*file) + name.len + 1);
if (file == NULL)
return NULL;
memset(file, 0, sizeof(*file));
memcpy(file->name, name.ptr, name.len);
file->name[name.len] = 0;
file->namelen = name.len;
file->diri = diri;
hlist_add_after(&file->diri_files_list, *after);
*after = &file->diri_files_list.next;
return file;
}
static struct apk_db_file *apk_db_file_get(struct apk_database *db,
struct apk_db_dir_instance *diri,
apk_blob_t name,
struct hlist_node ***after)
{
struct apk_db_file *file;
struct apk_db_file_hash_key key;
struct apk_db_dir *dir = diri->dir;
unsigned long hash;
key = (struct apk_db_file_hash_key) {
.dirname = APK_BLOB_PTR_LEN(dir->name, dir->namelen),
.filename = name,
};
hash = apk_blob_hash_seed(name, dir->hash);
file = (struct apk_db_file *) apk_hash_get_hashed(
&db->installed.files, APK_BLOB_BUF(&key), hash);
if (file != NULL)
return file;
apk_hash_insert_hashed(&db->installed.files, file, hash);
db->installed.stats.files++;
return file;
}
static void apk_db_pkg_rdepends(struct apk_database *db, struct apk_package *pkg)
{
int i, j;
for (i = 0; i < pkg->depends->num; i++) {
for (j = 0; j < rname->rdepends->num; j++)
if (rname->rdepends->item[j] == pkg->name)
*apk_name_array_add(&rname->rdepends) = pkg->name;
}
rdeps_done:
for (i = 0; i < pkg->install_if->num; i++) {
rname = pkg->install_if->item[i].name;
for (j = 0; j < rname->rinstall_if->num; j++)
if (rname->rinstall_if->item[j] == pkg->name)
goto riif_done;
*apk_name_array_add(&rname->rinstall_if) = pkg->name;
}
riif_done:
return;
struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg)
if (pkg->license == NULL)
pkg->license = apk_blob_atomize(APK_BLOB_NULL);
idb = apk_hash_get(&db->available.packages, APK_BLOB_CSUM(pkg->csum));
if (idb == NULL) {
idb = pkg;
apk_hash_insert(&db->available.packages, pkg);
*apk_package_array_add(&pkg->name->pkgs) = pkg;
if (idb->filename == NULL && pkg->filename != NULL) {
idb->filename = pkg->filename;
pkg->filename = NULL;
}
if (idb->ipkg == NULL && pkg->ipkg != NULL) {
idb->ipkg = pkg->ipkg;
idb->ipkg->pkg = idb;
pkg->ipkg = NULL;
}
apk_pkg_free(pkg);
}
return idb;
}
void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo)
/* APKINDEX.12345678.tar.gz */
apk_blob_push_blob(&to, APK_BLOB_STR("APKINDEX."));
apk_blob_push_hexdump(&to, APK_BLOB_PTR_LEN((char *) repo->csum.data,
APK_CACHE_CSUM_BYTES));
apk_blob_push_blob(&to, APK_BLOB_STR(".tar.gz"));
apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
}
int apk_cache_download(struct apk_database *db, const char *url, apk_blob_t *arch,
const char *item, const char *cacheitem, int verify)
{
char fullurl[PATH_MAX];
int r;
if (arch != NULL)
snprintf(fullurl, sizeof(fullurl), "%s%s" BLOB_FMT "/%s",
url, url[strlen(url)-1] == '/' ? "" : "/",
BLOB_PRINTF(*arch), item);
else
snprintf(fullurl, sizeof(fullurl), "%s%s/%s",
url, url[strlen(url)-1] == '/' ? "" : "/",
item);
apk_message("fetch %s", fullurl);
if (apk_flags & APK_SIMULATE)
return 0;
r = apk_url_download(fullurl, db->cachetmp_fd, cacheitem);
if (r < 0)
return r;
if (verify != APK_SIGN_NONE) {
struct apk_istream *is;
struct apk_sign_ctx sctx;
apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, db->keys_fd);
is = apk_bstream_gunzip_mpart(
apk_bstream_from_file(db->cachetmp_fd, cacheitem),
apk_sign_ctx_mpart_cb, &sctx);
r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, FALSE, &db->id_cache);
is->close(is);
apk_sign_ctx_free(&sctx);
if (r != 0) {
unlinkat(db->cachetmp_fd, cacheitem, 0);
return r;
}
}
if (db->cachetmp_fd != db->cache_fd) {
if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
return -errno;
}
static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg,
apk_blob_t dirname,
struct apk_db_dir_instance *curdiri,
struct hlist_node ***tail)
{
struct hlist_node *n;
struct apk_db_dir_instance *diri;
if (curdiri != NULL &&
apk_blob_compare(APK_BLOB_PTR_LEN(curdiri->dir->name,
curdiri->dir->namelen),
dirname) == 0)
return curdiri;
hlist_for_each_entry(diri, n, &ipkg->owned_dirs, pkg_dirs_list) {
if (apk_blob_compare(APK_BLOB_PTR_LEN(diri->dir->name,
diri->dir->namelen), dirname) == 0) {
if (tail != NULL)
*tail = hlist_tail_ptr(&diri->owned_files);
return diri;
}
}
return NULL;
}
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs)
{
struct apk_db_dir_instance *diri = NULL;
struct hlist_node **diri_node = NULL, **file_diri_node = NULL;
struct apk_package *pkg;
struct apk_installed_package *ipkg;
struct apk_db_file *file;
apk_blob_t token = APK_BLOB_STR("\n"), line, bdir, bfile;
pkg = apk_pkg_new();
if (pkg == NULL)
return -1;
ipkg = apk_pkg_install(db, pkg);
if (ipkg == NULL)
return -1;
diri_node = hlist_tail_ptr(&ipkg->owned_dirs);
while (!APK_BLOB_IS_NULL(line = bs->read(bs, token))) {
if (!apk_blob_rsplit(line, '/', &bdir, &bfile))
break;
if (bfile.len == 0) {
diri = apk_db_diri_new(db, pkg, bdir, &diri_node);
file_diri_node = &diri->owned_files.first;
} else {
diri = find_diri(ipkg, bdir, diri, &file_diri_node);
if (diri == NULL) {
diri = apk_db_diri_new(db, pkg, bdir, &diri_node);
file_diri_node = &diri->owned_files.first;
file = apk_db_file_get(db, diri, bfile, &file_diri_node);
}
}
return 0;
}
int apk_db_index_read(struct apk_database *db, struct apk_bstream *bs, int repo)
{
struct apk_package *pkg = NULL;
struct apk_installed_package *ipkg = NULL;
struct apk_db_dir_instance *diri = NULL;
struct apk_db_file *file = NULL;
struct hlist_node **diri_node = NULL;
struct hlist_node **file_diri_node = NULL;
apk_blob_t token = APK_BLOB_STR("\n"), l;
while (!APK_BLOB_IS_NULL(l = bs->read(bs, token))) {
if (l.len < 2 || l.ptr[1] != ':') {
if (pkg == NULL)
continue;
pkg->repos |= BIT(repo);
if (apk_db_pkg_add(db, pkg) == NULL) {
apk_error("Installed database load failed");
return -1;
/* Get field */
field = l.ptr[0];
l.ptr += 2;
l.len -= 2;
/* If no package, create new */
if (pkg == NULL) {
pkg = apk_pkg_new();
diri = NULL;
file_diri_node = NULL;
}
/* Standard index line? */
r = apk_pkg_add_info(db, pkg, field, l);
if (r == 0) {
if (repo == -1 && field == 'S') {
/* Instert to installed database; this needs to
* happen after package name has been read, but
* before first FDB entry. */
ipkg = apk_pkg_install(db, pkg);
diri_node = hlist_tail_ptr(&ipkg->owned_dirs);
}
if (repo != -1 || ipkg == NULL)
continue;
/* Check FDB special entries */
switch (field) {
case 'F':
if (pkg->name == NULL) {
apk_error("FDB directory entry before package entry");
diri = apk_db_diri_new(db, pkg, l, &diri_node);
file_diri_node = &diri->owned_files.first;
break;
case 'M':
if (diri == NULL) {
apk_error("FDB directory metadata entry before directory entry");
return -1;
}
diri->uid = apk_blob_pull_uint(&l, 10);
apk_blob_pull_char(&l, ':');
diri->gid = apk_blob_pull_uint(&l, 10);
apk_blob_pull_char(&l, ':');
diri->mode = apk_blob_pull_uint(&l, 8);
break;
case 'R':
if (diri == NULL) {
apk_error("FDB file entry before directory entry");
return -1;
}
file = apk_db_file_get(db, diri, l, &file_diri_node);
break;
case 'Z':
if (file == NULL) {
apk_error("FDB checksum entry before file entry");
return -1;
}
if (r != 0 && !(apk_flags & APK_FORCE)) {
/* Installed db should not have unsupported fields */
apk_error("This apk-tools is too old to handle installed packages");
return -1;
}
/* Installed. So mark the package as installable. */
pkg->filename = NULL;
continue;
}
if (APK_BLOB_IS_NULL(l)) {
apk_error("FDB format error in entry '%c'", field);
return -1;
}
}
}
static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
{
struct apk_installed_package *ipkg;
struct apk_package *pkg;
struct apk_db_file *file;
char buf[1024];
apk_blob_t bbuf = APK_BLOB_BUF(buf);
int r;
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
pkg = ipkg->pkg;
r = apk_pkg_write_index_entry(pkg, os);
if (r < 0)
return r;
hlist_for_each_entry(diri, c1, &ipkg->owned_dirs, pkg_dirs_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("F:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(diri->dir->name, diri->dir->namelen));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nM:"));
apk_blob_push_uint(&bbuf, diri->uid, 10);
apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
apk_blob_push_uint(&bbuf, diri->gid, 10);
apk_blob_push_blob(&bbuf, APK_BLOB_STR(":"));
apk_blob_push_uint(&bbuf, diri->mode, 8);
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("R:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(file->name, file->namelen));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\nZ:"));
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
if (os->write(os, buf, bbuf.ptr - buf) != bbuf.ptr - buf)
}
}
return 0;
}
static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os)
{
struct apk_installed_package *ipkg;
struct apk_package *pkg;
struct apk_file_info fi;
char filename[256];
apk_blob_t bfn;
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
pkg = ipkg->pkg;
for (i = 0; i < APK_SCRIPT_MAX; i++) {
if (ipkg->script[i].ptr == NULL)
continue;
fi = (struct apk_file_info) {
.name = filename,
.size = ipkg->script[i].len,
};
/* The scripts db expects file names in format:
* pkg-version.<hexdump of package checksum>.action */
bfn = APK_BLOB_BUF(filename);
apk_blob_push_blob(&bfn, APK_BLOB_STR(pkg->name->name));
apk_blob_push_blob(&bfn, APK_BLOB_STR("-"));
apk_blob_push_blob(&bfn, *pkg->version);
apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
apk_blob_push_csum(&bfn, &pkg->csum);
apk_blob_push_blob(&bfn, APK_BLOB_STR("."));
apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[i]));
apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1));
r = apk_tar_write_entry(os, &fi, ipkg->script[i].ptr);
}
}
return apk_tar_write_entry(os, NULL, NULL);
}
static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream *is)
{
struct apk_package *pkg;
struct {
unsigned char md5sum[16];
unsigned int type;
unsigned int size;
} hdr;
struct apk_checksum csum;
while (is->read(is, &hdr, sizeof(hdr)) == sizeof(hdr)) {
memcpy(csum.data, hdr.md5sum, sizeof(hdr.md5sum));
csum.type = APK_CHECKSUM_MD5;
pkg = apk_db_get_pkg(db, &csum);
if (pkg != NULL && pkg->ipkg != NULL)
apk_ipkg_add_script(pkg->ipkg, is, hdr.type, hdr.size);
}
return 0;
}
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
static int apk_read_script_archive_entry(void *ctx,
const struct apk_file_info *ae,
struct apk_istream *is)
{
struct apk_database *db = (struct apk_database *) ctx;
struct apk_package *pkg;
char *fncsum, *fnaction;
struct apk_checksum csum;
apk_blob_t blob;
int type;
if (!S_ISREG(ae->mode))
return 0;
/* The scripts db expects file names in format:
* pkgname-version.<hexdump of package checksum>.action */
fnaction = memrchr(ae->name, '.', strlen(ae->name));
if (fnaction == NULL || fnaction == ae->name)
return 0;
fncsum = memrchr(ae->name, '.', fnaction - ae->name - 1);
if (fncsum == NULL)
return 0;
fnaction++;
fncsum++;
/* Parse it */
type = apk_script_type(fnaction);
if (type == APK_SCRIPT_INVALID)
return 0;
blob = APK_BLOB_PTR_PTR(fncsum, fnaction - 2);
apk_blob_pull_csum(&blob, &csum);
/* Attach script */
pkg = apk_db_get_pkg(db, &csum);
if (pkg != NULL && pkg->ipkg != NULL)
apk_ipkg_add_script(pkg->ipkg, is, type, ae->size);
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);
bfn = apk_blob_pushed(APK_BLOB_BUF(buf), bfn);
os->write(os, bfn.ptr, bfn.len);
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->num != 0 &&
!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_bstream *bs;
/* Read:
* 1. installed repository
* 2. source repositories
* 3. master dependencies
* 4. package statuses
* 5. files db
* 6. script db
*/
blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world");
if (APK_BLOB_IS_NULL(blob))
return -ENOENT;
apk_deps_parse(db, &db->world, blob);
free(blob.ptr);
db->world->item[i].name->flags |= APK_NAME_TOPLEVEL;
}
bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed");
r = apk_db_index_read(db, bs, -1);
bs->close(bs, NULL);
if (r != 0)
return -1;
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);
}
}
is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar");
apk_tar_parse(is, apk_read_script_archive_entry, db,
FALSE, &db->id_cache);
is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts");
if (is != NULL)
apk_db_scriptdb_read_v1(db, is);
}
return 0;
}
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
struct index_write_ctx {
struct apk_ostream *os;
int count;
int force;
};
static int write_index_entry(apk_hash_item item, void *ctx)
{
struct index_write_ctx *iwctx = (struct index_write_ctx *) ctx;
struct apk_package *pkg = (struct apk_package *) item;
int r;
if (!iwctx->force && pkg->filename == NULL)
return 0;
r = apk_pkg_write_index_entry(pkg, iwctx->os);
if (r < 0)
return r;
if (iwctx->os->write(iwctx->os, "\n", 1) != 1)
return -1;
iwctx->count++;
return 0;
}
static int apk_db_index_write_nr_cache(struct apk_database *db)
{
struct index_write_ctx ctx = { NULL, 0, TRUE };
struct apk_installed_package *ipkg;
struct apk_ostream *os;
int r;
if (!apk_db_cache_active(db))
return 0;