diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/libcmd/installable-flake.cc | 9 | ||||
-rw-r--r-- | src/libcmd/repl-interacter.cc | 33 | ||||
-rw-r--r-- | src/libcmd/repl-interacter.hh | 5 | ||||
-rw-r--r-- | src/libcmd/repl.cc | 11 | ||||
-rw-r--r-- | src/libexpr/primops/context.cc | 6 | ||||
-rw-r--r-- | src/libfetchers/cache.cc | 11 | ||||
-rw-r--r-- | src/libstore/build/derivation-goal.cc | 11 | ||||
-rw-r--r-- | src/libstore/build/local-derivation-goal.cc | 20 | ||||
-rw-r--r-- | src/libutil/archive.cc | 9 | ||||
-rw-r--r-- | src/libutil/archive.hh | 2 | ||||
-rw-r--r-- | src/libutil/error.hh | 2 | ||||
-rw-r--r-- | src/libutil/util.cc | 8 | ||||
-rw-r--r-- | src/libutil/util.hh | 7 |
13 files changed, 91 insertions, 43 deletions
diff --git a/src/libcmd/installable-flake.cc b/src/libcmd/installable-flake.cc index 615f70945..46bdd411b 100644 --- a/src/libcmd/installable-flake.cc +++ b/src/libcmd/installable-flake.cc @@ -105,9 +105,14 @@ DerivedPathsWithInfo InstallableFlake::toDerivedPaths() fmt("while evaluating the flake output attribute '%s'", attrPath))) { return { *derivedPathWithInfo }; + } else { + throw Error( + "expected flake output attribute '%s' to be a derivation or path but found %s: %s", + attrPath, + showType(v), + ValuePrinter(*this->state, v, errorPrintOptions) + ); } - else - throw Error("flake output attribute '%s' is not a derivation or path", attrPath); } auto drvPath = attr->forceDerivation(); diff --git a/src/libcmd/repl-interacter.cc b/src/libcmd/repl-interacter.cc index 829383add..41589cda1 100644 --- a/src/libcmd/repl-interacter.cc +++ b/src/libcmd/repl-interacter.cc @@ -1,6 +1,8 @@ #include <cstdio> #include <iostream> #include <string> +#include <string_view> +#include <cerrno> #ifdef READLINE #include <readline/history.h> @@ -175,14 +177,43 @@ bool ReadlineLikeInteracter::getLine(std::string & input, ReplPromptType promptT if (!s) return false; + + this->writeHistory(); input += s; input += '\n'; return true; } +void ReadlineLikeInteracter::writeHistory() +{ + int ret = write_history(historyFile.c_str()); + int writeHistErr = errno; + + if (ret == 0) { + return; + } + + // If the open fails, editline returns EOF. If the close fails, editline + // forwards the return value of fclose(), which is EOF on error. + // readline however, returns the errno. + // So if we didn't get exactly EOF, then consider the return value the error + // code; otherwise use the errno we saved above. + // https://github.com/troglobit/editline/issues/66 + if (ret != EOF) { + writeHistErr = ret; + } + + // In any of these cases, we should explicitly ignore the error, but log + // them so the user isn't confused why their history is getting eaten. + + std::string_view const errMsg(std::strerror(writeHistErr)); + warn("ignoring error writing repl history to %s: %s", this->historyFile, errMsg); + +} + ReadlineLikeInteracter::~ReadlineLikeInteracter() { - write_history(historyFile.c_str()); + this->writeHistory(); } AutomationInteracter::Guard AutomationInteracter::init(detail::ReplCompleterMixin *) diff --git a/src/libcmd/repl-interacter.hh b/src/libcmd/repl-interacter.hh index c31b1a1e6..8f815fceb 100644 --- a/src/libcmd/repl-interacter.hh +++ b/src/libcmd/repl-interacter.hh @@ -42,6 +42,11 @@ public: } virtual Guard init(detail::ReplCompleterMixin * repl) override; virtual bool getLine(std::string & input, ReplPromptType promptType) override; + /** Writes the current history to the history file. + * + * This function logs but ignores errors from readline's write_history(). + */ + virtual void writeHistory(); virtual ~ReadlineLikeInteracter() override; }; diff --git a/src/libcmd/repl.cc b/src/libcmd/repl.cc index 525c25560..46b6d57ed 100644 --- a/src/libcmd/repl.cc +++ b/src/libcmd/repl.cc @@ -90,7 +90,8 @@ struct NixRepl Strings loadedFiles; std::function<AnnotatedValues()> getValues; - const static int envSize = 32768; + // Uses 8MiB of memory. It's fine. + const static int envSize = 1 << 20; std::shared_ptr<StaticEnv> staticEnv; Env * env; int displ; @@ -375,6 +376,9 @@ StringSet NixRepl::completePrefix(const std::string & prefix) // Quietly ignore evaluation errors. } catch (BadURL & e) { // Quietly ignore BadURL flake-related errors. + } catch (SysError & e) { + // Quietly ignore system errors which can for example be raised by + // a non-existent file being `import`-ed. } } @@ -854,6 +858,11 @@ void NixRepl::loadReplOverlays() replInitFilesFunction->determinePos(noPos) ); + // n.b. this does in fact load the stuff into the environment twice (once + // from the superset of the environment returned by repl-overlays and once + // from the thing itself), but it's not fixable because clearEnv here could + // lead to dangling references to the old environment in thunks. + // https://git.lix.systems/lix-project/lix/issues/337#issuecomment-3745 addAttrsToScope(newAttrs); } diff --git a/src/libexpr/primops/context.cc b/src/libexpr/primops/context.cc index 1eec8b316..36692aafb 100644 --- a/src/libexpr/primops/context.cc +++ b/src/libexpr/primops/context.cc @@ -36,7 +36,7 @@ static RegisterPrimOp primop_hasContext({ > **Example** > - > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally loosing track of string context elements. + > Many operations require a string context to be empty because they are intended only to work with "regular" strings, and also to help users avoid unintentionally losing track of string context elements. > `builtins.hasContext` can help create better domain-specific errors in those case. > > ```nix @@ -137,14 +137,14 @@ static RegisterPrimOp primop_addDrvOutputDependencies({ .name = "__addDrvOutputDependencies", .args = {"s"}, .doc = R"( - Create a copy of the given string where a single consant string context element is turned into a "derivation deep" string context element. + Create a copy of the given string where a single constant string context element is turned into a "derivation deep" string context element. The store path that is the constant string context element should point to a valid derivation, and end in `.drv`. The original string context element must not be empty or have multiple elements, and it must not have any other type of element other than a constant or derivation deep element. The latter is supported so this function is idempotent. - This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-addDrvOutputDependencies). + This is the opposite of [`builtins.unsafeDiscardOutputDependency`](#builtins-unsafeDiscardOutputDependency). )", .fun = prim_addDrvOutputDependencies }); diff --git a/src/libfetchers/cache.cc b/src/libfetchers/cache.cc index 0c8ecac9d..672e1e0bc 100644 --- a/src/libfetchers/cache.cc +++ b/src/libfetchers/cache.cc @@ -34,7 +34,16 @@ struct CacheImpl : Cache auto state(_state.lock()); auto dbPath = getCacheDir() + "/nix/fetcher-cache-v1.sqlite"; - createDirs(dirOf(dbPath)); + // It would be silly to fail fetcher operations if e.g. the user has no + // XDG_CACHE_HOME and their HOME directory doesn't exist. + // We'll warn the user if that happens, but fallback to an in-memory + // backend for the SQLite database. + try { + createDirs(dirOf(dbPath)); + } catch (SysError const & ex) { + warn("ignoring error initializing Lix fetcher cache: %s", ex.what()); + dbPath = ":memory:"; + } state->db = SQLite(dbPath); state->db.isCache(); diff --git a/src/libstore/build/derivation-goal.cc b/src/libstore/build/derivation-goal.cc index 3f24da276..5fa5deb7c 100644 --- a/src/libstore/build/derivation-goal.cc +++ b/src/libstore/build/derivation-goal.cc @@ -786,13 +786,6 @@ void DerivationGoal::tryLocalBuild() { } -static void chmod_(const Path & path, mode_t mode) -{ - if (chmod(path.c_str(), mode) == -1) - throw SysError("setting permissions on '%s'", path); -} - - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the directory's parent link ".."). */ @@ -803,12 +796,12 @@ static void movePath(const Path & src, const Path & dst) bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR)); if (changePerm) - chmod_(src, st.st_mode | S_IWUSR); + chmodPath(src, st.st_mode | S_IWUSR); renameFile(src, dst); if (changePerm) - chmod_(dst, st.st_mode); + chmodPath(dst, st.st_mode); } diff --git a/src/libstore/build/local-derivation-goal.cc b/src/libstore/build/local-derivation-goal.cc index cdbd0f5a7..5c36a3ac2 100644 --- a/src/libstore/build/local-derivation-goal.cc +++ b/src/libstore/build/local-derivation-goal.cc @@ -272,12 +272,6 @@ void LocalDerivationGoal::tryLocalBuild() started(); } -static void chmod_(const Path & path, mode_t mode) -{ - if (chmod(path.c_str(), mode) == -1) - throw SysError("setting permissions on '%s'", path); -} - /* Move/rename path 'src' to 'dst'. Temporarily make 'src' writable if it's a directory and we're not root (to be able to update the @@ -289,12 +283,12 @@ static void movePath(const Path & src, const Path & dst) bool changePerm = (geteuid() && S_ISDIR(st.st_mode) && !(st.st_mode & S_IWUSR)); if (changePerm) - chmod_(src, st.st_mode | S_IWUSR); + chmodPath(src, st.st_mode | S_IWUSR); renameFile(src, dst); if (changePerm) - chmod_(dst, st.st_mode); + chmodPath(dst, st.st_mode); } @@ -696,7 +690,7 @@ void LocalDerivationGoal::startBuilder() instead.) */ Path chrootTmpDir = chrootRootDir + "/tmp"; createDirs(chrootTmpDir); - chmod_(chrootTmpDir, 01777); + chmodPath(chrootTmpDir, 01777); /* Create a /etc/passwd with entries for the build user and the nobody account. The latter is kind of a hack to support @@ -721,7 +715,7 @@ void LocalDerivationGoal::startBuilder() build user. */ Path chrootStoreDir = chrootRootDir + worker.store.storeDir; createDirs(chrootStoreDir); - chmod_(chrootStoreDir, 01775); + chmodPath(chrootStoreDir, 01775); if (buildUser && chown(chrootStoreDir.c_str(), 0, buildUser->getGID()) == -1) throw SysError("cannot change ownership of '%1%'", chrootStoreDir); @@ -1862,7 +1856,7 @@ void LocalDerivationGoal::runChild() auto dst = chrootRootDir + i.first; createDirs(dirOf(dst)); writeFile(dst, std::string_view((const char *) sh, sizeof(sh))); - chmod_(dst, 0555); + chmodPath(dst, 0555); } else #endif doBind(i.second.source, chrootRootDir + i.first, i.second.optional); @@ -1900,7 +1894,7 @@ void LocalDerivationGoal::runChild() /* Make sure /dev/pts/ptmx is world-writable. With some Linux versions, it is created with permissions 0. */ - chmod_(chrootRootDir + "/dev/pts/ptmx", 0666); + chmodPath(chrootRootDir + "/dev/pts/ptmx", 0666); } else { if (errno != EINVAL) throw SysError("mounting /dev/pts"); @@ -1911,7 +1905,7 @@ void LocalDerivationGoal::runChild() /* Make /etc unwritable */ if (!parsedDrv->useUidRange()) - chmod_(chrootRootDir + "/etc", 0555); + chmodPath(chrootRootDir + "/etc", 0555); /* Unshare this mount namespace. This is necessary because pivot_root() below changes the root of the mount diff --git a/src/libutil/archive.cc b/src/libutil/archive.cc index 00536c1e1..a18c54ebf 100644 --- a/src/libutil/archive.cc +++ b/src/libutil/archive.cc @@ -389,13 +389,4 @@ void copyNAR(Source & source, Sink & sink) } -void copyPath(const Path & from, const Path & to) -{ - auto source = sinkToSource([&](Sink & sink) { - dumpPath(from, sink); - }); - restorePath(to, *source); -} - - } diff --git a/src/libutil/archive.hh b/src/libutil/archive.hh index 2cf164a41..017b6633c 100644 --- a/src/libutil/archive.hh +++ b/src/libutil/archive.hh @@ -124,8 +124,6 @@ void restorePath(const Path & path, Source & source); */ void copyNAR(Source & source, Sink & sink); -void copyPath(const Path & from, const Path & to); - inline constexpr std::string_view narVersionMagic1 = "nix-archive-1"; diff --git a/src/libutil/error.hh b/src/libutil/error.hh index 924366580..323365d65 100644 --- a/src/libutil/error.hh +++ b/src/libutil/error.hh @@ -110,6 +110,8 @@ protected: public: BaseError(const BaseError &) = default; + BaseError & operator=(BaseError const & rhs) = default; + template<typename... Args> BaseError(unsigned int status, const Args & ... args) : err { .level = lvlError, .msg = HintFmt(args...), .status = status } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index bc2dd1802..2c0fcc897 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -184,6 +184,11 @@ Path canonPath(PathView path, bool resolveSymlinks) return s.empty() ? "/" : std::move(s); } +void chmodPath(const Path & path, mode_t mode) +{ + if (chmod(path.c_str(), mode) == -1) + throw SysError("setting permissions on '%s'", path); +} Path dirOf(const PathView path) { @@ -1799,8 +1804,7 @@ AutoCloseFD createUnixDomainSocket(const Path & path, mode_t mode) bind(fdSocket.get(), path); - if (chmod(path.c_str(), mode) == -1) - throw SysError("changing permissions on '%1%'", path); + chmodPath(path.c_str(), mode); if (listen(fdSocket.get(), 100) == -1) throw SysError("cannot listen on socket '%1%'", path); diff --git a/src/libutil/util.hh b/src/libutil/util.hh index 914d6cce0..14868776c 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -78,6 +78,13 @@ Path absPath(Path path, Path canonPath(PathView path, bool resolveSymlinks = false); /** + * Change the permissions of a path + * Not called `chmod` as it shadows and could be confused with + * `int chmod(char *, mode_t)`, which does not handle errors + */ +void chmodPath(const Path & path, mode_t mode); + +/** * @return The directory part of the given canonical path, i.e., * everything before the final `/`. If the path is the root or an * immediate child thereof (e.g., `/foo`), this means `/` |