summaryrefslogtreecommitdiffstats
path: root/src/database.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/database.c')
-rw-r--r--src/database.c281
1 files changed, 200 insertions, 81 deletions
diff --git a/src/database.c b/src/database.c
index 53a18c7..45960d2 100644
--- a/src/database.c
+++ b/src/database.c
@@ -12,6 +12,7 @@
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
+#include <mntent.h>
#include <limits.h>
#include <unistd.h>
#include <malloc.h>
@@ -19,8 +20,11 @@
#include <stdlib.h>
#include <signal.h>
#include <fnmatch.h>
+#include <sys/vfs.h>
#include <sys/file.h>
+#include <sys/wait.h>
#include <sys/stat.h>
+#include <sys/statvfs.h>
#include "apk_defines.h"
#include "apk_package.h"
@@ -45,12 +49,29 @@ enum {
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_static_cache_dir = "var/cache/apk";
static const char * const apk_linked_cache_dir = "etc/apk/cache";
+static const char * const apk_lock_file = "var/lock/apkdb";
+
+static const char * const apk_world_file = "etc/apk/world";
+static const char * const apk_world_file_tmp = "etc/apk/world.new";
+static const char * const apk_world_file_old = "var/lib/apk/world";
+
+static const char * const apk_scripts_file = "lib/apk/db/scripts.tar";
+static const char * const apk_scripts_file_tmp = "lib/apk/db/scripts.tar.new";
+static const char * const apk_scripts_file_old = "var/lib/apk/scripts.tar";
+
+static const char * const apk_triggers_file = "lib/apk/db/triggers";
+static const char * const apk_triggers_file_tmp = "lib/apk/db/triggers.new";
+static const char * const apk_triggers_file_old = "var/lib/apk/triggers";
+
+static const char * const apk_installed_file = "lib/apk/db/installed";
+static const char * const apk_installed_file_tmp = "lib/apk/db/installed.new";
+static const char * const apk_installed_file_old = "var/lib/apk/installed";
+
struct install_ctx {
struct apk_database *db;
struct apk_package *pkg;
@@ -427,9 +448,7 @@ struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *
struct apk_package *idb;
if (pkg->license == NULL)
- pkg->license = apk_blob_atomize(APK_BLOB_NULL);
- if (pkg->arch == NULL)
- pkg->arch = apk_blob_atomize(APK_BLOB_STR(APK_DEFAULT_ARCH));
+ pkg->license = apk_blob_atomize(APK_BLOB_NULL);
idb = apk_hash_get(&db->available.packages, APK_BLOB_CSUM(pkg->csum));
if (idb == NULL) {
@@ -463,15 +482,13 @@ void apk_cache_format_index(apk_blob_t to, struct apk_repository *repo)
apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
}
-int apk_cache_download(struct apk_database *db, const char *url,
+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;
- snprintf(fullurl, sizeof(fullurl), "%s%s" BLOB_FMT "/%s",
- url, url[strlen(url)-1] == '/' ? "" : "/",
- BLOB_PRINTF(*db->arch), item);
+ apk_repo_format_filename(fullurl, sizeof(fullurl), url, arch, item);
apk_message("fetch %s", fullurl);
if (apk_flags & APK_SIMULATE)
@@ -499,8 +516,10 @@ int apk_cache_download(struct apk_database *db, const char *url,
}
}
- if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
- return -errno;
+ if (db->cachetmp_fd != db->cache_fd) {
+ if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
+ return -errno;
+ }
return 0;
}
@@ -536,7 +555,6 @@ int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs)
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();
@@ -562,7 +580,7 @@ int apk_db_read_overlay(struct apk_database *db, struct apk_bstream *bs)
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);
+ (void) apk_db_file_get(db, diri, bfile, &file_diri_node);
}
}
@@ -774,30 +792,6 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
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);
- else
- apk_istream_skip(is, hdr.size);
- }
-
- return 0;
-}
-
static int apk_read_script_archive_entry(void *ctx,
const struct apk_file_info *ae,
struct apk_istream *is)
@@ -910,7 +904,7 @@ static int apk_db_read_state(struct apk_database *db, int flags)
* 6. script db
*/
if (!(flags & APK_OPENF_NO_WORLD)) {
- blob = apk_blob_from_file(db->root_fd, "var/lib/apk/world");
+ blob = apk_blob_from_file(db->root_fd, apk_world_file);
if (APK_BLOB_IS_NULL(blob))
return -ENOENT;
apk_deps_parse(db, &db->world, blob);
@@ -921,7 +915,7 @@ static int apk_db_read_state(struct apk_database *db, int flags)
}
if (!(flags & APK_OPENF_NO_INSTALLED)) {
- bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/installed");
+ bs = apk_bstream_from_file(db->root_fd, apk_installed_file);
if (bs != NULL) {
r = apk_db_index_read(db, bs, -1);
bs->close(bs, NULL);
@@ -929,7 +923,7 @@ static int apk_db_read_state(struct apk_database *db, int flags)
return -1;
}
- bs = apk_bstream_from_file(db->root_fd, "var/lib/apk/triggers");
+ bs = apk_bstream_from_file(db->root_fd, apk_triggers_file);
if (bs != NULL) {
apk_db_triggers_read(db, bs);
bs->close(bs, NULL);
@@ -937,17 +931,12 @@ static int apk_db_read_state(struct apk_database *db, int flags)
}
if (!(flags & APK_OPENF_NO_SCRIPTS)) {
- is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts.tar");
+ is = apk_istream_from_file(db->root_fd, apk_scripts_file);
if (is != NULL) {
apk_tar_parse(is, apk_read_script_archive_entry, db,
FALSE, &db->id_cache);
- } else {
- is = apk_istream_from_file(db->root_fd, "var/lib/apk/scripts");
- if (is != NULL)
- apk_db_scriptdb_read_v1(db, is);
- }
- if (is != NULL)
is->close(is);
+ }
}
return 0;
@@ -1037,13 +1026,18 @@ static int apk_db_create(struct apk_database *db)
mkdirat(db->root_fd, "tmp", 01777);
mkdirat(db->root_fd, "dev", 0755);
mknodat(db->root_fd, "dev/null", 0666, makedev(1, 3));
+ mkdirat(db->root_fd, "etc", 0755);
+ mkdirat(db->root_fd, "etc/apk", 0755);
+ mkdirat(db->root_fd, "lib", 0755);
+ mkdirat(db->root_fd, "lib/apk", 0755);
+ mkdirat(db->root_fd, "lib/apk/db", 0755);
mkdirat(db->root_fd, "var", 0755);
- mkdirat(db->root_fd, "var/lib", 0755);
- mkdirat(db->root_fd, "var/lib/apk", 0755);
mkdirat(db->root_fd, "var/cache", 0755);
+ mkdirat(db->root_fd, "var/cache/apk", 0755);
mkdirat(db->root_fd, "var/cache/misc", 0755);
+ mkdirat(db->root_fd, "var/lock", 0755);
- fd = openat(db->root_fd, "var/lib/apk/world", O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644);
+ fd = openat(db->root_fd, apk_world_file, O_CREAT|O_RDWR|O_TRUNC|O_CLOEXEC, 0644);
if (fd < 0)
return -errno;
close(fd);
@@ -1055,14 +1049,83 @@ static void handle_alarm(int sig)
{
}
+static char *find_mountpoint(int atfd, const char *rel_path)
+{
+ struct mntent *me;
+ struct stat64 st;
+ FILE *f;
+ char *ret = NULL;
+ dev_t dev;
+
+ if (fstatat64(atfd, rel_path, &st, 0) != 0)
+ return NULL;
+ dev = st.st_dev;
+
+ f = setmntent("/proc/mounts", "r");
+ if (f == NULL)
+ return NULL;
+ while ((me = getmntent(f)) != NULL) {
+ if (strcmp(me->mnt_fsname, "rootfs") == 0)
+ continue;
+ if (fstatat64(atfd, me->mnt_dir, &st, 0) == 0 &&
+ st.st_dev == dev) {
+ ret = strdup(me->mnt_dir);
+ break;
+ }
+ }
+ endmntent(f);
+
+ return ret;
+}
+
+static int do_remount(const char *path, const char *option)
+{
+ pid_t pid;
+ int status;
+
+ pid = fork();
+ if (pid < 0)
+ return -errno;
+
+ if (pid == 0) {
+ execl("/bin/mount", "mount", "-o", "remount", "-o",
+ option, path, NULL);
+ return 1;
+ }
+
+ waitpid(pid, &status, 0);
+ if (!WIFEXITED(status))
+ return -1;
+
+ return WEXITSTATUS(status);
+}
+
+static void relocate_database(struct apk_database *db)
+{
+ mkdirat(db->root_fd, "etc", 0755);
+ mkdirat(db->root_fd, "etc/apk", 0755);
+ mkdirat(db->root_fd, "lib", 0755);
+ mkdirat(db->root_fd, "lib/apk", 0755);
+ mkdirat(db->root_fd, "lib/apk/db", 0755);
+ mkdirat(db->root_fd, "var", 0755);
+ mkdirat(db->root_fd, "var/cache", 0755);
+ mkdirat(db->root_fd, "var/cache/apk", 0755);
+ mkdirat(db->root_fd, "var/cache/misc", 0755);
+ mkdirat(db->root_fd, "var/lock", 0755);
+ apk_move_file(db->root_fd, apk_world_file_old, apk_world_file);
+ apk_move_file(db->root_fd, apk_scripts_file_old, apk_scripts_file);
+ apk_move_file(db->root_fd, apk_triggers_file_old, apk_triggers_file);
+ apk_move_file(db->root_fd, apk_installed_file_old, apk_installed_file);
+}
+
int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
{
const char *msg = NULL;
struct apk_repository_list *repo = NULL;
struct apk_bstream *bs;
- struct stat64 st;
+ struct statfs stfs;
apk_blob_t blob;
- int r, rr = 0;
+ int r, fd, rr = 0;
memset(db, 0, sizeof(*db));
if (apk_flags & APK_SIMULATE) {
@@ -1083,9 +1146,13 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
list_init(&db->installed.triggers);
apk_dependency_array_init(&db->world);
apk_string_array_init(&db->protected_paths);
- db->cache_dir = apk_static_cache_dir;
db->permanent = 1;
+ if (dbopts->root && dbopts->arch) {
+ db->arch = apk_blob_atomize(APK_BLOB_STR(dbopts->arch));
+ } else {
+ db->arch = apk_blob_atomize(APK_BLOB_STR(APK_DEFAULT_ARCH));
+ }
db->root = strdup(dbopts->root ?: "/");
db->root_fd = openat(AT_FDCWD, db->root, O_RDONLY | O_CLOEXEC);
if (db->root_fd < 0 && (dbopts->open_flags & APK_OPENF_CREATE)) {
@@ -1096,17 +1163,17 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
msg = "Unable to open root";
goto ret_errno;
}
- if (fstat64(db->root_fd, &st) != 0 || major(st.st_dev) == 0)
+ if (fstatfs(db->root_fd, &stfs) == 0 &&
+ stfs.f_type == 0x01021994 /* TMPFS_MAGIC */)
db->permanent = 0;
- if (fstatat64(db->root_fd, apk_linked_cache_dir, &st, 0) == 0 &&
- S_ISDIR(st.st_mode) && major(st.st_dev) != 0)
- db->cache_dir = apk_linked_cache_dir;
-
apk_id_cache_init(&db->id_cache, db->root_fd);
if (dbopts->open_flags & APK_OPENF_WRITE) {
- db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
+ if (faccessat(db->root_fd, apk_installed_file_old, F_OK, 0) == 0)
+ relocate_database(db);
+
+ db->lock_fd = openat(db->root_fd, apk_lock_file,
O_CREAT | O_RDWR | O_CLOEXEC, 0400);
if (db->lock_fd < 0 && errno == ENOENT &&
(dbopts->open_flags & APK_OPENF_CREATE)) {
@@ -1115,7 +1182,7 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
msg = "Unable to create database";
goto ret_r;
}
- db->lock_fd = openat(db->root_fd, "var/lib/apk/lock",
+ db->lock_fd = openat(db->root_fd, apk_lock_file,
O_CREAT | O_RDWR | O_CLOEXEC, 0400);
}
if (db->lock_fd < 0 ||
@@ -1144,10 +1211,25 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
blob = APK_BLOB_STR("etc:*etc/init.d");
apk_blob_for_each_segment(blob, ":", add_protected_path, db);
- db->arch = apk_blob_atomize(APK_BLOB_STR(apk_arch));
- db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
- mkdirat(db->cache_fd, "tmp", 0644);
- db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY | O_CLOEXEC);
+ /* figure out where to have the cache */
+ fd = openat(db->root_fd, apk_linked_cache_dir, O_RDONLY | O_CLOEXEC);
+ if (fd >= 0 && fstatfs(fd, &stfs) == 0 && stfs.f_type != 0x01021994 /* TMPFS_MAGIC */) {
+ struct statvfs stvfs;
+
+ db->cache_dir = apk_linked_cache_dir;
+ db->cache_fd = fd;
+ mkdirat(db->cache_fd, "tmp", 0644);
+ db->cachetmp_fd = openat(db->cache_fd, "tmp", O_RDONLY | O_CLOEXEC);
+ if (fstatvfs(fd, &stvfs) == 0 && (stvfs.f_flag & ST_RDONLY) != 0)
+ db->ro_cache = 1;
+ } else {
+ if (fd >= 0)
+ close(fd);
+ db->cache_dir = apk_static_cache_dir;
+ db->cache_fd = openat(db->root_fd, db->cache_dir, O_RDONLY | O_CLOEXEC);
+ db->cachetmp_fd = db->cache_fd;
+ }
+
db->keys_fd = openat(db->root_fd,
dbopts->keys_dir ?: "etc/apk/keys",
O_RDONLY | O_CLOEXEC);
@@ -1211,6 +1293,21 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
"might not function properly");
}
+ if ((dbopts->open_flags & (APK_OPENF_WRITE | APK_OPENF_CACHE_WRITE)) &&
+ db->ro_cache) {
+ /* remount cache read-write */
+ db->cache_remount_dir = find_mountpoint(db->root_fd, db->cache_dir);
+ if (db->cache_remount_dir == NULL) {
+ apk_warning("Unable to find cache directory mount point");
+ } else if (do_remount(db->cache_remount_dir, "rw") != 0) {
+ free(db->cache_remount_dir);
+ db->cache_remount_dir = NULL;
+ apk_error("Unable to remount cache read-write");
+ r = EROFS;
+ goto ret_r;
+ }
+ }
+
return rr;
ret_errno:
@@ -1242,8 +1339,8 @@ int apk_db_write_config(struct apk_database *db)
}
os = apk_ostream_to_file(db->root_fd,
- "var/lib/apk/world",
- "var/lib/apk/world.new",
+ apk_world_file,
+ apk_world_file_tmp,
0644);
if (os == NULL)
return -1;
@@ -1255,8 +1352,8 @@ int apk_db_write_config(struct apk_database *db)
return r;
os = apk_ostream_to_file(db->root_fd,
- "var/lib/apk/installed",
- "var/lib/apk/installed.new",
+ apk_installed_file,
+ apk_installed_file_tmp,
0644);
if (os == NULL)
return -1;
@@ -1266,8 +1363,8 @@ int apk_db_write_config(struct apk_database *db)
return r;
os = apk_ostream_to_file(db->root_fd,
- "var/lib/apk/scripts.tar",
- "var/lib/apk/scripts.tar.new",
+ apk_scripts_file,
+ apk_scripts_file_tmp,
0644);
if (os == NULL)
return -1;
@@ -1276,12 +1373,11 @@ int apk_db_write_config(struct apk_database *db)
if (r < 0)
return r;
- 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",
+ apk_triggers_file,
+ apk_triggers_file_tmp,
0644);
if (os == NULL)
return -1;
@@ -1300,6 +1396,12 @@ void apk_db_close(struct apk_database *db)
struct hlist_node *dc, *dn;
int i;
+ if (db->cache_remount_dir) {
+ do_remount(db->cache_remount_dir, "ro");
+ free(db->cache_remount_dir);
+ db->cache_remount_dir = NULL;
+ }
+
apk_id_cache_free(&db->id_cache);
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
@@ -1323,7 +1425,7 @@ void apk_db_close(struct apk_database *db)
if (db->keys_fd)
close(db->keys_fd);
- if (db->cachetmp_fd)
+ if (db->cachetmp_fd && db->cachetmp_fd != db->cache_fd)
close(db->cachetmp_fd);
if (db->cache_fd)
close(db->cache_fd);
@@ -1423,21 +1525,37 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db,
return dbf->diri->pkg;
}
+int apk_repo_format_filename(char *buf, size_t len,
+ const char *repourl, apk_blob_t *arch,
+ const char *item)
+{
+ int n;
+
+ if (arch != NULL)
+ n = snprintf(buf, len, "%s%s" BLOB_FMT "/%s",
+ repourl, repourl[strlen(repourl)-1] == '/' ? "" : "/",
+ BLOB_PRINTF(*arch), item);
+ else
+ n = snprintf(buf, len, "%s%s%s",
+ repourl, repourl[strlen(repourl)-1] == '/' ? "" : "/",
+ item);
+
+ return n;
+}
+
static int apk_repo_is_remote(struct apk_repository *repo)
{
return repo->csum.type != APK_CHECKSUM_NONE;
}
static struct apk_bstream *apk_repo_file_open(struct apk_repository *repo,
- apk_blob_t arch,
+ apk_blob_t *arch,
const char *file,
char *buf, int buflen)
{
const char *url = repo->url;
- snprintf(buf, buflen, "%s%s" BLOB_FMT "/%s",
- url, url[strlen(url)-1] == '/' ? "" : "/",
- BLOB_PRINTF(arch), file);
+ apk_repo_format_filename(buf, buflen, url, arch, file);
if ((apk_flags & APK_NO_NETWORK) && apk_repo_is_remote(repo))
return NULL;
@@ -1497,7 +1615,7 @@ int apk_repository_update(struct apk_database *db, struct apk_repository *repo)
return 0;
apk_cache_format_index(APK_BLOB_BUF(cacheitem), repo);
- r = apk_cache_download(db, repo->url, apkindex_tar_gz, cacheitem,
+ r = apk_cache_download(db, repo->url, db->arch, apkindex_tar_gz, cacheitem,
(apk_flags & APK_ALLOW_UNTRUSTED) ?
APK_SIGN_NONE : APK_SIGN_VERIFY);
if (r != 0)
@@ -1605,7 +1723,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t repository)
bs = apk_bstream_from_file(db->cache_fd, buf);
} else {
db->local_repos |= BIT(r);
- bs = apk_repo_file_open(repo, *db->arch, apkindex_tar_gz, buf, sizeof(buf));
+ bs = apk_repo_file_open(repo, db->arch, apkindex_tar_gz, buf, sizeof(buf));
}
if (bs == NULL) {
apk_warning("%s: index failed to open", buf);
@@ -2015,7 +2133,8 @@ static int apk_db_unpack_pkg(struct apk_database *db,
if (bs == NULL) {
apk_pkg_format_plain(pkg, APK_BLOB_BUF(item));
- bs = apk_repo_file_open(repo, *(pkg->arch ?: db->arch), item, file, sizeof(file));
+ bs = apk_repo_file_open(repo, pkg->arch,
+ item, file, sizeof(file));
if (apk_repo_is_remote(repo))
need_copy = TRUE;
}