more reasonable tracking of open FDs
This commit is contained in:
parent
398fccc5d0
commit
aee8dcb31a
6 changed files with 163 additions and 77 deletions
49
Cargo.lock
generated
49
Cargo.lock
generated
|
|
@ -11,6 +11,12 @@ dependencies = [
|
||||||
"memchr",
|
"memchr",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "allocator-api2"
|
||||||
|
version = "0.2.21"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "683d7910e743518b0e34f1186f92494becacb047c7b6bf616c96772180fef923"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "anstream"
|
name = "anstream"
|
||||||
version = "0.6.21"
|
version = "0.6.21"
|
||||||
|
|
@ -67,6 +73,12 @@ version = "1.5.0"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "bimap"
|
||||||
|
version = "0.6.3"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "230c5f1ca6a325a32553f8640d31ac9b49f2411e901e427570154868b46da4f7"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "bitflags"
|
name = "bitflags"
|
||||||
version = "2.11.0"
|
version = "2.11.0"
|
||||||
|
|
@ -187,6 +199,7 @@ checksum = "d0881ea181b1df73ff77ffaaf9c7544ecc11e82fba9b5f27b262a3c73a332555"
|
||||||
name = "dynix"
|
name = "dynix"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"bimap",
|
||||||
"bitflags",
|
"bitflags",
|
||||||
"bstr",
|
"bstr",
|
||||||
"circular-buffer",
|
"circular-buffer",
|
||||||
|
|
@ -195,6 +208,8 @@ dependencies = [
|
||||||
"const-str",
|
"const-str",
|
||||||
"displaydoc",
|
"displaydoc",
|
||||||
"fs-err",
|
"fs-err",
|
||||||
|
"humantime",
|
||||||
|
"iddqd",
|
||||||
"itertools",
|
"itertools",
|
||||||
"libc",
|
"libc",
|
||||||
"mio",
|
"mio",
|
||||||
|
|
@ -232,6 +247,12 @@ dependencies = [
|
||||||
"windows-sys 0.61.2",
|
"windows-sys 0.61.2",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "foldhash"
|
||||||
|
version = "0.2.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "77ce24cb58228fbb8aa041425bb1050850ac19177686ea6e0f41a70416f56fdb"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "fs-err"
|
name = "fs-err"
|
||||||
version = "3.3.0"
|
version = "3.3.0"
|
||||||
|
|
@ -246,6 +267,9 @@ name = "hashbrown"
|
||||||
version = "0.16.1"
|
version = "0.16.1"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "heck"
|
name = "heck"
|
||||||
|
|
@ -259,6 +283,25 @@ version = "0.5.2"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "humantime"
|
||||||
|
version = "2.3.0"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "135b12329e5e3ce057a9f972339ea52bc954fe1e9358ef27f95e89716fbc5424"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "iddqd"
|
||||||
|
version = "0.3.17"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "6b215e67ed1d1a4b1702acd787c487d16e4c977c5dcbcc4587bdb5ea26b6ce06"
|
||||||
|
dependencies = [
|
||||||
|
"allocator-api2",
|
||||||
|
"equivalent",
|
||||||
|
"foldhash",
|
||||||
|
"hashbrown",
|
||||||
|
"rustc-hash",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "indexmap"
|
name = "indexmap"
|
||||||
version = "2.13.0"
|
version = "2.13.0"
|
||||||
|
|
@ -513,6 +556,12 @@ version = "0.8.10"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a"
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "rustc-hash"
|
||||||
|
version = "2.1.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "rustix"
|
name = "rustix"
|
||||||
version = "1.1.4"
|
version = "1.1.4"
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,7 @@ regex-full = ["dep:regex"]
|
||||||
regex-lite = ["dep:regex-lite"]
|
regex-lite = ["dep:regex-lite"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
bimap = "0.6.3"
|
||||||
bitflags = { version = "2.11.0", features = ["std"] }
|
bitflags = { version = "2.11.0", features = ["std"] }
|
||||||
bstr = "1.12.1"
|
bstr = "1.12.1"
|
||||||
circular-buffer = "1.2.0"
|
circular-buffer = "1.2.0"
|
||||||
|
|
@ -30,6 +31,8 @@ command-error = "0.8.0"
|
||||||
const-str = "1.1.0"
|
const-str = "1.1.0"
|
||||||
displaydoc = "0.2.5"
|
displaydoc = "0.2.5"
|
||||||
fs-err = "3.2.2"
|
fs-err = "3.2.2"
|
||||||
|
humantime = "2.3.0"
|
||||||
|
iddqd = "0.3.17"
|
||||||
itertools = "0.14.0"
|
itertools = "0.14.0"
|
||||||
libc = { version = "0.2.180", features = ["extra_traits"] }
|
libc = { version = "0.2.180", features = ["extra_traits"] }
|
||||||
#macro_rules_attribute = { version = "0.2.2", features = ["better-docs", "verbose-expansions"] }
|
#macro_rules_attribute = { version = "0.2.2", features = ["better-docs", "verbose-expansions"] }
|
||||||
|
|
|
||||||
138
src/daemon.rs
138
src/daemon.rs
|
|
@ -7,19 +7,15 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use circular_buffer::CircularBuffer;
|
use circular_buffer::CircularBuffer;
|
||||||
|
use iddqd::BiHashMap;
|
||||||
|
|
||||||
use mio::{Events, Interest, Poll, Token, net::UnixListener, unix::SourceFd};
|
use mio::{Events, Interest, Poll, Token, net::UnixListener, unix::SourceFd};
|
||||||
|
|
||||||
use rustix::{
|
use rustix::{
|
||||||
buffer::{Buffer, spare_capacity},
|
buffer::spare_capacity,
|
||||||
fs::{FileType, OFlags, Stat, fcntl_setfl},
|
fs::{FileType, Stat},
|
||||||
io::Errno,
|
|
||||||
net::SocketFlags,
|
net::SocketFlags,
|
||||||
process::Uid,
|
process::Uid,
|
||||||
termios::{
|
|
||||||
ControlModes, InputModes, LocalModes, OptionalActions, OutputModes, SpecialCodeIndex,
|
|
||||||
SpecialCodes, Termios, tcgetattr, tcsetattr,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
@ -27,7 +23,7 @@ use serde_json::StreamDeserializer;
|
||||||
|
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
use crate::OwnedFdWithFlags;
|
use crate::{OwnedFdWithFlags, TokenFd};
|
||||||
|
|
||||||
pub static UID: LazyLock<Uid> = LazyLock::new(|| rustix::process::getuid());
|
pub static UID: LazyLock<Uid> = LazyLock::new(|| rustix::process::getuid());
|
||||||
|
|
||||||
|
|
@ -109,10 +105,33 @@ pub struct Daemon {
|
||||||
poll_error_buffer: CircularBuffer<ERROR_BUFFER_LEN, IoError>,
|
poll_error_buffer: CircularBuffer<ERROR_BUFFER_LEN, IoError>,
|
||||||
fd_error_buffer: CircularBuffer<ERROR_BUFFER_LEN, IoError>,
|
fd_error_buffer: CircularBuffer<ERROR_BUFFER_LEN, IoError>,
|
||||||
|
|
||||||
|
// Bijective mapping of [`mio::Token`]s to [`RawFd`]s.
|
||||||
|
tokfd: BiHashMap<TokenFd>,
|
||||||
|
|
||||||
cmd_buffer: Vec<u8>,
|
cmd_buffer: Vec<u8>,
|
||||||
next_timeout: Option<Duration>,
|
next_timeout: Option<Duration>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// `tokfd` handling.
|
||||||
|
impl Daemon {
|
||||||
|
//fn register(&mut self, token: Token, fd: RawFd) {
|
||||||
|
// self.insert_unique
|
||||||
|
//}
|
||||||
|
fn fd_for_token(&self, token: Token) -> Option<RawFd> {
|
||||||
|
self.tokfd
|
||||||
|
.get1(&token)
|
||||||
|
.map(|TokenFd { fd, .. }| fd)
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn token_for_fd(&self, fd: RawFd) -> Option<Token> {
|
||||||
|
self.tokfd
|
||||||
|
.get2(&fd)
|
||||||
|
.map(|TokenFd { token, .. }| token)
|
||||||
|
.copied()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Daemon {
|
impl Daemon {
|
||||||
pub fn new(fd: OwnedFd, name_or_path: Box<OsStr>) -> Self {
|
pub fn new(fd: OwnedFd, name_or_path: Box<OsStr>) -> Self {
|
||||||
let fd = OwnedFdWithFlags::new_with_fallback(fd);
|
let fd = OwnedFdWithFlags::new_with_fallback(fd);
|
||||||
|
|
@ -126,6 +145,7 @@ impl Daemon {
|
||||||
fd,
|
fd,
|
||||||
path: name_or_path,
|
path: name_or_path,
|
||||||
poll_error_buffer: Default::default(),
|
poll_error_buffer: Default::default(),
|
||||||
|
tokfd: Default::default(),
|
||||||
fd_error_buffer: Default::default(),
|
fd_error_buffer: Default::default(),
|
||||||
cmd_buffer: Vec::with_capacity(1024),
|
cmd_buffer: Vec::with_capacity(1024),
|
||||||
next_timeout: TIMEOUT_NEVER,
|
next_timeout: TIMEOUT_NEVER,
|
||||||
|
|
@ -137,9 +157,8 @@ impl Daemon {
|
||||||
let _ = rustix::fs::unlink(path);
|
let _ = rustix::fs::unlink(path);
|
||||||
let listener = UnixListener::bind(path)
|
let listener = UnixListener::bind(path)
|
||||||
.tap_err(|e| error!("failed to bind AF_UNIX socket at {}: {e}", path.display()))?;
|
.tap_err(|e| error!("failed to bind AF_UNIX socket at {}: {e}", path.display()))?;
|
||||||
//let (stream, _addr) = listener.accept().unwrap_or_else(|e| todo!("error: {e}"));
|
|
||||||
//warn!("stream is: {stream:?} ({})", stream.as_raw_fd());
|
|
||||||
let listener_owned_fd = OwnedFd::from(listener);
|
let listener_owned_fd = OwnedFd::from(listener);
|
||||||
|
// FIXME: should we KEEP_ALIVE?
|
||||||
rustix::net::sockopt::set_socket_keepalive(&listener_owned_fd, true).unwrap();
|
rustix::net::sockopt::set_socket_keepalive(&listener_owned_fd, true).unwrap();
|
||||||
let path: Box<OsStr> = path.to_path_buf().into_boxed_path().into_boxed_os_str();
|
let path: Box<OsStr> = path.to_path_buf().into_boxed_path().into_boxed_os_str();
|
||||||
|
|
||||||
|
|
@ -249,8 +268,19 @@ impl Daemon {
|
||||||
let raw_fd = self.fd.as_raw_fd();
|
let raw_fd = self.fd.as_raw_fd();
|
||||||
let mut daemon_source = SourceFd(&raw_fd);
|
let mut daemon_source = SourceFd(&raw_fd);
|
||||||
const DAEMON: Token = Token(0);
|
const DAEMON: Token = Token(0);
|
||||||
|
self.tokfd
|
||||||
|
.insert_unique(TokenFd {
|
||||||
|
token: DAEMON,
|
||||||
|
fd: raw_fd,
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
let mut next_token_number: usize = 1;
|
let mut next_token_number: usize = 1;
|
||||||
let mut extra_tokens: Vec<(Token, RawFd)> = Default::default();
|
let mut next_token = || -> Token {
|
||||||
|
let t = Token(next_token_number);
|
||||||
|
next_token_number = next_token_number.saturating_add(1);
|
||||||
|
t
|
||||||
|
};
|
||||||
|
|
||||||
let mut poll = Poll::new().unwrap_or_else(|e| unreachable!("creating new mio Poll: {e}"));
|
let mut poll = Poll::new().unwrap_or_else(|e| unreachable!("creating new mio Poll: {e}"));
|
||||||
|
|
||||||
poll.registry()
|
poll.registry()
|
||||||
|
|
@ -259,27 +289,14 @@ impl Daemon {
|
||||||
|
|
||||||
let mut events = Events::with_capacity(1024);
|
let mut events = Events::with_capacity(1024);
|
||||||
|
|
||||||
let example = DaemonCmd::Append {
|
|
||||||
//name: ConvenientAttrPath::Dotted(Box::from(
|
|
||||||
// "services.gotosocial.settings.application-name",
|
|
||||||
//)),
|
|
||||||
//name: ConvenientAttrPath::Split(Box::from([
|
|
||||||
// Box::from("services"),
|
|
||||||
// Box::from("gotosocial"),
|
|
||||||
//])),
|
|
||||||
name: ConvenientAttrPath::clone_from_split(&[
|
|
||||||
"services",
|
|
||||||
"gotosocial",
|
|
||||||
"settings",
|
|
||||||
"application-name",
|
|
||||||
]),
|
|
||||||
value: Box::from("foo"),
|
|
||||||
};
|
|
||||||
|
|
||||||
//let example_as_json = serde_json::to_string_pretty(&example).unwrap();
|
|
||||||
//info!("{}", example_as_json);
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
if let Some(timeout) = self.next_timeout {
|
||||||
|
debug!(
|
||||||
|
"epoll_wait() with a timeout: {}",
|
||||||
|
humantime::format_duration(timeout),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
match poll.poll(&mut events, self.next_timeout.take()) {
|
match poll.poll(&mut events, self.next_timeout.take()) {
|
||||||
Ok(_) => {
|
Ok(_) => {
|
||||||
if events.is_empty() {
|
if events.is_empty() {
|
||||||
|
|
@ -333,50 +350,25 @@ impl Daemon {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Add this stream to our poll interest list.
|
||||||
let mut stream_fd = stream_fd.into_raw_fd();
|
let mut stream_fd = stream_fd.into_raw_fd();
|
||||||
|
let token = next_token();
|
||||||
// And add this stream to our poll interest list.
|
self.tokfd
|
||||||
if let Err(idx) =
|
.insert_unique((token, stream_fd).into())
|
||||||
extra_tokens.binary_search_by_key(&stream_fd, |(_, fd)| fd.as_raw_fd())
|
.unwrap_or_else(|e| unreachable!("? {e}"));
|
||||||
{
|
|
||||||
let token = Token(next_token_number);
|
|
||||||
extra_tokens.insert(idx, (token, stream_fd));
|
|
||||||
next_token_number = next_token_number.wrapping_add(1);
|
|
||||||
let mut source = SourceFd(&mut stream_fd);
|
let mut source = SourceFd(&mut stream_fd);
|
||||||
poll.registry()
|
poll.registry()
|
||||||
.register(&mut source, token, Interest::READABLE)
|
.register(&mut source, token, Interest::READABLE)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
|
||||||
|
|
||||||
// Wait for the next poll to handle.
|
// Wait for the next poll to handle.
|
||||||
|
|
||||||
//match self.read_cmd(Some(&stream_fd)) {
|
|
||||||
// Ok(()) => (),
|
|
||||||
// Err(e) if e.kind() == IoErrorKind::WouldBlock => {
|
|
||||||
// continue;
|
|
||||||
// },
|
|
||||||
// Err(e) => {
|
|
||||||
// self.fd_error_buffer.try_push_back(e.into()).tap_err(|e| {
|
|
||||||
// error!(
|
|
||||||
// "Accumulated too many errors for fd {:?} {e}",
|
|
||||||
// &stream_fd,
|
|
||||||
// )
|
|
||||||
// })?;
|
|
||||||
// },
|
|
||||||
//}
|
|
||||||
},
|
},
|
||||||
other_token => {
|
other_token => {
|
||||||
let index = match extra_tokens
|
|
||||||
.binary_search_by_key(&other_token, |&(t, _)| t)
|
|
||||||
{
|
|
||||||
Ok(index) => index,
|
|
||||||
Err(index) => unreachable!(
|
|
||||||
"tried to get index ({index}) for non-existent token {other_token:?}"
|
|
||||||
),
|
|
||||||
};
|
|
||||||
|
|
||||||
// This must be a stream fd.
|
// This must be a stream fd.
|
||||||
let (_, stream_fd) = extra_tokens[index];
|
let stream_fd = self.fd_for_token(other_token).unwrap_or_else(|| {
|
||||||
|
unreachable!("tried to get fd for no-existent token? {other_token:?}")
|
||||||
|
});
|
||||||
|
|
||||||
// SAFETY: oh boy.
|
// SAFETY: oh boy.
|
||||||
let stream_fd = unsafe { BorrowedFd::borrow_raw(stream_fd) };
|
let stream_fd = unsafe { BorrowedFd::borrow_raw(stream_fd) };
|
||||||
self.read_cmd(Some(&stream_fd)).unwrap();
|
self.read_cmd(Some(&stream_fd)).unwrap();
|
||||||
|
|
@ -386,14 +378,14 @@ impl Daemon {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_fallback_fd_name<Fd: AsRawFd>(fd: Fd) -> Option<Box<OsStr>> {
|
//fn get_fallback_fd_name<Fd: AsRawFd>(fd: Fd) -> Option<Box<OsStr>> {
|
||||||
let dev_fd_path = Path::new("/dev/fd").join(fd.as_raw_fd().to_string());
|
// let dev_fd_path = Path::new("/dev/fd").join(fd.as_raw_fd().to_string());
|
||||||
|
//
|
||||||
fs_err::read_link(dev_fd_path)
|
// fs_err::read_link(dev_fd_path)
|
||||||
.map(PathBuf::into_os_string)
|
// .map(PathBuf::into_os_string)
|
||||||
.map(OsString::into_boxed_os_str)
|
// .map(OsString::into_boxed_os_str)
|
||||||
.ok()
|
// .ok()
|
||||||
}
|
//}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for Daemon {
|
impl Drop for Daemon {
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ use std::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use iddqd::BiHashItem;
|
||||||
|
use mio::Token;
|
||||||
use rustix::{
|
use rustix::{
|
||||||
fs::{OFlags, fcntl_getfl, fcntl_setfl},
|
fs::{OFlags, fcntl_getfl, fcntl_setfl},
|
||||||
io::Errno,
|
io::Errno,
|
||||||
|
|
|
||||||
38
src/daemon_tokfd.rs
Normal file
38
src/daemon_tokfd.rs
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
use std::os::fd::RawFd;
|
||||||
|
|
||||||
|
use iddqd::BiHashItem;
|
||||||
|
use mio::Token;
|
||||||
|
|
||||||
|
#[derive(Copy)]
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
|
pub struct TokenFd {
|
||||||
|
pub token: Token,
|
||||||
|
pub fd: RawFd,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BiHashItem for TokenFd {
|
||||||
|
type K1<'a> = Token;
|
||||||
|
type K2<'a> = RawFd;
|
||||||
|
|
||||||
|
fn key1(&self) -> Token {
|
||||||
|
self.token
|
||||||
|
}
|
||||||
|
|
||||||
|
fn key2(&self) -> RawFd {
|
||||||
|
self.fd
|
||||||
|
}
|
||||||
|
|
||||||
|
iddqd::bi_upcast!();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<TokenFd> for (Token, RawFd) {
|
||||||
|
fn from(TokenFd { token, fd }: TokenFd) -> (Token, RawFd) {
|
||||||
|
(token, fd)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<(Token, RawFd)> for TokenFd {
|
||||||
|
fn from((token, fd): (Token, RawFd)) -> TokenFd {
|
||||||
|
TokenFd { token, fd }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -53,6 +53,8 @@ mod daemon;
|
||||||
pub use daemon::Daemon;
|
pub use daemon::Daemon;
|
||||||
mod daemon_io;
|
mod daemon_io;
|
||||||
pub use daemon_io::OwnedFdWithFlags;
|
pub use daemon_io::OwnedFdWithFlags;
|
||||||
|
mod daemon_tokfd;
|
||||||
|
pub(crate) use daemon_tokfd::TokenFd;
|
||||||
pub mod line;
|
pub mod line;
|
||||||
pub use line::Line;
|
pub use line::Line;
|
||||||
mod nixcmd;
|
mod nixcmd;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue