mirror of
https://github.com/edera-dev/krata.git
synced 2025-08-02 12:50:54 +00:00
krata: restructure packages for cleanliness
This commit is contained in:
parent
da9e6cac14
commit
bdb91a6cb3
16
Cargo.toml
16
Cargo.toml
@ -1,14 +1,12 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"crates/krata",
|
||||
"crates/krataoci",
|
||||
"crates/krataguest",
|
||||
"crates/kratart",
|
||||
"crates/kratad",
|
||||
"crates/kratanet",
|
||||
"crates/kratactl",
|
||||
"crates/vendor/advmac",
|
||||
"crates/vendor/loopdev",
|
||||
"crates/oci",
|
||||
"crates/guest",
|
||||
"crates/runtime",
|
||||
"crates/daemon",
|
||||
"crates/network",
|
||||
"crates/ctl",
|
||||
"crates/xen/xencall",
|
||||
"crates/xen/xenclient",
|
||||
"crates/xen/xenevtchn",
|
||||
@ -21,6 +19,7 @@ resolver = "2"
|
||||
version = "0.0.1"
|
||||
|
||||
[workspace.dependencies]
|
||||
advmac = "1.0.3"
|
||||
anyhow = "1.0"
|
||||
arrayvec = "0.7.4"
|
||||
async-compression = "0.4.6"
|
||||
@ -40,6 +39,7 @@ futures = "0.3.30"
|
||||
ipnetwork = "0.20.0"
|
||||
libc = "0.2"
|
||||
log = "0.4.20"
|
||||
loopdev-3 = "0.5.1"
|
||||
memchr = "2"
|
||||
nix = "0.28.0"
|
||||
oci-spec = "0.6.4"
|
||||
|
8
DEV.md
8
DEV.md
@ -6,10 +6,10 @@ krata is composed of four major executables:
|
||||
|
||||
| Executable | Runs On | User Interaction | Dev Runner | Code Path |
|
||||
| ---------- | ------- | ---------------- | ------------------------ | ----------------- |
|
||||
| kratad | host | backend daemon | ./hack/debug/kratad.sh | crates/kratad |
|
||||
| kratanet | host | backend daemon | ./hack/debug/kratanet.sh | crates/kratanet |
|
||||
| kratactl | host | CLI tool | ./hack/debug/kratactl.sh | crates/kratactl |
|
||||
| krataguest | guest | none, guest init | N/A | crates/krataguest |
|
||||
| kratad | host | backend daemon | ./hack/debug/kratad.sh | crates/daemon |
|
||||
| kratanet | host | backend daemon | ./hack/debug/kratanet.sh | crates/network |
|
||||
| kratactl | host | CLI tool | ./hack/debug/kratactl.sh | crates/ctl |
|
||||
| krataguest | guest | none, guest init | N/A | crates/guest |
|
||||
|
||||
You will find the code to each executable available in the bin/ and src/ directories inside
|
||||
it's corresponding code path from the above table.
|
||||
|
14
LICENSING.md
14
LICENSING.md
@ -1,14 +0,0 @@
|
||||
# Licensing Guide
|
||||
|
||||
## Krata License
|
||||
|
||||
This repository is licensed under Apache License 2.0, except where noted in this document.
|
||||
|
||||
## Licensing Exceptions
|
||||
|
||||
As noted in the table below, some code in this repository is licensed under different terms:
|
||||
|
||||
| Vendored Path | Source Repository | License |
|
||||
| --------------------- | -------------------------------------------- | -------- |
|
||||
| crates/vendor/advmac | https://github.com/GamePad64/advmac | MIT |
|
||||
| crates/vendor/loopdev | https://github.com/stratis-storage/loopdev-3 | MIT |
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "kratactl"
|
||||
name = "krata-ctl"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "kratad"
|
||||
name = "krata-daemon"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
@ -13,7 +13,7 @@ clap = { workspace = true }
|
||||
env_logger = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
krata = { path = "../krata" }
|
||||
kratart = { path = "../kratart" }
|
||||
krata-runtime = { path = "../runtime" }
|
||||
log = { workspace = true }
|
||||
prost = { workspace = true }
|
||||
redb = { workspace = true }
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "krataguest"
|
||||
name = "krata-guest"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
@ -10,6 +10,7 @@ env_logger = { workspace = true }
|
||||
futures = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
krata = { path = "../krata" }
|
||||
krata-xenstore = { path = "../xen/xenstore" }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
nix = { workspace = true, features = ["process"] }
|
||||
@ -21,7 +22,6 @@ serde_json = { workspace = true }
|
||||
sys-mount = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
walkdir = { workspace = true }
|
||||
xenstore = { path = "../xen/xenstore" }
|
||||
|
||||
[lib]
|
||||
name = "krataguest"
|
@ -1,11 +1,11 @@
|
||||
[package]
|
||||
name = "kratanet"
|
||||
name = "krata-network"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
advmac = { path = "../vendor/advmac" }
|
||||
advmac = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
async-trait = { workspace = true }
|
||||
bytes = { workspace = true }
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "krataoci"
|
||||
name = "krata-oci"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
@ -1,25 +1,25 @@
|
||||
[package]
|
||||
name = "kratart"
|
||||
name = "krata-runtime"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
||||
[dependencies]
|
||||
advmac = { path = "../vendor/advmac" }
|
||||
advmac = { workspace = true }
|
||||
anyhow = { workspace = true }
|
||||
backhand = { workspace = true }
|
||||
ipnetwork = { workspace = true }
|
||||
krata = { path = "../krata" }
|
||||
krataoci = { path = "../krataoci" }
|
||||
krata-oci = { path = "../oci" }
|
||||
log = { workspace = true }
|
||||
loopdev = { path = "../vendor/loopdev" }
|
||||
loopdev-3 = { workspace = true }
|
||||
serde_json = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
xenclient = { path = "../xen/xenclient" }
|
||||
xenevtchn = { path = "../xen/xenevtchn" }
|
||||
xengnt = { path = "../xen/xengnt" }
|
||||
xenstore = { path = "../xen/xenstore" }
|
||||
krata-xenclient = { path = "../xen/xenclient" }
|
||||
krata-xenevtchn = { path = "../xen/xenevtchn" }
|
||||
krata-xengnt = { path = "../xen/xengnt" }
|
||||
krata-xenstore = { path = "../xen/xenstore" }
|
||||
|
||||
[lib]
|
||||
name = "kratart"
|
15
crates/vendor/advmac/Cargo.toml
vendored
15
crates/vendor/advmac/Cargo.toml
vendored
@ -1,15 +0,0 @@
|
||||
# This package is from https://github.com/GamePad64/advmac
|
||||
# Edera maintains an in-tree version because of dependencies being out of date.
|
||||
[package]
|
||||
name = "advmac"
|
||||
version.workspace = true
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
arrayvec = { workspace = true, features = ["serde"] }
|
||||
rand = { workspace = true }
|
||||
serde = { workspace = true }
|
||||
|
||||
[lib]
|
||||
name = "advmac"
|
21
crates/vendor/advmac/LICENSE
vendored
21
crates/vendor/advmac/LICENSE
vendored
@ -1,21 +0,0 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2022 Alexander Shishenko
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
474
crates/vendor/advmac/src/lib.rs
vendored
474
crates/vendor/advmac/src/lib.rs
vendored
@ -1,474 +0,0 @@
|
||||
mod parser;
|
||||
|
||||
use arrayvec::ArrayString;
|
||||
use core::fmt::{self, Debug, Display, Formatter};
|
||||
use core::str::FromStr;
|
||||
use rand::Rng;
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||
pub enum ParseError {
|
||||
InvalidMac,
|
||||
InvalidLength { length: usize },
|
||||
}
|
||||
|
||||
impl Display for ParseError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::InvalidMac => write!(f, "invalid MAC address"),
|
||||
Self::InvalidLength { length } => write!(f, "invalid string length: {}", length),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for ParseError {}
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone, Copy)]
|
||||
pub enum IpError {
|
||||
NotLinkLocal,
|
||||
NotMulticast,
|
||||
}
|
||||
|
||||
impl Display for IpError {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
match self {
|
||||
Self::NotLinkLocal => write!(f, "not link-local address"),
|
||||
Self::NotMulticast => write!(f, "not multicast address"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl std::error::Error for IpError {}
|
||||
|
||||
/// Maximum formatted size.
|
||||
///
|
||||
/// It is useful for creating a stack-allocated buffer `[u8; MAC_MAX_SIZE]`
|
||||
/// and formatting address into it using [MacAddr6::format_write] or [MacAddr8::format_write].
|
||||
pub const MAC_MAX_SIZE: usize = 23;
|
||||
/// Size of formatted MAC using [MacAddr6::format_string] and [MacAddrFormat::Canonical].
|
||||
pub const MAC_CANONICAL_SIZE6: usize = 17;
|
||||
/// Size of formatted MAC using [MacAddr8::format_string] and [MacAddrFormat::Canonical].
|
||||
pub const MAC_CANONICAL_SIZE8: usize = 23;
|
||||
/// Size of formatted MAC using [MacAddr6::format_string] and [MacAddrFormat::ColonNotation].
|
||||
pub const MAC_COLON_NOTATION_SIZE6: usize = 17;
|
||||
/// Size of formatted MAC using [MacAddr8::format_string] and [MacAddrFormat::ColonNotation].
|
||||
pub const MAC_COLON_NOTATION_SIZE8: usize = 23;
|
||||
/// Size of formatted MAC using [MacAddr6::format_string] and [MacAddrFormat::DotNotation].
|
||||
pub const MAC_DOT_NOTATION_SIZE6: usize = 14;
|
||||
/// Size of formatted MAC using [MacAddr8::format_string] and [MacAddrFormat::DotNotation].
|
||||
pub const MAC_DOT_NOTATION_SIZE8: usize = 19;
|
||||
/// Size of formatted MAC using [MacAddr6::format_string] and [MacAddrFormat::Hexadecimal].
|
||||
pub const MAC_HEXADECIMAL_SIZE6: usize = 12;
|
||||
/// Size of formatted MAC using [MacAddr8::format_string] and [MacAddrFormat::Hexadecimal].
|
||||
pub const MAC_HEXADECIMAL_SIZE8: usize = 16;
|
||||
/// Size of formatted MAC using [MacAddr6::format_string] and [MacAddrFormat::Hexadecimal0x].
|
||||
pub const MAC_HEXADECIMAL0X_SIZE6: usize = 14;
|
||||
/// Size of formatted MAC using [MacAddr8::format_string] and [MacAddrFormat::Hexadecimal0x].
|
||||
pub const MAC_HEXADECIMAL0X_SIZE8: usize = 18;
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq)]
|
||||
pub enum MacAddrFormat {
|
||||
/// `AA-BB-CC-DD-EE-FF` (17 bytes) or `AA-BB-CC-DD-EE-FF-GG-HH` (23 bytes)
|
||||
Canonical,
|
||||
/// `AA:BB:CC:DD:EE:FF` (17 bytes) or `AA:BB:CC:DD:EE:FF:GG:HH` (23 bytes)
|
||||
ColonNotation,
|
||||
/// `AABB.CCDD.EEFF` (14 bytes) or `AABB.CCDD.EEFF.GGHH` (19 bytes)
|
||||
DotNotation,
|
||||
/// `AABBCCDDEEFF` (12 bytes) or `AABBCCDDEEFFGGHH` (16 bytes)
|
||||
Hexadecimal,
|
||||
/// `0xAABBCCDDEEFF` (14 bytes) or `0xAABBCCDDEEFFGGHH` (18 bytes)
|
||||
Hexadecimal0x,
|
||||
}
|
||||
|
||||
macro_rules! mac_impl {
|
||||
($nm:ident, $sz:literal, $hex_sz:literal) => {
|
||||
impl $nm {
|
||||
pub const fn new(eui: [u8; $sz]) -> Self {
|
||||
Self(eui)
|
||||
}
|
||||
|
||||
pub fn random() -> Self {
|
||||
let mut result = Self::default();
|
||||
rand::rngs::OsRng.fill(result.as_mut_slice());
|
||||
result
|
||||
}
|
||||
|
||||
pub const fn broadcast() -> Self {
|
||||
Self([0xFF; $sz])
|
||||
}
|
||||
|
||||
pub const fn nil() -> Self {
|
||||
Self([0; $sz])
|
||||
}
|
||||
|
||||
/// Sets *locally administered* flag
|
||||
pub fn set_local(&mut self, v: bool) {
|
||||
if v {
|
||||
self.0[0] |= 0b0000_0010;
|
||||
} else {
|
||||
self.0[0] &= !0b0000_0010;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the state of *locally administered* flag
|
||||
pub const fn is_local(&self) -> bool {
|
||||
(self.0[0] & 0b0000_0010) != 0
|
||||
}
|
||||
|
||||
/// Sets *multicast* flag
|
||||
pub fn set_multicast(&mut self, v: bool) {
|
||||
if v {
|
||||
self.0[0] |= 0b0000_0001;
|
||||
} else {
|
||||
self.0[0] &= !0b0000_0001;
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the state of *multicast* flag
|
||||
pub const fn is_multicast(&self) -> bool {
|
||||
(self.0[0] & 0b0000_0001) != 0
|
||||
}
|
||||
|
||||
/// Returns [organizationally unique identifier (OUI)](https://en.wikipedia.org/wiki/Organizationally_unique_identifier) of this MAC address
|
||||
pub const fn oui(&self) -> [u8; 3] {
|
||||
[self.0[0], self.0[1], self.0[2]]
|
||||
}
|
||||
|
||||
/// Sets [organizationally unique identifier (OUI)](https://en.wikipedia.org/wiki/Organizationally_unique_identifier) for this MAC address
|
||||
pub fn set_oui(&mut self, oui: [u8; 3]) {
|
||||
self.0[..3].copy_from_slice(&oui);
|
||||
}
|
||||
|
||||
/// Returns internal array representation for this MAC address, consuming it
|
||||
pub const fn to_array(self) -> [u8; $sz] {
|
||||
self.0
|
||||
}
|
||||
|
||||
/// Returns internal array representation for this MAC address as [u8] slice
|
||||
pub const fn as_slice(&self) -> &[u8] {
|
||||
&self.0
|
||||
}
|
||||
|
||||
/// Returns internal array representation for this MAC address as mutable [u8] slice
|
||||
pub fn as_mut_slice(&mut self) -> &mut [u8] {
|
||||
&mut self.0
|
||||
}
|
||||
|
||||
/// Returns internal array representation for this MAC address as [core::ffi::c_char] slice.
|
||||
/// This can be useful in parsing `ifr_hwaddr`, for example.
|
||||
pub const fn as_c_slice(&self) -> &[core::ffi::c_char] {
|
||||
unsafe { &*(self.as_slice() as *const _ as *const [core::ffi::c_char]) }
|
||||
}
|
||||
|
||||
/// Parse MAC address from string and return it as `MacAddr`.
|
||||
/// This function can be used in const context, so MAC address can be parsed in compile-time.
|
||||
pub const fn parse_str(s: &str) -> Result<Self, ParseError> {
|
||||
match parser::MacParser::<$sz, $hex_sz>::parse(s) {
|
||||
Ok(v) => Ok(Self(v)),
|
||||
Err(e) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write MAC address to `impl core::fmt::Write`, which can be used in `no_std` environments.
|
||||
///
|
||||
/// It can be used like this with [arrayvec::ArrayString] without allocations:
|
||||
/// ```
|
||||
/// use arrayvec::ArrayString;
|
||||
/// use advmac::{MacAddr6, MacAddrFormat, MAC_CANONICAL_SIZE6};
|
||||
///
|
||||
/// let mac = MacAddr6::parse_str("AA:BB:CC:DD:EE:FF").unwrap();
|
||||
///
|
||||
/// let mut buf = ArrayString::<MAC_CANONICAL_SIZE6>::new();
|
||||
/// mac.format_write(&mut buf, MacAddrFormat::Canonical).unwrap();
|
||||
/// # assert_eq!(buf.as_str(), "AA-BB-CC-DD-EE-FF")
|
||||
/// ```
|
||||
pub fn format_write<T: fmt::Write>(
|
||||
&self,
|
||||
f: &mut T,
|
||||
format: MacAddrFormat,
|
||||
) -> fmt::Result {
|
||||
match format {
|
||||
MacAddrFormat::Canonical => self.write_internal(f, "", "-", "-"),
|
||||
MacAddrFormat::ColonNotation => self.write_internal(f, "", ":", ":"),
|
||||
MacAddrFormat::DotNotation => self.write_internal(f, "", "", "."),
|
||||
MacAddrFormat::Hexadecimal => self.write_internal(f, "", "", ""),
|
||||
MacAddrFormat::Hexadecimal0x => self.write_internal(f, "0x", "", ""),
|
||||
}
|
||||
}
|
||||
|
||||
/// Write MAC address to [String]. This function uses [Self::format_write] internally and
|
||||
/// produces the same result, but in string form, which can be convenient in non-constrainted
|
||||
/// environments.
|
||||
|
||||
pub fn format_string(&self, format: MacAddrFormat) -> String {
|
||||
let mut buf = String::new();
|
||||
self.format_write(&mut buf, format).unwrap();
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for $nm {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.format_write(f, MacAddrFormat::Canonical)
|
||||
}
|
||||
}
|
||||
|
||||
impl Debug for $nm {
|
||||
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||
self.format_write(f, MacAddrFormat::Canonical)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<[u8; $sz]> for $nm {
|
||||
fn from(arr: [u8; $sz]) -> Self {
|
||||
Self(arr)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&[u8]> for $nm {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
|
||||
Ok(Self(value.try_into().map_err(|_| ParseError::InvalidMac)?))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(target_arch = "aarch64"))]
|
||||
impl TryFrom<&[core::ffi::c_char]> for $nm {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: &[core::ffi::c_char]) -> Result<Self, Self::Error> {
|
||||
Self::try_from(unsafe { &*(value as *const _ as *const [u8]) })
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for $nm {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: &str) -> Result<Self, Self::Error> {
|
||||
Self::parse_str(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<String> for $nm {
|
||||
type Error = ParseError;
|
||||
|
||||
fn try_from(value: String) -> Result<Self, Self::Error> {
|
||||
Self::parse_str(&value)
|
||||
}
|
||||
}
|
||||
|
||||
impl FromStr for $nm {
|
||||
type Err = ParseError;
|
||||
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
Self::parse_str(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl Serialize for $nm {
|
||||
fn serialize<S: Serializer>(&self, s: S) -> Result<S::Ok, S::Error> {
|
||||
let mut buf = ArrayString::<MAC_MAX_SIZE>::new();
|
||||
self.format_write(&mut buf, MacAddrFormat::Canonical)
|
||||
.unwrap();
|
||||
s.serialize_str(buf.as_ref())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for $nm {
|
||||
fn deserialize<D: Deserializer<'de>>(d: D) -> Result<Self, D::Error> {
|
||||
Self::from_str(ArrayString::<MAC_MAX_SIZE>::deserialize(d)?.as_ref())
|
||||
.map_err(serde::de::Error::custom)
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// MAC address, represented as EUI-48
|
||||
#[repr(transparent)]
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct MacAddr6([u8; 6]);
|
||||
/// MAC address, represented as EUI-64
|
||||
#[repr(transparent)]
|
||||
#[derive(Default, Copy, Clone, Eq, PartialEq, Hash, Ord, PartialOrd)]
|
||||
pub struct MacAddr8([u8; 8]);
|
||||
|
||||
mac_impl!(MacAddr6, 6, 12);
|
||||
mac_impl!(MacAddr8, 8, 16);
|
||||
|
||||
impl MacAddr6 {
|
||||
pub const fn to_modified_eui64(self) -> MacAddr8 {
|
||||
let b = self.to_array();
|
||||
MacAddr8([b[0] ^ 0b00000010, b[1], b[2], 0xFF, 0xFE, b[3], b[4], b[5]])
|
||||
}
|
||||
|
||||
pub const fn try_from_modified_eui64(eui64: MacAddr8) -> Result<Self, IpError> {
|
||||
let b = eui64.to_array();
|
||||
if (b[3] == 0xFF) | (b[4] == 0xFE) {
|
||||
Ok(Self([b[0] ^ 0b00000010, b[1], b[2], b[5], b[6], b[7]]))
|
||||
} else {
|
||||
Err(IpError::NotLinkLocal)
|
||||
}
|
||||
}
|
||||
|
||||
pub const fn to_link_local_ipv6(self) -> Ipv6Addr {
|
||||
let mac64 = self.to_modified_eui64().to_array();
|
||||
|
||||
Ipv6Addr::new(
|
||||
0xFE80,
|
||||
0x0000,
|
||||
0x0000,
|
||||
0x0000,
|
||||
((mac64[0] as u16) << 8) + mac64[1] as u16,
|
||||
((mac64[2] as u16) << 8) + mac64[3] as u16,
|
||||
((mac64[4] as u16) << 8) + mac64[5] as u16,
|
||||
((mac64[6] as u16) << 8) + mac64[7] as u16,
|
||||
)
|
||||
}
|
||||
|
||||
pub const fn try_from_link_local_ipv6(ip: Ipv6Addr) -> Result<Self, IpError> {
|
||||
let octets = ip.octets();
|
||||
if (octets[0] != 0xFE)
|
||||
| (octets[1] != 0x80)
|
||||
| (octets[2] != 0x00)
|
||||
| (octets[3] != 0x00)
|
||||
| (octets[4] != 0x00)
|
||||
| (octets[5] != 0x00)
|
||||
| (octets[6] != 0x00)
|
||||
| (octets[7] != 0x00)
|
||||
| (octets[11] != 0xFF)
|
||||
| (octets[12] != 0xFE)
|
||||
{
|
||||
return Err(IpError::NotLinkLocal);
|
||||
}
|
||||
|
||||
Ok(Self([
|
||||
octets[8] ^ 0b00000010,
|
||||
octets[9],
|
||||
octets[10],
|
||||
octets[13],
|
||||
octets[14],
|
||||
octets[15],
|
||||
]))
|
||||
}
|
||||
|
||||
pub const fn try_from_multicast_ipv4(ip: Ipv4Addr) -> Result<Self, IpError> {
|
||||
if !ip.is_multicast() {
|
||||
return Err(IpError::NotMulticast);
|
||||
}
|
||||
let b = ip.octets();
|
||||
Ok(Self::new([0x01, 0x00, 0x5E, b[1] & 0x7F, b[2], b[3]]))
|
||||
}
|
||||
|
||||
pub const fn try_from_multicast_ipv6(ip: Ipv6Addr) -> Result<Self, IpError> {
|
||||
if !ip.is_multicast() {
|
||||
return Err(IpError::NotMulticast);
|
||||
}
|
||||
let b = ip.octets();
|
||||
Ok(Self::new([0x33, 0x33, b[12], b[13], b[14], b[15]]))
|
||||
}
|
||||
|
||||
pub const fn try_from_multicast_ip(ip: IpAddr) -> Result<Self, IpError> {
|
||||
match ip {
|
||||
IpAddr::V4(ip) => Self::try_from_multicast_ipv4(ip),
|
||||
IpAddr::V6(ip) => Self::try_from_multicast_ipv6(ip),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MacAddr6 {
|
||||
// String representations
|
||||
fn write_internal<T: fmt::Write>(
|
||||
&self,
|
||||
f: &mut T,
|
||||
pre: &str,
|
||||
sep: &str,
|
||||
sep2: &str,
|
||||
) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{pre}{:02X}{sep}{:02X}{sep2}{:02X}{sep}{:02X}{sep2}{:02X}{sep}{:02X}",
|
||||
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl MacAddr8 {
|
||||
// String representations
|
||||
fn write_internal<T: fmt::Write>(
|
||||
&self,
|
||||
f: &mut T,
|
||||
pre: &str,
|
||||
sep: &str,
|
||||
sep2: &str,
|
||||
) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"{pre}{:02X}{sep}{:02X}{sep2}{:02X}{sep}{:02X}{sep2}{:02X}{sep}{:02X}{sep2}{:02X}{sep}{:02X}",
|
||||
self.0[0], self.0[1], self.0[2], self.0[3], self.0[4], self.0[5], self.0[6], self.0[7]
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
/// Convenience macro for creating [MacAddr6] in compile-time.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use advmac::{mac6, MacAddr6};
|
||||
/// const MAC6: MacAddr6 = mac6!("11:22:33:44:55:66");
|
||||
/// # assert_eq!(MAC6.to_array(), [0x11, 0x22, 0x33, 0x44, 0x55, 0x66]);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! mac6 {
|
||||
($s:expr) => {
|
||||
match $crate::MacAddr6::parse_str($s) {
|
||||
Ok(mac) => mac,
|
||||
Err(_) => panic!("Invalid MAC address"),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Convenience macro for creating [MacAddr8] in compile-time.
|
||||
///
|
||||
/// Example:
|
||||
/// ```
|
||||
/// use advmac::{mac8, MacAddr8};
|
||||
/// const MAC8: MacAddr8 = mac8!("11:22:33:44:55:66:77:88");
|
||||
/// # assert_eq!(MAC8.to_array(), [0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88]);
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! mac8 {
|
||||
($s:expr) => {
|
||||
match $crate::MacAddr8::parse_str($s) {
|
||||
Ok(mac) => mac,
|
||||
Err(_) => panic!("Invalid MAC address"),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
#[test]
|
||||
fn test_flags_roundtrip() {
|
||||
let mut addr = mac6!("50:74:f2:b1:a8:7f");
|
||||
assert!(!addr.is_local());
|
||||
assert!(!addr.is_multicast());
|
||||
|
||||
addr.set_multicast(true);
|
||||
assert!(!addr.is_local());
|
||||
assert!(addr.is_multicast());
|
||||
|
||||
addr.set_local(true);
|
||||
assert!(addr.is_local());
|
||||
assert!(addr.is_multicast());
|
||||
|
||||
addr.set_multicast(false);
|
||||
assert!(addr.is_local());
|
||||
assert!(!addr.is_multicast());
|
||||
|
||||
addr.set_local(false);
|
||||
assert!(!addr.is_local());
|
||||
assert!(!addr.is_multicast());
|
||||
}
|
||||
}
|
113
crates/vendor/advmac/src/parser.rs
vendored
113
crates/vendor/advmac/src/parser.rs
vendored
@ -1,113 +0,0 @@
|
||||
use crate::ParseError;
|
||||
|
||||
// This whole thing is written this way to be const.
|
||||
// If you want normal hex handling, just use hex crate
|
||||
pub struct MacParser<const N: usize, const N2: usize>;
|
||||
|
||||
impl<const N: usize, const N2: usize> MacParser<N, N2> {
|
||||
const CANONICAL_COLON_SIZE: usize = 3 * N - 1;
|
||||
const DOT_NOTATION_SIZE: usize = (2 * N) + (N / 2 - 1);
|
||||
const HEXADECIMAL_SIZE: usize = 2 * N;
|
||||
const HEXADECIMAL0X_SIZE: usize = 2 * N + 2;
|
||||
|
||||
#[inline]
|
||||
const fn nibble(v: u8) -> Result<u8, ParseError> {
|
||||
match v {
|
||||
b'A'..=b'F' => Ok(10 + (v - b'A')),
|
||||
b'a'..=b'f' => Ok(10 + (v - b'a')),
|
||||
b'0'..=b'9' => Ok(v - b'0'),
|
||||
_ => Err(ParseError::InvalidMac),
|
||||
}
|
||||
}
|
||||
|
||||
#[inline]
|
||||
const fn byte(b1: u8, b2: u8) -> Result<u8, ParseError> {
|
||||
// ? is not available in const
|
||||
match (Self::nibble(b1), Self::nibble(b2)) {
|
||||
(Ok(v1), Ok(v2)) => Ok((v1 << 4) + v2),
|
||||
(Err(e), _) | (_, Err(e)) => Err(e),
|
||||
}
|
||||
}
|
||||
|
||||
const fn from_hex(s: &[u8]) -> Result<[u8; N], ParseError> {
|
||||
if s.len() != Self::HEXADECIMAL_SIZE {
|
||||
return Err(ParseError::InvalidLength { length: s.len() });
|
||||
}
|
||||
|
||||
let mut result = [0u8; N];
|
||||
|
||||
// for-loops and iterators are unavailable in const
|
||||
let mut i = 0;
|
||||
while i < N {
|
||||
result[i] = match Self::byte(s[2 * i], s[2 * i + 1]) {
|
||||
Ok(v) => v,
|
||||
Err(e) => return Err(e),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
const fn check_separator(s: &[u8], sep: u8, group_len: usize) -> bool {
|
||||
let mut i = group_len;
|
||||
while i < s.len() {
|
||||
if s[i] != sep {
|
||||
return false;
|
||||
}
|
||||
i += group_len + 1;
|
||||
}
|
||||
true
|
||||
}
|
||||
|
||||
const fn parse_separated(s: &[u8], sep: u8, group_len: usize) -> Result<[u8; N], ParseError> {
|
||||
let expected_len = (2 * N) + ((2 * N) / group_len) - 1;
|
||||
if s.len() != expected_len {
|
||||
return Err(ParseError::InvalidLength { length: s.len() });
|
||||
}
|
||||
|
||||
if !Self::check_separator(s, sep, group_len) {
|
||||
return Err(ParseError::InvalidMac);
|
||||
}
|
||||
|
||||
let mut hex_buf = [0u8; N2];
|
||||
|
||||
let (mut in_i, mut out_i) = (0, 0);
|
||||
while in_i < s.len() {
|
||||
if (in_i + 1) % (group_len + 1) != 0 {
|
||||
hex_buf[out_i] = s[in_i];
|
||||
out_i += 1;
|
||||
}
|
||||
in_i += 1;
|
||||
}
|
||||
|
||||
Self::from_hex(&hex_buf)
|
||||
}
|
||||
|
||||
pub const fn parse(s: &str) -> Result<[u8; N], ParseError> {
|
||||
let s = s.as_bytes();
|
||||
|
||||
if s.len() == Self::HEXADECIMAL_SIZE {
|
||||
Self::from_hex(s)
|
||||
} else if (s.len() == Self::HEXADECIMAL0X_SIZE) && (s[0] == b'0') && (s[1] == b'x') {
|
||||
// unsafe is the only way I know to make it const
|
||||
Self::from_hex(unsafe {
|
||||
core::slice::from_raw_parts(s.as_ptr().offset(2), s.len() - 2)
|
||||
})
|
||||
} else if s.len() == Self::CANONICAL_COLON_SIZE {
|
||||
let sep = s[2];
|
||||
match sep {
|
||||
b'-' | b':' => Self::parse_separated(s, sep, 2),
|
||||
_ => Err(ParseError::InvalidMac),
|
||||
}
|
||||
} else if s.len() == Self::DOT_NOTATION_SIZE {
|
||||
let sep = s[4];
|
||||
match sep {
|
||||
b'.' => Self::parse_separated(s, sep, 4),
|
||||
_ => Err(ParseError::InvalidMac),
|
||||
}
|
||||
} else {
|
||||
Err(ParseError::InvalidLength { length: s.len() })
|
||||
}
|
||||
}
|
||||
}
|
15
crates/vendor/loopdev/Cargo.toml
vendored
15
crates/vendor/loopdev/Cargo.toml
vendored
@ -1,15 +0,0 @@
|
||||
# This package is from https://github.com/stratis-storage/loopdev-3
|
||||
# Edera maintains an in-tree version because the goals of krata mean that
|
||||
# there is as little binding generation as possible, especially bindings which
|
||||
# prevent development from macOS, like the original library.
|
||||
[package]
|
||||
name = "loopdev"
|
||||
version.workspace = true
|
||||
license = "MIT"
|
||||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
libc = { workspace = true }
|
||||
|
||||
[lib]
|
||||
name = "loopdev"
|
21
crates/vendor/loopdev/LICENSE
vendored
21
crates/vendor/loopdev/LICENSE
vendored
@ -1,21 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2023 Anne Mulhern
|
||||
Copyright (c) 2016 Michael Daffin
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
this software and associated documentation files (the "Software"), to deal in
|
||||
the Software without restriction, including without limitation the rights to
|
||||
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
|
||||
the Software, and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
|
||||
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
|
||||
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
|
||||
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
147
crates/vendor/loopdev/src/bindings.rs
vendored
147
crates/vendor/loopdev/src/bindings.rs
vendored
@ -1,147 +0,0 @@
|
||||
/* originally generated by rust-bindgen */
|
||||
/* modified to remove unused content by Edera */
|
||||
#![allow(non_camel_case_types)]
|
||||
|
||||
pub const __BITS_PER_LONG: u32 = 64;
|
||||
pub const __FD_SETSIZE: u32 = 1024;
|
||||
pub const LOOP_SET_FD: u32 = 19456;
|
||||
pub const LOOP_CLR_FD: u32 = 19457;
|
||||
pub const LOOP_SET_STATUS64: u32 = 19460;
|
||||
pub const LOOP_SET_CAPACITY: u32 = 19463;
|
||||
pub const LOOP_CTL_ADD: u32 = 19584;
|
||||
pub const LOOP_CTL_GET_FREE: u32 = 19586;
|
||||
pub const LO_FLAGS_READ_ONLY: _bindgen_ty_1 = 1;
|
||||
pub const LO_FLAGS_AUTOCLEAR: _bindgen_ty_1 = 4;
|
||||
pub const LO_FLAGS_PARTSCAN: _bindgen_ty_1 = 8;
|
||||
pub type _bindgen_ty_1 = ::std::os::raw::c_uint;
|
||||
pub type __kernel_old_uid_t = ::std::os::raw::c_ushort;
|
||||
pub type __kernel_old_gid_t = ::std::os::raw::c_ushort;
|
||||
pub type __kernel_old_dev_t = ::std::os::raw::c_ulong;
|
||||
pub type __kernel_long_t = ::std::os::raw::c_long;
|
||||
pub type __kernel_ulong_t = ::std::os::raw::c_ulong;
|
||||
pub type __kernel_ino_t = __kernel_ulong_t;
|
||||
pub type __kernel_mode_t = ::std::os::raw::c_uint;
|
||||
pub type __kernel_pid_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_ipc_pid_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_uid_t = ::std::os::raw::c_uint;
|
||||
pub type __kernel_gid_t = ::std::os::raw::c_uint;
|
||||
pub type __kernel_suseconds_t = __kernel_long_t;
|
||||
pub type __kernel_daddr_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_uid32_t = ::std::os::raw::c_uint;
|
||||
pub type __kernel_gid32_t = ::std::os::raw::c_uint;
|
||||
pub type __kernel_size_t = __kernel_ulong_t;
|
||||
pub type __kernel_ssize_t = __kernel_long_t;
|
||||
pub type __kernel_ptrdiff_t = __kernel_long_t;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct __kernel_fsid_t {
|
||||
pub val: [::std::os::raw::c_int; 2usize],
|
||||
}
|
||||
pub type __kernel_off_t = __kernel_long_t;
|
||||
pub type __kernel_loff_t = ::std::os::raw::c_longlong;
|
||||
pub type __kernel_old_time_t = __kernel_long_t;
|
||||
pub type __kernel_time_t = __kernel_long_t;
|
||||
pub type __kernel_time64_t = ::std::os::raw::c_longlong;
|
||||
pub type __kernel_clock_t = __kernel_long_t;
|
||||
pub type __kernel_timer_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_clockid_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_caddr_t = *mut ::std::os::raw::c_char;
|
||||
pub type __kernel_uid16_t = ::std::os::raw::c_ushort;
|
||||
pub type __kernel_gid16_t = ::std::os::raw::c_ushort;
|
||||
pub type __s8 = ::std::os::raw::c_schar;
|
||||
pub type __u8 = ::std::os::raw::c_uchar;
|
||||
pub type __s16 = ::std::os::raw::c_short;
|
||||
pub type __u16 = ::std::os::raw::c_ushort;
|
||||
pub type __s32 = ::std::os::raw::c_int;
|
||||
pub type __u32 = ::std::os::raw::c_uint;
|
||||
pub type __s64 = ::std::os::raw::c_longlong;
|
||||
pub type __u64 = ::std::os::raw::c_ulonglong;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Default, Copy, Clone)]
|
||||
pub struct __kernel_fd_set {
|
||||
pub fds_bits: [::std::os::raw::c_ulong; 16usize],
|
||||
}
|
||||
|
||||
pub type __kernel_sighandler_t = Option<unsafe extern "C" fn(arg1: ::std::os::raw::c_int)>;
|
||||
pub type __kernel_key_t = ::std::os::raw::c_int;
|
||||
pub type __kernel_mqd_t = ::std::os::raw::c_int;
|
||||
pub type __le16 = __u16;
|
||||
pub type __be16 = __u16;
|
||||
pub type __le32 = __u32;
|
||||
pub type __be32 = __u32;
|
||||
pub type __le64 = __u64;
|
||||
pub type __be64 = __u64;
|
||||
pub type __sum16 = __u16;
|
||||
pub type __wsum = __u32;
|
||||
pub type __poll_t = ::std::os::raw::c_uint;
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct loop_info {
|
||||
pub lo_number: ::std::os::raw::c_int,
|
||||
pub lo_device: __kernel_old_dev_t,
|
||||
pub lo_inode: ::std::os::raw::c_ulong,
|
||||
pub lo_rdevice: __kernel_old_dev_t,
|
||||
pub lo_offset: ::std::os::raw::c_int,
|
||||
pub lo_encrypt_type: ::std::os::raw::c_int,
|
||||
pub lo_encrypt_key_size: ::std::os::raw::c_int,
|
||||
pub lo_flags: ::std::os::raw::c_int,
|
||||
pub lo_name: [::std::os::raw::c_char; 64usize],
|
||||
pub lo_encrypt_key: [::std::os::raw::c_uchar; 32usize],
|
||||
pub lo_init: [::std::os::raw::c_ulong; 2usize],
|
||||
pub reserved: [::std::os::raw::c_char; 4usize],
|
||||
}
|
||||
|
||||
impl Default for loop_info {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct loop_info64 {
|
||||
pub lo_device: __u64,
|
||||
pub lo_inode: __u64,
|
||||
pub lo_rdevice: __u64,
|
||||
pub lo_offset: __u64,
|
||||
pub lo_sizelimit: __u64,
|
||||
pub lo_number: __u32,
|
||||
pub lo_encrypt_type: __u32,
|
||||
pub lo_encrypt_key_size: __u32,
|
||||
pub lo_flags: __u32,
|
||||
pub lo_file_name: [__u8; 64usize],
|
||||
pub lo_crypt_name: [__u8; 64usize],
|
||||
pub lo_encrypt_key: [__u8; 32usize],
|
||||
pub lo_init: [__u64; 2usize],
|
||||
}
|
||||
|
||||
impl Default for loop_info64 {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub struct loop_config {
|
||||
pub fd: __u32,
|
||||
pub block_size: __u32,
|
||||
pub info: loop_info64,
|
||||
pub __reserved: [__u64; 8usize],
|
||||
}
|
||||
|
||||
impl Default for loop_config {
|
||||
fn default() -> Self {
|
||||
let mut s = ::std::mem::MaybeUninit::<Self>::uninit();
|
||||
unsafe {
|
||||
::std::ptr::write_bytes(s.as_mut_ptr(), 0, 1);
|
||||
s.assume_init()
|
||||
}
|
||||
}
|
||||
}
|
475
crates/vendor/loopdev/src/lib.rs
vendored
475
crates/vendor/loopdev/src/lib.rs
vendored
@ -1,475 +0,0 @@
|
||||
// Taken from https://github.com/stratis-storage/loopdev-3/blob/master/src/lib.rs
|
||||
// Licensed under MIT.
|
||||
|
||||
//! Setup and control loop devices.
|
||||
//!
|
||||
//! Provides rust interface with similar functionality to the Linux utility `losetup`.
|
||||
//!
|
||||
//! # Examples
|
||||
//!
|
||||
//! Default options:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use loopdev::LoopControl;
|
||||
//! let lc = LoopControl::open().unwrap();
|
||||
//! let ld = lc.next_free().unwrap();
|
||||
//!
|
||||
//! println!("{}", ld.path().unwrap().display());
|
||||
//!
|
||||
//! ld.attach_file("disk.img").unwrap();
|
||||
//! // ...
|
||||
//! ld.detach().unwrap();
|
||||
//! ```
|
||||
//!
|
||||
//! Custom options:
|
||||
//!
|
||||
//! ```no_run
|
||||
//! # use loopdev::LoopControl;
|
||||
//! # let lc = LoopControl::open().unwrap();
|
||||
//! # let ld = lc.next_free().unwrap();
|
||||
//! #
|
||||
//! ld.with()
|
||||
//! .part_scan(true)
|
||||
//! .offset(512 * 1024 * 1024) // 512 MiB
|
||||
//! .size_limit(1024 * 1024 * 1024) // 1GiB
|
||||
//! .attach("disk.img").unwrap();
|
||||
//! // ...
|
||||
//! ld.detach().unwrap();
|
||||
//! ```
|
||||
mod bindings;
|
||||
mod linux;
|
||||
|
||||
use crate::bindings::{
|
||||
loop_info64, LOOP_CLR_FD, LOOP_CTL_ADD, LOOP_CTL_GET_FREE, LOOP_SET_CAPACITY, LOOP_SET_FD,
|
||||
LOOP_SET_STATUS64, LO_FLAGS_AUTOCLEAR, LO_FLAGS_PARTSCAN, LO_FLAGS_READ_ONLY,
|
||||
};
|
||||
use libc::ioctl;
|
||||
use std::ffi::c_int;
|
||||
use std::{
|
||||
default::Default,
|
||||
fs::{File, OpenOptions},
|
||||
io,
|
||||
os::unix::prelude::*,
|
||||
path::{Path, PathBuf},
|
||||
};
|
||||
|
||||
#[cfg(all(not(target_os = "android"), not(target_env = "musl")))]
|
||||
type IoctlRequest = std::ffi::c_ulong;
|
||||
#[cfg(any(target_os = "android", target_env = "musl"))]
|
||||
type IoctlRequest = c_int;
|
||||
|
||||
const LOOP_CONTROL: &str = "/dev/loop-control";
|
||||
#[cfg(not(target_os = "android"))]
|
||||
const LOOP_PREFIX: &str = "/dev/loop";
|
||||
#[cfg(target_os = "android")]
|
||||
const LOOP_PREFIX: &str = "/dev/block/loop";
|
||||
|
||||
/// Interface to the loop control device: `/dev/loop-control`.
|
||||
#[derive(Debug)]
|
||||
pub struct LoopControl {
|
||||
dev_file: File,
|
||||
}
|
||||
|
||||
impl LoopControl {
|
||||
/// Opens the loop control device.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when opening
|
||||
/// the loop control file `/dev/loop-control`. See
|
||||
/// [`OpenOptions::open`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
|
||||
/// for further details.
|
||||
pub fn open() -> io::Result<Self> {
|
||||
Ok(Self {
|
||||
dev_file: OpenOptions::new()
|
||||
.read(true)
|
||||
.write(true)
|
||||
.open(LOOP_CONTROL)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Finds and opens the next available loop device.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopControl;
|
||||
/// let lc = LoopControl::open().unwrap();
|
||||
/// let ld = lc.next_free().unwrap();
|
||||
/// println!("{}", ld.path().unwrap().display());
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when opening
|
||||
/// the loop device file `/dev/loopX`. See
|
||||
/// [`OpenOptions::open`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
|
||||
/// for further details.
|
||||
pub fn next_free(&self) -> io::Result<LoopDevice> {
|
||||
let dev_num = ioctl_to_error(unsafe {
|
||||
ioctl(
|
||||
self.dev_file.as_raw_fd() as c_int,
|
||||
LOOP_CTL_GET_FREE as IoctlRequest,
|
||||
)
|
||||
})?;
|
||||
LoopDevice::open(format!("{}{}", LOOP_PREFIX, dev_num))
|
||||
}
|
||||
|
||||
/// Add and opens a new loop device.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopControl;
|
||||
/// let lc = LoopControl::open().unwrap();
|
||||
/// let ld = lc.add(1).unwrap();
|
||||
/// println!("{}", ld.path().unwrap().display());
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This funcitons will return an error when a loop device with the passed
|
||||
/// number exists or opening the newly created device fails.
|
||||
pub fn add(&self, n: u32) -> io::Result<LoopDevice> {
|
||||
let dev_num = ioctl_to_error(unsafe {
|
||||
ioctl(
|
||||
self.dev_file.as_raw_fd() as c_int,
|
||||
LOOP_CTL_ADD as IoctlRequest,
|
||||
n as c_int,
|
||||
)
|
||||
})?;
|
||||
LoopDevice::open(format!("{}{}", LOOP_PREFIX, dev_num))
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRawFd for LoopControl {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.dev_file.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for LoopControl {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.dev_file.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
/// Interface to a loop device ie `/dev/loop0`.
|
||||
#[derive(Debug)]
|
||||
pub struct LoopDevice {
|
||||
device: File,
|
||||
}
|
||||
|
||||
impl AsRawFd for LoopDevice {
|
||||
fn as_raw_fd(&self) -> RawFd {
|
||||
self.device.as_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl IntoRawFd for LoopDevice {
|
||||
fn into_raw_fd(self) -> RawFd {
|
||||
self.device.into_raw_fd()
|
||||
}
|
||||
}
|
||||
|
||||
impl LoopDevice {
|
||||
/// Opens a loop device.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when opening
|
||||
/// the given loop device file. See
|
||||
/// [`OpenOptions::open`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
|
||||
/// for further details.
|
||||
pub fn open<P: AsRef<Path>>(dev: P) -> io::Result<Self> {
|
||||
// TODO create dev if it does not exist and begins with LOOP_PREFIX
|
||||
Ok(Self {
|
||||
device: OpenOptions::new().read(true).write(true).open(dev)?,
|
||||
})
|
||||
}
|
||||
|
||||
/// Attach the loop device to a file with given options.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Attach the device to a file.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopDevice;
|
||||
/// let mut ld = LoopDevice::open("/dev/loop0").unwrap();
|
||||
/// ld.with().part_scan(true).attach("disk.img").unwrap();
|
||||
/// # ld.detach().unwrap();
|
||||
/// ```
|
||||
pub fn with(&self) -> AttachOptions<'_> {
|
||||
AttachOptions {
|
||||
device: self,
|
||||
info: loop_info64::default(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Attach the loop device to a file that maps to the whole file.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Attach the device to a file.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopDevice;
|
||||
/// let ld = LoopDevice::open("/dev/loop0").unwrap();
|
||||
/// ld.attach_file("disk.img").unwrap();
|
||||
/// # ld.detach().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons. Either when
|
||||
/// opening the backing file (see
|
||||
/// [`OpenOptions::open`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
|
||||
/// for further details) or when calling the ioctl to attach the backing
|
||||
/// file to the device.
|
||||
pub fn attach_file<P: AsRef<Path>>(&self, backing_file: P) -> io::Result<()> {
|
||||
let info = loop_info64 {
|
||||
..Default::default()
|
||||
};
|
||||
|
||||
Self::attach_with_loop_info(self, backing_file, info)
|
||||
}
|
||||
|
||||
/// Attach the loop device to a file with `loop_info64`.
|
||||
fn attach_with_loop_info(
|
||||
&self, // TODO should be mut? - but changing it is a breaking change
|
||||
backing_file: impl AsRef<Path>,
|
||||
info: loop_info64,
|
||||
) -> io::Result<()> {
|
||||
let write_access = (info.lo_flags & LO_FLAGS_READ_ONLY) == 0;
|
||||
let bf = OpenOptions::new()
|
||||
.read(true)
|
||||
.write(write_access)
|
||||
.open(backing_file)?;
|
||||
self.attach_fd_with_loop_info(bf, info)
|
||||
}
|
||||
|
||||
/// Attach the loop device to a fd with `loop_info`.
|
||||
fn attach_fd_with_loop_info(&self, bf: impl AsRawFd, info: loop_info64) -> io::Result<()> {
|
||||
// Attach the file
|
||||
ioctl_to_error(unsafe {
|
||||
ioctl(
|
||||
self.device.as_raw_fd() as c_int,
|
||||
LOOP_SET_FD as IoctlRequest,
|
||||
bf.as_raw_fd() as c_int,
|
||||
)
|
||||
})?;
|
||||
|
||||
let result = unsafe {
|
||||
ioctl(
|
||||
self.device.as_raw_fd() as c_int,
|
||||
LOOP_SET_STATUS64 as IoctlRequest,
|
||||
&info,
|
||||
)
|
||||
};
|
||||
match ioctl_to_error(result) {
|
||||
Err(err) => {
|
||||
// Ignore the error to preserve the original error
|
||||
let _detach_err = self.detach();
|
||||
Err(err)
|
||||
}
|
||||
Ok(_) => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the path of the loop device.
|
||||
pub fn path(&self) -> Option<PathBuf> {
|
||||
let mut p = PathBuf::from("/proc/self/fd");
|
||||
p.push(self.device.as_raw_fd().to_string());
|
||||
std::fs::read_link(&p).ok()
|
||||
}
|
||||
|
||||
/// Get the device major number
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function needs to stat the backing file and can fail if there is
|
||||
/// an IO error.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
pub fn major(&self) -> io::Result<u32> {
|
||||
self.device
|
||||
.metadata()
|
||||
.map(|m| linux::major(m.rdev()))
|
||||
.map(|m| m as u32)
|
||||
}
|
||||
|
||||
/// Get the device major number
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function needs to stat the backing file and can fail if there is
|
||||
/// an IO error.
|
||||
#[allow(clippy::unnecessary_cast)]
|
||||
pub fn minor(&self) -> io::Result<u32> {
|
||||
self.device
|
||||
.metadata()
|
||||
.map(|m| linux::minor(m.rdev()))
|
||||
.map(|m| m as u32)
|
||||
}
|
||||
|
||||
/// Detach a loop device from its backing file.
|
||||
///
|
||||
/// Note that the device won't fully detach until a short delay after the underling device file
|
||||
/// gets closed. This happens when `LoopDev` goes out of scope so you should ensure the `LoopDev`
|
||||
/// lives for a short a time as possible.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopDevice;
|
||||
/// let ld = LoopDevice::open("/dev/loop0").unwrap();
|
||||
/// # ld.attach_file("disk.img").unwrap();
|
||||
/// ld.detach().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when calling the
|
||||
/// ioctl to detach the backing file from the device.
|
||||
pub fn detach(&self) -> io::Result<()> {
|
||||
ioctl_to_error(unsafe {
|
||||
ioctl(
|
||||
self.device.as_raw_fd() as c_int,
|
||||
LOOP_CLR_FD as IoctlRequest,
|
||||
0,
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Resize a live loop device. If the size of the backing file changes this can be called to
|
||||
/// inform the loop driver about the new size.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when calling the
|
||||
/// ioctl to set the capacity of the device.
|
||||
pub fn set_capacity(&self) -> io::Result<()> {
|
||||
ioctl_to_error(unsafe {
|
||||
ioctl(
|
||||
self.device.as_raw_fd() as c_int,
|
||||
LOOP_SET_CAPACITY as IoctlRequest,
|
||||
0,
|
||||
)
|
||||
})?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// Used to set options when attaching a device. Created with [`LoopDevice::with`()].
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Enable partition scanning on attach:
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopDevice;
|
||||
/// let mut ld = LoopDevice::open("/dev/loop0").unwrap();
|
||||
/// ld.with()
|
||||
/// .part_scan(true)
|
||||
/// .attach("disk.img")
|
||||
/// .unwrap();
|
||||
/// # ld.detach().unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// A 1MiB slice of the file located at 1KiB into the file.
|
||||
///
|
||||
/// ```no_run
|
||||
/// use loopdev::LoopDevice;
|
||||
/// let mut ld = LoopDevice::open("/dev/loop0").unwrap();
|
||||
/// ld.with()
|
||||
/// .offset(1024*1024)
|
||||
/// .size_limit(1024*1024*1024)
|
||||
/// .attach("disk.img")
|
||||
/// .unwrap();
|
||||
/// # ld.detach().unwrap();
|
||||
/// ```
|
||||
#[must_use]
|
||||
pub struct AttachOptions<'d> {
|
||||
device: &'d LoopDevice,
|
||||
info: loop_info64,
|
||||
}
|
||||
|
||||
impl AttachOptions<'_> {
|
||||
/// Offset in bytes from the start of the backing file the data will start at.
|
||||
pub fn offset(mut self, offset: u64) -> Self {
|
||||
self.info.lo_offset = offset;
|
||||
self
|
||||
}
|
||||
|
||||
/// Maximum size of the data in bytes.
|
||||
pub fn size_limit(mut self, size_limit: u64) -> Self {
|
||||
self.info.lo_sizelimit = size_limit;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set read only flag
|
||||
pub fn read_only(mut self, read_only: bool) -> Self {
|
||||
if read_only {
|
||||
self.info.lo_flags |= LO_FLAGS_READ_ONLY;
|
||||
} else {
|
||||
self.info.lo_flags &= !LO_FLAGS_READ_ONLY;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Set autoclear flag
|
||||
pub fn autoclear(mut self, autoclear: bool) -> Self {
|
||||
if autoclear {
|
||||
self.info.lo_flags |= LO_FLAGS_AUTOCLEAR;
|
||||
} else {
|
||||
self.info.lo_flags &= !LO_FLAGS_AUTOCLEAR;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Force the kernel to scan the partition table on a newly created loop device. Note that the
|
||||
/// partition table parsing depends on sector sizes. The default is sector size is 512 bytes
|
||||
pub fn part_scan(mut self, enable: bool) -> Self {
|
||||
if enable {
|
||||
self.info.lo_flags |= LO_FLAGS_PARTSCAN;
|
||||
} else {
|
||||
self.info.lo_flags &= !LO_FLAGS_PARTSCAN;
|
||||
}
|
||||
self
|
||||
}
|
||||
|
||||
/// Attach the loop device to a file with the set options.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons. Either when
|
||||
/// opening the backing file (see
|
||||
/// [`OpenOptions::open`](https://doc.rust-lang.org/std/fs/struct.OpenOptions.html)
|
||||
/// for further details) or when calling the ioctl to attach the backing
|
||||
/// file to the device.
|
||||
pub fn attach(self, backing_file: impl AsRef<Path>) -> io::Result<()> {
|
||||
self.device.attach_with_loop_info(backing_file, self.info)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Attach the loop device to an fd
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
/// This function will return an error for various reasons when calling the
|
||||
/// ioctl to attach the backing file to the device.
|
||||
pub fn attach_fd(self, backing_file_fd: impl AsRawFd) -> io::Result<()> {
|
||||
self.device
|
||||
.attach_fd_with_loop_info(backing_file_fd, self.info)?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
fn ioctl_to_error(ret: i32) -> io::Result<i32> {
|
||||
if ret < 0 {
|
||||
Err(io::Error::last_os_error())
|
||||
} else {
|
||||
Ok(ret)
|
||||
}
|
||||
}
|
15
crates/vendor/loopdev/src/linux.rs
vendored
15
crates/vendor/loopdev/src/linux.rs
vendored
@ -1,15 +0,0 @@
|
||||
use std::ffi::c_uint;
|
||||
|
||||
pub fn major(dev: u64) -> c_uint {
|
||||
let mut major = 0;
|
||||
major |= (dev & 0x00000000000fff00) >> 8;
|
||||
major |= (dev & 0xfffff00000000000) >> 32;
|
||||
major as c_uint
|
||||
}
|
||||
|
||||
pub fn minor(dev: u64) -> c_uint {
|
||||
let mut minor = 0;
|
||||
minor |= dev & 0x00000000000000ff;
|
||||
minor |= (dev & 0x00000ffffff00000) >> 12;
|
||||
minor as c_uint
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "xencall"
|
||||
name = "krata-xencall"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "xenclient"
|
||||
name = "krata-xenclient"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
@ -9,14 +9,14 @@ elf = { workspace = true }
|
||||
flate2 = { workspace = true }
|
||||
libc = { workspace = true }
|
||||
log = { workspace = true }
|
||||
krata-xencall = { path = "../xencall" }
|
||||
krata-xenstore = { path = "../xenstore" }
|
||||
memchr = { workspace = true }
|
||||
slice-copy = { workspace = true }
|
||||
thiserror = { workspace = true }
|
||||
tokio = { workspace = true }
|
||||
uuid = { workspace = true }
|
||||
xz2 = { workspace = true }
|
||||
xencall = { path = "../xencall" }
|
||||
xenstore = { path = "../xenstore" }
|
||||
|
||||
[dev-dependencies]
|
||||
env_logger = { workspace = true }
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "xenevtchn"
|
||||
name = "krata-xenevtchn"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "xengnt"
|
||||
name = "krata-xengnt"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
@ -1,5 +1,5 @@
|
||||
[package]
|
||||
name = "xenstore"
|
||||
name = "krata-xenstore"
|
||||
version.workspace = true
|
||||
edition = "2021"
|
||||
resolver = "2"
|
||||
|
Loading…
Reference in New Issue
Block a user