feat: Introduce userspace namespace manager and adapt all schemes.
This commit is contained in:
committed by
Jeremy Soller
parent
1753859f75
commit
334928f151
Generated
+66
-64
@@ -14,7 +14,7 @@ dependencies = [
|
||||
"pcid",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
@@ -48,7 +48,7 @@ dependencies = [
|
||||
"plain",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"ron",
|
||||
"rustc-hash",
|
||||
"serde",
|
||||
@@ -68,7 +68,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -90,7 +90,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -214,7 +214,7 @@ dependencies = [
|
||||
"libc",
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -245,7 +245,7 @@ dependencies = [
|
||||
"fdt 0.2.0-alpha1",
|
||||
"libredox",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -260,7 +260,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"pcid",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -462,7 +462,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"log",
|
||||
"redox-log",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -600,7 +600,7 @@ dependencies = [
|
||||
"log",
|
||||
"partitionlib",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -614,7 +614,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"log",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -624,7 +624,7 @@ dependencies = [
|
||||
"daemon",
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -677,7 +677,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -757,7 +757,7 @@ dependencies = [
|
||||
"ransid",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -776,7 +776,7 @@ dependencies = [
|
||||
"ransid",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -903,7 +903,7 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
|
||||
|
||||
[[package]]
|
||||
name = "getrandom"
|
||||
@@ -960,7 +960,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"log",
|
||||
"redox-ioctl",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1019,6 +1019,7 @@ dependencies = [
|
||||
"common",
|
||||
"daemon",
|
||||
"fdt 0.1.5",
|
||||
"libredox",
|
||||
"log",
|
||||
"ron",
|
||||
]
|
||||
@@ -1058,7 +1059,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1073,7 +1074,7 @@ dependencies = [
|
||||
"pcid",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
@@ -1097,7 +1098,7 @@ dependencies = [
|
||||
"range-alloc",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"void",
|
||||
]
|
||||
|
||||
@@ -1129,7 +1130,7 @@ dependencies = [
|
||||
"log",
|
||||
"orbclient",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1154,7 +1155,7 @@ dependencies = [
|
||||
"redox-rt",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1180,7 +1181,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1207,14 +1208,14 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
|
||||
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"ioslice",
|
||||
"libc",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1238,7 +1239,7 @@ dependencies = [
|
||||
"driver-block",
|
||||
"libredox",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1263,7 +1264,7 @@ dependencies = [
|
||||
"daemon",
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1360,7 +1361,7 @@ dependencies = [
|
||||
"partitionlib",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"smallvec 1.15.1",
|
||||
]
|
||||
|
||||
@@ -1486,7 +1487,7 @@ dependencies = [
|
||||
"pico-args",
|
||||
"plain",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@@ -1499,7 +1500,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"pico-args",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"serde",
|
||||
"toml 0.5.11",
|
||||
]
|
||||
@@ -1581,7 +1582,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1592,7 +1593,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
@@ -1625,7 +1626,7 @@ dependencies = [
|
||||
"indexmap",
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"slab",
|
||||
]
|
||||
|
||||
@@ -1713,7 +1714,7 @@ dependencies = [
|
||||
"rand_core 0.5.1",
|
||||
"raw-cpuid",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"sha2",
|
||||
]
|
||||
|
||||
@@ -1778,17 +1779,16 @@ dependencies = [
|
||||
[[package]]
|
||||
name = "redox-ioctl"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
|
||||
dependencies = [
|
||||
"drm-sys",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-log"
|
||||
version = "0.1.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "81460b1526438123d16f0c968dbe42ba7f61e99645109b70e57864a8b66710fb"
|
||||
version = "0.1.5"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/redox-log.git#ac8cbc40a281879f1fee77483342edcc4de89983"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"log",
|
||||
@@ -1805,31 +1805,32 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
[[package]]
|
||||
name = "redox-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3362ca356a9dafdfd7d74fc88d97609f400f7329"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#3a8f64aa143184dc11fe1927a4f9e55c33ae3052"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"generic-rt",
|
||||
"goblin",
|
||||
"ioslice",
|
||||
"plain",
|
||||
"redox-path",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox-scheme"
|
||||
version = "0.8.3"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cea2668a5932f878a4298a1d7f8950249bbbb77120fb263da252c589152f5ea"
|
||||
checksum = "5eb0cee524a5c6e4db180250f699e101ee25f3f79ad2618527e539e028cb6722"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "redox_event"
|
||||
version = "0.4.2"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f8eafe403549fab08a0c0862769493ad992625bb5a694aae2df6901e7e4fd05a"
|
||||
checksum = "c30b73c93693667b5a8e6f54bddcc5a57449ef17c99f4b55c12d5bae4ab79e82"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
"libredox",
|
||||
@@ -1847,7 +1848,7 @@ dependencies = [
|
||||
"redox-rt",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"smoltcp",
|
||||
]
|
||||
|
||||
@@ -1862,9 +1863,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
|
||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||
dependencies = [
|
||||
"bitflags 2.10.0",
|
||||
]
|
||||
@@ -1884,7 +1885,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"qemu-exit",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"redox_termios",
|
||||
]
|
||||
|
||||
@@ -1958,7 +1959,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1973,7 +1974,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2011,7 +2012,7 @@ dependencies = [
|
||||
"log",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"spin 0.9.8",
|
||||
]
|
||||
|
||||
@@ -2411,6 +2412,7 @@ name = "usbctl"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"clap 2.34.0",
|
||||
"common",
|
||||
"xhcid",
|
||||
]
|
||||
|
||||
@@ -2423,7 +2425,7 @@ dependencies = [
|
||||
"inputd",
|
||||
"log",
|
||||
"orbclient",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"rehid",
|
||||
"xhcid",
|
||||
]
|
||||
@@ -2434,7 +2436,7 @@ version = "0.1.0"
|
||||
dependencies = [
|
||||
"common",
|
||||
"log",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"xhcid",
|
||||
]
|
||||
|
||||
@@ -2448,7 +2450,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"plain",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"thiserror 1.0.69",
|
||||
"xhcid",
|
||||
]
|
||||
@@ -2486,7 +2488,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2515,7 +2517,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"ransid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2531,7 +2533,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"spin 0.10.0",
|
||||
"static_assertions",
|
||||
"thiserror 1.0.69",
|
||||
@@ -2550,7 +2552,7 @@ dependencies = [
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"static_assertions",
|
||||
"thiserror 1.0.69",
|
||||
]
|
||||
@@ -2573,7 +2575,7 @@ dependencies = [
|
||||
"orbclient",
|
||||
"pcid",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"spin 0.9.8",
|
||||
"static_assertions",
|
||||
"virtio-core",
|
||||
@@ -2590,7 +2592,7 @@ dependencies = [
|
||||
"libredox",
|
||||
"log",
|
||||
"pcid",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"static_assertions",
|
||||
"virtio-core",
|
||||
]
|
||||
@@ -2801,7 +2803,7 @@ dependencies = [
|
||||
"plain",
|
||||
"redox-scheme",
|
||||
"redox_event",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
"regex",
|
||||
"serde",
|
||||
"serde_json",
|
||||
@@ -2837,7 +2839,7 @@ dependencies = [
|
||||
"daemon",
|
||||
"libredox",
|
||||
"redox-scheme",
|
||||
"redox_syscall 0.6.0",
|
||||
"redox_syscall 0.7.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
+5
-7
@@ -77,16 +77,14 @@ exclude = ["bootstrap"]
|
||||
[workspace.dependencies]
|
||||
libc = "0.2.180"
|
||||
log = "0.4"
|
||||
# libredox 0.1.12 uses redox_syscall 0.7, wait until that is supported
|
||||
libredox = "=0.1.11"
|
||||
libredox = "0.1.12"
|
||||
orbclient = { git = "https://gitlab.redox-os.org/redox-os/orbclient" }
|
||||
# redox_event 0.4.3 uses redox_syscall 0.7, wait until that is supported
|
||||
redox_event = "=0.4.2"
|
||||
redox_event = "0.4.3"
|
||||
redox-ioctl = { git = "https://gitlab.redox-os.org/redox-os/relibc.git" }
|
||||
redox-log = "0.1.4"
|
||||
redox-log = { git = "https://gitlab.redox-os.org/redox-os/redox-log.git" }
|
||||
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false }
|
||||
redox-scheme = "0.8.3"
|
||||
redox_syscall = "0.6"
|
||||
redox-scheme = "0.9.0"
|
||||
redox_syscall = "0.7"
|
||||
redox_termios = "0.1.3"
|
||||
|
||||
[patch.crates-io]
|
||||
|
||||
+15
-11
@@ -8,6 +8,7 @@ use ioslice::IoSlice;
|
||||
use libredox::flag;
|
||||
use libredox::{error::Result, Fd};
|
||||
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::Socket;
|
||||
|
||||
@@ -47,29 +48,32 @@ fn daemon(daemon: Daemon) -> anyhow::Result<()> {
|
||||
|
||||
let pid = libredox::call::getpid()?;
|
||||
|
||||
let socket = Socket::create("audio").context("failed to create scheme")?;
|
||||
let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?;
|
||||
|
||||
let socket = Socket::create().context("failed to create scheme")?;
|
||||
|
||||
let scheme = Arc::new(Mutex::new(AudioScheme::new()));
|
||||
|
||||
{
|
||||
let mut scheme = scheme.lock().unwrap();
|
||||
register_sync_scheme(&socket, "audio", &mut *scheme)
|
||||
.expect("audiod: failed to register scheme to namespace");
|
||||
}
|
||||
|
||||
// The scheme is now ready to accept requests, notify the original process
|
||||
daemon.ready();
|
||||
|
||||
let hw_file = Fd::open("/scheme/audiohw", flag::O_WRONLY | flag::O_CLOEXEC, 0)?;
|
||||
|
||||
let scheme = Arc::new(Mutex::new(AudioScheme::new()));
|
||||
|
||||
// Enter a constrained namespace
|
||||
let ns = libredox::call::mkns(&[
|
||||
//IoSlice::new(b"memory"), TODO: already included, uncommenting gives EEXIST
|
||||
IoSlice::new(b"memory"),
|
||||
IoSlice::new(b"rand"), // for HashMap
|
||||
])
|
||||
.context("failed to make namespace")?;
|
||||
libredox::call::setrens(ns, ns).context("failed to set namespace")?;
|
||||
libredox::call::setns(ns).context("failed to set namespace")?;
|
||||
|
||||
// Spawn a thread to mix and send audio data
|
||||
let scheme_thread = scheme.clone();
|
||||
let _thread = thread::spawn(move || {
|
||||
libredox::call::setrens(ns, ns).unwrap();
|
||||
thread(scheme_thread, pid, hw_file)
|
||||
});
|
||||
let _thread = thread::spawn(move || thread(scheme_thread, pid, hw_file));
|
||||
|
||||
let mut readiness = ReadinessBased::new(&socket, 16);
|
||||
|
||||
|
||||
+25
-2
@@ -1,7 +1,7 @@
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use std::collections::{BTreeMap, VecDeque};
|
||||
use std::str;
|
||||
use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
|
||||
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT, EWOULDBLOCK};
|
||||
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
@@ -16,6 +16,7 @@ enum Handle {
|
||||
// TODO: move volume to audiohw:?
|
||||
// TODO: Use SYS_CALL to handle this better?
|
||||
Volume,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
pub struct AudioScheme {
|
||||
@@ -64,7 +65,27 @@ impl AudioScheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for AudioScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let (handle, flags) = match path.trim_matches('/') {
|
||||
"" => (
|
||||
Handle::Audio {
|
||||
@@ -109,6 +130,7 @@ impl SchemeSync for AudioScheme {
|
||||
|
||||
Ok(len)
|
||||
}
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -158,6 +180,7 @@ impl SchemeSync for AudioScheme {
|
||||
Ok(0)
|
||||
}
|
||||
}
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+15
-8
@@ -41,7 +41,7 @@ checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2"
|
||||
[[package]]
|
||||
name = "generic-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#5d378c146078a58c025ad9c857402c983e5e8b37"
|
||||
source = "git+https://gitlab.redox-os.org/Ibuki.O/relibc.git?branch=namespace-improvement#aa4bd6493b3682c8bee1f5c391043b54554d2ba2"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
@@ -63,6 +63,12 @@ dependencies = [
|
||||
"foldhash",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "ioslice"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e571352c8a3b89074d12e3ee5173ffe162159105352aaaf1fc5764da747e31b"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.180"
|
||||
@@ -71,9 +77,9 @@ checksum = "bcc35a38544a891a5f7c865aca548a982ccb3b8650a5b06d0fd33a10283c56fc"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
version = "0.1.11"
|
||||
version = "0.1.12"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "df15f6eac291ed1cf25865b1ee60399f57e7c227e7f51bdbd4c5270396a9ed50"
|
||||
checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"libc",
|
||||
@@ -144,11 +150,12 @@ checksum = "436d45c2b6a5b159d43da708e62b25be3a4a3d5550d654b72216ade4c4bfd717"
|
||||
[[package]]
|
||||
name = "redox-rt"
|
||||
version = "0.1.0"
|
||||
source = "git+https://gitlab.redox-os.org/redox-os/relibc.git#5d378c146078a58c025ad9c857402c983e5e8b37"
|
||||
source = "git+https://gitlab.redox-os.org/Ibuki.O/relibc.git?branch=namespace-improvement#aa4bd6493b3682c8bee1f5c391043b54554d2ba2"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
"generic-rt",
|
||||
"goblin",
|
||||
"ioslice",
|
||||
"plain",
|
||||
"redox-path",
|
||||
"redox_syscall",
|
||||
@@ -156,9 +163,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox-scheme"
|
||||
version = "0.8.3"
|
||||
version = "0.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2cea2668a5932f878a4298a1d7f8950249bbbb77120fb263da252c589152f5ea"
|
||||
checksum = "5eb0cee524a5c6e4db180250f699e101ee25f3f79ad2618527e539e028cb6722"
|
||||
dependencies = [
|
||||
"libredox",
|
||||
"redox_syscall",
|
||||
@@ -166,9 +173,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ec96166dafa0886eb81fe1c0a388bece180fbef2135f97c1e2cf8302e74b43b5"
|
||||
checksum = "49f3fe0889e69e2ae9e41f4d6c4c0181701d00e4697b356fb1f74173a5e0ee27"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
|
||||
@@ -15,19 +15,18 @@ hashbrown = { version = "0.15", default-features = false, features = [
|
||||
"default-hasher",
|
||||
] }
|
||||
linked_list_allocator = "0.10"
|
||||
# libredox 0.1.12 uses redox_syscall 0.7, wait until that is supported
|
||||
libredox = { version = "=0.1.11", default-features = false }
|
||||
libredox = { version = "0.1.12", default-features = false }
|
||||
log = { version = "0.4", default-features = false }
|
||||
plain = "0.2"
|
||||
redox-initfs = { path = "../initfs", default-features = false }
|
||||
redox_syscall = { version = "0.6", default-features = false }
|
||||
redox-scheme = { version = "0.8.3", default-features = false }
|
||||
redox_syscall = { version = "0.7", default-features = false }
|
||||
redox-scheme = { version = "0.9.0", default-features = false }
|
||||
redox-path = "0.3.1"
|
||||
slab = { version = "0.4.9", default-features = false }
|
||||
arrayvec = { version = "0.7.6", default-features = false }
|
||||
|
||||
[target.'cfg(target_os = "redox")'.dependencies]
|
||||
redox-rt = { git = "https://gitlab.redox-os.org/redox-os/relibc.git", default-features = false }
|
||||
redox-rt = { git = "https://gitlab.redox-os.org/Ibuki.O/relibc.git", branch = "namespace-improvement", default-features = false }
|
||||
|
||||
[profile.release]
|
||||
panic = "abort"
|
||||
|
||||
@@ -2,7 +2,7 @@ use core::mem;
|
||||
use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
static MAP: Map = Map {
|
||||
|
||||
+108
-23
@@ -1,13 +1,18 @@
|
||||
use alloc::sync::Arc;
|
||||
use core::str::FromStr;
|
||||
|
||||
use alloc::borrow::ToOwned;
|
||||
use alloc::vec::Vec;
|
||||
|
||||
use syscall::CallFlags;
|
||||
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
|
||||
use syscall::flag::{O_CLOEXEC, O_RDONLY};
|
||||
use syscall::{Error, EINTR};
|
||||
use syscall::{EINTR, Error};
|
||||
|
||||
use redox_rt::proc::*;
|
||||
|
||||
use crate::KernelSchemeMap;
|
||||
|
||||
struct Logger;
|
||||
|
||||
impl log::Log for Logger {
|
||||
@@ -27,9 +32,38 @@ impl log::Log for Logger {
|
||||
fn flush(&self) {}
|
||||
}
|
||||
|
||||
const KERNEL_METADATA_BASE: usize = crate::arch::USERMODE_END - syscall::KERNEL_METADATA_SIZE;
|
||||
|
||||
pub fn main() -> ! {
|
||||
let auth = FdGuard::open("/scheme/kernel.proc/authority", O_CLOEXEC)
|
||||
.expect("failed to get proc authority");
|
||||
let mut cursor = KERNEL_METADATA_BASE;
|
||||
let kernel_scheme_infos = unsafe {
|
||||
let base_ptr = cursor as *const u8;
|
||||
let infos_len = *(base_ptr as *const usize);
|
||||
let infos_ptr = base_ptr.add(core::mem::size_of::<usize>()) as *const KernelSchemeInfo;
|
||||
let slice = core::slice::from_raw_parts(infos_ptr, infos_len);
|
||||
cursor += core::mem::size_of::<usize>() // kernel scheme number size
|
||||
+ infos_len // kernel scheme number
|
||||
* core::mem::size_of::<KernelSchemeInfo>();
|
||||
slice
|
||||
};
|
||||
let scheme_creation_cap = unsafe {
|
||||
let base_ptr = cursor as *const u8;
|
||||
let cap = *(base_ptr as *const usize);
|
||||
cap
|
||||
};
|
||||
|
||||
let kernel_schemes = KernelSchemeMap::new(kernel_scheme_infos);
|
||||
|
||||
let auth = FdGuard::new(
|
||||
*kernel_schemes
|
||||
.get(GlobalSchemes::Proc)
|
||||
.expect("failed to get proc fd"),
|
||||
);
|
||||
let pipe_fd = *kernel_schemes
|
||||
.get(GlobalSchemes::Pipe)
|
||||
.expect("failed to get pipe fd");
|
||||
let infos_arc = Arc::new(kernel_schemes);
|
||||
|
||||
let this_thr_fd = auth
|
||||
.dup(b"cur-context")
|
||||
.expect("failed to open open_via_dup")
|
||||
@@ -39,8 +73,17 @@ pub fn main() -> ! {
|
||||
|
||||
let mut env_bytes = [0_u8; 4096];
|
||||
let envs = {
|
||||
let fd = FdGuard::open("/scheme/sys/env", O_RDONLY | O_CLOEXEC)
|
||||
.expect("bootstrap: failed to open env");
|
||||
let fd = FdGuard::new(
|
||||
syscall::openat(
|
||||
*infos_arc
|
||||
.get(GlobalSchemes::Sys)
|
||||
.expect("failed to get sys fd"),
|
||||
"env",
|
||||
O_RDONLY | O_CLOEXEC,
|
||||
0,
|
||||
)
|
||||
.expect("bootstrap: failed to open env"),
|
||||
);
|
||||
let bytes_read = fd
|
||||
.read(&mut env_bytes)
|
||||
.expect("bootstrap: failed to read env");
|
||||
@@ -80,10 +123,12 @@ pub fn main() -> ! {
|
||||
(*(core::ptr::addr_of!(__initfs_header) as *const redox_initfs::types::Header)).initfs_size
|
||||
};
|
||||
|
||||
spawn(
|
||||
let infos_arc_clone = infos_arc.clone();
|
||||
let initfs_fd = spawn(
|
||||
"initfs daemon",
|
||||
&auth,
|
||||
&this_thr_fd,
|
||||
pipe_fd,
|
||||
move |write_fd| unsafe {
|
||||
// Creating a reference to NULL is UB. Mask the UB for now using black_box.
|
||||
// FIXME use a raw pointer and inline asm for reading instead for the initfs header.
|
||||
@@ -93,14 +138,39 @@ pub fn main() -> ! {
|
||||
crate::initfs::run(
|
||||
core::slice::from_raw_parts(initfs_start, initfs_length),
|
||||
write_fd,
|
||||
&infos_arc_clone,
|
||||
scheme_creation_cap,
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
spawn("process manager", &auth, &this_thr_fd, |write_fd| {
|
||||
crate::procmgr::run(write_fd, &auth)
|
||||
});
|
||||
let (init_proc_fd, init_thr_fd) = unsafe { redox_rt::proc::make_init() };
|
||||
let infos_arc_clone = infos_arc.clone();
|
||||
let proc_fd = spawn(
|
||||
"process manager",
|
||||
&auth,
|
||||
&this_thr_fd,
|
||||
pipe_fd,
|
||||
|write_fd| crate::procmgr::run(write_fd, &auth, &infos_arc_clone, scheme_creation_cap),
|
||||
);
|
||||
|
||||
let infos_arc_clone = infos_arc.clone();
|
||||
let initns_fd = spawn(
|
||||
"init namespace manager",
|
||||
&auth,
|
||||
&this_thr_fd,
|
||||
pipe_fd,
|
||||
|write_fd| {
|
||||
crate::initnsmgr::run(
|
||||
write_fd,
|
||||
&infos_arc_clone,
|
||||
initfs_fd,
|
||||
proc_fd,
|
||||
scheme_creation_cap,
|
||||
)
|
||||
},
|
||||
);
|
||||
|
||||
let (init_proc_fd, init_thr_fd) = unsafe { make_init(proc_fd) };
|
||||
// from this point, this_thr_fd is no longer valid
|
||||
|
||||
const CWD: &[u8] = b"/scheme/initfs";
|
||||
@@ -111,21 +181,27 @@ pub fn main() -> ! {
|
||||
umask: redox_rt::sys::get_umask(),
|
||||
thr_fd: init_thr_fd.as_raw_fd(),
|
||||
proc_fd: init_proc_fd.as_raw_fd(),
|
||||
ns_fd: Some(initns_fd),
|
||||
};
|
||||
|
||||
let path = "/scheme/initfs/bin/init";
|
||||
let path = "/bin/init";
|
||||
|
||||
let image_file = FdGuard::open(path, O_RDONLY | O_CLOEXEC)
|
||||
.expect("failed to open init")
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
let image_file = FdGuard::new(
|
||||
syscall::openat(initfs_fd, path, O_RDONLY | O_CLOEXEC, 0).expect("failed to open init"),
|
||||
)
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
|
||||
drop(infos_arc);
|
||||
|
||||
let exe_path = alloc::format!("/scheme/initfs{}", path);
|
||||
|
||||
fexec_impl(
|
||||
image_file,
|
||||
init_thr_fd,
|
||||
init_proc_fd,
|
||||
path.as_bytes(),
|
||||
&[path.as_bytes()],
|
||||
exe_path.as_bytes(),
|
||||
&[exe_path.as_bytes()],
|
||||
&envs,
|
||||
&extrainfo,
|
||||
None,
|
||||
@@ -139,9 +215,10 @@ pub(crate) fn spawn(
|
||||
name: &str,
|
||||
auth: &FdGuard,
|
||||
this_thr_fd: &FdGuardUpper,
|
||||
inner: impl FnOnce(usize),
|
||||
) {
|
||||
let read = syscall::open("/scheme/pipe", O_CLOEXEC).expect("failed to open sync read pipe");
|
||||
pipe_fd: usize,
|
||||
inner: impl FnOnce(usize) -> !,
|
||||
) -> usize {
|
||||
let read = syscall::openat(pipe_fd, "", O_CLOEXEC, 0).expect("failed to open sync read pipe");
|
||||
|
||||
// The write pipe will not inherit O_CLOEXEC, but is closed by the daemon later.
|
||||
let write = syscall::dup(read, b"write").expect("failed to open sync write pipe");
|
||||
@@ -157,15 +234,23 @@ pub(crate) fn spawn(
|
||||
// Return in order to execute init, as the parent.
|
||||
Ok(_) => {
|
||||
let _ = syscall::close(write);
|
||||
|
||||
let mut new_fd = usize::MAX;
|
||||
let fd_bytes = unsafe {
|
||||
core::slice::from_raw_parts_mut(
|
||||
core::slice::from_mut(&mut new_fd).as_mut_ptr() as *mut u8,
|
||||
core::mem::size_of::<usize>(),
|
||||
)
|
||||
};
|
||||
loop {
|
||||
match syscall::read(read, &mut [0]) {
|
||||
match syscall::call_ro(read, fd_bytes, CallFlags::FD | CallFlags::FD_UPPER, &[]) {
|
||||
Err(Error { errno: EINTR }) => continue,
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
return new_fd;
|
||||
}
|
||||
}
|
||||
inner(write);
|
||||
inner(write)
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 0x8000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
|
||||
+90
-22
@@ -6,13 +6,12 @@ use core::str;
|
||||
use alloc::string::String;
|
||||
|
||||
use hashbrown::HashMap;
|
||||
use redox_initfs::{InitFs, Inode, InodeDir, InodeKind, InodeStruct, types::Timespec};
|
||||
use redox_initfs::{types::Timespec, InitFs, Inode, InodeDir, InodeKind, InodeStruct};
|
||||
|
||||
use redox_path::canonicalize_to_standard;
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, scheme::SchemeSync};
|
||||
use redox_scheme::{scheme::SchemeSync, CallerCtx, OpenResult, RequestKind};
|
||||
|
||||
use redox_scheme::{SignalBehavior, Socket};
|
||||
use syscall::PAGE_SIZE;
|
||||
use syscall::data::Stat;
|
||||
use syscall::dirent::DirEntry;
|
||||
use syscall::dirent::DirentBuf;
|
||||
@@ -20,8 +19,30 @@ use syscall::dirent::DirentKind;
|
||||
use syscall::error::*;
|
||||
use syscall::flag::*;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
struct Handle {
|
||||
use crate::KernelSchemeMap;
|
||||
|
||||
enum Handle {
|
||||
Node(Node),
|
||||
SchemeRoot,
|
||||
}
|
||||
impl Handle {
|
||||
fn as_node(&self) -> Result<&Node> {
|
||||
match self {
|
||||
Handle::Node(n) => Ok(n),
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
fn as_node_mut(&mut self) -> Result<&mut Node> {
|
||||
match self {
|
||||
Handle::Node(n) => Ok(n),
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Node {
|
||||
inode: Inode,
|
||||
// TODO: Any better way to implement fpath? Or maybe work around it, e.g. by giving paths such
|
||||
// as `initfs:__inodes__/<inode>`?
|
||||
@@ -91,7 +112,20 @@ fn inode_len(inode: InodeStruct<'static>) -> Result<usize> {
|
||||
}
|
||||
|
||||
impl SchemeSync for InitFsScheme {
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
let mut components = path
|
||||
// trim leading and trailing slash
|
||||
.trim_matches('/')
|
||||
@@ -158,10 +192,10 @@ impl SchemeSync for InitFsScheme {
|
||||
let id = self.next_id();
|
||||
let old = self.handles.insert(
|
||||
id,
|
||||
Handle {
|
||||
Handle::Node(Node {
|
||||
inode: current_inode,
|
||||
filename: path.into(),
|
||||
},
|
||||
}),
|
||||
);
|
||||
assert!(old.is_none());
|
||||
|
||||
@@ -183,7 +217,11 @@ impl SchemeSync for InitFsScheme {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.as_node_mut()?;
|
||||
|
||||
match Self::get_inode(&self.fs, handle.inode)?.kind() {
|
||||
InodeKind::File(file) => {
|
||||
@@ -222,7 +260,7 @@ impl SchemeSync for InitFsScheme {
|
||||
let Ok(offset) = u32::try_from(opaque_offset) else {
|
||||
return Ok(buf);
|
||||
};
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
|
||||
let InodeKind::Dir(dir) = Self::get_inode(&self.fs, handle.inode)?.kind() else {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
};
|
||||
@@ -247,19 +285,23 @@ impl SchemeSync for InitFsScheme {
|
||||
}
|
||||
|
||||
fn fsize(&mut self, id: usize, _ctx: &CallerCtx) -> Result<u64> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&id)
|
||||
.ok_or(Error::new(EBADF))?
|
||||
.as_node_mut()?;
|
||||
|
||||
Ok(inode_len(Self::get_inode(&self.fs, handle.inode)?)? as u64)
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
|
||||
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
|
||||
|
||||
// TODO: Copy scheme part in kernel
|
||||
let scheme_path = b"/scheme/initfs";
|
||||
@@ -274,7 +316,7 @@ impl SchemeSync for InitFsScheme {
|
||||
}
|
||||
|
||||
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?.as_node()?;
|
||||
|
||||
let Timespec { sec, nsec } = self.fs.image_creation_time();
|
||||
|
||||
@@ -315,8 +357,10 @@ impl SchemeSync for InitFsScheme {
|
||||
_ctx: &CallerCtx,
|
||||
) -> syscall::Result<usize> {
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let data = match Self::get_inode(&self.fs, handle.inode)?.kind() {
|
||||
let Handle::Node(node) = handle else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
let data = match Self::get_inode(&self.fs, node.inode)?.kind() {
|
||||
InodeKind::File(file) => file.data().map_err(|_| Error::new(EIO))?,
|
||||
InodeKind::Dir(_) => return Err(Error::new(EISDIR)),
|
||||
InodeKind::Link(link) => return Err(Error::new(ELOOP)),
|
||||
@@ -339,12 +383,30 @@ impl SchemeSync for InitFsScheme {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
|
||||
pub fn run(
|
||||
bytes: &'static [u8],
|
||||
sync_pipe: usize,
|
||||
kernel_schemes: &KernelSchemeMap,
|
||||
scheme_creation_cap: usize,
|
||||
) -> ! {
|
||||
log::info!("bootstrap: starting initfs scheme");
|
||||
let mut scheme = InitFsScheme::new(bytes);
|
||||
|
||||
let socket = Socket::create("initfs").expect("failed to open initfs scheme socket");
|
||||
let socket = Socket::create_inner(scheme_creation_cap, false)
|
||||
.expect("failed to open initfs scheme socket");
|
||||
let _ = syscall::close(scheme_creation_cap);
|
||||
|
||||
let _ = syscall::write(sync_pipe, &[0]);
|
||||
for fd in kernel_schemes.0.values() {
|
||||
let _ = syscall::close(*fd);
|
||||
}
|
||||
|
||||
// send open-capability to bootstrap
|
||||
let new_id = scheme.next_id();
|
||||
scheme.handles.insert(new_id, Handle::SchemeRoot);
|
||||
let cap_fd = socket
|
||||
.create_this_scheme_fd(0, new_id, 0, 0)
|
||||
.expect("failed to issue initfs root fd");
|
||||
let _ = syscall::call_rw(sync_pipe, &mut cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
|
||||
let _ = syscall::close(sync_pipe);
|
||||
|
||||
loop {
|
||||
@@ -380,17 +442,23 @@ pub fn run(bytes: &'static [u8], sync_pipe: usize) -> ! {
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn redox_read_v1(fd: usize, ptr: *mut u8, len: usize) -> isize {
|
||||
Error::mux(syscall::read(fd, core::slice::from_raw_parts_mut(ptr, len))) as isize
|
||||
Error::mux(syscall::read(fd, unsafe {
|
||||
core::slice::from_raw_parts_mut(ptr, len)
|
||||
})) as isize
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn redox_write_v1(fd: usize, ptr: *const u8, len: usize) -> isize {
|
||||
Error::mux(syscall::write(fd, core::slice::from_raw_parts(ptr, len))) as isize
|
||||
Error::mux(syscall::write(fd, unsafe {
|
||||
core::slice::from_raw_parts(ptr, len)
|
||||
})) as isize
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn redox_open_v1(ptr: *const u8, len: usize, flags: usize) -> isize {
|
||||
Error::mux(syscall::open(core::str::from_raw_parts(ptr, len), flags)) as isize
|
||||
pub unsafe fn redox_dup_v1(fd: usize, buf: *const u8, len: usize) -> isize {
|
||||
Error::mux(syscall::dup(fd, unsafe {
|
||||
core::slice::from_raw_parts(buf, len)
|
||||
})) as isize
|
||||
}
|
||||
|
||||
#[unsafe(no_mangle)]
|
||||
|
||||
@@ -0,0 +1,536 @@
|
||||
use super::KernelSchemeMap;
|
||||
|
||||
use alloc::rc::Rc;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use core::cell::RefCell;
|
||||
use core::fmt::Debug;
|
||||
use core::mem;
|
||||
use hashbrown::HashMap;
|
||||
use log::{error, warn};
|
||||
use redox_path::RedoxPath;
|
||||
use redox_path::RedoxScheme;
|
||||
use redox_rt::protocol::{NsDup, NsPermissions};
|
||||
use redox_scheme::{
|
||||
CallerCtx, OpenResult, RequestKind, Response, SendFdRequest, SignalBehavior, Socket,
|
||||
scheme::SchemeSync,
|
||||
};
|
||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
use syscall::{CallFlags, FobtainFdFlags, error::*, schemev2::NewFdFlags};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct Namespace {
|
||||
schemes: HashMap<String, usize>,
|
||||
}
|
||||
|
||||
impl Namespace {
|
||||
fn fork(&self, buf: &[u8]) -> Result<Self> {
|
||||
let mut schemes = HashMap::new();
|
||||
let mut cursor = 0;
|
||||
while cursor < buf.len() {
|
||||
let len = read_num::<usize>(&buf[cursor..])?;
|
||||
cursor += mem::size_of::<usize>();
|
||||
let name = String::from_utf8(Vec::from(&buf[cursor..cursor + len]))
|
||||
.map_err(|_| Error::new(EINVAL))?;
|
||||
cursor += len;
|
||||
if name.ends_with('*') {
|
||||
let prefix = &name[..name.len() - 1];
|
||||
for (registered_name, fd) in &self.schemes {
|
||||
if registered_name.starts_with(prefix) {
|
||||
schemes.insert(registered_name.clone(), *fd);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
let Some(fd) = self.schemes.get(&name) else {
|
||||
warn!("Scheme {} not found in namespace", name);
|
||||
continue;
|
||||
};
|
||||
schemes.insert(name, *fd);
|
||||
}
|
||||
}
|
||||
Ok(Self { schemes })
|
||||
}
|
||||
fn get_scheme_fd(&self, scheme: &str) -> Option<usize> {
|
||||
self.schemes.get(scheme).copied()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct NamespaceAccess {
|
||||
namespace: Rc<RefCell<Namespace>>,
|
||||
permission: NsPermissions,
|
||||
}
|
||||
|
||||
impl NamespaceAccess {
|
||||
fn has_permission(&self, permission: NsPermissions) -> bool {
|
||||
self.permission.contains(permission)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
struct SchemeRegister {
|
||||
target_namespace: Rc<RefCell<Namespace>>,
|
||||
scheme_name: String,
|
||||
}
|
||||
|
||||
impl SchemeRegister {
|
||||
fn register(&self, fd: usize) -> Result<()> {
|
||||
let mut ns = self.target_namespace.borrow_mut();
|
||||
if ns.schemes.contains_key(&self.scheme_name) {
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
ns.schemes.insert(self.scheme_name.clone(), fd);
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
enum Handle {
|
||||
Access(NamespaceAccess),
|
||||
Register(SchemeRegister),
|
||||
List(NamespaceAccess),
|
||||
}
|
||||
|
||||
pub struct NamespaceScheme<'sock> {
|
||||
socket: &'sock Socket,
|
||||
handles: HashMap<usize, Handle>,
|
||||
root_namespace: Namespace,
|
||||
next_id: usize,
|
||||
scheme_creation_cap: usize,
|
||||
}
|
||||
|
||||
const HIGH_PERMISSIONS: NsPermissions = NsPermissions::SCHEME_CREATE;
|
||||
|
||||
impl<'sock> NamespaceScheme<'sock> {
|
||||
pub fn new(
|
||||
socket: &'sock Socket,
|
||||
schemes: HashMap<String, usize>,
|
||||
scheme_creation_cap: usize,
|
||||
) -> Self {
|
||||
let mut scheme = Self {
|
||||
socket,
|
||||
handles: HashMap::new(),
|
||||
root_namespace: Namespace { schemes },
|
||||
next_id: 0,
|
||||
scheme_creation_cap,
|
||||
};
|
||||
|
||||
scheme
|
||||
}
|
||||
|
||||
fn add_namespace(&mut self, id: usize, schemes: Namespace, permission: NsPermissions) {
|
||||
let handle = Handle::Access(NamespaceAccess {
|
||||
namespace: Rc::new(RefCell::new(schemes)),
|
||||
permission,
|
||||
});
|
||||
self.handles.insert(id, handle);
|
||||
}
|
||||
|
||||
fn get_ns_access(&self, id: usize) -> Option<&NamespaceAccess> {
|
||||
let handle = self.handles.get(&id);
|
||||
match handle {
|
||||
Some(Handle::Access(access)) => Some(access),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn open_namespace_resource(
|
||||
&self,
|
||||
ns_access: &NamespaceAccess,
|
||||
reference: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
match reference {
|
||||
"scheme-creation-cap" => {
|
||||
if !ns_access.has_permission(NsPermissions::SCHEME_CREATE) {
|
||||
error!("Permission denied to get scheme creation capability");
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
Ok(syscall::dup(self.scheme_creation_cap, &[])?)
|
||||
}
|
||||
_ => {
|
||||
error!("Unknown special reference: {}", reference);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn open_scheme_resource(
|
||||
&self,
|
||||
ns: &Namespace,
|
||||
scheme: &str,
|
||||
reference: &str,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let Some(cap_fd) = ns.get_scheme_fd(scheme) else {
|
||||
warn!("Scheme {} not found in namespace", scheme);
|
||||
return Err(Error::new(ENODEV));
|
||||
};
|
||||
|
||||
let scheme_fd = syscall::openat_with_filter(
|
||||
cap_fd,
|
||||
reference,
|
||||
flags,
|
||||
fcntl_flags as usize,
|
||||
ctx.uid,
|
||||
ctx.gid,
|
||||
)?;
|
||||
|
||||
Ok(scheme_fd)
|
||||
}
|
||||
|
||||
fn fork_namespace(&mut self, namespace: Rc<RefCell<Namespace>>, names: &[u8]) -> Result<usize> {
|
||||
let new_id = self.next_id;
|
||||
let new_namespace = namespace.borrow().fork(names).map_err(|e| {
|
||||
error!("Failed to fork namespace {}: {}", new_id, e);
|
||||
e
|
||||
})?;
|
||||
self.add_namespace(
|
||||
new_id,
|
||||
new_namespace,
|
||||
NsPermissions::all().difference(HIGH_PERMISSIONS),
|
||||
);
|
||||
self.next_id += 1;
|
||||
Ok(new_id)
|
||||
}
|
||||
|
||||
fn shrink_permissions(
|
||||
&mut self,
|
||||
mut ns: NamespaceAccess,
|
||||
permission: NsPermissions,
|
||||
) -> Result<usize> {
|
||||
ns.permission = ns.permission.intersection(permission);
|
||||
let next_id = self.next_id;
|
||||
self.handles.insert(next_id, Handle::Access(ns));
|
||||
self.next_id += 1;
|
||||
Ok(next_id)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sock> SchemeSync for NamespaceScheme<'sock> {
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let ns_access = {
|
||||
let handle = self.handles.get(&fd);
|
||||
match handle {
|
||||
Some(Handle::Access(access)) => Some(access),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
.ok_or_else(|| {
|
||||
error!("Namespace with ID {} not found", fd);
|
||||
Error::new(ENOENT)
|
||||
})?;
|
||||
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
|
||||
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
|
||||
let res_fd = match scheme.as_ref() {
|
||||
"namespace" => self.open_namespace_resource(
|
||||
ns_access,
|
||||
reference.as_ref(),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
ctx,
|
||||
)?,
|
||||
"" => {
|
||||
if !ns_access.has_permission(NsPermissions::LIST) {
|
||||
error!("Permission denied to list schemes in namespace {}", fd);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let new_id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(new_id, Handle::List(ns_access.clone()));
|
||||
|
||||
return Ok(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
flags: NewFdFlags::empty(),
|
||||
});
|
||||
}
|
||||
_ => self.open_scheme_resource(
|
||||
&ns_access.namespace.borrow(),
|
||||
scheme.as_ref(),
|
||||
reference.as_ref(),
|
||||
flags,
|
||||
fcntl_flags,
|
||||
ctx,
|
||||
)?,
|
||||
};
|
||||
|
||||
Ok(OpenResult::OtherScheme { fd: res_fd })
|
||||
}
|
||||
|
||||
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
let ns_access = self.get_ns_access(id).ok_or_else(|| {
|
||||
error!("Namespace with ID {} not found", id);
|
||||
Error::new(ENOENT)
|
||||
})?;
|
||||
|
||||
let raw_kind = read_num::<usize>(buf)?;
|
||||
let Some(kind) = NsDup::try_from_raw(raw_kind) else {
|
||||
error!("Unknown dup kind: {}", raw_kind);
|
||||
return Err(Error::new(EINVAL));
|
||||
};
|
||||
let payload = &buf[mem::size_of::<NsDup>()..];
|
||||
let new_id = match kind {
|
||||
NsDup::ForkNs => {
|
||||
let ns = ns_access.namespace.clone();
|
||||
let _ = ns_access;
|
||||
self.fork_namespace(ns, payload)?
|
||||
}
|
||||
NsDup::ShrinkPermissions => self.shrink_permissions(
|
||||
ns_access.clone(),
|
||||
NsPermissions::from_bits_truncate(read_num::<usize>(payload)?),
|
||||
)?,
|
||||
NsDup::IssueRegister => {
|
||||
let name = core::str::from_utf8(payload).map_err(|_| Error::new(EINVAL))?;
|
||||
let scheme_name = RedoxScheme::new(name).ok_or_else(|| {
|
||||
error!("Invalid scheme name: {}", name);
|
||||
Error::new(EINVAL)
|
||||
})?;
|
||||
|
||||
if !ns_access.has_permission(NsPermissions::INSERT) {
|
||||
error!(
|
||||
"Permission denied to issue register capability for namespace {}",
|
||||
id
|
||||
);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
let new_id = self.next_id;
|
||||
let register_cap = Handle::Register(SchemeRegister {
|
||||
target_namespace: ns_access.namespace.clone(),
|
||||
scheme_name: scheme_name.as_ref().to_string(),
|
||||
});
|
||||
self.handles.insert(new_id, register_cap);
|
||||
self.next_id += 1;
|
||||
new_id
|
||||
}
|
||||
};
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
|
||||
fn unlinkat(&mut self, fd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
|
||||
let ns_access = {
|
||||
let handle = self.handles.get(&fd);
|
||||
match handle {
|
||||
Some(Handle::Access(access)) => Some(access),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
.ok_or_else(|| {
|
||||
error!("Namespace with ID {} not found", fd);
|
||||
Error::new(ENOENT)
|
||||
})?;
|
||||
let ns = ns_access.namespace.borrow();
|
||||
|
||||
let redox_path = RedoxPath::from_absolute(path).ok_or(Error::new(EINVAL))?;
|
||||
let (scheme, reference) = redox_path.as_parts().ok_or(Error::new(EINVAL))?;
|
||||
let Some(cap_fd) = ns.get_scheme_fd(scheme.as_ref()) else {
|
||||
error!("Scheme {} not found in namespace", scheme);
|
||||
return Err(Error::new(ENODEV));
|
||||
};
|
||||
|
||||
syscall::unlinkat_with_filter(cap_fd, reference, flags, ctx.uid, ctx.gid)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn on_close(&mut self, id: usize) {
|
||||
self.handles.remove(&id);
|
||||
}
|
||||
|
||||
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
|
||||
let namespace_id = sendfd_request.id();
|
||||
let num_fds = sendfd_request.num_fds();
|
||||
|
||||
let handle = self.handles.get(&namespace_id).ok_or_else(|| {
|
||||
error!("Namespace with ID {} not found", namespace_id);
|
||||
Error::new(ENOENT)
|
||||
})?;
|
||||
let Handle::Register(register_cap) = handle else {
|
||||
error!(
|
||||
"Handle with ID {} is not a register capability",
|
||||
namespace_id
|
||||
);
|
||||
return Err(Error::new(EACCES));
|
||||
};
|
||||
|
||||
if num_fds == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
if num_fds > 1 {
|
||||
error!("Can only send one fd at a time");
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let mut new_fd = usize::MAX;
|
||||
if let Err(e) = sendfd_request.obtain_fd(
|
||||
&self.socket,
|
||||
FobtainFdFlags::UPPER_TBL,
|
||||
core::slice::from_mut(&mut new_fd),
|
||||
) {
|
||||
error!("on_sendfd: obtain_fd failed with error: {:?}", e);
|
||||
return Err(e);
|
||||
}
|
||||
register_cap.register(new_fd)?;
|
||||
|
||||
Ok(num_fds)
|
||||
}
|
||||
|
||||
fn getdents<'buf>(
|
||||
&mut self,
|
||||
id: usize,
|
||||
mut buf: DirentBuf<&'buf mut [u8]>,
|
||||
opaque_offset: u64,
|
||||
) -> Result<DirentBuf<&'buf mut [u8]>> {
|
||||
let Handle::List(ns_access) = self.handles.get(&id).ok_or(Error::new(EBADF))? else {
|
||||
return Err(Error::new(ENOTDIR));
|
||||
};
|
||||
|
||||
if !ns_access.has_permission(NsPermissions::LIST) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let ns = ns_access.namespace.borrow();
|
||||
|
||||
let opaque_offset = opaque_offset as usize;
|
||||
for (i, (name, _)) in ns.schemes.iter().enumerate().skip(opaque_offset) {
|
||||
if name.is_empty() {
|
||||
continue;
|
||||
}
|
||||
if let Err(err) = buf.entry(DirEntry {
|
||||
kind: DirentKind::Unspecified,
|
||||
name: &name.clone(),
|
||||
inode: 0,
|
||||
next_opaque_id: i as u64 + 1,
|
||||
}) {
|
||||
if err.errno == EINVAL && i > opaque_offset {
|
||||
// POSIX allows partial result of getdents
|
||||
break;
|
||||
} else {
|
||||
return Err(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(buf)
|
||||
}
|
||||
}
|
||||
|
||||
trait NumFromBytes: Sized + Debug {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
macro_rules! num_from_bytes_impl {
|
||||
($($t:ty),*) => {
|
||||
$(
|
||||
impl NumFromBytes for $t {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error> {
|
||||
let size = mem::size_of::<Self>();
|
||||
let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok());
|
||||
|
||||
if let Some(slice) = buffer_slice {
|
||||
Ok(Self::from_le_bytes(slice))
|
||||
} else {
|
||||
error!(
|
||||
"read_num: buffer is too short to read num of size {} (buffer len: {})",
|
||||
size, buffer.len()
|
||||
);
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
num_from_bytes_impl!(usize);
|
||||
|
||||
fn read_num<T>(buffer: &[u8]) -> Result<T, Error>
|
||||
where
|
||||
T: NumFromBytes,
|
||||
{
|
||||
T::from_le_bytes_slice(buffer)
|
||||
}
|
||||
|
||||
pub fn run(
|
||||
sync_pipe: usize,
|
||||
kernel_schemes: &KernelSchemeMap,
|
||||
initfs_cap: usize,
|
||||
proc_cap: usize,
|
||||
scheme_creation_cap: usize,
|
||||
) -> ! {
|
||||
let socket = Socket::create_inner(scheme_creation_cap, false)
|
||||
.expect("failed to open init namespace scheme socket");
|
||||
|
||||
let mut schemes = HashMap::default();
|
||||
for (scheme, fd) in kernel_schemes.0.iter() {
|
||||
schemes.insert(scheme.as_str().to_string(), *fd);
|
||||
}
|
||||
schemes.insert("proc".to_string(), proc_cap);
|
||||
schemes.insert("initfs".to_string(), initfs_cap);
|
||||
|
||||
let mut scheme = NamespaceScheme::new(&socket, schemes, scheme_creation_cap);
|
||||
|
||||
// send namespace fd to bootstrap
|
||||
let new_id = scheme.next_id;
|
||||
scheme.add_namespace(new_id, scheme.root_namespace.clone(), NsPermissions::all());
|
||||
scheme.next_id += 1;
|
||||
let cap_fd = scheme
|
||||
.socket
|
||||
.create_this_scheme_fd(0, new_id, 0, 0)
|
||||
.expect("nsmgr: failed to create namespace fd");
|
||||
let _ = syscall::call_wo(sync_pipe, &cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
|
||||
let _ = syscall::close(sync_pipe);
|
||||
|
||||
log::info!("bootstrap: namespace scheme start!");
|
||||
loop {
|
||||
let Some(req) = socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
.expect("bootstrap: failed to read scheme request from kernel")
|
||||
else {
|
||||
break;
|
||||
};
|
||||
match req.kind() {
|
||||
RequestKind::Call(req) => {
|
||||
let resp = req.handle_sync(&mut scheme);
|
||||
|
||||
if !socket
|
||||
.write_response(resp, SignalBehavior::Restart)
|
||||
.expect("bootstrap: failed to write scheme response to kernel")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
RequestKind::OnClose { id } => scheme.on_close(id),
|
||||
RequestKind::SendFd(sendfd_request) => {
|
||||
let result = scheme.on_sendfd(&sendfd_request);
|
||||
let resp = Response::new(result, sendfd_request);
|
||||
if !socket
|
||||
.write_response(resp, SignalBehavior::Restart)
|
||||
.expect("bootstrap: failed to write scheme response to kernel")
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
unreachable!()
|
||||
}
|
||||
+59
-34
@@ -1,6 +1,6 @@
|
||||
#![no_std]
|
||||
#![allow(internal_features)]
|
||||
#![feature(core_intrinsics, str_from_raw_parts)]
|
||||
#![feature(core_intrinsics, str_from_raw_parts, never_type)]
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
#[path = "aarch64.rs"]
|
||||
@@ -20,6 +20,7 @@ pub mod arch;
|
||||
|
||||
pub mod exec;
|
||||
pub mod initfs;
|
||||
pub mod initnsmgr;
|
||||
pub mod procmgr;
|
||||
pub mod start;
|
||||
|
||||
@@ -27,7 +28,9 @@ extern crate alloc;
|
||||
|
||||
use core::cell::UnsafeCell;
|
||||
|
||||
use alloc::collections::btree_map::BTreeMap;
|
||||
use syscall::data::Map;
|
||||
use syscall::data::{GlobalSchemes, KernelSchemeInfo};
|
||||
use syscall::flag::MapFlags;
|
||||
|
||||
#[panic_handler]
|
||||
@@ -71,23 +74,25 @@ const HEAP_INCREASE_BY: usize = SIZE;
|
||||
|
||||
unsafe impl alloc::alloc::GlobalAlloc for Allocator {
|
||||
unsafe fn alloc(&self, layout: core::alloc::Layout) -> *mut u8 {
|
||||
let state = &mut (*ALLOC_STATE.0.get());
|
||||
let state = unsafe { &mut (*ALLOC_STATE.0.get()) };
|
||||
let heap = state.heap.get_or_insert_with(|| {
|
||||
state.heap_top = HEAP_OFF + SIZE;
|
||||
let _ = syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size: SIZE,
|
||||
address: HEAP_OFF,
|
||||
flags: MapFlags::PROT_WRITE
|
||||
| MapFlags::PROT_READ
|
||||
| MapFlags::MAP_PRIVATE
|
||||
| MapFlags::MAP_FIXED_NOREPLACE,
|
||||
},
|
||||
)
|
||||
let _ = unsafe {
|
||||
syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size: SIZE,
|
||||
address: HEAP_OFF,
|
||||
flags: MapFlags::PROT_WRITE
|
||||
| MapFlags::PROT_READ
|
||||
| MapFlags::MAP_PRIVATE
|
||||
| MapFlags::MAP_FIXED_NOREPLACE,
|
||||
},
|
||||
)
|
||||
}
|
||||
.expect("failed to map initial heap");
|
||||
linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE)
|
||||
unsafe { linked_list_allocator::Heap::new(HEAP_OFF as *mut u8, SIZE) }
|
||||
});
|
||||
|
||||
match heap.allocate_first_fit(layout) {
|
||||
@@ -97,31 +102,51 @@ unsafe impl alloc::alloc::GlobalAlloc for Allocator {
|
||||
return core::ptr::null_mut();
|
||||
}
|
||||
|
||||
let _ = syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size: HEAP_INCREASE_BY,
|
||||
address: state.heap_top,
|
||||
flags: MapFlags::PROT_WRITE
|
||||
| MapFlags::PROT_READ
|
||||
| MapFlags::MAP_PRIVATE
|
||||
| MapFlags::MAP_FIXED_NOREPLACE,
|
||||
},
|
||||
)
|
||||
let _ = unsafe {
|
||||
syscall::fmap(
|
||||
!0,
|
||||
&Map {
|
||||
offset: 0,
|
||||
size: HEAP_INCREASE_BY,
|
||||
address: state.heap_top,
|
||||
flags: MapFlags::PROT_WRITE
|
||||
| MapFlags::PROT_READ
|
||||
| MapFlags::MAP_PRIVATE
|
||||
| MapFlags::MAP_FIXED_NOREPLACE,
|
||||
},
|
||||
)
|
||||
}
|
||||
.expect("failed to extend heap");
|
||||
heap.extend(HEAP_INCREASE_BY);
|
||||
unsafe { heap.extend(HEAP_INCREASE_BY) };
|
||||
state.heap_top += HEAP_INCREASE_BY;
|
||||
|
||||
return self.alloc(layout);
|
||||
return unsafe { self.alloc(layout) };
|
||||
}
|
||||
}
|
||||
}
|
||||
unsafe fn dealloc(&self, ptr: *mut u8, layout: core::alloc::Layout) {
|
||||
(&mut *ALLOC_STATE.0.get())
|
||||
.heap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
|
||||
unsafe {
|
||||
(&mut *ALLOC_STATE.0.get())
|
||||
.heap
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.deallocate(core::ptr::NonNull::new(ptr).unwrap(), layout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct KernelSchemeMap(BTreeMap<GlobalSchemes, usize>);
|
||||
impl KernelSchemeMap {
|
||||
fn new(kernel_scheme_infos: &[KernelSchemeInfo]) -> Self {
|
||||
let mut map = BTreeMap::new();
|
||||
for info in kernel_scheme_infos {
|
||||
if let Some(scheme_id) = GlobalSchemes::try_from_raw(info.scheme_id) {
|
||||
map.insert(scheme_id, info.fd);
|
||||
}
|
||||
}
|
||||
Self(map)
|
||||
}
|
||||
fn get(&self, scheme: GlobalSchemes) -> Option<&usize> {
|
||||
self.0.get(&scheme)
|
||||
}
|
||||
}
|
||||
|
||||
+64
-14
@@ -29,15 +29,18 @@ use redox_scheme::{
|
||||
Socket, Tag,
|
||||
};
|
||||
use slab::Slab;
|
||||
use syscall::data::GlobalSchemes;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED, ECHILD,
|
||||
EEXIST, EINTR, EINVAL, ENOENT, ENOSYS, EOPNOTSUPP, EOWNERDEAD, EPERM, ERESTART, ESRCH,
|
||||
CallFlags, ContextStatus, ContextVerb, CtxtStsBuf, EACCES, EAGAIN, EBADF, EBADFD, ECANCELED,
|
||||
ECHILD, EEXIST, EINTR, EINVAL, ENOENT, ENOSYS, EOPNOTSUPP, EOWNERDEAD, EPERM, ERESTART, ESRCH,
|
||||
EWOULDBLOCK, Error, Event, EventFlags, FobtainFdFlags, MapFlags, O_ACCMODE, O_CREAT, O_RDONLY,
|
||||
PAGE_SIZE, ProcSchemeAttrs, Result, SenderInfo, SetSighandlerData, SigProcControl, Sigcontrol,
|
||||
sig_bit,
|
||||
};
|
||||
|
||||
use crate::KernelSchemeMap;
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
|
||||
enum VirtualId {
|
||||
KernelId(Id),
|
||||
@@ -45,13 +48,31 @@ enum VirtualId {
|
||||
InternalId(u64),
|
||||
}
|
||||
|
||||
pub fn run(write_fd: usize, auth: &FdGuard) {
|
||||
let socket = Socket::nonblock("proc").expect("failed to open proc scheme socket");
|
||||
pub fn run(
|
||||
write_fd: usize,
|
||||
auth: &FdGuard,
|
||||
kernel_schemes: &KernelSchemeMap,
|
||||
scheme_creation_cap: usize,
|
||||
) -> ! {
|
||||
let socket =
|
||||
Socket::create_inner(scheme_creation_cap, true).expect("failed to open proc scheme socket");
|
||||
let _ = syscall::close(scheme_creation_cap);
|
||||
|
||||
// TODO?
|
||||
let socket_ident = socket.inner().raw();
|
||||
|
||||
let queue = RawEventQueue::new().expect("failed to create event queue");
|
||||
let queue = RawEventQueue::new(
|
||||
*kernel_schemes
|
||||
.get(GlobalSchemes::Event)
|
||||
.expect("failed to get event fd"),
|
||||
)
|
||||
.expect("failed to create event queue");
|
||||
for (scheme, fd) in kernel_schemes.0.iter() {
|
||||
if *scheme == GlobalSchemes::Proc {
|
||||
continue;
|
||||
}
|
||||
let _ = syscall::close(*fd);
|
||||
}
|
||||
|
||||
queue
|
||||
.subscribe(socket.inner().raw(), socket_ident, EventFlags::EVENT_READ)
|
||||
@@ -59,8 +80,14 @@ pub fn run(write_fd: usize, auth: &FdGuard) {
|
||||
|
||||
let mut scheme = ProcScheme::new(auth, &queue);
|
||||
|
||||
// send open-capability to bootstrap
|
||||
let new_id = scheme.handles.insert(Handle::SchemeRoot);
|
||||
let cap_fd = socket
|
||||
.create_this_scheme_fd(0, new_id, 0, 0)
|
||||
.expect("failed to issue procmgr root fd");
|
||||
|
||||
log::debug!("process manager started");
|
||||
let _ = syscall::write(write_fd, &[0]);
|
||||
let _ = syscall::call_wo(write_fd, &cap_fd.to_ne_bytes(), CallFlags::FD, &[]);
|
||||
let _ = syscall::close(write_fd);
|
||||
|
||||
let mut states = HashMap::<VirtualId, PendingState, DefaultHashBuilder>::new();
|
||||
@@ -205,8 +232,8 @@ fn handle_scheme<'a>(
|
||||
Err(req) => return Response::ready_err(ENOSYS, req),
|
||||
};
|
||||
match op {
|
||||
Op::Open(op) => Ready(Response::open_dup_like(
|
||||
scheme.on_open(op.path(), op.flags, &caller),
|
||||
Op::OpenAt(op) => Ready(Response::open_dup_like(
|
||||
scheme.on_openat(op.fd, op.path(), *op.flags(), op.fcntl_flags, &caller),
|
||||
op,
|
||||
)),
|
||||
Op::Dup(op) => Ready(Response::open_dup_like(scheme.on_dup(op.fd, op.buf()), op)),
|
||||
@@ -523,6 +550,9 @@ enum Handle {
|
||||
|
||||
// A handle that grants the holder the capability to obtain process credentials.
|
||||
ProcCredsCapability,
|
||||
|
||||
// A handle that grants the holder the capability to open process scheme resource.
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
@@ -536,8 +566,10 @@ enum WaitpidTarget {
|
||||
// backend
|
||||
struct RawEventQueue(FdGuard);
|
||||
impl RawEventQueue {
|
||||
pub fn new() -> Result<Self> {
|
||||
FdGuard::open("/scheme/event", O_CREAT).map(Self)
|
||||
pub fn new(cap_fd: usize) -> Result<Self> {
|
||||
syscall::openat(cap_fd, "", O_CREAT, 0)
|
||||
.map(FdGuard::new)
|
||||
.map(Self)
|
||||
}
|
||||
pub fn subscribe(&self, fd: usize, ident: usize, flags: EventFlags) -> Result<()> {
|
||||
self.0.write(&Event {
|
||||
@@ -586,7 +618,11 @@ impl<'a> ProcScheme<'a> {
|
||||
match self.handles[req.id()] {
|
||||
ref mut st @ Handle::Init => {
|
||||
let mut fd_out = usize::MAX;
|
||||
if let Err(e) = req.obtain_fd(socket, FobtainFdFlags::empty(), core::slice::from_mut(&mut fd_out)) {
|
||||
if let Err(e) = req.obtain_fd(
|
||||
socket,
|
||||
FobtainFdFlags::empty(),
|
||||
core::slice::from_mut(&mut fd_out),
|
||||
) {
|
||||
return Response::new(Err(e), req);
|
||||
};
|
||||
let fd = FdGuard::new(fd_out);
|
||||
@@ -765,7 +801,18 @@ impl<'a> ProcScheme<'a> {
|
||||
self.thread_lookup.insert(ident, thread_weak);
|
||||
Ok(thread)
|
||||
}
|
||||
fn on_open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn on_openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
match self.handles[fd] {
|
||||
Handle::SchemeRoot => {}
|
||||
_ => return Err(Error::new(EACCES)),
|
||||
};
|
||||
let path = path.trim_start_matches('/');
|
||||
Ok(match path {
|
||||
"init" => {
|
||||
@@ -833,7 +880,7 @@ impl<'a> ProcScheme<'a> {
|
||||
buf[..len].copy_from_slice(&src_buf[..len]);
|
||||
Ok(len)
|
||||
}
|
||||
Handle::Init | Handle::Thread(_) | Handle::ProcCredsCapability => {
|
||||
Handle::Init | Handle::Thread(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
}
|
||||
@@ -882,7 +929,9 @@ impl<'a> ProcScheme<'a> {
|
||||
fd: thread.fd.dup(buf)?.take(),
|
||||
})
|
||||
}
|
||||
Handle::Init | Handle::Ps(_) | Handle::ProcCredsCapability => Err(Error::new(EBADF)),
|
||||
Handle::Init | Handle::Ps(_) | Handle::ProcCredsCapability | Handle::SchemeRoot => {
|
||||
Err(Error::new(EBADF))
|
||||
}
|
||||
}
|
||||
}
|
||||
fn on_call(
|
||||
@@ -1063,6 +1112,7 @@ impl<'a> ProcScheme<'a> {
|
||||
_ => Response::ready_err(EINVAL, op),
|
||||
}
|
||||
}
|
||||
Handle::SchemeRoot => Response::ready_err(EBADF, op),
|
||||
}
|
||||
}
|
||||
fn on_getpgid(&mut self, caller_pid: ProcessId, target_pid: ProcessId) -> Result<ProcessId> {
|
||||
|
||||
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 1 << 47; // Assuming Sv48; it should work with Sv57 also
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
|
||||
+33
-29
@@ -46,37 +46,41 @@ pub unsafe extern "C" fn start() -> ! {
|
||||
let (rodata_start, rodata_end) = offsets::rodata();
|
||||
let (data_start, data_end) = offsets::data_and_bss();
|
||||
|
||||
let _ = syscall::open("/scheme/debug", syscall::O_RDONLY); // stdin
|
||||
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stdout
|
||||
let _ = syscall::open("/scheme/debug", syscall::O_WRONLY); // stderr
|
||||
// NOTE: Assuming the debug scheme root fd is always placed at this position
|
||||
let debug_fd = syscall::UPPER_FDTBL_TAG + syscall::data::GlobalSchemes::Debug as usize;
|
||||
let _ = syscall::openat(debug_fd, "", syscall::O_RDONLY, 0); // stdin
|
||||
let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stdout
|
||||
let _ = syscall::openat(debug_fd, "", syscall::O_WRONLY, 0); // stderr
|
||||
|
||||
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
|
||||
.expect("mprotect failed for initfs header page");
|
||||
unsafe {
|
||||
let _ = syscall::mprotect(4096, 4096, MapFlags::PROT_READ | MapFlags::MAP_PRIVATE)
|
||||
.expect("mprotect failed for initfs header page");
|
||||
|
||||
let _ = syscall::mprotect(
|
||||
text_start,
|
||||
text_end - text_start,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .text");
|
||||
let _ = syscall::mprotect(
|
||||
rodata_start,
|
||||
rodata_end - rodata_start,
|
||||
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .rodata");
|
||||
let _ = syscall::mprotect(
|
||||
data_start,
|
||||
data_end - data_start,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .data/.bss");
|
||||
let _ = syscall::mprotect(
|
||||
data_end,
|
||||
crate::arch::STACK_START - data_end,
|
||||
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for rest of memory");
|
||||
let _ = syscall::mprotect(
|
||||
text_start,
|
||||
text_end - text_start,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_EXEC | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .text");
|
||||
let _ = syscall::mprotect(
|
||||
rodata_start,
|
||||
rodata_end - rodata_start,
|
||||
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .rodata");
|
||||
let _ = syscall::mprotect(
|
||||
data_start,
|
||||
data_end - data_start,
|
||||
MapFlags::PROT_READ | MapFlags::PROT_WRITE | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for .data/.bss");
|
||||
let _ = syscall::mprotect(
|
||||
data_end,
|
||||
crate::arch::STACK_START - data_end,
|
||||
MapFlags::PROT_READ | MapFlags::MAP_PRIVATE,
|
||||
)
|
||||
.expect("mprotect failed for rest of memory");
|
||||
}
|
||||
|
||||
// FIXME make the initfs read-only
|
||||
|
||||
|
||||
@@ -3,7 +3,7 @@ use syscall::{data::Map, flag::MapFlags, number::SYS_FMAP};
|
||||
|
||||
const STACK_SIZE: usize = 64 * 1024; // 64 KiB
|
||||
pub const USERMODE_END: usize = 0x0000_8000_0000_0000;
|
||||
pub const STACK_START: usize = USERMODE_END - STACK_SIZE;
|
||||
pub const STACK_START: usize = USERMODE_END - syscall::KERNEL_METADATA_SIZE - STACK_SIZE;
|
||||
|
||||
static MAP: Map = Map {
|
||||
offset: 0,
|
||||
|
||||
@@ -18,11 +18,11 @@ redox_event.workspace = true
|
||||
rustc-hash = "1.1.0"
|
||||
thiserror = "1"
|
||||
ron = "0.8.1"
|
||||
arrayvec = "0.7.6"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
|
||||
amlserde = { path = "../amlserde" }
|
||||
common = { path = "../common" }
|
||||
daemon = { path = "../../daemon" }
|
||||
libredox.workspace = true
|
||||
redox-scheme.workspace = true
|
||||
arrayvec = "0.7.6"
|
||||
serde = { version = "1.0.228", features = ["derive"] }
|
||||
|
||||
+16
-11
@@ -257,12 +257,12 @@ impl AmlSymbols {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
pub fn init(&mut self, pci_fd: Option<&libredox::Fd>) -> Result<(), Box<dyn Error>> {
|
||||
if self.aml_context.is_some() {
|
||||
return Err("AML interpreter already initialized".into());
|
||||
}
|
||||
let format_err = |err| format!("{:?}", err);
|
||||
let handler = AmlPhysMemHandler::new(Arc::clone(&self.page_cache));
|
||||
let handler = AmlPhysMemHandler::new(pci_fd, Arc::clone(&self.page_cache));
|
||||
//TODO: use these parsed tables for the rest of acpid
|
||||
let rsdp_address = usize::from_str_radix(&std::env::var("RSDP_ADDR")?, 16)?;
|
||||
let tables =
|
||||
@@ -276,10 +276,12 @@ impl AmlSymbols {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn aml_context_mut(&mut self) -> &mut Interpreter<AmlPhysMemHandler> {
|
||||
// PCID must be running by this time!
|
||||
pub fn aml_context_mut(
|
||||
&mut self,
|
||||
pci_fd: Option<&libredox::Fd>,
|
||||
) -> &mut Interpreter<AmlPhysMemHandler> {
|
||||
if self.aml_context.is_none() {
|
||||
match self.init() {
|
||||
match self.init(pci_fd) {
|
||||
Ok(()) => (),
|
||||
Err(err) => {
|
||||
log::error!("failed to initialize AML context: {}", err);
|
||||
@@ -303,8 +305,8 @@ impl AmlSymbols {
|
||||
None
|
||||
}
|
||||
|
||||
pub fn build_cache(&mut self) {
|
||||
let aml_context = self.aml_context_mut();
|
||||
pub fn build_cache(&mut self, pci_fd: Option<&libredox::Fd>) {
|
||||
let aml_context = self.aml_context_mut(pci_fd);
|
||||
|
||||
let mut symbol_list: Vec<(AmlName, String)> = Vec::with_capacity(5000);
|
||||
|
||||
@@ -391,7 +393,7 @@ impl AcpiContext {
|
||||
args: Vec<AmlSerdeValue>,
|
||||
) -> Result<AmlSerdeValue, AmlEvalError> {
|
||||
let mut symbols = self.aml_symbols.write();
|
||||
let interpreter = symbols.aml_context_mut();
|
||||
let interpreter = symbols.aml_context_mut(None);
|
||||
interpreter.acquire_global_lock(16)?;
|
||||
|
||||
let args = args
|
||||
@@ -520,14 +522,17 @@ impl AcpiContext {
|
||||
}
|
||||
|
||||
pub fn aml_lookup(&self, symbol: &str) -> Option<String> {
|
||||
if let Ok(aml_symbols) = self.aml_symbols() {
|
||||
if let Ok(aml_symbols) = self.aml_symbols(None) {
|
||||
aml_symbols.lookup(symbol)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub fn aml_symbols(&self) -> Result<RwLockReadGuard<'_, AmlSymbols>, AmlError> {
|
||||
pub fn aml_symbols(
|
||||
&self,
|
||||
pci_fd: Option<&libredox::Fd>,
|
||||
) -> Result<RwLockReadGuard<'_, AmlSymbols>, AmlError> {
|
||||
// return the cached value if it exists
|
||||
let symbols = self.aml_symbols.read();
|
||||
if !symbols.symbols_cache().is_empty() {
|
||||
@@ -541,7 +546,7 @@ impl AcpiContext {
|
||||
|
||||
let mut aml_symbols = self.aml_symbols.write();
|
||||
|
||||
aml_symbols.build_cache();
|
||||
aml_symbols.build_cache(pci_fd);
|
||||
|
||||
// return the cached value
|
||||
Ok(RwLockWriteGuard::downgrade(aml_symbols))
|
||||
|
||||
@@ -146,22 +146,17 @@ pub struct AmlPhysMemHandler {
|
||||
/// Read from a physical address.
|
||||
/// Generic parameter must be u8, u16, u32 or u64.
|
||||
impl AmlPhysMemHandler {
|
||||
pub fn new(page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
|
||||
//TODO: have PCID send a socket?
|
||||
let pci_fd = Arc::new(
|
||||
match libredox::Fd::open(
|
||||
"/scheme/pci/access",
|
||||
libredox::flag::O_RDWR | libredox::flag::O_CLOEXEC,
|
||||
0,
|
||||
) {
|
||||
Ok(fd) => Some(fd),
|
||||
Err(err) => {
|
||||
log::error!("failed to open /scheme/pci/access: {}", err);
|
||||
None
|
||||
}
|
||||
},
|
||||
);
|
||||
Self { page_cache, pci_fd }
|
||||
pub fn new(pci_fd_opt: Option<&libredox::Fd>, page_cache: Arc<Mutex<AmlPageCache>>) -> Self {
|
||||
let pci_fd = if let Some(pci_fd) = pci_fd_opt {
|
||||
Some(libredox::Fd::new(pci_fd.raw()))
|
||||
} else {
|
||||
log::error!("pci_fd is not registered");
|
||||
None
|
||||
};
|
||||
Self {
|
||||
page_cache,
|
||||
pci_fd: Arc::new(pci_fd),
|
||||
}
|
||||
}
|
||||
|
||||
fn pci_call_metadata(kind: u8, addr: PciAddress, off: u16) -> [u64; 2] {
|
||||
|
||||
@@ -6,7 +6,10 @@ use std::sync::Arc;
|
||||
|
||||
use ::acpi::aml::op_region::{RegionHandler, RegionSpace};
|
||||
use event::{EventFlags, RawEventQueue};
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{
|
||||
scheme::{register_sync_scheme, SchemeSync},
|
||||
RequestKind, Response, SignalBehavior, Socket,
|
||||
};
|
||||
use syscall::{EAGAIN, EWOULDBLOCK};
|
||||
|
||||
mod acpi;
|
||||
@@ -25,6 +28,8 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
common::file_level(),
|
||||
);
|
||||
|
||||
log::info!("acpid start");
|
||||
|
||||
let rxsdt_raw_data: Arc<[u8]> = std::fs::read("/scheme/kernel.acpi/rxsdt")
|
||||
.expect("acpid: failed to read `/scheme/kernel.acpi/rxsdt`")
|
||||
.into();
|
||||
@@ -78,11 +83,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
.expect("acpid: failed to open `/scheme/kernel.acpi/kstop`");
|
||||
|
||||
let mut event_queue = RawEventQueue::new().expect("acpid: failed to create event queue");
|
||||
let socket = Socket::nonblock("acpi").expect("acpid: failed to create disk scheme");
|
||||
let socket = Socket::nonblock().expect("acpid: failed to create disk scheme");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
//TODO: needs to open /scheme/pci/access later! libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
|
||||
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context, &socket);
|
||||
|
||||
event_queue
|
||||
.subscribe(shutdown_pipe.as_raw_fd() as usize, 0, EventFlags::READ)
|
||||
@@ -91,7 +94,12 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
.subscribe(socket.inner().raw(), 1, EventFlags::READ)
|
||||
.expect("acpid: failed to register scheme socket for event queue");
|
||||
|
||||
let mut scheme = self::scheme::AcpiScheme::new(&acpi_context);
|
||||
register_sync_scheme(&socket, "acpi", &mut scheme)
|
||||
.expect("acpid: failed to register acpi scheme to namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("acpid: failed to enter null namespace");
|
||||
|
||||
let mut mounted = true;
|
||||
while mounted {
|
||||
@@ -119,7 +127,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
match req.kind() {
|
||||
RequestKind::Call(call) => {
|
||||
let response = call.handle_sync(&mut scheme);
|
||||
@@ -130,6 +137,15 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
RequestKind::OnClose { id } => {
|
||||
scheme.on_close(id);
|
||||
}
|
||||
RequestKind::SendFd(sendfd_request) => {
|
||||
let result = scheme.on_sendfd(&sendfd_request);
|
||||
socket
|
||||
.write_response(
|
||||
Response::new(result, sendfd_request),
|
||||
SignalBehavior::Restart,
|
||||
)
|
||||
.expect("acpid: failed to write response");
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
@@ -151,5 +167,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
daemon::Daemon::new(daemon);
|
||||
}
|
||||
|
||||
+120
-35
@@ -2,29 +2,33 @@ use acpi::aml::namespace::AmlName;
|
||||
use amlserde::aml_serde_name::to_aml_format;
|
||||
use amlserde::AmlSerdeValue;
|
||||
use core::str;
|
||||
use libredox::Fd;
|
||||
use parking_lot::RwLockReadGuard;
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket};
|
||||
use ron::de::SpannedError;
|
||||
use std::collections::BTreeMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::str::FromStr;
|
||||
use syscall::dirent::{DirEntry, DirentBuf, DirentKind};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::FobtainFdFlags;
|
||||
|
||||
use syscall::data::Stat;
|
||||
use syscall::error::{Error, Result};
|
||||
use syscall::error::{EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
|
||||
use syscall::error::{EACCES, EBADF, EBADFD, EINVAL, EIO, EISDIR, ENOENT, ENOTDIR};
|
||||
use syscall::flag::{MODE_DIR, MODE_FILE};
|
||||
use syscall::flag::{O_ACCMODE, O_DIRECTORY, O_RDONLY, O_STAT, O_SYMLINK};
|
||||
use syscall::{EOPNOTSUPP, EOVERFLOW, EPERM};
|
||||
|
||||
use crate::acpi::{AcpiContext, AmlSymbols, SdtSignature};
|
||||
|
||||
pub struct AcpiScheme<'acpi> {
|
||||
pub struct AcpiScheme<'acpi, 'sock> {
|
||||
ctx: &'acpi AcpiContext,
|
||||
handles: BTreeMap<usize, Handle<'acpi>>,
|
||||
next_fd: usize,
|
||||
pci_fd: Option<Fd>,
|
||||
socket: &'sock Socket,
|
||||
}
|
||||
|
||||
struct Handle<'a> {
|
||||
@@ -38,6 +42,8 @@ enum HandleKind<'a> {
|
||||
Table(SdtSignature),
|
||||
Symbols(RwLockReadGuard<'a, AmlSymbols>),
|
||||
Symbol { name: String, description: String },
|
||||
SchemeRoot,
|
||||
RegisterPci,
|
||||
}
|
||||
|
||||
impl HandleKind<'_> {
|
||||
@@ -48,6 +54,8 @@ impl HandleKind<'_> {
|
||||
Self::Table(_) => false,
|
||||
Self::Symbols(_) => true,
|
||||
Self::Symbol { .. } => false,
|
||||
Self::SchemeRoot => false,
|
||||
Self::RegisterPci => false,
|
||||
}
|
||||
}
|
||||
fn len(&self, acpi_ctx: &AcpiContext) -> Result<usize> {
|
||||
@@ -60,16 +68,19 @@ impl HandleKind<'_> {
|
||||
Self::Symbol { description, .. } => description.len(),
|
||||
// Directories
|
||||
Self::TopLevel | Self::Symbols(_) | Self::Tables => 0,
|
||||
Self::SchemeRoot | Self::RegisterPci => return Err(Error::new(EBADF)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<'acpi> AcpiScheme<'acpi> {
|
||||
pub fn new(ctx: &'acpi AcpiContext) -> Self {
|
||||
impl<'acpi, 'sock> AcpiScheme<'acpi, 'sock> {
|
||||
pub fn new(ctx: &'acpi AcpiContext, socket: &'sock Socket) -> Self {
|
||||
Self {
|
||||
ctx,
|
||||
handles: BTreeMap::new(),
|
||||
next_fd: 0,
|
||||
pci_fd: None,
|
||||
socket,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -148,53 +159,92 @@ fn parse_table(table: &[u8]) -> Option<SdtSignature> {
|
||||
})
|
||||
}
|
||||
|
||||
impl SchemeSync for AcpiScheme<'_> {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
impl SchemeSync for AcpiScheme<'_, '_> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let fd = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
|
||||
self.handles.insert(
|
||||
fd,
|
||||
Handle {
|
||||
stat: false,
|
||||
kind: HandleKind::SchemeRoot,
|
||||
allowed_to_eval: false,
|
||||
},
|
||||
);
|
||||
Ok(fd)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let path = path.trim_start_matches('/');
|
||||
|
||||
let flag_stat = flags & O_STAT == O_STAT;
|
||||
let flag_dir = flags & O_DIRECTORY == O_DIRECTORY;
|
||||
|
||||
// TODO: arrayvec
|
||||
let components = {
|
||||
let mut v = arrayvec::ArrayVec::<&str, 3>::new();
|
||||
let it = path.split('/');
|
||||
for component in it.take(3) {
|
||||
v.push(component);
|
||||
}
|
||||
let kind = match handle.kind {
|
||||
HandleKind::SchemeRoot => {
|
||||
// TODO: arrayvec
|
||||
let components = {
|
||||
let mut v = arrayvec::ArrayVec::<&str, 3>::new();
|
||||
let it = path.split('/');
|
||||
for component in it.take(3) {
|
||||
v.push(component);
|
||||
}
|
||||
|
||||
v
|
||||
};
|
||||
v
|
||||
};
|
||||
|
||||
let kind = match &*components {
|
||||
[""] => HandleKind::TopLevel,
|
||||
["tables"] => HandleKind::Tables,
|
||||
match &*components {
|
||||
[""] => HandleKind::TopLevel,
|
||||
["register_pci"] => HandleKind::RegisterPci,
|
||||
["tables"] => HandleKind::Tables,
|
||||
|
||||
["tables", table] => {
|
||||
let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?;
|
||||
HandleKind::Table(signature)
|
||||
}
|
||||
["tables", table] => {
|
||||
let signature = parse_table(table.as_bytes()).ok_or(Error::new(ENOENT))?;
|
||||
HandleKind::Table(signature)
|
||||
}
|
||||
|
||||
["symbols"] => {
|
||||
if let Ok(aml_symbols) = self.ctx.aml_symbols() {
|
||||
HandleKind::Symbols(aml_symbols)
|
||||
} else {
|
||||
return Err(Error::new(EIO));
|
||||
["symbols"] => {
|
||||
if let Ok(aml_symbols) = self.ctx.aml_symbols(self.pci_fd.as_ref()) {
|
||||
HandleKind::Symbols(aml_symbols)
|
||||
} else {
|
||||
return Err(Error::new(EIO));
|
||||
}
|
||||
}
|
||||
|
||||
["symbols", symbol] => {
|
||||
if let Some(description) = self.ctx.aml_lookup(symbol) {
|
||||
HandleKind::Symbol {
|
||||
name: (*symbol).to_owned(),
|
||||
description,
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
}
|
||||
}
|
||||
|
||||
["symbols", symbol] => {
|
||||
if let Some(description) = self.ctx.aml_lookup(symbol) {
|
||||
HandleKind::Symbols(ref aml_symbols) => {
|
||||
if let Some(description) = aml_symbols.lookup(path) {
|
||||
HandleKind::Symbol {
|
||||
name: (*symbol).to_owned(),
|
||||
name: (*path).to_owned(),
|
||||
description,
|
||||
}
|
||||
} else {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
}
|
||||
|
||||
_ => return Err(Error::new(ENOENT)),
|
||||
_ => return Err(Error::new(EACCES)),
|
||||
};
|
||||
|
||||
if kind.is_dir() && !flag_dir && !flag_stat {
|
||||
@@ -419,9 +469,44 @@ impl SchemeSync for AcpiScheme<'_> {
|
||||
|
||||
Ok(result_len)
|
||||
}
|
||||
|
||||
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
|
||||
let id = sendfd_request.id();
|
||||
let num_fds = sendfd_request.num_fds();
|
||||
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle.kind, HandleKind::RegisterPci) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if num_fds == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
if num_fds > 1 {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
let mut new_fd = usize::MAX;
|
||||
if let Err(e) = sendfd_request.obtain_fd(
|
||||
&self.socket,
|
||||
FobtainFdFlags::UPPER_TBL,
|
||||
std::slice::from_mut(&mut new_fd),
|
||||
) {
|
||||
return Err(e);
|
||||
}
|
||||
let new_fd = libredox::Fd::new(new_fd);
|
||||
|
||||
if self.pci_fd.is_some() {
|
||||
return Err(Error::new(EINVAL));
|
||||
} else {
|
||||
self.pci_fd = Some(new_fd);
|
||||
}
|
||||
|
||||
Ok(num_fds)
|
||||
}
|
||||
}
|
||||
|
||||
impl AcpiScheme<'_> {
|
||||
impl AcpiScheme<'_, '_> {
|
||||
pub fn on_close(&mut self, id: usize) {
|
||||
self.handles.remove(&id);
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ const SUB_BUFF_SIZE: usize = 2048;
|
||||
|
||||
enum Handle {
|
||||
Todo,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -262,7 +263,26 @@ impl Ac97 {
|
||||
}
|
||||
|
||||
impl SchemeSync for Ac97 {
|
||||
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
_path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
{
|
||||
let mut handles = self.handles.lock();
|
||||
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
if ctx.uid == 0 {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, Handle::Todo);
|
||||
@@ -285,7 +305,10 @@ impl SchemeSync for Ac97 {
|
||||
) -> Result<usize> {
|
||||
{
|
||||
let mut handles = self.handles.lock();
|
||||
let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::Todo) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
}
|
||||
|
||||
if buf.len() != SUB_BUFF_SIZE {
|
||||
@@ -310,8 +333,13 @@ impl SchemeSync for Ac97 {
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let mut handles = self.handles.lock();
|
||||
let _handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
{
|
||||
let mut handles = self.handles.lock();
|
||||
let handle = handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::Todo) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
}
|
||||
|
||||
let mut i = 0;
|
||||
let scheme_path = b"/scheme/audiohw";
|
||||
|
||||
@@ -11,6 +11,7 @@ use std::usize;
|
||||
|
||||
use event::{user_data, EventQueue};
|
||||
use pcid_interface::PciFunctionHandle;
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::Socket;
|
||||
use std::cell::RefCell;
|
||||
@@ -19,6 +20,7 @@ use std::cell::RefCell;
|
||||
pub mod device;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
@@ -51,10 +53,10 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
|
||||
|
||||
let mut irq_file = irq.irq_handle("ac97d");
|
||||
|
||||
let socket = Socket::nonblock().expect("ac97d: failed to create socket");
|
||||
let device = RefCell::new(unsafe {
|
||||
device::Ac97::new(bar0, bar1).expect("ac97d: failed to allocate device")
|
||||
});
|
||||
let socket = Socket::nonblock("audiohw").expect("ac97d: failed to create socket");
|
||||
let mut readiness_based = ReadinessBased::new(&socket, 16);
|
||||
|
||||
user_data! {
|
||||
@@ -80,6 +82,8 @@ fn daemon(daemon: daemon::Daemon, pcid_handle: PciFunctionHandle) -> ! {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
register_sync_scheme(&socket, "audiohw", &mut *device.borrow_mut())
|
||||
.expect("ac97d: failed to register audiohw scheme to namespace");
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("ac97d: failed to enter null namespace");
|
||||
|
||||
@@ -68,6 +68,7 @@ enum Handle {
|
||||
Pcmout(usize, usize, usize), // Card, index, block_ptr
|
||||
Pcmin(usize, usize, usize), // Card, index, block_ptr
|
||||
StrBuf(Vec<u8>),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
#[repr(C, packed)]
|
||||
@@ -984,7 +985,26 @@ impl Drop for IntelHDA {
|
||||
}
|
||||
|
||||
impl SchemeSync for IntelHDA {
|
||||
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
{
|
||||
let mut handles = self.handles.lock();
|
||||
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
//let path: Vec<&str>;
|
||||
/*
|
||||
match str::from_utf8(_path) {
|
||||
|
||||
@@ -3,6 +3,7 @@ extern crate event;
|
||||
extern crate spin;
|
||||
extern crate syscall;
|
||||
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::Socket;
|
||||
use std::cell::RefCell;
|
||||
@@ -24,6 +25,7 @@ QEMU ICH9 8086:293E
|
||||
*/
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
@@ -60,12 +62,14 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
|
||||
|
||||
let event_queue =
|
||||
EventQueue::<Source>::new().expect("ihdad: Could not create event queue.");
|
||||
let socket = Socket::nonblock().expect("ihdad: failed to create socket");
|
||||
let device = RefCell::new(unsafe {
|
||||
hda::IntelHDA::new(address, vend_prod).expect("ihdad: failed to allocate device")
|
||||
});
|
||||
let socket = Socket::nonblock("audiohw").expect("ihdad: failed to create socket");
|
||||
let mut readiness_based = ReadinessBased::new(&socket, 16);
|
||||
|
||||
register_sync_scheme(&socket, "audiohw", &mut *device.borrow_mut())
|
||||
.expect("ihdad: failed to register audiohw scheme to namespace");
|
||||
daemon.ready();
|
||||
|
||||
event_queue
|
||||
|
||||
@@ -19,6 +19,7 @@ const SUB_BUFF_SIZE: usize = 2048;
|
||||
|
||||
enum Handle {
|
||||
Todo,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
@@ -185,7 +186,26 @@ impl Sb16 {
|
||||
}
|
||||
|
||||
impl SchemeSync for Sb16 {
|
||||
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
_path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
{
|
||||
let mut handles = self.handles.lock();
|
||||
let handle = handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
if ctx.uid == 0 {
|
||||
let id = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.lock().insert(id, Handle::Todo);
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
//#![deny(warnings)]
|
||||
|
||||
use libredox::{flag, Fd};
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::Socket;
|
||||
use std::cell::RefCell;
|
||||
@@ -34,9 +35,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
common::acquire_port_io_rights().expect("sb16d: failed to acquire port IO rights");
|
||||
|
||||
let socket = Socket::nonblock().expect("sb16d: failed to create socket");
|
||||
let device =
|
||||
RefCell::new(unsafe { device::Sb16::new(addr).expect("sb16d: failed to allocate device") });
|
||||
let socket = Socket::nonblock("audiohw").expect("sb16d: failed to create socket");
|
||||
let mut readiness_based = ReadinessBased::new(&socket, 16);
|
||||
|
||||
//TODO: error on multiple IRQs?
|
||||
@@ -64,6 +65,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
)
|
||||
.unwrap();
|
||||
|
||||
register_sync_scheme(&socket, "sb16d", &mut *device.borrow_mut())
|
||||
.expect("sb16d: failed to register audiohw scheme to namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("sb16d: failed to enter null namespace");
|
||||
|
||||
@@ -7,7 +7,7 @@ use libredox::call::MmapArgs;
|
||||
use libredox::{error::Result, flag, Fd};
|
||||
use syscall::PAGE_SIZE;
|
||||
|
||||
use crate::{MemoryType, VirtaddrTranslationHandle};
|
||||
use crate::{memory_root_fd, MemoryType, VirtaddrTranslationHandle};
|
||||
|
||||
/// Defines the platform-specific memory type for DMA operations
|
||||
///
|
||||
@@ -42,8 +42,8 @@ const DMA_MEMTY: MemoryType = {
|
||||
///
|
||||
/// - The request for the physical memory fails.
|
||||
pub(crate) fn phys_contiguous_fd() -> Result<Fd> {
|
||||
Fd::open(
|
||||
&format!("/scheme/memory/zeroed@{DMA_MEMTY}?phys_contiguous"),
|
||||
memory_root_fd().openat(
|
||||
&format!("zeroed@{DMA_MEMTY}?phys_contiguous"),
|
||||
flag::O_CLOEXEC,
|
||||
0,
|
||||
)
|
||||
|
||||
+34
-17
@@ -21,6 +21,28 @@ pub mod timeout;
|
||||
|
||||
pub use logger::{file_level, output_level, setup_logging};
|
||||
|
||||
use std::sync::OnceLock;
|
||||
|
||||
static MEMORY_ROOT_FD: OnceLock<libredox::Fd> = OnceLock::new();
|
||||
|
||||
pub fn init() {
|
||||
if MEMORY_ROOT_FD
|
||||
.set(
|
||||
libredox::Fd::open("/scheme/memory/scheme-root", 0, 0)
|
||||
.expect("drivers common: failed to open memory root fd"),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
panic!("drivers common: failed to set memory root fd");
|
||||
}
|
||||
}
|
||||
|
||||
pub fn memory_root_fd() -> &'static libredox::Fd {
|
||||
MEMORY_ROOT_FD
|
||||
.get()
|
||||
.expect("acpid: failed to get memory_root_fd")
|
||||
}
|
||||
|
||||
/// Specifies the write behavior for a specific region of memory
|
||||
///
|
||||
/// These types indicate to the driver how writes to a specific memory region are handled by the
|
||||
@@ -136,7 +158,7 @@ pub unsafe fn physmap(
|
||||
}
|
||||
|
||||
let path = format!(
|
||||
"/scheme/memory/physical@{}",
|
||||
"physical@{}",
|
||||
match ty {
|
||||
MemoryType::Writeback => "wb",
|
||||
MemoryType::Uncacheable => "uc",
|
||||
@@ -158,7 +180,7 @@ pub unsafe fn physmap(
|
||||
prot |= flag::PROT_WRITE;
|
||||
}
|
||||
|
||||
let fd = Fd::open(&path, O_CLOEXEC | mode, 0)?;
|
||||
let fd = memory_root_fd().openat(&path, O_CLOEXEC | mode, 0)?;
|
||||
Ok(libredox::call::mmap(MmapArgs {
|
||||
fd: fd.raw(),
|
||||
offset: base_phys as u64,
|
||||
@@ -245,18 +267,6 @@ impl Drop for PhysBorrowed {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: temporary wrapper in redox_syscall?
|
||||
unsafe fn sys_call(fd: usize, buf: &mut [u8], metadata: &[u64]) -> Result<usize> {
|
||||
Ok(syscall::syscall5(
|
||||
syscall::SYS_CALL,
|
||||
fd,
|
||||
buf.as_mut_ptr() as usize,
|
||||
buf.len(),
|
||||
metadata.len(),
|
||||
metadata.as_ptr() as usize,
|
||||
)?)
|
||||
}
|
||||
|
||||
/// Instructs the kernel to enable I/O ports for this (usermode) process (x86-specific).
|
||||
///
|
||||
/// On Redox, x86 privilege ring 3 represents userspace. Most Redox drivers run in userspace to
|
||||
@@ -268,7 +278,14 @@ pub fn acquire_port_io_rights() -> Result<()> {
|
||||
fn redox_cur_thrfd_v0() -> usize;
|
||||
}
|
||||
let kernel_fd = syscall::dup(unsafe { redox_cur_thrfd_v0() }, b"open_via_dup")?;
|
||||
let res = unsafe { sys_call(kernel_fd, &mut [], &[ProcSchemeVerb::Iopl as u64]) };
|
||||
let res = unsafe {
|
||||
libredox::call::call_wo(
|
||||
kernel_fd,
|
||||
&[],
|
||||
syscall::CallFlags::empty(),
|
||||
&[ProcSchemeVerb::Iopl as u64],
|
||||
)
|
||||
};
|
||||
let _ = syscall::close(kernel_fd);
|
||||
res?;
|
||||
Ok(())
|
||||
@@ -287,14 +304,14 @@ impl VirtaddrTranslationHandle {
|
||||
/// Create a new handle, requires uid=0 but this may change.
|
||||
pub fn new() -> Result<Self> {
|
||||
Ok(Self {
|
||||
fd: Fd::open("/scheme/memory/translation", O_CLOEXEC, 0)?,
|
||||
fd: memory_root_fd().openat("translation", O_CLOEXEC, 0)?,
|
||||
})
|
||||
}
|
||||
/// Translate physical => virtual.
|
||||
pub fn translate(&self, physical: usize) -> Result<usize> {
|
||||
let mut buf = physical.to_ne_bytes();
|
||||
unsafe {
|
||||
sys_call(self.fd.raw(), &mut buf, &[])?;
|
||||
libredox::call::call_ro(self.fd.raw(), &mut buf, syscall::CallFlags::empty(), &[])?;
|
||||
}
|
||||
Ok(usize::from_ne_bytes(buf))
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ pub fn setup_logging(
|
||||
mut output_level: log::LevelFilter,
|
||||
file_level: log::LevelFilter,
|
||||
) {
|
||||
RedoxLogger::init_timezone();
|
||||
if let Some(log_level) = read_bootloader_log_level_env(category, subcategory) {
|
||||
output_level = log_level;
|
||||
}
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
//! <https://www.qemu.org/docs/master/specs/standard-vga.html>
|
||||
|
||||
use common::acquire_port_io_rights;
|
||||
use inputd::ProducerHandle;
|
||||
use pcid_interface::PciFunctionHandle;
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
|
||||
|
||||
use crate::bga::Bga;
|
||||
use crate::scheme::BgaScheme;
|
||||
@@ -13,6 +14,7 @@ mod scheme;
|
||||
// FIXME add a driver-graphics implementation
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
@@ -32,7 +34,7 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
|
||||
|
||||
log::info!("BGA {}", pci_config.func.display());
|
||||
|
||||
let socket = Socket::create("bga").expect("bgad: failed to create bga scheme");
|
||||
let socket = Socket::create().expect("bgad: failed to create bga scheme");
|
||||
|
||||
let bar = unsafe { pcid_handle.map_bar(2) }.ptr.as_ptr();
|
||||
|
||||
@@ -46,10 +48,12 @@ fn daemon(daemon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> ! {
|
||||
|
||||
scheme.update_size();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace");
|
||||
register_sync_scheme(&socket, "bga", &mut scheme).expect("bgad: failed to register bga scheme");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("bgad: failed to enter null namespace");
|
||||
|
||||
loop {
|
||||
let Some(request) = socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
|
||||
@@ -27,8 +27,23 @@ impl BgaScheme {
|
||||
}
|
||||
}
|
||||
|
||||
const SCHEME_ROOT_ID: usize = 1;
|
||||
|
||||
impl SchemeSync for BgaScheme {
|
||||
fn open(&mut self, _path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
Ok(SCHEME_ROOT_ID)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
_path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if dirfd != SCHEME_ROOT_ID {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if ctx.uid == 0 {
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: 0,
|
||||
|
||||
@@ -19,10 +19,12 @@ use graphics_ipc::v1::CursorDamage;
|
||||
use graphics_ipc::v2::Damage;
|
||||
use inputd::{VtEvent, VtEventKind};
|
||||
use libredox::Fd;
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::scheme::{register_scheme_inner, SchemeSync};
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error, MapFlags, Result, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP};
|
||||
use syscall::{
|
||||
CallFlags, Error, MapFlags, Result, EACCES, EAGAIN, EBADF, EINVAL, ENOENT, EOPNOTSUPP,
|
||||
};
|
||||
|
||||
use crate::objects::{DrmObjectId, DrmObjects};
|
||||
use crate::properties::DrmPropertyKind;
|
||||
@@ -119,12 +121,13 @@ enum Handle<T: GraphicsAdapter> {
|
||||
next_id: u32,
|
||||
fbs: HashMap<u32, Arc<T::Framebuffer>>,
|
||||
},
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
pub fn new(mut adapter: T, scheme_name: String) -> Self {
|
||||
assert!(scheme_name.starts_with("display"));
|
||||
let socket = Socket::nonblock(&scheme_name).expect("failed to create graphics scheme");
|
||||
let socket = Socket::nonblock().expect("failed to create graphics scheme");
|
||||
|
||||
let disable_graphical_debug = Some(
|
||||
File::open("/scheme/debug/disable-graphical-debug")
|
||||
@@ -152,7 +155,7 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
adapter.probe_connector(&mut objects, &standard_properties, connector_id)
|
||||
}
|
||||
|
||||
GraphicsScheme {
|
||||
let mut scheme = GraphicsScheme {
|
||||
adapter,
|
||||
scheme_name,
|
||||
disable_graphical_debug,
|
||||
@@ -163,7 +166,15 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
handles: BTreeMap::new(),
|
||||
active_vt: 0,
|
||||
vts: HashMap::new(),
|
||||
}
|
||||
};
|
||||
|
||||
let cap_id = scheme
|
||||
.scheme_root()
|
||||
.expect("failed to get this scheme root");
|
||||
register_scheme_inner(&scheme.socket, &scheme.scheme_name, cap_id)
|
||||
.expect("failed to register graphics scheme root");
|
||||
|
||||
scheme
|
||||
}
|
||||
|
||||
pub fn event_handle(&self) -> &Fd {
|
||||
@@ -308,7 +319,26 @@ impl<T: GraphicsAdapter> GraphicsScheme<T> {
|
||||
const MAP_FAKE_OFFSET_MULTIPLIER: usize = 0x10_000_000;
|
||||
|
||||
impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if path.is_empty() {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
@@ -369,6 +399,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
next_id: _,
|
||||
fbs: _,
|
||||
} => format!("/scheme/{}/v2/{vt}", self.scheme_name),
|
||||
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
|
||||
};
|
||||
buf[..path.len()].copy_from_slice(path.as_bytes());
|
||||
Ok(path.len())
|
||||
@@ -390,6 +421,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Ok(())
|
||||
}
|
||||
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
|
||||
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -414,6 +446,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Ok(1)
|
||||
}
|
||||
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
|
||||
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -493,6 +526,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Ok(buf.len())
|
||||
}
|
||||
Handle::V2 { .. } => Err(Error::new(EOPNOTSUPP)),
|
||||
Handle::SchemeRoot => Err(Error::new(EOPNOTSUPP)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,6 +569,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
Handle::V1Screen { .. } => {
|
||||
return Err(Error::new(EOPNOTSUPP));
|
||||
}
|
||||
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
|
||||
Handle::V2 { vt, next_id, fbs } => match metadata[0] {
|
||||
ipc::VERSION => ipc::DrmVersion::with(payload, |mut data| {
|
||||
data.set_version_major(1);
|
||||
@@ -887,6 +922,7 @@ impl<T: GraphicsAdapter> SchemeSync for GraphicsScheme<T> {
|
||||
.unwrap(),
|
||||
offset & (MAP_FAKE_OFFSET_MULTIPLIER as u64 - 1),
|
||||
),
|
||||
Handle::SchemeRoot => return Err(Error::new(EOPNOTSUPP)),
|
||||
};
|
||||
let ptr = T::map_dumb_framebuffer(&mut self.adapter, framebuffer);
|
||||
Ok(unsafe { ptr.add(offset as usize) } as usize)
|
||||
|
||||
@@ -14,7 +14,7 @@ use event::EventQueue;
|
||||
use inputd::ConsumerHandleEvent;
|
||||
use libredox::errno::EAGAIN;
|
||||
use orbclient::Event;
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
|
||||
|
||||
use crate::scheme::FbbootlogScheme;
|
||||
|
||||
@@ -33,17 +33,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
}
|
||||
}
|
||||
|
||||
let socket =
|
||||
Socket::nonblock("fbbootlog").expect("fbbootlogd: failed to create fbbootlog scheme");
|
||||
let socket = Socket::nonblock().expect("fbbootlogd: failed to create fbbootlog scheme");
|
||||
|
||||
{
|
||||
// Add ourself as log sink
|
||||
let mut log_file = std::fs::OpenOptions::new()
|
||||
.write(true)
|
||||
.open("/scheme/log/add_sink")
|
||||
.unwrap();
|
||||
log_file.write(b"/scheme/fbbootlog").unwrap();
|
||||
}
|
||||
let mut scheme = FbbootlogScheme::new();
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
@@ -51,9 +43,7 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
Source::Scheme,
|
||||
event::EventFlags::READ,
|
||||
)
|
||||
.expect("fbcond: failed to subscribe to scheme events");
|
||||
|
||||
let mut scheme = FbbootlogScheme::new();
|
||||
.expect("fbbootlogd: failed to subscribe to scheme events");
|
||||
|
||||
event_queue
|
||||
.subscribe(
|
||||
@@ -63,6 +53,25 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
)
|
||||
.expect("fbbootlogd: failed to subscribe to scheme events");
|
||||
|
||||
{
|
||||
let log_fd = socket
|
||||
.create_this_scheme_fd(0, 0, 0, 0)
|
||||
.expect("fbbootlogd: failed to create log fd");
|
||||
// Add ourself as log sink
|
||||
let mut log_file = libredox::Fd::open(
|
||||
"/scheme/log/add_sink",
|
||||
libredox::flag::O_WRONLY | libredox::flag::O_CLOEXEC,
|
||||
0,
|
||||
)
|
||||
.expect("fbbootlogd: failed to open log/add_sink");
|
||||
log_file
|
||||
.call_wo(&log_fd.to_ne_bytes(), syscall::CallFlags::FD, &[])
|
||||
.expect("fbbootlogd: failed to send log fd to log scheme.");
|
||||
}
|
||||
|
||||
register_sync_scheme(&socket, "fbbootlog", &mut scheme)
|
||||
.expect("fbbootlog: failed to register scheme to namespace");
|
||||
|
||||
// This is not possible for now as fbbootlogd needs to open new displays at runtime for graphics
|
||||
// driver handoff. In the future inputd may directly pass a handle to the display instead.
|
||||
//libredox::call::setrens(0, 0).expect("fbbootlogd: failed to enter null namespace");
|
||||
|
||||
@@ -10,7 +10,7 @@ use orbclient::{Event, EventOption};
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error, Result, EINVAL, ENOENT};
|
||||
use syscall::{Error, Result, EACCES, EBADF, EINVAL, ENOENT};
|
||||
|
||||
pub struct FbbootlogScheme {
|
||||
pub input_handle: ConsumerHandle,
|
||||
@@ -173,8 +173,24 @@ impl FbbootlogScheme {
|
||||
}
|
||||
}
|
||||
|
||||
const SCHEME_ROOT_ID: usize = 1;
|
||||
|
||||
impl SchemeSync for FbbootlogScheme {
|
||||
fn open(&mut self, path_str: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
Ok(SCHEME_ROOT_ID)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path_str: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if dirfd != SCHEME_ROOT_ID {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if !path_str.is_empty() {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
@@ -214,12 +230,15 @@ impl SchemeSync for FbbootlogScheme {
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
_id: usize,
|
||||
id: usize,
|
||||
buf: &[u8],
|
||||
_offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
if id == SCHEME_ROOT_ID {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
if let Some(map) = &mut self.display_map {
|
||||
Self::handle_resize(map, &mut self.text_screen);
|
||||
self.text_buffer.write(buf);
|
||||
|
||||
@@ -3,13 +3,13 @@ use inputd::ConsumerHandleEvent;
|
||||
use libredox::errno::{EAGAIN, EINTR};
|
||||
use orbclient::Event;
|
||||
use redox_scheme::{
|
||||
scheme::{Op, SchemeResponse, SchemeSync},
|
||||
scheme::{register_sync_scheme, Op, SchemeResponse, SchemeSync},
|
||||
CallerCtx, RequestKind, Response, SignalBehavior, Socket,
|
||||
};
|
||||
use std::env;
|
||||
use syscall::{EOPNOTSUPP, EVENT_READ};
|
||||
|
||||
use crate::scheme::{FbconScheme, VtIndex};
|
||||
use crate::scheme::{FbconScheme, Handle, VtIndex};
|
||||
|
||||
mod display;
|
||||
mod scheme;
|
||||
@@ -35,7 +35,7 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
// FIXME listen for resize events from inputd and handle them
|
||||
|
||||
let mut socket = Socket::nonblock("fbcon").expect("fbcond: failed to create fbcon scheme");
|
||||
let mut socket = Socket::nonblock().expect("fbcond: failed to create fbcon scheme");
|
||||
event_queue
|
||||
.subscribe(
|
||||
socket.inner().raw(),
|
||||
@@ -46,6 +46,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
let mut scheme = FbconScheme::new(&vt_ids, &mut event_queue);
|
||||
|
||||
register_sync_scheme(&socket, "fbcon", &mut scheme)
|
||||
.expect("fbcond: failed to register scheme to namespace");
|
||||
|
||||
// This is not possible for now as fbcond needs to open new displays at runtime for graphics
|
||||
// driver handoff. In the future inputd may directly pass a handle to the display instead.
|
||||
// libredox::call::setrens(0, 0).expect("fbcond: failed to enter null namespace");
|
||||
@@ -204,7 +207,8 @@ fn handle_event(
|
||||
|
||||
for (handle_id, handle) in scheme.handles.iter_mut() {
|
||||
let handle = match handle {
|
||||
handle => handle,
|
||||
Handle::SchemeRoot => continue,
|
||||
Handle::Vt(handle) => handle,
|
||||
};
|
||||
|
||||
if !handle.events.contains(EVENT_READ) {
|
||||
|
||||
@@ -34,10 +34,15 @@ pub struct FdHandle {
|
||||
pub notified_read: bool,
|
||||
}
|
||||
|
||||
pub enum Handle {
|
||||
Vt(FdHandle),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
pub struct FbconScheme {
|
||||
pub vts: BTreeMap<VtIndex, TextScreen>,
|
||||
next_id: usize,
|
||||
pub handles: BTreeMap<usize, FdHandle>,
|
||||
pub handles: BTreeMap<usize, Handle>,
|
||||
}
|
||||
|
||||
impl FbconScheme {
|
||||
@@ -65,14 +70,36 @@ impl FbconScheme {
|
||||
|
||||
fn get_vt_handle_mut(&mut self, id: usize) -> Result<&mut FdHandle> {
|
||||
match self.handles.get_mut(&id) {
|
||||
Some(handle) => Ok(handle),
|
||||
Some(Handle::Vt(handle)) => Ok(handle),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeSync for FbconScheme {
|
||||
fn open(&mut self, path_str: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path_str: &str,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let vt_i = VtIndex(path_str.parse::<usize>().map_err(|_| Error::new(ENOENT))?);
|
||||
if self.vts.contains_key(&vt_i) {
|
||||
let id = self.next_id;
|
||||
@@ -80,12 +107,12 @@ impl SchemeSync for FbconScheme {
|
||||
|
||||
self.handles.insert(
|
||||
id,
|
||||
FdHandle {
|
||||
Handle::Vt(FdHandle {
|
||||
vt_i,
|
||||
flags: flags,
|
||||
flags: flags | fcntl_flags as usize,
|
||||
events: EventFlags::empty(),
|
||||
notified_read: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
@@ -104,7 +131,8 @@ impl SchemeSync for FbconScheme {
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<syscall::EventFlags> {
|
||||
let handle = match self.handles.get_mut(&id) {
|
||||
Some(handle) => Ok(handle),
|
||||
Some(Handle::Vt(handle)) => Ok(handle),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}?;
|
||||
|
||||
@@ -116,7 +144,8 @@ impl SchemeSync for FbconScheme {
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = match self.handles.get(&id) {
|
||||
Some(handle) => Ok(handle),
|
||||
Some(Handle::Vt(handle)) => Ok(handle),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}?;
|
||||
|
||||
@@ -134,7 +163,8 @@ impl SchemeSync for FbconScheme {
|
||||
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
match self.handles.get(&id) {
|
||||
Some(_) => Ok(()),
|
||||
Some(Handle::Vt(_)) => Ok(()),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
@@ -155,7 +185,8 @@ impl SchemeSync for FbconScheme {
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = match self.handles.get(&id) {
|
||||
Some(handle) => Ok(handle),
|
||||
Some(Handle::Vt(handle)) => Ok(handle),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}?;
|
||||
|
||||
@@ -183,7 +214,8 @@ impl SchemeSync for FbconScheme {
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = match self.handles.get(&id) {
|
||||
Some(handle) => Ok(handle),
|
||||
Some(Handle::Vt(handle)) => Ok(handle),
|
||||
Some(Handle::SchemeRoot) => Err(Error::new(EBADF)),
|
||||
None => Err(Error::new(EBADF)),
|
||||
}?;
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ use crate::scheme::{FbAdapter, FrameBuffer};
|
||||
mod scheme;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
daemon::Daemon::new(daemon);
|
||||
}
|
||||
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
@@ -476,6 +476,7 @@ impl MoveCursor {
|
||||
static DEVICE: spin::Once<virtio_core::Device> = spin::Once::new();
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon_runner);
|
||||
}
|
||||
|
||||
@@ -524,7 +525,6 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
device.transport.setup_config_notify(MSIX_PRIMARY_VECTOR);
|
||||
|
||||
device.transport.run_device();
|
||||
deamon.ready();
|
||||
|
||||
let (mut scheme, mut inputd_handle) = scheme::GpuScheme::new(
|
||||
config,
|
||||
@@ -533,6 +533,7 @@ fn deamon(deamon: daemon::Daemon, mut pcid_handle: PciFunctionHandle) -> anyhow:
|
||||
device.transport.clone(),
|
||||
has_edid,
|
||||
)?;
|
||||
deamon.ready();
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
|
||||
@@ -7,6 +7,7 @@ edition = "2018"
|
||||
fdt = "0.1.5"
|
||||
log.workspace = true
|
||||
ron = "0.8.1"
|
||||
libredox = { version = "0.1.12", default-features = false, features = ["std", "call"] }
|
||||
|
||||
amlserde = { path = "../amlserde" }
|
||||
common = { path = "../common" }
|
||||
|
||||
@@ -20,11 +20,23 @@ impl Backend for AcpiBackend {
|
||||
|
||||
fn probe(&mut self) -> Result<(), Box<dyn Error>> {
|
||||
// Read symbols from acpi scheme
|
||||
for entry_res in fs::read_dir("/scheme/acpi/symbols")? {
|
||||
let entries = fs::read_dir("/scheme/acpi/symbols")?;
|
||||
// TODO: Reimplement with getdents?
|
||||
let symbols_fd = libredox::Fd::open(
|
||||
"/scheme/acpi/symbols",
|
||||
libredox::flag::O_DIRECTORY | libredox::flag::O_RDONLY,
|
||||
0,
|
||||
)?;
|
||||
for entry_res in entries {
|
||||
let entry = entry_res?;
|
||||
if let Some(file_name) = entry.file_name().to_str() {
|
||||
if file_name.ends_with("_CID") || file_name.ends_with("_HID") {
|
||||
let ron = fs::read_to_string(entry.path())?;
|
||||
let symbol_fd = symbols_fd.openat(file_name, libredox::flag::O_RDONLY, 0)?;
|
||||
let stat = symbol_fd.stat()?;
|
||||
let mut buf: Vec<u8> = vec![0u8; stat.st_size as usize];
|
||||
let count = symbol_fd.read(&mut buf)?;
|
||||
buf.truncate(count);
|
||||
let ron = String::from_utf8(buf)?;
|
||||
let AmlSerde { name, value } = ron::from_str(&ron)?;
|
||||
let id = match value {
|
||||
AmlSerdeValue::Integer(integer) => {
|
||||
|
||||
@@ -12,6 +12,9 @@ use std::{env, process};
|
||||
use common::acquire_port_io_rights;
|
||||
use event::{user_data, EventQueue};
|
||||
use inputd::ProducerHandle;
|
||||
use log::info;
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
|
||||
use syscall::{EAGAIN, EWOULDBLOCK};
|
||||
|
||||
use crate::state::Ps2d;
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ fn main() {
|
||||
interface_num
|
||||
);
|
||||
|
||||
let handle = XhciClientHandle::new(scheme, port);
|
||||
let handle = XhciClientHandle::new(scheme, port).expect("Faild to open XhciClientHandle");
|
||||
let desc: DevDesc = handle
|
||||
.get_standard_descs()
|
||||
.expect("Failed to get standard descriptors");
|
||||
|
||||
@@ -20,13 +20,12 @@ use std::sync::atomic::{AtomicUsize, Ordering};
|
||||
use inputd::{ControlEvent, VtEvent, VtEventKind};
|
||||
|
||||
use libredox::errno::ESTALE;
|
||||
use log::warn;
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::scheme::{register_sync_scheme, SchemeSync};
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket};
|
||||
|
||||
use orbclient::{Event, EventOption};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error as SysError, EventFlags, EINVAL};
|
||||
use syscall::{Error as SysError, EventFlags, EACCES, EBADF, EINVAL};
|
||||
|
||||
pub mod keymap;
|
||||
|
||||
@@ -54,6 +53,7 @@ enum Handle {
|
||||
is_earlyfb: bool,
|
||||
},
|
||||
Control,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
struct InputScheme {
|
||||
@@ -152,7 +152,27 @@ impl InputScheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for InputScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> syscall::Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> syscall::Result<usize> {
|
||||
let fd = self.next_id.fetch_add(1, Ordering::SeqCst);
|
||||
self.handles.insert(fd, Handle::SchemeRoot);
|
||||
Ok(fd)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> syscall::Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(SysError::new(EINVAL))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(SysError::new(EACCES));
|
||||
}
|
||||
|
||||
let mut path_parts = path.split('/');
|
||||
|
||||
let command = path_parts.next().ok_or(SysError::new(EINVAL))?;
|
||||
@@ -167,7 +187,6 @@ impl SchemeSync for InputScheme {
|
||||
if self.active_vt.is_none() {
|
||||
self.switch_vt(vt);
|
||||
}
|
||||
|
||||
Handle::Consumer {
|
||||
events: EventFlags::empty(),
|
||||
pending: Vec::new(),
|
||||
@@ -319,6 +338,7 @@ impl SchemeSync for InputScheme {
|
||||
log::error!("control tried to read");
|
||||
return Err(SysError::new(EINVAL));
|
||||
}
|
||||
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -364,6 +384,7 @@ impl SchemeSync for InputScheme {
|
||||
return Err(SysError::new(EINVAL));
|
||||
}
|
||||
Handle::Producer => {}
|
||||
Handle::SchemeRoot => return Err(SysError::new(EBADF)),
|
||||
}
|
||||
|
||||
if buf.len() == 1 && buf[0] > 0xf4 {
|
||||
@@ -508,11 +529,10 @@ impl SchemeSync for InputScheme {
|
||||
log::error!("producer or control tried to use an event queue");
|
||||
Err(SysError::new(EINVAL))
|
||||
}
|
||||
Handle::SchemeRoot => Err(SysError::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl InputScheme {
|
||||
fn on_close(&mut self, id: usize) {
|
||||
let handle = self.handles.remove(&id).unwrap();
|
||||
|
||||
@@ -534,9 +554,10 @@ impl InputScheme {
|
||||
|
||||
fn deamon(deamon: daemon::Daemon) -> anyhow::Result<()> {
|
||||
// Create the ":input" scheme.
|
||||
let socket_file = Socket::create("input")?;
|
||||
let socket_file = Socket::create()?;
|
||||
let mut scheme = InputScheme::new();
|
||||
|
||||
register_sync_scheme(&socket_file, "input", &mut scheme)?;
|
||||
deamon.ready();
|
||||
|
||||
loop {
|
||||
|
||||
@@ -1787,8 +1787,23 @@ impl Alx {
|
||||
}
|
||||
}
|
||||
|
||||
const SCHEME_ROOT_ID: usize = usize::MAX;
|
||||
|
||||
impl SchemeSync for Alx {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
Ok(SCHEME_ROOT_ID)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path_str: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if dirfd != SCHEME_ROOT_ID {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if ctx.uid == 0 {
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: flags,
|
||||
|
||||
@@ -12,6 +12,7 @@ use std::os::fd::AsRawFd;
|
||||
use std::{env, iter};
|
||||
|
||||
use event::{user_data, EventQueue};
|
||||
use redox_scheme::scheme::register_sync_scheme;
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::Socket;
|
||||
use std::cell::RefCell;
|
||||
@@ -19,6 +20,7 @@ use std::cell::RefCell;
|
||||
pub mod device;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
daemon::Daemon::new(daemon);
|
||||
}
|
||||
|
||||
@@ -36,11 +38,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
|
||||
println!(" + ALX {} on: {:X}, IRQ: {}\n", name, bar, irq);
|
||||
|
||||
let socket = Socket::nonblock("network").expect("alxd: failed to create socket");
|
||||
let socket = Socket::nonblock().expect("alxd: failed to create socket");
|
||||
let mut readiness_based = ReadinessBased::new(&socket, 16);
|
||||
|
||||
daemon.ready();
|
||||
|
||||
let mut irq_file =
|
||||
File::open(format!("/scheme/irq/{}", irq)).expect("alxd: failed to open IRQ file");
|
||||
|
||||
@@ -54,10 +54,16 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
.expect("alxd: failed to map address") as usize
|
||||
};
|
||||
{
|
||||
let device = RefCell::new(unsafe {
|
||||
device::Alx::new(address).expect("alxd: failed to allocate device")
|
||||
let device = RefCell::new({
|
||||
let mut device =
|
||||
unsafe { device::Alx::new(address).expect("alxd: failed to allocate device") };
|
||||
register_sync_scheme(&socket, "network", &mut device)
|
||||
.expect("alxd: failed to register network scheme to namespace");
|
||||
device
|
||||
});
|
||||
|
||||
daemon.ready();
|
||||
|
||||
user_data! {
|
||||
enum Source {
|
||||
Irq,
|
||||
|
||||
@@ -52,9 +52,12 @@ impl<T: NetworkAdapter> NetworkScheme<T> {
|
||||
daemon: daemon::Daemon,
|
||||
scheme_name: String,
|
||||
) -> Self {
|
||||
let socket = Socket::nonblock(&scheme_name).expect("failed to create network scheme");
|
||||
assert!(scheme_name.starts_with("network"));
|
||||
let socket = Socket::nonblock().expect("failed to create network scheme");
|
||||
let adapter = adapter_fn();
|
||||
let scheme = NetworkSchemeInner::new(adapter, scheme_name.clone());
|
||||
let mut scheme = NetworkSchemeInner::new(adapter, scheme_name.clone());
|
||||
redox_scheme::scheme::register_sync_scheme(&socket, &scheme_name, &mut scheme)
|
||||
.expect("failed to regitster network scheme");
|
||||
daemon.ready();
|
||||
Self {
|
||||
scheme,
|
||||
@@ -196,6 +199,7 @@ struct NetworkSchemeInner<T: NetworkAdapter> {
|
||||
enum Handle {
|
||||
Data,
|
||||
Mac,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
impl<T: NetworkAdapter> NetworkSchemeInner<T> {
|
||||
@@ -210,7 +214,27 @@ impl<T: NetworkAdapter> NetworkSchemeInner<T> {
|
||||
}
|
||||
|
||||
impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
|
||||
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&fd).ok_or(Error::new(EINVAL))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
@@ -247,6 +271,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
|
||||
buf[..i].copy_from_slice(&data[..i]);
|
||||
return Ok(i);
|
||||
}
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
match self.adapter.read_packet(buf)? {
|
||||
@@ -274,6 +299,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
|
||||
match handle {
|
||||
Handle::Data => {}
|
||||
Handle::Mac { .. } => return Err(Error::new(EINVAL)),
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
|
||||
Ok(self.adapter.write_packet(buf)?)
|
||||
@@ -306,6 +332,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
|
||||
let path = match handle {
|
||||
Handle::Data { .. } => &b""[..],
|
||||
Handle::Mac { .. } => &b"mac"[..],
|
||||
_ => &b""[..],
|
||||
};
|
||||
|
||||
j = 0;
|
||||
@@ -329,6 +356,7 @@ impl<T: NetworkAdapter> SchemeSync for NetworkSchemeInner<T> {
|
||||
stat.st_mode = MODE_FILE | 0o400;
|
||||
stat.st_size = 6;
|
||||
}
|
||||
_ => return Err(Error::new(EBADF)),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -8,6 +8,7 @@ use pcid_interface::PciFunctionHandle;
|
||||
pub mod device;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ pub mod device;
|
||||
mod ixgbe;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ fn map_bar(pcid_handle: &mut PciFunctionHandle) -> *mut u8 {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@ static_assertions::const_assert_eq!(core::mem::size_of::<VirtHeader>(), 12);
|
||||
|
||||
const MAX_BUFFER_LEN: usize = 65535;
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon_runner);
|
||||
}
|
||||
|
||||
|
||||
@@ -90,7 +90,7 @@ fn main() -> Result<()> {
|
||||
|
||||
match command.status() {
|
||||
Ok(status) if !status.success() => {
|
||||
log::error!("pcid-spawner: driver {command:?} failed with {status}");
|
||||
log::error!("pcid-spawner: driver {command:?} failed with {status}")
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(err) => log::error!("pcid-spawner: failed to execute {command:?}: {err}"),
|
||||
|
||||
@@ -327,9 +327,10 @@ impl PciFunctionHandle {
|
||||
}
|
||||
|
||||
pub fn connect_by_path(device_path: &Path) -> io::Result<Self> {
|
||||
let channel_fd = syscall::open(
|
||||
let channel_fd = libredox::call::open(
|
||||
device_path.join("channel").to_str().unwrap(),
|
||||
syscall::O_RDWR,
|
||||
libredox::flag::O_RDWR,
|
||||
0,
|
||||
)
|
||||
.map_err(|err| io::Error::other(format!("failed to open pcid channel: {}", err)))?;
|
||||
Ok(Self::connect_common(channel_fd as RawFd))
|
||||
|
||||
@@ -10,7 +10,7 @@ use pci_types::{
|
||||
Bar as TyBar, CommandRegister, EndpointHeader, HeaderType, PciAddress,
|
||||
PciHeader as TyPciHeader, PciPciBridgeHeader,
|
||||
};
|
||||
use redox_scheme::{RequestKind, SignalBehavior};
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior};
|
||||
|
||||
use crate::cfg_access::Pcie;
|
||||
use pcid_interface::{FullDeviceId, LegacyInterruptLine, PciBar, PciFunction, PciRom};
|
||||
@@ -232,6 +232,7 @@ fn enable_function(
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
daemon::Daemon::new(daemon);
|
||||
}
|
||||
|
||||
@@ -245,10 +246,39 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
);
|
||||
|
||||
let pcie = Pcie::new();
|
||||
let mut tree = BTreeMap::new();
|
||||
|
||||
info!("PCI SG-BS:DV.F VEND:DEVI CL.SC.IN.RV");
|
||||
|
||||
let mut scheme = scheme::PciScheme::new(pcie);
|
||||
let socket = redox_scheme::Socket::create().expect("failed to open pci scheme socket");
|
||||
|
||||
{
|
||||
match libredox::Fd::open("/scheme/acpi/register_pci", libredox::flag::O_WRONLY, 0) {
|
||||
Ok(register_pci) => {
|
||||
let access_id = scheme.access();
|
||||
|
||||
let access_fd = socket
|
||||
.create_this_scheme_fd(0, access_id, syscall::O_RDWR, 0)
|
||||
.expect("failed to issue this resource");
|
||||
let access_bytes = access_fd.to_ne_bytes();
|
||||
let _ = register_pci
|
||||
.call_wo(
|
||||
&access_bytes,
|
||||
syscall::CallFlags::WRITE | syscall::CallFlags::FD,
|
||||
&[],
|
||||
)
|
||||
.expect("failed to send pci_fd to acpid");
|
||||
}
|
||||
Err(err) => {
|
||||
if err.errno() == libredox::errno::ENODEV {
|
||||
debug!("pcid: acpid not found. Running without ACPI integration.");
|
||||
} else {
|
||||
warn!("pcid: failed to open acpid register_pci (error: {}). Running without ACPI integration.", err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// FIXME Use full ACPI for enumerating the host bridges. MCFG only describes the first
|
||||
// host bridge, while multi-processor systems likely have a host bridge for each CPU.
|
||||
// See also https://www.kernel.org/doc/html/latest/PCI/acpi-info.html
|
||||
@@ -261,13 +291,19 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
bus_i += 1;
|
||||
|
||||
for dev_num in 0..32 {
|
||||
scan_device(&mut tree, &pcie, &mut bus_nums, bus_num, dev_num);
|
||||
scan_device(
|
||||
&mut scheme.tree,
|
||||
&scheme.pcie,
|
||||
&mut bus_nums,
|
||||
bus_num,
|
||||
dev_num,
|
||||
);
|
||||
}
|
||||
}
|
||||
debug!("Enumeration complete, now starting pci scheme");
|
||||
|
||||
let mut scheme = scheme::PciScheme::new(pcie, tree);
|
||||
let socket = redox_scheme::Socket::create("pci").expect("failed to open pci scheme socket");
|
||||
register_sync_scheme(&socket, "pci", &mut scheme)
|
||||
.expect("failed to register pci scheme to namespace");
|
||||
|
||||
let _ = daemon.ready();
|
||||
|
||||
|
||||
@@ -14,14 +14,15 @@ use crate::cfg_access::Pcie;
|
||||
pub struct PciScheme {
|
||||
handles: BTreeMap<usize, HandleWrapper>,
|
||||
next_id: usize,
|
||||
pcie: Pcie,
|
||||
tree: BTreeMap<PciAddress, crate::Func>,
|
||||
pub pcie: Pcie,
|
||||
pub tree: BTreeMap<PciAddress, crate::Func>,
|
||||
}
|
||||
enum Handle {
|
||||
TopLevel { entries: Vec<String> },
|
||||
Access,
|
||||
Device,
|
||||
Channel { addr: PciAddress, st: ChannelState },
|
||||
SchemeRoot,
|
||||
}
|
||||
struct HandleWrapper {
|
||||
inner: Handle,
|
||||
@@ -38,6 +39,9 @@ impl Handle {
|
||||
fn requires_root(&self) -> bool {
|
||||
matches!(self, Self::Access | Self::Channel { .. })
|
||||
}
|
||||
fn is_scheme_root(&self) -> bool {
|
||||
matches!(self, Self::SchemeRoot)
|
||||
}
|
||||
}
|
||||
|
||||
enum ChannelState {
|
||||
@@ -47,8 +51,50 @@ enum ChannelState {
|
||||
|
||||
const DEVICE_CONTENTS: &[&str] = &["channel"];
|
||||
|
||||
impl PciScheme {
|
||||
pub fn access(&mut self) -> usize {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(
|
||||
id,
|
||||
HandleWrapper {
|
||||
inner: Handle::Access,
|
||||
stat: false,
|
||||
},
|
||||
);
|
||||
|
||||
id
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeSync for PciScheme {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(
|
||||
id,
|
||||
HandleWrapper {
|
||||
inner: Handle::SchemeRoot,
|
||||
stat: false,
|
||||
},
|
||||
);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
if !handle.inner.is_scheme_root() {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
log::trace!("OPEN `{}` flags {}", path, flags);
|
||||
|
||||
// TODO: Check flags are correct
|
||||
@@ -108,6 +154,7 @@ impl SchemeSync for PciScheme {
|
||||
Handle::TopLevel { ref entries } => (entries.len(), MODE_DIR | 0o755),
|
||||
Handle::Device => (DEVICE_CONTENTS.len(), MODE_DIR | 0o755),
|
||||
Handle::Access | Handle::Channel { .. } => (0, MODE_CHR | 0o600),
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
stat.st_size = len as u64;
|
||||
stat.st_mode = mode;
|
||||
@@ -134,6 +181,7 @@ impl SchemeSync for PciScheme {
|
||||
addr: _,
|
||||
ref mut st,
|
||||
} => Self::read_channel(st, buf),
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
_ => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
@@ -167,6 +215,7 @@ impl SchemeSync for PciScheme {
|
||||
}
|
||||
Handle::Device => DEVICE_CONTENTS,
|
||||
Handle::Access | Handle::Channel { .. } => return Err(Error::new(ENOTDIR)),
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
for (i, dent_name) in entries.iter().enumerate().skip(offset) {
|
||||
@@ -296,12 +345,12 @@ impl PciScheme {
|
||||
}
|
||||
|
||||
impl PciScheme {
|
||||
pub fn new(pcie: Pcie, tree: BTreeMap<PciAddress, crate::Func>) -> Self {
|
||||
pub fn new(pcie: Pcie) -> Self {
|
||||
Self {
|
||||
handles: BTreeMap::new(),
|
||||
next_id: 0,
|
||||
pcie,
|
||||
tree,
|
||||
tree: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
fn parse_after_pci_addr(&mut self, addr: PciAddress, after: &str) -> Result<Handle> {
|
||||
|
||||
@@ -9,10 +9,6 @@ mod sys;
|
||||
const DEFAULT_COLS: u32 = 80;
|
||||
const DEFAULT_LINES: u32 = 30;
|
||||
|
||||
pub fn syscall_error(error: syscall::Error) -> io::Error {
|
||||
io::Error::from_raw_os_error(error.errno)
|
||||
}
|
||||
|
||||
event::user_data! {
|
||||
enum EventData {
|
||||
Pty,
|
||||
@@ -32,15 +28,15 @@ fn handle(
|
||||
let mut packet = [0; 4096];
|
||||
loop {
|
||||
// Read data from PTY master
|
||||
let count = match syscall::read(master_fd as usize, &mut packet) {
|
||||
let count = match libredox::call::read(master_fd as usize, &mut packet) {
|
||||
Ok(0) => return Ok(false),
|
||||
Ok(count) => count,
|
||||
Err(ref err) if err.errno == syscall::EAGAIN => return Ok(true),
|
||||
Err(err) => return Err(syscall_error(err)),
|
||||
Err(ref err) if err.errno() == libredox::errno::EAGAIN => return Ok(true),
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
|
||||
// Write data to stdout
|
||||
syscall::write(1, &packet[1..count]).map_err(syscall_error)?;
|
||||
libredox::call::write(1, &packet[1..count])?;
|
||||
|
||||
for i in 1..count {
|
||||
// Write byte to QEMU debugcon (Bochs compatible)
|
||||
@@ -50,10 +46,10 @@ fn handle(
|
||||
}
|
||||
EventData::Timer => {
|
||||
let mut timespec = syscall::TimeSpec::default();
|
||||
syscall::read(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
|
||||
libredox::call::read(timeout_fd as usize, &mut timespec)?;
|
||||
|
||||
timespec.tv_sec += 1;
|
||||
syscall::write(timeout_fd as usize, &mut timespec).map_err(syscall_error)?;
|
||||
libredox::call::write(timeout_fd as usize, &mut timespec)?;
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
@@ -85,25 +81,28 @@ fn handle(
|
||||
}
|
||||
|
||||
fn getpty(columns: u32, lines: u32) -> io::Result<(RawFd, String)> {
|
||||
let master = syscall::open(
|
||||
let master = libredox::call::open(
|
||||
"/scheme/pty",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_CREAT | syscall::O_NONBLOCK,
|
||||
)
|
||||
.map_err(syscall_error)?;
|
||||
libredox::flag::O_CLOEXEC
|
||||
| libredox::flag::O_RDWR
|
||||
| libredox::flag::O_CREAT
|
||||
| libredox::flag::O_NONBLOCK,
|
||||
0,
|
||||
)?;
|
||||
|
||||
if let Ok(winsize_fd) = syscall::dup(master, b"winsize") {
|
||||
let _ = syscall::write(
|
||||
if let Ok(winsize_fd) = libredox::call::dup(master, b"winsize") {
|
||||
let _ = libredox::call::write(
|
||||
winsize_fd,
|
||||
&redox_termios::Winsize {
|
||||
ws_row: lines as u16,
|
||||
ws_col: columns as u16,
|
||||
},
|
||||
);
|
||||
let _ = syscall::close(winsize_fd);
|
||||
let _ = libredox::call::close(winsize_fd);
|
||||
}
|
||||
|
||||
let mut buf: [u8; 4096] = [0; 4096];
|
||||
let count = syscall::fpath(master, &mut buf).map_err(syscall_error)?;
|
||||
let count = libredox::call::fpath(master, &mut buf)?;
|
||||
Ok((master as RawFd, unsafe {
|
||||
String::from_utf8_unchecked(Vec::from(&buf[..count]))
|
||||
}))
|
||||
@@ -118,11 +117,11 @@ fn inner() -> anyhow::Result<()> {
|
||||
let (columns, lines) = (DEFAULT_COLS, DEFAULT_LINES);
|
||||
let (master_fd, pty) = getpty(columns, lines)?;
|
||||
|
||||
let timeout_fd = syscall::open(
|
||||
let timeout_fd = libredox::call::open(
|
||||
"/scheme/time/4",
|
||||
syscall::O_CLOEXEC | syscall::O_RDWR | syscall::O_NONBLOCK,
|
||||
)
|
||||
.map_err(syscall_error)? as RawFd;
|
||||
libredox::flag::O_CLOEXEC | libredox::flag::O_RDWR | libredox::flag::O_NONBLOCK,
|
||||
0,
|
||||
)? as RawFd;
|
||||
|
||||
let event_queue = event::EventQueue::new()?;
|
||||
event_queue.subscribe(master_fd as usize, EventData::Pty, event::EventFlags::READ)?;
|
||||
|
||||
@@ -14,6 +14,7 @@ use log::{error, info};
|
||||
pub mod ahci;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,13 +11,13 @@ use std::task::Poll;
|
||||
use executor::LocalExecutor;
|
||||
use libredox::Fd;
|
||||
use partitionlib::{LogicalBlockSize, PartitionTable};
|
||||
use redox_scheme::scheme::SchemeAsync;
|
||||
use redox_scheme::scheme::{register_scheme_inner, SchemeAsync};
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket};
|
||||
use syscall::dirent::DirentBuf;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK, EOPNOTSUPP,
|
||||
EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT,
|
||||
CallFlags, Error, Result, Stat, EACCES, EAGAIN, EBADF, EINTR, EINVAL, EISDIR, ENOENT, ENOLCK,
|
||||
EOPNOTSUPP, EOVERFLOW, EWOULDBLOCK, MODE_DIR, MODE_FILE, O_DIRECTORY, O_STAT,
|
||||
};
|
||||
|
||||
/// Split the read operation into a series of block reads.
|
||||
@@ -258,6 +258,7 @@ enum Handle {
|
||||
List(Vec<u8>), // entries
|
||||
Disk(u32), // disk num
|
||||
Partition(u32, u32), // disk num, part num
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
pub struct DiskScheme<T> {
|
||||
@@ -310,14 +311,10 @@ impl<T: Disk> DiskScheme<T> {
|
||||
executor: &impl ExecutorTrait,
|
||||
) -> Self {
|
||||
assert!(scheme_name.starts_with("disk"));
|
||||
let socket = Socket::nonblock(&scheme_name).expect("failed to create disk scheme");
|
||||
let socket = Socket::nonblock().expect("failed to create disk scheme");
|
||||
|
||||
if let Some(daemon) = daemon {
|
||||
daemon.ready();
|
||||
}
|
||||
|
||||
Self {
|
||||
scheme_name,
|
||||
let mut scheme = Self {
|
||||
scheme_name: scheme_name,
|
||||
socket,
|
||||
disks: disks
|
||||
.into_iter()
|
||||
@@ -325,7 +322,19 @@ impl<T: Disk> DiskScheme<T> {
|
||||
.collect(),
|
||||
next_id: 0,
|
||||
handles: BTreeMap::new(),
|
||||
};
|
||||
|
||||
let cap_id = scheme
|
||||
.scheme_root()
|
||||
.expect("failed to get this scheme root");
|
||||
register_scheme_inner(&scheme.socket, &scheme.scheme_name, cap_id)
|
||||
.expect("failed to register disk scheme root");
|
||||
|
||||
if let Some(daemon) = daemon {
|
||||
daemon.ready();
|
||||
}
|
||||
|
||||
scheme
|
||||
}
|
||||
|
||||
pub fn event_handle(&self) -> &Fd {
|
||||
@@ -358,7 +367,8 @@ impl<T: Disk> DiskScheme<T> {
|
||||
// correctly ordered wrt IO on the same fd.
|
||||
call_request.handle_async(self).await
|
||||
}
|
||||
RequestKind::SendFd(sendfd_request) => Response::err(EOPNOTSUPP, sendfd_request),
|
||||
RequestKind::SendFd(request) => Response::err(EOPNOTSUPP, request),
|
||||
RequestKind::RecvFd(request) => Response::err(EOPNOTSUPP, request),
|
||||
RequestKind::Cancellation(_cancellation_request) => {
|
||||
// FIXME implement cancellation
|
||||
continue;
|
||||
@@ -410,7 +420,27 @@ impl<T: Disk> DiskScheme<T> {
|
||||
}
|
||||
|
||||
impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
async fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
async fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path_str: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
@@ -522,6 +552,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
stat.st_blksize = disk.block_size();
|
||||
Ok(())
|
||||
}
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -566,6 +597,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
j += 1;
|
||||
}
|
||||
}
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
}
|
||||
|
||||
Ok(i)
|
||||
@@ -599,6 +631,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.read(Some(part_num as usize), block, buf).await
|
||||
}
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -622,6 +655,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
let block = offset / u64::from(disk.block_size());
|
||||
disk.write(Some(part_num as usize), block, buf).await
|
||||
}
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -644,6 +678,7 @@ impl<T: Disk> SchemeAsync for DiskScheme<T> {
|
||||
|
||||
part.size * u64::from(disk.block_size())
|
||||
}
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ use crate::ide::{AtaCommand, AtaDisk, Channel};
|
||||
pub mod ide;
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -57,6 +57,7 @@ fn time_arm(time_handle: &mut File, secs: i64) -> io::Result<()> {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -39,10 +39,8 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
let disk_scheme_name = format!("disk.usb-{scheme}+{port}-scsi");
|
||||
|
||||
// TODO: Use eventfds.
|
||||
let handle = XhciClientHandle::new(scheme.to_owned(), port);
|
||||
|
||||
// FIXME should this wait notifying readiness until the disk scheme is created?
|
||||
daemon.ready();
|
||||
let handle =
|
||||
XhciClientHandle::new(scheme.to_owned(), port).expect("Faild to open XhciClientHandle");
|
||||
|
||||
let desc = handle
|
||||
.get_standard_descs()
|
||||
@@ -110,6 +108,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
&driver_block::FuturesExecutor,
|
||||
);
|
||||
|
||||
// FIXME should this wait notifying readiness until the disk scheme is created?
|
||||
daemon.ready();
|
||||
|
||||
//libredox::call::setrens(0, 0).expect("nvmed: failed to enter null namespace");
|
||||
|
||||
event_queue
|
||||
|
||||
@@ -9,3 +9,4 @@ edition = "2018"
|
||||
[dependencies]
|
||||
clap = "2.33"
|
||||
xhcid = { path = "../xhcid" }
|
||||
common = { path = "../../common" }
|
||||
|
||||
@@ -2,6 +2,7 @@ use clap::{App, Arg};
|
||||
use xhcid_interface::{PortId, XhciClientHandle};
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
let matches = App::new("usbctl")
|
||||
.arg(
|
||||
Arg::with_name("SCHEME")
|
||||
@@ -35,7 +36,8 @@ fn main() {
|
||||
.parse::<PortId>()
|
||||
.expect("expected PORT ID");
|
||||
|
||||
let handle = XhciClientHandle::new(scheme.to_owned(), port);
|
||||
let handle =
|
||||
XhciClientHandle::new(scheme.to_owned(), port).expect("Faild to open XhciClientHandle");
|
||||
|
||||
if let Some(_status_scmd_matches) = port_scmd_matches.subcommand_matches("status") {
|
||||
let state = handle.port_state().expect("Failed to get port state");
|
||||
|
||||
@@ -6,6 +6,7 @@ use xhcid_interface::{
|
||||
};
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
let mut args = env::args().skip(1);
|
||||
|
||||
const USAGE: &'static str = "usbhubd <scheme> <port> <interface>";
|
||||
@@ -38,7 +39,8 @@ fn main() {
|
||||
common::file_level(),
|
||||
);
|
||||
|
||||
let handle = XhciClientHandle::new(scheme.clone(), port_id);
|
||||
let handle =
|
||||
XhciClientHandle::new(scheme.clone(), port_id).expect("Faild to open XhciClientHandle");
|
||||
let desc: DevDesc = handle
|
||||
.get_standard_descs()
|
||||
.expect("Failed to get standard descriptors");
|
||||
@@ -146,7 +148,8 @@ fn main() {
|
||||
} else {
|
||||
usb::HubPortStatus::V2(usb::HubPortStatusV2::default())
|
||||
},
|
||||
handle: XhciClientHandle::new(scheme.clone(), child_port_id),
|
||||
handle: XhciClientHandle::new(scheme.clone(), child_port_id)
|
||||
.expect("Faild to open XhciClientHandle"),
|
||||
attached: false,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2,9 +2,11 @@ pub extern crate serde;
|
||||
pub extern crate smallvec;
|
||||
|
||||
use std::convert::TryFrom;
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::fs::File;
|
||||
use std::io::prelude::*;
|
||||
use std::num::NonZeroU8;
|
||||
use std::os::fd::{FromRawFd, RawFd};
|
||||
use std::string::FromUtf8Error;
|
||||
use std::{fmt, io, result, str};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
@@ -392,11 +394,20 @@ impl str::FromStr for PortId {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct XhciClientHandle {
|
||||
fd: libredox::Fd,
|
||||
scheme: String,
|
||||
port: PortId,
|
||||
}
|
||||
impl fmt::Debug for XhciClientHandle {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("XhciClientHandle")
|
||||
.field("scheme", &self.scheme)
|
||||
.field("port", &self.port)
|
||||
.field("fd", &"libredox::Fd")
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
#[repr(u8)]
|
||||
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
|
||||
pub enum PortState {
|
||||
@@ -522,34 +533,43 @@ impl DeviceReqData<'_> {
|
||||
}
|
||||
|
||||
impl XhciClientHandle {
|
||||
pub fn new(scheme: String, port: PortId) -> Self {
|
||||
Self { scheme, port }
|
||||
pub fn new(scheme: String, port: PortId) -> result::Result<Self, XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}", scheme, port);
|
||||
let fd = libredox::Fd::open(&path, libredox::flag::O_DIRECTORY, 0)?;
|
||||
Ok(Self { fd, scheme, port })
|
||||
}
|
||||
fn read(&self, path: &str) -> result::Result<Vec<u8>, XhciClientHandleError> {
|
||||
let target_fd = self.fd.openat(path, libredox::flag::O_RDONLY, 0)?;
|
||||
let stat = target_fd.stat()?;
|
||||
let mut buf: Vec<u8> = vec![0u8; stat.st_size as usize];
|
||||
let count = target_fd.read(&mut buf)?;
|
||||
buf.truncate(count);
|
||||
Ok(buf)
|
||||
}
|
||||
fn read_to_string(&self, path: &str) -> result::Result<String, XhciClientHandleError> {
|
||||
let buf = self.read(path)?;
|
||||
Ok(String::from_utf8(buf)?)
|
||||
}
|
||||
|
||||
pub fn attach(&self) -> result::Result<(), XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}/attach", self.scheme, self.port);
|
||||
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
|
||||
let mut file = self.fd.openat("attach", libredox::flag::O_WRONLY, 0)?;
|
||||
let _bytes_written = file.write(&[])?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn detach(&self) -> result::Result<(), XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}/detach", self.scheme, self.port);
|
||||
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
|
||||
let mut file = self.fd.openat("detach", libredox::flag::O_WRONLY, 0)?;
|
||||
let _bytes_written = file.write(&[])?;
|
||||
Ok(())
|
||||
}
|
||||
pub fn get_standard_descs(&self) -> result::Result<DevDesc, XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}/descriptors", self.scheme, self.port);
|
||||
let json = std::fs::read(path)?;
|
||||
let json = self.read("descriptors")?;
|
||||
Ok(serde_json::from_slice(&json)?)
|
||||
}
|
||||
pub fn configure_endpoints(
|
||||
&self,
|
||||
req: &ConfigureEndpointsReq,
|
||||
) -> result::Result<(), XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}/configure", self.scheme, self.port);
|
||||
let json = serde_json::to_vec(req)?;
|
||||
let mut file = OpenOptions::new().read(false).write(true).open(path)?;
|
||||
let mut file = self.fd.openat("configure", libredox::flag::O_WRONLY, 0)?;
|
||||
let json_bytes_written = file.write(&json)?;
|
||||
if json_bytes_written != json.len() {
|
||||
return Err(XhciClientHandleError::InvalidResponse(Invalid(
|
||||
@@ -559,23 +579,18 @@ impl XhciClientHandle {
|
||||
Ok(())
|
||||
}
|
||||
pub fn port_state(&self) -> result::Result<PortState, XhciClientHandleError> {
|
||||
let path = format!("/scheme/{}/port{}/state", self.scheme, self.port);
|
||||
let string = std::fs::read_to_string(path)?;
|
||||
let string = self.read_to_string("state")?;
|
||||
Ok(string.parse()?)
|
||||
}
|
||||
pub fn open_endpoint_ctl(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
|
||||
let path = format!(
|
||||
"/scheme/{}/port{}/endpoints/{}/ctl",
|
||||
self.scheme, self.port, num
|
||||
);
|
||||
Ok(File::open(path)?)
|
||||
let path = format!("endpoints/{}/ctl", num);
|
||||
let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?;
|
||||
Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) })
|
||||
}
|
||||
pub fn open_endpoint_data(&self, num: u8) -> result::Result<File, XhciClientHandleError> {
|
||||
let path = format!(
|
||||
"/scheme/{}/port{}/endpoints/{}/data",
|
||||
self.scheme, self.port, num
|
||||
);
|
||||
Ok(File::open(path)?)
|
||||
let path = format!("endpoints/{}/data", num);
|
||||
let fd = self.fd.openat(&path, libredox::flag::O_RDWR, 0)?;
|
||||
Ok(unsafe { File::from_raw_fd(fd.into_raw() as RawFd) })
|
||||
}
|
||||
pub fn open_endpoint(&self, num: u8) -> result::Result<XhciEndpHandle, XhciClientHandleError> {
|
||||
Ok(XhciEndpHandle {
|
||||
@@ -607,8 +622,7 @@ impl XhciClientHandle {
|
||||
};
|
||||
let json = serde_json::to_vec(&req)?;
|
||||
|
||||
let path = format!("/scheme/{}/port{}/request", self.scheme, self.port);
|
||||
let mut file = File::open(path)?;
|
||||
let file = self.fd.openat("request", libredox::flag::O_RDWR, 0)?;
|
||||
|
||||
let json_bytes_written = file.write(&json)?;
|
||||
if json_bytes_written != json.len() {
|
||||
@@ -863,4 +877,13 @@ pub enum XhciClientHandleError {
|
||||
|
||||
#[error("unexpected short packet of size {0}")]
|
||||
UnexpectedShortPacket(usize),
|
||||
|
||||
#[error("utf8 error: {0}")]
|
||||
Utf8Error(#[from] FromUtf8Error),
|
||||
}
|
||||
|
||||
impl From<libredox::error::Error> for XhciClientHandleError {
|
||||
fn from(error: libredox::error::Error) -> Self {
|
||||
Self::IoError(error.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,7 +37,7 @@ use pcid_interface::irq_helpers::{
|
||||
};
|
||||
use pcid_interface::{PciFeature, PciFeatureInfo, PciFunctionHandle};
|
||||
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
|
||||
|
||||
use crate::xhci::{InterruptMethod, Xhci};
|
||||
|
||||
@@ -143,14 +143,16 @@ fn daemon_with_context_size<const N: usize>(
|
||||
log::info!("XHCI {}", pci_config.func.display());
|
||||
|
||||
let scheme_name = format!("usb.{}", name);
|
||||
let socket = Socket::create(scheme_name.clone()).expect("xhcid: failed to create usb scheme");
|
||||
|
||||
daemon.ready();
|
||||
let socket = Socket::create().expect("xhcid: failed to create usb scheme");
|
||||
|
||||
let hci = Arc::new(
|
||||
Xhci::<N>::new(scheme_name, address, interrupt_method, pcid_handle)
|
||||
Xhci::<N>::new(scheme_name.clone(), address, interrupt_method, pcid_handle)
|
||||
.expect("xhcid: failed to allocate device"),
|
||||
);
|
||||
register_sync_scheme(&socket, &scheme_name, &mut &*hci)
|
||||
.expect("xhcid: failed to regsiter scheme to namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
xhci::start_irq_reactor(&hci, irq_file);
|
||||
xhci::start_device_enumerator(&hci);
|
||||
@@ -182,6 +184,7 @@ fn daemon_with_context_size<const N: usize>(
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
@@ -75,6 +75,8 @@ lazy_static! {
|
||||
r"port([\d\.]+)/endpoints/(\d{1,3})/(ctl|data)$"
|
||||
)
|
||||
.expect("Failed to create the regex for the port<n>/endpoints/<n>/<sub_endpoint> scheme");
|
||||
static ref REGEX_PORT_ROOT: Regex =
|
||||
Regex::new(r"^port([\d\.]+)$").expect("Failed to create the regex for the port<n> scheme.");
|
||||
static ref REGEX_TOP_LEVEL: Regex =
|
||||
Regex::new(r"^$").expect("Failed to create the regex for the top-level scheme");
|
||||
}
|
||||
@@ -141,6 +143,7 @@ pub enum Handle {
|
||||
ConfigureEndpoints(PortId), // port
|
||||
AttachDevice(PortId), // port
|
||||
DetachDevice(PortId), // port
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
/// The type of handle.
|
||||
@@ -232,6 +235,7 @@ impl Handle {
|
||||
Handle::DetachDevice(port_num) => {
|
||||
format!("port{}/detach", port_num)
|
||||
}
|
||||
Handle::SchemeRoot => String::from(""),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -263,6 +267,7 @@ impl Handle {
|
||||
EndpointHandleTy::Ctl => HandleType::Character,
|
||||
EndpointHandleTy::Root(_) => HandleType::Directory,
|
||||
},
|
||||
&Handle::SchemeRoot => HandleType::Directory,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -293,6 +298,7 @@ impl Handle {
|
||||
EndpointHandleTy::Ctl => None,
|
||||
EndpointHandleTy::Root(ref buf) => Some(buf.len()),
|
||||
},
|
||||
&Handle::SchemeRoot => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -404,6 +410,9 @@ impl SchemeParameters {
|
||||
let handle_type = get_string_from_regex(®EX_PORT_SUB_ENDPOINT, scheme, 2)?;
|
||||
|
||||
Ok(Self::Endpoint(port_num, endpoint_num, handle_type))
|
||||
} else if REGEX_PORT_ROOT.is_match(scheme) {
|
||||
let port_num = get_port_id_from_regex(®EX_PORT_ROOT, scheme, 0)?;
|
||||
Ok(Self::Port(port_num))
|
||||
} else if REGEX_TOP_LEVEL.is_match(scheme) {
|
||||
Ok(Self::TopLevel)
|
||||
} else {
|
||||
@@ -2099,7 +2108,31 @@ impl<const N: usize> Xhci<N> {
|
||||
}
|
||||
|
||||
impl<const N: usize> SchemeSync for &Xhci<N> {
|
||||
fn open(&mut self, path_str: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed);
|
||||
self.handles.insert(fd, Handle::SchemeRoot);
|
||||
Ok(fd)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path_str: &str,
|
||||
mut flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let full_path = match *self.handles.get(&dirfd).ok_or(Error::new(EBADF))? {
|
||||
Handle::SchemeRoot => path_str.trim_start_matches('/').to_string(),
|
||||
Handle::Port(port_num, _) => {
|
||||
let clean_path = path_str.trim_start_matches('/');
|
||||
if clean_path.is_empty() {
|
||||
format!("port{}", port_num)
|
||||
} else {
|
||||
format!("port{}/{}", port_num, clean_path)
|
||||
}
|
||||
}
|
||||
_ => return Err(Error::new(EACCES)),
|
||||
};
|
||||
if ctx.uid != 0 {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
@@ -2107,7 +2140,9 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
|
||||
//Parse the scheme, determine if it's in the valid format, return an error if not.
|
||||
//This doesn't guarantee that the parameters themselves are valid (i.e. bounded correctly)
|
||||
//only that the scheme itself was parseable.
|
||||
let scheme_parameters = SchemeParameters::from_scheme(path_str)?;
|
||||
let scheme_parameters = SchemeParameters::from_scheme(&full_path)?;
|
||||
|
||||
flags |= fcntl_flags as usize;
|
||||
|
||||
//Once we have our scheme parsed into parameters, we can match on those parameters to
|
||||
//find the correct routine to open a handle
|
||||
@@ -2142,7 +2177,7 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
|
||||
|
||||
let fd = self.next_handle.fetch_add(1, atomic::Ordering::Relaxed);
|
||||
|
||||
trace!("OPENED {} to FD={}, handle: {:?}", path_str, fd, handle);
|
||||
trace!("OPENED {} to FD={}, handle: {:?}", full_path, fd, handle);
|
||||
|
||||
self.handles.insert(fd, handle);
|
||||
|
||||
@@ -2228,6 +2263,7 @@ impl<const N: usize> SchemeSync for &Xhci<N> {
|
||||
Handle::ConfigureEndpoints(_) => Err(Error::new(EBADF)),
|
||||
Handle::AttachDevice(_) => Err(Error::new(EBADF)),
|
||||
Handle::DetachDevice(_) => Err(Error::new(EBADF)),
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
|
||||
&mut Handle::Endpoint(port_num, endp_num, ref mut st) => match st {
|
||||
EndpointHandleTy::Ctl => self.on_read_endp_ctl(port_num, endp_num, buf),
|
||||
|
||||
@@ -190,6 +190,7 @@ impl VboxGuestInfo {
|
||||
}
|
||||
|
||||
fn main() {
|
||||
common::init();
|
||||
pcid_interface::pci_daemon(daemon);
|
||||
}
|
||||
|
||||
|
||||
+56
-11
@@ -19,6 +19,7 @@ pub struct Listener {
|
||||
pub enum Extra {
|
||||
Client(Client),
|
||||
Listener(Listener),
|
||||
SchemeRoot,
|
||||
}
|
||||
impl Default for Extra {
|
||||
fn default() -> Self {
|
||||
@@ -115,16 +116,8 @@ impl<'sock> ChanScheme<'sock> {
|
||||
Err(err) => Err(err), // Error writing response
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
// ___ ____ _____ _ _
|
||||
// / _ \| _ \| ____| \ | |
|
||||
// | | | | |_) | _| | \| |
|
||||
// | |_| | __/| |___| |\ |
|
||||
// \___/|_| |_____|_| \_|
|
||||
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn open(&mut self, path: &str, flags: usize) -> Result<OpenResult> {
|
||||
let new_id = self.next_id;
|
||||
let mut new = Handle::default();
|
||||
new.flags = flags;
|
||||
@@ -164,7 +157,45 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
fn dup(&mut self, id: usize, buf: &[u8], ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
}
|
||||
|
||||
impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(
|
||||
id,
|
||||
Handle {
|
||||
flags: 0,
|
||||
extra: Extra::SchemeRoot,
|
||||
path: None,
|
||||
},
|
||||
);
|
||||
Ok(id)
|
||||
}
|
||||
// ___ ____ _____ _ _
|
||||
// / _ \| _ \| ____| \ | |
|
||||
// | | | | |_) | _| | \| |
|
||||
// | |_| | __/| |___| |\ |
|
||||
// \___/|_| |_____|_| \_|
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
|
||||
if !matches!(handle.extra, Extra::SchemeRoot) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
self.open(path, flags)
|
||||
}
|
||||
fn dup(&mut self, id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
match buf {
|
||||
b"listen" => {
|
||||
loop {
|
||||
@@ -190,6 +221,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
Extra::Listener(_) => {
|
||||
panic!("newly created handle can't possibly be a listener")
|
||||
}
|
||||
Extra::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
}
|
||||
self.post_fevent(remote_id, EVENT_WRITE.bits())?;
|
||||
|
||||
@@ -245,8 +277,12 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
if matches!(handle.extra, Extra::SchemeRoot) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
let flags = handle.flags;
|
||||
return self.open(path, flags, ctx);
|
||||
return self.open(path, flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -283,6 +319,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
Extra::Listener(_) => {
|
||||
panic!("somehow, a client was connected to a listener directly")
|
||||
}
|
||||
Extra::SchemeRoot => panic!("somehow, a client was connected to a SchemeRoot"),
|
||||
}
|
||||
} else if client.remote == Connection::Closed {
|
||||
Err(Error::new(EPIPE))
|
||||
@@ -303,6 +340,9 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
|
||||
// Write path
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
if let Extra::SchemeRoot = handle.extra {
|
||||
return Ok(len);
|
||||
}
|
||||
let path = handle.path.as_ref().ok_or(Error::new(EBADF))?;
|
||||
let len = cmp::min(path.len(), buf.len() - PREFIX.len());
|
||||
buf[PREFIX.len()..][..len].copy_from_slice(&path.as_bytes()[..len]);
|
||||
@@ -358,6 +398,9 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
}
|
||||
}
|
||||
Extra::Listener(_) => panic!("a client can't be connected to a listener!"),
|
||||
Extra::SchemeRoot => {
|
||||
panic!("a client can't be connected to a scheme root!")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -366,6 +409,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
self.listeners.remove(&path);
|
||||
}
|
||||
}
|
||||
Extra::SchemeRoot => {}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -403,6 +447,7 @@ impl<'sock> SchemeSync for ChanScheme<'sock> {
|
||||
events |= EVENT_READ | EVENT_WRITE;
|
||||
}
|
||||
}
|
||||
Extra::SchemeRoot => {}
|
||||
}
|
||||
Ok(events)
|
||||
}
|
||||
|
||||
+28
-6
@@ -1,5 +1,5 @@
|
||||
use event::{EventFlags, EventQueue};
|
||||
use redox_scheme::{wrappers::ReadinessBased, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, wrappers::ReadinessBased, Socket};
|
||||
use std::sync::Mutex;
|
||||
|
||||
mod chan;
|
||||
@@ -37,19 +37,19 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
|
||||
}
|
||||
|
||||
// Prepare chan scheme
|
||||
let chan_socket = Socket::nonblock("chan")
|
||||
.map_err(|e| anyhow::anyhow!("failed to create chan scheme: {e}"))?;
|
||||
let chan_socket =
|
||||
Socket::nonblock().map_err(|e| anyhow::anyhow!("failed to create chan scheme: {e}"))?;
|
||||
let chan = Mutex::new(ChanScheme::new(&chan_socket));
|
||||
let mut chan_handler = ReadinessBased::new(&chan_socket, 16);
|
||||
|
||||
// Prepare shm scheme
|
||||
let shm_socket =
|
||||
Socket::nonblock("shm").map_err(|e| anyhow::anyhow!("failed to create shm socket: {e}"))?;
|
||||
Socket::nonblock().map_err(|e| anyhow::anyhow!("failed to create shm socket: {e}"))?;
|
||||
let shm = Mutex::new(ShmScheme::new());
|
||||
let mut shm_handler = ReadinessBased::new(&shm_socket, 16);
|
||||
|
||||
// Prepare uds stream scheme
|
||||
let uds_stream_socket = Socket::nonblock("uds_stream")
|
||||
let uds_stream_socket = Socket::nonblock()
|
||||
.map_err(|e| anyhow::anyhow!("failed to create uds stream scheme: {e}"))?;
|
||||
let uds_stream = Mutex::new(
|
||||
UdsStreamScheme::new(&uds_stream_socket)
|
||||
@@ -58,7 +58,7 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
|
||||
let mut uds_stream_handler = ReadinessBased::new(&uds_stream_socket, 16);
|
||||
|
||||
// Prepare uds dgram scheme
|
||||
let uds_dgram_socket = Socket::nonblock("uds_dgram")
|
||||
let uds_dgram_socket = Socket::nonblock()
|
||||
.map_err(|e| anyhow::anyhow!("failed to create uds dgram scheme: {e}"))?;
|
||||
let uds_dgram = Mutex::new(
|
||||
UdsDgramScheme::new(&uds_dgram_socket)
|
||||
@@ -66,6 +66,28 @@ fn inner(daemon: daemon::Daemon) -> anyhow::Result<()> {
|
||||
);
|
||||
let mut uds_dgram_handler = ReadinessBased::new(&uds_dgram_socket, 16);
|
||||
|
||||
{
|
||||
let mut chan_guard = chan.lock().unwrap();
|
||||
register_sync_scheme(&chan_socket, "chan", &mut *chan_guard)
|
||||
.map_err(|e| anyhow::anyhow!("failed to register chan scheme: {e}"))?;
|
||||
}
|
||||
{
|
||||
let mut shm_guard = shm.lock().unwrap();
|
||||
register_sync_scheme(&shm_socket, "shm", &mut *shm_guard)
|
||||
.map_err(|e| anyhow::anyhow!("failed to register shm scheme: {e}"))?;
|
||||
}
|
||||
{
|
||||
let mut uds_stream_guard = uds_stream.lock().unwrap();
|
||||
register_sync_scheme(&uds_stream_socket, "uds_stream", &mut *uds_stream_guard)
|
||||
.map_err(|e| anyhow::anyhow!("failed to register uds stream scheme: {e}"))?;
|
||||
}
|
||||
{
|
||||
let mut uds_dgram_guard = uds_dgram.lock().unwrap();
|
||||
// Register schemes to namespace
|
||||
register_sync_scheme(&uds_dgram_socket, "uds_dgram", &mut *uds_dgram_guard)
|
||||
.map_err(|e| anyhow::anyhow!("failed to register uds dgram scheme: {e}"))?;
|
||||
}
|
||||
|
||||
daemon.ready();
|
||||
|
||||
// Create event listener for both files
|
||||
|
||||
+19
-11
@@ -47,19 +47,27 @@ impl ShmScheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for ShmScheme {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
//FIXME: Handle O_RDONLY/O_WRONLY/O_RDWR
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
if path.is_empty() {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
|
||||
return Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::empty(),
|
||||
});
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
let handle = self.handles.get(&dirfd).ok_or(Error::new(EBADF))?;
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let path = Rc::from(path);
|
||||
let entry = match self.maps.entry(Rc::clone(&path)) {
|
||||
Entry::Occupied(e) => {
|
||||
|
||||
+118
-51
@@ -22,6 +22,44 @@ use std::{
|
||||
};
|
||||
use syscall::{error::*, flag::*, schemev2::NewFdFlags, Error, FobtainFdFlags, Stat};
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Socket {
|
||||
primary_id: usize,
|
||||
path: Option<String>,
|
||||
state: State,
|
||||
peer: Option<usize>,
|
||||
messages: VecDeque<DataPacket>,
|
||||
options: HashSet<i32>,
|
||||
fds: VecDeque<usize>,
|
||||
flags: usize,
|
||||
issued_token: Option<u64>,
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
fn drop_fds(&mut self, num_fd: usize) -> Result<()> {
|
||||
for i in 0..num_fd {
|
||||
if self.fds.pop_front().is_none() {
|
||||
eprintln!("Socket::drop_fds: Attempted to drop FD #{} of {}, but fd queue is empty. State inconsistency.", i + 1, num_fd);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
Unbound,
|
||||
Bound,
|
||||
Closed,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self::Unbound
|
||||
}
|
||||
}
|
||||
|
||||
impl DataPacket {
|
||||
pub fn serialize_to_stream(
|
||||
self,
|
||||
@@ -70,46 +108,26 @@ impl DataPacket {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub enum State {
|
||||
Unbound,
|
||||
Bound,
|
||||
Closed,
|
||||
enum Handle {
|
||||
Socket(Rc<RefCell<Socket>>),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
impl Default for State {
|
||||
fn default() -> Self {
|
||||
Self::Unbound
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
pub struct Socket {
|
||||
primary_id: usize,
|
||||
path: Option<String>,
|
||||
state: State,
|
||||
peer: Option<usize>,
|
||||
messages: VecDeque<DataPacket>,
|
||||
options: HashSet<i32>,
|
||||
fds: VecDeque<usize>,
|
||||
flags: usize,
|
||||
issued_token: Option<u64>,
|
||||
}
|
||||
|
||||
impl Socket {
|
||||
fn drop_fds(&mut self, num_fd: usize) -> Result<()> {
|
||||
for i in 0..num_fd {
|
||||
if self.fds.pop_front().is_none() {
|
||||
eprintln!("Socket::drop_fds: Attempted to drop FD #{} of {}, but fd queue is empty. State inconsistency.", i + 1, num_fd);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
impl Handle {
|
||||
fn as_socket(&self) -> Option<&Rc<RefCell<Socket>>> {
|
||||
if let Self::Socket(socket) = self {
|
||||
Some(socket)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn is_scheme_root(&self) -> bool {
|
||||
matches!(self, Self::SchemeRoot)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UdsDgramScheme<'sock> {
|
||||
sockets: HashMap<usize, Rc<RefCell<Socket>>>,
|
||||
handles: HashMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
socket_paths: HashMap<String, Rc<RefCell<Socket>>>,
|
||||
socket_tokens: HashMap<u64, Rc<RefCell<Socket>>>,
|
||||
@@ -121,15 +139,18 @@ pub struct UdsDgramScheme<'sock> {
|
||||
impl<'sock> UdsDgramScheme<'sock> {
|
||||
pub fn new(socket: &'sock SchemeSocket) -> Result<Self> {
|
||||
Ok(Self {
|
||||
sockets: HashMap::new(),
|
||||
handles: HashMap::new(),
|
||||
next_id: 0,
|
||||
socket_paths: HashMap::new(),
|
||||
socket_tokens: HashMap::new(),
|
||||
socket,
|
||||
proc_creds_capability: syscall::open(
|
||||
"/scheme/proc/proc-creds-capability",
|
||||
syscall::O_RDONLY,
|
||||
)?,
|
||||
proc_creds_capability: {
|
||||
libredox::call::open(
|
||||
"/scheme/proc/proc-creds-capability",
|
||||
libredox::flag::O_RDONLY,
|
||||
0,
|
||||
)?
|
||||
},
|
||||
rng: SmallRng::from_entropy(),
|
||||
})
|
||||
}
|
||||
@@ -147,7 +168,14 @@ impl<'sock> UdsDgramScheme<'sock> {
|
||||
}
|
||||
|
||||
fn get_socket(&self, id: usize) -> Result<&Rc<RefCell<Socket>>, Error> {
|
||||
self.sockets.get(&id).ok_or(Error::new(EBADF))
|
||||
self.handles
|
||||
.get(&id)
|
||||
.and_then(Handle::as_socket)
|
||||
.ok_or(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn insert_socket(&mut self, id: usize, socket: Rc<RefCell<Socket>>) {
|
||||
self.handles.insert(id, Handle::Socket(socket));
|
||||
}
|
||||
|
||||
fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc<RefCell<Socket>>), Error> {
|
||||
@@ -177,7 +205,7 @@ impl<'sock> UdsDgramScheme<'sock> {
|
||||
new.flags = flags;
|
||||
new.primary_id = new_id;
|
||||
|
||||
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
|
||||
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
|
||||
self.next_id += 1;
|
||||
new_id
|
||||
}
|
||||
@@ -473,7 +501,7 @@ impl<'sock> UdsDgramScheme<'sock> {
|
||||
// why not)
|
||||
self.post_fevent(id, (EVENT_READ | EVENT_WRITE).bits())?;
|
||||
|
||||
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
|
||||
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
|
||||
|
||||
self.next_id += 1;
|
||||
|
||||
@@ -496,7 +524,7 @@ impl<'sock> UdsDgramScheme<'sock> {
|
||||
|
||||
let new_id = self.next_id;
|
||||
|
||||
self.sockets.insert(new_id, socket_rc.clone());
|
||||
self.insert_socket(new_id, socket_rc.clone());
|
||||
self.next_id += 1;
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
@@ -625,9 +653,45 @@ impl<'sock> UdsDgramScheme<'sock> {
|
||||
}
|
||||
|
||||
impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let new_id = self.next_id;
|
||||
self.handles.insert(new_id, Handle::SchemeRoot);
|
||||
self.next_id += 1;
|
||||
Ok(new_id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
mut flags: usize,
|
||||
fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
{
|
||||
let Some(handle) = self.handles.get(&fd) else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
if !handle.is_scheme_root() {
|
||||
eprintln!(
|
||||
"openat(fd: {}, path: '{}'): fd is not an open capability.",
|
||||
fd, path
|
||||
);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
flags |= fcntl_flags as usize;
|
||||
|
||||
let new_id = if path.is_empty() {
|
||||
self.handle_unnamed_socket(flags)
|
||||
if flags & O_CREAT == O_CREAT {
|
||||
self.handle_unnamed_socket(flags)
|
||||
} else {
|
||||
eprintln!(
|
||||
"open(path: '{}'): Attempting to open an unnamed socket without O_CREAT.",
|
||||
path
|
||||
);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
} else {
|
||||
eprintln!(
|
||||
"open(path: '{}'): Attempting to open a named socket, which is not supported.",
|
||||
@@ -674,12 +738,15 @@ impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let socket_rc = self.get_socket(id)?;
|
||||
let socket = socket_rc.borrow();
|
||||
|
||||
let empty = String::new();
|
||||
let path = socket.path.as_ref().unwrap_or(&empty);
|
||||
Ok(Self::fpath_inner(path, buf)?)
|
||||
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::SchemeRoot => Ok(Self::fpath_inner(&String::new(), buf)?),
|
||||
Handle::Socket(socket_rc) => {
|
||||
let socket = socket_rc.borrow();
|
||||
let empty = String::new();
|
||||
let path = socket.path.as_ref().unwrap_or(&empty);
|
||||
Ok(Self::fpath_inner(path, buf)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
@@ -698,7 +765,7 @@ impl<'sock> SchemeSync for UdsDgramScheme<'sock> {
|
||||
}
|
||||
|
||||
fn on_close(&mut self, id: usize) {
|
||||
let Some(socket_rc) = self.sockets.remove(&id) else {
|
||||
let Some(Handle::Socket(socket_rc)) = self.handles.remove(&id) else {
|
||||
return;
|
||||
};
|
||||
let mut socket = socket_rc.borrow_mut();
|
||||
|
||||
+30
-67
@@ -1,4 +1,5 @@
|
||||
use redox_rt::protocol::ProcMeta;
|
||||
use std::fmt::Debug;
|
||||
use std::{cmp, convert::TryInto, mem};
|
||||
use syscall::{error::*, Error};
|
||||
|
||||
@@ -143,79 +144,41 @@ impl DataPacket {
|
||||
}
|
||||
}
|
||||
|
||||
trait NumFromBytes: Sized + Debug {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
|
||||
}
|
||||
|
||||
macro_rules! num_from_bytes_impl {
|
||||
($($t:ty),*) => {
|
||||
$(
|
||||
impl NumFromBytes for $t {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error> {
|
||||
let size = mem::size_of::<Self>();
|
||||
let buffer_slice = buffer.get(..size).and_then(|s| s.try_into().ok());
|
||||
|
||||
if let Some(slice) = buffer_slice {
|
||||
Ok(Self::from_le_bytes(slice))
|
||||
} else {
|
||||
eprintln!(
|
||||
"read_num: buffer is too short to read num of size {} (buffer len: {})",
|
||||
size, buffer.len()
|
||||
);
|
||||
Err(Error::new(EINVAL))
|
||||
}
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
num_from_bytes_impl!(i32, u32, u64, usize);
|
||||
|
||||
fn read_num<T>(buffer: &[u8]) -> Result<T, Error>
|
||||
where
|
||||
T: NumFromBytes,
|
||||
{
|
||||
T::from_le_bytes_slice(buffer)
|
||||
}
|
||||
trait NumFromBytes: Sized {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self, Error>;
|
||||
}
|
||||
impl NumFromBytes for i32 {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
|
||||
Ok(i32::from_le_bytes(
|
||||
buffer
|
||||
.get(..mem::size_of::<i32>())
|
||||
.and_then(|slice| slice.try_into().ok())
|
||||
.ok_or_else(|| {
|
||||
eprintln!(
|
||||
"read_num: buffer is too short to read num len: {}",
|
||||
buffer.len()
|
||||
);
|
||||
Error::new(EINVAL)
|
||||
})?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl NumFromBytes for u32 {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
|
||||
Ok(u32::from_le_bytes(
|
||||
buffer
|
||||
.get(..mem::size_of::<u32>())
|
||||
.and_then(|slice| slice.try_into().ok())
|
||||
.ok_or_else(|| {
|
||||
eprintln!(
|
||||
"read_num: buffer is too short to read num len: {}",
|
||||
buffer.len()
|
||||
);
|
||||
Error::new(EINVAL)
|
||||
})?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl NumFromBytes for u64 {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
|
||||
Ok(u64::from_le_bytes(
|
||||
buffer
|
||||
.get(..mem::size_of::<u64>())
|
||||
.and_then(|slice| slice.try_into().ok())
|
||||
.ok_or_else(|| {
|
||||
eprintln!(
|
||||
"read_num: buffer is too short to read num len: {}",
|
||||
buffer.len()
|
||||
);
|
||||
Error::new(EINVAL)
|
||||
})?,
|
||||
))
|
||||
}
|
||||
}
|
||||
impl NumFromBytes for usize {
|
||||
fn from_le_bytes_slice(buffer: &[u8]) -> Result<Self> {
|
||||
Ok(usize::from_le_bytes(
|
||||
buffer
|
||||
.get(..mem::size_of::<usize>())
|
||||
.and_then(|slice| slice.try_into().ok())
|
||||
.ok_or_else(|| {
|
||||
eprintln!(
|
||||
"read_num: buffer is too short to read num len: {}",
|
||||
buffer.len()
|
||||
);
|
||||
Error::new(EINVAL)
|
||||
})?,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
fn get_uid_gid_from_pid(cap_fd: usize, target_pid: usize) -> Result<(u32, u32, u32)> {
|
||||
let mut buffer = [0u8; mem::size_of::<ProcMeta>()];
|
||||
|
||||
+86
-18
@@ -364,8 +364,26 @@ impl Socket {
|
||||
}
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
Socket(Rc<RefCell<Socket>>),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
fn as_socket(&self) -> Option<&Rc<RefCell<Socket>>> {
|
||||
if let Self::Socket(socket) = self {
|
||||
Some(socket)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
fn is_scheme_root(&self) -> bool {
|
||||
matches!(self, Self::SchemeRoot)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct UdsStreamScheme<'sock> {
|
||||
sockets: HashMap<usize, Rc<RefCell<Socket>>>,
|
||||
handles: HashMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
socket_paths: HashMap<String, Rc<RefCell<Socket>>>,
|
||||
socket_tokens: HashMap<u64, Rc<RefCell<Socket>>>,
|
||||
@@ -377,15 +395,18 @@ pub struct UdsStreamScheme<'sock> {
|
||||
impl<'sock> UdsStreamScheme<'sock> {
|
||||
pub fn new(socket: &'sock SchemeSocket) -> Result<Self> {
|
||||
Ok(Self {
|
||||
sockets: HashMap::new(),
|
||||
handles: HashMap::new(),
|
||||
next_id: 0,
|
||||
socket_paths: HashMap::new(),
|
||||
socket_tokens: HashMap::new(),
|
||||
socket,
|
||||
proc_creds_capability: syscall::open(
|
||||
"/scheme/proc/proc-creds-capability",
|
||||
syscall::O_RDONLY,
|
||||
)?,
|
||||
proc_creds_capability: {
|
||||
libredox::call::open(
|
||||
"/scheme/proc/proc-creds-capability",
|
||||
libredox::flag::O_RDONLY,
|
||||
0,
|
||||
)?
|
||||
},
|
||||
rng: SmallRng::from_entropy(),
|
||||
})
|
||||
}
|
||||
@@ -409,7 +430,14 @@ impl<'sock> UdsStreamScheme<'sock> {
|
||||
}
|
||||
|
||||
fn get_socket(&self, id: usize) -> Result<&Rc<RefCell<Socket>>, Error> {
|
||||
self.sockets.get(&id).ok_or(Error::new(EBADF))
|
||||
self.handles
|
||||
.get(&id)
|
||||
.and_then(Handle::as_socket)
|
||||
.ok_or(Error::new(EBADF))
|
||||
}
|
||||
|
||||
fn insert_socket(&mut self, id: usize, socket: Rc<RefCell<Socket>>) {
|
||||
self.handles.insert(id, Handle::Socket(socket));
|
||||
}
|
||||
|
||||
fn get_connected_peer(&self, id: usize) -> Result<(usize, Rc<RefCell<Socket>>), Error> {
|
||||
@@ -443,7 +471,7 @@ impl<'sock> UdsStreamScheme<'sock> {
|
||||
None,
|
||||
ctx,
|
||||
);
|
||||
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
|
||||
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
|
||||
self.next_id += 1;
|
||||
new_id
|
||||
}
|
||||
@@ -850,7 +878,7 @@ impl<'sock> UdsStreamScheme<'sock> {
|
||||
};
|
||||
|
||||
self.next_id += 1;
|
||||
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
|
||||
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
|
||||
self.post_fevent(client_id, EVENT_READ | EVENT_WRITE)?;
|
||||
Ok(Some(OpenResult::ThisScheme {
|
||||
number: new_id,
|
||||
@@ -961,7 +989,7 @@ impl<'sock> UdsStreamScheme<'sock> {
|
||||
// why not)
|
||||
self.post_fevent(id, EVENT_READ | EVENT_WRITE)?;
|
||||
|
||||
self.sockets.insert(new_id, Rc::new(RefCell::new(new)));
|
||||
self.insert_socket(new_id, Rc::new(RefCell::new(new)));
|
||||
|
||||
self.next_id += 1;
|
||||
|
||||
@@ -1195,9 +1223,45 @@ impl<'sock> UdsStreamScheme<'sock> {
|
||||
}
|
||||
|
||||
impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let new_id = self.next_id;
|
||||
self.handles.insert(new_id, Handle::SchemeRoot);
|
||||
self.next_id += 1;
|
||||
Ok(new_id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
mut flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
{
|
||||
let Some(handle) = self.handles.get(&fd) else {
|
||||
return Err(Error::new(EBADF));
|
||||
};
|
||||
if !handle.is_scheme_root() {
|
||||
eprintln!(
|
||||
"openat(fd: {}, path: '{}'): fd is not an open capability.",
|
||||
fd, path
|
||||
);
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
|
||||
flags |= fcntl_flags as usize;
|
||||
|
||||
let new_id = if path.is_empty() {
|
||||
self.handle_unnamed_socket(flags, ctx)
|
||||
if flags & O_CREAT == O_CREAT {
|
||||
self.handle_unnamed_socket(flags, ctx)
|
||||
} else {
|
||||
eprintln!(
|
||||
"open(path: '{}'): Attempting to open an unnamed socket without O_CREAT.",
|
||||
path
|
||||
);
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
} else {
|
||||
eprintln!(
|
||||
"open(path: '{}'): Attempting to open a named socket, which is not supported.",
|
||||
@@ -1243,11 +1307,15 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let socket_rc = self.get_socket(id)?;
|
||||
let socket = socket_rc.borrow();
|
||||
let empty = String::new();
|
||||
let path = socket.path.as_ref().unwrap_or(&empty);
|
||||
Ok(Self::fpath_inner(path, buf)?)
|
||||
match self.handles.get(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::SchemeRoot => Ok(Self::fpath_inner(&String::new(), buf)?),
|
||||
Handle::Socket(socket_rc) => {
|
||||
let socket = socket_rc.borrow();
|
||||
let empty = String::new();
|
||||
let path = socket.path.as_ref().unwrap_or(&empty);
|
||||
Ok(Self::fpath_inner(path, buf)?)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
@@ -1288,7 +1356,7 @@ impl<'sock> SchemeSync for UdsStreamScheme<'sock> {
|
||||
}
|
||||
|
||||
fn on_close(&mut self, id: usize) {
|
||||
let Some(socket_rc) = self.sockets.remove(&id) else {
|
||||
let Some(Handle::Socket(socket_rc)) = self.handles.remove(&id) else {
|
||||
return;
|
||||
};
|
||||
|
||||
|
||||
+20
-4
@@ -1,4 +1,7 @@
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{
|
||||
scheme::{register_sync_scheme, SchemeSync},
|
||||
RequestKind, Response, SignalBehavior, Socket,
|
||||
};
|
||||
use std::process;
|
||||
|
||||
use crate::scheme::LogScheme;
|
||||
@@ -6,12 +9,17 @@ use crate::scheme::LogScheme;
|
||||
mod scheme;
|
||||
|
||||
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
let socket = Socket::create("log").expect("logd: failed to create log scheme");
|
||||
let socket = Socket::create().expect("logd: failed to create log scheme");
|
||||
|
||||
let mut scheme = LogScheme::new(&socket);
|
||||
|
||||
register_sync_scheme(&socket, "log", &mut scheme)
|
||||
.expect("logd: failed to register scheme to namespace");
|
||||
|
||||
libredox::call::setrens(0, 0).expect("logd: failed to enter null namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
let mut scheme = LogScheme::new();
|
||||
|
||||
while let Some(request) = socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
.expect("logd: failed to read events from log scheme")
|
||||
@@ -22,6 +30,14 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
scheme.on_close(id);
|
||||
continue;
|
||||
}
|
||||
RequestKind::SendFd(sendfd_request) => {
|
||||
let result = scheme.on_sendfd(&sendfd_request);
|
||||
let resp = Response::new(result, sendfd_request);
|
||||
socket
|
||||
.write_response(resp, SignalBehavior::Restart)
|
||||
.expect("logd: failed to write responses to log scheme");
|
||||
continue;
|
||||
}
|
||||
_ => continue,
|
||||
};
|
||||
|
||||
|
||||
+67
-36
@@ -2,11 +2,12 @@ use std::collections::{BTreeMap, VecDeque};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::io::{Read, Write};
|
||||
use std::mem;
|
||||
use std::os::fd::{FromRawFd, RawFd};
|
||||
use std::path::PathBuf;
|
||||
use std::sync::mpsc::{self, Sender};
|
||||
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use redox_scheme::{CallerCtx, OpenResult, SendFdRequest, Socket};
|
||||
use syscall::error::*;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
|
||||
@@ -16,10 +17,12 @@ pub enum LogHandle {
|
||||
bufs: BTreeMap<usize, Vec<u8>>,
|
||||
},
|
||||
AddSink,
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
pub struct LogScheme {
|
||||
pub struct LogScheme<'sock> {
|
||||
next_id: usize,
|
||||
socket: &'sock Socket,
|
||||
output_tx: Sender<OutputCmd>,
|
||||
handles: BTreeMap<usize, LogHandle>,
|
||||
}
|
||||
@@ -28,16 +31,18 @@ enum OutputCmd {
|
||||
Log(Vec<u8>),
|
||||
/// Log a message from the kernel. This skips writing it back to the kernel debug output.
|
||||
LogKernel(Vec<u8>),
|
||||
AddSink(PathBuf),
|
||||
AddSink(usize),
|
||||
}
|
||||
|
||||
impl LogScheme {
|
||||
pub fn new() -> Self {
|
||||
impl<'sock> LogScheme<'sock> {
|
||||
pub fn new(socket: &'sock Socket) -> Self {
|
||||
let mut kernel_debug = OpenOptions::new()
|
||||
.write(true)
|
||||
.open("/scheme/debug")
|
||||
.unwrap();
|
||||
|
||||
let mut kernel_sys_log = std::fs::File::open("/scheme/sys/log").unwrap();
|
||||
|
||||
let (output_tx, output_rx) = mpsc::channel::<OutputCmd>();
|
||||
|
||||
std::thread::spawn(move || {
|
||||
@@ -69,20 +74,14 @@ impl LogScheme {
|
||||
logs.pop_front();
|
||||
}
|
||||
}
|
||||
OutputCmd::AddSink(sink_path) => {
|
||||
match OpenOptions::new().write(true).open(&sink_path) {
|
||||
Ok(mut file) => {
|
||||
for line in &logs {
|
||||
let _ = file.write(line);
|
||||
let _ = file.flush();
|
||||
}
|
||||
|
||||
files.push(file)
|
||||
}
|
||||
Err(err) => {
|
||||
eprintln!("logd: failed to open {:?}: {:?}", sink_path, err)
|
||||
}
|
||||
OutputCmd::AddSink(log_fd) => {
|
||||
let mut file = unsafe { File::from_raw_fd(log_fd as RawFd) };
|
||||
for line in &logs {
|
||||
let _ = file.write(line);
|
||||
let _ = file.flush();
|
||||
}
|
||||
|
||||
files.push(file)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -90,12 +89,11 @@ impl LogScheme {
|
||||
|
||||
let output_tx2 = output_tx.clone();
|
||||
std::thread::spawn(move || {
|
||||
let mut debug_file = std::fs::File::open("/scheme/sys/log").unwrap();
|
||||
let mut handle_buf = vec![];
|
||||
let mut buf = [0; 4096];
|
||||
buf[.."kernel: ".len()].copy_from_slice(b"kernel: ");
|
||||
loop {
|
||||
let n = debug_file.read(&mut buf["kernel: ".len()..]).unwrap();
|
||||
let n = kernel_sys_log.read(&mut buf["kernel: ".len()..]).unwrap();
|
||||
if n == 0 {
|
||||
// FIXME currently possible as /scheme/log/kernel presents a snapshot of the log queue
|
||||
break;
|
||||
@@ -106,6 +104,7 @@ impl LogScheme {
|
||||
|
||||
LogScheme {
|
||||
next_id: 0,
|
||||
socket,
|
||||
output_tx,
|
||||
handles: BTreeMap::new(),
|
||||
}
|
||||
@@ -144,8 +143,28 @@ impl LogScheme {
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeSync for LogScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
impl<'sock> SchemeSync for LogScheme<'sock> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, LogHandle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
LogHandle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
@@ -192,17 +211,7 @@ impl SchemeSync for LogScheme {
|
||||
) -> Result<usize> {
|
||||
let (context, bufs) = match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
LogHandle::Log { context, bufs } => (context, bufs),
|
||||
LogHandle::AddSink => {
|
||||
// FIXME maybe check if root
|
||||
|
||||
let sink_path = PathBuf::from(
|
||||
String::from_utf8(buf.to_owned()).map_err(|_| Error::new(EINVAL))?,
|
||||
);
|
||||
|
||||
self.output_tx.send(OutputCmd::AddSink(sink_path)).unwrap();
|
||||
|
||||
return Ok(buf.len());
|
||||
}
|
||||
LogHandle::SchemeRoot | LogHandle::AddSink => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
let handle_buf = bufs.entry(ctx.pid).or_insert_with(|| Vec::new());
|
||||
@@ -212,6 +221,29 @@ impl SchemeSync for LogScheme {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn on_sendfd(&mut self, sendfd_request: &SendFdRequest) -> Result<usize> {
|
||||
let id = sendfd_request.id();
|
||||
|
||||
if !matches!(
|
||||
self.handles.get(&id).ok_or(Error::new(EBADF))?,
|
||||
LogHandle::AddSink
|
||||
) {
|
||||
return Err(Error::new(EBADF));
|
||||
}
|
||||
|
||||
let mut new_fd = usize::MAX;
|
||||
if let Err(e) = sendfd_request.obtain_fd(
|
||||
&self.socket,
|
||||
syscall::FobtainFdFlags::CLOEXEC,
|
||||
std::slice::from_mut(&mut new_fd),
|
||||
) {
|
||||
return Err(e);
|
||||
}
|
||||
self.output_tx.send(OutputCmd::AddSink(new_fd)).unwrap();
|
||||
|
||||
Ok(1)
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
@@ -232,6 +264,7 @@ impl SchemeSync for LogScheme {
|
||||
let path_bytes = match handle {
|
||||
LogHandle::Log { context, .. } => context.as_bytes(),
|
||||
LogHandle::AddSink => b"add_sink",
|
||||
LogHandle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
let mut j = 0;
|
||||
while i < buf.len() && j < path_bytes.len() {
|
||||
@@ -250,10 +283,8 @@ impl SchemeSync for LogScheme {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl LogScheme {
|
||||
pub fn on_close(&mut self, id: usize) {
|
||||
fn on_close(&mut self, id: usize) {
|
||||
self.handles.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
+15
-13
@@ -63,24 +63,24 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
.context("failed to get mac address from network adapter")?;
|
||||
|
||||
trace!("opening ip scheme socket");
|
||||
let ip_fd = Socket::nonblock("ip")
|
||||
.map_err(|e| anyhow!("failed to open create ip scheme socket: {}", e))?;
|
||||
let ip_fd = Socket::nonblock()
|
||||
.map_err(|e| anyhow!("failed to open create ip scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening udp scheme socket");
|
||||
let udp_fd =
|
||||
Socket::nonblock("udp").map_err(|e| anyhow!("failed to open udp scheme socket: {}", e))?;
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open udp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening tcp scheme socket");
|
||||
let tcp_fd =
|
||||
Socket::nonblock("tcp").map_err(|e| anyhow!("failed to open tcp scheme socket: {}", e))?;
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open tcp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening icmp scheme socket");
|
||||
let icmp_fd = Socket::nonblock("icmp")
|
||||
.map_err(|e| anyhow!("failed to open icmp scheme socket: {}", e))?;
|
||||
let icmp_fd =
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open icmp scheme socket: {:?}", e))?;
|
||||
|
||||
trace!("opening netcfg scheme socket");
|
||||
let netcfg_fd = Socket::nonblock("netcfg")
|
||||
.map_err(|e| anyhow!("failed to open netcfg scheme socket {}", e))?;
|
||||
let netcfg_fd =
|
||||
Socket::nonblock().map_err(|e| anyhow!("failed to open netcfg scheme socket {:?}", e))?;
|
||||
|
||||
let time_path = format!("/scheme/time/{}", syscall::CLOCK_MONOTONIC);
|
||||
let time_fd = Fd::open(&time_path, O_RDWR, 0).context("failed to open /scheme/time")?;
|
||||
@@ -97,17 +97,18 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
}
|
||||
}
|
||||
|
||||
let event_queue = EventQueue::<EventSource>::new().context("failed to create event queue")?;
|
||||
let event_queue = EventQueue::<EventSource>::new()
|
||||
.map_err(|e| anyhow!("failed to create event queue: {:?}", e))?;
|
||||
|
||||
daemon.ready();
|
||||
|
||||
event_queue
|
||||
.subscribe(network_fd.raw(), EventSource::Network, EventFlags::READ)
|
||||
.context("failed to listen to network events")?;
|
||||
.map_err(|e| anyhow!("failed to listen to network events: {:?}", e))?;
|
||||
|
||||
event_queue
|
||||
.subscribe(time_fd.raw(), EventSource::Time, EventFlags::READ)
|
||||
.context("failed to listen to timer events")?;
|
||||
.map_err(|e| anyhow!("failed to listen to timer events: {:?}", e))?;
|
||||
|
||||
event_queue
|
||||
.subscribe(ip_fd.inner().raw(), EventSource::IpScheme, EventFlags::READ)
|
||||
@@ -154,7 +155,8 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
icmp_fd,
|
||||
time_fd,
|
||||
netcfg_fd,
|
||||
);
|
||||
)
|
||||
.context("smolnetd: failed to initialize smolnetd")?;
|
||||
|
||||
libredox::call::setrens(0, 0).context("smolnetd: failed to enter null namespace")?;
|
||||
|
||||
@@ -167,7 +169,7 @@ fn run(daemon: daemon::Daemon) -> Result<()> {
|
||||
.into_iter()
|
||||
.chain(event_queue.map(|r| r.map(|e| e.user_data)))
|
||||
{
|
||||
match event_res? {
|
||||
match event_res.map_err(|e| anyhow!("event result is error: {:?}", e))? {
|
||||
EventSource::Network => smolnetd.on_network_scheme_event(),
|
||||
EventSource::Time => smolnetd.on_time_event(),
|
||||
EventSource::IpScheme => smolnetd.on_ip_scheme_event(),
|
||||
|
||||
+25
-14
@@ -4,7 +4,7 @@ use crate::link::{loopback::LoopbackDevice, DeviceList};
|
||||
use crate::router::route_table::{RouteTable, Rule};
|
||||
use crate::router::Router;
|
||||
use crate::scheme::smoltcp::iface::SocketSet as SmoltcpSocketSet;
|
||||
use crate::scheme::socket::{SchemeSocket, SocketScheme};
|
||||
use crate::scheme::socket::{Handle, SchemeSocket, SocketScheme};
|
||||
use libredox::flag;
|
||||
use libredox::Fd;
|
||||
use redox_scheme::{
|
||||
@@ -87,7 +87,7 @@ impl Smolnetd {
|
||||
icmp_file: Socket,
|
||||
time_file: Fd,
|
||||
netcfg_file: Socket,
|
||||
) -> Smolnetd {
|
||||
) -> Result<Smolnetd> {
|
||||
let protocol_addrs = vec![
|
||||
//This is a placeholder IP for DHCP
|
||||
IpCidr::new(IpAddress::v4(0, 0, 0, 0), 8),
|
||||
@@ -131,43 +131,47 @@ impl Smolnetd {
|
||||
devices.borrow_mut().push(loopback);
|
||||
devices.borrow_mut().push(eth0);
|
||||
|
||||
Smolnetd {
|
||||
Ok(Smolnetd {
|
||||
iface: Rc::clone(&iface),
|
||||
router_device: network_device,
|
||||
socket_set: Rc::clone(&socket_set),
|
||||
timer: ::std::time::Instant::now(),
|
||||
time_file: unsafe { File::from_raw_fd(time_file.into_raw() as RawFd) },
|
||||
ip_scheme: IpScheme::new(
|
||||
"ip",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
ip_file,
|
||||
),
|
||||
)?,
|
||||
udp_scheme: UdpScheme::new(
|
||||
"udp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
udp_file,
|
||||
),
|
||||
)?,
|
||||
tcp_scheme: TcpScheme::new(
|
||||
"tcp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
tcp_file,
|
||||
),
|
||||
)?,
|
||||
icmp_scheme: IcmpScheme::new(
|
||||
"icmp",
|
||||
Rc::clone(&iface),
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&socket_set),
|
||||
icmp_file,
|
||||
),
|
||||
)?,
|
||||
netcfg_scheme: NetCfgScheme::new(
|
||||
Rc::clone(&iface),
|
||||
netcfg_file,
|
||||
Rc::clone(&route_table),
|
||||
Rc::clone(&devices),
|
||||
),
|
||||
}
|
||||
)?,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn on_network_scheme_event(&mut self) -> Result<()> {
|
||||
@@ -319,15 +323,19 @@ where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
iface: Interface,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: Socket,
|
||||
) -> Self {
|
||||
Self {
|
||||
scheme: SocketScheme::<SocketT>::new(iface, route_table, socket_set, scheme_file),
|
||||
) -> Result<Self> {
|
||||
Ok(Self {
|
||||
scheme: SocketScheme::<SocketT>::new(name, iface, route_table, socket_set, scheme_file)
|
||||
.map_err(|e| {
|
||||
Error::from_syscall_error(e, &format!("failed to initialize {} scheme", name))
|
||||
})?,
|
||||
wait_queue: Vec::new(),
|
||||
}
|
||||
})
|
||||
}
|
||||
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
let result = loop {
|
||||
@@ -442,7 +450,10 @@ where
|
||||
// Notify non-blocking sockets
|
||||
let scheme = &mut self.scheme;
|
||||
|
||||
for (&fd, ref mut file) in &mut scheme.files {
|
||||
for (&fd, handle) in &mut scheme.handles {
|
||||
let Handle::File(file) = handle else {
|
||||
continue;
|
||||
};
|
||||
let events = {
|
||||
let mut socket_set = scheme.socket_set.borrow_mut();
|
||||
file.events(&mut socket_set)
|
||||
|
||||
@@ -3,7 +3,8 @@ mod nodes;
|
||||
mod notifier;
|
||||
|
||||
use redox_scheme::{
|
||||
scheme::SchemeSync, CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket,
|
||||
scheme::register_scheme_inner, scheme::SchemeSync, CallerCtx, OpenResult, RequestKind,
|
||||
Response, SignalBehavior, Socket,
|
||||
};
|
||||
use smoltcp::wire::{EthernetAddress, IpAddress, IpCidr, Ipv4Address};
|
||||
use std::cell::RefCell;
|
||||
@@ -324,10 +325,15 @@ impl NetCfgFile {
|
||||
}
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
SchemeRoot,
|
||||
File(NetCfgFile),
|
||||
}
|
||||
|
||||
pub struct NetCfgScheme {
|
||||
scheme_file: Socket,
|
||||
next_fd: usize,
|
||||
files: BTreeMap<usize, NetCfgFile>,
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
root_node: CfgNodeRef,
|
||||
notifier: NotifierRef,
|
||||
}
|
||||
@@ -338,15 +344,15 @@ impl NetCfgScheme {
|
||||
scheme_file: Socket,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
devices: Rc<RefCell<DeviceList>>,
|
||||
) -> NetCfgScheme {
|
||||
) -> Result<NetCfgScheme> {
|
||||
let notifier = Notifier::new_ref();
|
||||
let dns_config = Rc::new(RefCell::new(DNSConfig {
|
||||
name_server: Ipv4Address::new(8, 8, 8, 8),
|
||||
}));
|
||||
NetCfgScheme {
|
||||
let mut scheme = NetCfgScheme {
|
||||
scheme_file,
|
||||
next_fd: 1,
|
||||
files: BTreeMap::new(),
|
||||
handles: BTreeMap::new(),
|
||||
root_node: mk_root_node(
|
||||
iface,
|
||||
Rc::clone(¬ifier),
|
||||
@@ -355,7 +361,14 @@ impl NetCfgScheme {
|
||||
devices,
|
||||
),
|
||||
notifier,
|
||||
}
|
||||
};
|
||||
let cap_id = scheme
|
||||
.scheme_root()
|
||||
.map_err(|e| Error::from_syscall_error(e, "failed to get scheme root id"))?;
|
||||
register_scheme_inner(&scheme.scheme_file, "netcfg", cap_id).map_err(|e| {
|
||||
Error::from_syscall_error(e, "failed to register netcfg scheme to namespace")
|
||||
})?;
|
||||
Ok(scheme)
|
||||
}
|
||||
|
||||
pub fn on_scheme_event(&mut self) -> Result<Option<()>> {
|
||||
@@ -418,7 +431,32 @@ impl NetCfgScheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for NetCfgScheme {
|
||||
fn open(&mut self, path: &str, _flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
fn scheme_root(&mut self) -> SyscallResult<usize> {
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> SyscallResult<OpenResult> {
|
||||
{
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&dirfd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if !matches!(handle, Handle::SchemeRoot) {
|
||||
return Err(SyscallError::new(syscall::EACCES));
|
||||
}
|
||||
}
|
||||
|
||||
let mut current_node = Rc::clone(&self.root_node);
|
||||
for part in path.split('/') {
|
||||
if part.is_empty() {
|
||||
@@ -435,9 +473,9 @@ impl SchemeSync for NetCfgScheme {
|
||||
let fd = self.next_fd;
|
||||
trace!("open {} {}", fd, path);
|
||||
self.next_fd += 1;
|
||||
self.files.insert(
|
||||
self.handles.insert(
|
||||
fd,
|
||||
NetCfgFile {
|
||||
Handle::File(NetCfgFile {
|
||||
path: path.to_owned(),
|
||||
is_dir: current_node.is_dir(),
|
||||
is_writable: current_node.is_writable(),
|
||||
@@ -452,7 +490,7 @@ impl SchemeSync for NetCfgScheme {
|
||||
read_buf,
|
||||
write_buf: vec![],
|
||||
done: false,
|
||||
},
|
||||
}),
|
||||
);
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: fd,
|
||||
@@ -462,10 +500,17 @@ impl SchemeSync for NetCfgScheme {
|
||||
|
||||
fn on_close(&mut self, fd: usize) {
|
||||
trace!("close {}", fd);
|
||||
if let Some(mut file) = self.files.remove(&fd) {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
if !file.done {
|
||||
let _ = file.commit().map(|_| 0);
|
||||
if let Some(handle) = self.handles.remove(&fd) {
|
||||
match handle {
|
||||
Handle::SchemeRoot => {
|
||||
// SchemeRoot closed, nothing specific to clean up
|
||||
}
|
||||
Handle::File(mut file) => {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
if !file.done {
|
||||
let _ = file.commit().map(|_| 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -478,11 +523,16 @@ impl SchemeSync for NetCfgScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
if file.done {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
@@ -514,11 +564,16 @@ impl SchemeSync for NetCfgScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
let mut i = 0;
|
||||
while i < buf.len() && file.pos < file.read_buf.len() {
|
||||
buf[i] = file.read_buf[file.pos];
|
||||
@@ -529,21 +584,26 @@ impl SchemeSync for NetCfgScheme {
|
||||
}
|
||||
|
||||
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
match handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::File(file) => {
|
||||
stat.st_mode = if file.is_dir { MODE_DIR } else { MODE_FILE };
|
||||
if file.is_writable {
|
||||
stat.st_mode |= 0o222;
|
||||
}
|
||||
if file.is_readable {
|
||||
stat.st_mode |= 0o444;
|
||||
}
|
||||
stat.st_uid = 0;
|
||||
stat.st_gid = 0;
|
||||
stat.st_size = file.read_buf.len() as u64;
|
||||
}
|
||||
}
|
||||
if file.is_readable {
|
||||
stat.st_mode |= 0o444;
|
||||
}
|
||||
stat.st_uid = 0;
|
||||
stat.st_gid = 0;
|
||||
stat.st_size = file.read_buf.len() as u64;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -554,24 +614,35 @@ impl SchemeSync for NetCfgScheme {
|
||||
events: SyscallEventFlags,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<SyscallEventFlags> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
if events.contains(syscall::EVENT_READ) {
|
||||
self.notifier.borrow_mut().subscribe(&file.path, fd);
|
||||
} else {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
|
||||
match handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::File(file) => {
|
||||
if events.contains(syscall::EVENT_READ) {
|
||||
self.notifier.borrow_mut().subscribe(&file.path, fd);
|
||||
} else {
|
||||
self.notifier.borrow_mut().unsubscribe(&file.path, fd);
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(SyscallEventFlags::empty())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match handle {
|
||||
Handle::File(file) => file,
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
if !file.done {
|
||||
let res = file.commit();
|
||||
file.done = true;
|
||||
|
||||
+181
-129
@@ -12,7 +12,7 @@ use std::str;
|
||||
use libredox::flag::CLOCK_MONOTONIC;
|
||||
use redox_rt::protocol::SocketCall;
|
||||
use redox_scheme::{
|
||||
scheme::{Op, SchemeSync},
|
||||
scheme::{register_scheme_inner, Op, SchemeSync},
|
||||
CallerCtx, OpenResult, Socket,
|
||||
};
|
||||
use syscall::data::TimeSpec;
|
||||
@@ -239,13 +239,21 @@ where
|
||||
fn handle_shutdown(&mut self, file: &mut SchemeFile<Self>, how: usize) -> SyscallResult<usize>;
|
||||
}
|
||||
|
||||
pub enum Handle<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket,
|
||||
{
|
||||
SchemeRoot,
|
||||
Null(NullFile),
|
||||
File(SchemeFile<SocketT>),
|
||||
}
|
||||
|
||||
pub struct SocketScheme<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
next_fd: usize,
|
||||
nulls: BTreeMap<usize, NullFile>,
|
||||
pub files: BTreeMap<usize, SchemeFile<SocketT>>,
|
||||
pub handles: BTreeMap<usize, Handle<SocketT>>,
|
||||
ref_counts: BTreeMap<SocketHandle, usize>,
|
||||
context: Context,
|
||||
pub socket_set: Rc<RefCell<SocketSet>>,
|
||||
@@ -259,33 +267,36 @@ where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
pub fn new(
|
||||
name: &str,
|
||||
iface: Interface,
|
||||
route_table: Rc<RefCell<RouteTable>>,
|
||||
socket_set: Rc<RefCell<SocketSet>>,
|
||||
scheme_file: Socket,
|
||||
) -> SocketScheme<SocketT> {
|
||||
SocketScheme {
|
||||
) -> SyscallResult<SocketScheme<SocketT>> {
|
||||
let mut scheme = SocketScheme {
|
||||
next_fd: 1,
|
||||
nulls: BTreeMap::new(),
|
||||
files: BTreeMap::new(),
|
||||
handles: BTreeMap::new(),
|
||||
ref_counts: BTreeMap::new(),
|
||||
socket_set,
|
||||
scheme_data: SocketT::new_scheme_data(),
|
||||
scheme_file,
|
||||
_phantom_socket: PhantomData,
|
||||
context: Context { iface, route_table },
|
||||
}
|
||||
};
|
||||
let cap_id = scheme.scheme_root()?;
|
||||
register_scheme_inner(&scheme.scheme_file, name, cap_id)?;
|
||||
Ok(scheme)
|
||||
}
|
||||
|
||||
pub fn handle_block(&mut self, op: &Op) -> SyscallResult<Option<TimeSpec>> {
|
||||
let fd = op.file_id().expect("op is not fd based request");
|
||||
let (read_timeout, write_timeout) = {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if let SchemeFile::Socket(ref scheme_file) = *file {
|
||||
if let Handle::File(SchemeFile::Socket(ref scheme_file)) = *handle {
|
||||
Ok((scheme_file.read_timeout, scheme_file.write_timeout))
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
@@ -319,14 +330,13 @@ where
|
||||
buf: &mut [u8],
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match setting {
|
||||
@@ -369,14 +379,12 @@ where
|
||||
buf: &[u8],
|
||||
) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
let file = match *file {
|
||||
SchemeFile::Socket(ref mut file) => file,
|
||||
_ => {
|
||||
return Err(SyscallError::new(syscall::EBADF));
|
||||
}
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => file,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
match setting {
|
||||
Setting::ReadTimeout | Setting::WriteTimeout => {
|
||||
@@ -445,9 +453,14 @@ where
|
||||
// SocketCall::GetToken => self.handle_get_token(id, payload),
|
||||
SocketCall::GetPeerName => {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
@@ -456,28 +469,31 @@ where
|
||||
SocketCall::Shutdown => {
|
||||
let how = metadata[1] as usize;
|
||||
|
||||
if let Some(null_file) = self.nulls.get_mut(&fd) {
|
||||
match how {
|
||||
0 => null_file.read_enabled = false,
|
||||
1 => null_file.write_enabled = false,
|
||||
2 => {
|
||||
null_file.read_enabled = false;
|
||||
null_file.write_enabled = false;
|
||||
}
|
||||
_ => return Err(SyscallError::new(EINVAL)),
|
||||
}
|
||||
return Ok(0);
|
||||
}
|
||||
|
||||
let file = self
|
||||
.files
|
||||
match self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?
|
||||
{
|
||||
Handle::File(file) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle());
|
||||
|
||||
SocketT::handle_shutdown(socket, file, how)
|
||||
SocketT::handle_shutdown(socket, file, how)
|
||||
}
|
||||
Handle::Null(null_file) => {
|
||||
match how {
|
||||
0 => null_file.read_enabled = false,
|
||||
1 => null_file.write_enabled = false,
|
||||
2 => {
|
||||
null_file.read_enabled = false;
|
||||
null_file.write_enabled = false;
|
||||
}
|
||||
_ => return Err(SyscallError::new(EINVAL)),
|
||||
}
|
||||
Ok(0)
|
||||
}
|
||||
Handle::SchemeRoot => Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
}
|
||||
_ => Err(SyscallError::new(EOPNOTSUPP)),
|
||||
}
|
||||
@@ -504,7 +520,7 @@ where
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
|
||||
self.nulls.insert(id, null);
|
||||
self.handles.insert(id, Handle::Null(null));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
@@ -536,7 +552,7 @@ where
|
||||
self.next_fd += 1;
|
||||
|
||||
self.ref_counts.insert(socket_handle, 1);
|
||||
self.files.insert(id, file);
|
||||
self.handles.insert(id, Handle::File(file));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
@@ -550,8 +566,30 @@ impl<SocketT> SchemeSync for SocketScheme<SocketT>
|
||||
where
|
||||
SocketT: SchemeSocket + AnySocket<'static>,
|
||||
{
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
self.open_inner(path, flags, ctx.uid, ctx.gid, true, true)
|
||||
fn scheme_root(&mut self) -> SyscallResult<usize> {
|
||||
let id = self.next_fd;
|
||||
self.next_fd += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
fd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> SyscallResult<OpenResult> {
|
||||
let handle = self
|
||||
.handles
|
||||
.get(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match handle {
|
||||
Handle::SchemeRoot => self.open_inner(path, flags, ctx.uid, ctx.gid, true, true),
|
||||
_ => Err(SyscallError::new(syscall::EACCES)),
|
||||
}
|
||||
}
|
||||
|
||||
fn call(
|
||||
@@ -565,22 +603,11 @@ where
|
||||
}
|
||||
|
||||
fn on_close(&mut self, fd: usize) {
|
||||
if let Some(_null) = self.nulls.remove(&fd) {
|
||||
let handle = if let Some(handle) = self.handles.remove(&fd) {
|
||||
handle
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
|
||||
let socket_handle = {
|
||||
let Some(file) = self.files.get(&fd) else {
|
||||
return;
|
||||
};
|
||||
file.socket_handle()
|
||||
};
|
||||
let scheme_file = self.files.remove(&fd);
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
if let Some(scheme_file) = scheme_file {
|
||||
let socket = socket_set.get::<SocketT>(socket_handle);
|
||||
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
|
||||
}
|
||||
|
||||
// incorrect, and kernel can't send close until all references are gone
|
||||
/*self.wait_queue.retain(
|
||||
@@ -590,30 +617,42 @@ where
|
||||
}| a != fd,
|
||||
);*/
|
||||
|
||||
let remove = match self.ref_counts.entry(socket_handle) {
|
||||
Entry::Vacant(_) => {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
true
|
||||
}
|
||||
Entry::Occupied(mut e) => {
|
||||
if *e.get() == 0 {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
*e.get_mut() -= 1;
|
||||
if *e.get() == 0 {
|
||||
e.remove();
|
||||
match handle {
|
||||
Handle::SchemeRoot => return,
|
||||
Handle::Null(_) => return,
|
||||
Handle::File(scheme_file) => {
|
||||
let socket_handle = scheme_file.socket_handle();
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
|
||||
let socket = socket_set.get::<SocketT>(socket_handle);
|
||||
let _ = socket.close_file(&scheme_file, &mut self.scheme_data);
|
||||
|
||||
let remove = match self.ref_counts.entry(socket_handle) {
|
||||
Entry::Vacant(_) => {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
Entry::Occupied(mut e) => {
|
||||
if *e.get() == 0 {
|
||||
warn!("Closing a socket_handle with no ref");
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
*e.get_mut() -= 1;
|
||||
if *e.get() == 0 {
|
||||
e.remove();
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if remove {
|
||||
socket_set.remove(socket_handle);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
if remove {
|
||||
socket_set.remove(socket_handle);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -627,15 +666,15 @@ where
|
||||
) -> SyscallResult<usize> {
|
||||
let (fd, setting) = {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match *file {
|
||||
SchemeFile::Setting(ref setting_handle) => {
|
||||
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
|
||||
(setting_handle.fd, setting_handle.setting)
|
||||
}
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
let ret = SocketT::write_buf(socket, file, buf);
|
||||
@@ -646,6 +685,7 @@ where
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
};
|
||||
self.update_setting(fd, setting, buf)
|
||||
@@ -661,14 +701,14 @@ where
|
||||
) -> SyscallResult<usize> {
|
||||
let (fd, setting) = {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
match *file {
|
||||
SchemeFile::Setting(ref setting_handle) => {
|
||||
Handle::File(SchemeFile::Setting(ref setting_handle)) => {
|
||||
(setting_handle.fd, setting_handle.setting)
|
||||
}
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
Handle::File(SchemeFile::Socket(ref mut file)) => {
|
||||
let mut socket_set = self.socket_set.borrow_mut();
|
||||
let socket = socket_set.get_mut::<SocketT>(file.socket_handle);
|
||||
|
||||
@@ -681,6 +721,7 @@ where
|
||||
|
||||
return ret;
|
||||
}
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
};
|
||||
self.get_setting(fd, setting, buf)
|
||||
@@ -689,27 +730,28 @@ where
|
||||
fn dup(&mut self, fd: usize, buf: &[u8], _ctx: &CallerCtx) -> SyscallResult<OpenResult> {
|
||||
let path = str::from_utf8(buf).or_else(|_| Err(SyscallError::new(syscall::EINVAL)))?;
|
||||
|
||||
if let Some((flags, uid, gid, read_enabled, write_enabled)) =
|
||||
self.nulls.get(&fd).map(|null| {
|
||||
(
|
||||
null.flags,
|
||||
null.uid,
|
||||
null.gid,
|
||||
null.read_enabled,
|
||||
null.write_enabled,
|
||||
)
|
||||
})
|
||||
{
|
||||
// dup from empty path to a new path
|
||||
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
|
||||
}
|
||||
|
||||
let new_file = {
|
||||
let file = self
|
||||
.files
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *handle {
|
||||
Handle::SchemeRoot => return Err(SyscallError::new(syscall::EBADF)),
|
||||
Handle::Null(ref null) => {
|
||||
let (flags, uid, gid, read_enabled, write_enabled) = (
|
||||
null.flags,
|
||||
null.uid,
|
||||
null.gid,
|
||||
null.read_enabled,
|
||||
null.write_enabled,
|
||||
);
|
||||
// dup from empty path to a new path
|
||||
return self.open_inner(path, flags, uid, gid, read_enabled, write_enabled);
|
||||
}
|
||||
Handle::File(ref mut file) => file,
|
||||
};
|
||||
|
||||
let socket_handle = file.socket_handle();
|
||||
|
||||
let (new_handle, update_with) = match path {
|
||||
@@ -757,7 +799,10 @@ where
|
||||
.and_modify(|e| *e = e.saturating_sub(1))
|
||||
.or_insert(0);
|
||||
|
||||
*self.ref_counts.entry(socket_handle).or_insert(0) += 1;
|
||||
*self
|
||||
.ref_counts
|
||||
.entry(new_handle.socket_handle())
|
||||
.or_insert(0) += 1;
|
||||
|
||||
file.socket_handle = socket_handle;
|
||||
file.data = data;
|
||||
@@ -771,7 +816,7 @@ where
|
||||
};
|
||||
|
||||
let id = self.next_fd;
|
||||
self.files.insert(id, new_file);
|
||||
self.handles.insert(id, Handle::File(new_file));
|
||||
self.next_fd += 1;
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
@@ -787,9 +832,15 @@ where
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<SyscallEventFlags> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
match *file {
|
||||
SchemeFile::Setting(_) => return Err(SyscallError::new(syscall::EBADF)),
|
||||
SchemeFile::Socket(ref mut file) => {
|
||||
@@ -806,7 +857,7 @@ where
|
||||
fn fsync(&mut self, fd: usize, _ctx: &CallerCtx) -> SyscallResult<()> {
|
||||
{
|
||||
let _file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
}
|
||||
@@ -817,10 +868,15 @@ where
|
||||
|
||||
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> SyscallResult<usize> {
|
||||
let file = self
|
||||
.files
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
let file = match *file {
|
||||
Handle::File(ref mut f) => f,
|
||||
_ => return Err(SyscallError::new(syscall::EBADF)),
|
||||
};
|
||||
|
||||
let socket_set = self.socket_set.borrow();
|
||||
let socket = socket_set.get::<SocketT>(file.socket_handle());
|
||||
|
||||
@@ -834,33 +890,29 @@ where
|
||||
arg: usize,
|
||||
_ctx: &CallerCtx,
|
||||
) -> SyscallResult<usize> {
|
||||
if let Some(ref mut null) = self.nulls.get_mut(&fd) {
|
||||
match cmd {
|
||||
let handle = self
|
||||
.handles
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
match *handle {
|
||||
Handle::File(SchemeFile::Socket(ref mut socket_file)) => match cmd {
|
||||
syscall::F_GETFL => Ok(socket_file.flags),
|
||||
syscall::F_SETFL => {
|
||||
socket_file.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
},
|
||||
Handle::Null(ref mut null) => match cmd {
|
||||
syscall::F_GETFL => Ok(null.flags),
|
||||
syscall::F_SETFL => {
|
||||
null.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
} else {
|
||||
let file = self
|
||||
.files
|
||||
.get_mut(&fd)
|
||||
.ok_or_else(|| SyscallError::new(syscall::EBADF))?;
|
||||
|
||||
if let SchemeFile::Socket(ref mut socket_file) = *file {
|
||||
match cmd {
|
||||
syscall::F_GETFL => Ok(socket_file.flags),
|
||||
syscall::F_SETFL => {
|
||||
socket_file.flags = arg & !syscall::O_ACCMODE;
|
||||
Ok(0)
|
||||
}
|
||||
_ => Err(SyscallError::new(syscall::EINVAL)),
|
||||
}
|
||||
} else {
|
||||
Err(SyscallError::new(syscall::EBADF))
|
||||
}
|
||||
},
|
||||
_ => Err(SyscallError::new(syscall::EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::{Rc, Weak};
|
||||
|
||||
use syscall::error::{Error, Result, EAGAIN, EINVAL};
|
||||
use syscall::error::{Error, Result, EAGAIN, EINVAL, EWOULDBLOCK};
|
||||
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
|
||||
use syscall::EWOULDBLOCK;
|
||||
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
|
||||
+22
-15
@@ -4,7 +4,7 @@ use event::{user_data, EventFlags, EventQueue};
|
||||
use libredox::{flag, Fd};
|
||||
|
||||
use redox_scheme::wrappers::ReadinessBased;
|
||||
use redox_scheme::{Response, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, Response, SignalBehavior, Socket};
|
||||
use syscall::data::TimeSpec;
|
||||
|
||||
mod controlterm;
|
||||
@@ -16,7 +16,7 @@ mod subterm;
|
||||
mod termios;
|
||||
mod winsize;
|
||||
|
||||
use scheme::PtyScheme;
|
||||
use scheme::{Handle, PtyScheme};
|
||||
|
||||
fn main() {
|
||||
daemon::Daemon::new(daemon);
|
||||
@@ -36,9 +36,14 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
let mut time_file =
|
||||
Fd::open(&time_path, flag::O_NONBLOCK, 0).expect("pty: failed to open time:");
|
||||
|
||||
let socket = redox_scheme::Socket::nonblock("pty").expect("pty: failed to create pty scheme");
|
||||
let socket = redox_scheme::Socket::nonblock().expect("pty: failed to create pty scheme");
|
||||
let mut handler = ReadinessBased::new(&socket, 16);
|
||||
|
||||
let scheme = RefCell::new(PtyScheme::new());
|
||||
register_sync_scheme(&socket, "pty", &mut *scheme.borrow_mut())
|
||||
.expect("ptyd: failed to register scheme to namespace");
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("ptyd: failed to enter null namespace");
|
||||
|
||||
event_queue
|
||||
@@ -48,12 +53,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
.subscribe(time_file.raw(), EventSource::Time, EventFlags::READ)
|
||||
.expect("pty: failed to watch events on time:");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
//TODO: do not set timeout if not necessary
|
||||
timeout(&mut time_file).expect("pty: failed to set timeout");
|
||||
|
||||
let scheme = RefCell::new(PtyScheme::new());
|
||||
let mut timeout_count = 0u64;
|
||||
|
||||
scan_requests(&mut handler, &scheme).expect("pty: could not scan requests");
|
||||
@@ -74,7 +76,9 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
timeout_count = timeout_count.wrapping_add(1);
|
||||
|
||||
for (_id, handle) in scheme.borrow_mut().handles.iter_mut() {
|
||||
handle.timeout(timeout_count);
|
||||
if let Handle::Resource(res) = handle {
|
||||
res.timeout(timeout_count);
|
||||
}
|
||||
}
|
||||
|
||||
handler
|
||||
@@ -127,14 +131,16 @@ fn scan_requests(
|
||||
|
||||
fn issue_events(socket: &Socket, scheme: &mut PtyScheme) {
|
||||
for (id, handle) in scheme.handles.iter_mut() {
|
||||
let events = handle.events();
|
||||
if events != syscall::EventFlags::empty() {
|
||||
socket
|
||||
.write_response(
|
||||
Response::post_fevent(*id, events.bits()),
|
||||
SignalBehavior::Restart,
|
||||
)
|
||||
.expect("pty: failed to send scheme event");
|
||||
if let Handle::Resource(ref mut res) = handle {
|
||||
let events = res.events();
|
||||
if events != syscall::EventFlags::empty() {
|
||||
socket
|
||||
.write_response(
|
||||
Response::post_fevent(*id, events.bits()),
|
||||
SignalBehavior::Restart,
|
||||
)
|
||||
.expect("pty: failed to send scheme event");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -143,6 +149,7 @@ fn timeout(time_file: &mut Fd) -> libredox::error::Result<()> {
|
||||
let mut time = TimeSpec::default();
|
||||
time_file.read(&mut time)?;
|
||||
|
||||
// Set timeout for 100ms
|
||||
time.tv_nsec += 100_000_000;
|
||||
while time.tv_nsec >= 1_000_000_000 {
|
||||
time.tv_sec += 1;
|
||||
|
||||
+83
-40
@@ -6,7 +6,7 @@ use std::str;
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use syscall::data::Stat;
|
||||
use syscall::error::{Error, Result, EBADF, EINVAL, ENOENT};
|
||||
use syscall::error::{Error, Result, EACCES, EBADF, EINVAL, ENOENT};
|
||||
use syscall::flag::{EventFlags, MODE_CHR};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
|
||||
@@ -18,9 +18,14 @@ use crate::subterm::PtySubTerm;
|
||||
use crate::termios::PtyTermios;
|
||||
use crate::winsize::PtyWinsize;
|
||||
|
||||
pub enum Handle {
|
||||
Resource(Box<dyn Resource>),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
pub struct PtyScheme {
|
||||
next_id: usize,
|
||||
pub handles: BTreeMap<usize, Box<dyn Resource>>,
|
||||
pub handles: BTreeMap<usize, Handle>,
|
||||
}
|
||||
|
||||
impl PtyScheme {
|
||||
@@ -30,24 +35,49 @@ impl PtyScheme {
|
||||
handles: BTreeMap::new(),
|
||||
}
|
||||
}
|
||||
|
||||
fn get_resource_mut(&mut self, id: usize) -> Result<&mut Box<dyn Resource>> {
|
||||
match self.handles.get_mut(&id).ok_or(Error::new(EBADF))? {
|
||||
Handle::Resource(res) => Ok(res),
|
||||
Handle::SchemeRoot => Err(Error::new(EBADF)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SchemeSync for PtyScheme {
|
||||
fn open(&mut self, path: &str, flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let path = path.trim_matches('/');
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
if path.is_empty() {
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
let pty = Rc::new(RefCell::new(Pty::new(id)));
|
||||
self.handles
|
||||
.insert(id, Box::new(PtyControlTerm::new(pty, flags)));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
self.handles.insert(
|
||||
id,
|
||||
Handle::Resource(Box::new(PtyControlTerm::new(pty, flags))),
|
||||
);
|
||||
} else {
|
||||
let control_term_id = path.parse::<usize>().or(Err(Error::new(EINVAL)))?;
|
||||
let pty = {
|
||||
@@ -55,32 +85,40 @@ impl SchemeSync for PtyScheme {
|
||||
.handles
|
||||
.get(&control_term_id)
|
||||
.ok_or(Error::new(ENOENT))?;
|
||||
handle.pty()
|
||||
|
||||
match handle {
|
||||
Handle::Resource(res) => res.pty(),
|
||||
Handle::SchemeRoot => return Err(Error::new(ENOENT)),
|
||||
}
|
||||
};
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
|
||||
self.handles
|
||||
.insert(id, Box::new(PtySubTerm::new(pty, flags)));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
self.handles.insert(
|
||||
id,
|
||||
Handle::Resource(Box::new(PtySubTerm::new(pty, flags | fcntl_flags as usize))),
|
||||
);
|
||||
}
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
|
||||
fn dup(&mut self, old_id: usize, buf: &[u8], _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
let handle: Box<dyn Resource> = {
|
||||
let old_handle = self.handles.get(&old_id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
let old_resource = match old_handle {
|
||||
Handle::Resource(res) => res,
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
};
|
||||
|
||||
if buf == b"pgrp" {
|
||||
Box::new(PtyPgrp::new(old_handle.pty(), old_handle.flags()))
|
||||
Box::new(PtyPgrp::new(old_resource.pty(), old_resource.flags()))
|
||||
} else if buf == b"termios" {
|
||||
Box::new(PtyTermios::new(old_handle.pty(), old_handle.flags()))
|
||||
Box::new(PtyTermios::new(old_resource.pty(), old_resource.flags()))
|
||||
} else if buf == b"winsize" {
|
||||
Box::new(PtyWinsize::new(old_handle.pty(), old_handle.flags()))
|
||||
Box::new(PtyWinsize::new(old_resource.pty(), old_resource.flags()))
|
||||
} else {
|
||||
return Err(Error::new(EINVAL));
|
||||
}
|
||||
@@ -88,7 +126,7 @@ impl SchemeSync for PtyScheme {
|
||||
|
||||
let id = self.next_id;
|
||||
self.next_id += 1;
|
||||
self.handles.insert(id, handle);
|
||||
self.handles.insert(id, Handle::Resource(handle));
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: id,
|
||||
@@ -104,7 +142,7 @@ impl SchemeSync for PtyScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.read(buf)
|
||||
}
|
||||
|
||||
@@ -116,42 +154,47 @@ impl SchemeSync for PtyScheme {
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.write(buf)
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, id: usize, cmd: usize, arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.fcntl(cmd, arg)
|
||||
}
|
||||
|
||||
fn fevent(&mut self, id: usize, _flags: EventFlags, _ctx: &CallerCtx) -> Result<EventFlags> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.fevent()
|
||||
}
|
||||
|
||||
fn fpath(&mut self, id: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.path(buf)
|
||||
}
|
||||
|
||||
fn fstat(&mut self, id: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
let _handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.handles.get(&id).ok_or(Error::new(EBADF))?;
|
||||
|
||||
*stat = Stat {
|
||||
st_mode: MODE_CHR | 0o666,
|
||||
..Default::default()
|
||||
};
|
||||
match handle {
|
||||
Handle::SchemeRoot => return Err(Error::new(EBADF)),
|
||||
Handle::Resource(_res) => {
|
||||
*stat = Stat {
|
||||
st_mode: MODE_CHR | 0o666,
|
||||
..Default::default()
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fsync(&mut self, id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
let handle = self.handles.get_mut(&id).ok_or(Error::new(EBADF))?;
|
||||
let handle = self.get_resource_mut(id)?;
|
||||
handle.sync()
|
||||
}
|
||||
|
||||
fn on_close(&mut self, id: usize) {
|
||||
self.handles.remove(&id);
|
||||
let _ = self.handles.remove(&id);
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -1,9 +1,8 @@
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Weak;
|
||||
|
||||
use syscall::error::{Error, Result, EAGAIN, EINVAL, EPIPE};
|
||||
use syscall::error::{Error, Result, EAGAIN, EINVAL, EPIPE, EWOULDBLOCK};
|
||||
use syscall::flag::{EventFlags, F_GETFL, F_SETFL, O_ACCMODE, O_NONBLOCK};
|
||||
use syscall::EWOULDBLOCK;
|
||||
|
||||
use crate::pty::Pty;
|
||||
use crate::resource::Resource;
|
||||
|
||||
+5
-5
@@ -14,14 +14,14 @@ fn main() {
|
||||
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
let scheme_name = env::args().nth(1).expect("Usage:\n\tramfs SCHEME_NAME");
|
||||
|
||||
let socket =
|
||||
redox_scheme::Socket::create(&scheme_name).expect("ramfs: failed to create socket");
|
||||
let socket = redox_scheme::Socket::create().expect("ramfs: failed to create socket");
|
||||
|
||||
let mut scheme = Scheme::new(scheme_name).expect("ramfs: failed to initialize scheme");
|
||||
|
||||
libredox::call::setrens(0, 0).expect("ramfs: failed to enter null namespace");
|
||||
let mut scheme = Scheme::new(scheme_name.clone()).expect("ramfs: failed to initialize scheme");
|
||||
|
||||
redox_scheme::scheme::register_sync_scheme(&socket, &scheme_name, &mut scheme)
|
||||
.expect("ramfs: failed to register to namespace");
|
||||
daemon.ready();
|
||||
libredox::call::setrens(0, 0).expect("ramfs: failed to enter null namespace");
|
||||
|
||||
loop {
|
||||
let Some(request) = socket
|
||||
|
||||
+95
-26
@@ -1,3 +1,4 @@
|
||||
use std::collections::HashMap;
|
||||
use std::convert::{TryFrom, TryInto};
|
||||
use std::io::{Cursor, Seek};
|
||||
use std::iter;
|
||||
@@ -22,9 +23,19 @@ use redox_scheme::{CallerCtx, OpenResult};
|
||||
|
||||
use crate::filesystem::{self, File, FileData, Filesystem, Inode};
|
||||
|
||||
enum Handle {
|
||||
Inode(usize),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
// TODO: Move to relibc
|
||||
const AT_REMOVEDIR: usize = 0x200;
|
||||
|
||||
pub struct Scheme {
|
||||
scheme_name: String,
|
||||
filesystem: Filesystem,
|
||||
handles: HashMap<usize, Handle>,
|
||||
next_id: usize,
|
||||
}
|
||||
impl Scheme {
|
||||
/// Create the scheme, with the name being used for `fpath`.
|
||||
@@ -32,10 +43,11 @@ impl Scheme {
|
||||
Ok(Self {
|
||||
scheme_name,
|
||||
filesystem: Filesystem::new()?,
|
||||
handles: HashMap::new(),
|
||||
next_id: 0,
|
||||
})
|
||||
}
|
||||
/// Remove a directory entry, where the entry can be both a file or a directory. Used by both
|
||||
/// `unlink` and `rmdir`.
|
||||
/// Remove a directory entry, where the entry can be both a file or a directory. Used by `unlinkat`.
|
||||
pub fn remove_dentry(&mut self, path: &str, uid: u32, gid: u32, directory: bool) -> Result<()> {
|
||||
let removed_inode = {
|
||||
let (parent_dir_inode, name_to_delete) =
|
||||
@@ -148,7 +160,27 @@ impl Scheme {
|
||||
}
|
||||
|
||||
impl SchemeSync for Scheme {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.handles.insert(id, Handle::SchemeRoot);
|
||||
self.next_id += 1;
|
||||
Ok(id)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
let exists = self.filesystem.resolve(path, 0, 0).is_ok();
|
||||
if flags & O_CREAT != 0 && flags & O_EXCL != 0 && exists {
|
||||
return Err(Error::new(EEXIST));
|
||||
@@ -232,19 +264,26 @@ impl SchemeSync for Scheme {
|
||||
|
||||
new_inode_number
|
||||
} else {
|
||||
self.open_existing(path, flags, ctx.uid, ctx.gid)?.0
|
||||
self.open_existing(path, flags | fcntl_flags as usize, ctx.uid, ctx.gid)?
|
||||
.0
|
||||
};
|
||||
let new_id = self.next_id;
|
||||
self.handles.insert(new_id, Handle::Inode(inode));
|
||||
self.next_id += 1;
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: inode,
|
||||
number: new_id,
|
||||
flags: NewFdFlags::POSITIONED,
|
||||
})
|
||||
}
|
||||
fn unlinkat(&mut self, dirfd: usize, path: &str, flags: usize, ctx: &CallerCtx) -> Result<()> {
|
||||
let _ = self
|
||||
.filesystem
|
||||
.files
|
||||
.get_mut(&dirfd)
|
||||
.ok_or(Error::new(EBADFD))?;
|
||||
{
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
}
|
||||
self.remove_dentry(
|
||||
path,
|
||||
ctx.uid,
|
||||
@@ -254,7 +293,7 @@ impl SchemeSync for Scheme {
|
||||
}
|
||||
fn read(
|
||||
&mut self,
|
||||
inode: usize,
|
||||
fd: usize,
|
||||
buf: &mut [u8],
|
||||
offset: u64,
|
||||
fcntl_flags: u32,
|
||||
@@ -263,7 +302,10 @@ impl SchemeSync for Scheme {
|
||||
let Ok(offset) = usize::try_from(offset) else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -289,13 +331,17 @@ impl SchemeSync for Scheme {
|
||||
}
|
||||
fn getdents<'buf>(
|
||||
&mut self,
|
||||
inode: usize,
|
||||
fd: usize,
|
||||
mut buf: DirentBuf<&'buf mut [u8]>,
|
||||
opaque_offset: u64,
|
||||
) -> Result<DirentBuf<&'buf mut [u8]>> {
|
||||
let Ok(offset) = usize::try_from(opaque_offset) else {
|
||||
return Ok(buf);
|
||||
};
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -318,7 +364,7 @@ impl SchemeSync for Scheme {
|
||||
}
|
||||
fn write(
|
||||
&mut self,
|
||||
inode: usize,
|
||||
fd: usize,
|
||||
buf: &[u8],
|
||||
offset: u64,
|
||||
_fcntl_flags: u32,
|
||||
@@ -327,7 +373,10 @@ impl SchemeSync for Scheme {
|
||||
let Ok(offset) = usize::try_from(offset) else {
|
||||
return Ok(0);
|
||||
};
|
||||
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -353,7 +402,11 @@ impl SchemeSync for Scheme {
|
||||
Err(Error::new(EISDIR))
|
||||
}
|
||||
}
|
||||
fn fchmod(&mut self, inode: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fchmod(&mut self, fd: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -413,12 +466,12 @@ impl SchemeSync for Scheme {
|
||||
// TODO
|
||||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
fn fpath(
|
||||
&mut self,
|
||||
mut current_inode: usize,
|
||||
buf: &mut [u8],
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
fn fpath(&mut self, fd: usize, buf: &mut [u8], _ctx: &CallerCtx) -> Result<usize> {
|
||||
let mut current_inode = match *self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
|
||||
let mut chain = Vec::new();
|
||||
|
||||
let mut current_info = self
|
||||
@@ -462,7 +515,12 @@ impl SchemeSync for Scheme {
|
||||
// TODO
|
||||
Err(Error::new(ENOSYS))
|
||||
}
|
||||
fn fstat(&mut self, inode: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fstat(&mut self, fd: usize, stat: &mut Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
let inode = match *self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
|
||||
let block_size = self.filesystem.block_size();
|
||||
let file = self
|
||||
.filesystem
|
||||
@@ -535,7 +593,11 @@ impl SchemeSync for Scheme {
|
||||
fn fsync(&mut self, _inode: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
fn ftruncate(&mut self, inode: usize, size: u64, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn ftruncate(&mut self, fd: usize, size: u64, _ctx: &CallerCtx) -> Result<()> {
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -560,7 +622,11 @@ impl SchemeSync for Scheme {
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
fn futimens(&mut self, inode: usize, times: &[TimeSpec], _ctx: &CallerCtx) -> Result<()> {
|
||||
fn futimens(&mut self, fd: usize, times: &[TimeSpec], _ctx: &CallerCtx) -> Result<()> {
|
||||
let inode = match self.handles.get(&fd).ok_or(Error::new(EBADFD))? {
|
||||
Handle::Inode(inode) => inode,
|
||||
Handle::SchemeRoot => return Err(Error::new(EISDIR)),
|
||||
};
|
||||
let file = self
|
||||
.filesystem
|
||||
.files
|
||||
@@ -577,7 +643,10 @@ impl SchemeSync for Scheme {
|
||||
}
|
||||
}
|
||||
impl Scheme {
|
||||
pub fn on_close(&mut self, inode: usize) {
|
||||
pub fn on_close(&mut self, fd: usize) {
|
||||
let Some(Handle::Inode(inode)) = self.handles.remove(&fd) else {
|
||||
return;
|
||||
};
|
||||
let Some(inode_info) = self.filesystem.files.get_mut(&inode) else {
|
||||
return;
|
||||
};
|
||||
|
||||
+199
-146
@@ -13,15 +13,14 @@ pub const MODE_READ: u16 = 0o4;
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use raw_cpuid::CpuId;
|
||||
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult, RequestKind, SignalBehavior, Socket};
|
||||
use syscall::data::Stat;
|
||||
use syscall::flag::EventFlags;
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{
|
||||
Error, Result, EBADF, EEXIST, ENOENT, EPERM, MODE_CHR, O_CREAT, O_EXCL, O_RDONLY, O_RDWR,
|
||||
O_WRONLY,
|
||||
use redox_scheme::{
|
||||
scheme::{register_sync_scheme, SchemeSync},
|
||||
CallerCtx, OpenResult, RequestKind, Response, SignalBehavior, Socket,
|
||||
};
|
||||
use syscall::data::Stat;
|
||||
use syscall::flag::{EventFlags, O_CREAT, O_EXCL, O_RDONLY, O_RDWR, O_WRONLY};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{Error, Result, EACCES, EBADF, EEXIST, ENOENT, EOPNOTSUPP, EPERM, MODE_CHR};
|
||||
|
||||
// Create an RNG Seed to create initial seed from the rdrand intel instruction
|
||||
use rand_core::SeedableRng;
|
||||
@@ -100,6 +99,20 @@ impl OpenFileInfo {
|
||||
}
|
||||
}
|
||||
|
||||
enum Handle {
|
||||
File(OpenFileInfo),
|
||||
SchemeRoot,
|
||||
}
|
||||
|
||||
impl Handle {
|
||||
fn as_file(&self) -> Option<&OpenFileInfo> {
|
||||
match self {
|
||||
Self::File(info) => Some(info),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Struct to represent the rand scheme.
|
||||
struct RandScheme {
|
||||
prng: ChaCha20Rng,
|
||||
@@ -107,11 +120,11 @@ struct RandScheme {
|
||||
// https://docs.rs/rand/0.5.0/rand/prng/chacha/struct.ChaChaRng.html
|
||||
// Allows 2^64 streams of random numbers, which we will equate with file numbers
|
||||
prng_stat: Stat,
|
||||
open_descriptors: BTreeMap<usize, OpenFileInfo>, // Cannot use HashMap as the implementation
|
||||
handles: BTreeMap<usize, Handle>,
|
||||
// calls the system RNG (us) for entropy to protect against HashDOS attacks.
|
||||
// Trying to create a HashMap causes a system crash.
|
||||
// <file number, information about the open file>
|
||||
next_fd: Wrapping<usize>,
|
||||
next_id: Wrapping<usize>,
|
||||
}
|
||||
|
||||
impl RandScheme {
|
||||
@@ -125,19 +138,16 @@ impl RandScheme {
|
||||
st_uid: 0,
|
||||
..Default::default()
|
||||
},
|
||||
open_descriptors: BTreeMap::new(),
|
||||
next_fd: Wrapping(0),
|
||||
handles: BTreeMap::new(),
|
||||
next_id: Wrapping(0),
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets the open file info for a file descriptor if it is open - error otherwise.
|
||||
fn get_fd(&self, fd: usize) -> Result<&OpenFileInfo> {
|
||||
// Check we've got a valid file descriptor
|
||||
let file_info = match self.open_descriptors.get(&fd) {
|
||||
Some(m) => m,
|
||||
None => return Err(Error::new(EBADF)),
|
||||
};
|
||||
Ok(file_info)
|
||||
let handle = self.handles.get(&fd).ok_or(Error::new(EBADF))?;
|
||||
handle.as_file().ok_or(Error::new(EBADF))
|
||||
}
|
||||
/// Checks to see if the op (MODE_READ, MODE_WRITE) can be performed on the open file
|
||||
/// descriptor - Will return the open file info if successful, and error if the file
|
||||
@@ -162,120 +172,19 @@ impl RandScheme {
|
||||
entropy_array.copy_from_slice(hash.as_slice());
|
||||
self.prng = ChaCha20Rng::from_seed(entropy_array);
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_scheme_perms() {
|
||||
use syscall::{O_CLOEXEC, O_STAT};
|
||||
|
||||
let mut ctx = CallerCtx {
|
||||
pid: 0,
|
||||
uid: 1,
|
||||
gid: 1,
|
||||
id: unsafe { std::mem::zeroed() }, // Id doesn't have a public constructor
|
||||
};
|
||||
|
||||
let mut scheme = RandScheme::new();
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o200;
|
||||
scheme.prng_stat.st_uid = 1;
|
||||
scheme.prng_stat.st_gid = 1;
|
||||
assert!(scheme.open("/", O_RDWR, &ctx).is_err());
|
||||
assert!(scheme.open("/", O_RDONLY, &ctx).is_err());
|
||||
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o400;
|
||||
let mut fd = match scheme.open("", O_RDONLY, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
|
||||
assert!(scheme.open("", O_WRONLY, &ctx).is_err());
|
||||
assert!(scheme.open("", O_RDWR, &ctx).is_err());
|
||||
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o600;
|
||||
fd = match scheme.open("", O_RDWR, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 2;
|
||||
fd = match scheme.open("", O_STAT, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Try another user in group (no group perms)
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 1;
|
||||
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
|
||||
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Check root can do anything
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o000;
|
||||
ctx.uid = 0;
|
||||
ctx.gid = 0;
|
||||
fd = match scheme.open("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Check the rand:/urandom URL (Equivalent to rand:/)
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 1;
|
||||
fd = match scheme.open("/urandom", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
}
|
||||
|
||||
impl SchemeSync for RandScheme {
|
||||
fn open(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn open_inner(&mut self, path: &str, flags: usize, ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
// We are only allowing
|
||||
// reads/writes from rand:/ and rand:/urandom - the root directory on its own is passed as an empty slice
|
||||
// reads/writes from /scheme/rand/ and /scheme/rand/urandom - the root directory on its own is passed as an empty slice
|
||||
if path != "" && path != "/urandom" {
|
||||
return Err(Error::new(ENOENT));
|
||||
}
|
||||
|
||||
if flags & (O_CREAT | O_EXCL) == O_CREAT | O_EXCL {
|
||||
return Err(Error::new(EEXIST));
|
||||
}
|
||||
|
||||
let fd = self.next_fd;
|
||||
let id = self.next_id;
|
||||
let open_file_info = OpenFileInfo {
|
||||
o_flags: flags,
|
||||
file_stat: self.prng_stat,
|
||||
@@ -293,38 +202,179 @@ impl SchemeSync for RandScheme {
|
||||
{
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
self.open_descriptors.insert(fd.0, open_file_info);
|
||||
// Get the next file descriptor
|
||||
self.next_fd += Wrapping(1);
|
||||
|
||||
self.handles.insert(id.0, Handle::File(open_file_info));
|
||||
|
||||
// If we've looped round there's a small chance that the file descriptor still exists, so loop till we get one that doesn't
|
||||
self.next_id += Wrapping(1);
|
||||
loop {
|
||||
if !self.open_descriptors.contains_key(&self.next_fd.0) {
|
||||
if !self.handles.contains_key(&self.next_id.0) {
|
||||
break;
|
||||
} else {
|
||||
self.next_fd += Wrapping(1);
|
||||
self.next_id += Wrapping(1);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: fd.0,
|
||||
number: id.0,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
}
|
||||
#[test]
|
||||
fn test_scheme_perms() {
|
||||
use syscall::{O_CLOEXEC, O_STAT};
|
||||
|
||||
let mut ctx = CallerCtx {
|
||||
pid: 0,
|
||||
uid: 1,
|
||||
gid: 1,
|
||||
id: unsafe { std::mem::zeroed() }, // Id doesn't have a public constructor
|
||||
};
|
||||
|
||||
let mut scheme = RandScheme::new();
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o200;
|
||||
scheme.prng_stat.st_uid = 1;
|
||||
scheme.prng_stat.st_gid = 1;
|
||||
assert!(scheme.open_inner("/", O_RDWR, &ctx).is_err());
|
||||
assert!(scheme.open_inner("/", O_RDONLY, &ctx).is_err());
|
||||
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o400;
|
||||
let mut fd = match scheme.open("", O_RDONLY, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
|
||||
assert!(scheme.open_inner("", O_WRONLY, &ctx).is_err());
|
||||
assert!(scheme.open_inner("", O_RDWR, &ctx).is_err());
|
||||
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o600;
|
||||
fd = match scheme.open_inner("", O_RDWR, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 2;
|
||||
fd = match scheme.open_inner("", O_STAT, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Try another user in group (no group perms)
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 1;
|
||||
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_err());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_err());
|
||||
scheme.on_close(fd);
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
|
||||
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Check root can do anything
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o000;
|
||||
ctx.uid = 0;
|
||||
ctx.gid = 0;
|
||||
fd = match scheme.open_inner("", O_STAT | O_CLOEXEC, &ctx).unwrap() {
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
|
||||
// Check the rand:/urandom URL (Equivalent to rand:/)
|
||||
scheme.prng_stat.st_mode = MODE_CHR | 0o660;
|
||||
ctx.uid = 2;
|
||||
ctx.gid = 1;
|
||||
fd = match scheme
|
||||
.open_inner("/urandom", O_STAT | O_CLOEXEC, &ctx)
|
||||
.unwrap()
|
||||
{
|
||||
OpenResult::ThisScheme { number, .. } => number,
|
||||
_ => panic!(),
|
||||
};
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_READ).is_ok());
|
||||
assert!(scheme.can_perform_op_on_fd(fd, MODE_WRITE).is_ok());
|
||||
scheme.on_close(fd);
|
||||
}
|
||||
|
||||
impl SchemeSync for RandScheme {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
let id = self.next_id;
|
||||
self.handles.insert(id.0, Handle::SchemeRoot);
|
||||
|
||||
// Get the next file descriptor
|
||||
self.next_id += Wrapping(1);
|
||||
// If we've looped round there's a small chance that the file descriptor still exists, so loop till we get one that doesn't
|
||||
loop {
|
||||
if !self.handles.contains_key(&self.next_id.0) {
|
||||
break;
|
||||
} else {
|
||||
self.next_id += Wrapping(1);
|
||||
}
|
||||
}
|
||||
Ok(id.0)
|
||||
}
|
||||
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if !matches!(
|
||||
self.handles.get(&dirfd).ok_or(Error::new(EBADF))?,
|
||||
Handle::SchemeRoot
|
||||
) {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
|
||||
self.open_inner(path, flags, ctx)
|
||||
}
|
||||
|
||||
/* Resource operations */
|
||||
fn read(
|
||||
&mut self,
|
||||
file: usize,
|
||||
id: usize,
|
||||
buf: &mut [u8],
|
||||
_offset: u64,
|
||||
_flags: u32,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
// Check fd and permissions
|
||||
self.can_perform_op_on_fd(file, MODE_READ)?;
|
||||
self.can_perform_op_on_fd(id, MODE_READ)?;
|
||||
|
||||
// Setting the stream will ensure that if two clients are reading concurrently, they won't get the same numbers
|
||||
self.prng.set_stream(file as u64); // Should probably find a way to re-instate the counter for this stream, but
|
||||
// not doing so won't make the output any less 'random'
|
||||
self.prng.set_stream(id as u64); // Should probably find a way to re-instate the counter for this stream, but
|
||||
// not doing so won't make the output any less 'random'
|
||||
self.prng.fill_bytes(buf);
|
||||
|
||||
Ok(buf.len())
|
||||
@@ -332,14 +382,14 @@ impl SchemeSync for RandScheme {
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
file: usize,
|
||||
id: usize,
|
||||
buf: &[u8],
|
||||
_offset: u64,
|
||||
_flags: u32,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
// Check fd and permissions
|
||||
self.can_perform_op_on_fd(file, MODE_WRITE)?;
|
||||
self.can_perform_op_on_fd(id, MODE_WRITE)?;
|
||||
|
||||
// TODO - when we support other entropy sources, just add this to an entropy pool
|
||||
// TODO - consider having trusted and untrusted entropy writing paths
|
||||
@@ -357,23 +407,23 @@ impl SchemeSync for RandScheme {
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn fchmod(&mut self, file: usize, mode: u16, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fchmod(&mut self, id: usize, mode: u16, ctx: &CallerCtx) -> Result<()> {
|
||||
// Check fd and permissions
|
||||
let file_info = self.get_fd(file)?;
|
||||
let file_info = self.get_fd(id)?;
|
||||
// only root and owner can chmod
|
||||
if file_info.uid != file_info.file_stat.st_uid && file_info.uid != 0 {
|
||||
if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
self.prng_stat.st_mode = MODE_CHR | mode;
|
||||
self.prng_stat.st_mode = MODE_CHR | (mode & MODE_PERM); // Apply mask
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fchown(&mut self, file: usize, uid: u32, gid: u32, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fchown(&mut self, id: usize, uid: u32, gid: u32, ctx: &CallerCtx) -> Result<()> {
|
||||
// Check fd and permissions
|
||||
let file_info = self.get_fd(file)?;
|
||||
// only root and owner can chmod
|
||||
if file_info.uid != file_info.file_stat.st_uid && file_info.uid != 0 {
|
||||
let file_info = self.get_fd(id)?;
|
||||
// only root and owner can fchown
|
||||
if ctx.uid != file_info.file_stat.st_uid && ctx.uid != 0 {
|
||||
return Err(Error::new(EPERM));
|
||||
}
|
||||
|
||||
@@ -411,15 +461,18 @@ impl SchemeSync for RandScheme {
|
||||
|
||||
fn on_close(&mut self, file: usize) {
|
||||
// just remove the file descriptor from the open descriptors
|
||||
self.open_descriptors.remove(&file);
|
||||
let _ = self.handles.remove(&file);
|
||||
}
|
||||
}
|
||||
|
||||
fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
let socket = Socket::create("rand").expect("randd: failed to create rand scheme");
|
||||
let socket = Socket::create().expect("randd: failed to create rand scheme");
|
||||
|
||||
let mut scheme = RandScheme::new();
|
||||
|
||||
register_sync_scheme(&socket, "rand", &mut scheme)
|
||||
.expect("randd: failed to register scheme to namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("randd: failed to enter null namespace");
|
||||
|
||||
+6
-5
@@ -1,5 +1,4 @@
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{RequestKind, SignalBehavior, Socket};
|
||||
use redox_scheme::{scheme::register_sync_scheme, RequestKind, SignalBehavior, Socket};
|
||||
|
||||
use scheme::ZeroScheme;
|
||||
|
||||
@@ -25,13 +24,16 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
Ty::Null => "null",
|
||||
Ty::Zero => "zero",
|
||||
};
|
||||
let socket = Socket::create(name).expect("zerod: failed to create zero scheme");
|
||||
let socket = Socket::create().expect("zerod: failed to create zero scheme");
|
||||
let mut zero_scheme = ZeroScheme(ty);
|
||||
|
||||
libredox::call::setrens(0, 0).expect("zerod: failed to enter null namespace");
|
||||
register_sync_scheme(&socket, name, &mut zero_scheme)
|
||||
.expect("zerod: failed to register scheme to namespace");
|
||||
|
||||
daemon.ready();
|
||||
|
||||
libredox::call::setrens(0, 0).expect("zerod: failed to enter null namespace");
|
||||
|
||||
loop {
|
||||
let Some(request) = socket
|
||||
.next_request(SignalBehavior::Restart)
|
||||
@@ -47,7 +49,6 @@ fn daemon(daemon: daemon::Daemon) -> ! {
|
||||
.write_response(response, SignalBehavior::Restart)
|
||||
.expect("zerod: failed to write responses to zero scheme");
|
||||
}
|
||||
RequestKind::OnClose { id } => zero_scheme.on_close(id),
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
+23
-12
@@ -1,23 +1,36 @@
|
||||
use redox_scheme::scheme::SchemeSync;
|
||||
use redox_scheme::{CallerCtx, OpenResult};
|
||||
use syscall::schemev2::NewFdFlags;
|
||||
use syscall::{error::*, MODE_CHR};
|
||||
use syscall::{error::*, schemev2::NewFdFlags, MODE_CHR};
|
||||
|
||||
use crate::Ty;
|
||||
|
||||
pub struct ZeroScheme(pub Ty);
|
||||
|
||||
const SCHEME_ROOT_ID: usize = 1;
|
||||
|
||||
impl SchemeSync for ZeroScheme {
|
||||
fn open(&mut self, _path: &str, _flags: usize, _ctx: &CallerCtx) -> Result<OpenResult> {
|
||||
fn scheme_root(&mut self) -> Result<usize> {
|
||||
Ok(SCHEME_ROOT_ID)
|
||||
}
|
||||
fn openat(
|
||||
&mut self,
|
||||
dirfd: usize,
|
||||
path: &str,
|
||||
_flags: usize,
|
||||
_fcntl_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<OpenResult> {
|
||||
if dirfd != SCHEME_ROOT_ID {
|
||||
return Err(Error::new(EACCES));
|
||||
}
|
||||
Ok(OpenResult::ThisScheme {
|
||||
number: 0,
|
||||
flags: NewFdFlags::empty(),
|
||||
})
|
||||
}
|
||||
|
||||
fn read(
|
||||
&mut self,
|
||||
_file: usize,
|
||||
_id: usize,
|
||||
buf: &mut [u8],
|
||||
_offset: u64,
|
||||
_flags: u32,
|
||||
@@ -34,13 +47,13 @@ impl SchemeSync for ZeroScheme {
|
||||
|
||||
fn write(
|
||||
&mut self,
|
||||
_file: usize,
|
||||
buffer: &[u8],
|
||||
_id: usize,
|
||||
buf: &[u8],
|
||||
_offset: u64,
|
||||
_flags: u32,
|
||||
_ctx: &CallerCtx,
|
||||
) -> Result<usize> {
|
||||
Ok(buffer.len())
|
||||
Ok(buf.len())
|
||||
}
|
||||
|
||||
fn fcntl(&mut self, _id: usize, _cmd: usize, _arg: usize, _ctx: &CallerCtx) -> Result<usize> {
|
||||
@@ -62,13 +75,11 @@ impl SchemeSync for ZeroScheme {
|
||||
Ok(size)
|
||||
}
|
||||
|
||||
fn fsync(&mut self, _file: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fsync(&mut self, _id: usize, _ctx: &CallerCtx) -> Result<()> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Close the file `number`
|
||||
fn on_close(&mut self, _file: usize) {}
|
||||
fn fstat(&mut self, _: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
fn fstat(&mut self, _id: usize, stat: &mut syscall::Stat, _ctx: &CallerCtx) -> Result<()> {
|
||||
stat.st_mode = 0o666 | MODE_CHR;
|
||||
stat.st_size = 0;
|
||||
stat.st_blocks = 0;
|
||||
|
||||
Reference in New Issue
Block a user