<commit_before>use euclid::{Vector2D, vec2};
use hex::Dir6;
use num::Integer;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self>;

    /// Return whether the given offset contains an isometric wall tile.
    ///
    /// Optional method for showing acute corners of fake isometric rooms in fov.
    fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
        let _ = offset;
        false
    }
}

/// Field of view iterator for a hexagonal map.
pub struct HexFov<T> {
    stack: Vec<Arc<T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(Vector2D<i32>, T)>,
}

impl<T: FovValue> HexFov<T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> HexFov<T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        HexFov {
            stack: vec![
                Arc::new(
                    PolarPoint::new(0.0, 1),
                    PolarPoint::new(6.0, 1),
                    init.clone()
                ),
            ],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }

    /// Add visible horizontal corners to fake-isometric rooms.
    fn make_corners_visible(&mut self, current: &Arc<T>) {
        // We're moving along a vertical line on the hex circle, so there are side
        // points to check.
        if let Some(side_pos) = current.pt.side_point() {
            let next = current.pt.next();
            let next_value = current.prev_value.advance(next.to_v2());
            // If the next cell is within the current span and the current cell is
            // wallform, and current and next are in the same value group,
            if next.is_below(current.end) &&
                current.prev_value.is_fake_isometric_wall(
                    current.pt.to_v2(),
                ) && next_value == current.prev_value.advance(current.pt.to_v2())
            {
                if let Some(next_value) = next_value {
                    // and if both the next cell and the third corner point cell are
                    // wallforms, and the side point would not be otherwise
                    // visible:
                    if next_value.is_fake_isometric_wall(next.to_v2()) &&
                        next_value.advance(side_pos).is_none() &&
                        next_value.is_fake_isometric_wall(side_pos)
                    {
                        // Add the side point to the side channel.
                        self.side_channel.push(
                            (side_pos, current.prev_value.clone()),
                        );
                    }
                }
            }
        }
    }
}

impl<T: FovValue> Iterator for HexFov<T> {
    type Item = (Vector2D<i32>, T);
    fn next(&mut self) -> Option<(Vector2D<i32>, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            self.make_corners_visible(&current);

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                return Some((pos, ret));
            } else {
                return self.next();
            }
        } else {
            None
        }
    }
}

struct Arc<T> {
    /// Start point of current arc.
    begin: PolarPoint,
    /// Point currently being processed.
    pt: PolarPoint,
    /// End point of current arc.
    end: PolarPoint,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<T: FovValue> Arc<T> {
    pub fn new(begin: PolarPoint, end: PolarPoint, prev_value: T) -> Arc<T> {
        let group_value = prev_value.advance(begin.to_v2());
        Arc {
            begin: begin,
            pt: begin,
            end: end,
            prev_value: prev_value,
            group_value: group_value,
        }
    }

    /// Consume the given arc and add its descendent, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<Arc<T>>) {
        self.pt = self.pt.next();
        if self.pt.is_below(self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(Arc::new(
                self.begin.further(),
                self.end.further(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<Arc<T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(Arc {
                begin: self.pt,
                pt: self.pt,
                end: self.end,
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(Arc::new(
                    self.begin.further(),
                    self.pt.further(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}

/// Points on a hex circle expressed in polar coordinates.
#[derive(Copy, Clone, PartialEq)]
struct PolarPoint {
    pos: f32,
    radius: u32,
}

impl PolarPoint {
    pub fn new(pos: f32, radius: u32) -> PolarPoint { PolarPoint { pos, radius } }

    /// Index of the discrete hex cell along the circle that corresponds to this point.
    fn winding_index(self) -> i32 { (self.pos + 0.5).floor() as i32 }

    pub fn is_below(self, other: PolarPoint) -> bool { self.winding_index() < other.end_index() }

    fn end_index(self) -> i32 { (self.pos + 0.5).ceil() as i32 }

    pub fn to_v2(self) -> Vector2D<i32> {
        if self.radius == 0 {
            return vec2(0, 0);
        }
        let index = self.winding_index();
        let sector = index.mod_floor(&(self.radius as i32 * 6)) / self.radius as i32;
        let offset = index.mod_floor(&(self.radius as i32));

        let rod = Dir6::from_int(sector).to_v2();
        let tangent = Dir6::from_int(sector + 2).to_v2();

        rod * (self.radius as i32) + tangent * offset
    }

    /// If this point and the next point are adjacent vertically (along the xy
    /// axis), return the point outside of the circle between the two points.
    ///
    /// This is a helper function for the FOV special case where acute corners
    /// of fake isometric rooms are marked visible even though strict hex FOV
    /// logic would keep them unseen.
    pub fn side_point(self) -> Option<Vector2D<i32>> {
        let next = self.next();
        let a = self.to_v2();
        let b = next.to_v2();

        if b.x == a.x + 1 && b.y == a.y + 1 {
            // Going down the right rim.
            Some(vec2(a.x + 1, a.y))
        } else if b.x == a.x - 1 && b.y == a.y - 1 {
            // Going up the left rim.
            Some(vec2(a.x - 1, a.y))
        } else {
            None
        }
    }

    /// The point corresponding to this one on the hex circle with radius +1.
    pub fn further(self) -> PolarPoint {
        PolarPoint::new(
            self.pos * (self.radius + 1) as f32 / self.radius as f32,
            self.radius + 1,
        )
    }

    /// The point next to this one along the hex circle.
    pub fn next(self) -> PolarPoint { PolarPoint::new((self.pos + 0.5).floor() + 0.5, self.radius) }
}

#[cfg(test)]
mod test {
    use super::{FovValue, HexFov};
    use euclid::{Vector2D, vec2};
    use hex::HexGeom;
    use std::collections::HashMap;
    use std::iter::FromIterator;

    #[derive(PartialEq, Eq, Clone)]
    struct Cell1 {
        range: i32,
    }

    impl FovValue for Cell1 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }
    }

    #[derive(PartialEq, Eq, Clone)]
    struct Cell2 {
        range: i32,
    }

    impl FovValue for Cell2 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }

        fn is_fake_isometric_wall(&self, offset: Vector2D<i32>) -> bool {
            let _ = offset;
            true
        }
    }

    #[test]
    fn trivial_fov() {
        // Just draw a small circle.
        let field: HashMap<Vector2D<i32>, Cell1> =
            HashMap::from_iter(HexFov::new(Cell1 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(!field.contains_key(&vec2(1, -1)));

        // Now test out the fake-isometric corners.
        let field: HashMap<Vector2D<i32>, Cell2> =
            HashMap::from_iter(HexFov::new(Cell2 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(field.contains_key(&vec2(1, -1)));
    }
}
<commit_msg>Remove the isometric corners hack<commit_after>use euclid::{Vector2D, vec2};
use hex::Dir6;
use num::Integer;

/// User data for field of view cells.
pub trait FovValue: PartialEq + Clone {
    /// Construct a new FovValue for a position based on the previous one along the line of sight.
    fn advance(&self, offset: Vector2D<i32>) -> Option<Self>;
}

/// Field of view iterator for a hexagonal map.
pub struct HexFov<T> {
    stack: Vec<Arc<T>>,
    /// Extra values generated by special cases.
    side_channel: Vec<(Vector2D<i32>, T)>,
}

impl<T: FovValue> HexFov<T> {
    /// Create a new field of view iterator with a seed userdata for the origin position.
    pub fn new(init: T) -> HexFov<T> {
        // We could run f for (0, 0) here, but the traditional way for the FOV to work is to only
        // consider your surroundings, not the origin site itself.
        HexFov {
            stack: vec![
                Arc::new(
                    PolarPoint::new(0.0, 1),
                    PolarPoint::new(6.0, 1),
                    init.clone()
                ),
            ],
            // The FOV algorithm will not generate the origin point, so we use
            // the side channel to explicitly add it in the beginning.
            side_channel: vec![(vec2(0, 0), init)],
        }
    }
}

impl<T: FovValue> Iterator for HexFov<T> {
    type Item = (Vector2D<i32>, T);
    fn next(&mut self) -> Option<(Vector2D<i32>, T)> {
        // Empty the side channel before proceeding to the algorithm proper.
        if let Some(ret) = self.side_channel.pop() {
            return Some(ret);
        }

        // Start processing the next arc in the stack.
        if let Some(current) = self.stack.pop() {
            if current.arc_has_split(&mut self.stack) {
                return self.next();
            }

            debug_assert!(current.group_value == current.prev_value.advance(current.pt.to_v2()));

            let pos = current.pt.to_v2();
            let ret = current.group_value.clone();

            current.advance(&mut self.stack);

            if let Some(ret) = ret {
                return Some((pos, ret));
            } else {
                return self.next();
            }
        } else {
            None
        }
    }
}

struct Arc<T> {
    /// Start point of current arc.
    begin: PolarPoint,
    /// Point currently being processed.
    pt: PolarPoint,
    /// End point of current arc.
    end: PolarPoint,
    /// The user value from previous iteration.
    prev_value: T,
    /// The user value for this group.
    group_value: Option<T>,
}

impl<T: FovValue> Arc<T> {
    pub fn new(begin: PolarPoint, end: PolarPoint, prev_value: T) -> Arc<T> {
        let group_value = prev_value.advance(begin.to_v2());
        Arc {
            begin: begin,
            pt: begin,
            end: end,
            prev_value: prev_value,
            group_value: group_value,
        }
    }

    /// Consume the given arc and add its descendent, if any, to the stack.
    pub fn advance(mut self, stack: &mut Vec<Arc<T>>) {
        self.pt = self.pt.next();
        if self.pt.is_below(self.end) {
            stack.push(self);
        } else if let Some(group_value) = self.group_value {
            stack.push(Arc::new(
                self.begin.further(),
                self.end.further(),
                group_value,
            ));
        }
    }

    /// If the arc has advanced into a different value group, split it into the given stack.
    ///
    /// Return true if arc was split, false otherwise.
    pub fn arc_has_split(&self, stack: &mut Vec<Arc<T>>) -> bool {
        let next_value = self.prev_value.advance(self.pt.to_v2());
        if next_value != self.group_value {
            // Using the literal instead of the constructor to avoid recomputing next_value.
            stack.push(Arc {
                begin: self.pt,
                pt: self.pt,
                end: self.end,
                prev_value: self.prev_value.clone(),
                group_value: next_value,
            });

            // Extend current arc if it has a group value.
            if let Some(ref group_value) = self.group_value {
                stack.push(Arc::new(
                    self.begin.further(),
                    self.pt.further(),
                    group_value.clone(),
                ));
            }

            true
        } else {
            false
        }
    }
}

/// Points on a hex circle expressed in polar coordinates.
#[derive(Copy, Clone, PartialEq)]
struct PolarPoint {
    pos: f32,
    radius: u32,
}

impl PolarPoint {
    pub fn new(pos: f32, radius: u32) -> PolarPoint { PolarPoint { pos, radius } }

    /// Index of the discrete hex cell along the circle that corresponds to this point.
    fn winding_index(self) -> i32 { (self.pos + 0.5).floor() as i32 }

    pub fn is_below(self, other: PolarPoint) -> bool { self.winding_index() < other.end_index() }

    fn end_index(self) -> i32 { (self.pos + 0.5).ceil() as i32 }

    pub fn to_v2(self) -> Vector2D<i32> {
        if self.radius == 0 {
            return vec2(0, 0);
        }
        let index = self.winding_index();
        let sector = index.mod_floor(&(self.radius as i32 * 6)) / self.radius as i32;
        let offset = index.mod_floor(&(self.radius as i32));

        let rod = Dir6::from_int(sector).to_v2();
        let tangent = Dir6::from_int(sector + 2).to_v2();

        rod * (self.radius as i32) + tangent * offset
    }

    /// The point corresponding to this one on the hex circle with radius +1.
    pub fn further(self) -> PolarPoint {
        PolarPoint::new(
            self.pos * (self.radius + 1) as f32 / self.radius as f32,
            self.radius + 1,
        )
    }

    /// The point next to this one along the hex circle.
    pub fn next(self) -> PolarPoint { PolarPoint::new((self.pos + 0.5).floor() + 0.5, self.radius) }
}

#[cfg(test)]
mod test {
    use super::{FovValue, HexFov};
    use euclid::{Vector2D, vec2};
    use hex::HexGeom;
    use std::collections::HashMap;
    use std::iter::FromIterator;

    #[derive(PartialEq, Eq, Clone)]
    struct Cell1 {
        range: i32,
    }

    impl FovValue for Cell1 {
        fn advance(&self, offset: Vector2D<i32>) -> Option<Self> {
            if offset.hex_dist() < self.range {
                Some(self.clone())
            } else {
                None
            }
        }
    }

    #[test]
    fn trivial_fov() {
        // Just draw a small circle.
        let field: HashMap<Vector2D<i32>, Cell1> =
            HashMap::from_iter(HexFov::new(Cell1 { range: 2 }));
        assert!(field.contains_key(&vec2(1, 0)));
        assert!(!field.contains_key(&vec2(1, -1)));
    }
}
<|endoftext|>


<commit_before>use std::ffi::CString;
use std::io::Error as IoError;
use std::path::Path;

use libc::{c_int, pid_t, size_t};
use libc::funcs::posix88::fcntl::open;
use libc::funcs::posix88::unistd::close;
use libc::consts::os::posix88::O_RDONLY;

use super::container::{Namespace, convert_namespace};

static O_CLOEXEC: c_int = 0o2000000;

extern {
    fn setns(fd: c_int, nstype: c_int) -> c_int;
    fn unshare(flags: c_int) -> c_int;
    fn sethostname(name: *const u8, len: size_t) -> c_int;
}

pub fn set_namespace_fd(fd: c_int, ns: Namespace) -> Result<(), IoError> {
    let rc = unsafe { setns(fd, convert_namespace(ns)) };
    if rc < 0 {
        return Err(IoError::last_error());
    }
    return Ok(());
}

pub fn set_namespace(path: &Path, ns: Namespace) -> Result<(), IoError> {
    let c_path = CString::from_slice(path.container_as_bytes());
    let fd = unsafe { open(c_path.as_ptr(), O_RDONLY|O_CLOEXEC, 0) };
    if fd < 0 {
        return Err(IoError::last_error());
    }
    let rc = unsafe { setns(fd, convert_namespace(ns)) };
    unsafe { close(fd) };
    if rc < 0 {
        return Err(IoError::last_error());
    }
    return Ok(());
}

pub fn nsopen(pid: pid_t, ns_name: &str) -> Result<c_int, IoError> {
    let filename = CString::from_slice(
        format!("/proc/{}/ns/{}", pid, ns_name).as_bytes());
    let fd = unsafe { open(filename.as_ptr(), O_RDONLY|O_CLOEXEC, 0) };
    if fd < 0 {
        return Err(IoError::last_error());
    }
    return Ok(fd);
}

pub fn unshare_namespace(ns: Namespace) -> Result<(), IoError> {
    let rc = unsafe { unshare(convert_namespace(ns)) };
    if rc < 0 {
        return Err(IoError::last_error());
    }
    return Ok(());
}

pub fn set_hostname(name: &str) -> Result<(), IoError> {
    let rc = unsafe { sethostname(name.as_bytes().as_ptr(),
                                  name.as_bytes().len() as size_t) };
    if rc < 0 {
        return Err(IoError::last_error());
    }
    return Ok(());
}
<commit_msg>Fix container/nsutil<commit_after>use std::ffi::CString;
use std::io::Error as IoError;
use std::path::Path;

use libc::{c_int, pid_t, size_t};
use libc::funcs::posix88::fcntl::open;
use libc::funcs::posix88::unistd::close;
use libc::consts::os::posix88::O_RDONLY;

use super::container::{Namespace, convert_namespace};

static O_CLOEXEC: c_int = 0o2000000;

extern {
    fn setns(fd: c_int, nstype: c_int) -> c_int;
    fn unshare(flags: c_int) -> c_int;
    fn sethostname(name: *const u8, len: size_t) -> c_int;
}

pub fn set_namespace_fd(fd: c_int, ns: Namespace) -> Result<(), IoError> {
    let rc = unsafe { setns(fd, convert_namespace(ns)) };
    if rc < 0 {
        return Err(IoError::last_os_error());
    }
    return Ok(());
}

pub fn set_namespace(path: &Path, ns: Namespace) -> Result<(), IoError> {
    let c_path = CString::new(path.to_str().unwrap()).unwrap();
    let fd = unsafe { open(c_path.as_ptr(), O_RDONLY|O_CLOEXEC, 0) };
    if fd < 0 {
        return Err(IoError::last_os_error());
    }
    let rc = unsafe { setns(fd, convert_namespace(ns)) };
    unsafe { close(fd) };
    if rc < 0 {
        return Err(IoError::last_os_error());
    }
    return Ok(());
}

pub fn nsopen(pid: pid_t, ns_name: &str) -> Result<c_int, IoError> {
    let filename = CString::new(&format!("/proc/{}/ns/{}", pid, ns_name)[..]
        ).unwrap();
    let fd = unsafe { open(filename.as_ptr(), O_RDONLY|O_CLOEXEC, 0) };
    if fd < 0 {
        return Err(IoError::last_os_error());
    }
    return Ok(fd);
}

pub fn unshare_namespace(ns: Namespace) -> Result<(), IoError> {
    let rc = unsafe { unshare(convert_namespace(ns)) };
    if rc < 0 {
        return Err(IoError::last_os_error());
    }
    return Ok(());
}

pub fn set_hostname(name: &str) -> Result<(), IoError> {
    let rc = unsafe { sethostname(name.as_bytes().as_ptr(),
                                  name.as_bytes().len() as size_t) };
    if rc < 0 {
        return Err(IoError::last_os_error());
    }
    return Ok(());
}
<|endoftext|>


<commit_before>use std::cmp::min;
use std::cmp::Ordering;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufRead, Write};
use std::io::Error as IoError;
use std::io::ErrorKind::{Interrupted, Other};
use std::str::FromStr;
use std::str::from_utf8;
use std::path::Path;
use std::process::{Command, Stdio};

use libc::funcs::posix88::unistd::{geteuid, getegid};
use libc::{pid_t, uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subuid")),
        "Can't open /etc/subuid: {err}");
    let mut res = Vec::new();
    let mut reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subuid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        let start = FromStr::from_str(parts[1]);
        let count = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subuid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

fn read_gid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subgid")),
        "Can't open /etc/subgid: {err}");
    let mut res = Vec::new();
    let mut reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subgid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        let start = FromStr::from_str(parts[1]);
        let count = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subgid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(username) {
            let start: gid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start, allowval.start, clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let mut cmd = Command::new("id");
    cmd.arg("--user").arg("--name");
    if let Ok(path) = env::var("HOST_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(cmd.output()
        .map_err(|e| format!("Error running `id --user --name`: {}", e))
        .and_then(|out| if out.status.success() { Ok(out.output) } else
            { Err(format!("Error running `id --user --name`")) })
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map(&username).ok();
    let gid_map = read_gid_map(&username).ok();

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Some(uid_map), Some(gid_map)) = (uid_map, gid_map) {
        if uid_map.len() == 0 && gid_map.len() == 0 && uid == 0 {
            let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
            let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
            return Ok(Ranges(
                uid_rng.into_iter()
                    .map(|r| (r.start, r.start, r.end-r.start+1)).collect(),
                gid_rng.into_iter()
                    .map(|r| (r.start, r.start, r.end-r.start+1)).collect()));
        }
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start && uid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start, rng.start, rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start && gid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start, rng.start, rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!(concat!("Your system doesn't have /etc/subuid and /etc/subgid.",
            " Presumably your system is too old. Some features may not work"));
        return Ok(Singleton(uid, gid));
    }
}

pub fn apply_uidmap(pid: pid_t, map: &Uidmap) -> Result<(), IoError> {
    match map {
        &Singleton(uid, gid) => {
            let uid_map = format!("0 {} 1", uid);
            debug!("Writing uid_map: {}", uid_map);
            let uid_map_file = Path::new("/proc")
                              .join(pid.to_string())
                              .join("uid_map");
            try!(OpenOptions().write(true).open(&uid_map_file)
                .write_all(&uid_map));
            let gid_map = format!("0 {} 1", gid);
            debug!("Writing gid_map: {}", gid_map);
            let gid_map_file = Path::new("/proc")
                              .join(pid.to_string())
                              .join("gid_map");
            try!(OpenOptions().write().open(&gid_map_file)
                .write_all(&uid_map));
        }
        &Ranges(ref uids, ref gids) => {
            let myuid = unsafe { geteuid() };
            if myuid > 0 {
                let mut cmd = Command::new("newuidmap");
                cmd.stdin(Stdio::null());
                cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in uids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Uid map command: {:?}", cmd);
                match cmd.status() {
                    Ok(s) if s.success() => {},
                    Ok(s) if s.signal().is_some() => {
                        return Err(IoError::new(Interrupted,
                            format!("Error writing uid mapping: \
                                newuidmap was killed on signal {}",
                                s.signal().unwrap())));
                    }
                    Ok(s) => {
                        return Err(IoError::new(Other,
                            format!("Error writing uid mapping: \
                                newuidmap was exit with status {}",
                                s.status())));
                    }
                    Err(e) => return Err(e),
                }

                let mut cmd = Command::new("newgidmap");
                cmd.stdin(Stdio::null());
                cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in gids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Gid map command: {:?}", cmd);
                match cmd.status() {
                    Ok(s) if s.success() => {},
                    Ok(s) if s.signal().is_some() => {
                        return Err(IoError::new(Interrupted,
                            format!("Error writing gid mapping: \
                                newuidmap was killed on signal {}",
                                s.signal().unwrap())));
                    }
                    Ok(s) => {
                        return Err(IoError::new(Other,
                            format!("Error writing gid mapping: \
                                newuidmap was exit with status {}",
                                s.status())));
                    }
                    Err(e) => return Err(e),
                }
            } else {
                let mut membuf = Vec::with_capacity(100);
                for &(ins, outs, cnt) in uids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/uid_map", pid))));
                let value = membuf.into_inner();
                debug!("Writing uid map ```{}```",
                    String::from_utf8_lossy(&value));
                try!(file.write(&value));

                let mut membuf = Vec::with_capacity(100);
                for &(ins, outs, cnt) in gids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(&Path::new(
                    format!("/proc/{}/gid_map", pid))));
                let value = membuf.into_inner();
                debug!("Writing gid map ```{}```",
                    String::from_utf8_lossy(&value));
                try!(file.write(&value));
            }
        }
    }
    return Ok(());
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let mut file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|e| format!("Error reading uid/gid map: {}", e)));
        let mut words = line[..].split_whitespace();
        let inside = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range { start: inside, end: inside+count-1 });
        } else {
            result.push(Range { start: outside, end: outside+count-1 });
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range { start: 0, end: 0 });
    let default_gids = vec!(Range { start: 0, end: 0 });
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    if settings.uid_map.is_none() {
        let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
        let uid_map = try!(match_ranges(uids, &ranges, 0)
            .map_err(|()| {
                return format!("Number of allowed subuids is too small. \
                    Required {}, allowed {}. You either need to increase \
                    allowed numbers in /etc/subuid (preferred) or decrease \
                    needed ranges in vagga.yaml by adding `uids` key \
                    to container config", uids, ranges);
            }));
        let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
        let gid_map = try!(match_ranges(gids, &ranges, 0)
            .map_err(|()| {
                return format!("Number of allowed subgids is too small. \
                    Required {}, allowed {}. You either need to increase \
                    allowed numbers in /etc/subgid (preferred) or decrease \
                    needed ranges in vagga.yaml by adding `gids` key \
                    to container config", gids, ranges);
            }));
        return Ok(Ranges(uid_map, gid_map));
    } else {
        let &(ref uids, ref gids) = settings.uid_map.as_ref().unwrap();
        return Ok(Ranges(uids.clone(), gids.clone()));
    }
}
<commit_msg>Ported container/uidmap.rs<commit_after>use std::cmp::min;
use std::cmp::Ordering;
use std::env;
use std::fs::{File, OpenOptions};
use std::io::{BufReader, BufRead, Write};
use std::io::Error as IoError;
use std::io::ErrorKind::{Interrupted, Other};
use std::os::unix::process::ExitStatusExt;
use std::str::FromStr;
use std::str::from_utf8;
use std::path::Path;
use std::process::{Command, Stdio};

use libc::funcs::posix88::unistd::{geteuid, getegid};
use libc::{pid_t, uid_t, gid_t};

use config::Range;
use config::Settings;
use self::Uidmap::*;

#[derive(Clone)]
pub enum Uidmap {
    Singleton(uid_t, gid_t),
    Ranges(Vec<(uid_t, uid_t, uid_t)>, Vec<(gid_t, gid_t, gid_t)>),
}

fn read_uid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subuid")),
        "Can't open /etc/subuid: {err}");
    let mut res = Vec::new();
    let mut reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subuid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        let start = FromStr::from_str(parts[1]);
        let count = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subuid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(username) {
            let start: uid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

fn read_gid_map(username: &str) -> Result<Vec<Range>,String> {
    let file = try_msg!(File::open(&Path::new("/etc/subgid")),
        "Can't open /etc/subgid: {err}");
    let mut res = Vec::new();
    let mut reader = BufReader::new(file);
    for (num, line) in reader.lines().enumerate() {
        let line = try_msg!(line, "Error reading /etc/subgid: {err}");
        let parts: Vec<&str> = line[..].split(':').collect();
        let start = FromStr::from_str(parts[1]);
        let count = FromStr::from_str(parts[2].trim_right());
        if parts.len() != 3 || start.is_err() || count.is_err() {
            return Err(format!("/etc/subgid:{}: Bad syntax", num+1));
        }
        if parts[0].eq(username) {
            let start: gid_t = start.unwrap();
            let end = start + count.unwrap() - 1;
            res.push(Range::new(start, end));
        }
    }
    return Ok(res);
}

pub fn match_ranges(req: &Vec<Range>, allowed: &Vec<Range>, own_id: uid_t)
    -> Result<Vec<(uid_t, uid_t, uid_t)>, ()>
{
    let mut res = vec!((0, own_id, 1));
    let mut reqiter = req.iter();
    let mut reqval = *reqiter.next().unwrap();
    let mut allowiter = allowed.iter();
    let mut allowval = *allowiter.next().unwrap();
    loop {
        if reqval.start == 0 {
            reqval = reqval.shift(1);
        }
        if allowval.start == 0 {
            allowval = allowval.shift(1);
        }
        let clen = min(reqval.len(), allowval.len());
        if clen > 0 {
            res.push((reqval.start, allowval.start, clen));
        }
        reqval = reqval.shift(clen);
        allowval = allowval.shift(clen);
        if reqval.len() == 0 {
            reqval = match reqiter.next() {
                Some(val) => *val,
                None => break,
            };
        }
        if allowval.len() == 0 {
            allowval = match allowiter.next() {
                Some(val) => *val,
                None => return Err(()),
            };
        }
    }
    return Ok(res);
}

pub fn get_max_uidmap() -> Result<Uidmap, String>
{
    let mut cmd = Command::new("id");
    cmd.arg("--user").arg("--name");
    if let Ok(path) = env::var("HOST_PATH") {
        cmd.env("PATH", path);
    }
    cmd.stdin(Stdio::null()).stderr(Stdio::inherit());
    let username = try!(cmd.output()
        .map_err(|e| format!("Error running `id --user --name`: {}", e))
        .and_then(|out| if out.status.success() { Ok(out.stdout) } else
            { Err(format!("Error running `id --user --name`")) })
        .and_then(|val| from_utf8(&val).map(|x| x.trim().to_string())
                   .map_err(|e| format!("Can't decode username: {}", e))));
    let uid_map = read_uid_map(&username).ok();
    let gid_map = read_gid_map(&username).ok();

    let uid = unsafe { geteuid() };
    let gid = unsafe { getegid() };
    if let (Some(uid_map), Some(gid_map)) = (uid_map, gid_map) {
        if uid_map.len() == 0 && gid_map.len() == 0 && uid == 0 {
            let uid_rng = try!(read_uid_ranges("/proc/self/uid_map", true));
            let gid_rng = try!(read_uid_ranges("/proc/self/gid_map", true));
            return Ok(Ranges(
                uid_rng.into_iter()
                    .map(|r| (r.start, r.start, r.end-r.start+1)).collect(),
                gid_rng.into_iter()
                    .map(|r| (r.start, r.start, r.end-r.start+1)).collect()));
        }
        let mut uids = vec!((0, uid, 1));
        for &rng in uid_map.iter() {
            let mut rng = rng;
            if uid >= rng.start && uid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(uid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            uids.push((rng.start, rng.start, rng.len()));
        }

        let mut gids = vec!((0, gid, 1));
        for &rng in gid_map.iter() {
            let mut rng = rng;
            if gid >= rng.start && gid <= rng.end {
                // TODO(tailhook) implement better heuristic
                assert!(gid == rng.start);
                rng = rng.shift(1);
                if rng.len() == 0 { continue; }
            }
            gids.push((rng.start, rng.start, rng.len()));
        }

        return Ok(Ranges(uids, gids));
    } else {
        warn!(concat!("Your system doesn't have /etc/subuid and /etc/subgid.",
            " Presumably your system is too old. Some features may not work"));
        return Ok(Singleton(uid, gid));
    }
}

pub fn apply_uidmap(pid: pid_t, map: &Uidmap) -> Result<(), IoError> {
    match map {
        &Singleton(uid, gid) => {
            let uid_map = format!("0 {} 1", uid);
            debug!("Writing uid_map: {}", uid_map);
            let uid_map_file = Path::new("/proc")
                              .join(pid.to_string())
                              .join("uid_map");
            try!(OpenOptions::new().write(true).open(&uid_map_file)
                .and_then(|mut f| f.write_all(uid_map.as_bytes())));
            let gid_map = format!("0 {} 1", gid);
            debug!("Writing gid_map: {}", gid_map);
            let gid_map_file = Path::new("/proc")
                              .join(pid.to_string())
                              .join("gid_map");
            try!(OpenOptions::new().write(true).open(&gid_map_file)
                .and_then(|mut f| f.write_all(uid_map.as_bytes())));
        }
        &Ranges(ref uids, ref gids) => {
            let myuid = unsafe { geteuid() };
            if myuid > 0 {
                let mut cmd = Command::new("newuidmap");
                cmd.stdin(Stdio::null());
                cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in uids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Uid map command: {:?}", cmd);
                match cmd.status() {
                    Ok(s) if s.success() => {},
                    Ok(s) if s.signal().is_some() => {
                        return Err(IoError::new(Interrupted,
                            format!("Error writing uid mapping: \
                                newuidmap was killed on signal {}",
                                s.signal().unwrap())));
                    }
                    Ok(s) => {
                        return Err(IoError::new(Other,
                            format!("Error writing uid mapping: \
                                newuidmap was exit with status {}", s)));
                    }
                    Err(e) => return Err(e),
                }

                let mut cmd = Command::new("newgidmap");
                cmd.stdin(Stdio::null());
                cmd.stdout(Stdio::inherit()).stderr(Stdio::inherit());
                cmd.arg(pid.to_string());
                for &(req, allowed, count) in gids.iter() {
                    cmd
                        .arg(req.to_string())
                        .arg(allowed.to_string())
                        .arg(count.to_string());
                }
                info!("Gid map command: {:?}", cmd);
                match cmd.status() {
                    Ok(s) if s.success() => {},
                    Ok(s) if s.signal().is_some() => {
                        return Err(IoError::new(Interrupted,
                            format!("Error writing gid mapping: \
                                newuidmap was killed on signal {}",
                                s.signal().unwrap())));
                    }
                    Ok(s) => {
                        return Err(IoError::new(Other,
                            format!("Error writing gid mapping: \
                                newuidmap was exit with status {}", s)));
                    }
                    Err(e) => return Err(e),
                }
            } else {
                let mut membuf = Vec::with_capacity(100);
                for &(ins, outs, cnt) in uids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(
                    &format!("/proc/{}/uid_map", pid)));
                debug!("Writing uid map ```{}```",
                    String::from_utf8_lossy(&membuf[..]));
                try!(file.write(&membuf));

                let mut membuf = Vec::with_capacity(100);
                for &(ins, outs, cnt) in gids.iter() {
                    try!(writeln!(&mut membuf, "{} {} {}", ins, outs, cnt));
                }
                let mut file = try!(File::create(
                    &format!("/proc/{}/gid_map", pid)));
                debug!("Writing gid map ```{}```",
                    String::from_utf8_lossy(&membuf[..]));
                try!(file.write(&membuf));
            }
        }
    }
    return Ok(());
}

fn read_uid_ranges(path: &str, read_inside: bool) -> Result<Vec<Range>, String>
{
    let mut file = BufReader::new(try!(File::open(&Path::new(path))
        .map_err(|e| format!("Error reading uid/gid map: {}", e))));
    let mut result = vec!();
    for line in file.lines() {
        let line = try!(line
            .map_err(|e| format!("Error reading uid/gid map")));
        let mut words = line[..].split_whitespace();
        let inside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let outside: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        let count: u32 = try!(words.next().and_then(|x| FromStr::from_str(x).ok())
            .ok_or(format!("uid/gid map format error")));
        if read_inside {
            result.push(Range { start: inside, end: inside+count-1 });
        } else {
            result.push(Range { start: outside, end: outside+count-1 });
        }
    }
    return Ok(result);
}

pub fn map_users(settings: &Settings, uids: &Vec<Range>, gids: &Vec<Range>)
    -> Result<Uidmap, String>
{
    let default_uids = vec!(Range { start: 0, end: 0 });
    let default_gids = vec!(Range { start: 0, end: 0 });
    let uids = if uids.len() > 0 { uids } else { &default_uids };
    let gids = if gids.len() > 0 { gids } else { &default_gids };
    if settings.uid_map.is_none() {
        let ranges = try!(read_uid_ranges("/proc/self/uid_map", true));
        let uid_map = try!(match_ranges(uids, &ranges, 0)
            .map_err(|()| {
                return format!("Number of allowed subuids is too small. \
                    Required {:?}, allowed {:?}. You either need to increase \
                    allowed numbers in /etc/subuid (preferred) or decrease \
                    needed ranges in vagga.yaml by adding `uids` key \
                    to container config", uids, ranges);
            }));
        let ranges = try!(read_uid_ranges("/proc/self/gid_map", true));
        let gid_map = try!(match_ranges(gids, &ranges, 0)
            .map_err(|()| {
                return format!("Number of allowed subgids is too small. \
                    Required {:?}, allowed {:?}. You either need to increase \
                    allowed numbers in /etc/subgid (preferred) or decrease \
                    needed ranges in vagga.yaml by adding `gids` key \
                    to container config", gids, ranges);
            }));
        return Ok(Ranges(uid_map, gid_map));
    } else {
        let &(ref uids, ref gids) = settings.uid_map.as_ref().unwrap();
        return Ok(Ranges(uids.clone(), gids.clone()));
    }
}
<|endoftext|>


<commit_before>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::{CStr, CString};

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
                                                 "xsave\0", "xsaveopt\0", "xsavec\0",
                                                 "xsaves\0", "aes\0",
                                                 "avx512bw\0", "avx512cd\0",
                                                 "avx512dq\0", "avx512er\0",
                                                 "avx512f\0", "avx512ifma\0",
                                                 "avx512pf\0", "avx512vbmi\0",
                                                 "avx512vl\0", "avx512vpopcntdq\0",
                                                 "mmx\0", "fxsr\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let whitelist = target_feature_whitelist(sess);
    let target_machine = create_target_machine(sess);
    let mut features = Vec::new();
    for feat in whitelist {
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } {
            features.push(Symbol::intern(feat.to_str().unwrap()));
        }
    }
    features
}

pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> {
    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };
    whitelist.iter().map(|m| {
        CStr::from_bytes_with_nul(m.as_bytes()).unwrap()
    }).collect()
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<commit_msg>Whitelist pclmul x86 feature flag<commit_after>// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use syntax_pos::symbol::Symbol;
use back::write::create_target_machine;
use llvm;
use rustc::session::Session;
use rustc::session::config::PrintRequest;
use libc::c_int;
use std::ffi::{CStr, CString};

use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Once;

static POISONED: AtomicBool = AtomicBool::new(false);
static INIT: Once = Once::new();

pub(crate) fn init(sess: &Session) {
    unsafe {
        // Before we touch LLVM, make sure that multithreading is enabled.
        INIT.call_once(|| {
            if llvm::LLVMStartMultithreaded() != 1 {
                // use an extra bool to make sure that all future usage of LLVM
                // cannot proceed despite the Once not running more than once.
                POISONED.store(true, Ordering::SeqCst);
            }

            configure_llvm(sess);
        });

        if POISONED.load(Ordering::SeqCst) {
            bug!("couldn't enable multi-threaded LLVM");
        }
    }
}

fn require_inited() {
    INIT.call_once(|| bug!("llvm is not initialized"));
    if POISONED.load(Ordering::SeqCst) {
        bug!("couldn't enable multi-threaded LLVM");
    }
}

unsafe fn configure_llvm(sess: &Session) {
    let mut llvm_c_strs = Vec::new();
    let mut llvm_args = Vec::new();

    {
        let mut add = |arg: &str| {
            let s = CString::new(arg).unwrap();
            llvm_args.push(s.as_ptr());
            llvm_c_strs.push(s);
        };
        add("rustc"); // fake program name
        if sess.time_llvm_passes() { add("-time-passes"); }
        if sess.print_llvm_passes() { add("-debug-pass=Structure"); }

        for arg in &sess.opts.cg.llvm_args {
            add(&(*arg));
        }
    }

    llvm::LLVMInitializePasses();

    llvm::initialize_available_targets();

    llvm::LLVMRustSetLLVMOptions(llvm_args.len() as c_int,
                                 llvm_args.as_ptr());
}

// WARNING: the features must be known to LLVM or the feature
// detection code will walk past the end of the feature array,
// leading to crashes.

const ARM_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0", "vfp2\0", "vfp3\0", "vfp4\0"];

const AARCH64_WHITELIST: &'static [&'static str] = &["neon\0", "v7\0"];

const X86_WHITELIST: &'static [&'static str] = &["avx\0", "avx2\0", "bmi\0", "bmi2\0", "sse\0",
                                                 "sse2\0", "sse3\0", "sse4.1\0", "sse4.2\0",
                                                 "ssse3\0", "tbm\0", "lzcnt\0", "popcnt\0",
                                                 "sse4a\0", "rdrnd\0", "rdseed\0", "fma\0",
                                                 "xsave\0", "xsaveopt\0", "xsavec\0",
                                                 "xsaves\0", "aes\0", "pclmul\0"
                                                 "avx512bw\0", "avx512cd\0",
                                                 "avx512dq\0", "avx512er\0",
                                                 "avx512f\0", "avx512ifma\0",
                                                 "avx512pf\0", "avx512vbmi\0",
                                                 "avx512vl\0", "avx512vpopcntdq\0",
                                                 "mmx\0", "fxsr\0"];

const HEXAGON_WHITELIST: &'static [&'static str] = &["hvx\0", "hvx-double\0"];

const POWERPC_WHITELIST: &'static [&'static str] = &["altivec\0",
                                                     "power8-altivec\0", "power9-altivec\0",
                                                     "power8-vector\0", "power9-vector\0",
                                                     "vsx\0"];

const MIPS_WHITELIST: &'static [&'static str] = &["msa\0"];

pub fn target_features(sess: &Session) -> Vec<Symbol> {
    let whitelist = target_feature_whitelist(sess);
    let target_machine = create_target_machine(sess);
    let mut features = Vec::new();
    for feat in whitelist {
        if unsafe { llvm::LLVMRustHasFeature(target_machine, feat.as_ptr()) } {
            features.push(Symbol::intern(feat.to_str().unwrap()));
        }
    }
    features
}

pub fn target_feature_whitelist(sess: &Session) -> Vec<&CStr> {
    let whitelist = match &*sess.target.target.arch {
        "arm" => ARM_WHITELIST,
        "aarch64" => AARCH64_WHITELIST,
        "x86" | "x86_64" => X86_WHITELIST,
        "hexagon" => HEXAGON_WHITELIST,
        "mips" | "mips64" => MIPS_WHITELIST,
        "powerpc" | "powerpc64" => POWERPC_WHITELIST,
        _ => &[],
    };
    whitelist.iter().map(|m| {
        CStr::from_bytes_with_nul(m.as_bytes()).unwrap()
    }).collect()
}

pub fn print_version() {
    // Can be called without initializing LLVM
    unsafe {
        println!("LLVM version: {}.{}",
                 llvm::LLVMRustVersionMajor(), llvm::LLVMRustVersionMinor());
    }
}

pub fn print_passes() {
    // Can be called without initializing LLVM
    unsafe { llvm::LLVMRustPrintPasses(); }
}

pub(crate) fn print(req: PrintRequest, sess: &Session) {
    require_inited();
    let tm = create_target_machine(sess);
    unsafe {
        match req {
            PrintRequest::TargetCPUs => llvm::LLVMRustPrintTargetCPUs(tm),
            PrintRequest::TargetFeatures => llvm::LLVMRustPrintTargetFeatures(tm),
            _ => bug!("rustc_trans can't handle print request: {:?}", req),
        }
    }
}
<|endoftext|>


<commit_before>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;

use std::cmp;
use std::collections::{RingBuf, Deque};
use std::io::{IoResult, IoError};
use std::mem;
use std::option::{Option, Some};
use std::raw::Slice;
use std::sync::Arc;

use bindings::{bpf, winpcap};
use datalink::{DataLinkChannelType};
use packet::Packet;
use packet::ethernet::{EthernetHeader, MutableEthernetHeader};
use util::NetworkInterface;

struct WinPcapAdapter {
    adapter: winpcap::LPADAPTER,
}

impl Drop for WinPcapAdapter {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketCloseAdapter(self.adapter);
        }
    }
}

struct WinPcapPacket {
    packet: winpcap::LPPACKET,
}

impl Drop for WinPcapPacket {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketFreePacket(self.packet);
        }
    }
}

pub fn datalink_channel(network_interface: &NetworkInterface,
           read_buffer_size: uint,
           write_buffer_size: uint,
           channel_type: DataLinkChannelType)
    -> IoResult<(DataLinkSenderImpl, DataLinkReceiverImpl)> {
    let mut read_buffer = Vec::from_elem(read_buffer_size, 0u8);
    let mut write_buffer = Vec::from_elem(read_buffer_size, 0u8);

    let adapter = unsafe {
        winpcap::PacketOpenAdapter(network_interface.name.to_c_str().as_mut_ptr())
    };
    if adapter.is_null() {
        return Err(IoError::last_error());
    }

    let ret = unsafe {
        winpcap::PacketSetHwFilter(adapter, winpcap::NDIS_PACKET_TYPE_PROMISCUOUS)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // Set kernel buffer size
    let ret = unsafe {
        winpcap::PacketSetBuff(adapter, read_buffer_size as libc::c_int)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // FIXME [windows] This shouldn't be here - on Win32 reading seems to block indefinitely
    //       currently.
    let ret = unsafe {
        winpcap::PacketSetReadTimeout(adapter, 5000)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // Immediate mode
    let ret = unsafe {
        winpcap::PacketSetMinToCopy(adapter, 1)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    let read_packet = unsafe { winpcap::PacketAllocatePacket() };
    if read_packet.is_null() {
        unsafe {
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(IoError::last_error());
    }

    unsafe {
        winpcap::PacketInitPacket(read_packet,
                                  read_buffer.as_mut_ptr() as winpcap::PVOID,
                                  read_buffer_size as winpcap::UINT)
    }

    let write_packet = unsafe { winpcap::PacketAllocatePacket() };
    if write_packet.is_null() {
        unsafe {
            winpcap::PacketFreePacket(read_packet);
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(IoError::last_error());
    }

    unsafe {
        winpcap::PacketInitPacket(write_packet,
                                  write_buffer.as_mut_ptr() as winpcap::PVOID,
                                  write_buffer_size as winpcap::UINT)
    }

    let adapter = Arc::new(WinPcapAdapter { adapter: adapter });
    let sender = DataLinkSenderImpl {
        adapter: adapter.clone(),
        _vec: write_buffer,
        packet: WinPcapPacket { packet: write_packet }
    };
    let receiver = DataLinkReceiverImpl {
        adapter: adapter,
        _vec: read_buffer,
        packet: WinPcapPacket { packet: read_packet }
    };
    Ok((sender, receiver))
}

pub struct DataLinkSenderImpl {
    adapter: Arc<WinPcapAdapter>,
    _vec: Vec<u8>,
    packet: WinPcapPacket,
}

pub struct DataLinkReceiverImpl {
    adapter: Arc<WinPcapAdapter>,
    _vec: Vec<u8>,
    packet: WinPcapPacket,
}

impl DataLinkSenderImpl {
    pub fn build_and_send(&mut self, num_packets: uint, packet_size: uint,
                          func: |MutableEthernetHeader| -> ()) -> Option<IoResult<()>> {
        use std::raw::Slice;
        let len = num_packets * packet_size;
        if len >= unsafe { (*self.packet.packet).Length } as uint {
            None
        } else {
            let min = unsafe { cmp::min((*self.packet.packet).Length as uint, len) };
            let slice: &mut [u8] = unsafe {
                    mem::transmute(
                        Slice {
                            data: (*self.packet.packet).Buffer as *const (),
                            len: min
                        }
                    )
            };
            for chunk in slice.chunks_mut(packet_size) {
                {
                    let eh = MutableEthernetHeader::new(chunk);
                    func(eh);
                }

                // Make sure the right length of packet is sent
                let old_len = unsafe { (*self.packet.packet).Length };
                unsafe { (*self.packet.packet).Length = packet_size as u32; }

                let ret = unsafe { winpcap::PacketSendPacket(self.adapter.adapter, self.packet.packet, 0) };

                unsafe { (*self.packet.packet).Length = old_len; }

                match ret {
                    0 => return Some(Err(IoError::last_error())),
                    _ => ()
                }
            }
            Some(Ok(()))
        }
    }

    pub fn send_to(&mut self, packet: EthernetHeader, _dst: Option<NetworkInterface>)
        -> Option<IoResult<()>> {
        self.build_and_send(1, packet.packet().len(), |mut eh| {
            eh.clone_from(packet);
        })
    }
}

impl DataLinkReceiverImpl {
    pub fn iter<'a>(&'a mut self) -> DataLinkChannelIteratorImpl<'a> {
        let buflen = unsafe { (*self.packet.packet).Length } as uint;
        DataLinkChannelIteratorImpl {
            pc: self,
            // Enough room for minimally sized packets without reallocating
            packets: RingBuf::with_capacity(buflen / 64)
        }
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
    packets: RingBuf<(uint, uint)>,
}

impl<'a> DataLinkChannelIteratorImpl<'a> {
    pub fn next<'c>(&'c mut self) -> IoResult<EthernetHeader<'c>> {
        // NOTE Most of the logic here is identical to FreeBSD/OS X
        if self.packets.is_empty() {
            let ret = unsafe {
                winpcap::PacketReceivePacket(self.pc.adapter.adapter, self.pc.packet.packet, 0)
            };
            let buflen = match ret {
                0 => return Err(IoError::last_error()),
                _ => unsafe { (*self.pc.packet.packet).ulBytesReceived },
            };
            let mut ptr = unsafe { (*self.pc.packet.packet).Buffer };
            let end = unsafe { (*self.pc.packet.packet).Buffer.offset(buflen as int) };
            while ptr < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as int +
                                (*packet).bh_hdrlen as int -
                                (*self.pc.packet.packet).Buffer as int;
                    self.packets.push((start as uint, (*packet).bh_caplen as uint));
                    let offset = (*packet).bh_hdrlen as int + (*packet).bh_caplen as int;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, len) = self.packets.pop_front().unwrap();
        let slice = unsafe {
            let data = (*self.pc.packet.packet).Buffer as uint + start;
            mem::transmute(Slice { data: data as *const u8, len: len } )
        };
        Ok(EthernetHeader::new(slice))
    }
}

<commit_msg>Fix Windows build.<commit_after>// Copyright (c) 2014 Robert Clipsham <robert@octarineparrot.com>
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate libc;

use std::cmp;
use std::collections::{RingBuf, Deque};
use std::io::{IoResult, IoError};
use std::mem;
use std::option::{Option, Some};
use std::raw::Slice;
use std::sync::Arc;

use bindings::{bpf, winpcap};
use datalink::{DataLinkChannelType};
use packet::Packet;
use packet::ethernet::{EthernetHeader, MutableEthernetHeader};
use util::NetworkInterface;

struct WinPcapAdapter {
    adapter: winpcap::LPADAPTER,
}

impl Drop for WinPcapAdapter {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketCloseAdapter(self.adapter);
        }
    }
}

struct WinPcapPacket {
    packet: winpcap::LPPACKET,
}

impl Drop for WinPcapPacket {
    fn drop(&mut self) {
        unsafe {
            winpcap::PacketFreePacket(self.packet);
        }
    }
}

pub fn datalink_channel(network_interface: &NetworkInterface,
           read_buffer_size: uint,
           write_buffer_size: uint,
           channel_type: DataLinkChannelType)
    -> IoResult<(DataLinkSenderImpl, DataLinkReceiverImpl)> {
    let mut read_buffer = Vec::from_elem(read_buffer_size, 0u8);
    let mut write_buffer = Vec::from_elem(read_buffer_size, 0u8);

    let adapter = unsafe {
        winpcap::PacketOpenAdapter(network_interface.name.to_c_str().as_mut_ptr())
    };
    if adapter.is_null() {
        return Err(IoError::last_error());
    }

    let ret = unsafe {
        winpcap::PacketSetHwFilter(adapter, winpcap::NDIS_PACKET_TYPE_PROMISCUOUS)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // Set kernel buffer size
    let ret = unsafe {
        winpcap::PacketSetBuff(adapter, read_buffer_size as libc::c_int)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // FIXME [windows] This shouldn't be here - on Win32 reading seems to block indefinitely
    //       currently.
    let ret = unsafe {
        winpcap::PacketSetReadTimeout(adapter, 5000)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    // Immediate mode
    let ret = unsafe {
        winpcap::PacketSetMinToCopy(adapter, 1)
    };
    if ret == 0 {
        return Err(IoError::last_error());
    }

    let read_packet = unsafe { winpcap::PacketAllocatePacket() };
    if read_packet.is_null() {
        unsafe {
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(IoError::last_error());
    }

    unsafe {
        winpcap::PacketInitPacket(read_packet,
                                  read_buffer.as_mut_ptr() as winpcap::PVOID,
                                  read_buffer_size as winpcap::UINT)
    }

    let write_packet = unsafe { winpcap::PacketAllocatePacket() };
    if write_packet.is_null() {
        unsafe {
            winpcap::PacketFreePacket(read_packet);
            winpcap::PacketCloseAdapter(adapter);
        }
        return Err(IoError::last_error());
    }

    unsafe {
        winpcap::PacketInitPacket(write_packet,
                                  write_buffer.as_mut_ptr() as winpcap::PVOID,
                                  write_buffer_size as winpcap::UINT)
    }

    let adapter = Arc::new(WinPcapAdapter { adapter: adapter });
    let sender = DataLinkSenderImpl {
        adapter: adapter.clone(),
        _vec: write_buffer,
        packet: WinPcapPacket { packet: write_packet }
    };
    let receiver = DataLinkReceiverImpl {
        adapter: adapter,
        _vec: read_buffer,
        packet: WinPcapPacket { packet: read_packet }
    };
    Ok((sender, receiver))
}

pub struct DataLinkSenderImpl {
    adapter: Arc<WinPcapAdapter>,
    _vec: Vec<u8>,
    packet: WinPcapPacket,
}

pub struct DataLinkReceiverImpl {
    adapter: Arc<WinPcapAdapter>,
    _vec: Vec<u8>,
    packet: WinPcapPacket,
}

impl DataLinkSenderImpl {
    pub fn build_and_send(&mut self, num_packets: uint, packet_size: uint,
                          func: |MutableEthernetHeader| -> ()) -> Option<IoResult<()>> {
        use std::raw::Slice;
        let len = num_packets * packet_size;
        if len >= unsafe { (*self.packet.packet).Length } as uint {
            None
        } else {
            let min = unsafe { cmp::min((*self.packet.packet).Length as uint, len) };
            let slice: &mut [u8] = unsafe {
                    mem::transmute(
                        Slice {
                            data: (*self.packet.packet).Buffer as *const (),
                            len: min
                        }
                    )
            };
            for chunk in slice.chunks_mut(packet_size) {
                {
                    let eh = MutableEthernetHeader::new(chunk);
                    func(eh);
                }

                // Make sure the right length of packet is sent
                let old_len = unsafe { (*self.packet.packet).Length };
                unsafe { (*self.packet.packet).Length = packet_size as u32; }

                let ret = unsafe { winpcap::PacketSendPacket(self.adapter.adapter, self.packet.packet, 0) };

                unsafe { (*self.packet.packet).Length = old_len; }

                match ret {
                    0 => return Some(Err(IoError::last_error())),
                    _ => ()
                }
            }
            Some(Ok(()))
        }
    }

    pub fn send_to(&mut self, packet: EthernetHeader, _dst: Option<NetworkInterface>)
        -> Option<IoResult<()>> {
        use packet::MutablePacket;
        self.build_and_send(1, packet.packet().len(), |mut eh| {
            eh.clone_from(packet);
        })
    }
}

impl DataLinkReceiverImpl {
    pub fn iter<'a>(&'a mut self) -> DataLinkChannelIteratorImpl<'a> {
        let buflen = unsafe { (*self.packet.packet).Length } as uint;
        DataLinkChannelIteratorImpl {
            pc: self,
            // Enough room for minimally sized packets without reallocating
            packets: RingBuf::with_capacity(buflen / 64)
        }
    }
}

pub struct DataLinkChannelIteratorImpl<'a> {
    pc: &'a mut DataLinkReceiverImpl,
    packets: RingBuf<(uint, uint)>,
}

impl<'a> DataLinkChannelIteratorImpl<'a> {
    pub fn next<'c>(&'c mut self) -> IoResult<EthernetHeader<'c>> {
        // NOTE Most of the logic here is identical to FreeBSD/OS X
        if self.packets.is_empty() {
            let ret = unsafe {
                winpcap::PacketReceivePacket(self.pc.adapter.adapter, self.pc.packet.packet, 0)
            };
            let buflen = match ret {
                0 => return Err(IoError::last_error()),
                _ => unsafe { (*self.pc.packet.packet).ulBytesReceived },
            };
            let mut ptr = unsafe { (*self.pc.packet.packet).Buffer };
            let end = unsafe { (*self.pc.packet.packet).Buffer.offset(buflen as int) };
            while ptr < end {
                unsafe {
                    let packet: *const bpf::bpf_hdr = mem::transmute(ptr);
                    let start = ptr as int +
                                (*packet).bh_hdrlen as int -
                                (*self.pc.packet.packet).Buffer as int;
                    self.packets.push((start as uint, (*packet).bh_caplen as uint));
                    let offset = (*packet).bh_hdrlen as int + (*packet).bh_caplen as int;
                    ptr = ptr.offset(bpf::BPF_WORDALIGN(offset));
                }
            }
        }
        let (start, len) = self.packets.pop_front().unwrap();
        let slice = unsafe {
            let data = (*self.pc.packet.packet).Buffer as uint + start;
            mem::transmute(Slice { data: data as *const u8, len: len } )
        };
        Ok(EthernetHeader::new(slice))
    }
}

<|endoftext|>


<commit_before>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_autoscaling::{Client, Error, Region, PKG_VERSION};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The name of the Amazon EC2 Auto Scaling group.
    #[structopt(short, long)]
    autoscaling_name: String,

    /// Whether to force the deletion.
    #[structopt(short, long)]
    force: bool,

    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

// Deletes a group.
// snippet-start:[autoscaling.rust.delete-autoscaling-group]
async fn delete_group(client: &Client, name: &str, force: bool) -> Result<(), Error> {
    client
        .delete_auto_scaling_group()
        .auto_scaling_group_name(name)
        .set_force_delete(force.then(|| true))
        .send()
        .await?;

    println!("Deleted Auto Scaling group");

    Ok(())
}
// snippet-end:[autoscaling.rust.delete-autoscaling-group]

/// Updates an Auto Scaling group in the Region to the specified maximum size.
/// # Arguments
///
/// * `-a AUTOSCALING-NAME` - The name of the Auto Scaling group.
/// * - [-f] - Whether to force the deletion.
/// * `[-r REGION]` - The Region in which the client is created.
///    If not supplied, uses the value of the **AWS_REGION** environment variable.
///    If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();

    let Opt {
        autoscaling_name,
        force,
        region,
        verbose,
    } = Opt::from_args();

    let region_provider = RegionProviderChain::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));
    println!();

    println!();

    if verbose {
        println!("Auto Scaling client version: {}", PKG_VERSION);
        println!(
            "Region:                      {}",
            region_provider.region().await.unwrap().as_ref()
        );
        println!("Auto Scaling group name:     {}", &autoscaling_name);
        println!("Force deletion?:             {}", &force);
        println!();
    }

    let shared_config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&shared_config);

    delete_group(&client, &autoscaling_name, force).await
}
<commit_msg>Updated comment for delete autoscaling group in Rust<commit_after>/*
 * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
 * SPDX-License-Identifier: Apache-2.0.
 */

use aws_config::meta::region::RegionProviderChain;
use aws_sdk_autoscaling::{Client, Error, Region, PKG_VERSION};
use structopt::StructOpt;

#[derive(Debug, StructOpt)]
struct Opt {
    /// The name of the Amazon EC2 Auto Scaling group.
    #[structopt(short, long)]
    autoscaling_name: String,

    /// Whether to force the deletion.
    #[structopt(short, long)]
    force: bool,

    /// The AWS Region.
    #[structopt(short, long)]
    region: Option<String>,

    /// Whether to display additional information.
    #[structopt(short, long)]
    verbose: bool,
}

// Deletes a group.
// snippet-start:[autoscaling.rust.delete-autoscaling-group]
async fn delete_group(client: &Client, name: &str, force: bool) -> Result<(), Error> {
    client
        .delete_auto_scaling_group()
        .auto_scaling_group_name(name)
        .set_force_delete(force.then(|| true))
        .send()
        .await?;

    println!("Deleted Auto Scaling group");

    Ok(())
}
// snippet-end:[autoscaling.rust.delete-autoscaling-group]

/// Deletes an Auto Scaling group in the Region.
/// # Arguments
///
/// * `-a AUTOSCALING-NAME` - The name of the Auto Scaling group.
/// * - [-f] - Whether to force the deletion.
/// * `[-r REGION]` - The Region in which the client is created.
///    If not supplied, uses the value of the **AWS_REGION** environment variable.
///    If the environment variable is not set, defaults to **us-west-2**.
/// * `[-v]` - Whether to display additional information.
#[tokio::main]
async fn main() -> Result<(), Error> {
    tracing_subscriber::fmt::init();

    let Opt {
        autoscaling_name,
        force,
        region,
        verbose,
    } = Opt::from_args();

    let region_provider = RegionProviderChain::first_try(region.map(Region::new))
        .or_default_provider()
        .or_else(Region::new("us-west-2"));
    println!();

    println!();

    if verbose {
        println!("Auto Scaling client version: {}", PKG_VERSION);
        println!(
            "Region:                      {}",
            region_provider.region().await.unwrap().as_ref()
        );
        println!("Auto Scaling group name:     {}", &autoscaling_name);
        println!("Force deletion?:             {}", &force);
        println!();
    }

    let shared_config = aws_config::from_env().region(region_provider).load().await;
    let client = Client::new(&shared_config);

    delete_group(&client, &autoscaling_name, force).await
}
<|endoftext|>


<commit_before>/*
Module: ptr

Unsafe pointer utility functions
*/
#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
    fn ptr_offset<T>(ptr: *T, count: uint) -> *T;
}

/*
Function: addr_of

Get an unsafe pointer to a value
*/
fn addr_of<T>(val: T) -> *T { ret rusti::addr_of(val); }

/*
Function: mut_addr_of

Get an unsafe mutable pointer to a value
*/
fn mut_addr_of<T>(val: T) -> *mutable T unsafe {
    ret unsafe::reinterpret_cast(rusti::addr_of(val));
}

/*
Function: offset

Calculate the offset from a pointer
*/
fn offset<T>(ptr: *T, count: uint) -> *T {
    ret rusti::ptr_offset(ptr, count);
}

/*
Function: null

Create an unsafe null pointer
*/
fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }
<commit_msg>ptr: Add mut_offset, to be able to calculate an offset on mutable pointers.<commit_after>/*
Module: ptr

Unsafe pointer utility functions
*/
#[abi = "rust-intrinsic"]
native mod rusti {
    fn addr_of<T>(val: T) -> *T;
    fn ptr_offset<T>(ptr: *T, count: uint) -> *T;
}

/*
Function: addr_of

Get an unsafe pointer to a value
*/
fn addr_of<T>(val: T) -> *T { ret rusti::addr_of(val); }

/*
Function: mut_addr_of

Get an unsafe mutable pointer to a value
*/
fn mut_addr_of<T>(val: T) -> *mutable T unsafe {
    ret unsafe::reinterpret_cast(rusti::addr_of(val));
}

/*
Function: offset

Calculate the offset from a pointer
*/
fn offset<T>(ptr: *T, count: uint) -> *T {
    ret rusti::ptr_offset(ptr, count);
}

/*
Function: mut_offset

Calculate the offset from a mutable pointer
*/
fn mut_offset<T>(ptr: *mutable T, count: uint) -> *mutable T {
    ret rusti::ptr_offset(ptr as *T, count) as *mutable T;
}

/*
Function: null

Create an unsafe null pointer
*/
fn null<T>() -> *T unsafe { ret unsafe::reinterpret_cast(0u); }
<|endoftext|>