diff options
author | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-09-25T19·38-0400 |
---|---|---|
committer | Eelco Dolstra <eelco.dolstra@logicblox.com> | 2012-09-25T19·38-0400 |
commit | e464b0247d9dd2c53770a851956dd34f82b7c9a6 (patch) | |
tree | 75517243f3ce6c5facd3e2424fefbaeeaaad1af1 /src/libstore | |
parent | 28bf183d2d2f775e653efe4cee98d7359ce65455 (diff) | |
parent | b9c2b4d5b4cd5d52a950e6dd90eb2e2e79891fa0 (diff) |
Merge branch 'readonly-store'
Diffstat (limited to 'src/libstore')
-rw-r--r-- | src/libstore/build.cc | 32 | ||||
-rw-r--r-- | src/libstore/gc.cc | 2 | ||||
-rw-r--r-- | src/libstore/globals.cc | 20 | ||||
-rw-r--r-- | src/libstore/local-store.cc | 47 | ||||
-rw-r--r-- | src/libstore/local-store.hh | 2 | ||||
-rw-r--r-- | src/libstore/optimise-store.cc | 88 |
6 files changed, 92 insertions, 99 deletions
diff --git a/src/libstore/build.cc b/src/libstore/build.cc index 04ba02d14e46..4051adacca0b 100644 --- a/src/libstore/build.cc +++ b/src/libstore/build.cc @@ -1355,11 +1355,6 @@ void DerivationGoal::buildDone() /* Delete the chroot (if we were using one). */ autoDelChroot.reset(); /* this runs the destructor */ - /* Deleting the chroot will have caused the immutable bits on - hard-linked inputs to be cleared. So set them again. */ - foreach (PathSet::iterator, i, regularInputPaths) - makeImmutable(*i); - /* Delete redirected outputs (when doing hash rewriting). */ foreach (PathSet::iterator, i, redirectedOutputs) deletePath(*i); @@ -1435,7 +1430,7 @@ HookReply DerivationGoal::tryBuildHook() /* Tell the hook about system features (beyond the system type) required from the build machine. (The hook could parse the drv file itself, but this is easier.) */ - Strings features = tokenizeString(drv.env["requiredSystemFeatures"]); + Strings features = tokenizeString<Strings>(drv.env["requiredSystemFeatures"]); foreach (Strings::iterator, i, features) checkStoreName(*i); /* !!! abuse */ /* Send the request to the hook. */ @@ -1594,7 +1589,7 @@ void DerivationGoal::startBuilder() fixed-output derivations is by definition pure (since we already know the cryptographic hash of the output). */ if (fixedOutput) { - Strings varNames = tokenizeString(drv.env["impureEnvVars"]); + Strings varNames = tokenizeString<Strings>(drv.env["impureEnvVars"]); foreach (Strings::iterator, i, varNames) env[*i] = getEnv(*i); } @@ -1606,7 +1601,7 @@ void DerivationGoal::startBuilder() by `nix-store --register-validity'. However, the deriver fields are left empty. */ string s = drv.env["exportReferencesGraph"]; - Strings ss = tokenizeString(s); + Strings ss = tokenizeString<Strings>(s); if (ss.size() % 2 != 0) throw BuildError(format("odd number of tokens in `exportReferencesGraph': `%1%'") % s); for (Strings::iterator i = ss.begin(); i != ss.end(); ) { @@ -1766,11 +1761,8 @@ void DerivationGoal::startBuilder() /* Hard-linking fails if we exceed the maximum link count on a file (e.g. 32000 of ext3), which is quite possible after a `nix-store - --optimise'. It can also fail if another - process called makeImmutable() on *i after we - did makeMutable(). In those cases, make a copy - instead. */ - if (errno != EMLINK && errno != EPERM) + --optimise'. */ + if (errno != EMLINK) throw SysError(format("linking `%1%' to `%2%'") % p % *i); StringSink sink; dumpPath(*i, sink); @@ -1778,7 +1770,6 @@ void DerivationGoal::startBuilder() restorePath(p, source); } - makeImmutable(*i); regularInputPaths.insert(*i); } } @@ -1911,14 +1902,11 @@ void DerivationGoal::initChild() outside of the namespace. Making a subtree private is local to the namespace, though, so setting MS_PRIVATE does not affect the outside world. */ - Strings mounts = tokenizeString(readFile("/proc/self/mountinfo", true), "\n"); + Strings mounts = tokenizeString<Strings>(readFile("/proc/self/mountinfo", true), "\n"); foreach (Strings::iterator, i, mounts) { - Strings fields = tokenizeString(*i, " "); - assert(fields.size() >= 5); - Strings::iterator j = fields.begin(); - std::advance(j, 4); - if (mount(0, j->c_str(), 0, MS_PRIVATE, 0) == -1) - throw SysError(format("unable to make filesystem `%1%' private") % *j); + vector<string> fields = tokenizeString<vector<string> >(*i, " "); + if (mount(0, fields.at(4).c_str(), 0, MS_PRIVATE, 0) == -1) + throw SysError(format("unable to make filesystem `%1%' private") % fields.at(4)); } /* Bind-mount all the directories from the "host" @@ -2053,7 +2041,7 @@ void DerivationGoal::initChild() PathSet parseReferenceSpecifiers(const Derivation & drv, string attr) { PathSet result; - Paths paths = tokenizeString(attr); + Paths paths = tokenizeString<Paths>(attr); foreach (Strings::iterator, i, paths) { if (isStorePath(*i)) result.insert(*i); diff --git a/src/libstore/gc.cc b/src/libstore/gc.cc index 4a025a8feb92..ca16b6491009 100644 --- a/src/libstore/gc.cc +++ b/src/libstore/gc.cc @@ -373,7 +373,7 @@ static void addAdditionalRoots(StoreAPI & store, PathSet & roots) string result = runProgram(rootFinder); - Strings paths = tokenizeString(result, "\n"); + Strings paths = tokenizeString<Strings>(result, "\n"); foreach (Strings::iterator, i, paths) { if (isInStore(*i)) { diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc index 7e2624bbf712..9b22d54508c1 100644 --- a/src/libstore/globals.cc +++ b/src/libstore/globals.cc @@ -65,15 +65,7 @@ void Settings::processEnvironment() substituters.push_back(nixLibexecDir + "/nix/substituters/download-using-manifests.pl"); substituters.push_back(nixLibexecDir + "/nix/substituters/download-from-binary-cache.pl"); } else - substituters = tokenizeString(subs, ":"); -} - - -string & at(Strings & ss, unsigned int n) -{ - Strings::iterator i = ss.begin(); - advance(i, n); - return *i; + substituters = tokenizeString<Strings>(subs, ":"); } @@ -95,15 +87,15 @@ void Settings::loadConfFile() if (hash != string::npos) line = string(line, 0, hash); - Strings tokens = tokenizeString(line); + vector<string> tokens = tokenizeString<vector<string> >(line); if (tokens.empty()) continue; - if (tokens.size() < 2 || at(tokens, 1) != "=") + if (tokens.size() < 2 || tokens[1] != "=") throw Error(format("illegal configuration line `%1%' in `%2%'") % line % settingsFile); - string name = at(tokens, 0); + string name = tokens[0]; - Strings::iterator i = tokens.begin(); + vector<string>::iterator i = tokens.begin(); advance(i, 2); settings[name] = concatStringsSep(" ", Strings(i, tokens.end())); // FIXME: slow }; @@ -170,7 +162,7 @@ void Settings::get(PathSet & res, const string & name) SettingsMap::iterator i = settings.find(name); if (i == settings.end()) return; res.clear(); - Strings ss = tokenizeString(i->second); + Strings ss = tokenizeString<Strings>(i->second); res.insert(ss.begin(), ss.end()); } diff --git a/src/libstore/local-store.cc b/src/libstore/local-store.cc index 793ec89d918b..3fd772f26fb1 100644 --- a/src/libstore/local-store.cc +++ b/src/libstore/local-store.cc @@ -20,6 +20,11 @@ #include <stdio.h> #include <time.h> +#if HAVE_UNSHARE +#include <sched.h> +#include <sys/mount.h> +#endif + #include <sqlite3.h> @@ -292,6 +297,8 @@ LocalStore::LocalStore(bool reserveSpace) } else openDB(false); + + makeStoreWritable(); } @@ -411,6 +418,38 @@ void LocalStore::openDB(bool create) } +/* To improve purity, users may want to make the Nix store a read-only + bind mount. So make the Nix store writable for this process. */ +void LocalStore::makeStoreWritable() +{ +#if HAVE_UNSHARE + if (getuid() != 0) return; + + if (!pathExists("/proc/self/mountinfo")) return; + + /* Check if /nix/store is a read-only bind mount. */ + bool found = false; + Strings mounts = tokenizeString<Strings>(readFile("/proc/self/mountinfo", true), "\n"); + foreach (Strings::iterator, i, mounts) { + 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 (unshare(CLONE_NEWNS) == -1) + throw SysError("setting up a private mount namespace"); + + if (mount(0, settings.nixStore.c_str(), 0, MS_REMOUNT | MS_BIND, 0) == -1) + throw SysError(format("remounting %1% writable") % settings.nixStore); +#endif +} + + const time_t mtimeStore = 1; /* 1 second into the epoch */ @@ -478,8 +517,6 @@ void canonicalisePathMetaData(const Path & path, bool recurse) foreach (Strings::iterator, i, names) canonicalisePathMetaData(path + "/" + *i, true); } - - makeImmutable(path); } @@ -1435,7 +1472,7 @@ Path LocalStore::importPath(bool requireSignature, Source & source) /* Lock the output path. But don't lock if we're being called from a build hook (whose parent process already acquired a lock on this path). */ - Strings locksHeld = tokenizeString(getEnv("NIX_HELD_LOCKS")); + Strings locksHeld = tokenizeString<Strings>(getEnv("NIX_HELD_LOCKS")); if (find(locksHeld.begin(), locksHeld.end(), dstPath) == locksHeld.end()) outputLock.lockPaths(singleton<PathSet, Path>(dstPath)); @@ -1645,7 +1682,7 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path) string info = readFile(infoFile); /* Parse it. */ - Strings lines = tokenizeString(info, "\n"); + Strings lines = tokenizeString<Strings>(info, "\n"); foreach (Strings::iterator, i, lines) { string::size_type p = i->find(':'); @@ -1654,7 +1691,7 @@ ValidPathInfo LocalStore::queryPathInfoOld(const Path & path) string name(*i, 0, p); string value(*i, p + 2); if (name == "References") { - Strings refs = tokenizeString(value, " "); + Strings refs = tokenizeString<Strings>(value, " "); res.references = PathSet(refs.begin(), refs.end()); } else if (name == "Deriver") { res.deriver = value; diff --git a/src/libstore/local-store.hh b/src/libstore/local-store.hh index d2b13d6a9028..8899873a72c6 100644 --- a/src/libstore/local-store.hh +++ b/src/libstore/local-store.hh @@ -228,6 +228,8 @@ private: void openDB(bool create); + void makeStoreWritable(); + unsigned long long queryValidPathId(const Path & path); unsigned long long addValidPath(const ValidPathInfo & info, bool checkOutputs = true); diff --git a/src/libstore/optimise-store.cc b/src/libstore/optimise-store.cc index 9d0242bbc857..43b3c9b4fbc3 100644 --- a/src/libstore/optimise-store.cc +++ b/src/libstore/optimise-store.cc @@ -33,8 +33,7 @@ struct MakeReadOnly ~MakeReadOnly() { try { - /* This will make the path read-only (and restore the - immutable bit on platforms that support it). */ + /* This will make the path read-only. */ if (path != "") canonicalisePathMetaData(path, false); } catch (...) { ignoreException(); @@ -43,14 +42,6 @@ struct MakeReadOnly }; -struct MakeImmutable -{ - Path path; - MakeImmutable(const Path & path) : path(path) { } - ~MakeImmutable() { makeImmutable(path); } -}; - - void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) { checkInterrupt(); @@ -101,7 +92,6 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) if (!pathExists(linkPath)) { /* Nope, create a hard link in the links directory. */ makeMutable(path); - MakeImmutable mk1(path); if (link(path.c_str(), linkPath.c_str()) == 0) return; if (errno != EEXIST) throw SysError(format("cannot link `%1%' to `%2%'") % linkPath % path); @@ -134,58 +124,42 @@ void LocalStore::optimisePath_(OptimiseStats & stats, const Path & path) MakeReadOnly makeReadOnly(mustToggle ? dirOf(path) : ""); /* If ‘linkPath’ is immutable, we can't create hard links to it, - so make it mutable first (and make it immutable again when - we're done). We also have to make ‘path’ mutable, otherwise - rename() will fail to delete it. */ + so make it mutable first. We also have to make ‘path’ mutable, + otherwise rename() will fail to delete it. */ makeMutable(path); - MakeImmutable mk2(path); - - /* Another process might be doing the same thing (creating a new - link to ‘linkPath’) and make ‘linkPath’ immutable before we're - done. In that case, just retry. */ - unsigned int retries = 1024; - while (--retries > 0) { - makeMutable(linkPath); - MakeImmutable mk1(linkPath); - - Path tempLink = (format("%1%/.tmp-link-%2%-%3%") - % settings.nixStore % getpid() % rand()).str(); - - if (link(linkPath.c_str(), tempLink.c_str()) == -1) { - if (errno == EMLINK) { - /* Too many links to the same file (>= 32000 on most - file systems). This is likely to happen with empty - files. Just shrug and ignore. */ - if (st.st_size) - printMsg(lvlInfo, format("`%1%' has maximum number of links") % linkPath); - return; - } - if (errno == EPERM) continue; - throw SysError(format("cannot link `%1%' to `%2%'") % tempLink % linkPath); + makeMutable(linkPath); + + Path tempLink = (format("%1%/.tmp-link-%2%-%3%") + % settings.nixStore % getpid() % rand()).str(); + + if (link(linkPath.c_str(), tempLink.c_str()) == -1) { + if (errno == EMLINK) { + /* Too many links to the same file (>= 32000 on most file + systems). This is likely to happen with empty files. + Just shrug and ignore. */ + if (st.st_size) + printMsg(lvlInfo, format("`%1%' has maximum number of links") % linkPath); + return; } + throw SysError(format("cannot link `%1%' to `%2%'") % tempLink % linkPath); + } - /* Atomically replace the old file with the new hard link. */ - if (rename(tempLink.c_str(), path.c_str()) == -1) { - if (unlink(tempLink.c_str()) == -1) - printMsg(lvlError, format("unable to unlink `%1%'") % tempLink); - if (errno == EMLINK) { - /* Some filesystems generate too many links on the - rename, rather than on the original link. - (Probably it temporarily increases the st_nlink - field before decreasing it again.) */ - if (st.st_size) - printMsg(lvlInfo, format("`%1%' has maximum number of links") % linkPath); - return; - } - if (errno == EPERM) continue; - throw SysError(format("cannot rename `%1%' to `%2%'") % tempLink % path); + /* Atomically replace the old file with the new hard link. */ + if (rename(tempLink.c_str(), path.c_str()) == -1) { + if (unlink(tempLink.c_str()) == -1) + printMsg(lvlError, format("unable to unlink `%1%'") % tempLink); + if (errno == EMLINK) { + /* Some filesystems generate too many links on the rename, + rather than on the original link. (Probably it + temporarily increases the st_nlink field before + decreasing it again.) */ + if (st.st_size) + printMsg(lvlInfo, format("`%1%' has maximum number of links") % linkPath); + return; } - - break; + throw SysError(format("cannot rename `%1%' to `%2%'") % tempLink % path); } - if (retries == 0) throw Error(format("cannot link `%1%' to `%2%'") % path % linkPath); - stats.filesLinked++; stats.bytesFreed += st.st_size; stats.blocksFreed += st.st_blocks; |