c0e849b696 broke interrupt handling since
writeFull started throwing Interrupted even when allowInterrupts was false.
This would lead to exceptions leaking out when they must not (for example during
progress bar shutdown).
This commit reverts to using `getFSSourceAccessor()` so absolute symlink targets resolve correctly, since `makeFSSourceAccessor(path)` roots the accessor at `path` and can't follow symlinks that escape it.
`getCacheDir`, `getConfigDir`, `getDataDir`, `getStateDir`, and related functions now return `std::filesystem::path` and use `getEnvOs` for native OS string handling, letting callsites replace string concatenation with `operator/` and drop the ad-hoc `namespace nix::fs` alias from six CLI files. `expandTilde` is fixed to strip both `~` and `/` before joining with `operator/` (an absolute right-hand operand silently replaces the left-hand side), and `ExecutablePath` gains `parseAppend` for incremental `PATH` construction.
Co-authored-by: Amaan Qureshi <git@amaanq.com>
- Improve existing `read` and `readOffset` wrappers:
- Unix: Add `EINTR` retry handling and `checkInterrupt`
- Windows: Handle `ERROR_BROKEN_PIPE` as EOF, add `checkInterrupt`
- Add `write` wrapper with same treatment (`EINTR` on Unix, `checkInterrupt`)
- Improve many `windows/file-descriptor.cc` error messages with
`descriptorToPath`
- Move `readFull`, `readLine`, `writeFull` to common file, using the
platform wrappers instead of duplicating platform-specific logic.
These ones don't need any `EINTR` or interrupt checking either. They
only have `EGAIN` checking as Unix-specific code, but this is a temp
hack to be removed per #12688, so its fine that it goes in the
platform-agnostic file for now.
- Add `retryOnBlock` helper to abstract `EAGAIN`/`EWOULDBLOCK` poll-and-retry
logic (Unix only, needed for buildhook workaround #12688)
- Simplify `FdSource::readUnbuffered` to just call `nix::read`
- Remove now-dead `EINTR` handling from `drainFD` and `copyFdRange`
- `writeErr` better impl on Windows
The gcroots/profiles link became outdated in
aeb810b01e when the GC code started
reading directly from /profiles, and gcroots/profiles was even
partially deleted in that commit.
The new signature is:
writeFile(Descriptor fd, std::string_view s, FsSync sync = FsSync::No, const Path * origPath = nullptr)
This uses `descriptorToPath` if `origPath` is not provided.
`AutoCloseFD::fsync()` contained platform-specific logic behind CPP
guards. This extracts it into a free function `syncDescriptor(Descriptor)`
with separate Unix and Windows implementations, and makes
`AutoCloseFD::fsync()` an inline wrapper that delegates to it. The
Windows implementation uses `FlushFileBuffers` (returns `BOOL`, true on
success) while Unix uses `::fsync` (or `F_FULLFSYNC` on macOS), so
splitting them avoids conflating the two calling conventions.
This indicates that they are returning an owned handle (i.e. the caller
should --- and will, thanks to RAII --- close it).
`ntOpenAt` and friends (internal) also use `AutoCloseFD` for the same
reason.
This provides an explicit API for call-fail-retry-succeed evaluation
flows, such as currently used in NixOps4.
An alternative design would simply reset the `Value` to the original
thunk instead of `tFailed` under the condition of catching a
`RecoverableEvalError`.
That is somewhat simpler, but I believe the presence of `tFailed` is
beneficial for possible use in the repl; being able to show the error
sooner, without re-evaluation.
The hasPos method is required in order to avoid an include loop.
In the multithreaded evaluator, it's possible for multiple threads to
wait on the same thunk. If evaluation of the thunk results in an
exception, the waiting threads shouldn't try to re-force the thunk.
Instead, they should rethrow the same exception, without duplicating
any work.
Therefore, there is now a new value type `tFailed` that stores an
std::exception_ptr. If evaluation of a thunk/app results in an
exception, `forceValue()` overwrites the value with a `tFailed`. If
`forceValue()` encounters a `tFailed`, it rethrows the exception. So
you normally never need to check for failed values (since forcing them
causes a rethrow).
Co-authored-by: Robert Hensing <robert@roberthensing.nl>
This rather commonly occurs when the computer was uncleanly shut down
and fsync was not enabled. Show the user a more actionable message than
"expected string 'D'".
This reverts commit 4f91e9599f.
This broke:
when I applied this pr, `--print-out-paths` wouldn't print anything:
```
shell-for-nix-env % nix build --print-out-paths .#legacyPackages.aarch64-darwin.homeConfigurations.macos.activationPackage
```
After dropping the patches from my fork, it does again.
```
shell-for-nix-env % nix build --print-out-paths .#legacyPackages.aarch64-darwin.homeConfigurations.macos.activationPackage
/nix/store/s8mlcalszdml0v8172w4hwqnx0m6477r-home-manager-generation
```
EvalState inherits from enable_shared_from_this (added in b4c24a29 for
debugRepl), but was being stack-allocated or created with make_unique
in several places. This causes bad_weak_ptr errors when shared_from_this
is called.
Convert all EvalState allocations to use make_shared.
- Make `descriptorToPath` cross-platform (renamed from
`windows::handleToPath`). Uses `/proc/self/fd` on Linux and
`F_GETPATH` on macOS. Add `HAVE_F_GETPATH` meson check.
This is based on 7226a116a0, which was
removed in 479c356510, but is now
introduced more judiciously.
- Unix error messages in `readFull`, `writeFull`, `readLine` now include
file paths via `descriptorToPath`.
- Convert `std::filesystem::filesystem_error` to `SystemError`
Wrappers like `readLink`, `createDirs`, `DirectoryIterator`, etc. now
catch `std::filesystem::filesystem_error` and rethrow as `SystemError`
with the error code preserved. This ensures consistent exception types
throughout the codebase.
Call sites that previously caught `filesystem_error` and rethrew with
`throw;` now throw `SystemError(e.code(), ...)` instead.
Some call sites can stop catching `filesystem_error` at all,
because they only call the wrapped functions.
- Rework `SystemError` constructors to auto-append error message
The public `SystemError(std::error_code, ...)` constructor now
automatically appends `errorCode.message()` to the error message.
A protected constructor takes an explicit error message string for
subclasses.
`SysError` delegates to the protected constructor with `strerror(errNo)`.
`WinError` delegates with `renderError(lastError)` (now static).
This removes the need to manually append `e.code().message()` at call
sites when converting `filesystem_error` to `SystemError`.
- Use perfect forwarding (`Args &&...` with `std::forward`) consistently
in `BaseError`, `SystemError`, `SysError`, and `WinError` constructors.
Co-authored-by: Sergei Zimmerman <sergei@zimmerman.foo>
In 3df91bea62 I forgot that the header
might get included out-of-tree with -Wundef. Let's make this a public
config option for libutil as it can affect function bodies in headers.
`tryToBuild` threaded a single `PathLocks outputLocks` by reference
across all build phases and managed a `std::unique_ptr<Activity> actLock`
with explicit `if (!actLock)` guards and `.reset()` calls around the hook
retry loop. This commit introduces coroutine lambdas for the three phases:
`tryHookLoop` owns a `PathLocks` in a scoped block for the first attempt
and per-iteration in the retry loop, `tryBuildLocally` acquires its own
`PathLocks`, and the hook-wait `Activity` is a stack variable scoped to
the postpone block.
When `max-jobs = 0` and no remote builders are available, Nix reported
"required system or feature not available" even though the system and
features matched fine. The `canBuildLocally` lambda returned a plain
`bool`, conflating a configuration knob (`max-jobs = 0`) with actual
incompatibility (wrong platform, missing features). It also short-circuited
on the first failing check, so a user with both a platform mismatch and
missing features would only see one of the two.
This commit replaces the bool with a `LocalBuildRejection` struct whose
`WrongLocalStore` variant collects all applicable failures into
`badPlatform`, `missingFeatures`, and an orthogonal `maxJobsZero` flag.
Platform mismatch and missing features now produce separate error
paragraphs, and all applicable reasons appear in a single message.
The local-build capability check also now returns
`std::variant<LocalBuildCapability, LocalBuildRejection>`, bundling
the `LocalStore &` and optional `ExternalBuilder *` together.
This comes in two parts: a `nix store roots-daemon` command that
can run as root and list runtime roots,
and client logic to find runtime roots for a `LocalStore` by connecting
to that daemon.
This may be useful with an unprivileged nix daemon, as it would
otherwise be unable to find runtime roots from process open files
and maps.
Using nix::unreachable() in getInternalType() and type() turns
out to be quite expensive and prevents inlining. Also Value::type
got compiled to a jump table which has a high overhead from indirect
jumps. Using an explicit lookup table turns out to be more efficient.
This does mean that we lose out on nice diagnostics from nix::unreachable
calls, but this code is probably one of the hottests functions in the whole
evaluator, so I think the tradeoff is worth it. The nixUnreachableWhenHardened
boils down to nix::unreachable when UBSan is enabled so we still have good
coverage there.