<commit_before>use std::marker::MarkerTrait;
use std::mem;

use runtime::{Class, Method, Object, Sel, Super, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message : MarkerTrait { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to an `id` pointer that may be sent Objective-C
/// messages.
pub trait ToMessage {
    /// Returns self as an `id` pointer, a pointer to an `Object`.
    fn as_id_ptr(&self) -> *mut Object;

    /// Returns true if self is nil.
    fn is_nil(&self) -> bool {
        self.as_id_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<T> ToMessage for *mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *const T as *mut Object
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut T as *mut Object
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: &T, superclass: &Class, sel: Sel) -> R
            where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_id_ptr();
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }

            unsafe fn send_super<T, R>(self, obj: &T, superclass: &Class, sel: Sel) -> R
                    where T: ToMessage {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj.as_id_ptr(), superclass: superclass };
                let ($($a,)*) = self;
                msg_send_fn(&sup, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

#[allow(dead_code)]
fn verify_message_signature<A, R>(obj: Option<&Object>, sel: Sel, _args: &A) ->
        Result<(), String> where A: MessageArguments, R: Encode {
    let obj = match obj {
        Some(obj) => obj,
        None => return Err(format!("Messaging {:?} to nil", sel)),
    };
    let cls = obj.class();
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

#[cfg(any(ndebug, not(feature = "verify_message_encode")))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

/**
Sends a message to an object with selector `sel` and arguments `args`.
This function will choose the correct version of `objc_msgSend` based on the
return type. For more information, see Apple's documenation:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778

When the verify_message_encode feature is defined, at runtime in debug
builds this function will verify that the encoding of the return type
matches the encoding of the method.

# Example
``` no_run
# #[macro_use] extern crate objc;
# use objc::send_message;
# use objc::runtime::Object;
# fn main() {
# unsafe {
let dict: *mut Object;
let key: *const Object;
# let dict: *mut Object = 0 as *mut Object;
# let key: *const Object = 0 as *const Object;
let obj: *const Object = send_message(&dict, sel!(objectForKey:), (key,));
let _: () = send_message(&dict, sel!(setObject:forKey:), (obj, key));
# }
# }
```
*/
#[cfg(all(not(ndebug), feature = "verify_message_encode"))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments, R: Encode {
    let obj_ref = obj.as_id_ptr().as_ref();
    match verify_message_signature::<_, R>(obj_ref, sel, &args) {
        Err(s) => panic!("Verify message failed: {}", s),
        Ok(_) => args.send(obj, sel),
    }
}

/// Sends a message to the superclass of an instance of a class.
pub unsafe fn send_super_message<T, A, R>(
        obj: &T, superclass: &Class, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send_super(obj, superclass, sel)
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;
    use super::send_message;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            send_message(&obj, sel!(self), ())
        };
        assert!(&*obj as *const Object == result);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            send_message(&obj, sel!(customStruct), ())
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }
}
<commit_msg>Tweaked verify_message_signature to accept a class.<commit_after>use std::marker::MarkerTrait;
use std::mem;

use runtime::{Class, Method, Object, Sel, Super, self};
use {encode, Encode};

/*
 The Sized bound on Message is unfortunate; ideally, objc objects would not be
 treated as Sized. However, rust won't allow casting a dynamically-sized type
 pointer to an Object pointer, because dynamically-sized types can have fat
 pointers (two words) instead of real pointers.
 */
/// Types that may be sent Objective-C messages.
/// For example: objects, classes, and blocks.
pub unsafe trait Message : MarkerTrait { }

unsafe impl Message for Object { }

unsafe impl Message for Class { }

/// A trait for converting to an `id` pointer that may be sent Objective-C
/// messages.
pub trait ToMessage {
    /// Returns self as an `id` pointer, a pointer to an `Object`.
    fn as_id_ptr(&self) -> *mut Object;

    /// Returns true if self is nil.
    fn is_nil(&self) -> bool {
        self.as_id_ptr().is_null()
    }
}

impl<T> ToMessage for *const T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<T> ToMessage for *mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut Object
    }
}

impl<'a, T> ToMessage for &'a T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *const T as *mut Object
    }
}

impl<'a, T> ToMessage for &'a mut T where T: Message {
    fn as_id_ptr(&self) -> *mut Object {
        *self as *mut T as *mut Object
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_fn<R>() -> unsafe extern fn(*mut Object, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSend) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSend_stret) }
    }
}

#[cfg(target_arch = "x86_64")]
fn msg_send_super_fn<R>() -> unsafe extern fn(*const Super, Sel, ...) -> R {
    if mem::size_of::<R>() <= 16 {
        unsafe { mem::transmute(runtime::objc_msgSendSuper) }
    } else {
        unsafe { mem::transmute(runtime::objc_msgSendSuper_stret) }
    }
}

/// Types that may be used as the arguments of an Objective-C message.
pub trait MessageArguments {
    /// Sends a message to the given obj with the given selector and self as
    /// the arguments.
    ///
    /// It is recommended to use the `msg_send!` macro rather than calling this
    /// method directly.
    unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage;

    /// Sends a message to the superclass of an instance of a class with self
    /// as the arguments.
    unsafe fn send_super<T, R>(self, obj: &T, superclass: &Class, sel: Sel) -> R
            where T: ToMessage;
}

macro_rules! message_args_impl {
    ($($a:ident : $t:ident),*) => (
        impl<$($t),*> MessageArguments for ($($t,)*) {
            unsafe fn send<T, R>(self, obj: &T, sel: Sel) -> R where T: ToMessage {
                let msg_send_fn = msg_send_fn::<R>();
                let msg_send_fn: unsafe extern fn(*mut Object, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let obj_ptr = obj.as_id_ptr();
                let ($($a,)*) = self;
                msg_send_fn(obj_ptr, sel $(, $a)*)
            }

            unsafe fn send_super<T, R>(self, obj: &T, superclass: &Class, sel: Sel) -> R
                    where T: ToMessage {
                let msg_send_fn = msg_send_super_fn::<R>();
                let msg_send_fn: unsafe extern fn(*const Super, Sel $(, $t)*) -> R =
                    mem::transmute(msg_send_fn);
                let sup = Super { receiver: obj.as_id_ptr(), superclass: superclass };
                let ($($a,)*) = self;
                msg_send_fn(&sup, sel $(, $a)*)
            }
        }
    );
}

message_args_impl!();
message_args_impl!(a: A);
message_args_impl!(a: A, b: B);
message_args_impl!(a: A, b: B, c: C);
message_args_impl!(a: A, b: B, c: C, d: D);
message_args_impl!(a: A, b: B, c: C, d: D, e: E);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K);
message_args_impl!(a: A, b: B, c: C, d: D, e: E, f: F, g: G, h: H, i: I, j: J, k: K, l: L);

#[allow(dead_code)]
fn verify_message_arguments(types: &[&str], method: &Method) -> Result<(), String> {
    let count = 2 + types.len();
    let expected_count = method.arguments_count();
    if count != expected_count {
        return Err(format!("Method {:?} accepts {} arguments, but {} were given",
            method.name(), expected_count, count));
    }

    let expected_types = (2..expected_count).map(|i| method.argument_type(i));
    for (&arg, expected) in types.iter().zip(expected_types) {
        let expected = match expected {
            Some(s) => s,
            None => return Err(format!("Method {:?} doesn't expect argument with type code {}",
                method.name(), arg)),
        };
        if arg != &*expected {
            return Err(format!("Method {:?} expected argument with type code {} but was given {}",
                method.name(), &*expected, arg));
        }
    }

    Ok(())
}

#[allow(dead_code)]
fn verify_message_signature<A, R>(cls: &Class, sel: Sel) -> Result<(), String>
        where A: MessageArguments, R: Encode {
    let method = match cls.instance_method(sel) {
        Some(method) => method,
        None => return Err(format!("Method {:?} not found on class {:?}",
            sel, cls)),
    };

    let ret = encode::<R>();
    let expected_ret = method.return_type();
    // Allow encoding "oneway void" (Vv) as "void" (v)
    if &*expected_ret != ret && !(&*expected_ret == "Vv" && ret == "v") {
        return Err(format!("Return type code {} does not match expected {} for method {:?} on class {:?}",
            ret, &*expected_ret, sel, cls));
    }

    // I don't think either of these can happen, but just to be safe...
    let accepts_self_arg = match method.argument_type(0) {
        Some(s) => &*s == "@",
        None => false,
    };
    if !accepts_self_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for self",
            sel, cls));
    }
    let accepts_cmd_arg = match method.argument_type(1) {
        Some(s) => &*s == ":",
        None => false,
    };
    if !accepts_cmd_arg {
        return Err(format!("Method {:?} of class {:?} doesn't accept an argument for the selector",
            sel, cls));
    }

    Ok(())
}

#[cfg(any(ndebug, not(feature = "verify_message_encode")))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send(obj, sel)
}

/**
Sends a message to an object with selector `sel` and arguments `args`.
This function will choose the correct version of `objc_msgSend` based on the
return type. For more information, see Apple's documenation:
https://developer.apple.com/library/mac/documentation/Cocoa/Reference/ObjCRuntimeRef/index.html#//apple_ref/doc/uid/TP40001418-CH1g-88778

When the verify_message_encode feature is defined, at runtime in debug
builds this function will verify that the encoding of the return type
matches the encoding of the method.

# Example
``` no_run
# #[macro_use] extern crate objc;
# use objc::send_message;
# use objc::runtime::Object;
# fn main() {
# unsafe {
let dict: *mut Object;
let key: *const Object;
# let dict: *mut Object = 0 as *mut Object;
# let key: *const Object = 0 as *const Object;
let obj: *const Object = send_message(&dict, sel!(objectForKey:), (key,));
let _: () = send_message(&dict, sel!(setObject:forKey:), (obj, key));
# }
# }
```
*/
#[cfg(all(not(ndebug), feature = "verify_message_encode"))]
pub unsafe fn send_message<T, A, R>(obj: &T, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments, R: Encode {
    let cls = match obj.as_id_ptr().as_ref() {
        Some(obj) => obj.class(),
        None => panic!("Messaging {:?} to nil", sel),
    };
    match verify_message_signature::<A, R>(cls, sel) {
        Err(s) => panic!("Verify message failed: {}", s),
        Ok(_) => args.send(obj, sel),
    }
}

/// Sends a message to the superclass of an instance of a class.
pub unsafe fn send_super_message<T, A, R>(
        obj: &T, superclass: &Class, sel: Sel, args: A) -> R
        where T: ToMessage, A: MessageArguments {
    args.send_super(obj, superclass, sel)
}

#[cfg(test)]
mod tests {
    use runtime::Object;
    use test_utils;
    use super::send_message;

    #[test]
    fn test_send_message() {
        let obj = test_utils::sample_object();
        let result: *const Object = unsafe {
            send_message(&obj, sel!(self), ())
        };
        assert!(&*obj as *const Object == result);
    }

    #[test]
    fn test_send_message_stret() {
        let obj = test_utils::custom_object();
        let result: test_utils::CustomStruct = unsafe {
            send_message(&obj, sel!(customStruct), ())
        };
        let expected = test_utils::CustomStruct { a: 1, b:2, c: 3, d: 4 };
        assert!(result == expected);
    }
}
<|endoftext|>


<commit_before>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::processor::*;
use sys::process::*;
use sys::Disk;
use sys::disk;
use ::{DiskExt, ProcessExt, SystemExt};
use std::fs::{File, read_link};
use std::io::{self, Read};
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{pid_t, uid_t, sysconf, _SC_CLK_TCK, _SC_PAGESIZE};
use utils::realpath;

/// Structs containing system's information.
pub struct System {
    process_list: Process,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
}

impl System {
    fn clear_procs(&mut self) {
        if !self.processors.is_empty() {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (if old > new { 1 } else { new - old }) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in &mut self.process_list.tasks {
                if !has_been_updated(proc_) {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.tasks.remove(&pid);
            }
        }
    }

    /// **WARNING**: This method is specific to Linux.
    ///
    /// Refresh *only* the process corresponding to `pid`.
    pub fn refresh_process(&mut self, pid: pid_t) -> bool {
        if let Some(proc_) = self.process_list.tasks.get_mut(&pid) {
            _get_process_data(Path::new(&format!("/proc/{}", pid)), proc_, self.page_size_kb, pid);
            true
        } else {
            false
        }
    }
}

impl SystemExt for System {
    fn new() -> System {
        let mut s = System {
            process_list: Process::new(0, None, 0),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: component::get_components(),
            disks: get_all_disks(),
        };
        s.refresh_all();
        s
    }

    fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();

        for component in &mut self.temperatures {
            component.update();
        }
        for line in &lines {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.is_empty();
        for line in &lines {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| !s.is_empty());
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(&mut self.processors[i],
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    fn refresh_processes(&mut self) {
        if refresh_procs(&mut self.process_list, "/proc", self.page_size_kb, 0) {
            self.clear_procs();
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = get_all_disks();
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    fn get_process_list(&self) -> &HashMap<pid_t, Process> {
        &self.process_list.tasks
    }

    fn get_process(&self, pid: pid_t) -> Option<&Process> {
        self.process_list.tasks.get(&pid)
    }

    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.tasks.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }
}

impl Default for System {
    fn default() -> System {
        System::new()
    }
}

pub fn get_all_data(file_path: &str) -> io::Result<String> {
    let mut file = File::open(file_path)?;
    let mut data = String::new();

    file.read_to_string(&mut data).unwrap();
    Ok(data)
}

fn refresh_procs<P: AsRef<Path>>(proc_list: &mut Process, path: P, page_size_kb: u64,
                                 pid: pid_t) -> bool {
    if let Ok(d) = fs::read_dir(&Path::new(path.as_ref())) {
        for entry in d {
            if !entry.is_ok() {
                continue;
            }
            let entry = entry.unwrap();
            let entry = entry.path();

            if entry.is_dir() {
                _get_process_data(entry.as_path(), proc_list, page_size_kb, pid);
            }
        }
        true
    } else {
        false
    }
}

fn update_time_and_memory(path: &Path, entry: &mut Process, parts: &[&str], page_size_kb: u64,
                          parent_memory: u64, pid: pid_t) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss
    {
        entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb;
        if entry.memory >= parent_memory {
            entry.memory -= parent_memory;
        }
        set_time(entry,
                 u64::from_str(parts[13]).unwrap(),
                 u64::from_str(parts[14]).unwrap());
    }
    refresh_procs(entry, path.join(Path::new("task")).as_path(), page_size_kb, pid);
}

fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64, pid: pid_t) {
    if !path.exists() || !path.is_dir() {
        return
    }
    let last = path.to_str().unwrap().split('/').last();
    if last.is_none() {
        return
    }
    if let Ok(nb) = pid_t::from_str(last.unwrap()) {
        if nb == pid {
            return
        }
        let mut tmp = PathBuf::from(path);

        tmp.push("stat");
        let data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // The stat file is "interesting" to parse, because spaces cannot
        // be used as delimiters. The second field stores the command name
        // sourrounded by parentheses. Unfortunately, whitespace and
        // parentheses are legal parts of the command, so parsing has to
        // proceed like this: The first field is delimited by the first
        // whitespace, the second field is everything until the last ')'
        // in the entire string. All other fields are delimited by
        // whitespace.

        let mut parts = Vec::new();
        let mut data_it = data.splitn(2, ' ');
        parts.push(data_it.next().unwrap());
        // The following loses the ) from the input, but that's ok because
        // we're not using it anyway.
        let mut data_it = data_it.next().unwrap().rsplitn(2, ')');
        let data = data_it.next().unwrap();
        parts.push(data_it.next().unwrap());
        parts.extend(data.split_whitespace());
        let parent_memory = proc_list.memory;
        if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) {
            update_time_and_memory(path, entry, &parts, page_size_kb, parent_memory, nb);
            return;
        }

        let parent_pid = if proc_list.pid != 0 {
            Some(proc_list.pid)
        } else {
            match pid_t::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p),
            }
        };

        let mut p = Process::new(nb,
                                 parent_pid,
                                 u64::from_str(parts[21]).unwrap() /
                                 unsafe { sysconf(_SC_CLK_TCK) } as u64);

        p.status = parts[2].chars().next().and_then(|c| Some(ProcessStatus::from(c)));

        tmp = PathBuf::from(path);
        tmp.push("status");
        let status_data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // We're only interested in the lines starting with Uid: and Gid:
        // here. From these lines, we're looking at the second entry to get
        // the effective u/gid.

        let f = |h: &str, n: &str| -> Option<uid_t> {
            if h.starts_with(n) {
                h.split_whitespace().nth(2).unwrap().parse().ok()
            } else {
                None
            }
        };
        let mut set_uid = false;
        let mut set_gid = false;
        for line in status_data.lines() {
            if let Some(u) = f(line, "Uid:") {
                assert!(!set_uid);
                set_uid = true;
                p.uid = u;
            }
            if let Some(g) = f(line, "Gid:") {
                assert!(!set_gid);
                set_gid = true;
                p.gid = g;
            }
        }
        assert!(set_uid && set_gid);

        if proc_list.pid != 0 {
            p.cmd = proc_list.cmd.clone();
            p.name = proc_list.name.clone();
            p.environ = proc_list.environ.clone();
            p.exe = proc_list.exe.clone();
            p.cwd = proc_list.cwd.clone();
            p.root = proc_list.root.clone();
        } else {
            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = copy_from_file(&tmp);
            p.name = p.cmd[0].split('/').last().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
        }

        update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb);
        proc_list.tasks.insert(nb, p);
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            d.split('\0').map(|x| x.to_owned()).collect()
        },
        Err(_) => Vec::new()
    }
}

fn get_all_disks() -> Vec<Disk> {
    #[allow(or_fun_call)]
    let content = get_all_data("/proc/mounts").unwrap_or(String::new());
    let disks: Vec<_> = content.lines()
                               .filter(|line| line.trim_left()
                                                  .starts_with("/dev/sd"))
                               .collect();
    let mut ret = Vec::with_capacity(disks.len());

    if disks.len() == 1 {
        let info: Vec<_> = disks[0].split(' ').collect();
        if info.len() < 3 {
            return ret;
        }
        ret.push(disk::new_disk("sda", info[1], info[2]));
    } else {
        for line in disks {
            let info: Vec<_> = line.split(' ').collect();
            if info.len() < 3 {
                continue
            }
            ret.push(disk::new_disk(&info[0][5..], info[1], info[2]));
        }
    }
    ret
}
<commit_msg>Fix failure in case of read_to_string failure<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use sys::component::{self, Component};
use sys::processor::*;
use sys::process::*;
use sys::Disk;
use sys::disk;
use ::{DiskExt, ProcessExt, SystemExt};
use std::fs::{File, read_link};
use std::io::{self, Read};
use std::str::FromStr;
use std::path::{Path, PathBuf};
use std::collections::HashMap;
use std::fs;
use libc::{pid_t, uid_t, sysconf, _SC_CLK_TCK, _SC_PAGESIZE};
use utils::realpath;

/// Structs containing system's information.
pub struct System {
    process_list: Process,
    mem_total: u64,
    mem_free: u64,
    swap_total: u64,
    swap_free: u64,
    processors: Vec<Processor>,
    page_size_kb: u64,
    temperatures: Vec<Component>,
    disks: Vec<Disk>,
}

impl System {
    fn clear_procs(&mut self) {
        if !self.processors.is_empty() {
            let (new, old) = get_raw_times(&self.processors[0]);
            let total_time = (if old > new { 1 } else { new - old }) as f32;
            let mut to_delete = Vec::new();
            let nb_processors = self.processors.len() as u64 - 1;

            for (pid, proc_) in &mut self.process_list.tasks {
                if !has_been_updated(proc_) {
                    to_delete.push(*pid);
                } else {
                    compute_cpu_usage(proc_, nb_processors, total_time);
                }
            }
            for pid in to_delete {
                self.process_list.tasks.remove(&pid);
            }
        }
    }

    /// **WARNING**: This method is specific to Linux.
    ///
    /// Refresh *only* the process corresponding to `pid`.
    pub fn refresh_process(&mut self, pid: pid_t) -> bool {
        if let Some(proc_) = self.process_list.tasks.get_mut(&pid) {
            _get_process_data(Path::new(&format!("/proc/{}", pid)), proc_, self.page_size_kb, pid);
            true
        } else {
            false
        }
    }
}

impl SystemExt for System {
    fn new() -> System {
        let mut s = System {
            process_list: Process::new(0, None, 0),
            mem_total: 0,
            mem_free: 0,
            swap_total: 0,
            swap_free: 0,
            processors: Vec::new(),
            page_size_kb: unsafe { sysconf(_SC_PAGESIZE) as u64 / 1024 },
            temperatures: component::get_components(),
            disks: get_all_disks(),
        };
        s.refresh_all();
        s
    }

    fn refresh_system(&mut self) {
        let data = get_all_data("/proc/meminfo").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();

        for component in &mut self.temperatures {
            component.update();
        }
        for line in &lines {
            match *line {
                l if l.starts_with("MemTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("MemAvailable:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.mem_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapTotal:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_total = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                l if l.starts_with("SwapFree:") => {
                    let parts: Vec<&str> = line.split(' ').collect();

                    self.swap_free = u64::from_str(parts[parts.len() - 2]).unwrap();
                },
                _ => continue,
            }
        }
        let data = get_all_data("/proc/stat").unwrap();
        let lines: Vec<&str> = data.split('\n').collect();
        let mut i = 0;
        let first = self.processors.is_empty();
        for line in &lines {
            if !line.starts_with("cpu") {
                break;
            }

            let (parts, _): (Vec<&str>, Vec<&str>) = line.split(' ').partition(|s| !s.is_empty());
            if first {
                self.processors.push(new_processor(parts[0], u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap()));
            } else {
                set_processor(&mut self.processors[i],
                    u64::from_str(parts[1]).unwrap(),
                    u64::from_str(parts[2]).unwrap(),
                    u64::from_str(parts[3]).unwrap(),
                    u64::from_str(parts[4]).unwrap(),
                    u64::from_str(parts[5]).unwrap(),
                    u64::from_str(parts[6]).unwrap(),
                    u64::from_str(parts[7]).unwrap(),
                    u64::from_str(parts[8]).unwrap(),
                    u64::from_str(parts[9]).unwrap(),
                    u64::from_str(parts[10]).unwrap());
                i += 1;
            }
        }
    }

    fn refresh_processes(&mut self) {
        if refresh_procs(&mut self.process_list, "/proc", self.page_size_kb, 0) {
            self.clear_procs();
        }
    }

    fn refresh_disks(&mut self) {
        for disk in &mut self.disks {
            disk.update();
        }
    }

    fn refresh_disk_list(&mut self) {
        self.disks = get_all_disks();
    }

    // COMMON PART
    //
    // Need to be moved into a "common" file to avoid duplication.

    fn get_process_list(&self) -> &HashMap<pid_t, Process> {
        &self.process_list.tasks
    }

    fn get_process(&self, pid: pid_t) -> Option<&Process> {
        self.process_list.tasks.get(&pid)
    }

    fn get_process_by_name(&self, name: &str) -> Vec<&Process> {
        let mut ret = vec!();
        for val in self.process_list.tasks.values() {
            if val.name.starts_with(name) {
                ret.push(val);
            }
        }
        ret
    }

    fn get_processor_list(&self) -> &[Processor] {
        &self.processors[..]
    }

    fn get_total_memory(&self) -> u64 {
        self.mem_total
    }

    fn get_free_memory(&self) -> u64 {
        self.mem_free
    }

    fn get_used_memory(&self) -> u64 {
        self.mem_total - self.mem_free
    }

    fn get_total_swap(&self) -> u64 {
        self.swap_total
    }

    fn get_free_swap(&self) -> u64 {
        self.swap_free
    }

    // need to be checked
    fn get_used_swap(&self) -> u64 {
        self.swap_total - self.swap_free
    }

    fn get_components_list(&self) -> &[Component] {
        &self.temperatures[..]
    }

    fn get_disks(&self) -> &[Disk] {
        &self.disks[..]
    }
}

impl Default for System {
    fn default() -> System {
        System::new()
    }
}

pub fn get_all_data(file_path: &str) -> io::Result<String> {
    let mut file = File::open(file_path)?;
    let mut data = String::new();

    file.read_to_string(&mut data)?;
    Ok(data)
}

fn refresh_procs<P: AsRef<Path>>(proc_list: &mut Process, path: P, page_size_kb: u64,
                                 pid: pid_t) -> bool {
    if let Ok(d) = fs::read_dir(&Path::new(path.as_ref())) {
        for entry in d {
            if !entry.is_ok() {
                continue;
            }
            let entry = entry.unwrap();
            let entry = entry.path();

            if entry.is_dir() {
                _get_process_data(entry.as_path(), proc_list, page_size_kb, pid);
            }
        }
        true
    } else {
        false
    }
}

fn update_time_and_memory(path: &Path, entry: &mut Process, parts: &[&str], page_size_kb: u64,
                          parent_memory: u64, pid: pid_t) {
    //entry.name = parts[1][1..].to_owned();
    //entry.name.pop();
    // we get the rss
    {
        entry.memory = u64::from_str(parts[23]).unwrap() * page_size_kb;
        if entry.memory >= parent_memory {
            entry.memory -= parent_memory;
        }
        set_time(entry,
                 u64::from_str(parts[13]).unwrap(),
                 u64::from_str(parts[14]).unwrap());
    }
    refresh_procs(entry, path.join(Path::new("task")).as_path(), page_size_kb, pid);
}

fn _get_process_data(path: &Path, proc_list: &mut Process, page_size_kb: u64, pid: pid_t) {
    if !path.exists() || !path.is_dir() {
        return
    }
    let last = path.to_str().unwrap().split('/').last();
    if last.is_none() {
        return
    }
    if let Ok(nb) = pid_t::from_str(last.unwrap()) {
        if nb == pid {
            return
        }
        let mut tmp = PathBuf::from(path);

        tmp.push("stat");
        let data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // The stat file is "interesting" to parse, because spaces cannot
        // be used as delimiters. The second field stores the command name
        // sourrounded by parentheses. Unfortunately, whitespace and
        // parentheses are legal parts of the command, so parsing has to
        // proceed like this: The first field is delimited by the first
        // whitespace, the second field is everything until the last ')'
        // in the entire string. All other fields are delimited by
        // whitespace.

        let mut parts = Vec::new();
        let mut data_it = data.splitn(2, ' ');
        parts.push(data_it.next().unwrap());
        // The following loses the ) from the input, but that's ok because
        // we're not using it anyway.
        let mut data_it = data_it.next().unwrap().rsplitn(2, ')');
        let data = data_it.next().unwrap();
        parts.push(data_it.next().unwrap());
        parts.extend(data.split_whitespace());
        let parent_memory = proc_list.memory;
        if let Some(ref mut entry) = proc_list.tasks.get_mut(&nb) {
            update_time_and_memory(path, entry, &parts, page_size_kb, parent_memory, nb);
            return;
        }

        let parent_pid = if proc_list.pid != 0 {
            Some(proc_list.pid)
        } else {
            match pid_t::from_str(parts[3]).unwrap() {
                0 => None,
                p => Some(p),
            }
        };

        let mut p = Process::new(nb,
                                 parent_pid,
                                 u64::from_str(parts[21]).unwrap() /
                                 unsafe { sysconf(_SC_CLK_TCK) } as u64);

        p.status = parts[2].chars().next().and_then(|c| Some(ProcessStatus::from(c)));

        tmp = PathBuf::from(path);
        tmp.push("status");
        let status_data = get_all_data(tmp.to_str().unwrap()).unwrap();

        // We're only interested in the lines starting with Uid: and Gid:
        // here. From these lines, we're looking at the second entry to get
        // the effective u/gid.

        let f = |h: &str, n: &str| -> Option<uid_t> {
            if h.starts_with(n) {
                h.split_whitespace().nth(2).unwrap().parse().ok()
            } else {
                None
            }
        };
        let mut set_uid = false;
        let mut set_gid = false;
        for line in status_data.lines() {
            if let Some(u) = f(line, "Uid:") {
                assert!(!set_uid);
                set_uid = true;
                p.uid = u;
            }
            if let Some(g) = f(line, "Gid:") {
                assert!(!set_gid);
                set_gid = true;
                p.gid = g;
            }
        }
        assert!(set_uid && set_gid);

        if proc_list.pid != 0 {
            p.cmd = proc_list.cmd.clone();
            p.name = proc_list.name.clone();
            p.environ = proc_list.environ.clone();
            p.exe = proc_list.exe.clone();
            p.cwd = proc_list.cwd.clone();
            p.root = proc_list.root.clone();
        } else {
            tmp = PathBuf::from(path);
            tmp.push("cmdline");
            p.cmd = copy_from_file(&tmp);
            p.name = p.cmd[0].split('/').last().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("environ");
            p.environ = copy_from_file(&tmp);
            tmp = PathBuf::from(path);
            tmp.push("exe");

            let s = read_link(tmp.to_str().unwrap());

            if s.is_ok() {
                p.exe = s.unwrap().to_str().unwrap().to_owned();
            }
            tmp = PathBuf::from(path);
            tmp.push("cwd");
            p.cwd = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
            tmp = PathBuf::from(path);
            tmp.push("root");
            p.root = realpath(Path::new(tmp.to_str().unwrap())).to_str().unwrap().to_owned();
        }

        update_time_and_memory(path, &mut p, &parts, page_size_kb, proc_list.memory, nb);
        proc_list.tasks.insert(nb, p);
    }
}

#[allow(unused_must_use)]
fn copy_from_file(entry: &Path) -> Vec<String> {
    match File::open(entry.to_str().unwrap()) {
        Ok(mut f) => {
            let mut d = String::new();

            f.read_to_string(&mut d);
            d.split('\0').map(|x| x.to_owned()).collect()
        },
        Err(_) => Vec::new()
    }
}

fn get_all_disks() -> Vec<Disk> {
    #[allow(or_fun_call)]
    let content = get_all_data("/proc/mounts").unwrap_or(String::new());
    let disks: Vec<_> = content.lines()
                               .filter(|line| line.trim_left()
                                                  .starts_with("/dev/sd"))
                               .collect();
    let mut ret = Vec::with_capacity(disks.len());

    if disks.len() == 1 {
        let info: Vec<_> = disks[0].split(' ').collect();
        if info.len() < 3 {
            return ret;
        }
        ret.push(disk::new_disk("sda", info[1], info[2]));
    } else {
        for line in disks {
            let info: Vec<_> = line.split(' ').collect();
            if info.len() < 3 {
                continue
            }
            ret.push(disk::new_disk(&info[0][5..], info[1], info[2]));
        }
    }
    ret
}
<|endoftext|>


<commit_before>//! `coresimd`

#[macro_use]
mod macros;

#[macro_use]
mod ppsv;

/// Platform independent SIMD vector types and operations.
///
/// This is an **unstable** module for portable SIMD operations. This module
/// has not yet gone through an RFC and is likely to change, but feedback is
/// always welcome!
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod simd {
    pub use coresimd::ppsv::*;
}

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "wasm32")]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "powerpc64")]
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;
#[cfg(target_arch = "wasm32")]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

mod nvptx;
<commit_msg>Remove stray inconsistent #[cfg]<commit_after>//! `coresimd`

#[macro_use]
mod macros;

#[macro_use]
mod ppsv;

/// Platform independent SIMD vector types and operations.
///
/// This is an **unstable** module for portable SIMD operations. This module
/// has not yet gone through an RFC and is likely to change, but feedback is
/// always welcome!
#[unstable(feature = "stdsimd", issue = "27731")]
pub mod simd {
    pub use coresimd::ppsv::*;
}

/// Platform dependent vendor intrinsics.
///
/// This documentation is for the version of this module in the `coresimd`
/// crate, but you probably want to use the [`stdsimd` crate][stdsimd] which
/// should have more complete documentation.
///
/// [stdsimd]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
///
/// Also note that while this module may appear to contains the intrinsics for
/// only one platform it actually contains intrinsics for multiple platforms
/// compiled in conditionally. For other platforms of stdsimd see:
///
/// * [`x86`]
/// * [`x86_64`]
/// * [`arm`]
/// * [`aarch64`]
/// * [`mips`]
/// * [`mips64`]
/// * [`PowerPC`]
/// * [`PowerPC64`]
///
/// [`x86`]: https://rust-lang-nursery.github.io/stdsimd/x86/stdsimd/arch/index.html
/// [`x86_64`]: https://rust-lang-nursery.github.io/stdsimd/x86_64/stdsimd/arch/index.html
/// [`arm`]: https://rust-lang-nursery.github.io/stdsimd/arm/stdsimd/arch/index.html
/// [`aarch64`]: https://rust-lang-nursery.github.io/stdsimd/aarch64/stdsimd/arch/index.html
/// [`mips`]: https://rust-lang-nursery.github.io/stdsimd/mips/stdsimd/arch/index.html
/// [`mips64`]: https://rust-lang-nursery.github.io/stdsimd/mips64/stdsimd/arch/index.html
/// [`PowerPC`]: https://rust-lang-nursery.github.io/stdsimd/powerpc/stdsimd/arch/index.html
/// [`PowerPC64`]: https://rust-lang-nursery.github.io/stdsimd/powerpc64/stdsimd/arch/index.html
#[stable(feature = "simd_arch", since = "1.27.0")]
pub mod arch {
    /// Platform-specific intrinsics for the `x86` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86", dox))]
    #[doc(cfg(target_arch = "x86"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
    }

    /// Platform-specific intrinsics for the `x86_64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "x86_64", dox))]
    #[doc(cfg(target_arch = "x86_64"))]
    #[stable(feature = "simd_x86", since = "1.27.0")]
    pub mod x86_64 {
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86::*;
        #[stable(feature = "simd_x86", since = "1.27.0")]
        pub use coresimd::x86_64::*;
    }

    /// Platform-specific intrinsics for the `arm` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "arm", dox))]
    #[doc(cfg(target_arch = "arm"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod arm {
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `aarch64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "aarch64", dox))]
    #[doc(cfg(target_arch = "aarch64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod aarch64 {
        pub use coresimd::aarch64::*;
        pub use coresimd::arm::*;
    }

    /// Platform-specific intrinsics for the `wasm32` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(target_arch = "wasm32")]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod wasm32 {
        pub use coresimd::wasm32::*;
    }

    /// Platform-specific intrinsics for the `mips` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips", dox))]
    #[doc(cfg(target_arch = "mips"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `mips64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "mips64", dox))]
    #[doc(cfg(target_arch = "mips64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod mips64 {
        pub use coresimd::mips::*;
    }

    /// Platform-specific intrinsics for the `PowerPC` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc", dox))]
    #[doc(cfg(target_arch = "powerpc"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc {
        pub use coresimd::powerpc::*;
    }

    /// Platform-specific intrinsics for the `PowerPC64` platform.
    ///
    /// See the [module documentation](../index.html) for more details.
    #[cfg(any(target_arch = "powerpc64", dox))]
    #[doc(cfg(target_arch = "powerpc64"))]
    #[unstable(feature = "stdsimd", issue = "27731")]
    pub mod powerpc64 {
        pub use coresimd::powerpc64::*;
    }
}

mod simd_llvm;

#[cfg(any(target_arch = "x86", target_arch = "x86_64", dox))]
#[doc(cfg(any(target_arch = "x86", target_arch = "x86_64")))]
mod x86;
#[cfg(any(target_arch = "x86_64", dox))]
#[doc(cfg(target_arch = "x86_64"))]
mod x86_64;

#[cfg(any(target_arch = "aarch64", dox))]
#[doc(cfg(target_arch = "aarch64"))]
mod aarch64;
#[cfg(any(target_arch = "arm", target_arch = "aarch64", dox))]
#[doc(cfg(any(target_arch = "arm", target_arch = "aarch64")))]
mod arm;
#[cfg(target_arch = "wasm32")]
mod wasm32;

#[cfg(any(target_arch = "mips", target_arch = "mips64", dox))]
#[doc(cfg(any(target_arch = "mips", target_arch = "mips64")))]
mod mips;

#[cfg(any(target_arch = "powerpc", target_arch = "powerpc64", dox))]
#[doc(cfg(any(target_arch = "powerpc", target_arch = "powerpc64")))]
mod powerpc;

#[cfg(any(target_arch = "powerpc64", dox))]
#[doc(cfg(target_arch = "powerpc64"))]
mod powerpc64;

mod nvptx;
<|endoftext|>


<commit_before>#[macro_use] extern crate clap;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate rand;
extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

mod command;

use mio_uds::UnixStream;
use clap::{App,Arg,SubCommand};
use sozu::channel::Channel;

use sozu_command::config::Config;
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer};

use command::{dump_state,load_state,save_state,soft_stop,hard_stop,upgrade,status, remove_backend, add_backend, remove_frontend, add_frontend};

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("upgrades the proxy"))
                        .subcommand(SubCommand::with_name("status")
                                    .about("gets information on the running workers"))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .subcommand(SubCommand::with_name("backend")
                                                .about("backend management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("frontend")
                                                .about("frontend management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("certificate")
                                                .about("certificate management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("certificate chain")
                                                      .short("chain")
                                                      .long("certificate-chain")
                                                      .value_name("path to the certificate chain")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("key")
                                                      .long("key")
                                                      .value_name("path to the key")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))))
                        .get_matches();

  let config_file = matches.value_of("config").expect("required config file");

  let config = Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(&config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: Channel<ConfigMessage,ConfigMessageAnswer> = Channel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
      if hard_shutdown {
        hard_stop(&mut channel);
      } else {
        soft_stop(&mut channel);
      }
    },
    ("upgrade", Some(_)) => {
      upgrade(&mut channel);
    },
    ("status", Some(_)) => {
      status(&mut channel);
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          load_state(&mut channel, file);
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    ("backend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          remove_backend(&mut channel, id, ip, port);
        }
        ("add", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          add_backend(&mut channel, id, ip, port);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("frontend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(frontend_sub)) => {
          let id         = frontend_sub.value_of("id").expect("missing id");
          let hostname   = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin = frontend_sub.value_of("path_begin").unwrap_or("");
          remove_frontend(&mut channel, id, hostname, path_begin);
        },
        ("add", Some(frontend_sub)) => {
          let id         = frontend_sub.value_of("id").expect("missing id");
          let hostname   = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin = frontend_sub.value_of("path_begin").unwrap_or("");
          add_frontend(&mut channel, id, hostname, path_begin);
        }
        _ => println!("unknown backend management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<commit_msg>add and remove certificates from sozuctl<commit_after>#[macro_use] extern crate clap;
extern crate mio;
extern crate mio_uds;
extern crate nix;
extern crate libc;
extern crate time;
extern crate rand;
extern crate sozu_lib as sozu;
extern crate sozu_command_lib as sozu_command;

mod command;

use mio_uds::UnixStream;
use clap::{App,Arg,SubCommand};
use sozu::channel::Channel;

use sozu_command::config::Config;
use sozu_command::data::{ConfigMessage,ConfigMessageAnswer};

use command::{dump_state,load_state,save_state,soft_stop,hard_stop,upgrade,status,
  remove_backend, add_backend, remove_frontend, add_frontend, add_certificate, remove_certificate};

fn main() {
  let matches = App::new("sozuctl")
                        .version(crate_version!())
                        .about("hot reconfigurable proxy")
                        .arg(Arg::with_name("config")
                            .short("c")
                            .long("config")
                            .value_name("FILE")
                            .help("Sets a custom config file")
                            .takes_value(true)
                            .required(true))
                        .subcommand(SubCommand::with_name("shutdown")
                                    .about("shuts down the proxy")
                                    .arg(Arg::with_name("hard").long("hard")
                                         .help("shuts down the proxy without waiting for connections to finish")))
                        .subcommand(SubCommand::with_name("upgrade")
                                    .about("upgrades the proxy"))
                        .subcommand(SubCommand::with_name("status")
                                    .about("gets information on the running workers"))
                        .subcommand(SubCommand::with_name("state")
                                    .about("state management")
                                    .subcommand(SubCommand::with_name("save")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)
                                                    .required(true)))
                                    .subcommand(SubCommand::with_name("load")
                                                .arg(Arg::with_name("file")
                                                    .short("f")
                                                    .long("file")
                                                    .value_name("state file")
                                                    .help("Save state to that file")
                                                    .takes_value(true)))
                                    .subcommand(SubCommand::with_name("dump")))
                        .subcommand(SubCommand::with_name("backend")
                                                .about("backend management")
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true)))
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("ip")
                                                      .long("ip")
                                                      .value_name("ip of the backend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("port")
                                                      .long("port")
                                                      .short("p")
                                                      .value_name("port of the backend")
                                                      .takes_value(true)
                                                      .required(true))))
                        .subcommand(SubCommand::with_name("frontend")
                                                .about("frontend management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("id")
                                                      .short("i")
                                                      .long("id")
                                                      .value_name("app id of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("hostname")
                                                      .short("host")
                                                      .long("hostname")
                                                      .value_name("hostname of the frontend")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("path_begin")
                                                      .long("path_begin")
                                                      .value_name("URL prefix of the frontend")
                                                      .takes_value(true)
                                                      .required(false))))
                        .subcommand(SubCommand::with_name("certificate")
                                                .about("certificate management")
                                                .subcommand(SubCommand::with_name("add")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("certificate chain")
                                                      .short("chain")
                                                      .long("certificate-chain")
                                                      .value_name("path to the certificate chain")
                                                      .takes_value(true)
                                                      .required(true))
                                                  .arg(Arg::with_name("key")
                                                      .long("key")
                                                      .value_name("path to the key")
                                                      .takes_value(true)
                                                      .required(false)))
                                                .subcommand(SubCommand::with_name("remove")
                                                  .arg(Arg::with_name("certificate")
                                                      .long("certificate")
                                                      .value_name("path to the certificate")
                                                      .takes_value(true)
                                                      .required(true))))
                        .get_matches();

  let config_file = matches.value_of("config").expect("required config file");

  let config = Config::load_from_path(config_file).expect("could not parse configuration file");
  let stream = UnixStream::connect(&config.command_socket).expect("could not connect to the command unix socket");
  let mut channel: Channel<ConfigMessage,ConfigMessageAnswer> = Channel::new(stream, 10000, 20000);
  channel.set_nonblocking(false);

  match matches.subcommand() {
    ("shutdown", Some(sub)) => {
      let hard_shutdown = sub.is_present("hard");
      if hard_shutdown {
        hard_stop(&mut channel);
      } else {
        soft_stop(&mut channel);
      }
    },
    ("upgrade", Some(_)) => {
      upgrade(&mut channel);
    },
    ("status", Some(_)) => {
      status(&mut channel);
    },
    ("state", Some(sub))    => {
      match sub.subcommand() {
        ("save", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          save_state(&mut channel, file);
        },
        ("load", Some(state_sub)) => {
          let file = state_sub.value_of("file").expect("missing target file");
          load_state(&mut channel, file);
        },
        ("dump", _) => {
          dump_state(&mut channel);
        },
        _                   => println!("unknown state management command")
      }
    },
    ("backend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          remove_backend(&mut channel, id, ip, port);
        }
        ("add", Some(backend_sub)) => {
          let id = backend_sub.value_of("id").expect("missing id");
          let ip = backend_sub.value_of("ip").expect("missing backend ip");
          let port: u16 = backend_sub.value_of("port").expect("mssing backend port").parse().unwrap();
          add_backend(&mut channel, id, ip, port);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("frontend", Some(sub)) => {
      match sub.subcommand() {
        ("remove", Some(frontend_sub)) => {
          let id         = frontend_sub.value_of("id").expect("missing id");
          let hostname   = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin = frontend_sub.value_of("path_begin").unwrap_or("");
          remove_frontend(&mut channel, id, hostname, path_begin);
        },
        ("add", Some(frontend_sub)) => {
          let id         = frontend_sub.value_of("id").expect("missing id");
          let hostname   = frontend_sub.value_of("hostname").expect("missing frontend hostname");
          let path_begin = frontend_sub.value_of("path_begin").unwrap_or("");
          add_frontend(&mut channel, id, hostname, path_begin);
        }
        _ => println!("unknown backend management command")
      }
    },
    ("certificate", Some(sub)) => {
      match sub.subcommand() {
        ("add", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          let chain       = cert_sub.value_of("certificate-chain").expect("missing certificate chain path");
          let key         = cert_sub.value_of("key").unwrap_or("missing key path");
          add_certificate(&mut channel, certificate, chain, key);
        }
        ("remove", Some(cert_sub)) => {
          let certificate = cert_sub.value_of("certificate").expect("missing certificate path");
          remove_certificate(&mut channel, certificate);
        },
        _ => println!("unknown backend management command")
      }
    },
    _                => println!("unknown subcommand")
  }

}
<|endoftext|>


<commit_before>use nom::{Err, IResult, Needed};

use std::io;
use std::io::Read;
use std::ptr;

pub enum ErrorKind {
  IO(io::Error),
  Incomplete(usize),
  Consumed(usize),
  EndOfInput,
  Unknown,
}

pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(e)      => {
        if let Err::Position(_, i) = e {
          self.offset += self.len() - i.len();
        }

        Err(ErrorKind::Unknown)
      }
    }
  }
}

struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  fn fill(&mut self) -> io::Result<usize> {
    let needed = self.needed;

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity();

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(e)      => {
      if let Err::Position(_, i) = e {
        Err(ErrorKind::Consumed(buffer.len() - i.len()))
      } else {
        Err(ErrorKind::Unknown)
      }
    }
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(ErrorKind::IO));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        match kind {
          ErrorKind::Incomplete(needed) => self.needed = needed,
          ErrorKind::Consumed(consumed) => buffer.consume(consumed),
          _                             => (),
        }

        Err(kind)
      }
    }
  }
}
<commit_msg>Make `ErrorKind` derive for `Debug`<commit_after>use nom::{Err, IResult, Needed};

use std::io;
use std::io::Read;
use std::ptr;

#[derive(Debug)]
pub enum ErrorKind {
  IO(io::Error),
  Incomplete(usize),
  Consumed(usize),
  EndOfInput,
  Unknown,
}

pub trait StreamProducer {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T>;
}

pub struct ByteStream<'a> {
  offset: usize,
  bytes: &'a [u8],
}

impl<'a> ByteStream<'a> {
  pub fn new(bytes: &'a [u8]) -> Self {
    ByteStream {
      offset: 0,
      bytes: bytes,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.bytes.len() - self.offset
  }

  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }
}

impl<'a> StreamProducer for ByteStream<'a> {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.is_empty() {
      return Err(ErrorKind::EndOfInput);
    }

    match f(&self.bytes[self.offset..]) {
      IResult::Done(i, o)    => {
        self.offset += self.len() - i.len();

        Ok(o)
      }
      IResult::Incomplete(n) => {
        let mut needed = self.len();

        if let Needed::Size(size) = n {
          needed = size;
        }

        Err(ErrorKind::Incomplete(needed))
      }
      IResult::Error(e)      => {
        if let Err::Position(_, i) = e {
          self.offset += self.len() - i.len();
        }

        Err(ErrorKind::Unknown)
      }
    }
  }
}

struct Buffer {
  data: Vec<u8>,
  filled: usize,
  offset: usize,
}

impl Buffer {
  pub fn new() -> Self {
    Self::with_capacity(1024)
  }

  pub fn with_capacity(capacity: usize) -> Self {
    let mut buffer = Vec::with_capacity(capacity);

    unsafe {
      buffer.set_len(capacity);
    }

    Buffer {
      data: buffer,
      filled: 0,
      offset: 0,
    }
  }

  #[inline]
  pub fn len(&self) -> usize {
    self.filled - self.offset
  }

  #[inline]
  pub fn is_empty(&self) -> bool {
    self.len() == 0
  }

  #[inline]
  pub fn capacity(&self) -> usize {
    self.data.len()
  }

  pub fn as_slice(&self) -> &[u8] {
    &self.data[self.offset..self.filled]
  }

  pub fn fill<R: Read>(&mut self, reader: &mut R) -> io::Result<usize> {
    reader.read(&mut self.data[self.filled..]).map(|consumed| {
      self.filled += consumed;

      consumed
    })
  }

  pub fn resize(&mut self, size: usize) {
    if size > self.data.capacity() {
      self.data.reserve(size);

      let capacity = self.data.capacity();

      unsafe {
        self.data.set_len(capacity);
      }
    }

    if self.data.len() - self.filled < size  {
      let length  = self.filled - self.offset;
      let mut_ptr = self.data.as_mut_ptr();

      unsafe {
        let offset_ptr  = self.data.as_ptr().offset(self.offset as isize);

        ptr::copy(offset_ptr, mut_ptr, length);
      }

      self.filled -= self.offset;
      self.offset  = 0;
    }
  }

  pub fn consume(&mut self, consumed: usize) {
    self.offset += consumed;
  }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
enum ParserState {
  Incomplete,
  EndOfInput,
}

fn fill<R: Read>(buffer: &mut Buffer, reader: &mut R, needed: usize)
                 -> io::Result<usize> {
  let mut read = 0;

  if buffer.len() < needed {
    buffer.resize(needed);

    while buffer.len() < needed {
      let size_read = try!(buffer.fill(reader));

      if size_read > 0 {
        read += size_read;
      } else {
        break;
      }
    }
  }

  Ok(read)
}

pub struct ReadStream<R: Read> {
  reader: R,
  buffer: Buffer,
  needed: usize,
  state: ParserState,
}

impl<R> ReadStream<R> where R: Read {
  pub fn new(reader: R) -> Self {
    ReadStream {
      reader: reader,
      buffer: Buffer::new(),
      needed: 0,
      state: ParserState::Incomplete,
    }
  }

  fn fill(&mut self) -> io::Result<usize> {
    let needed = self.needed;

    fill(&mut self.buffer, &mut self.reader, needed).map(|consumed| {
      if self.buffer.len() < needed {
        self.state = ParserState::EndOfInput;
      }

      consumed
    })
  }
}

fn from_iresult<T>(buffer: &Buffer, result: IResult<&[u8], T>)
                   -> Result<(usize, T), ErrorKind> {
  match result {
    IResult::Done(i, o)    => Ok((buffer.len() - i.len(), o)),
    IResult::Incomplete(n) => {
      let mut needed = buffer.capacity();

      if let Needed::Size(size) = n {
        needed = size;
      }

      Err(ErrorKind::Incomplete(needed))
    }
    IResult::Error(e)      => {
      if let Err::Position(_, i) = e {
        Err(ErrorKind::Consumed(buffer.len() - i.len()))
      } else {
        Err(ErrorKind::Unknown)
      }
    }
  }
}

impl<R> StreamProducer for ReadStream<R> where R: Read {
  fn parse<F, T>(&mut self, f: F) -> Result<T, ErrorKind>
   where F: FnOnce(&[u8]) -> IResult<&[u8], T> {
    if self.state != ParserState::EndOfInput {
      try!(self.fill().map_err(ErrorKind::IO));
    }

    let mut buffer = &mut self.buffer;

    if buffer.is_empty() {
      self.state = ParserState::EndOfInput;

      return Err(ErrorKind::EndOfInput);
    }

    let result = {
      let iresult = f(buffer.as_slice());

      from_iresult(&buffer, iresult)
    };

    match result {
      Ok((consumed, o)) => {
        buffer.consume(consumed);

        Ok(o)
      }
      Err(kind)         => {
        match kind {
          ErrorKind::Incomplete(needed) => self.needed = needed,
          ErrorKind::Consumed(consumed) => buffer.consume(consumed),
          _                             => (),
        }

        Err(kind)
      }
    }
  }
}
<|endoftext|>