aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/libcmd/installable-flake.cc9
-rw-r--r--src/libcmd/repl-interacter.cc33
-rw-r--r--src/libcmd/repl-interacter.hh5
-rw-r--r--src/libcmd/repl.cc11
-rw-r--r--src/libexpr/primops/context.cc6
-rw-r--r--src/libfetchers/cache.cc11
-rw-r--r--src/libstore/build/derivation-goal.cc11
-rw-r--r--src/libstore/build/local-derivation-goal.cc20
-rw-r--r--src/libutil/archive.cc9
-rw-r--r--src/libutil/archive.hh2
-rw-r--r--src/libutil/error.hh2
-rw-r--r--src/libutil/util.cc8
-rw-r--r--src/libutil/util.hh7
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 `/`