<commit_before>use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char};
use std::mem::uninitialized;
use std::cmp;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
use std::ffi::CString;
use std::string::String;
use super::mpz::mp_bitcnt_t;
use super::mpz::{Mpz, mpz_srcptr};
use super::mpq::{Mpq, mpq_srcptr};
use super::sign::Sign;
use num_traits::{Zero, One};

type mp_exp_t = c_long;

#[repr(C)]
pub struct mpf_struct {
    _mp_prec: c_int,
    _mp_size: c_int,
    _mp_exp: mp_exp_t,
    _mp_d: *mut c_void
}

pub type mpf_srcptr = *const mpf_struct;
pub type mpf_ptr = *mut mpf_struct;

#[link(name = "gmp")]
extern "C" {
    fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_init_set(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_clear(x: mpf_ptr);
    fn __gmpf_get_prec(op: mpf_srcptr) -> mp_bitcnt_t;
    fn __gmpf_set_prec(rop: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_set(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_set_z(rop: mpf_ptr, op: mpz_srcptr);
    fn __gmpf_set_q(rop: mpf_ptr, op: mpq_srcptr);

    fn __gmpf_set_str(rop: mpf_ptr, str: *const c_char, base: c_int);
    fn __gmpf_set_si(rop: mpf_ptr, op: c_long);
    fn __gmpf_get_str(str: *const c_char, expptr: *const mp_exp_t, base: i32, n_digits: i32, op: mpf_ptr) -> *mut c_char;

    fn __gmpf_cmp(op1: mpf_srcptr, op2: mpf_srcptr) -> c_int;
    fn __gmpf_cmp_d(op1: mpf_srcptr, op2: c_double) -> c_int;
    fn __gmpf_cmp_ui(op1: mpf_srcptr, op2: c_ulong) -> c_int;
    fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int;
    fn __gmpf_reldiff(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_add(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_sub(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_mul(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_div(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_neg(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_abs(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_ceil(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_floor(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_trunc(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_sqrt(rop: mpf_ptr, op: mpf_srcptr);
}

pub struct Mpf {
    mpf: mpf_struct,
}

unsafe impl Send for Mpf { }
unsafe impl Sync for Mpf { }

impl Drop for Mpf {
    fn drop(&mut self) { unsafe { __gmpf_clear(&mut self.mpf) } }
}

impl Mpf {
    pub unsafe fn inner(&self) -> mpf_srcptr {
        &self.mpf
    }

    pub unsafe fn inner_mut(&mut self) -> mpf_ptr {
        &mut self.mpf
    }

    pub fn zero() -> Mpf { Mpf::new(32) }

    pub fn new(precision: usize) -> Mpf {
        unsafe {
            let mut mpf = uninitialized();
            __gmpf_init2(&mut mpf, precision as c_ulong);
            Mpf { mpf: mpf }
        }
    }

    pub fn set(&mut self, other: &Mpf) {
        unsafe { __gmpf_set(&mut self.mpf, &other.mpf) }
    }

    pub fn set_z(&mut self, other: &Mpz) {
        unsafe { __gmpf_set_z(&mut self.mpf, other.inner()) }
    }

    pub fn set_q(&mut self, other: &Mpq) {
        unsafe { __gmpf_set_q(&mut self.mpf, other.inner()) }
    }

    pub fn get_prec(&self) -> usize {
        unsafe { __gmpf_get_prec(&self.mpf) as usize }
    }

    pub fn set_prec(&mut self, precision: usize) {
        unsafe { __gmpf_set_prec(&mut self.mpf, precision as c_ulong) }
    }

    pub fn set_from_str(&mut self, string: &str, base: i32){
        let c_str = CString::new(string).unwrap();
        unsafe {
            __gmpf_set_str(&mut self.mpf, c_str.as_ptr(), base as c_int);
        }
    }

    pub fn set_from_si(&mut self, int: i64){
        unsafe{
            __gmpf_set_si(&mut self.mpf,int as c_long);
        }
    }

    pub fn get_str(&mut self, n_digits: i32, base: i32, exp: &mut c_long) -> String{
        let c_str = CString::new("").unwrap();
        let out;
        unsafe{
            out = CString::from_raw(__gmpf_get_str(c_str.into_raw(), exp, base, n_digits, &mut self.mpf));
        }
        out.to_str().unwrap().to_string()
    }

    pub fn abs(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_abs(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn ceil(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_ceil(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn floor(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_floor(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn trunc(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_trunc(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn reldiff(&self, other: &Mpf) -> Mpf {
        unsafe {
            let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
            __gmpf_reldiff(&mut res.mpf, &self.mpf, &other.mpf);
            res
        }
    }

    pub fn sqrt(self) -> Mpf {
        let mut retval:Mpf;
        unsafe {
            retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize);
            retval.set_from_si(0);
            if __gmpf_cmp_si(&self.mpf, 0) > 0 {
                __gmpf_sqrt(&mut retval.mpf, &self.mpf);
            } else {
                panic!("Square root of negative/zero");
            }
        }
        retval
    }

    pub fn sign(&self) -> Sign {
        let size = self.mpf._mp_size;
        if size == 0 {
            Sign::Zero
        } else if size > 0 {
            Sign::Positive
        } else {
            Sign::Negative
        }
    }
}

impl Clone for Mpf {
    fn clone(&self) -> Mpf {
        unsafe {
            let mut mpf = uninitialized();
            __gmpf_init_set(&mut mpf, &self.mpf);
            Mpf { mpf: mpf }
        }
    }
}

impl Eq for Mpf { }
impl PartialEq for Mpf {
    fn eq(&self, other: &Mpf) -> bool {
        unsafe { __gmpf_cmp(&self.mpf, &other.mpf) == 0 }
    }
}

impl Ord for Mpf {
    fn cmp(&self, other: &Mpf) -> Ordering {
        let cmp = unsafe { __gmpf_cmp(&self.mpf, &other.mpf) };
        if cmp == 0 {
            Equal
        } else if cmp > 0 {
            Greater
        } else {
            Less
        }
    }
}

impl PartialOrd for Mpf {
    fn partial_cmp(&self, other: &Mpf) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

macro_rules! div_guard {
    (Div, $is_zero: expr) => {
        if $is_zero {
            panic!("divide by zero")
        }
    };
    ($tr: ident, $what: expr) => {}
}

macro_rules! impl_oper {
    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
        impl<'a> $tr<Mpf> for &'a Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(self, other: Mpf) -> Mpf {
                self.$meth(&other)
            }
        }

        impl<'a> $tr<&'a Mpf> for Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(mut self, other: &Mpf) -> Mpf {
                self.$meth_assign(other);
                self
            }
        }

        impl $tr<Mpf> for Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(self, other: Mpf) -> Mpf {
                self.$meth(&other)
            }
        }

        impl<'a, 'b> $tr<&'a Mpf> for &'b Mpf {
            type Output = Mpf;
            fn $meth(self, other: &Mpf) -> Mpf {
                unsafe {
                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
                    let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
                    $fun(&mut res.mpf, &self.mpf, &other.mpf);
                    res
                }
            }
        }

        impl<'a> $tr_assign<Mpf> for Mpf {
            #[inline]
            fn $meth_assign(&mut self, other: Mpf) {
                self.$meth_assign(&other)
            }
        }

        impl<'a> $tr_assign<&'a Mpf> for Mpf {
            #[inline]
            fn $meth_assign(&mut self, other: &Mpf) {
                unsafe {
                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
                    $fun(&mut self.mpf, &self.mpf, &other.mpf)
                }
            }
        }
    }
}

impl_oper!(Add, add, AddAssign, add_assign, __gmpf_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpf_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpf_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpf_div);

impl<'b> Neg for &'b Mpf {
    type Output = Mpf;
    fn neg(self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_neg(&mut res.mpf, &self.mpf);
            res
        }
    }
}

impl Neg for Mpf {
    type Output = Mpf;
    #[inline]
    fn neg(mut self) -> Mpf {
        unsafe {
            __gmpf_neg(&mut self.mpf, &self.mpf);
            self
        }
    }
}

impl Zero for Mpf {
    #[inline]
    fn zero() -> Mpf {
        Mpf::zero()
    }

    #[inline]
    fn is_zero(&self) -> bool {
        unsafe {
            __gmpf_cmp_ui(&self.mpf, 0) == 0
        }
    }
}

impl One for Mpf {
    #[inline]
    fn one() -> Mpf {
        let mut res = Mpf::new(32);
        res.set_from_si(1);
        res
    }
}
<commit_msg>Fixes #26<commit_after>use libc::{c_double, c_int, c_long, c_ulong, c_void,c_char, free};
use std;
use std::mem::uninitialized;
use std::cmp;
use std::cmp::Ordering::{self, Greater, Less, Equal};
use std::ops::{Div, DivAssign, Mul, MulAssign, Add, AddAssign, Sub, SubAssign, Neg};
use std::ffi::CString;
use std::string::String;
use super::mpz::mp_bitcnt_t;
use super::mpz::{Mpz, mpz_srcptr};
use super::mpq::{Mpq, mpq_srcptr};
use super::sign::Sign;
use num_traits::{Zero, One};

type mp_exp_t = c_long;

#[repr(C)]
pub struct mpf_struct {
    _mp_prec: c_int,
    _mp_size: c_int,
    _mp_exp: mp_exp_t,
    _mp_d: *mut c_void
}

pub type mpf_srcptr = *const mpf_struct;
pub type mpf_ptr = *mut mpf_struct;

#[link(name = "gmp")]
extern "C" {
    fn __gmpf_init2(x: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_init_set(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_clear(x: mpf_ptr);
    fn __gmpf_get_prec(op: mpf_srcptr) -> mp_bitcnt_t;
    fn __gmpf_set_prec(rop: mpf_ptr, prec: mp_bitcnt_t);
    fn __gmpf_set(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_set_z(rop: mpf_ptr, op: mpz_srcptr);
    fn __gmpf_set_q(rop: mpf_ptr, op: mpq_srcptr);

    fn __gmpf_set_str(rop: mpf_ptr, str: *const c_char, base: c_int);
    fn __gmpf_set_si(rop: mpf_ptr, op: c_long);
    fn __gmpf_get_str(str: *const c_char, expptr: *const mp_exp_t, base: i32, n_digits: i32, op: mpf_ptr) -> *mut c_char;

    fn __gmpf_cmp(op1: mpf_srcptr, op2: mpf_srcptr) -> c_int;
    fn __gmpf_cmp_d(op1: mpf_srcptr, op2: c_double) -> c_int;
    fn __gmpf_cmp_ui(op1: mpf_srcptr, op2: c_ulong) -> c_int;
    fn __gmpf_cmp_si(op1: mpf_srcptr, op2: c_long) -> c_int;
    fn __gmpf_reldiff(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_add(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_sub(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_mul(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_div(rop: mpf_ptr, op1: mpf_srcptr, op2: mpf_srcptr);
    fn __gmpf_neg(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_abs(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_ceil(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_floor(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_trunc(rop: mpf_ptr, op: mpf_srcptr);
    fn __gmpf_sqrt(rop: mpf_ptr, op: mpf_srcptr);
}

pub struct Mpf {
    mpf: mpf_struct,
}

unsafe impl Send for Mpf { }
unsafe impl Sync for Mpf { }

impl Drop for Mpf {
    fn drop(&mut self) { unsafe { __gmpf_clear(&mut self.mpf) } }
}

impl Mpf {
    pub unsafe fn inner(&self) -> mpf_srcptr {
        &self.mpf
    }

    pub unsafe fn inner_mut(&mut self) -> mpf_ptr {
        &mut self.mpf
    }

    pub fn zero() -> Mpf { Mpf::new(32) }

    pub fn new(precision: usize) -> Mpf {
        unsafe {
            let mut mpf = uninitialized();
            __gmpf_init2(&mut mpf, precision as c_ulong);
            Mpf { mpf: mpf }
        }
    }

    pub fn set(&mut self, other: &Mpf) {
        unsafe { __gmpf_set(&mut self.mpf, &other.mpf) }
    }

    pub fn set_z(&mut self, other: &Mpz) {
        unsafe { __gmpf_set_z(&mut self.mpf, other.inner()) }
    }

    pub fn set_q(&mut self, other: &Mpq) {
        unsafe { __gmpf_set_q(&mut self.mpf, other.inner()) }
    }

    pub fn get_prec(&self) -> usize {
        unsafe { __gmpf_get_prec(&self.mpf) as usize }
    }

    pub fn set_prec(&mut self, precision: usize) {
        unsafe { __gmpf_set_prec(&mut self.mpf, precision as c_ulong) }
    }

    pub fn set_from_str(&mut self, string: &str, base: i32){
        let c_str = CString::new(string).unwrap();
        unsafe {
            __gmpf_set_str(&mut self.mpf, c_str.as_ptr(), base as c_int);
        }
    }

    pub fn set_from_si(&mut self, int: i64){
        unsafe{
            __gmpf_set_si(&mut self.mpf,int as c_long);
        }
    }

    pub fn get_str(&mut self, n_digits: i32, base: i32, exp: &mut c_long) -> String{
	let out;
        unsafe{
            out = CString::from_raw(__gmpf_get_str(std::ptr::null(), exp, base, n_digits, &mut self.mpf));
        }
        let r = out.to_str().unwrap().to_string();
	// Free the pointer returned to us, as r already took a copy of the data inside of it
	// Stops memory leaking
	unsafe { free(out.into_raw() as _) };
	r
    }

    pub fn abs(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_abs(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn ceil(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_ceil(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn floor(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_floor(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn trunc(&self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_trunc(&mut res.mpf, &self.mpf);
            res
        }
    }

    pub fn reldiff(&self, other: &Mpf) -> Mpf {
        unsafe {
            let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
            __gmpf_reldiff(&mut res.mpf, &self.mpf, &other.mpf);
            res
        }
    }

    pub fn sqrt(self) -> Mpf {
        let mut retval:Mpf;
        unsafe {
            retval = Mpf::new(__gmpf_get_prec(&self.mpf) as usize);
            retval.set_from_si(0);
            if __gmpf_cmp_si(&self.mpf, 0) > 0 {
                __gmpf_sqrt(&mut retval.mpf, &self.mpf);
            } else {
                panic!("Square root of negative/zero");
            }
        }
        retval
    }

    pub fn sign(&self) -> Sign {
        let size = self.mpf._mp_size;
        if size == 0 {
            Sign::Zero
        } else if size > 0 {
            Sign::Positive
        } else {
            Sign::Negative
        }
    }
}

impl Clone for Mpf {
    fn clone(&self) -> Mpf {
        unsafe {
            let mut mpf = uninitialized();
            __gmpf_init_set(&mut mpf, &self.mpf);
            Mpf { mpf: mpf }
        }
    }
}

impl Eq for Mpf { }
impl PartialEq for Mpf {
    fn eq(&self, other: &Mpf) -> bool {
        unsafe { __gmpf_cmp(&self.mpf, &other.mpf) == 0 }
    }
}

impl Ord for Mpf {
    fn cmp(&self, other: &Mpf) -> Ordering {
        let cmp = unsafe { __gmpf_cmp(&self.mpf, &other.mpf) };
        if cmp == 0 {
            Equal
        } else if cmp > 0 {
            Greater
        } else {
            Less
        }
    }
}

impl PartialOrd for Mpf {
    fn partial_cmp(&self, other: &Mpf) -> Option<Ordering> {
        Some(self.cmp(other))
    }
}

macro_rules! div_guard {
    (Div, $is_zero: expr) => {
        if $is_zero {
            panic!("divide by zero")
        }
    };
    ($tr: ident, $what: expr) => {}
}

macro_rules! impl_oper {
    ($tr: ident, $meth: ident, $tr_assign: ident, $meth_assign: ident, $fun: ident) => {
        impl<'a> $tr<Mpf> for &'a Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(self, other: Mpf) -> Mpf {
                self.$meth(&other)
            }
        }

        impl<'a> $tr<&'a Mpf> for Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(mut self, other: &Mpf) -> Mpf {
                self.$meth_assign(other);
                self
            }
        }

        impl $tr<Mpf> for Mpf {
            type Output = Mpf;
            #[inline]
            fn $meth(self, other: Mpf) -> Mpf {
                self.$meth(&other)
            }
        }

        impl<'a, 'b> $tr<&'a Mpf> for &'b Mpf {
            type Output = Mpf;
            fn $meth(self, other: &Mpf) -> Mpf {
                unsafe {
                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
                    let mut res = Mpf::new(cmp::max(self.get_prec(), other.get_prec()));
                    $fun(&mut res.mpf, &self.mpf, &other.mpf);
                    res
                }
            }
        }

        impl<'a> $tr_assign<Mpf> for Mpf {
            #[inline]
            fn $meth_assign(&mut self, other: Mpf) {
                self.$meth_assign(&other)
            }
        }

        impl<'a> $tr_assign<&'a Mpf> for Mpf {
            #[inline]
            fn $meth_assign(&mut self, other: &Mpf) {
                unsafe {
                    div_guard!($tr, __gmpf_cmp_ui(&other.mpf, 0) == 0);
                    $fun(&mut self.mpf, &self.mpf, &other.mpf)
                }
            }
        }
    }
}

impl_oper!(Add, add, AddAssign, add_assign, __gmpf_add);
impl_oper!(Sub, sub, SubAssign, sub_assign, __gmpf_sub);
impl_oper!(Mul, mul, MulAssign, mul_assign, __gmpf_mul);
impl_oper!(Div, div, DivAssign, div_assign, __gmpf_div);

impl<'b> Neg for &'b Mpf {
    type Output = Mpf;
    fn neg(self) -> Mpf {
        unsafe {
            let mut res = Mpf::new(self.get_prec());
            __gmpf_neg(&mut res.mpf, &self.mpf);
            res
        }
    }
}

impl Neg for Mpf {
    type Output = Mpf;
    #[inline]
    fn neg(mut self) -> Mpf {
        unsafe {
            __gmpf_neg(&mut self.mpf, &self.mpf);
            self
        }
    }
}

impl Zero for Mpf {
    #[inline]
    fn zero() -> Mpf {
        Mpf::zero()
    }

    #[inline]
    fn is_zero(&self) -> bool {
        unsafe {
            __gmpf_cmp_ui(&self.mpf, 0) == 0
        }
    }
}

impl One for Mpf {
    #[inline]
    fn one() -> Mpf {
        let mut res = Mpf::new(32);
        res.set_from_si(1);
        res
    }
}
<|endoftext|>


<commit_before>extern crate ocf;

use std::borrow::Cow;
use std::ffi::CString;
use nix;
use super::*;

impl From<ocf::linux::NamespaceKind> for NamespaceKind {
    fn from(kind: ocf::linux::NamespaceKind) -> Self {
        match kind {
            ocf::linux::NamespaceKind::PID => NamespaceKind::PID,
            ocf::linux::NamespaceKind::Network => NamespaceKind::Network,
            ocf::linux::NamespaceKind::Mount => NamespaceKind::Mount,
            ocf::linux::NamespaceKind::IPC => NamespaceKind::IPC,
            ocf::linux::NamespaceKind::UTS => NamespaceKind::UTS,
            ocf::linux::NamespaceKind::User => NamespaceKind::User,
        }
    }
}

quick_error! {
    #[derive(Clone, Debug)]
    pub enum OcfError {
        UnsupportedPlatform {
            description("unsupported platform")
        }
        UnsupportedArchitecture {
            description("unsupported architecture")
        }
        InvalidConfiguration(err: &'static str) {
            description("invalid configuration")
            display("{}", err)
        }
        MissingMount(mount: String) {
            description("runtime configuration missing mountpoint")
            display("missing mountpoint: {}", mount)
        }
        CStringError {
            description("internal nul error")
            from(::std::ffi::NulError)
        }
    }
}

pub fn ocf_config<'s, 'r>(config: &'s ocf::Spec, runtime: &'r ocf::RuntimeSpec) -> Result<(Box<Config>, Command<'static>), OcfError> {
    use std::path::Path;
    use std::ffi::NulError;
    use std::iter;

    let (arch, caps, linux) = if let (&ocf::Platform::Linux { ref arch, ref capabilities }, Some(linux)) = (config.platform(), runtime.linux()) {
        (arch, capabilities, linux)
    } else {
        return Err(OcfError::UnsupportedPlatform)
    };

    #[cfg(target_arch = "x86")]
    const ARCH: [ocf::Arch; 1] = [ocf::Arch::X86];
    #[cfg(target_arch = "x86_64")]
    const ARCH: [ocf::Arch; 2] = [ocf::Arch::X86, ocf::Arch::X86_64];

    if !ARCH.contains(arch) {
        return Err(OcfError::UnsupportedArchitecture)
    }

    if config.hostname().is_some() && !linux.namespaces().iter().any(|ns| ns.path.is_none() && ns.kind == ocf::linux::NamespaceKind::UTS) {
        return Err(OcfError::InvalidConfiguration("hostname requires new uts namespace"))
    }

    if !linux.namespaces().iter().any(|ns| ns.kind == ocf::linux::NamespaceKind::Mount) {
        return Err(OcfError::InvalidConfiguration("mount namespace required"))
    }

    let mounts: Result<Vec<_>, _> = config.mounts().iter().map(|mount|
        runtime.mounts().get(&mount.name).map(|rm| (mount, rm)).ok_or(&mount.name)
    ).collect();

    let mounts = try!(mounts.map_err(|mount|
        OcfError::MissingMount(mount.to_owned())
    ));

    fn opres<T, E>(str: Option<Result<T, E>>) -> Result<Option<T>, E> {
        match str {
            Some(Ok(t)) => Ok(Some(t)),
            Some(Err(e)) => Err(e),
            None => Ok(None),
        }
    }

    let namespaces = try!(linux.namespaces().iter().map(|ns| -> Result<_, NulError> {
        Ok(Namespace::new(ns.kind.into(), try!(opres(ns.path().map(CString::new)))))
    }).collect::<Result<Vec<_>, _>>());

    let root = try!(CString::new(config.root().path()));
    let root_readonly = if config.root().readonly() { nix::mount::MS_RDONLY } else { nix::mount::MsFlags::empty() };
    let root_propagation = match linux.rootfs_propagation() {
        ocf::linux::MountPropagation::Private => nix::mount::MS_PRIVATE,
        ocf::linux::MountPropagation::Shared => nix::mount::MS_SHARED,
        ocf::linux::MountPropagation::Slave => nix::mount::MS_SLAVE,
    };
    let mounts = try!(
        iter::once(Ok(Mount::from_bind(root.clone(), root, nix::mount::MS_BIND | root_propagation | root_readonly)))
        .chain(mounts.into_iter().map(|(m, mount)| -> Result<_, OcfError> {
            let path = Path::new(m.path().trim_left_matches('/'));
            if path.has_root() {
                return Err(OcfError::InvalidConfiguration("mount path issue"))
            }

            let path = Path::new(config.root().path()).join(path).to_string_lossy().into_owned();
            let path = try!(CString::new(path));

            let (mut flags, opts) = mount.options().iter().map(|opt| (Some(match &opt[..] {
                "bind" => nix::mount::MS_BIND,
                "move" => nix::mount::MS_MOVE,

                "private" => nix::mount::MS_PRIVATE,
                "slave" => nix::mount::MS_SLAVE,
                "shared" => nix::mount::MS_SHARED,

                "acl" => nix::mount::MS_POSIXACL,
                "noatime" => nix::mount::MS_NOATIME,
                "nodev" => nix::mount::MS_NODEV,
                "nodiratime" => nix::mount::MS_NODIRATIME,
                "dirsync" => nix::mount::MS_DIRSYNC,
                "noexec" => nix::mount::MS_NOEXEC,
                "mand" => nix::mount::MS_MANDLOCK,
                "relatime" => nix::mount::MS_RELATIME,
                "strictatime" => nix::mount::MS_STRICTATIME,
                "lazytime" => nix::mount::MS_LAZYTIME,
                "nosuid" => nix::mount::MS_NOSUID,
                "silent" => nix::mount::MS_SILENT,
                "remount" => nix::mount::MS_REMOUNT,
                "ro" => nix::mount::MS_RDONLY,
                "sync" => nix::mount::MS_SYNCHRONOUS,
                "nouser" => nix::mount::MS_NOUSER,
                "x-mount-mkdir" => unimplemented!(),
                _ => return (None, Some(opt)),
            }), None)).fold((nix::mount::MsFlags::empty(), String::new()), |(flags, mut opts), (flag, opt)| (
                if let Some(flag) = flag { flags | flag } else { flags },
                {
                    if let Some(opt) = opt {
                        if !opts.is_empty() {
                            opts.push(',');
                        }
                        opts.push_str(opt);
                    }
                    opts
                },
            ));

            let kind = match mount.kind() {
                "" => None,
                "bind" => {
                    flags = flags | nix::mount::MS_BIND;
                    None
                },
                kind => Some(try!(CString::new(kind))),
            };

            Ok(Mount::new(
                path,
                Some(try!(CString::new(mount.source()))),
                kind,
                flags,
                if opts.is_empty() { None } else { Some(try!(CString::new(opts))) }
            ))
        }))
        .collect::<Result<Vec<_>, _>>()
    );

    let devices = try!(linux.devices().iter().map(|device| -> Result<_, OcfError> {
        let mode = try!(nix::sys::stat::Mode::from_bits(device.mode())
            .ok_or(OcfError::InvalidConfiguration("invalid device mode")));

        let kind = match device.kind() {
            b'b' => nix::sys::stat::S_IFBLK,
            b'c' | b'u' => nix::sys::stat::S_IFCHR,
            b'p' => nix::sys::stat::S_IFIFO,
            _ => return Err(OcfError::InvalidConfiguration("invalid device type"))
        };

        Ok(Device::new(
            try!(CString::new(device.path())),
            kind,
            mode,
            (device.major(), device.minor())
        ))
    }).collect::<Result<Vec<_>, _>>());

    let hostname = config.hostname().map(ToOwned::to_owned).map(Hostname::new);

    if let Some(cwd) = config.process().cwd() {
        use std::path::Path;

        if !Path::new(cwd).is_absolute() {
            return Err(OcfError::InvalidConfiguration("process cwd must be an absolute path"))
        }
    }

    let root = Root::new(
        try!(CString::new(config.root().path())),
        try!(
            config.process().cwd().map(|cwd| CString::new(cwd).map(Cow::Owned))
            .unwrap_or(Ok(Cow::Borrowed(cstr!("/"))))
        )
    );

    let user = config.process().linux_user().map(|user| User::new(user.uid(), user.gid(), user.additional_gids().to_owned()));

    let capabilities = Capabilities::new(caps.iter().fold(
        nix::sys::capability::CapabilityFlags::empty(),
        |flags, cap| flags | nix::sys::capability::CapabilityFlags::from_bits_truncate(1 << cap.cap_flag())
    ));

    let command = {
        let cmd = try!(CString::new(config.process().cmd()));
        let args = try!(iter::once(Ok(cmd.clone())).chain(config.process().args().iter().map(|s| CString::new(&s[..]))).collect::<Result<Vec<_>, _>>());
        let env = try!(config.process().env().iter().map(ToString::to_string).map(CString::new).collect::<Result<Vec<_>, _>>());
        Command::new(cmd, nix::null_terminated::NullTerminatedVec::map_from(args), nix::null_terminated::NullTerminatedVec::map_from(env))
    };

    Ok((Box::new(
        Configs::new(namespaces)
        .chain(Configs::new(mounts))
        .chain(root)
        .chain(Configs::new(devices))
        .chain(hostname)
        .chain(user)
        .chain(capabilities)
    ),
    command))
}
<commit_msg>x-mount.mkdir typo<commit_after>extern crate ocf;

use std::borrow::Cow;
use std::ffi::CString;
use nix;
use super::*;

impl From<ocf::linux::NamespaceKind> for NamespaceKind {
    fn from(kind: ocf::linux::NamespaceKind) -> Self {
        match kind {
            ocf::linux::NamespaceKind::PID => NamespaceKind::PID,
            ocf::linux::NamespaceKind::Network => NamespaceKind::Network,
            ocf::linux::NamespaceKind::Mount => NamespaceKind::Mount,
            ocf::linux::NamespaceKind::IPC => NamespaceKind::IPC,
            ocf::linux::NamespaceKind::UTS => NamespaceKind::UTS,
            ocf::linux::NamespaceKind::User => NamespaceKind::User,
        }
    }
}

quick_error! {
    #[derive(Clone, Debug)]
    pub enum OcfError {
        UnsupportedPlatform {
            description("unsupported platform")
        }
        UnsupportedArchitecture {
            description("unsupported architecture")
        }
        InvalidConfiguration(err: &'static str) {
            description("invalid configuration")
            display("{}", err)
        }
        MissingMount(mount: String) {
            description("runtime configuration missing mountpoint")
            display("missing mountpoint: {}", mount)
        }
        CStringError {
            description("internal nul error")
            from(::std::ffi::NulError)
        }
    }
}

pub fn ocf_config<'s, 'r>(config: &'s ocf::Spec, runtime: &'r ocf::RuntimeSpec) -> Result<(Box<Config>, Command<'static>), OcfError> {
    use std::path::Path;
    use std::ffi::NulError;
    use std::iter;

    let (arch, caps, linux) = if let (&ocf::Platform::Linux { ref arch, ref capabilities }, Some(linux)) = (config.platform(), runtime.linux()) {
        (arch, capabilities, linux)
    } else {
        return Err(OcfError::UnsupportedPlatform)
    };

    #[cfg(target_arch = "x86")]
    const ARCH: [ocf::Arch; 1] = [ocf::Arch::X86];
    #[cfg(target_arch = "x86_64")]
    const ARCH: [ocf::Arch; 2] = [ocf::Arch::X86, ocf::Arch::X86_64];

    if !ARCH.contains(arch) {
        return Err(OcfError::UnsupportedArchitecture)
    }

    if config.hostname().is_some() && !linux.namespaces().iter().any(|ns| ns.path.is_none() && ns.kind == ocf::linux::NamespaceKind::UTS) {
        return Err(OcfError::InvalidConfiguration("hostname requires new uts namespace"))
    }

    if !linux.namespaces().iter().any(|ns| ns.kind == ocf::linux::NamespaceKind::Mount) {
        return Err(OcfError::InvalidConfiguration("mount namespace required"))
    }

    let mounts: Result<Vec<_>, _> = config.mounts().iter().map(|mount|
        runtime.mounts().get(&mount.name).map(|rm| (mount, rm)).ok_or(&mount.name)
    ).collect();

    let mounts = try!(mounts.map_err(|mount|
        OcfError::MissingMount(mount.to_owned())
    ));

    fn opres<T, E>(str: Option<Result<T, E>>) -> Result<Option<T>, E> {
        match str {
            Some(Ok(t)) => Ok(Some(t)),
            Some(Err(e)) => Err(e),
            None => Ok(None),
        }
    }

    let namespaces = try!(linux.namespaces().iter().map(|ns| -> Result<_, NulError> {
        Ok(Namespace::new(ns.kind.into(), try!(opres(ns.path().map(CString::new)))))
    }).collect::<Result<Vec<_>, _>>());

    let root = try!(CString::new(config.root().path()));
    let root_readonly = if config.root().readonly() { nix::mount::MS_RDONLY } else { nix::mount::MsFlags::empty() };
    let root_propagation = match linux.rootfs_propagation() {
        ocf::linux::MountPropagation::Private => nix::mount::MS_PRIVATE,
        ocf::linux::MountPropagation::Shared => nix::mount::MS_SHARED,
        ocf::linux::MountPropagation::Slave => nix::mount::MS_SLAVE,
    };
    let mounts = try!(
        iter::once(Ok(Mount::from_bind(root.clone(), root, nix::mount::MS_BIND | root_propagation | root_readonly)))
        .chain(mounts.into_iter().map(|(m, mount)| -> Result<_, OcfError> {
            let path = Path::new(m.path().trim_left_matches('/'));
            if path.has_root() {
                return Err(OcfError::InvalidConfiguration("mount path issue"))
            }

            let path = Path::new(config.root().path()).join(path).to_string_lossy().into_owned();
            let path = try!(CString::new(path));

            let (mut flags, opts) = mount.options().iter().map(|opt| (Some(match &opt[..] {
                "bind" => nix::mount::MS_BIND,
                "move" => nix::mount::MS_MOVE,

                "private" => nix::mount::MS_PRIVATE,
                "slave" => nix::mount::MS_SLAVE,
                "shared" => nix::mount::MS_SHARED,

                "acl" => nix::mount::MS_POSIXACL,
                "noatime" => nix::mount::MS_NOATIME,
                "nodev" => nix::mount::MS_NODEV,
                "nodiratime" => nix::mount::MS_NODIRATIME,
                "dirsync" => nix::mount::MS_DIRSYNC,
                "noexec" => nix::mount::MS_NOEXEC,
                "mand" => nix::mount::MS_MANDLOCK,
                "relatime" => nix::mount::MS_RELATIME,
                "strictatime" => nix::mount::MS_STRICTATIME,
                "lazytime" => nix::mount::MS_LAZYTIME,
                "nosuid" => nix::mount::MS_NOSUID,
                "silent" => nix::mount::MS_SILENT,
                "remount" => nix::mount::MS_REMOUNT,
                "ro" => nix::mount::MS_RDONLY,
                "sync" => nix::mount::MS_SYNCHRONOUS,
                "nouser" => nix::mount::MS_NOUSER,
                "x-mount.mkdir" => unimplemented!(), // TODO: x-mount.mkdir=[mode]
                _ => return (None, Some(opt)),
            }), None)).fold((nix::mount::MsFlags::empty(), String::new()), |(flags, mut opts), (flag, opt)| (
                if let Some(flag) = flag { flags | flag } else { flags },
                {
                    if let Some(opt) = opt {
                        if !opts.is_empty() {
                            opts.push(',');
                        }
                        opts.push_str(opt);
                    }
                    opts
                },
            ));

            let kind = match mount.kind() {
                "" => None,
                "bind" => {
                    flags = flags | nix::mount::MS_BIND;
                    None
                },
                kind => Some(try!(CString::new(kind))),
            };

            Ok(Mount::new(
                path,
                Some(try!(CString::new(mount.source()))),
                kind,
                flags,
                if opts.is_empty() { None } else { Some(try!(CString::new(opts))) }
            ))
        }))
        .collect::<Result<Vec<_>, _>>()
    );

    let devices = try!(linux.devices().iter().map(|device| -> Result<_, OcfError> {
        let mode = try!(nix::sys::stat::Mode::from_bits(device.mode())
            .ok_or(OcfError::InvalidConfiguration("invalid device mode")));

        let kind = match device.kind() {
            b'b' => nix::sys::stat::S_IFBLK,
            b'c' | b'u' => nix::sys::stat::S_IFCHR,
            b'p' => nix::sys::stat::S_IFIFO,
            _ => return Err(OcfError::InvalidConfiguration("invalid device type"))
        };

        Ok(Device::new(
            try!(CString::new(device.path())),
            kind,
            mode,
            (device.major(), device.minor())
        ))
    }).collect::<Result<Vec<_>, _>>());

    let hostname = config.hostname().map(ToOwned::to_owned).map(Hostname::new);

    if let Some(cwd) = config.process().cwd() {
        use std::path::Path;

        if !Path::new(cwd).is_absolute() {
            return Err(OcfError::InvalidConfiguration("process cwd must be an absolute path"))
        }
    }

    let root = Root::new(
        try!(CString::new(config.root().path())),
        try!(
            config.process().cwd().map(|cwd| CString::new(cwd).map(Cow::Owned))
            .unwrap_or(Ok(Cow::Borrowed(cstr!("/"))))
        )
    );

    let user = config.process().linux_user().map(|user| User::new(user.uid(), user.gid(), user.additional_gids().to_owned()));

    let capabilities = Capabilities::new(caps.iter().fold(
        nix::sys::capability::CapabilityFlags::empty(),
        |flags, cap| flags | nix::sys::capability::CapabilityFlags::from_bits_truncate(1 << cap.cap_flag())
    ));

    let command = {
        let cmd = try!(CString::new(config.process().cmd()));
        let args = try!(iter::once(Ok(cmd.clone())).chain(config.process().args().iter().map(|s| CString::new(&s[..]))).collect::<Result<Vec<_>, _>>());
        let env = try!(config.process().env().iter().map(ToString::to_string).map(CString::new).collect::<Result<Vec<_>, _>>());
        Command::new(cmd, nix::null_terminated::NullTerminatedVec::map_from(args), nix::null_terminated::NullTerminatedVec::map_from(env))
    };

    Ok((Box::new(
        Configs::new(namespaces)
        .chain(Configs::new(mounts))
        .chain(root)
        .chain(Configs::new(devices))
        .chain(hostname)
        .chain(user)
        .chain(capabilities)
    ),
    command))
}
<|endoftext|>


<commit_before>// Copyright (c) 2018 The predicates-rs Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types.

use std::fmt;

use crate::reflection;
use crate::utils;
use crate::Predicate;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum EqOps {
    Equal,
    NotEqual,
}

impl fmt::Display for EqOps {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match *self {
            EqOps::Equal => "==",
            EqOps::NotEqual => "!=",
        };
        write!(f, "{}", op)
    }
}

/// Predicate that returns `true` if `variable` matches the pre-defined `Eq`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{eq, ne}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    constant: T,
    op: EqOps,
}

impl<T> Predicate<T> for EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            EqOps::Equal => variable.eq(&self.constant),
            EqOps::NotEqual => variable.ne(&self.constant),
        }
    }

    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<'a, T> Predicate<T> for EqPredicate<&'a T>
where
    T: fmt::Debug + PartialEq + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            EqOps::Equal => variable.eq(self.constant),
            EqOps::NotEqual => variable.ne(self.constant),
        }
    }

    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug + PartialEq {}

impl<T> fmt::Display for EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let palette = crate::Palette::current();
        write!(
            f,
            "{} {} {:?}",
            palette.var.paint("var"),
            palette.description.paint(self.op),
            self.constant
        )
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::eq(5);
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&10));
///
/// let predicate_fn = predicate::eq("Hello");
/// assert_eq!(true, predicate_fn.eval("Hello"));
/// assert_eq!(false, predicate_fn.eval("Goodbye"));
/// ```
pub fn eq<T>(constant: T) -> EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    EqPredicate {
        constant,
        op: EqOps::Equal,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// _not_ equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::ne(5);
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&10));
/// ```
pub fn ne<T>(constant: T) -> EqPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    EqPredicate {
        constant,
        op: EqOps::NotEqual,
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum OrdOps {
    LessThan,
    LessThanOrEqual,
    GreaterThanOrEqual,
    GreaterThan,
}

impl fmt::Display for OrdOps {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match *self {
            OrdOps::LessThan => "<",
            OrdOps::LessThanOrEqual => "<=",
            OrdOps::GreaterThanOrEqual => ">=",
            OrdOps::GreaterThan => ">",
        };
        write!(f, "{}", op)
    }
}

/// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{gt, ge, lt, le}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    constant: T,
    op: OrdOps,
}

impl<T> Predicate<T> for OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            OrdOps::LessThan => variable.lt(&self.constant),
            OrdOps::LessThanOrEqual => variable.le(&self.constant),
            OrdOps::GreaterThanOrEqual => variable.ge(&self.constant),
            OrdOps::GreaterThan => variable.gt(&self.constant),
        }
    }

    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<'a, T> Predicate<T> for OrdPredicate<&'a T>
where
    T: fmt::Debug + PartialOrd + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            OrdOps::LessThan => variable.lt(self.constant),
            OrdOps::LessThanOrEqual => variable.le(self.constant),
            OrdOps::GreaterThanOrEqual => variable.ge(self.constant),
            OrdOps::GreaterThan => variable.gt(self.constant),
        }
    }

    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug + PartialOrd {}

impl<T> fmt::Display for OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let palette = crate::Palette::current();
        write!(
            f,
            "{} {} {:?}",
            palette.var.paint("var"),
            palette.description.paint(self.op),
            self.constant
        )
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// less than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::lt(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&6));
///
/// let predicate_fn = predicate::lt("b");
/// assert_eq!(true, predicate_fn.eval("a"));
/// assert_eq!(false, predicate_fn.eval("c"));
/// ```
pub fn lt<T>(constant: T) -> OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    OrdPredicate {
        constant,
        op: OrdOps::LessThan,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// less than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::le(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&6));
/// ```
pub fn le<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::LessThanOrEqual,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate = predicate::ge(5);
/// assert_eq!(false, predicate.eval(&4));
/// assert_eq!(true, predicate.eval(&5));
/// assert_eq!(true, predicate.eval(&6));
/// ```
pub fn ge<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::GreaterThanOrEqual,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::gt(5);
/// assert_eq!(false, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&6));
/// ```
pub fn gt<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::GreaterThan,
    }
}
<commit_msg>fix: Clarify var vs expected<commit_after>// Copyright (c) 2018 The predicates-rs Project Developers.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/license/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

//! Definition of `Predicate`s for comparisons over `Ord` and `Eq` types.

use std::fmt;

use crate::reflection;
use crate::utils;
use crate::Predicate;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum EqOps {
    Equal,
    NotEqual,
}

impl fmt::Display for EqOps {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match *self {
            EqOps::Equal => "==",
            EqOps::NotEqual => "!=",
        };
        write!(f, "{}", op)
    }
}

/// Predicate that returns `true` if `variable` matches the pre-defined `Eq`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{eq, ne}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    constant: T,
    op: EqOps,
}

impl<T> Predicate<T> for EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            EqOps::Equal => variable.eq(&self.constant),
            EqOps::NotEqual => variable.ne(&self.constant),
        }
    }

    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<'a, T> Predicate<T> for EqPredicate<&'a T>
where
    T: fmt::Debug + PartialEq + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            EqOps::Equal => variable.eq(self.constant),
            EqOps::NotEqual => variable.ne(self.constant),
        }
    }

    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<T> reflection::PredicateReflection for EqPredicate<T> where T: fmt::Debug + PartialEq {}

impl<T> fmt::Display for EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let palette = crate::Palette::current();
        write!(
            f,
            "{} {} {}",
            palette.var.paint("var"),
            palette.description.paint(self.op),
            palette
                .expected
                .paint(utils::DebugAdapter::new(&self.constant)),
        )
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::eq(5);
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&10));
///
/// let predicate_fn = predicate::eq("Hello");
/// assert_eq!(true, predicate_fn.eval("Hello"));
/// assert_eq!(false, predicate_fn.eval("Goodbye"));
/// ```
pub fn eq<T>(constant: T) -> EqPredicate<T>
where
    T: fmt::Debug + PartialEq,
{
    EqPredicate {
        constant,
        op: EqOps::Equal,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// _not_ equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::ne(5);
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&10));
/// ```
pub fn ne<T>(constant: T) -> EqPredicate<T>
where
    T: PartialEq + fmt::Debug,
{
    EqPredicate {
        constant,
        op: EqOps::NotEqual,
    }
}

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
enum OrdOps {
    LessThan,
    LessThanOrEqual,
    GreaterThanOrEqual,
    GreaterThan,
}

impl fmt::Display for OrdOps {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let op = match *self {
            OrdOps::LessThan => "<",
            OrdOps::LessThanOrEqual => "<=",
            OrdOps::GreaterThanOrEqual => ">=",
            OrdOps::GreaterThan => ">",
        };
        write!(f, "{}", op)
    }
}

/// Predicate that returns `true` if `variable` matches the pre-defined `Ord`
/// value, otherwise returns `false`.
///
/// This is created by the `predicate::{gt, ge, lt, le}` functions.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    constant: T,
    op: OrdOps,
}

impl<T> Predicate<T> for OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            OrdOps::LessThan => variable.lt(&self.constant),
            OrdOps::LessThanOrEqual => variable.le(&self.constant),
            OrdOps::GreaterThanOrEqual => variable.ge(&self.constant),
            OrdOps::GreaterThan => variable.gt(&self.constant),
        }
    }

    fn find_case<'a>(&'a self, expected: bool, variable: &T) -> Option<reflection::Case<'a>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<'a, T> Predicate<T> for OrdPredicate<&'a T>
where
    T: fmt::Debug + PartialOrd + ?Sized,
{
    fn eval(&self, variable: &T) -> bool {
        match self.op {
            OrdOps::LessThan => variable.lt(self.constant),
            OrdOps::LessThanOrEqual => variable.le(self.constant),
            OrdOps::GreaterThanOrEqual => variable.ge(self.constant),
            OrdOps::GreaterThan => variable.gt(self.constant),
        }
    }

    fn find_case<'b>(&'b self, expected: bool, variable: &T) -> Option<reflection::Case<'b>> {
        utils::default_find_case(self, expected, variable)
    }
}

impl<T> reflection::PredicateReflection for OrdPredicate<T> where T: fmt::Debug + PartialOrd {}

impl<T> fmt::Display for OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        let palette = crate::Palette::current();
        write!(
            f,
            "{} {} {}",
            palette.var.paint("var"),
            palette.description.paint(self.op),
            palette
                .expected
                .paint(utils::DebugAdapter::new(&self.constant)),
        )
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// less than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::lt(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&6));
///
/// let predicate_fn = predicate::lt("b");
/// assert_eq!(true, predicate_fn.eval("a"));
/// assert_eq!(false, predicate_fn.eval("c"));
/// ```
pub fn lt<T>(constant: T) -> OrdPredicate<T>
where
    T: fmt::Debug + PartialOrd,
{
    OrdPredicate {
        constant,
        op: OrdOps::LessThan,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// less than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::le(5);
/// assert_eq!(true, predicate_fn.eval(&4));
/// assert_eq!(true, predicate_fn.eval(&5));
/// assert_eq!(false, predicate_fn.eval(&6));
/// ```
pub fn le<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::LessThanOrEqual,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than or equal to a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate = predicate::ge(5);
/// assert_eq!(false, predicate.eval(&4));
/// assert_eq!(true, predicate.eval(&5));
/// assert_eq!(true, predicate.eval(&6));
/// ```
pub fn ge<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::GreaterThanOrEqual,
    }
}

/// Creates a new predicate that will return `true` when the given `variable` is
/// greater than a pre-defined value.
///
/// # Examples
///
/// ```
/// use predicates::prelude::*;
///
/// let predicate_fn = predicate::gt(5);
/// assert_eq!(false, predicate_fn.eval(&4));
/// assert_eq!(false, predicate_fn.eval(&5));
/// assert_eq!(true, predicate_fn.eval(&6));
/// ```
pub fn gt<T>(constant: T) -> OrdPredicate<T>
where
    T: PartialOrd + fmt::Debug,
{
    OrdPredicate {
        constant,
        op: OrdOps::GreaterThan,
    }
}
<|endoftext|>


<commit_before>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbtk;
extern crate userutils;

use std::{env, str};
use std::fs::File;
use std::io::Read;
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::sync::{Arc, Mutex};

use orbtk::{Button, Label, Placeable, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use userutils::Passwd;

pub fn main() {
    let mut args = env::args().skip(1);

    let launcher_cmd = args.next().expect("orblogin: no window manager command");
    let launcher_args: Vec<String> = args.collect();

    loop {
        let user_lock = Arc::new(Mutex::new(String::new()));
        let pass_lock = Arc::new(Mutex::new(String::new()));

        {
            let mut issue = String::new();
            if let Ok(mut issue_file) = File::open("/etc/issue") {
                let _ = issue_file.read_to_string(&mut issue);
            }

            let window_height = 80 + issue.lines().count() as u32 * 16;
            let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
            let mut window = Window::new(Rect::new((width as i32 - 576)/2, (height as i32 - window_height as i32)/2, 576, window_height), "Orbital Login");

            let mut y = 0;
            for line in issue.lines() {
                Label::new()
                    .text(line)
                    .position(0, y)
                    .size(576, 16)
                    .place(&window);
                y += 16;
            }

            Label::new()
                .text("Username")
                .position(0, y)
                .size(576, 16)
                .place(&window);
            y += 16;

            let user_text_box = TextBox::new()
                .position(0, y)
                .size(576, 16)
                .grab_focus(true)
                .on_enter(|_| {
                })
                .place(&window);
            y += 16;

            Label::new()
                .text("Password")
                .position(0, y)
                .size(576, 16)
                .place(&window);
            y += 16;

            let pass_text_box = TextBox::new()
                .position(0, y)
                .size(576, 16)
                .place(&window);
            y += 16;

            // Pressing enter in user text box will transfer focus to password text box
            {
                let pass_text_box = pass_text_box.clone();
                *user_text_box.on_enter.borrow_mut() = Some(Arc::new(move |_| {
                    pass_text_box.grab_focus.set(true);
                }));
            }

            // Pressing enter in password text box will try to login
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let user_text_box = user_text_box.clone();
                let window_login = &mut window as *mut Window;
                *pass_text_box.on_enter.borrow_mut() = Some(Arc::new(move |me: &TextBox| {
                    println!("Login {}", user_text_box.text.get());
                    *user_lock.lock().unwrap() = user_text_box.text.get();
                    *pass_lock.lock().unwrap() = me.text.get();
                    unsafe { (&mut *window_login).close(); }
                }));
            }

            // Add a login button
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let window_login = &mut window as *mut Window;
                Button::new()
                    .position(0, y)
                    .size(576, 16)
                    .text("Login")
                    .on_click(move |_button: &Button, _point: Point| {
                        println!("Login {}", user_text_box.text.get());
                        *user_lock.lock().unwrap() = user_text_box.text.get();
                        *pass_lock.lock().unwrap() = pass_text_box.text.get();
                        unsafe { (&mut *window_login).close(); }
                    })
                    .place(&window);
            }

            window.exec();
        }

        let user = user_lock.lock().unwrap().clone();
        let pass = pass_lock.lock().unwrap().clone();
        if ! user.is_empty() {
            let mut passwd_string = String::new();
            File::open("/etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap();

            let mut passwd_option = None;
            for line in passwd_string.lines() {
                if let Ok(passwd) = Passwd::parse(line) {
                    if user == passwd.user && "" == passwd.hash {
                        passwd_option = Some(passwd);
                        break;
                    }
                }
            }

            if passwd_option.is_none() {
                for line in passwd_string.lines() {
                    if let Ok(passwd) = Passwd::parse(line) {
                        if user == passwd.user && passwd.verify(&pass) {
                            passwd_option = Some(passwd);
                            break;
                        }
                    }
                }
            }

            if let Some(passwd) = passwd_option {
                let mut command = Command::new(&launcher_cmd);
                for arg in launcher_args.iter() {
                    command.arg(&arg);
                }

                command.uid(passwd.uid);
                command.gid(passwd.gid);

                command.current_dir(passwd.home);

                command.env("USER", &user);
                command.env("HOME", passwd.home);

                match command.spawn() {
                    Ok(mut child) => match child.wait() {
                        Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()),
                        Err(err) => panic!("orblogin: failed to wait for '{}': {}", passwd.shell, err)
                    },
                    Err(err) => panic!("orblogin: failed to execute '{}': {}", passwd.shell, err)
                }
            }
        }
    }
}
<commit_msg>Use mask char<commit_after>#![deny(warnings)]
#![feature(const_fn)]

extern crate orbclient;
extern crate orbtk;
extern crate userutils;

use std::{env, str};
use std::fs::File;
use std::io::Read;
use std::os::unix::process::CommandExt;
use std::process::Command;
use std::sync::{Arc, Mutex};

use orbtk::{Button, Label, Placeable, Point, Rect, TextBox, Window};
use orbtk::callback::{Click, Enter};
use userutils::Passwd;

pub fn main() {
    let mut args = env::args().skip(1);

    let launcher_cmd = args.next().expect("orblogin: no window manager command");
    let launcher_args: Vec<String> = args.collect();

    loop {
        let user_lock = Arc::new(Mutex::new(String::new()));
        let pass_lock = Arc::new(Mutex::new(String::new()));

        {
            let mut issue = String::new();
            if let Ok(mut issue_file) = File::open("/etc/issue") {
                let _ = issue_file.read_to_string(&mut issue);
            }

            let window_height = 80 + issue.lines().count() as u32 * 16;
            let (width, height) = orbclient::get_display_size().expect("launcher: failed to get display size");
            let mut window = Window::new(Rect::new((width as i32 - 576)/2, (height as i32 - window_height as i32)/2, 576, window_height), "Orbital Login");

            let mut y = 0;
            for line in issue.lines() {
                Label::new()
                    .text(line)
                    .position(0, y)
                    .size(576, 16)
                    .place(&window);
                y += 16;
            }

            Label::new()
                .text("Username")
                .position(0, y)
                .size(576, 16)
                .place(&window);
            y += 16;

            let user_text_box = TextBox::new()
                .position(0, y)
                .size(576, 16)
                .grab_focus(true)
                .on_enter(|_| {
                })
                .place(&window);
            y += 16;

            Label::new()
                .text("Password")
                .position(0, y)
                .size(576, 16)
                .place(&window);
            y += 16;

            let pass_text_box = TextBox::new()
                .position(0, y)
                .size(576, 16)
                .mask_char(Some('*'))
                .place(&window);
            y += 16;

            // Pressing enter in user text box will transfer focus to password text box
            {
                let pass_text_box = pass_text_box.clone();
                *user_text_box.on_enter.borrow_mut() = Some(Arc::new(move |_| {
                    pass_text_box.grab_focus.set(true);
                }));
            }

            // Pressing enter in password text box will try to login
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let user_text_box = user_text_box.clone();
                let window_login = &mut window as *mut Window;
                *pass_text_box.on_enter.borrow_mut() = Some(Arc::new(move |me: &TextBox| {
                    println!("Login {}", user_text_box.text.get());
                    *user_lock.lock().unwrap() = user_text_box.text.get();
                    *pass_lock.lock().unwrap() = me.text.get();
                    unsafe { (&mut *window_login).close(); }
                }));
            }

            // Add a login button
            {
                let user_lock = user_lock.clone();
                let pass_lock = pass_lock.clone();
                let window_login = &mut window as *mut Window;
                Button::new()
                    .position(0, y)
                    .size(576, 16)
                    .text("Login")
                    .on_click(move |_button: &Button, _point: Point| {
                        println!("Login {}", user_text_box.text.get());
                        *user_lock.lock().unwrap() = user_text_box.text.get();
                        *pass_lock.lock().unwrap() = pass_text_box.text.get();
                        unsafe { (&mut *window_login).close(); }
                    })
                    .place(&window);
            }

            window.exec();
        }

        let user = user_lock.lock().unwrap().clone();
        let pass = pass_lock.lock().unwrap().clone();
        if ! user.is_empty() {
            let mut passwd_string = String::new();
            File::open("/etc/passwd").unwrap().read_to_string(&mut passwd_string).unwrap();

            let mut passwd_option = None;
            for line in passwd_string.lines() {
                if let Ok(passwd) = Passwd::parse(line) {
                    if user == passwd.user && "" == passwd.hash {
                        passwd_option = Some(passwd);
                        break;
                    }
                }
            }

            if passwd_option.is_none() {
                for line in passwd_string.lines() {
                    if let Ok(passwd) = Passwd::parse(line) {
                        if user == passwd.user && passwd.verify(&pass) {
                            passwd_option = Some(passwd);
                            break;
                        }
                    }
                }
            }

            if let Some(passwd) = passwd_option {
                let mut command = Command::new(&launcher_cmd);
                for arg in launcher_args.iter() {
                    command.arg(&arg);
                }

                command.uid(passwd.uid);
                command.gid(passwd.gid);

                command.current_dir(passwd.home);

                command.env("USER", &user);
                command.env("HOME", passwd.home);

                match command.spawn() {
                    Ok(mut child) => match child.wait() {
                        Ok(_status) => (), //println!("login: waited for {}: {:?}", sh, status.code()),
                        Err(err) => panic!("orblogin: failed to wait for '{}': {}", passwd.shell, err)
                    },
                    Err(err) => panic!("orblogin: failed to execute '{}': {}", passwd.shell, err)
                }
            }
        }
    }
}
<|endoftext|>


<commit_before>// See LICENSE file for copyright and license details.

use std::mem;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, AttrId};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad, Deg, ToRad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::ffi;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Zgl {
    pub gl: Gl, // TODO: make private
}

impl Zgl {
    pub fn new<F>(get_proc_address: F) -> Zgl
        where F: Fn(&str) -> *const c_void
    {
        let gl = Gl::load_with(|s| get_proc_address(s));
        Zgl{gl: gl}
    }

    pub fn init_opengl(&self) {
        unsafe {
            self.gl.Enable(gl::DEPTH_TEST);
        }
        self.check();
        // verify!(gl::Enable(gl::BLEND));
        // verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: &Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        unsafe {
            let version = self.gl.GetString(name) as *const i8;
            String::from_utf8_lossy(ffi::c_str_to_bytes(&version)).into_owned()
        }
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::<ZFloat>::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8; 4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr,
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }

    pub fn draw_arrays(&self, mode: &MeshRenderMode, length: ZInt) {
        let starting_index = 0;
        unsafe {
            self.gl.DrawArrays(mode.to_gl_type(), starting_index, length);
        }
        self.check();
    }

    pub fn enable_vertex_attrib_array(&self, attr_id: &AttrId) {
        unsafe {
            self.gl.EnableVertexAttribArray(attr_id.id);
        }
        self.check();
    }
}

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<commit_msg>src/zgl.rs: Removed unneeded '::<ZFloat>'<commit_after>// See LICENSE file for copyright and license details.

use std::mem;
use core_types::{Size2, ZInt};
use visualizer_types::{Color3, ZFloat, ScreenPos, AttrId};
use cgmath::{Matrix, Matrix4, Matrix3, ToMatrix4, Vector3, rad, Deg, ToRad};
use libc::c_void;
use gl;
use gl::Gl;
use gl::types::{GLuint, GLsizeiptr};
use std::ffi;

/*
pub const GREY_3: Color3 = Color3{r: 0.3, g: 0.3, b: 0.3};
pub const BLACK_3: Color3 = Color3{r: 0.0, g: 0.0, b: 0.0};
pub const WHITE: Color4 = Color4{r: 1.0, g: 1.0, b: 1.0, a: 1.0};
pub const BLUE: Color4 = Color4{r: 0.0, g: 0.0, b: 1.0, a: 1.0};
pub const BLACK: Color4 = Color4{r: 0.0, g: 0.0, b: 0.0, a: 1.0};
*/

pub enum MeshRenderMode {
    Triangles,
    // Lines,
}

impl MeshRenderMode {
    pub fn to_gl_type(&self) -> GLuint {
        match *self {
            MeshRenderMode::Triangles => gl::TRIANGLES,
            // MeshRenderMode::Lines => gl::LINES,
        }
    }
}

pub struct Zgl {
    pub gl: Gl, // TODO: make private
}

impl Zgl {
    pub fn new<F>(get_proc_address: F) -> Zgl
        where F: Fn(&str) -> *const c_void
    {
        let gl = Gl::load_with(|s| get_proc_address(s));
        Zgl{gl: gl}
    }

    pub fn init_opengl(&self) {
        unsafe {
            self.gl.Enable(gl::DEPTH_TEST);
        }
        self.check();
        // verify!(gl::Enable(gl::BLEND));
        // verify!(gl::BlendFunc(gl::SRC_ALPHA, gl::ONE_MINUS_SRC_ALPHA));
    }

    pub fn print_gl_info(&self) {
        println!("GL_VERSION: {}", self.get_info(gl::VERSION));
        println!("GL_SHADING_LANGUAGE_VERSION: {}", self.get_info(gl::SHADING_LANGUAGE_VERSION));
        println!("GL_VENDOR: {}", self.get_info(gl::VENDOR));
        println!("GL_RENDERER: {}", self.get_info(gl::RENDERER));
        // println!("GL_EXTENSIONS: {}", self.get_info(gl::EXTENSIONS));
    }

    pub fn set_clear_color(&mut self, color: &Color3) {
        unsafe {
            self.gl.ClearColor(color.r, color.g, color.b, 1.0);
        }
        self.check();
    }

    pub fn clear_screen(&self) {
        unsafe {
            self.gl.Clear(gl::COLOR_BUFFER_BIT | gl::DEPTH_BUFFER_BIT);
        }
        self.check();
    }

    pub fn get_info(&self, name: GLuint) -> String {
        unsafe {
            let version = self.gl.GetString(name) as *const i8;
            String::from_utf8_lossy(ffi::c_str_to_bytes(&version)).into_owned()
        }
    }

    pub fn set_viewport(&mut self, size: &Size2<ZInt>) {
        unsafe {
            self.gl.Viewport(0, 0, size.w, size.h);
        }
        self.check();
    }

    // TODO: replace with something from cgmath-rs
    // from cgmath-rs`s docs:
    // "Transformations are not usually done directly on matrices, but go
    // through transformation objects that can be converted to matrices.
    // Rotations go through the Basis types, which are guaranteed to be
    // orthogonal matrices."
    pub fn tr(&self, m: Matrix4<ZFloat>, v: Vector3<ZFloat>) -> Matrix4<ZFloat> {
        let mut t = Matrix4::identity();
        t[3][0] = v.x;
        t[3][1] = v.y;
        t[3][2] = v.z;
        m.mul_m(&t)
    }

    /*
    pub fn scale(&self, m: Matrix4<ZFloat>, scale: ZFloat) -> Matrix4<ZFloat> {
        let mut t = Matrix4::identity();
        t[0][0] = scale;
        t[1][1] = scale;
        t[2][2] = scale;
        m.mul_m(&t)
    }
    */

    pub fn rot_x(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_x(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn rot_z(&self, m: Matrix4<ZFloat>, angle: Deg<ZFloat>) -> Matrix4<ZFloat> {
        let rad = angle.to_rad();
        let r = Matrix3::from_angle_z(rad).to_matrix4();
        m.mul_m(&r)
    }

    pub fn check(&self) {
        let error_code = unsafe { self.gl.GetError() };
        if error_code != 0 {
            let description = match error_code {
                gl::INVALID_ENUM => "GL_INVALID_ENUM",
                gl::INVALID_FRAMEBUFFER_OPERATION => "GL_INVALID_FRAMEBUFFER_OPERATION",
                gl::INVALID_OPERATION => "GL_INVALID_OPERATION",
                gl::INVALID_VALUE => "GL_INVALID_VALUE",
                gl::NO_ERROR => "GL_NO_ERROR",
                gl::OUT_OF_MEMORY => "GL_OUT_OF_MEMORY",
                _ => panic!("Bad gl error code: {}", error_code),
            };
            panic!("gl error: {}({})", description, error_code);
        }
    }

    pub fn read_pixel_bytes(
        &self,
        win_size: &Size2<ZInt>,
        mouse_pos: &ScreenPos,
    ) -> (ZInt, ZInt, ZInt, ZInt) {
        let height = win_size.h;
        let reverted_h = height - mouse_pos.v.y;
        let data: [u8; 4] = [0, 0, 0, 0];
        unsafe {
            let data_ptr = mem::transmute(&data[0]);
            self.gl.ReadPixels(
                mouse_pos.v.x, reverted_h, 1, 1,
                gl::RGBA,
                gl::UNSIGNED_BYTE,
                data_ptr,
            );
        }
        self.check();
        (data[0] as ZInt, data[1] as ZInt, data[2] as ZInt, data[3] as ZInt)
    }

    pub fn draw_arrays(&self, mode: &MeshRenderMode, length: ZInt) {
        let starting_index = 0;
        unsafe {
            self.gl.DrawArrays(mode.to_gl_type(), starting_index, length);
        }
        self.check();
    }

    pub fn enable_vertex_attrib_array(&self, attr_id: &AttrId) {
        unsafe {
            self.gl.EnableVertexAttribArray(attr_id.id);
        }
        self.check();
    }
}

pub struct Vbo {
    id: GLuint,
}

impl Vbo {
    pub fn from_data<T>(zgl: &Zgl, data: &[T]) -> Vbo {
        let vbo = Vbo{id: Vbo::get_new_vbo_id(zgl)};
        vbo.bind(zgl);
        let size = mem::size_of::<T>();
        let buf_size = (data.len() * size) as GLsizeiptr;
        if data.len() != 0 {
            unsafe {
                let data_ptr = mem::transmute(&data[0]);
                zgl.gl.BufferData(
                    gl::ARRAY_BUFFER,
                    buf_size,
                    data_ptr,
                    gl::STATIC_DRAW,
                );
                zgl.check();
            }
        }
        vbo
    }

    fn get_new_vbo_id(zgl: &Zgl) -> GLuint {
        let mut id = 0;
        unsafe {
            zgl.gl.GenBuffers(1, &mut id);
            zgl.check();
        }
        id
    }

    pub fn bind(&self, zgl: &Zgl) {
        unsafe {
            zgl.gl.BindBuffer(gl::ARRAY_BUFFER, self.id);
        }
        zgl.check();
    }
}

/*
// TODO: how to pass Zgl to d-tor?
impl Drop for Vbo {
    fn drop(&mut self) {
        unsafe {
            verify!(gl::DeleteBuffers(1, &self.id));
        }
    }
}
*/

/*
pub fn get_2d_screen_matrix(&self, win_size: &Size2<ZInt>) -> Matrix4<ZFloat> {
    let left = 0.0;
    let right = win_size.w as ZFloat;
    let bottom = 0.0;
    let top = win_size.h as ZFloat;
    let near = -1.0;
    let far = 1.0;
    ortho(left, right, bottom, top, near, far)
}
*/

// vim: set tabstop=4 shiftwidth=4 softtabstop=4 expandtab:
<|endoftext|>


<commit_before>use List::{Cons, Nil};
use std::ops::Deref;

fn main() {
    let boxed = Box::new(5);
    println!("boxed = {}", boxed);

    let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));

    let song = Mp3 {
        audio: vec![1, 2, 3, 4, 5],
        artist: Some(String::from("Travis Scott")),
        title: Some(String::from("RaRa"))
    };

    assert_eq!(*song, vec![1, 2, 3, 4, 5]);
}

enum List {
    Cons(i32, Box<List>),
    Nil
}

struct Mp3 {
    audio: Vec<u8>,
    artist: Option<String>,
    title: Option<String>
}

impl Deref for Mp3 {
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8> {
        &self.audio
    }
}
<commit_msg>Example of using Drop trait<commit_after>use List::{Cons, Nil};
use std::ops::Deref;

fn main() {
    let boxed = Box::new(5);
    println!("boxed = {}", boxed);

    let list = Cons(1, Box::new(Cons(2, Box::new(Nil))));

    let song = Mp3 {
        audio: vec![1, 2, 3, 4, 5],
        artist: Some(String::from("Travis Scott")),
        title: Some(String::from("RaRa"))
    };

    assert_eq!(*song, vec![1, 2, 3, 4, 5]);

    let smart = CustomSmartPointer {
        data: String::from("Data of smart pointer!")
    };
}

enum List {
    Cons(i32, Box<List>),
    Nil
}

struct Mp3 {
    audio: Vec<u8>,
    artist: Option<String>,
    title: Option<String>
}

impl Deref for Mp3 {
    type Target = Vec<u8>;

    fn deref(&self) -> &Vec<u8> {
        &self.audio
    }
}

struct CustomSmartPointer {
    data: String,
}

impl Drop for CustomSmartPointer {
    fn drop(&mut self) {
        println!("Dropping smart pointer with data: {}", &self.data);
    }
}
<|endoftext|>


<commit_before>#![allow(unused)]
#[macro_use(s)]
extern crate ndarray;
extern crate num_traits;

use num_traits::Float;

use ndarray::{
    ArrayView,
    ArrayViewMut,
    OwnedArray,
    Ix,
};

type Ix2 = (Ix, Ix);

fn main() {
    let n = 16;
    let mut a = OwnedArray::zeros((n, n));

    for ((i, j), elt) in a.indexed_iter_mut() {

        *elt = (i as f32).powi(2) + (j as f32).powi(2);

    }
    println!("{:3}", a);

}
<commit_msg>ndarray `OwnedArray` is deprecated since 0.6.0<commit_after>#![allow(unused)]
#[macro_use(s)]
extern crate ndarray;
extern crate num_traits;

use num_traits::Float;

use ndarray::{
    ArrayView,
    ArrayViewMut,
    Array,
    Ix,
};

type Ix2 = (Ix, Ix);

fn main() {
    let n = 16;
    let mut a = Array::zeros((n, n));

    for ((i, j), elt) in a.indexed_iter_mut() {

        *elt = (i as f32).powi(2) + (j as f32).powi(2);

    }
    println!("{:3}", a);

}
<|endoftext|>


<commit_before>// This module implements configuration related stuff.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use serialize::json::JsonObject;

pub trait ConfigTrait {
    fn from_jsonfile(&mut self, filepath: Path) -> Path {
        filepath
    }
}

/// Currently we are using `JsonObject` as config type.  Works like
/// a JSON Object but provides ways to fill it from JSON files:
///
/// ```rust
/// app.config.from_jsonfile("yourconfig.json")
/// ```
///
/// You can also load configurations from an environment variable
/// pointing to a file:
///
/// ```rust
/// app.config.from_envvar("YOURAPPLICATION_SETTINGS")
/// ```
///
/// In this case, you have to set this environment variable to the file
/// you want to use.  On Linux and OS X you can use the export statement:
///
/// ```bash
/// export YOURAPPLICATION_SETTINGS="/path/to/config/file"
/// ```
///
pub type Config = JsonObject;

impl ConfigTrait for Config {
}
<commit_msg>Fixed docs<commit_after>// This module implements configuration related stuff.
// Copyright (c) 2014 by Shipeng Feng.
// Licensed under the BSD License, see LICENSE for more details.

use serialize::json::JsonObject;

pub trait ConfigTrait {
    fn from_jsonfile(&mut self, filepath: Path) -> Path {
        filepath
    }
}

/// Currently we are using `JsonObject` as config type.  Works like
/// a JSON Object but provides ways to fill it from JSON files:
///
/// ```rust,no_run
/// app.config.from_jsonfile("yourconfig.json")
/// ```
///
/// You can also load configurations from an environment variable
/// pointing to a file:
///
/// ```rust,no_run
/// app.config.from_envvar("YOURAPPLICATION_SETTINGS")
/// ```
///
/// In this case, you have to set this environment variable to the file
/// you want to use.  On Linux and OS X you can use the export statement:
///
/// ```bash
/// export YOURAPPLICATION_SETTINGS="/path/to/config/file"
/// ```
///
pub type Config = JsonObject;

impl ConfigTrait for Config {
}
<|endoftext|>


<commit_before>extern crate libc;
extern crate contain;

use libc::{c_void, c_int};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, SIGCHLD};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::io::{Read, Write};
use std::thread;
use contain::Stack;

// a lot copied from man USER_NAMESPACES(7)

extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let h = thread::spawn(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            assert_eq!(libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1), 0);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        let container_root = Path::new("./mntcont");
        if container_root.exists() {
            assert!(container_root.is_dir());
        } else {
            println!("creating {:?} at {}", container_root.file_name().expect("root name"), container_root.to_string_lossy());
            fs::create_dir(container_root).expect("mkdir mntcont");
        }

        panic!("Oops!");
    });

    match h.join() {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

struct ChildArgs {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
}

fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
    //file gets dropped
}
fn main() {
    println!("Hello, world!");

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1]});
        Box::into_raw(child_args) as *mut c_void
    };

    let child_stack = Stack::new(512);

    println!("cloning");
    let child_pid = unsafe {
        libc::clone(child_func, child_stack.top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //child_stack gets unmapped
}
<commit_msg>mounting the container fs<commit_after>extern crate libc;
extern crate contain;

use libc::{c_void, c_int, c_ulong, c_char};
use std::ptr;
use libc::{MS_REC, MS_PRIVATE, MS_NOSUID, MS_NODEV, MS_NOEXEC};
use libc::{CLONE_NEWUSER, CLONE_NEWNS, CLONE_NEWPID, SIGCHLD};
use std::fs;
use std::fs::{File, OpenOptions};
use std::path::Path;
use std::io::{Read, Write};
use std::thread;
use std::ffi::{CString, CStr};
use std::os::unix::ffi::OsStrExt;
use contain::Stack;

//path to cstr
fn p2cstr<P: AsRef<Path>>(po: Option<P>) -> Option<CString> {
    po.map( |p|
        //http://stackoverflow.com/questions/38948669/whats-the-most-direct-way-to-convert-a-path-to-a-c-char
        // TODO possible without copying?
        CString::new(p.as_ref().as_os_str().as_bytes()).expect("string contains NULLs")
    )
}

// CString Option to pointer
fn cstr2p(o: Option<CString>) -> *const c_char {
    o.map_or(ptr::null(), |x| x.as_ptr())
}

fn domount<P: AsRef<Path>>(source: Option<P>, target: Option<P>, filesystemtype: Option<&str>, mountflags: c_ulong) -> () {
    let source = p2cstr(source.as_ref());
    let target = p2cstr(target.as_ref());
    let fstype = match filesystemtype {
            None => ptr::null(),
            Some(fst) => CString::new(fst).expect("fstypes has NULLs").as_ptr(),
        };
    let r = unsafe { libc::mount(cstr2p(source), cstr2p(target), fstype, mountflags, ptr::null()) };
    assert_eq!(r, 0);
}

// a lot copied from man USER_NAMESPACES(7)
extern "C" fn child_func(args: *mut c_void) -> c_int {
    println!("I'm called from child_func");

    let args = args as *mut ChildArgs;
    let r_pipe_fd = unsafe { (*args).r_pipe_fd };
    let w_pipe_fd = unsafe { (*args).w_pipe_fd };
    println!("r_pipe_fd: {}", r_pipe_fd);

    // run everything in a new thread so exceptions bubble up to rust
    let h = thread::spawn(move || {
        // wait for parent
        println!("waiting for parent to set up mapping, ...");
        assert_eq!(unsafe { libc::close(w_pipe_fd) } , 0);
        unsafe {
            let mut buf = 0u8;
            assert_eq!(libc::read(r_pipe_fd, (&mut buf) as *mut u8 as *mut c_void, 1), 0);
        }

        {
            println!("Child status");
            let mut fstatus = File::open("/proc/self/status").expect("open status");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                if l.starts_with("Seccomp") || l.starts_with("Cap"){
                    println!("{}", l);
                }
            }
        }

        let container_root = Path::new("./mntcont");
        if container_root.exists() {
            assert!(container_root.is_dir());
        } else {
            println!("creating {:?}", container_root.as_os_str());
            fs::create_dir(container_root).expect("mkdir mntcont");
        }

        domount(None, Some(container_root), Some("tmpfs"), 0);
        domount(Some("none"), Some("/"), None, MS_REC|MS_PRIVATE);
        let proc_dir = container_root.join("proc");
        println!("setting up {:?}", proc_dir.as_os_str());
        fs::create_dir(proc_dir.as_path()).expect("mkdir proc");
        domount(None, Some(proc_dir.as_path()), Some("proc"), MS_NOSUID|MS_NODEV|MS_NOEXEC);

        // TODO populate root?

        //TODO pivot root

        {
            println!("mountinfo");
            let mut fstatus = File::open("/proc/self/mountinfo").expect("open mountinfo");
            let mut contents = String::new();
            fstatus.read_to_string(&mut contents).expect("read status");
            for l in contents.lines(){
                println!("{}", l);
            }
        }
        panic!("Oops!");
    });

    match h.join() {
        Ok(_) => 0,
        Err(_) => 1,
    }
}

struct ChildArgs {
    r_pipe_fd: c_int,
    w_pipe_fd: c_int,
}

fn write(path: &String, content: &[u8]) {
    println!("Writing to {}", path);
    let mut file = OpenOptions::new().read(false).write(true).create(false).open(path).expect("open");
    // needs to happen in one write call
    assert_eq!(file.write(content).expect("write"), content.len());
    //file gets dropped
}
fn main() {
    println!("Hello, world!");

    let mut pipe_fd = vec![0;2];  /* Pipe used to synchronize parent and child */
    assert_eq!(unsafe { libc::pipe(pipe_fd.as_mut_ptr()) }, 0);
    println!("r pipe: {} w pipe: {}", pipe_fd[0], pipe_fd[1]);
    let ptr_child_args = {
        let child_args = Box::new(ChildArgs { r_pipe_fd: pipe_fd[0], w_pipe_fd: pipe_fd[1]});
        Box::into_raw(child_args) as *mut c_void
    };

    let child_stack = Stack::new(512);

    println!("cloning");
    let child_pid = unsafe {
        libc::clone(child_func, child_stack.top, CLONE_NEWUSER|CLONE_NEWNS|CLONE_NEWPID|SIGCHLD, ptr_child_args)
    };
    assert!(child_pid != -1);

    let uid = unsafe { libc::getuid() };
    write(&format!("/proc/{}/uid_map", child_pid), &format!("0 {} 1", uid).into_bytes());

    //proc_setgroups_write man user_namespaces
    write(&format!("/proc/{}/setgroups", child_pid), &format!("deny").into_bytes());

    let gid = unsafe { libc::getgid() };
    write(&format!("/proc/{}/gid_map", child_pid), &format!("0 {} 1", gid).into_bytes());

    //unleash child
    assert_eq!(unsafe { libc::close(pipe_fd[1]) }, 0);

    let mut child_status: c_int = 0;
    assert!(unsafe { libc::waitpid(child_pid, &mut child_status, 0) } != -1);
    println!("Child terminated: {}", child_status);

    unsafe {
        drop(Box::from_raw(ptr_child_args));
    }

    //child_stack gets unmapped
}
<|endoftext|>