Commit 415e230a authored by Timo Teräs's avatar Timo Teräs

db, cache: automatically remount cache read-write when needed

.. and back to read-only after finishing with modifications.

fixes #512
parent 1e17da9d
...@@ -105,9 +105,11 @@ struct apk_database { ...@@ -105,9 +105,11 @@ struct apk_database {
int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd; int root_fd, lock_fd, cache_fd, cachetmp_fd, keys_fd;
unsigned name_id, num_repos; unsigned name_id, num_repos;
const char *cache_dir; const char *cache_dir;
char *cache_remount_dir;
apk_blob_t *arch; apk_blob_t *arch;
unsigned int local_repos; unsigned int local_repos;
int permanent : 1; int permanent : 1;
int ro_cache : 1;
int compat_newfeatures : 1; int compat_newfeatures : 1;
int compat_notinstallable : 1; int compat_notinstallable : 1;
...@@ -155,6 +157,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db, ...@@ -155,6 +157,7 @@ struct apk_db_file *apk_db_file_query(struct apk_database *db,
#define APK_OPENF_NO_WORLD 0x0040 #define APK_OPENF_NO_WORLD 0x0040
#define APK_OPENF_NO_SYS_REPOS 0x0100 #define APK_OPENF_NO_SYS_REPOS 0x0100
#define APK_OPENF_NO_INSTALLED_REPO 0x0200 #define APK_OPENF_NO_INSTALLED_REPO 0x0200
#define APK_OPENF_CACHE_WRITE 0x0400
#define APK_OPENF_NO_REPOS (APK_OPENF_NO_SYS_REPOS | \ #define APK_OPENF_NO_REPOS (APK_OPENF_NO_SYS_REPOS | \
APK_OPENF_NO_INSTALLED_REPO) APK_OPENF_NO_INSTALLED_REPO)
......
...@@ -172,7 +172,7 @@ static struct apk_applet apk_cache = { ...@@ -172,7 +172,7 @@ static struct apk_applet apk_cache = {
"making /etc/apk/cache a symlink to the directory (on boot " "making /etc/apk/cache a symlink to the directory (on boot "
"media) that will be used as package cache.", "media) that will be used as package cache.",
.arguments = "sync | clean | download", .arguments = "sync | clean | download",
.open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_INSTALLED, .open_flags = APK_OPENF_READ|APK_OPENF_NO_SCRIPTS|APK_OPENF_NO_INSTALLED|APK_OPENF_CACHE_WRITE,
.main = cache_main, .main = cache_main,
}; };
......
...@@ -12,6 +12,7 @@ ...@@ -12,6 +12,7 @@
#include <errno.h> #include <errno.h>
#include <stdio.h> #include <stdio.h>
#include <fcntl.h> #include <fcntl.h>
#include <mntent.h>
#include <limits.h> #include <limits.h>
#include <unistd.h> #include <unistd.h>
#include <malloc.h> #include <malloc.h>
...@@ -21,7 +22,9 @@ ...@@ -21,7 +22,9 @@
#include <fnmatch.h> #include <fnmatch.h>
#include <sys/vfs.h> #include <sys/vfs.h>
#include <sys/file.h> #include <sys/file.h>
#include <sys/wait.h>
#include <sys/stat.h> #include <sys/stat.h>
#include <sys/statvfs.h>
#include "apk_defines.h" #include "apk_defines.h"
#include "apk_package.h" #include "apk_package.h"
...@@ -503,8 +506,10 @@ int apk_cache_download(struct apk_database *db, const char *url, apk_blob_t *arc ...@@ -503,8 +506,10 @@ int apk_cache_download(struct apk_database *db, const char *url, apk_blob_t *arc
} }
} }
if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0) if (db->cachetmp_fd != db->cache_fd) {
return -errno; if (renameat(db->cachetmp_fd, cacheitem, db->cache_fd, cacheitem) < 0)
return -errno;
}
return 0; return 0;
} }
...@@ -1059,15 +1064,65 @@ static void handle_alarm(int sig) ...@@ -1059,15 +1064,65 @@ 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);
}
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)
{ {
const char *msg = NULL; const char *msg = NULL;
struct apk_repository_list *repo = NULL; struct apk_repository_list *repo = NULL;
struct apk_bstream *bs; struct apk_bstream *bs;
struct stat64 st;
struct statfs stfs; struct statfs stfs;
apk_blob_t blob; apk_blob_t blob;
int r, rr = 0; int r, fd, rr = 0;
memset(db, 0, sizeof(*db)); memset(db, 0, sizeof(*db));
if (apk_flags & APK_SIMULATE) { if (apk_flags & APK_SIMULATE) {
...@@ -1088,7 +1143,6 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) ...@@ -1088,7 +1143,6 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
list_init(&db->installed.triggers); list_init(&db->installed.triggers);
apk_dependency_array_init(&db->world); apk_dependency_array_init(&db->world);
apk_string_array_init(&db->protected_paths); apk_string_array_init(&db->protected_paths);
db->cache_dir = apk_static_cache_dir;
db->permanent = 1; db->permanent = 1;
db->root = strdup(dbopts->root ?: "/"); db->root = strdup(dbopts->root ?: "/");
...@@ -1105,10 +1159,6 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) ...@@ -1105,10 +1159,6 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
stfs.f_type == 0x01021994 /* TMPFS_MAGIC */) stfs.f_type == 0x01021994 /* TMPFS_MAGIC */)
db->permanent = 0; 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); apk_id_cache_init(&db->id_cache, db->root_fd);
if (dbopts->open_flags & APK_OPENF_WRITE) { if (dbopts->open_flags & APK_OPENF_WRITE) {
...@@ -1150,10 +1200,26 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) ...@@ -1150,10 +1200,26 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
blob = APK_BLOB_STR("etc:*etc/init.d"); blob = APK_BLOB_STR("etc:*etc/init.d");
apk_blob_for_each_segment(blob, ":", add_protected_path, db); apk_blob_for_each_segment(blob, ":", add_protected_path, db);
/* 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->arch = apk_blob_atomize(APK_BLOB_STR(apk_arch)); 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);
db->keys_fd = openat(db->root_fd, db->keys_fd = openat(db->root_fd,
dbopts->keys_dir ?: "etc/apk/keys", dbopts->keys_dir ?: "etc/apk/keys",
O_RDONLY | O_CLOEXEC); O_RDONLY | O_CLOEXEC);
...@@ -1217,6 +1283,21 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts) ...@@ -1217,6 +1283,21 @@ int apk_db_open(struct apk_database *db, struct apk_db_options *dbopts)
"might not function properly"); "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; return rr;
ret_errno: ret_errno:
...@@ -1306,6 +1387,12 @@ void apk_db_close(struct apk_database *db) ...@@ -1306,6 +1387,12 @@ void apk_db_close(struct apk_database *db)
struct hlist_node *dc, *dn; struct hlist_node *dc, *dn;
int i; 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); apk_id_cache_free(&db->id_cache);
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) { list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
...@@ -1329,7 +1416,7 @@ void apk_db_close(struct apk_database *db) ...@@ -1329,7 +1416,7 @@ void apk_db_close(struct apk_database *db)
if (db->keys_fd) if (db->keys_fd)
close(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); close(db->cachetmp_fd);
if (db->cache_fd) if (db->cache_fd)
close(db->cache_fd); close(db->cache_fd);
......
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