forked from Rust-related/RustPython
Merge pull request #1970 from youknowone/sub-1962
non-subprocess stuff from #1962
This commit is contained in:
@@ -122,7 +122,7 @@ schannel = "0.1"
|
||||
|
||||
[target.'cfg(windows)'.dependencies.winapi]
|
||||
version = "0.3"
|
||||
features = ["winsock2", "handleapi", "ws2def", "std", "winbase", "wincrypt", "fileapi"]
|
||||
features = ["winsock2", "handleapi", "ws2def", "std", "winbase", "wincrypt", "fileapi", "wincon"]
|
||||
|
||||
[target.'cfg(target_arch = "wasm32")'.dependencies]
|
||||
wasm-bindgen = "0.2"
|
||||
|
||||
@@ -274,6 +274,11 @@ impl<T> From<HashMap<String, T>> for KwArgs<T> {
|
||||
KwArgs(map)
|
||||
}
|
||||
}
|
||||
impl<T> Default for KwArgs<T> {
|
||||
fn default() -> Self {
|
||||
KwArgs(HashMap::new())
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> FromArgs for KwArgs<T>
|
||||
where
|
||||
|
||||
@@ -10,7 +10,7 @@ use crate::exceptions::PyBaseExceptionRef;
|
||||
use crate::function::{KwArgs, OptionalArg, PyFuncArgs};
|
||||
use crate::pyobject::{
|
||||
IdProtocol, IntoPyObject, ItemProtocol, PyAttributes, PyClassImpl, PyContext, PyIterable,
|
||||
PyObjectRef, PyRef, PyResult, PyValue,
|
||||
PyObjectRef, PyRef, PyResult, PyValue, TryFromObject,
|
||||
};
|
||||
use crate::vm::{ReprGuard, VirtualMachine};
|
||||
|
||||
@@ -39,6 +39,7 @@ impl PyValue for PyDict {
|
||||
}
|
||||
|
||||
// Python dict methods:
|
||||
#[allow(clippy::len_without_is_empty)]
|
||||
#[pyimpl(flags(BASETYPE))]
|
||||
impl PyDictRef {
|
||||
#[pyslot]
|
||||
@@ -179,7 +180,7 @@ impl PyDictRef {
|
||||
}
|
||||
|
||||
#[pymethod(magic)]
|
||||
fn len(self) -> usize {
|
||||
pub fn len(self) -> usize {
|
||||
self.entries.len()
|
||||
}
|
||||
|
||||
@@ -531,6 +532,11 @@ impl Iterator for DictIter {
|
||||
None => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
let l = self.dict.entries.len_from_entry_index(self.position);
|
||||
(l, Some(l))
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! dict_iterator {
|
||||
@@ -675,3 +681,26 @@ pub(crate) fn init(context: &PyContext) {
|
||||
PyDictItems::extend_class(context, &context.types.dictitems_type);
|
||||
PyDictItemIterator::extend_class(context, &context.types.dictitemiterator_type);
|
||||
}
|
||||
|
||||
pub struct PyMapping {
|
||||
dict: PyDictRef,
|
||||
}
|
||||
|
||||
impl TryFromObject for PyMapping {
|
||||
fn try_from_object(vm: &VirtualMachine, obj: PyObjectRef) -> PyResult<Self> {
|
||||
let dict = vm.ctx.new_dict();
|
||||
PyDictRef::merge(
|
||||
&dict.entries,
|
||||
OptionalArg::Present(obj),
|
||||
KwArgs::default(),
|
||||
vm,
|
||||
)?;
|
||||
Ok(PyMapping { dict })
|
||||
}
|
||||
}
|
||||
|
||||
impl PyMapping {
|
||||
pub fn into_dict(self) -> PyDictRef {
|
||||
self.dict
|
||||
}
|
||||
}
|
||||
|
||||
@@ -980,9 +980,12 @@ impl<T> PyIterable<T> {
|
||||
},
|
||||
)?;
|
||||
|
||||
let lenhint = objiter::length_hint(vm, iter_obj.clone())?;
|
||||
|
||||
Ok(PyIterator {
|
||||
vm,
|
||||
obj: iter_obj,
|
||||
lenhint,
|
||||
_item: std::marker::PhantomData,
|
||||
})
|
||||
}
|
||||
@@ -991,6 +994,7 @@ impl<T> PyIterable<T> {
|
||||
pub struct PyIterator<'a, T> {
|
||||
vm: &'a VirtualMachine,
|
||||
obj: PyObjectRef,
|
||||
lenhint: Option<usize>,
|
||||
_item: std::marker::PhantomData<T>,
|
||||
}
|
||||
|
||||
@@ -1012,6 +1016,10 @@ where
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn size_hint(&self) -> (usize, Option<usize>) {
|
||||
(self.lenhint.unwrap_or(0), self.lenhint)
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> TryFromObject for PyIterable<T>
|
||||
|
||||
@@ -28,7 +28,7 @@ use crate::exceptions::PyBaseExceptionRef;
|
||||
use crate::function::{IntoPyNativeFunc, OptionalArg, PyFuncArgs};
|
||||
use crate::obj::objbyteinner::PyBytesLike;
|
||||
use crate::obj::objbytes::{PyBytes, PyBytesRef};
|
||||
use crate::obj::objdict::PyDictRef;
|
||||
use crate::obj::objdict::{PyDictRef, PyMapping};
|
||||
use crate::obj::objint::PyIntRef;
|
||||
use crate::obj::objiter;
|
||||
use crate::obj::objset::PySet;
|
||||
@@ -41,14 +41,11 @@ use crate::pyobject::{
|
||||
};
|
||||
use crate::vm::VirtualMachine;
|
||||
|
||||
// cfg from nix
|
||||
#[cfg(any(
|
||||
target_os = "android",
|
||||
target_os = "freebsd",
|
||||
target_os = "linux",
|
||||
target_os = "openbsd"
|
||||
))]
|
||||
// just to avoid unused import warnings
|
||||
#[cfg(unix)]
|
||||
use crate::pyobject::PyIterable;
|
||||
#[cfg(unix)]
|
||||
use std::convert::TryFrom;
|
||||
|
||||
#[cfg(windows)]
|
||||
pub const MODULE_NAME: &str = "nt";
|
||||
@@ -138,6 +135,11 @@ impl PyPathLike {
|
||||
mode: OutputMode::String,
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
pub fn wide(&self) -> Vec<u16> {
|
||||
use std::os::windows::ffi::OsStrExt;
|
||||
self.path.encode_wide().chain(std::iter::once(0)).collect()
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFromObject for PyPathLike {
|
||||
@@ -412,11 +414,9 @@ fn getgroups() -> nix::Result<Vec<Gid>> {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn os_access(path: PyStringRef, mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
fn os_access(path: PyPathLike, mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
|
||||
let path = path.as_str();
|
||||
|
||||
let flags = AccessFlags::from_bits(mode).ok_or_else(|| {
|
||||
vm.new_value_error(
|
||||
"One of the flags is wrong, there are only 4 possibilities F_OK, R_OK, W_OK and X_OK"
|
||||
@@ -424,7 +424,7 @@ fn os_access(path: PyStringRef, mode: u8, vm: &VirtualMachine) -> PyResult<bool>
|
||||
)
|
||||
})?;
|
||||
|
||||
let metadata = fs::metadata(path);
|
||||
let metadata = fs::metadata(&path.path);
|
||||
|
||||
// if it's only checking for F_OK
|
||||
if flags == AccessFlags::F_OK {
|
||||
@@ -446,6 +446,19 @@ fn os_access(path: PyStringRef, mode: u8, vm: &VirtualMachine) -> PyResult<bool>
|
||||
|
||||
Ok(r_ok && w_ok && x_ok)
|
||||
}
|
||||
#[cfg(windows)]
|
||||
fn os_access(path: PyPathLike, mode: u8) -> bool {
|
||||
use winapi::um::{fileapi, winnt};
|
||||
let attr = unsafe { fileapi::GetFileAttributesW(path.wide().as_ptr()) };
|
||||
attr != fileapi::INVALID_FILE_ATTRIBUTES
|
||||
&& (mode & 2 == 0
|
||||
|| attr & winnt::FILE_ATTRIBUTE_READONLY == 0
|
||||
|| attr & winnt::FILE_ATTRIBUTE_DIRECTORY != 0)
|
||||
}
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
fn os_access(path: PyStringRef, mode: u8, vm: &VirtualMachine) -> PyResult<bool> {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn os_error(message: OptionalArg<PyStringRef>, vm: &VirtualMachine) -> PyResult {
|
||||
let msg = message.map_or("".to_owned(), |msg| msg.as_str().to_owned());
|
||||
@@ -1581,6 +1594,272 @@ fn os_setgroups(group_ids: PyIterable<u32>, vm: &VirtualMachine) -> PyResult<()>
|
||||
ret.map_err(|err| convert_nix_error(vm, err))
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn envp_from_dict(dict: PyDictRef, vm: &VirtualMachine) -> PyResult<Vec<ffi::CString>> {
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
dict.into_iter()
|
||||
.map(|(k, v)| {
|
||||
let k = PyPathLike::try_from_object(vm, k)?.path.into_vec();
|
||||
let v = PyPathLike::try_from_object(vm, v)?.path.into_vec();
|
||||
if k.contains(&0) {
|
||||
return Err(
|
||||
vm.new_value_error("envp dict key cannot contain a nul byte".to_owned())
|
||||
);
|
||||
}
|
||||
if k.contains(&b'=') {
|
||||
return Err(
|
||||
vm.new_value_error("envp dict key cannot contain a '=' character".to_owned())
|
||||
);
|
||||
}
|
||||
if v.contains(&0) {
|
||||
return Err(
|
||||
vm.new_value_error("envp dict value cannot contain a nul byte".to_owned())
|
||||
);
|
||||
}
|
||||
let mut env = k;
|
||||
env.push(b'=');
|
||||
env.extend(v);
|
||||
Ok(unsafe { ffi::CString::from_vec_unchecked(env) })
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
#[derive(FromArgs)]
|
||||
struct PosixSpawnArgs {
|
||||
#[pyarg(positional_only)]
|
||||
path: PyPathLike,
|
||||
#[pyarg(positional_only)]
|
||||
args: PyIterable<PyPathLike>,
|
||||
#[pyarg(positional_only)]
|
||||
env: PyMapping,
|
||||
#[pyarg(keyword_only, default = "None")]
|
||||
file_actions: Option<PyIterable<PyTupleRef>>,
|
||||
#[pyarg(keyword_only, default = "None")]
|
||||
setsigdef: Option<PyIterable<i32>>,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
#[derive(num_enum::IntoPrimitive, num_enum::TryFromPrimitive)]
|
||||
#[repr(i32)]
|
||||
enum PosixSpawnFileActionIdentifier {
|
||||
Open,
|
||||
Close,
|
||||
Dup2,
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
impl PosixSpawnArgs {
|
||||
fn spawn(self, spawnp: bool, vm: &VirtualMachine) -> PyResult<libc::pid_t> {
|
||||
use std::os::unix::ffi::OsStringExt;
|
||||
let path = ffi::CString::new(self.path.path.into_vec())
|
||||
.map_err(|_| vm.new_value_error("path should not have nul bytes".to_owned()))?;
|
||||
|
||||
let mut file_actions = unsafe {
|
||||
let mut fa = std::mem::MaybeUninit::uninit();
|
||||
assert!(libc::posix_spawn_file_actions_init(fa.as_mut_ptr()) == 0);
|
||||
fa.assume_init()
|
||||
};
|
||||
if let Some(it) = self.file_actions {
|
||||
for action in it.iter(vm)? {
|
||||
let action = action?;
|
||||
let (id, args) = action.as_slice().split_first().ok_or_else(|| {
|
||||
vm.new_type_error(
|
||||
"Each file_actions element must be a non-empty tuple".to_owned(),
|
||||
)
|
||||
})?;
|
||||
let id = i32::try_from_object(vm, id.clone())?;
|
||||
let id = PosixSpawnFileActionIdentifier::try_from(id)
|
||||
.map_err(|_| vm.new_type_error("Unknown file_actions identifier".to_owned()))?;
|
||||
let args = PyFuncArgs::from(args.to_vec());
|
||||
let ret = match id {
|
||||
PosixSpawnFileActionIdentifier::Open => {
|
||||
let (fd, path, oflag, mode): (_, PyPathLike, _, _) = args.bind(vm)?;
|
||||
let path = ffi::CString::new(path.path.into_vec()).map_err(|_| {
|
||||
vm.new_value_error(
|
||||
"POSIX_SPAWN_OPEN path should not have nul bytes".to_owned(),
|
||||
)
|
||||
})?;
|
||||
unsafe {
|
||||
libc::posix_spawn_file_actions_addopen(
|
||||
&mut file_actions,
|
||||
fd,
|
||||
path.as_ptr(),
|
||||
oflag,
|
||||
mode,
|
||||
)
|
||||
}
|
||||
}
|
||||
PosixSpawnFileActionIdentifier::Close => {
|
||||
let (fd,) = args.bind(vm)?;
|
||||
unsafe { libc::posix_spawn_file_actions_addclose(&mut file_actions, fd) }
|
||||
}
|
||||
PosixSpawnFileActionIdentifier::Dup2 => {
|
||||
let (fd, newfd) = args.bind(vm)?;
|
||||
unsafe {
|
||||
libc::posix_spawn_file_actions_adddup2(&mut file_actions, fd, newfd)
|
||||
}
|
||||
}
|
||||
};
|
||||
if ret != 0 {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let mut attrp = unsafe {
|
||||
let mut sa = std::mem::MaybeUninit::uninit();
|
||||
assert!(libc::posix_spawnattr_init(sa.as_mut_ptr()) == 0);
|
||||
sa.assume_init()
|
||||
};
|
||||
if let Some(sigs) = self.setsigdef {
|
||||
use nix::sys::signal;
|
||||
let mut set = signal::SigSet::empty();
|
||||
for sig in sigs.iter(vm)? {
|
||||
let sig = sig?;
|
||||
let sig = signal::Signal::try_from(sig).map_err(|_| {
|
||||
vm.new_value_error(format!("signal number {} out of range", sig))
|
||||
})?;
|
||||
set.add(sig);
|
||||
}
|
||||
assert!(unsafe { libc::posix_spawnattr_setsigdefault(&mut attrp, set.as_ref()) } == 0);
|
||||
}
|
||||
|
||||
let mut args: Vec<ffi::CString> = self
|
||||
.args
|
||||
.iter(vm)?
|
||||
.map(|res| {
|
||||
ffi::CString::new(res?.path.into_vec())
|
||||
.map_err(|_| vm.new_value_error("path should not have nul bytes".to_owned()))
|
||||
})
|
||||
.collect::<Result<_, _>>()?;
|
||||
let argv: Vec<*mut libc::c_char> = args
|
||||
.iter_mut()
|
||||
.map(|s| s.as_ptr() as _)
|
||||
.chain(std::iter::once(std::ptr::null_mut()))
|
||||
.collect();
|
||||
let mut env = envp_from_dict(self.env.into_dict(), vm)?;
|
||||
let envp: Vec<*mut libc::c_char> = env
|
||||
.iter_mut()
|
||||
.map(|s| s.as_ptr() as _)
|
||||
.chain(std::iter::once(std::ptr::null_mut()))
|
||||
.collect();
|
||||
|
||||
let mut pid = 0;
|
||||
let ret = unsafe {
|
||||
if spawnp {
|
||||
libc::posix_spawnp(
|
||||
&mut pid,
|
||||
path.as_ptr(),
|
||||
&file_actions,
|
||||
&attrp,
|
||||
argv.as_ptr(),
|
||||
envp.as_ptr(),
|
||||
)
|
||||
} else {
|
||||
libc::posix_spawn(
|
||||
&mut pid,
|
||||
path.as_ptr(),
|
||||
&file_actions,
|
||||
&attrp,
|
||||
argv.as_ptr(),
|
||||
envp.as_ptr(),
|
||||
)
|
||||
}
|
||||
};
|
||||
|
||||
if ret == 0 {
|
||||
Ok(pid)
|
||||
} else {
|
||||
Err(errno_err(vm))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
fn os_posix_spawn(args: PosixSpawnArgs, vm: &VirtualMachine) -> PyResult<libc::pid_t> {
|
||||
args.spawn(false, vm)
|
||||
}
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
fn os_posix_spawnp(args: PosixSpawnArgs, vm: &VirtualMachine) -> PyResult<libc::pid_t> {
|
||||
args.spawn(true, vm)
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
fn os_wifsignaled(status: i32) -> bool {
|
||||
unsafe { libc::WIFSIGNALED(status) }
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wifstopped(status: i32) -> bool {
|
||||
unsafe { libc::WIFSTOPPED(status) }
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wifexited(status: i32) -> bool {
|
||||
unsafe { libc::WIFEXITED(status) }
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wtermsig(status: i32) -> i32 {
|
||||
unsafe { libc::WTERMSIG(status) }
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wstopsig(status: i32) -> i32 {
|
||||
unsafe { libc::WSTOPSIG(status) }
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wexitstatus(status: i32) -> i32 {
|
||||
unsafe { libc::WEXITSTATUS(status) }
|
||||
}
|
||||
|
||||
// TODO: os.wait[pid] for windows
|
||||
#[cfg(unix)]
|
||||
fn os_waitpid(pid: libc::pid_t, opt: i32, vm: &VirtualMachine) -> PyResult<(libc::pid_t, i32)> {
|
||||
let mut status = 0;
|
||||
let pid = unsafe { libc::waitpid(pid, &mut status, opt) };
|
||||
let pid = Errno::result(pid).map_err(|e| convert_nix_error(vm, e))?;
|
||||
Ok((pid, status))
|
||||
}
|
||||
#[cfg(unix)]
|
||||
fn os_wait(vm: &VirtualMachine) -> PyResult<(libc::pid_t, i32)> {
|
||||
os_waitpid(-1, 0, vm)
|
||||
}
|
||||
|
||||
fn os_kill(pid: i32, sig: isize, vm: &VirtualMachine) -> PyResult<()> {
|
||||
#[cfg(unix)]
|
||||
{
|
||||
let ret = unsafe { libc::kill(pid, sig as i32) };
|
||||
if ret == -1 {
|
||||
Err(errno_err(vm))
|
||||
} else {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
#[cfg(windows)]
|
||||
{
|
||||
use winapi::um::{handleapi, processthreadsapi, wincon, winnt};
|
||||
let sig = sig as u32;
|
||||
let pid = pid as u32;
|
||||
|
||||
if sig == wincon::CTRL_C_EVENT || sig == wincon::CTRL_BREAK_EVENT {
|
||||
let ret = unsafe { wincon::GenerateConsoleCtrlEvent(sig, pid) };
|
||||
let res = if ret == 0 { Err(errno_err(vm)) } else { Ok(()) };
|
||||
return res;
|
||||
}
|
||||
|
||||
let h = unsafe { processthreadsapi::OpenProcess(winnt::PROCESS_ALL_ACCESS, 0, pid) };
|
||||
if h.is_null() {
|
||||
return Err(errno_err(vm));
|
||||
}
|
||||
let ret = unsafe { processthreadsapi::TerminateProcess(h, sig) };
|
||||
let res = if ret == 0 { Err(errno_err(vm)) } else { Ok(()) };
|
||||
unsafe { handleapi::CloseHandle(h) };
|
||||
res
|
||||
}
|
||||
#[cfg(not(any(unix, windows)))]
|
||||
{
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
|
||||
pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
let ctx = &vm.ctx;
|
||||
|
||||
@@ -1632,7 +1911,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
#[allow(unused_mut)]
|
||||
let mut support_funcs = vec![
|
||||
SupportFunc::new(vm, "open", os_open, None, Some(false), None),
|
||||
// access Some Some None
|
||||
SupportFunc::new(vm, "access", os_access, Some(false), Some(false), None),
|
||||
SupportFunc::new(vm, "chdir", os_chdir, Some(false), None, None),
|
||||
// chflags Some, None Some
|
||||
// chown Some Some Some
|
||||
@@ -1690,6 +1969,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef {
|
||||
"lseek" => ctx.new_function(os_lseek),
|
||||
"set_inheritable" => ctx.new_function(os_set_inheritable),
|
||||
"link" => ctx.new_function(os_link),
|
||||
"kill" => ctx.new_function(os_kill),
|
||||
|
||||
"O_RDONLY" => ctx.new_int(libc::O_RDONLY),
|
||||
"O_WRONLY" => ctx.new_int(libc::O_WRONLY),
|
||||
@@ -1748,7 +2028,6 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
|
||||
let uname_result = UnameResult::make_class(ctx);
|
||||
|
||||
extend_module!(vm, module, {
|
||||
"access" => ctx.new_function(os_access),
|
||||
"chmod" => ctx.new_function(os_chmod),
|
||||
"get_inheritable" => ctx.new_function(os_get_inheritable), // TODO: windows
|
||||
"get_blocking" => ctx.new_function(os_get_blocking),
|
||||
@@ -1769,6 +2048,15 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
|
||||
"ttyname" => ctx.new_function(os_ttyname),
|
||||
"uname" => ctx.new_function(os_uname),
|
||||
"uname_result" => uname_result,
|
||||
"wait" => ctx.new_function(os_wait),
|
||||
"waitpid" => ctx.new_function(os_waitpid),
|
||||
"WIFSIGNALED" => ctx.new_function(os_wifsignaled),
|
||||
"WIFSTOPPED" => ctx.new_function(os_wifstopped),
|
||||
"WIFEXITED" => ctx.new_function(os_wifexited),
|
||||
"WTERMSIG" => ctx.new_function(os_wtermsig),
|
||||
"WSTOPSIG" => ctx.new_function(os_wstopsig),
|
||||
"WEXITSTATUS" => ctx.new_function(os_wexitstatus),
|
||||
"WNOHANG" => ctx.new_int(libc::WNOHANG),
|
||||
"EX_OK" => ctx.new_int(exitcode::OK as i8),
|
||||
"EX_USAGE" => ctx.new_int(exitcode::USAGE as i8),
|
||||
"EX_DATAERR" => ctx.new_int(exitcode::DATAERR as i8),
|
||||
@@ -1846,6 +2134,15 @@ fn extend_module_platform_specific(vm: &VirtualMachine, module: &PyObjectRef) {
|
||||
extend_module!(vm, module, {
|
||||
"pipe2" => ctx.new_function(os_pipe2),
|
||||
});
|
||||
|
||||
#[cfg(any(target_os = "linux", target_os = "freebsd", target_os = "macos"))]
|
||||
extend_module!(vm, module, {
|
||||
"posix_spawn" => ctx.new_function(os_posix_spawn),
|
||||
"posix_spawnp" => ctx.new_function(os_posix_spawnp),
|
||||
"POSIX_SPAWN_OPEN" => ctx.new_int(i32::from(PosixSpawnFileActionIdentifier::Open)),
|
||||
"POSIX_SPAWN_CLOSE" => ctx.new_int(i32::from(PosixSpawnFileActionIdentifier::Close)),
|
||||
"POSIX_SPAWN_DUP2" => ctx.new_int(i32::from(PosixSpawnFileActionIdentifier::Dup2)),
|
||||
});
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
|
||||
Reference in New Issue
Block a user