Merge branch 'spawn' into 'master'
Add support for `posix_spawn` and `posix_spawnp` (Redox OS) Closes #192 See merge request redox-os/relibc!1333
This commit is contained in:
Generated
+46
-68
@@ -16,15 +16,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "autocfg"
|
||||
version = "1.5.0"
|
||||
version = "1.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8"
|
||||
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
|
||||
|
||||
[[package]]
|
||||
name = "base64ct"
|
||||
version = "1.8.0"
|
||||
version = "1.8.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba"
|
||||
checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06"
|
||||
|
||||
[[package]]
|
||||
name = "bcrypt-pbkdf"
|
||||
@@ -39,9 +39,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "2.10.0"
|
||||
version = "2.13.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3"
|
||||
checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
|
||||
|
||||
[[package]]
|
||||
name = "blake2"
|
||||
@@ -102,9 +102,9 @@ checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||
|
||||
[[package]]
|
||||
name = "chrono"
|
||||
version = "0.4.42"
|
||||
version = "0.4.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "145052bdd345b87320e369255277e3fb5152762ad123a901ef5c262dd38fe8d2"
|
||||
checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
|
||||
dependencies = [
|
||||
"num-traits",
|
||||
]
|
||||
@@ -181,9 +181,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "drm-sys"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bafb66c8dbc944d69e15cfcc661df7e703beffbaec8bd63151368b06c5f9858c"
|
||||
checksum = "ecc8e1361066d91f5ffccff060a3c3be9c3ecde15be2959c1937595f7a82a9f8"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"linux-raw-sys",
|
||||
@@ -205,9 +205,9 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "goblin"
|
||||
version = "0.10.5"
|
||||
version = "0.10.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "983a6aafb3b12d4c41ea78d39e189af4298ce747353945ff5105b54a056e5cd9"
|
||||
checksum = "17582616a7718cca54cec18e534a76c7c4aec11a8b9a85695712f262fd15a4c8"
|
||||
dependencies = [
|
||||
"log",
|
||||
"plain",
|
||||
@@ -244,15 +244,15 @@ version = "0.1.0"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.177"
|
||||
version = "0.2.186"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2874a2af47a2325c2001a6e6fad9b16a53b802102b528163885171cf92b15976"
|
||||
checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
|
||||
|
||||
[[package]]
|
||||
name = "libm"
|
||||
version = "0.2.15"
|
||||
version = "0.2.16"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de"
|
||||
checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
|
||||
|
||||
[[package]]
|
||||
name = "libredox"
|
||||
@@ -268,9 +268,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "linux-raw-sys"
|
||||
version = "0.6.5"
|
||||
version = "0.9.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a385b1be4e5c3e362ad2ffa73c392e53f031eaa5b7d648e64cd87f27f6063d7"
|
||||
checksum = "cd945864f07fe9f5371a27ad7b52a172b4b499999f1d97574c9fa68373937e12"
|
||||
|
||||
[[package]]
|
||||
name = "lock_api"
|
||||
@@ -283,9 +283,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "log"
|
||||
version = "0.4.29"
|
||||
version = "0.4.32"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897"
|
||||
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
|
||||
|
||||
[[package]]
|
||||
name = "md-5"
|
||||
@@ -299,9 +299,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "memchr"
|
||||
version = "2.7.6"
|
||||
version = "2.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273"
|
||||
checksum = "6b947ae49db0d222b1dbc6b113ce7248a3fc3a6ca21b696717bfc000ba4484d8"
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
@@ -374,29 +374,29 @@ checksum = "66df580334caab2f744839ab1be85493d7ec731a92d6cf928008ab0b212bf3bc"
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "1.0.103"
|
||||
version = "1.0.106"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5ee95bc4ef87b8d5ba32e8b7714ccc834865276eab0aed5c9958d00ec45f49e8"
|
||||
checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934"
|
||||
dependencies = [
|
||||
"unicode-ident",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "1.0.42"
|
||||
version = "1.0.45"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a338cc41d27e6cc6dce6cefc13a0729dfbb81c262b1f519331575dd80ef3067f"
|
||||
checksum = "41f2619966050689382d2b44f664f4bc593e129785a36d6ee376ddf37259b924"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8"
|
||||
checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
|
||||
dependencies = [
|
||||
"rand_core 0.10.0",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -407,19 +407,19 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.10.0"
|
||||
version = "0.10.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba"
|
||||
checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
|
||||
|
||||
[[package]]
|
||||
name = "rand_jitter"
|
||||
version = "0.6.0"
|
||||
version = "0.6.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a02dd27aa28665e46e60168c8f355240c73b8a344d2557a92318849441ffda33"
|
||||
checksum = "3fdcd80e68f0a8f9ca5ec7cfd02fd5fbb8fbe6ef4e9b90ea2f48bb929b74f88e"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"rand_core 0.10.0",
|
||||
"winapi",
|
||||
"rand_core 0.10.1",
|
||||
"windows-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -428,7 +428,7 @@ version = "0.5.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "60aa6af80be32871323012e02e6e65f8a7cc7890931ae421d217ad8fe0df2ccf"
|
||||
dependencies = [
|
||||
"rand_core 0.10.0",
|
||||
"rand_core 0.10.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -472,9 +472,9 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "redox_syscall"
|
||||
version = "0.8.0"
|
||||
version = "0.8.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7c7591fa2c6b601dfcfe5f043f65a1c39fcdf50efefcd7f1572e538c1f4b398d"
|
||||
checksum = "5b44b894f2a6e36457d665d1e08c3866add6ed5e70050c1b4ba8a8ddedb02ce7"
|
||||
dependencies = [
|
||||
"bitflags",
|
||||
]
|
||||
@@ -602,9 +602,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
|
||||
|
||||
[[package]]
|
||||
name = "siphasher"
|
||||
version = "1.0.1"
|
||||
version = "1.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56199f7ddabf13fe5074ce809e7d3f42b42ae711800501b5b16ea82ad029c39d"
|
||||
checksum = "8ee5873ec9cce0195efcb7a4e9507a04cd49aec9c83d0389df45b1ef7ba2e649"
|
||||
|
||||
[[package]]
|
||||
name = "spin"
|
||||
@@ -623,9 +623,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292"
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "2.0.110"
|
||||
version = "2.0.117"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a99801b5bd34ede4cf3fc688c5919368fea4e4814a4664359503e6015b280aea"
|
||||
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
@@ -634,15 +634,15 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "typenum"
|
||||
version = "1.19.0"
|
||||
version = "1.20.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb"
|
||||
checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-ident"
|
||||
version = "1.0.22"
|
||||
version = "1.0.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5"
|
||||
checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-width"
|
||||
@@ -656,28 +656,6 @@ version = "0.9.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu",
|
||||
"winapi-x86_64-pc-windows-gnu",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
||||
|
||||
[[package]]
|
||||
name = "windows-sys"
|
||||
version = "0.59.0"
|
||||
|
||||
+2
-4
@@ -70,7 +70,7 @@ ioslice = { version = "0.6", default-features = false }
|
||||
plain = "0.2"
|
||||
redox-path = "0.3"
|
||||
redox_protocols = { package = "libredox", version = "0.1.17", default-features = false, features = ["protocol"] }
|
||||
redox_syscall = "0.8.0"
|
||||
redox_syscall = "0.8.1"
|
||||
[build-dependencies]
|
||||
cc = "1"
|
||||
|
||||
@@ -122,9 +122,7 @@ sc = "0.2.7"
|
||||
redox_syscall.workspace = true
|
||||
redox-rt = { path = "redox-rt" }
|
||||
redox-path.workspace = true
|
||||
redox_event = { version = "0.4.7", default-features = false, features = [
|
||||
"redox_syscall",
|
||||
] }
|
||||
redox_event = { version = "0.4.7", default-features = false, features = ["redox_syscall"] }
|
||||
ioslice.workspace = true
|
||||
redox-ioctl = { path = "redox-ioctl" }
|
||||
redox_protocols.workspace = true
|
||||
|
||||
@@ -8,6 +8,6 @@ description = "Ioctl definitions and (de)serialization for Redox"
|
||||
|
||||
[dependencies]
|
||||
drm-sys = "0.8.0"
|
||||
redox_syscall = "0.8"
|
||||
redox_syscall = "0.8.1"
|
||||
|
||||
[features]
|
||||
|
||||
+15
-9
@@ -63,6 +63,8 @@ pub struct ExtraInfo<'a> {
|
||||
pub ns_fd: Option<usize>,
|
||||
/// CWD handle
|
||||
pub cwd_fd: Option<usize>,
|
||||
/// If the process for which the image is to be loaded the same as the currently running process
|
||||
pub same_process: bool,
|
||||
}
|
||||
|
||||
pub fn fexec_impl(
|
||||
@@ -74,7 +76,7 @@ pub fn fexec_impl(
|
||||
envs: &[&[u8]],
|
||||
extrainfo: &ExtraInfo,
|
||||
interp_override: Option<InterpOverride>,
|
||||
) -> Result<FexecResult> {
|
||||
) -> Result<Option<FexecResult>> {
|
||||
// Here, we do the minimum part of loading an application, which is what the kernel used to do.
|
||||
// We load the executable into memory (albeit at different offsets in this executable), fix
|
||||
// some misalignments, and then switch address space.
|
||||
@@ -235,7 +237,7 @@ pub fn fexec_impl(
|
||||
}
|
||||
|
||||
if let Some(interpreter_path) = interpreter {
|
||||
return Ok(FexecResult::Interp {
|
||||
return Ok(Some(FexecResult::Interp {
|
||||
path: interpreter_path,
|
||||
interp_override: InterpOverride {
|
||||
at_entry: base_addr + header.e_entry as usize,
|
||||
@@ -246,7 +248,7 @@ pub fn fexec_impl(
|
||||
min_mmap_addr,
|
||||
grants_fd: grants_fd.take(),
|
||||
},
|
||||
});
|
||||
}));
|
||||
}
|
||||
|
||||
mmap_anon_remote(
|
||||
@@ -462,7 +464,7 @@ pub fn fexec_impl(
|
||||
));
|
||||
|
||||
// Close all O_CLOEXEC file descriptors. TODO: close_range?
|
||||
{
|
||||
if extrainfo.same_process {
|
||||
// NOTE: This approach of implementing O_CLOEXEC will not work in multithreaded
|
||||
// scenarios. While execve() is undefined according to POSIX if there exist sibling
|
||||
// threads, it could still be allowed by keeping certain file descriptors and instead
|
||||
@@ -493,9 +495,13 @@ pub fn fexec_impl(
|
||||
}
|
||||
|
||||
// Dropping this FD will cause the address space switch.
|
||||
drop(addrspace_selection_fd);
|
||||
|
||||
unreachable!();
|
||||
if extrainfo.same_process {
|
||||
drop(addrspace_selection_fd);
|
||||
unreachable!();
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
}
|
||||
fn write_usizes<const N: usize>(fd: &FdGuardUpper, usizes: [usize; N]) -> Result<usize> {
|
||||
fd.write(unsafe { plain::as_bytes(&usizes) })
|
||||
@@ -1086,10 +1092,10 @@ pub fn fork_inner(initial_rsp: *mut usize, args: &ForkArgs) -> Result<usize> {
|
||||
}
|
||||
|
||||
pub struct NewChildProc {
|
||||
proc_fd: Option<FdGuardUpper>,
|
||||
pub proc_fd: Option<FdGuardUpper>,
|
||||
|
||||
thr_fd: FdGuardUpper,
|
||||
pid: usize,
|
||||
pub thr_fd: FdGuardUpper,
|
||||
pub pid: usize,
|
||||
}
|
||||
|
||||
pub fn new_child_process(args: &ForkArgs<'_>) -> Result<NewChildProc> {
|
||||
|
||||
+11
-2
@@ -340,7 +340,7 @@ pub struct Resugid<T> {
|
||||
}
|
||||
|
||||
/// Sets [res][ug]id, fields that are None will be unchanged.
|
||||
pub fn posix_setresugid(ids: &Resugid<Option<u32>>) -> Result<()> {
|
||||
pub fn posix_setresugid(ids: &Resugid<Option<u32>>, pid: Option<usize>) -> Result<()> {
|
||||
// TODO: not sure how "tmp" an IPC call is?
|
||||
let _sig_guard = tmp_disable_signals();
|
||||
let mut guard = DYNAMIC_PROC_INFO.lock();
|
||||
@@ -357,7 +357,16 @@ pub fn posix_setresugid(ids: &Resugid<Option<u32>>) -> Result<()> {
|
||||
ids.sgid.unwrap_or(u32::MAX),
|
||||
]);
|
||||
|
||||
this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?;
|
||||
if let Some(pid) = pid {
|
||||
proc_call(
|
||||
pid,
|
||||
&mut buf,
|
||||
CallFlags::empty(),
|
||||
&[ProcCall::SetResugid as u64],
|
||||
)?;
|
||||
} else {
|
||||
this_proc_call(&mut buf, CallFlags::empty(), &[ProcCall::SetResugid as u64])?;
|
||||
}
|
||||
|
||||
if let Some(ruid) = ids.ruid {
|
||||
guard.ruid = ruid;
|
||||
|
||||
+1
-1
@@ -126,7 +126,7 @@ pub mod setjmp;
|
||||
pub mod sgtty;
|
||||
pub mod shadow;
|
||||
pub mod signal;
|
||||
// TODO: spawn.h
|
||||
pub mod spawn;
|
||||
// TODO: stdalign.h (likely C implementation)
|
||||
pub mod stdarg;
|
||||
// stdatomic.h implemented in C
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
# POSIX header spec: https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/spawn.h.html
|
||||
#
|
||||
# Spec quotations relating to includes:
|
||||
# - "The <spawn.h> header shall define the mode_t and pid_t types as described in <sys/types.h>."
|
||||
# - "The <spawn.h> header shall define the sigset_t type as described in <signal.h>."
|
||||
# - "The tag sched_param shall be declared as naming an incomplete structure type, the contents of which are described in the <sched.h> header."
|
||||
# - "Inclusion of the <spawn.h> header may make visible symbols defined in the <sched.h> and <signal.h> headers."
|
||||
#
|
||||
# shed.h brings in pid_t
|
||||
# size_t would have been brought in by signal.h so we can include it here directly
|
||||
sys_includes = ["sched.h", "bits/sigset-t.h", "bits/mode-t.h", "bits/size-t.h"]
|
||||
include_guard = "_RELIBC_SPAWN_H"
|
||||
language = "C"
|
||||
cpp_compat = true
|
||||
|
||||
[enum]
|
||||
prefix_with_name = true
|
||||
|
||||
[export.rename]
|
||||
"sched_param" = "struct sched_param"
|
||||
@@ -0,0 +1,221 @@
|
||||
use alloc::{ffi::CString, vec::Vec};
|
||||
use core::ptr;
|
||||
|
||||
use crate::{
|
||||
header::errno::EBADF,
|
||||
platform::types::{c_char, c_int, c_uchar, mode_t, size_t},
|
||||
};
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Action {
|
||||
Open {
|
||||
fd: c_int,
|
||||
path: CString,
|
||||
flag: c_int,
|
||||
mode: mode_t,
|
||||
},
|
||||
Close(c_int),
|
||||
Chdir(CString),
|
||||
FChdir(c_int),
|
||||
Dup2(c_int, c_int),
|
||||
}
|
||||
|
||||
struct FileActions(Vec<Action>);
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct posix_spawn_file_actions_t {
|
||||
__relibc_internal_size: [c_uchar; 24],
|
||||
__relibc_internal_align: size_t,
|
||||
}
|
||||
|
||||
impl posix_spawn_file_actions_t {
|
||||
pub fn add_action(&mut self, action: Action) {
|
||||
let v = ptr::from_mut(self).cast::<FileActions>();
|
||||
unsafe {
|
||||
(*v).0.push(action);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FileActionsIter {
|
||||
actions: posix_spawn_file_actions_t,
|
||||
curr: usize,
|
||||
}
|
||||
|
||||
impl Iterator for FileActionsIter {
|
||||
type Item = Action;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let actions = unsafe {
|
||||
ptr::from_mut(&mut self.actions)
|
||||
.cast::<FileActions>()
|
||||
.as_ref()
|
||||
.unwrap()
|
||||
};
|
||||
let e = actions.0.get(self.curr)?;
|
||||
self.curr += 1;
|
||||
Some((*e).clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> IntoIterator for &'a posix_spawn_file_actions_t {
|
||||
type Item = Action;
|
||||
|
||||
type IntoIter = FileActionsIter;
|
||||
|
||||
fn into_iter(self) -> Self::IntoIter {
|
||||
FileActionsIter {
|
||||
actions: (*self).clone(),
|
||||
curr: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_init.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn posix_spawn_file_actions_init(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
) -> c_int {
|
||||
if file_actions.is_null() {
|
||||
panic!("file_actions cannot be NULL");
|
||||
}
|
||||
let v = Vec::new();
|
||||
let actions = FileActions(v);
|
||||
unsafe {
|
||||
ptr::write(file_actions.cast::<FileActions>(), actions);
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_destroy.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// If `file_actions` is not `NULL`, then it must be a pointer to a `file_actions` object that was initialised by calling `posix_spawn_file_actions_init`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_destroy(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
) -> c_int {
|
||||
if file_actions.is_null() {
|
||||
panic!("file_actions cannot be NULL");
|
||||
}
|
||||
unsafe {
|
||||
let _ = *(file_actions.cast::<FileActions>());
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addopen.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `path` must be a valid null-terminated C string.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_addopen(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
fd: c_int,
|
||||
path: *const c_char,
|
||||
oflag: c_int,
|
||||
mode: mode_t,
|
||||
) -> c_int {
|
||||
let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") };
|
||||
if fd < 0 {
|
||||
return EBADF;
|
||||
}
|
||||
file_actions.add_action(Action::Open {
|
||||
fd,
|
||||
path: if path.is_null() {
|
||||
CString::new("").unwrap()
|
||||
} else {
|
||||
unsafe { CString::from_raw(path as *mut c_char) }
|
||||
},
|
||||
flag: oflag,
|
||||
mode,
|
||||
});
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addclose.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_addclose(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
fd: c_int,
|
||||
) -> c_int {
|
||||
let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") };
|
||||
if fd < 0 {
|
||||
return EBADF;
|
||||
}
|
||||
file_actions.add_action(Action::Close(fd));
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addchdir.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` must be initialised and `path` must be a valid null-terminated C string.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_addchdir(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
path: *const c_char,
|
||||
) -> c_int {
|
||||
let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") };
|
||||
file_actions.add_action(Action::Chdir(unsafe {
|
||||
if path.is_null() {
|
||||
CString::new("").unwrap()
|
||||
} else {
|
||||
CString::from_raw(path as *mut c_char)
|
||||
}
|
||||
}));
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_addfchdir.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_addfchdir(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
fd: c_int,
|
||||
) -> c_int {
|
||||
let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") };
|
||||
if fd < 0 {
|
||||
return EBADF;
|
||||
}
|
||||
file_actions.add_action(Action::FChdir(fd));
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn_file_actions_adddup2.html>
|
||||
///
|
||||
/// Panics if `file_actions` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn_file_actions_adddup2(
|
||||
file_actions: *mut posix_spawn_file_actions_t,
|
||||
fd: c_int,
|
||||
new: c_int,
|
||||
) -> c_int {
|
||||
let file_actions = unsafe { file_actions.as_mut().expect("file_actions cannot be NULL") };
|
||||
if fd < 0 || new < 0 {
|
||||
return EBADF;
|
||||
}
|
||||
file_actions.add_action(Action::Dup2(fd, new));
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,218 @@
|
||||
//! `spawn.h` implementation
|
||||
//!
|
||||
//! See <https://pubs.opengroup.org/onlinepubs/9799919799/basedefs/spawn.h.html>.
|
||||
|
||||
mod file_actions;
|
||||
mod spawn_attr;
|
||||
|
||||
use core::str::FromStr;
|
||||
|
||||
use alloc::{
|
||||
ffi::CString,
|
||||
string::{String, ToString},
|
||||
};
|
||||
pub use file_actions::{Action, posix_spawn_file_actions_t};
|
||||
pub use spawn_attr::{Flags, posix_spawnattr_t};
|
||||
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
error::{Errno, Result},
|
||||
header::{
|
||||
dirent::{opendir, readdir},
|
||||
errno::{ENOENT, ENOTDIR},
|
||||
limits::PATH_MAX,
|
||||
stdlib::getenv,
|
||||
unistd::{chdir, getcwd},
|
||||
},
|
||||
iter::NulTerminated,
|
||||
platform::{
|
||||
self, ERRNO, Pal,
|
||||
types::{c_char, c_int, pid_t},
|
||||
},
|
||||
};
|
||||
|
||||
unsafe fn spawn(
|
||||
pid: Option<&mut pid_t>,
|
||||
mut program: String,
|
||||
file_actions: Option<&posix_spawn_file_actions_t>,
|
||||
spawn_attr: Option<&posix_spawnattr_t>,
|
||||
argv: NulTerminated<*mut c_char>,
|
||||
envp: Option<NulTerminated<*mut c_char>>,
|
||||
use_path: bool,
|
||||
) -> Result<()> {
|
||||
let mut original_cwd = [0 as c_char; PATH_MAX];
|
||||
assert!(
|
||||
unsafe { !getcwd(original_cwd.as_mut_ptr() as *mut c_char, PATH_MAX).is_null() },
|
||||
"Error getting cwd: {}",
|
||||
ERRNO.get()
|
||||
);
|
||||
|
||||
let mut path_path = None;
|
||||
if use_path {
|
||||
let path = unsafe { getenv(c"PATH".as_ptr()) };
|
||||
let path_env = unsafe { CStr::from_nullable_ptr(path).unwrap().to_str().unwrap() };
|
||||
let path_elements = path_env.split(':');
|
||||
let mut flag = false;
|
||||
|
||||
'a: for path_element in path_elements {
|
||||
let pe = CString::from_str(path_element).unwrap();
|
||||
let dir = if let Some(dir) =
|
||||
unsafe { opendir(pe.as_bytes_with_nul().as_ptr() as *const c_char).as_mut() }
|
||||
{
|
||||
dir
|
||||
} else if ERRNO.get() == 0 || ERRNO.get() == ENOTDIR || ERRNO.get() == ENOENT {
|
||||
continue;
|
||||
} else {
|
||||
return Err(Errno(ERRNO.get()));
|
||||
};
|
||||
|
||||
while let Some(dir_ent) = unsafe { readdir(dir).as_ref() } {
|
||||
let dir_ent_name = unsafe {
|
||||
CStr::from_ptr(dir_ent.d_name.as_ptr() as *const c_char)
|
||||
.to_str()
|
||||
.unwrap()
|
||||
.to_string()
|
||||
};
|
||||
if dir_ent_name == program {
|
||||
flag = true;
|
||||
program = format!("{}/{}", path_element, program);
|
||||
path_path = Some(path_element.to_string());
|
||||
break 'a;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !flag {
|
||||
return Err(Errno(ENOENT));
|
||||
}
|
||||
}
|
||||
|
||||
let program = CString::from_str(program.as_str()).unwrap();
|
||||
|
||||
unsafe {
|
||||
platform::Sys::spawn(
|
||||
CStr::from_bytes_with_nul(program.as_bytes_with_nul()).unwrap(),
|
||||
file_actions,
|
||||
spawn_attr,
|
||||
argv,
|
||||
envp,
|
||||
path_path,
|
||||
)
|
||||
.map(|v| {
|
||||
if let Some(pid) = pid {
|
||||
*pid = v;
|
||||
}
|
||||
})
|
||||
.map_err(|e| {
|
||||
let status = chdir(original_cwd.as_ptr() as *const c_char);
|
||||
if status != 0 {
|
||||
panic!("Error switching back to original cwd: {}", ERRNO.get());
|
||||
}
|
||||
e
|
||||
})?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawn.html>
|
||||
///
|
||||
/// `argv` must **not** be `NULL` and must contain atleast the program name. `path` must also be **not** `NULL`. Failure to ensure any of this will result in a panic.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` and `attrp` must either be `NULL` or be pointers to properly initialised objects. Doing otherwise is undefined behaviour.
|
||||
///
|
||||
/// `path` and the elements in `argv` must be a pointers to valid null-terminated character arrays. Failure to ensure any of this will result in undefined behaviour.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawn(
|
||||
pid: *mut pid_t,
|
||||
path: *const c_char,
|
||||
file_actions: *const posix_spawn_file_actions_t,
|
||||
attrp: *const posix_spawnattr_t,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> c_int {
|
||||
let argv = {
|
||||
if argv.is_null() {
|
||||
panic!("argv cannot be NULL")
|
||||
} else {
|
||||
if unsafe { (*argv).is_null() } {
|
||||
panic!("argv must contain the program name");
|
||||
}
|
||||
unsafe { NulTerminated::new(argv).unwrap() }
|
||||
}
|
||||
};
|
||||
let envp = unsafe { NulTerminated::new(envp) };
|
||||
let program = unsafe {
|
||||
CStr::from_ptr(path)
|
||||
.to_str()
|
||||
.expect("path cannot be NULL")
|
||||
.to_string()
|
||||
};
|
||||
|
||||
if let Err(e) = unsafe {
|
||||
spawn(
|
||||
pid.as_mut(),
|
||||
program,
|
||||
file_actions.as_ref(),
|
||||
attrp.as_ref(),
|
||||
argv,
|
||||
envp,
|
||||
false,
|
||||
)
|
||||
} {
|
||||
return e.0;
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnp.html>
|
||||
///
|
||||
/// `argv` must **not** be `NULL` and must contain atleast the program name. `path` must also be **not** `NULL`. Failure to ensure any of this will result in a panic.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `file_actions` and `attrp` must either be `NULL` or be pointers to properly initialised objects. Doing otherwise is undefined behaviour.
|
||||
///
|
||||
/// `path` and the elements in `argv` must be a pointers to valid null-terminated character arrays. Failure to ensure any of this will result in undefined behaviour.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnp(
|
||||
pid: *mut pid_t,
|
||||
path: *const c_char,
|
||||
file_actions: *const posix_spawn_file_actions_t,
|
||||
attrp: *const posix_spawnattr_t,
|
||||
argv: *const *mut c_char,
|
||||
envp: *const *mut c_char,
|
||||
) -> c_int {
|
||||
let argv = {
|
||||
if argv.is_null() {
|
||||
panic!("argv cannot be NULL")
|
||||
} else {
|
||||
if unsafe { (*argv).is_null() } {
|
||||
panic!("argv must contain the program name");
|
||||
}
|
||||
unsafe { NulTerminated::new(argv).unwrap() }
|
||||
}
|
||||
};
|
||||
let envp = unsafe { NulTerminated::new(envp) };
|
||||
let program = unsafe {
|
||||
CStr::from_ptr(path)
|
||||
.to_str()
|
||||
.expect("path cannot be NULL")
|
||||
.to_string()
|
||||
};
|
||||
|
||||
if let Err(e) = unsafe {
|
||||
spawn(
|
||||
pid.as_mut(),
|
||||
program.clone(),
|
||||
file_actions.as_ref(),
|
||||
attrp.as_ref(),
|
||||
argv,
|
||||
envp,
|
||||
if program.contains('/') { false } else { true },
|
||||
)
|
||||
} {
|
||||
return e.0;
|
||||
}
|
||||
0
|
||||
}
|
||||
@@ -0,0 +1,281 @@
|
||||
use core::{
|
||||
ffi::{c_int, c_short},
|
||||
mem::zeroed,
|
||||
};
|
||||
|
||||
use bitflags;
|
||||
|
||||
use crate::header::{
|
||||
bits_sigset_t::sigset_t,
|
||||
errno::EINVAL,
|
||||
sched::{SCHED_FIFO, SCHED_OTHER, SCHED_RR, sched_param},
|
||||
sys_types_internal::pid_t,
|
||||
};
|
||||
|
||||
bitflags::bitflags! {
|
||||
pub struct Flags: c_short
|
||||
{
|
||||
const POSIX_SPAWN_RESETIDS = 1;
|
||||
const POSIX_SPAWN_SETPGROUP = 2;
|
||||
const POSIX_SPAWN_SETSIGDEF = 3;
|
||||
const POSIX_SPAWN_SETSIGMASK = 4;
|
||||
const POSIX_SPAWN_SETSCHEDPARAM = 5;
|
||||
const POSIX_SPAWN_SETSCHEDULER = 6;
|
||||
}
|
||||
}
|
||||
|
||||
pub const POSIX_SPAWN_RESETIDS: c_short = 1;
|
||||
pub const POSIX_SPAWN_SETPGROUP: c_short = 2;
|
||||
pub const POSIX_SPAWN_SETSIGDEF: c_short = 3;
|
||||
pub const POSIX_SPAWN_SETSIGMASK: c_short = 4;
|
||||
pub const POSIX_SPAWN_SETSCHEDPARAM: c_short = 5;
|
||||
pub const POSIX_SPAWN_SETSCHEDULER: c_short = 6;
|
||||
|
||||
#[repr(C)]
|
||||
pub struct posix_spawnattr_t {
|
||||
pub param: sched_param,
|
||||
pub flags: c_short,
|
||||
pub pgroup: c_int,
|
||||
policy: c_int,
|
||||
pub sigdefault: sigset_t,
|
||||
pub sigmask: sigset_t,
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_init.html>
|
||||
///
|
||||
/// Panics is `attr` is `NULL`.
|
||||
#[unsafe(no_mangle)]
|
||||
pub extern "C" fn posix_spawnattr_init(attr: *mut posix_spawnattr_t) -> c_int {
|
||||
unsafe {
|
||||
let attr = attr.as_mut().expect("posix_spawnattr_t cannot be NULL");
|
||||
*attr = zeroed();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_destroy.html>
|
||||
///
|
||||
/// Panics is `attr` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be a pointer to `posix_spawnattr_t` and must at least be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_destroy(attr: *mut posix_spawnattr_t) -> c_int {
|
||||
unsafe {
|
||||
let attr = attr.as_mut().expect("posix_spawnattr_t cannot be NULL");
|
||||
*attr = zeroed();
|
||||
}
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setschedparam.html>
|
||||
///
|
||||
/// Panics if `attr` or `schedparam` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setschedparam(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
schedparam: *const sched_param,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let schedparam = unsafe { schedparam.as_ref().expect("schedparam cannot be NULL") };
|
||||
(*attr).param = *schedparam;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getschedparam.html>
|
||||
///
|
||||
/// Panics if `attr` or `schedparam` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getschedparam(
|
||||
attr: *const posix_spawnattr_t,
|
||||
schedparam: *mut sched_param,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let schedparam = unsafe { schedparam.as_mut().expect("schedparam cannot be NULL") };
|
||||
*schedparam = (*attr).param;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setschedpolicy.html>
|
||||
///
|
||||
/// Panics if `attr` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setschedpolicy(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
schedpolicy: c_int,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
match schedpolicy {
|
||||
SCHED_FIFO | SCHED_RR | SCHED_OTHER => (*attr).policy = schedpolicy,
|
||||
_ => return EINVAL,
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getschedpolicy.html>
|
||||
///
|
||||
/// Panics if `attr` or `schedpolicy` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getschedpolicy(
|
||||
attr: *const posix_spawnattr_t,
|
||||
schedpolicy: *mut c_int,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let schedpolicy = unsafe { schedpolicy.as_mut().expect("schedpolicy cannot be NULL") };
|
||||
*schedpolicy = (*attr).policy;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setsigdefault.html>
|
||||
///
|
||||
/// Panics if `attr` or `sigdefault` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setsigdefault(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
sigdefault: *const sigset_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let sigdefault = unsafe { sigdefault.as_ref().expect("sigdefault cannot be NULL") };
|
||||
(*attr).sigdefault = *sigdefault;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getsigdefault.html>
|
||||
///
|
||||
/// Panics if `attr` or `sigdefault` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getsigdefault(
|
||||
attr: *const posix_spawnattr_t,
|
||||
sigdefault: *mut sigset_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let sigdefault = unsafe { sigdefault.as_mut().expect("sigdefault cannot be NULL") };
|
||||
*sigdefault = (*attr).sigdefault;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setsigmask.html>
|
||||
///
|
||||
/// Panics if `attr` or `sigmask` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setsigmask(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
sigmask: *const sigset_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let sigmask = unsafe { sigmask.as_ref().expect("sigmask cannot be NULL") };
|
||||
(*attr).sigmask = *sigmask;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getsigmask.html>
|
||||
///
|
||||
/// Panics if `attr` or `sigmask` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getsigmask(
|
||||
attr: *const posix_spawnattr_t,
|
||||
sigmask: *mut sigset_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let sigmask = unsafe { sigmask.as_mut().expect("sigmask cannot be NULL") };
|
||||
*sigmask = (*attr).sigmask;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setflags.html>
|
||||
///
|
||||
/// Panics if `attr` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setflags(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
flags: c_short,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
match Flags::from_bits(flags) {
|
||||
Some(v) => (*attr).flags = v.bits(),
|
||||
None => {
|
||||
return EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getflags.html>
|
||||
///
|
||||
/// Panics if `attr` or `flags` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getflags(
|
||||
attr: *const posix_spawnattr_t,
|
||||
flags: *mut c_short,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let flags = unsafe { flags.as_mut().expect("flags cannot be NULL") };
|
||||
|
||||
*flags = (*attr).flags;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_setpgroup.html>
|
||||
///
|
||||
/// Panics if `attr` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_setpgroup(
|
||||
attr: *mut posix_spawnattr_t,
|
||||
pgroup: pid_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_mut().expect("posix_spawnattr_t cannot be NULL") };
|
||||
(*attr).pgroup = pgroup;
|
||||
0
|
||||
}
|
||||
|
||||
/// See <https://pubs.opengroup.org/onlinepubs/9799919799/functions/posix_spawnattr_getpgroup.html>
|
||||
///
|
||||
/// Panics if `attr` or `pgroup` is `NULL`.
|
||||
///
|
||||
/// # Safety:
|
||||
/// `attr` must be initialised.
|
||||
#[unsafe(no_mangle)]
|
||||
pub unsafe extern "C" fn posix_spawnattr_getpgroup(
|
||||
attr: *const posix_spawnattr_t,
|
||||
pgroup: *mut pid_t,
|
||||
) -> c_int {
|
||||
let attr = unsafe { attr.as_ref().expect("posix_spawnattr_t cannot be NULL") };
|
||||
let pgroup = unsafe { pgroup.as_mut().expect("pgroup cannot be NULL") };
|
||||
*pgroup = (*attr).pgroup;
|
||||
0
|
||||
}
|
||||
@@ -30,6 +30,12 @@ unsafe impl Zero for wchar_t {
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl Zero for *mut c_char {
|
||||
fn is_zero(&self) -> bool {
|
||||
self.is_null()
|
||||
}
|
||||
}
|
||||
|
||||
/// An iterator over a nul-terminated buffer.
|
||||
///
|
||||
/// This is intended to allow safe, ergonomic iteration over C-style byte and
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
use core::arch::asm;
|
||||
|
||||
use alloc::string::String;
|
||||
|
||||
use super::{Pal, types::*};
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
@@ -793,4 +795,15 @@ impl Pal for Sys {
|
||||
// GETPID on Linux is 39, which does not exist on Redox
|
||||
e_raw(unsafe { sc::syscall5(sc::nr::GETPID, !0, !0, !0, !0, !0) }).is_ok()
|
||||
}
|
||||
|
||||
unsafe fn spawn(
|
||||
program: CStr,
|
||||
fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>,
|
||||
fat: Option<&crate::header::spawn::posix_spawnattr_t>,
|
||||
argv: crate::iter::NulTerminated<*mut c_char>,
|
||||
envp: Option<crate::iter::NulTerminated<*mut c_char>>,
|
||||
dir_ent_name: Option<String>,
|
||||
) -> Result<pid_t> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
use core::num::NonZeroU64;
|
||||
|
||||
use alloc::string::String;
|
||||
|
||||
use super::types::*;
|
||||
use crate::{
|
||||
c_str::CStr,
|
||||
@@ -15,6 +17,7 @@ use crate::{
|
||||
sys_utsname::utsname,
|
||||
time::{itimerspec, timespec},
|
||||
},
|
||||
iter::NulTerminated,
|
||||
ld_so::tcb::OsSpecific,
|
||||
out::Out,
|
||||
pthread,
|
||||
@@ -433,6 +436,15 @@ pub trait Pal {
|
||||
/// Platform implementation of [`setsid()`](crate::header::unistd::setsid) from [`unistd.h`](crate::header::unistd).
|
||||
fn setsid() -> Result<c_int>;
|
||||
|
||||
unsafe fn spawn(
|
||||
program: CStr,
|
||||
fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>,
|
||||
fat: Option<&crate::header::spawn::posix_spawnattr_t>,
|
||||
argv: NulTerminated<*mut c_char>,
|
||||
envp: Option<NulTerminated<*mut c_char>>,
|
||||
dir_ent_name: Option<String>,
|
||||
) -> Result<pid_t>;
|
||||
|
||||
/// Platform implementation of [`symlink()`](crate::header::unistd::symlink) from [`unistd.h`](crate::header::unistd).
|
||||
fn symlink(path1: CStr, path2: CStr) -> Result<()> {
|
||||
Self::symlinkat(path1, AT_FDCWD, path2)
|
||||
|
||||
@@ -38,7 +38,8 @@ fn fexec_impl(
|
||||
envs,
|
||||
extrainfo,
|
||||
interp_override,
|
||||
)?;
|
||||
)?
|
||||
.unwrap();
|
||||
|
||||
// According to elf(5), PT_INTERP requires that the interpreter path be
|
||||
// null-terminated. Violating this should therefore give the "format error" ENOEXEC.
|
||||
@@ -238,6 +239,7 @@ pub fn execve(
|
||||
cwd_fd: super::path::current_dir()
|
||||
.ok()
|
||||
.map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()),
|
||||
same_process: true,
|
||||
};
|
||||
|
||||
fexec_impl(
|
||||
|
||||
+283
-23
@@ -1,3 +1,4 @@
|
||||
use alloc::string::String;
|
||||
use core::{
|
||||
convert::TryFrom,
|
||||
mem::{self, size_of},
|
||||
@@ -22,19 +23,20 @@ use self::{
|
||||
};
|
||||
use super::{Pal, Read, types::*};
|
||||
use crate::{
|
||||
alloc::string::ToString,
|
||||
c_str::{CStr, CString},
|
||||
error::{Errno, Result},
|
||||
fs::File,
|
||||
header::{
|
||||
errno::{
|
||||
EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT, ENOMEM,
|
||||
ENOSYS, EOPNOTSUPP, EPERM,
|
||||
EBADF, EBADFD, EEXIST, EFAULT, EFBIG, EINTR, EINVAL, EIO, ENAMETOOLONG, ENOENT,
|
||||
ENOEXEC, ENOMEM, ENOSYS, EOPNOTSUPP, EPERM,
|
||||
},
|
||||
fcntl::{
|
||||
self, AT_EACCESS, AT_EMPTY_PATH, AT_FDCWD, AT_REMOVEDIR, AT_SYMLINK_FOLLOW, F_GETLK,
|
||||
F_OFD_GETLK, F_OFD_SETLK, F_RDLCK, F_SETLK, F_SETLKW, F_UNLCK, F_WRLCK, flock,
|
||||
},
|
||||
limits,
|
||||
limits::{self},
|
||||
pthread::{pthread_cancel, pthread_create},
|
||||
signal::{NSIG, SIGEV_NONE, SIGEV_SIGNAL, SIGEV_THREAD, SIGRTMIN, sigevent},
|
||||
stdio::RENAME_NOREPLACE,
|
||||
@@ -42,9 +44,9 @@ use crate::{
|
||||
sys_file,
|
||||
sys_mman::{MAP_ANONYMOUS, PROT_READ, PROT_WRITE},
|
||||
sys_random,
|
||||
sys_resource::{RLIM_INFINITY, rlimit, rusage},
|
||||
sys_resource::{PRIO_PROCESS, RLIM_INFINITY, rlimit, rusage, setpriority},
|
||||
sys_select::timeval,
|
||||
sys_stat::{S_ISVTX, stat},
|
||||
sys_stat::{S_ISGID, S_ISUID, S_ISVTX, stat},
|
||||
sys_statvfs::statvfs,
|
||||
sys_time::timezone,
|
||||
sys_utsname::{UTSLENGTH, utsname},
|
||||
@@ -54,10 +56,11 @@ use crate::{
|
||||
unistd::{F_OK, R_OK, SEEK_CUR, SEEK_SET, W_OK, X_OK},
|
||||
},
|
||||
io::{self, BufReader, prelude::*},
|
||||
iter::NulTerminated,
|
||||
ld_so::tcb::OsSpecific,
|
||||
out::Out,
|
||||
platform::{
|
||||
free,
|
||||
ERRNO, free,
|
||||
sys::timer::{TIMERS, timer_routine, timer_update_wake_time},
|
||||
},
|
||||
sync::rwlock::RwLock,
|
||||
@@ -67,7 +70,7 @@ pub use redox_rt::proc::FdGuard;
|
||||
|
||||
mod epoll;
|
||||
mod event;
|
||||
mod exec;
|
||||
pub(crate) mod exec;
|
||||
mod extra;
|
||||
mod libcscheme;
|
||||
mod libredox;
|
||||
@@ -1169,29 +1172,286 @@ impl Pal for Sys {
|
||||
}
|
||||
|
||||
fn setresgid(rgid: gid_t, egid: gid_t, sgid: gid_t) -> Result<()> {
|
||||
redox_rt::sys::posix_setresugid(&Resugid {
|
||||
ruid: None,
|
||||
euid: None,
|
||||
suid: None,
|
||||
rgid: cvt_uid(rgid)?,
|
||||
egid: cvt_uid(egid)?,
|
||||
sgid: cvt_uid(sgid)?,
|
||||
})?;
|
||||
redox_rt::sys::posix_setresugid(
|
||||
&Resugid {
|
||||
ruid: None,
|
||||
euid: None,
|
||||
suid: None,
|
||||
rgid: cvt_uid(rgid)?,
|
||||
egid: cvt_uid(egid)?,
|
||||
sgid: cvt_uid(sgid)?,
|
||||
},
|
||||
None,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setresuid(ruid: uid_t, euid: uid_t, suid: uid_t) -> Result<()> {
|
||||
redox_rt::sys::posix_setresugid(&Resugid {
|
||||
ruid: cvt_uid(ruid)?,
|
||||
euid: cvt_uid(euid)?,
|
||||
suid: cvt_uid(suid)?,
|
||||
rgid: None,
|
||||
egid: None,
|
||||
sgid: None,
|
||||
})?;
|
||||
redox_rt::sys::posix_setresugid(
|
||||
&Resugid {
|
||||
ruid: cvt_uid(ruid)?,
|
||||
euid: cvt_uid(euid)?,
|
||||
suid: cvt_uid(suid)?,
|
||||
rgid: None,
|
||||
egid: None,
|
||||
sgid: None,
|
||||
},
|
||||
None,
|
||||
)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
unsafe fn spawn(
|
||||
program: CStr,
|
||||
fac: Option<&crate::header::spawn::posix_spawn_file_actions_t>,
|
||||
fat: Option<&crate::header::spawn::posix_spawnattr_t>,
|
||||
argv: NulTerminated<*mut c_char>,
|
||||
envp: Option<NulTerminated<*mut c_char>>,
|
||||
dir_ent_name: Option<String>,
|
||||
) -> Result<pid_t> {
|
||||
use crate::header::spawn::Flags;
|
||||
|
||||
let child = redox_rt::proc::new_child_process(&redox_rt::proc::ForkArgs::Managed)?;
|
||||
let executable = FdGuard::new(File::open(program, fcntl::O_RDONLY)?.fd as usize)
|
||||
.to_upper()
|
||||
.unwrap();
|
||||
let mut executable_stat = syscall::Stat::default();
|
||||
executable.fstat(&mut executable_stat)?;
|
||||
let original_cwd = path::clone_cwd().unwrap().to_string();
|
||||
let mut cwd = original_cwd.clone();
|
||||
let proc_fd = child.proc_fd.unwrap();
|
||||
let curr_proc_fd = redox_rt::current_proc_fd();
|
||||
let file_table = RtTcb::current()
|
||||
.thread_fd()
|
||||
.dup(b"filetable")?
|
||||
.dup(b"copy")?;
|
||||
|
||||
{
|
||||
let new_file_table = child.thr_fd.dup(b"current-filetable")?;
|
||||
new_file_table.write(&file_table.as_raw_fd().to_ne_bytes())?;
|
||||
}
|
||||
|
||||
let mut args = Vec::new();
|
||||
let mut envs = Vec::new();
|
||||
|
||||
for arg in argv {
|
||||
args.push(unsafe { CStr::from_ptr(*arg).to_chars() });
|
||||
}
|
||||
|
||||
if let Some(envp) = envp {
|
||||
for env in envp {
|
||||
envs.push(unsafe { CStr::from_ptr(*env).to_chars() });
|
||||
}
|
||||
}
|
||||
|
||||
let program_name: String = if let Some(ent) = dir_ent_name {
|
||||
let mut binary = str::from_utf8(args[0]).unwrap().to_string();
|
||||
binary.insert_str(0, "./");
|
||||
|
||||
redox_path::canonicalize_using_cwd(Some(ent.as_str()), binary.as_str())
|
||||
.ok_or(Errno(ENOENT))?
|
||||
} else {
|
||||
redox_path::canonicalize_using_cwd(
|
||||
Some(original_cwd.as_str()),
|
||||
str::from_utf8(args[0]).unwrap(),
|
||||
)
|
||||
.ok_or(Errno(ENOENT))?
|
||||
};
|
||||
|
||||
args[0] = program_name.as_bytes();
|
||||
|
||||
let new_file_table = child.thr_fd.dup(b"filetable")?;
|
||||
|
||||
if let Some(fac) = fac {
|
||||
for action in fac {
|
||||
match action {
|
||||
crate::header::spawn::Action::Open {
|
||||
fd,
|
||||
path,
|
||||
flag,
|
||||
mode,
|
||||
} => {
|
||||
let src_fd = Sys::open(
|
||||
CStr::from_bytes_with_nul(path.as_bytes_with_nul()).unwrap(),
|
||||
flag,
|
||||
mode,
|
||||
)? as usize;
|
||||
syscall::sendfd(
|
||||
new_file_table.as_raw_fd(),
|
||||
src_fd,
|
||||
0,
|
||||
u64::try_from(fd).map_err(|_| Errno(EBADFD))?,
|
||||
)?;
|
||||
}
|
||||
crate::header::spawn::Action::Close(fd) => {
|
||||
new_file_table.call_wo(
|
||||
&(fd as usize).to_ne_bytes(),
|
||||
syscall::CallFlags::empty(),
|
||||
&[syscall::flag::FileTableVerb::Close as u64],
|
||||
)?;
|
||||
}
|
||||
crate::header::spawn::Action::Chdir(path) => {
|
||||
cwd = path.to_str().unwrap().to_string();
|
||||
|
||||
path::chdir(path.to_str().unwrap())?;
|
||||
}
|
||||
crate::header::spawn::Action::FChdir(fd) => {
|
||||
path::fchdir(fd)?;
|
||||
path::getcwd(Out::from_mut(unsafe { cwd.as_bytes_mut() }))?;
|
||||
}
|
||||
crate::header::spawn::Action::Dup2(old, new) => {
|
||||
new_file_table.call_wo(
|
||||
[(old as usize).to_ne_bytes(), (new as usize).to_ne_bytes()]
|
||||
.into_iter()
|
||||
.flatten()
|
||||
.collect::<Vec<u8>>()
|
||||
.as_slice(),
|
||||
syscall::CallFlags::empty(),
|
||||
&[syscall::flag::FileTableVerb::Dup2 as u64],
|
||||
)?;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
new_file_table.call_wo(
|
||||
&[],
|
||||
syscall::CallFlags::empty(),
|
||||
&[syscall::flag::FileTableVerb::CloseCloExec as u64],
|
||||
)?;
|
||||
|
||||
let extra_info = redox_rt::proc::ExtraInfo {
|
||||
cwd: Some(cwd.as_bytes()),
|
||||
// Signals set to be ignored by the calling process
|
||||
// must also be ignored by the child process
|
||||
sigignmask: redox_rt::signal::get_sigignmask_to_inherit(),
|
||||
sigprocmask: if let Some(fat) = fat
|
||||
&& Flags::from_bits(fat.flags)
|
||||
.unwrap()
|
||||
.contains(Flags::POSIX_SPAWN_SETSIGMASK)
|
||||
{
|
||||
fat.sigmask
|
||||
} else {
|
||||
redox_rt::signal::get_sigmask().unwrap()
|
||||
},
|
||||
umask: redox_rt::sys::get_umask(),
|
||||
thr_fd: child.thr_fd.as_raw_fd(),
|
||||
proc_fd: proc_fd.as_raw_fd(),
|
||||
ns_fd: redox_rt::current_namespace_fd().ok(),
|
||||
cwd_fd: path::current_dir()
|
||||
.ok()
|
||||
.map(|fd| fd.as_ref().unwrap().fd.as_raw_fd()),
|
||||
same_process: false,
|
||||
};
|
||||
|
||||
if let Some(attr) = fat {
|
||||
let flags = Flags::from_bits(attr.flags).ok_or(Errno(EINVAL))?;
|
||||
|
||||
if flags.contains(Flags::POSIX_SPAWN_SETPGROUP) && attr.pgroup != 0 {
|
||||
redox_rt::sys::posix_setpgid(
|
||||
proc_fd.as_raw_fd(),
|
||||
usize::try_from(attr.pgroup).map_err(|_| Errno(EINVAL))?,
|
||||
)?;
|
||||
} else {
|
||||
redox_rt::sys::posix_setpgid(
|
||||
proc_fd.as_raw_fd(),
|
||||
redox_rt::sys::posix_getpgid(proc_fd.as_raw_fd())?,
|
||||
)?;
|
||||
}
|
||||
|
||||
let set_schedparam = || -> Result<()> {
|
||||
if setpriority(
|
||||
PRIO_PROCESS,
|
||||
proc_fd.as_raw_fd() as id_t,
|
||||
attr.param.sched_priority,
|
||||
) as usize
|
||||
!= 0
|
||||
{
|
||||
Err(Errno(ERRNO.get()))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
};
|
||||
let set_scheduler = || -> Result<()> { todo!() };
|
||||
|
||||
// scheduling paramters must be set regardless of whether the flag POSIX_SPAWN_SETSCHEDPARAM is set
|
||||
if flags.contains(Flags::POSIX_SPAWN_SETSCHEDULER) {
|
||||
set_schedparam()?;
|
||||
set_scheduler()?;
|
||||
} else if flags.contains(Flags::POSIX_SPAWN_SETSCHEDPARAM) {
|
||||
set_schedparam()?;
|
||||
}
|
||||
|
||||
let parent_resugid = redox_rt::sys::posix_getresugid();
|
||||
|
||||
redox_rt::sys::posix_setresugid(
|
||||
&Resugid {
|
||||
ruid: None,
|
||||
euid: Some(if executable_stat.st_mode as mode_t & S_ISUID == S_ISUID {
|
||||
executable_stat.st_uid
|
||||
} else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) {
|
||||
parent_resugid.ruid
|
||||
} else {
|
||||
parent_resugid.euid
|
||||
}),
|
||||
suid: None,
|
||||
rgid: None,
|
||||
egid: Some(if executable_stat.st_mode as mode_t & S_ISGID == S_ISGID {
|
||||
executable_stat.st_gid
|
||||
} else if flags.contains(Flags::POSIX_SPAWN_RESETIDS) {
|
||||
parent_resugid.rgid
|
||||
} else {
|
||||
parent_resugid.egid
|
||||
}),
|
||||
sgid: None,
|
||||
},
|
||||
Some(proc_fd.as_raw_fd()),
|
||||
)?;
|
||||
|
||||
// if POSIX_SPAWN_SETSIGDEF flag is set, the signals specified in
|
||||
// sigdefault must have default actions
|
||||
}
|
||||
|
||||
if let Some(redox_rt::proc::FexecResult::Interp {
|
||||
path: interp_path,
|
||||
interp_override,
|
||||
}) = redox_rt::proc::fexec_impl(
|
||||
executable,
|
||||
&child.thr_fd,
|
||||
&proc_fd,
|
||||
program.to_bytes(),
|
||||
args.as_slice(),
|
||||
envs.as_slice(),
|
||||
&extra_info,
|
||||
None,
|
||||
)? {
|
||||
let interp_path =
|
||||
CStr::from_bytes_with_nul(&interp_path).map_err(|_| Errno(ENOEXEC))?;
|
||||
|
||||
let interpreter = File::open(interp_path, fcntl::O_RDONLY | fcntl::O_CLOEXEC)
|
||||
.map_err(|_| Errno(ENOENT))?;
|
||||
|
||||
redox_rt::proc::fexec_impl(
|
||||
FdGuard::new(interpreter.fd as usize).to_upper().unwrap(),
|
||||
&child.thr_fd,
|
||||
&proc_fd,
|
||||
program.to_bytes(),
|
||||
args.as_slice(),
|
||||
envs.as_slice(),
|
||||
&extra_info,
|
||||
Some(interp_override),
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
path::chdir(original_cwd.as_str())?;
|
||||
|
||||
let start_fd = child.thr_fd.dup(b"start")?;
|
||||
start_fd.write(&[0])?;
|
||||
|
||||
Ok(pid_t::try_from(child.pid).unwrap())
|
||||
}
|
||||
|
||||
fn symlinkat(path1: CStr, fd: c_int, path2: CStr) -> Result<()> {
|
||||
let mut file = File::createat(
|
||||
fd,
|
||||
|
||||
@@ -11,7 +11,7 @@ FAILING_TESTS += malloc/usable_size
|
||||
FAILING_TESTS += mkfifo
|
||||
# Waitpid had EINTR
|
||||
FAILING_TESTS += sigchld
|
||||
# not triggering ERANGE
|
||||
# not triggering ERANGE
|
||||
FAILING_TESTS += stdlib/ptsname
|
||||
# Hang
|
||||
FAILING_TESTS += sys_epoll/epollet
|
||||
@@ -286,6 +286,7 @@ VARIED_NAMES=\
|
||||
signals/sigset-4 \
|
||||
signals/sigset-5 \
|
||||
signals/sigset-9 \
|
||||
spawn \
|
||||
stdio/ctermid \
|
||||
stdio/tempnam \
|
||||
stdio/tmpnam \
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
hello.txt
|
||||
HELLO REDOX
|
||||
@@ -0,0 +1,95 @@
|
||||
#include "./test_helpers.h"
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <fcntl.h>
|
||||
#include <limits.h>
|
||||
#include <sched.h>
|
||||
#include <spawn.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
#include <unistd.h>
|
||||
|
||||
static const char buf[] = "#include <unistd.h>\nint main()\n{\nwrite(900, "
|
||||
"\"hello_spawn REDOX\\n\", 18);\n}";
|
||||
|
||||
#define OPTIONALLY_ERROR(function, args, cond) \
|
||||
{ \
|
||||
int x = function args; \
|
||||
if (!(x cond)) { \
|
||||
printf("%s failed with error: %s\n", #function, strerror(x)); \
|
||||
exit(EXIT_FAILURE); \
|
||||
} \
|
||||
}
|
||||
|
||||
extern char **environ;
|
||||
|
||||
int main() {
|
||||
pid_t pid = 0;
|
||||
char cwd[PATH_MAX];
|
||||
int status = 0;
|
||||
char *__cwd = getcwd(cwd, PATH_MAX);
|
||||
ERROR_IF(getcwd, __cwd, == NULL);
|
||||
char target[PATH_MAX];
|
||||
strcpy(target, cwd);
|
||||
strcat(target, "/hello_spawn");
|
||||
|
||||
// TEST: chdir and open
|
||||
char *argv1[] = {"ls", target, NULL};
|
||||
posix_spawn_file_actions_t fa;
|
||||
posix_spawn_file_actions_init(&fa);
|
||||
status = mkdir("./hello_spawn", S_IRUSR | S_IWUSR);
|
||||
ERROR_IF(mkdir, status, != 0);
|
||||
OPTIONALLY_ERROR(posix_spawn_file_actions_addchdir, (&fa, "./hello_spawn"),
|
||||
== 0);
|
||||
OPTIONALLY_ERROR(
|
||||
posix_spawn_file_actions_addopen,
|
||||
(&fa, 2, "./hello_spawn.txt", O_CREAT | O_RDWR, S_IRUSR | S_IWUSR), == 0);
|
||||
OPTIONALLY_ERROR(posix_spawnp, (&pid, "ls", &fa, NULL, argv1, environ), == 0);
|
||||
assert(pid != 0);
|
||||
waitpid(pid, NULL, 0);
|
||||
OPTIONALLY_ERROR(posix_spawn_file_actions_destroy, (&fa), == 0);
|
||||
|
||||
pid = 0;
|
||||
|
||||
// TEST: close
|
||||
argv1[0] = "/usr/bin/ls";
|
||||
OPTIONALLY_ERROR(posix_spawn_file_actions_init, (&fa), == 0);
|
||||
OPTIONALLY_ERROR(posix_spawn_file_actions_addclose, (&fa, 1), == 0);
|
||||
OPTIONALLY_ERROR(posix_spawn,
|
||||
(&pid, "/usr/bin/ls", &fa, NULL, argv1, environ), == 0);
|
||||
assert(pid != 0);
|
||||
waitpid(pid, NULL, 0);
|
||||
OPTIONALLY_ERROR(posix_spawn_file_actions_destroy, (&fa), == 0);
|
||||
status = unlink("./hello_spawn/hello_spawn.txt");
|
||||
ERROR_IF(unlink, status, != 0);
|
||||
status = rmdir("./hello_spawn");
|
||||
ERROR_IF(rmdir, status, != 0);
|
||||
|
||||
// TEST: dup2
|
||||
pid = 0;
|
||||
posix_spawn_file_actions_init(&fa);
|
||||
posix_spawn_file_actions_adddup2(&fa, 1, 900);
|
||||
|
||||
FILE *f = fopen("./dup2_check.c", "w");
|
||||
if (!f) {
|
||||
printf("Failed to create dup2_check.c\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
OPTIONALLY_ERROR(fwrite, (buf, sizeof(char), 74, f), == 74);
|
||||
fclose(f);
|
||||
char *argv2[] = {"gcc", "./dup2_check.c", "-o", "d.out", NULL};
|
||||
OPTIONALLY_ERROR(posix_spawnp, (&pid, "gcc", NULL, NULL, argv2, environ),
|
||||
== 0);
|
||||
waitpid(pid, NULL, 0);
|
||||
assert(pid != 0);
|
||||
pid = 0;
|
||||
char *argv3[] = {"./d.out", NULL};
|
||||
OPTIONALLY_ERROR(posix_spawnp, (&pid, "./d.out", &fa, NULL, argv3, environ),
|
||||
== 0);
|
||||
assert(pid != 0);
|
||||
waitpid(pid, NULL, 0);
|
||||
posix_spawn_file_actions_destroy(&fa);
|
||||
}
|
||||
Reference in New Issue
Block a user