Compare commits

...

6 commits

Author SHA1 Message Date
Qyriad
420fac5f18 fix a bunch of lints 2026-03-22 17:10:26 +01:00
Qyriad
aed73e99be use lld for faster link times 2026-03-22 17:02:53 +01:00
Qyriad
88be53cd2f remove the persistent buffer until a refactor makes it per-connection 2026-03-22 17:02:53 +01:00
Qyriad
bd3ec3a904 nix: apply mkPretty to sub-derivations 2026-03-22 17:02:53 +01:00
Qyriad
e016c37634 customize Cargo a bit, for now 2026-03-22 16:41:01 +01:00
Qyriad
373e300b59 flake.lock: Update
Flake lock file updates:

• Updated input 'fenix':
    'github:nix-community/fenix/64407ddb1932af06ed5cd711f6a2ed946b2548b9' (2026-03-10)
  → 'github:nix-community/fenix/4cd28929c68cae521589bc21958d3793904ed1e2' (2026-03-22)
• Updated input 'nixpkgs':
    'github:NixOS/nixpkgs/608d0cadfed240589a7eea422407a547ad626a14' (2026-03-08)
  → 'github:NixOS/nixpkgs/9cf7092bdd603554bd8b63c216e8943cf9b12512' (2026-03-18)
2026-03-22 15:00:06 +01:00
11 changed files with 102 additions and 83 deletions

10
.cargo/config.toml Normal file
View file

@ -0,0 +1,10 @@
# SPDX-FileCopyrightText: 2026 Qyriad <qyriad@qyriad.me>
#
# SPDX-License-Identifier: EUPL-1.1
# vim: tabstop=2 shiftwidth=0 noexpandtab
[build]
rustflags = [
"-C", "force-frame-pointers=yes",
"-C", "force-unwind-tables=yes",
]

View file

@ -47,3 +47,19 @@ tap = "1.0.1"
tracing = { version = "0.1.44", features = ["attributes"] } tracing = { version = "0.1.44", features = ["attributes"] }
tracing-human-layer = "0.2.1" tracing-human-layer = "0.2.1"
tracing-subscriber = { version = "0.3.22", default-features = false, features = ["std", "env-filter", "fmt", "ansi", "registry", "parking_lot"] } tracing-subscriber = { version = "0.3.22", default-features = false, features = ["std", "env-filter", "fmt", "ansi", "registry", "parking_lot"] }
[profile.dev]
opt-level = 1
lto = "thin"
[profile.release]
debug = true
debug-assertions = true
lto = true
[profile.dev.package."*"]
opt-level = 1
[profile.release.package."*"]
debug = true
debug-assertions = true

View file

@ -9,7 +9,11 @@
in import src { inherit pkgs; }, in import src { inherit pkgs; },
}: let }: let
inherit (qpkgs) lib; inherit (qpkgs) lib;
dynix = qpkgs.callPackage ./package.nix { } dynix = (qpkgs.callPackage ./package.nix { })
.overrideAttrs (final: prev: {
dynixCommand = qpkgs.stdlib.mkStdenvPretty prev.dynixCommand;
dynixModules = qpkgs.stdlib.mkStdenvPretty prev.dynixModules;
})
|> qpkgs.stdlib.mkStdenvPretty; |> qpkgs.stdlib.mkStdenvPretty;
byStdenv = lib.mapAttrs (stdenvName: stdenv: let byStdenv = lib.mapAttrs (stdenvName: stdenv: let
withStdenv = dynix.override { clangStdenv = stdenv; }; withStdenv = dynix.override { clangStdenv = stdenv; };

12
flake.lock generated
View file

@ -3,11 +3,11 @@
"fenix": { "fenix": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1773126504, "lastModified": 1774163246,
"narHash": "sha256-/iXlg2V5UMlgCmyRHkPHjlD6NdMfFOnwFMvH7REigD4=", "narHash": "sha256-gzlqyLjP44LWraUd3Zn4xrQKOtK+zcBJ77pnsSUsxcM=",
"owner": "nix-community", "owner": "nix-community",
"repo": "fenix", "repo": "fenix",
"rev": "64407ddb1932af06ed5cd711f6a2ed946b2548b9", "rev": "4cd28929c68cae521589bc21958d3793904ed1e2",
"type": "github" "type": "github"
}, },
"original": { "original": {
@ -37,11 +37,11 @@
"nixpkgs": { "nixpkgs": {
"flake": false, "flake": false,
"locked": { "locked": {
"lastModified": 1772956932, "lastModified": 1773840656,
"narHash": "sha256-M0yS4AafhKxPPmOHGqIV0iKxgNO8bHDWdl1kOwGBwRY=", "narHash": "sha256-9tpvMGFteZnd3gRQZFlRCohVpqooygFuy9yjuyRL2C0=",
"owner": "NixOS", "owner": "NixOS",
"repo": "nixpkgs", "repo": "nixpkgs",
"rev": "608d0cadfed240589a7eea422407a547ad626a14", "rev": "9cf7092bdd603554bd8b63c216e8943cf9b12512",
"type": "github" "type": "github"
}, },
"original": { "original": {

View file

@ -7,14 +7,23 @@
clangStdenv, clangStdenv,
callPackage, callPackage,
linkFarm, linkFarm,
llvmPackages,
rustHooks, rustHooks,
rustPackages, rustPackages,
versionCheckHook, versionCheckHook,
wrapBintoolsWith,
}: lib.callWith' rustPackages ({ }: lib.callWith' rustPackages ({
rustPlatform, rustPlatform,
cargo, cargo,
}: let }: let
stdenv = clangStdenv; # Use LLD for faster link times.
stdenv = clangStdenv.override {
cc = clangStdenv.cc.override {
bintools = wrapBintoolsWith {
bintools = llvmPackages.bintools;
};
};
};
cargoToml = lib.importTOML ./Cargo.toml; cargoToml = lib.importTOML ./Cargo.toml;
cargoPackage = cargoToml.package; cargoPackage = cargoToml.package;
in stdenv.mkDerivation (finalAttrs: let in stdenv.mkDerivation (finalAttrs: let

View file

@ -21,7 +21,7 @@
inherit (pkgs) lib; inherit (pkgs) lib;
mkDevShell = dynix: qpkgs.callPackage dynix.mkDevShell { inherit fenixToolchain; }; mkDevShell = dynix: qpkgs.callPackage dynix.mkDevShell { inherit fenixToolchain; };
devShell = mkDevShell dynix; devShell = mkDevShell dynix |> qpkgs.stdlib.mkStdenvPretty;
byStdenv = lib.mapAttrs (lib.const mkDevShell) dynix.byStdenv; byStdenv = lib.mapAttrs (lib.const mkDevShell) dynix.byStdenv;

View file

@ -1,5 +1,5 @@
use std::{ use std::{
env, io, mem, env, io,
ops::Deref, ops::Deref,
os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd}, os::fd::{AsFd, BorrowedFd, IntoRawFd, OwnedFd, RawFd},
sync::{ sync::{
@ -26,7 +26,7 @@ use crate::{
use crate::{OwnedFdWithFlags, TokenFd}; use crate::{OwnedFdWithFlags, TokenFd};
pub static UID: LazyLock<Uid> = LazyLock::new(|| rustix::process::getuid()); pub static UID: LazyLock<Uid> = LazyLock::new(rustix::process::getuid);
pub static USER_SOCKET_DIR: LazyLock<&'static Path> = LazyLock::new(|| { pub static USER_SOCKET_DIR: LazyLock<&'static Path> = LazyLock::new(|| {
let dir: Box<Path> = env::var_os("XDG_RUNTIME_DIR") let dir: Box<Path> = env::var_os("XDG_RUNTIME_DIR")
@ -52,19 +52,23 @@ pub enum ConvenientAttrPath {
} }
impl ConvenientAttrPath { impl ConvenientAttrPath {
/// Not currently used, but here for completeness.
#[expect(dead_code)]
pub fn clone_from_dotted(s: &str) -> Self { pub fn clone_from_dotted(s: &str) -> Self {
Self::Dotted(Box::from(s)) Self::Dotted(Box::from(s))
} }
/// Not currently used, but here for completeness.
#[expect(dead_code)]
pub fn clone_from_split(s: &[&str]) -> Self { pub fn clone_from_split(s: &[&str]) -> Self {
Self::from_str_iter(s.into_iter().map(Deref::deref)) Self::from_str_iter(s.iter().map(Deref::deref))
} }
pub fn from_str_iter<'i, I>(iter: I) -> Self pub fn from_str_iter<'i, I>(iter: I) -> Self
where where
I: Iterator<Item = &'i str>, I: Iterator<Item = &'i str>,
{ {
let boxed = iter.map(|s| Box::from(s)); let boxed = iter.map(Box::from);
Self::Split(Box::from_iter(boxed)) Self::Split(Box::from_iter(boxed))
} }
@ -135,9 +139,6 @@ pub struct Daemon {
// Bijective mapping of [`mio::Token`]s to [`RawFd`]s. // Bijective mapping of [`mio::Token`]s to [`RawFd`]s.
tokfd: BiHashMap<TokenFd>, tokfd: BiHashMap<TokenFd>,
cmd_buffer: Vec<u8>,
next_timeout: Option<Duration>,
} }
/// `tokfd` handling. /// `tokfd` handling.
@ -222,6 +223,8 @@ impl Daemon {
.copied() .copied()
} }
/// Not currently used, but here for completeness.
#[expect(dead_code)]
fn token_for_fd(&self, fd: RawFd) -> Option<Token> { fn token_for_fd(&self, fd: RawFd) -> Option<Token> {
self.tokfd self.tokfd
.get2(&fd) .get2(&fd)
@ -255,10 +258,10 @@ impl Daemon {
debug!("opened daemon to {:?} file descriptor {fd:?}", name); debug!("opened daemon to {:?} file descriptor {fd:?}", name);
let path = match &name { let path = name
Some(name) => Some(PathBuf::from(name).into_boxed_path()), .as_ref()
None => None, .map(PathBuf::from)
}; .map(PathBuf::into_boxed_path);
Self { Self {
config_path, config_path,
@ -267,8 +270,6 @@ impl Daemon {
poller, poller,
fd_info, fd_info,
tokfd: Default::default(), tokfd: Default::default(),
cmd_buffer: Vec::with_capacity(1024),
next_timeout: TIMEOUT_NEVER,
} }
} }
@ -345,16 +346,12 @@ impl Daemon {
/// Private helpers. /// Private helpers.
impl Daemon { impl Daemon {
fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> { fn read_cmd(&mut self, fd: &BorrowedFd) -> Result<(), IoError> {
if self.cmd_buffer.len() == self.cmd_buffer.capacity() { // FIXME: don't use a new allocation every time.
self.cmd_buffer.reserve(1024); let mut cmd_buffer: Vec<u8> = Vec::with_capacity(1024);
}
let _count = rustix::io::read(fd, spare_capacity(&mut self.cmd_buffer)) let _count = rustix::io::read(fd, spare_capacity(&mut cmd_buffer))
.tap_err(|e| error!("read() on daemon fd {fd:?} failed: {e}"))?; .tap_err(|e| error!("read() on daemon fd {fd:?} failed: {e}"))?;
// So that the loop doesn't borrow from `self`.
let mut cmd_buffer = mem::take(&mut self.cmd_buffer);
// The buffer might have existing data from the last read. // The buffer might have existing data from the last read.
let deserializer = serde_json::Deserializer::from_slice(&cmd_buffer); let deserializer = serde_json::Deserializer::from_slice(&cmd_buffer);
let stream: StreamDeserializer<_, DaemonCmd> = deserializer.into_iter(); let stream: StreamDeserializer<_, DaemonCmd> = deserializer.into_iter();
@ -362,16 +359,13 @@ impl Daemon {
let cmd = match cmd { let cmd = match cmd {
Ok(cmd) => cmd, Ok(cmd) => cmd,
Err(e) if e.is_eof() => { Err(e) if e.is_eof() => {
self.next_timeout = Some(Duration::from_secs(4)); warn!("Got EOF before a valid command");
warn!("Didn't get a valid daemon command; giving the other side 4 seconds..."); debug!("command buffer was: {:?}", cmd_buffer.as_bstr());
let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer);
return Ok(()); return Ok(());
}, },
Err(e) => { Err(e) => {
warn!("error deserializing command: {e}"); warn!("error deserializing command: {e}");
debug!("command buffer was: {:?}", cmd_buffer.as_bstr()); debug!("command buffer was: {:?}", cmd_buffer.as_bstr());
cmd_buffer.clear();
let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer);
// Don't propagate the error unless we have too many. // Don't propagate the error unless we have too many.
self.fd_error_push(fd.as_raw_fd(), e.into()).tap_err(|e| { self.fd_error_push(fd.as_raw_fd(), e.into()).tap_err(|e| {
error!("Accumulated too many errors for daemon fd {fd:?}: {e}") error!("Accumulated too many errors for daemon fd {fd:?}: {e}")
@ -385,9 +379,6 @@ impl Daemon {
self.dispatch_cmd(cmd).unwrap_or_else(|e| todo!("{e}")); self.dispatch_cmd(cmd).unwrap_or_else(|e| todo!("{e}"));
} }
cmd_buffer.clear();
let _ = mem::replace(&mut self.cmd_buffer, cmd_buffer);
Ok(()) Ok(())
} }
@ -469,25 +460,19 @@ impl Daemon {
} }
} }
if let Some(timeout) = self.next_timeout { match self.poller.poll(&mut events, TIMEOUT_NEVER) {
debug!(
"epoll_wait() with a timeout: {}",
humantime::format_duration(timeout),
);
}
match self.poller.poll(&mut events, self.next_timeout.take()) {
Ok(_) => { Ok(_) => {
trace!( trace!(
"mio::Poller::poll() got events: {:?}", "mio::Poller::poll() got events: {:?}",
events.iter().size_hint().0, events.iter().size_hint().0,
); );
if events.is_empty() { if events.is_empty() {
warn!("timeout expired"); unreachable!(
self.cmd_buffer.clear(); "epoll_wait() with a \"forever\" timeout should never give empty events",
} else { );
let _ = self.fd_error_pop(self.poller.as_raw_fd());
} }
let _ = self.fd_error_pop(self.poller.as_raw_fd());
}, },
Err(e) if e.kind() == IoErrorKind::Interrupted => { Err(e) if e.kind() == IoErrorKind::Interrupted => {
// EINTR is silly. // EINTR is silly.

View file

@ -130,7 +130,7 @@ impl From<OwnedFd> for OwnedFdWithFlags {
impl Read for &OwnedFdWithFlags { impl Read for &OwnedFdWithFlags {
fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> { fn read(&mut self, buf: &mut [u8]) -> Result<usize, IoError> {
debug_assert!(buf.len() > 0); debug_assert!(!buf.is_empty());
loop { loop {
buf.fill(0); buf.fill(0);
match rustix::io::read(self.as_ref_owned(), &mut *buf) { match rustix::io::read(self.as_ref_owned(), &mut *buf) {

View file

@ -52,7 +52,7 @@ impl FdInfo {
match Self::guess_name(self.fd) { match Self::guess_name(self.fd) {
Ok(name) => { Ok(name) => {
let prev = self.name.set(Box::from(name)); let prev = self.name.set(name);
debug_assert_eq!(prev, Ok(())); debug_assert_eq!(prev, Ok(()));
}, },
Err(e) => { Err(e) => {
@ -105,13 +105,14 @@ impl<'a> Display for FdInfoDisplay<'a> {
} }
#[derive(Copy)] #[derive(Copy)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Default)]
#[non_exhaustive] #[non_exhaustive]
pub enum FdKind { pub enum FdKind {
File, File,
Socket, Socket,
SockStream, SockStream,
Poller, Poller,
#[default]
Unknown, Unknown,
} }
@ -128,12 +129,6 @@ impl FdKind {
} }
} }
impl Default for FdKind {
fn default() -> FdKind {
FdKind::Unknown
}
}
#[derive(Copy)] #[derive(Copy)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct TokenFd { pub struct TokenFd {

View file

@ -14,7 +14,7 @@ use tracing_subscriber::{EnvFilter, layer::SubscriberExt};
fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> { fn main_wrapped() -> Result<(), Box<dyn StdError + Send + Sync + 'static>> {
// Default RUST_LOG to warn if it's not specified. // Default RUST_LOG to warn if it's not specified.
if let None = env::var_os("RUST_LOG") { if env::var_os("RUST_LOG").is_none() {
unsafe { unsafe {
env::set_var("RUST_LOG", "warn"); env::set_var("RUST_LOG", "warn");
} }

View file

@ -5,27 +5,27 @@
#[allow(unused_imports)] #[allow(unused_imports)]
use crate::prelude::*; use crate::prelude::*;
#[derive(Debug, Clone, PartialEq, Hash)] //#[derive(Debug, Clone, PartialEq, Hash)]
pub(crate) struct NixEvalExpr<E, A> { //pub(crate) struct NixEvalExpr<E, A> {
pub(crate) expr: E, // pub(crate) expr: E,
pub(crate) attrpath: A, // pub(crate) attrpath: A,
} //}
//
impl<E, A> NixEvalExpr<E, A> //impl<E, A> NixEvalExpr<E, A>
where //where
E: AsRef<OsStr>, // E: AsRef<OsStr>,
A: AsRef<OsStr>, // A: AsRef<OsStr>,
{ //{
pub(crate) fn into_command(self) -> Command { // pub(crate) fn into_command(self) -> Command {
let mut cmd = Command::new("nix-instantiate"); // let mut cmd = Command::new("nix-instantiate");
cmd.arg("--eval") // cmd.arg("--eval")
.arg("--json") // .arg("--json")
.arg("--strict") // .arg("--strict")
.arg("--expr") // .arg("--expr")
.arg(self.expr) // .arg(self.expr)
.arg("-A") // .arg("-A")
.arg(self.attrpath); // .arg(self.attrpath);
//
cmd // cmd
} // }
} //}