forked from lix-project/lix
makeStoreWritable: Use statvfs instead of /proc/self/mountinfo to find out if /nix/store is a read-only bind mount
/nix/store could be a read-only bind mount even if it is / in its own filesystem, so checking the 4th field in mountinfo is insufficient. Signed-off-by: Shea Levy <shea@shealevy.com>
This commit is contained in:
parent
c3fc60d936
commit
2c9cf50746
|
@ -106,6 +106,7 @@ AC_LANG_POP(C++)
|
||||||
# Check for chroot support (requires chroot() and bind mounts).
|
# Check for chroot support (requires chroot() and bind mounts).
|
||||||
AC_CHECK_FUNCS([chroot])
|
AC_CHECK_FUNCS([chroot])
|
||||||
AC_CHECK_FUNCS([unshare])
|
AC_CHECK_FUNCS([unshare])
|
||||||
|
AC_CHECK_FUNCS([statvfs])
|
||||||
AC_CHECK_HEADERS([sched.h])
|
AC_CHECK_HEADERS([sched.h])
|
||||||
AC_CHECK_HEADERS([sys/param.h])
|
AC_CHECK_HEADERS([sys/param.h])
|
||||||
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
AC_CHECK_HEADERS([sys/mount.h], [], [],
|
||||||
|
|
|
@ -19,8 +19,9 @@
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#if HAVE_UNSHARE
|
#if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H
|
||||||
#include <sched.h>
|
#include <sched.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <sys/mount.h>
|
#include <sys/mount.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -434,30 +435,20 @@ void LocalStore::openDB(bool create)
|
||||||
bind mount. So make the Nix store writable for this process. */
|
bind mount. So make the Nix store writable for this process. */
|
||||||
void LocalStore::makeStoreWritable()
|
void LocalStore::makeStoreWritable()
|
||||||
{
|
{
|
||||||
#if HAVE_UNSHARE
|
#if HAVE_UNSHARE && HAVE_STATVFS && HAVE_SYS_MOUNT_H && defined(MS_BIND) && defined(MS_REMOUNT)
|
||||||
if (getuid() != 0) return;
|
if (getuid() != 0) return;
|
||||||
|
|
||||||
if (!pathExists("/proc/self/mountinfo")) return;
|
|
||||||
|
|
||||||
/* Check if /nix/store is a read-only bind mount. */
|
/* Check if /nix/store is a read-only bind mount. */
|
||||||
bool found = false;
|
struct statvfs stat;
|
||||||
Strings mounts = tokenizeString<Strings>(readFile("/proc/self/mountinfo", true), "\n");
|
if (statvfs(settings.nixStore.c_str(), &stat) !=0)
|
||||||
foreach (Strings::iterator, i, mounts) {
|
throw SysError("Getting info of nix store mountpoint");
|
||||||
vector<string> fields = tokenizeString<vector<string> >(*i, " ");
|
|
||||||
if (fields.at(3) == "/" || fields.at(4) != settings.nixStore) continue;
|
|
||||||
Strings options = tokenizeString<Strings>(fields.at(5), ",");
|
|
||||||
if (std::find(options.begin(), options.end(), "ro") == options.end()) continue;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) return;
|
|
||||||
|
|
||||||
|
if (stat.f_flag & (ST_RDONLY | MS_BIND)) {
|
||||||
if (unshare(CLONE_NEWNS) == -1)
|
if (unshare(CLONE_NEWNS) == -1)
|
||||||
throw SysError("setting up a private mount namespace");
|
throw SysError("setting up a private mount namespace");
|
||||||
|
|
||||||
if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1)
|
if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1)
|
||||||
throw SysError(format("remounting %1% writable") % settings.nixStore);
|
throw SysError(format("remounting %1% writable") % settings.nixStore);
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue