From 53c653fd2bc6430ae3c1e0ee5502d095b5dd53b5 Mon Sep 17 00:00:00 2001 From: Marcin Pajkowski Date: Thu, 25 Jul 2019 12:50:57 +0200 Subject: [PATCH 1/2] Implement several methods - os module os.getpid [RUST STD] os.getegid [UNIX] os.getgid [UNIX] os.getsid [UNIX] os.getuid [UNIX] os.geteuid [UNIX] os.getppid [UNIX] os.getpgid [UNIX] os.setgid [UNIX] os.setegid [UNIX] os.setpgid [UNIX] os.setuid [UNIX] os.seteuid [UNIX] --- Cargo.lock | 14 ++++ tests/snippets/stdlib_os.py | 23 ++++++ vm/Cargo.toml | 1 + vm/src/builtins.rs | 1 + vm/src/stdlib/os.rs | 155 ++++++++++++++++++++++++++++++++++++ 5 files changed, 194 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index f71f35a718..e05958928c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -588,6 +588,18 @@ dependencies = [ "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "nix" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cc 1.0.37 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.60 (registry+https://github.com/rust-lang/crates.io-index)", + "void 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "nodrop" version = "0.1.13" @@ -1019,6 +1031,7 @@ dependencies = [ "log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", "maplit 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "md-5 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "num-complex 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)", @@ -1913,6 +1926,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum memchr 2.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "88579771288728879b57485cc7d6b07d648c9f0141eb955f8ab7f9d45394468e" "checksum new_debug_unreachable 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "f40f005c60db6e03bae699e414c58bf9aa7ea02a2d0b9bfbcf19286cc4c82b30" "checksum nix 0.13.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4dbdc256eaac2e3bd236d93ad999d3479ef775c863dbda3068c4006a92eec51b" +"checksum nix 0.14.1 (registry+https://github.com/rust-lang/crates.io-index)" = "6c722bee1037d430d0f8e687bbdbf222f27cc6e4e68d5caf630857bb2b6dbdce" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nom 4.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2ad2a91a8e869eeb30b9cb3119ae87773a8f4ae617f41b1eb9c154b2905f7bd6" "checksum num-bigint 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "57450397855d951f1a41305e54851b1a7b8f5d2e349543a02a2effe25459f718" diff --git a/tests/snippets/stdlib_os.py b/tests/snippets/stdlib_os.py index d2e39c1ce5..df163a1959 100644 --- a/tests/snippets/stdlib_os.py +++ b/tests/snippets/stdlib_os.py @@ -1,6 +1,7 @@ import os import time import stat +import sys from testutils import assert_raises @@ -251,3 +252,25 @@ def __exit__(self, exc_type, exc_val, exc_tb): assert isinstance(os.supports_fd, set) assert isinstance(os.supports_dir_fd, set) assert isinstance(os.supports_follow_symlinks, set) + +# get pid +assert isinstance(os.getpid(), int) + +# unix +if "win" not in sys.platform: + assert isinstance(os.getegid(), int) + assert isinstance(os.getgid(), int) + assert isinstance(os.getsid(os.getpid()), int) + assert isinstance(os.getuid(), int) + assert isinstance(os.geteuid(), int) + assert isinstance(os.getppid(), int) + assert isinstance(os.getpgid(os.getpid()), int) + + assert os.getppid() < os.getpid() + + if os.getuid() != 0: + assert_raises(PermissionError, lambda: os.setgid(42)) + assert_raises(PermissionError, lambda: os.setegid(42)) + assert_raises(PermissionError, lambda: os.setpgid(os.getpid(), 42)) + assert_raises(PermissionError, lambda: os.setuid(42)) + assert_raises(PermissionError, lambda: os.seteuid(42)) diff --git a/vm/Cargo.toml b/vm/Cargo.toml index 0b15c0b2eb..bb8849e429 100644 --- a/vm/Cargo.toml +++ b/vm/Cargo.toml @@ -61,6 +61,7 @@ maplit = "1.0" proc-macro-hack = { version = "0.5", optional = true } bitflags = "1.1" libc = "0.2" +nix = "0.14.1" flame = { version = "0.2", optional = true } flamer = { version = "0.3", optional = true } diff --git a/vm/src/builtins.rs b/vm/src/builtins.rs index 0affb002d9..f0a2b4e731 100644 --- a/vm/src/builtins.rs +++ b/vm/src/builtins.rs @@ -887,6 +887,7 @@ pub fn make_module(vm: &VirtualMachine, module: PyObjectRef) { "FileExistsError" => ctx.exceptions.file_exists_error.clone(), "StopIteration" => ctx.exceptions.stop_iteration.clone(), "SystemError" => ctx.exceptions.system_error.clone(), + "PermissionError" => ctx.exceptions.permission_error.clone(), "UnicodeError" => ctx.exceptions.unicode_error.clone(), "UnicodeDecodeError" => ctx.exceptions.unicode_decode_error.clone(), "UnicodeEncodeError" => ctx.exceptions.unicode_encode_error.clone(), diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 80c3406b51..58f502acda 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -6,6 +6,8 @@ use std::time::{Duration, SystemTime}; use std::{env, fs}; use bitflags::bitflags; +use nix::errno::Errno; +use nix::unistd::{self, Gid, Pid, Uid}; use num_traits::cast::ToPrimitive; use crate::function::{IntoPyNativeFunc, PyFuncArgs}; @@ -174,6 +176,41 @@ fn convert_io_error(vm: &VirtualMachine, err: io::Error) -> PyObjectRef { os_error } +fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyObjectRef { + let nix_error = match err { + nix::Error::InvalidPath => { + let exc_type = vm.ctx.exceptions.file_not_found_error.clone(); + vm.new_exception(exc_type, err.to_string()) + } + nix::Error::InvalidUtf8 => { + let exc_type = vm.ctx.exceptions.unicode_error.clone(); + vm.new_exception(exc_type, err.to_string()) + } + nix::Error::UnsupportedOperation => { + let exc_type = vm.ctx.exceptions.runtime_error.clone(); + vm.new_exception(exc_type, err.to_string()) + } + nix::Error::Sys(errno) => { + let exc_type = convert_nix_errno(vm, errno); + vm.new_exception(exc_type, err.to_string()) + } + }; + + if let nix::Error::Sys(errno) = err { + vm.set_attr(&nix_error, "errno", vm.ctx.new_int(errno as i32)) + .unwrap(); + } + + nix_error +} + +fn convert_nix_errno(vm: &VirtualMachine, errno: Errno) -> PyClassRef { + match errno { + Errno::EPERM => vm.ctx.exceptions.permission_error.clone(), + _ => vm.ctx.exceptions.os_error.clone(), + } +} + fn os_error(vm: &VirtualMachine, args: PyFuncArgs) -> PyResult { arg_check!( vm, @@ -709,6 +746,105 @@ fn os_rename(src: PyStringRef, dst: PyStringRef, vm: &VirtualMachine) -> PyResul fs::rename(&src.value, &dst.value).map_err(|err| convert_io_error(vm, err)) } +fn os_getpid(vm: &VirtualMachine) -> PyObjectRef { + let pid = std::process::id(); + vm.new_int(pid) +} + +#[cfg(unix)] +fn os_getppid(vm: &VirtualMachine) -> PyObjectRef { + let ppid = unistd::getppid().as_raw(); + vm.new_int(ppid) +} + +#[cfg(unix)] +fn os_getgid(vm: &VirtualMachine) -> PyObjectRef { + let gid = unistd::getgid().as_raw(); + vm.new_int(gid) +} + +#[cfg(unix)] +fn os_getegid(vm: &VirtualMachine) -> PyObjectRef { + let egid = unistd::getegid().as_raw(); + vm.new_int(egid) +} + +#[cfg(unix)] +fn os_getpgid(pid: PyIntRef, vm: &VirtualMachine) -> PyObjectRef { + let pid = pid.as_bigint().to_u32().unwrap(); + + match unistd::getpgid(Some(Pid::from_raw(pid as i32))) { + Ok(pgid) => vm.new_int(pgid.as_raw()), + Err(err) => convert_nix_error(vm, err), + } +} + +#[cfg(unix)] +fn os_getsid(pid: PyIntRef, vm: &VirtualMachine) -> PyObjectRef { + let pid = pid.as_bigint().to_u32().unwrap(); + + match unistd::getsid(Some(Pid::from_raw(pid as i32))) { + Ok(sid) => vm.new_int(sid.as_raw()), + Err(err) => convert_nix_error(vm, err), + } +} + +#[cfg(unix)] +fn os_getuid(vm: &VirtualMachine) -> PyObjectRef { + let uid = unistd::getuid().as_raw(); + vm.new_int(uid) +} + +#[cfg(unix)] +fn os_geteuid(vm: &VirtualMachine) -> PyObjectRef { + let euid = unistd::geteuid().as_raw(); + vm.new_int(euid) +} + +#[cfg(unix)] +fn os_setgid(gid: PyIntRef, vm: &VirtualMachine) -> PyResult<()> { + let gid = gid.as_bigint().to_u32().unwrap(); + + unistd::setgid(Gid::from_raw(gid)).map_err(|err| convert_nix_error(vm, err)) +} + +#[cfg(unix)] +fn os_setegid(egid: PyIntRef, vm: &VirtualMachine) -> PyResult<()> { + let egid = egid.as_bigint().to_u32().unwrap(); + + unistd::setegid(Gid::from_raw(egid)).map_err(|err| convert_nix_error(vm, err)) +} + +#[cfg(unix)] +fn os_setpgid(pid: PyIntRef, pgid: PyIntRef, vm: &VirtualMachine) -> PyResult<()> { + let pid = pid.as_bigint().to_u32().unwrap(); + let pgid = pgid.as_bigint().to_u32().unwrap(); + + unistd::setpgid(Pid::from_raw(pid as i32), Pid::from_raw(pgid as i32)) + .map_err(|err| convert_nix_error(vm, err)) +} + +#[cfg(unix)] +fn os_setsid(vm: &VirtualMachine) -> PyResult<()> { + unistd::setsid() + .map(|_ok| ()) + .map_err(|err| convert_nix_error(vm, err)) +} + +#[cfg(unix)] +fn os_setuid(uid: PyIntRef, vm: &VirtualMachine) -> PyResult<()> { + let uid = uid.as_bigint().to_u32().unwrap(); + + unistd::setuid(Uid::from_raw(uid)).map_err(|err| convert_nix_error(vm, err)) +} + +#[cfg(unix)] +fn os_seteuid(euid: PyIntRef, vm: &VirtualMachine) -> PyResult<()> { + let euid = euid.as_bigint().to_u32().unwrap(); + + unistd::seteuid(Uid::from_raw(euid)).map_err(|err| convert_nix_error(vm, err)) +} + pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { let ctx = &vm.ctx; @@ -832,6 +968,7 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "R_OK" => ctx.new_int(4), "W_OK" => ctx.new_int(2), "X_OK" => ctx.new_int(1), + "getpid" => ctx.new_rustfunc(os_getpid) }); for support in support_funcs { @@ -863,5 +1000,23 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "supports_follow_symlinks" => supports_follow_symlinks.into_object(), }); + if cfg!(unix) { + extend_module!(vm, module, { + "getppid" => ctx.new_rustfunc(os_getppid), + "getgid" => ctx.new_rustfunc(os_getgid), + "getegid" => ctx.new_rustfunc(os_getegid), + "getpgid" => ctx.new_rustfunc(os_getpgid), + "getsid" => ctx.new_rustfunc(os_getsid), + "getuid" => ctx.new_rustfunc(os_getuid), + "geteuid" => ctx.new_rustfunc(os_geteuid), + "setgid" => ctx.new_rustfunc(os_setgid), + "setegid" => ctx.new_rustfunc(os_setegid), + "setpgid" => ctx.new_rustfunc(os_setpgid), + "setsid" => ctx.new_rustfunc(os_setsid), + "setuid" => ctx.new_rustfunc(os_setuid), + "seteuid" => ctx.new_rustfunc(os_seteuid), + }); + } + module } From 364ddeb6b219abef3329f6d57acd577cb4d48eac Mon Sep 17 00:00:00 2001 From: Marcin Pajkowski Date: Tue, 30 Jul 2019 22:54:29 +0200 Subject: [PATCH 2/2] Fix compilation on Windows --- vm/src/stdlib/os.rs | 48 +++++++++++++++++++++++++++++---------------- 1 file changed, 31 insertions(+), 17 deletions(-) diff --git a/vm/src/stdlib/os.rs b/vm/src/stdlib/os.rs index 58f502acda..d510699c91 100644 --- a/vm/src/stdlib/os.rs +++ b/vm/src/stdlib/os.rs @@ -6,7 +6,9 @@ use std::time::{Duration, SystemTime}; use std::{env, fs}; use bitflags::bitflags; +#[cfg(unix)] use nix::errno::Errno; +#[cfg(unix)] use nix::unistd::{self, Gid, Pid, Uid}; use num_traits::cast::ToPrimitive; @@ -176,6 +178,7 @@ fn convert_io_error(vm: &VirtualMachine, err: io::Error) -> PyObjectRef { os_error } +#[cfg(unix)] fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyObjectRef { let nix_error = match err { nix::Error::InvalidPath => { @@ -204,6 +207,7 @@ fn convert_nix_error(vm: &VirtualMachine, err: nix::Error) -> PyObjectRef { nix_error } +#[cfg(unix)] fn convert_nix_errno(vm: &VirtualMachine, errno: Errno) -> PyClassRef { match errno { Errno::EPERM => vm.ctx.exceptions.permission_error.clone(), @@ -1000,23 +1004,33 @@ pub fn make_module(vm: &VirtualMachine) -> PyObjectRef { "supports_follow_symlinks" => supports_follow_symlinks.into_object(), }); - if cfg!(unix) { - extend_module!(vm, module, { - "getppid" => ctx.new_rustfunc(os_getppid), - "getgid" => ctx.new_rustfunc(os_getgid), - "getegid" => ctx.new_rustfunc(os_getegid), - "getpgid" => ctx.new_rustfunc(os_getpgid), - "getsid" => ctx.new_rustfunc(os_getsid), - "getuid" => ctx.new_rustfunc(os_getuid), - "geteuid" => ctx.new_rustfunc(os_geteuid), - "setgid" => ctx.new_rustfunc(os_setgid), - "setegid" => ctx.new_rustfunc(os_setegid), - "setpgid" => ctx.new_rustfunc(os_setpgid), - "setsid" => ctx.new_rustfunc(os_setsid), - "setuid" => ctx.new_rustfunc(os_setuid), - "seteuid" => ctx.new_rustfunc(os_seteuid), - }); - } + extend_module_platform_specific(&vm, module) +} + +#[cfg(unix)] +fn extend_module_platform_specific(vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { + let ctx = &vm.ctx; + + extend_module!(vm, module, { + "getppid" => ctx.new_rustfunc(os_getppid), + "getgid" => ctx.new_rustfunc(os_getgid), + "getegid" => ctx.new_rustfunc(os_getegid), + "getpgid" => ctx.new_rustfunc(os_getpgid), + "getsid" => ctx.new_rustfunc(os_getsid), + "getuid" => ctx.new_rustfunc(os_getuid), + "geteuid" => ctx.new_rustfunc(os_geteuid), + "setgid" => ctx.new_rustfunc(os_setgid), + "setegid" => ctx.new_rustfunc(os_setegid), + "setpgid" => ctx.new_rustfunc(os_setpgid), + "setsid" => ctx.new_rustfunc(os_setsid), + "setuid" => ctx.new_rustfunc(os_setuid), + "seteuid" => ctx.new_rustfunc(os_seteuid), + }); + + module +} +#[cfg(not(unix))] +fn extend_module_platform_specific(_vm: &VirtualMachine, module: PyObjectRef) -> PyObjectRef { module }