~ruther/guix-local

2a0ac4cba5e3816e203b412934ee66345667c5ca — Rutherther 2 months ago 09eda16
daemon: Ensure store is writable even as non-root.

If the store is read only, return an error early.
This is bit of a compromise. Not all operations of the daemon need the store
as writable. For example, if hello package is built already `guix build hello`
could previously succeed even if store is RO.

* nix/libstore/local-store.cc
(makeStoreWritable): Rename to ensureStoreWritable.
(ensureStoreWritable): As non-root, check that the store is writable and if
not, throw an error.
(LocalStore::LocalStore): Use it.

* nix/libstore/local-store.hh: Rename makeStoreWritable to ensureStoreWritable.

Change-Id: I94783ba7e32d57bfa77e37e84b6ac316f95e31e2
Signed-off-by: Rutherther <rutherther@ditigal.xyz>
2 files changed, 14 insertions(+), 6 deletions(-)

M nix/libstore/local-store.cc
M nix/libstore/local-store.hh
M nix/libstore/local-store.cc => nix/libstore/local-store.cc +13 -5
@@ 67,7 67,7 @@ LocalStore::LocalStore(bool reserveSpace)

    /* Create missing state directories if they don't already exist. */
    createDirs(settings.nixStore);
    makeStoreWritable();
    ensureStoreWritable();
    createDirs(linksDir = settings.nixStore + "/.links");
    Path profilesDir = settings.nixStateDir + "/profiles";
    createDirs(profilesDir);


@@ 300,18 300,26 @@ void LocalStore::openDB(bool create)
}


/* To improve purity, users may want to make the store a read-only
   bind mount.  So make the store writable for this process. */
void LocalStore::makeStoreWritable()
/* To improve purity, users may want to make the store a read-only bind mount.
   So make the store writable for this process.  In case the store is read-only
   and cannot be made writable, throw an error. */
void LocalStore::ensureStoreWritable()
{
#if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
    if (getuid() != 0) return;
    /* Check if /nix/store is on a read-only mount. */
    struct statvfs stat;
    if (statvfs(settings.nixStore.c_str(), &stat) != 0)
        throw SysError("getting info about the store mount point");

    if (stat.f_flag & ST_RDONLY) {
        if (getuid() != 0) {
          throw Error(
              std::format(
                 "'{}' is read-only; make sure to mount it read-write "
                 "for proper guix-daemon operation",
                 settings.nixStore));
        }

        if (unshare(CLONE_NEWNS) == -1)
            throw SysError("setting up a private mount namespace");


M nix/libstore/local-store.hh => nix/libstore/local-store.hh +1 -1
@@ 212,7 212,7 @@ private:

    void openDB(bool create);

    void makeStoreWritable();
    void ensureStoreWritable();

    uint64_t queryValidPathId(const Path & path);