diff options
Diffstat (limited to 'src/database.c')
-rw-r--r-- | src/database.c | 281 |
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; } |