<commit_before>use super::*;

/// New vec is bigger than old vec.
pub fn grow_merkle_cache(
    old_bytes: &[u8],
    old_flags: &[bool],
    from_height: usize,
    to_height: usize,
) -> Option<(Vec<u8>, Vec<bool>)> {
    // Determine the size of our new tree. It is not just a simple `1 << to_height` as there can be
    // an arbitrary number of nodes in `old_bytes` leaves if those leaves are subtrees.
    let to_nodes = {
        let old_nodes = old_bytes.len() / HASHSIZE;
        let additional_nodes = old_nodes - nodes_in_tree_of_height(from_height);
        nodes_in_tree_of_height(to_height) + additional_nodes
    };

    let mut bytes = vec![0; to_nodes * HASHSIZE];
    let mut flags = vec![true; to_nodes];

    let leaf_level = from_height;

    for i in 0..=from_height as usize {
        // If we're on the leaf slice, grab the first byte and all the of the bytes after that.
        // This is required because we can have an arbitrary number of bytes at the leaf level
        // (e.g., the case where there are subtrees as leaves).
        //
        // If we're not on a leaf level, the number of nodes is fixed and known.
        let (old_byte_slice, old_flag_slice) = if i == leaf_level {
            (
                old_bytes.get(first_byte_at_height(i)..)?,
                old_flags.get(first_node_at_height(i)..)?,
            )
        } else {
            (
                old_bytes.get(byte_range_at_height(i))?,
                old_flags.get(node_range_at_height(i))?,
            )
        };

        let new_i = i + to_height - from_height;
        let (new_byte_slice, new_flag_slice) = if i == leaf_level {
            (
                bytes.get_mut(first_byte_at_height(new_i)..)?,
                flags.get_mut(first_node_at_height(new_i)..)?,
            )
        } else {
            (
                bytes.get_mut(byte_range_at_height(new_i))?,
                flags.get_mut(node_range_at_height(new_i))?,
            )
        };

        new_byte_slice
            .get_mut(0..old_byte_slice.len())?
            .copy_from_slice(old_byte_slice);
        new_flag_slice
            .get_mut(0..old_flag_slice.len())?
            .copy_from_slice(old_flag_slice);
    }

    Some((bytes, flags))
}

fn nodes_in_tree_of_height(h: usize) -> usize {
    2 * (1 << h) - 1
}

fn byte_range_at_height(h: usize) -> Range<usize> {
    let node_range = node_range_at_height(h);
    node_range.start * HASHSIZE..node_range.end * HASHSIZE
}

fn node_range_at_height(h: usize) -> Range<usize> {
    first_node_at_height(h)..last_node_at_height(h) + 1
}

fn first_byte_at_height(h: usize) -> usize {
    first_node_at_height(h) * HASHSIZE
}

fn first_node_at_height(h: usize) -> usize {
    (1 << h) - 1
}

fn last_node_at_height(h: usize) -> usize {
    (1 << (h + 1)) - 2
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn can_grow_three_levels() {
        let from: usize = 1;
        let to: usize = 15;

        let old_bytes = vec![42; from * HASHSIZE];
        let old_flags = vec![false; from];

        let (new_bytes, new_flags) = grow_merkle_cache(
            &old_bytes,
            &old_flags,
            (from + 1).trailing_zeros() as usize - 1,
            (to + 1).trailing_zeros() as usize - 1,
        )
        .unwrap();

        let mut expected_bytes = vec![];
        let mut expected_flags = vec![];
        // First level
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        // Second level
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        expected_flags.push(true);
        // Third level
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        // Fourth level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);

        assert_eq!(expected_bytes, new_bytes);
        assert_eq!(expected_flags, new_flags);
    }

    #[test]
    fn can_grow_one_level() {
        let from: usize = 7;
        let to: usize = 15;

        let old_bytes = vec![42; from * HASHSIZE];
        let old_flags = vec![false; from];

        let (new_bytes, new_flags) = grow_merkle_cache(
            &old_bytes,
            &old_flags,
            (from + 1).trailing_zeros() as usize - 1,
            (to + 1).trailing_zeros() as usize - 1,
        )
        .unwrap();

        let mut expected_bytes = vec![];
        let mut expected_flags = vec![];
        // First level
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        // Second level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(true);
        // Third level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        // Fourth level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);

        assert_eq!(expected_bytes, new_bytes);
        assert_eq!(expected_flags, new_flags);
    }
}
<commit_msg>Add tree shrink fn<commit_after>use super::*;

/// New vec is bigger than old vec.
pub fn grow_merkle_cache(
    old_bytes: &[u8],
    old_flags: &[bool],
    from_height: usize,
    to_height: usize,
) -> Option<(Vec<u8>, Vec<bool>)> {
    // Determine the size of our new tree. It is not just a simple `1 << to_height` as there can be
    // an arbitrary number of nodes in `old_bytes` leaves if those leaves are subtrees.
    let to_nodes = {
        let old_nodes = old_bytes.len() / HASHSIZE;
        let additional_nodes = old_nodes - nodes_in_tree_of_height(from_height);
        nodes_in_tree_of_height(to_height) + additional_nodes
    };

    let mut bytes = vec![0; to_nodes * HASHSIZE];
    let mut flags = vec![true; to_nodes];

    let leaf_level = from_height;

    for i in 0..=from_height as usize {
        // If we're on the leaf slice, grab the first byte and all the of the bytes after that.
        // This is required because we can have an arbitrary number of bytes at the leaf level
        // (e.g., the case where there are subtrees as leaves).
        //
        // If we're not on a leaf level, the number of nodes is fixed and known.
        let (old_byte_slice, old_flag_slice) = if i == leaf_level {
            (
                old_bytes.get(first_byte_at_height(i)..)?,
                old_flags.get(first_node_at_height(i)..)?,
            )
        } else {
            (
                old_bytes.get(byte_range_at_height(i))?,
                old_flags.get(node_range_at_height(i))?,
            )
        };

        let new_i = i + to_height - from_height;
        let (new_byte_slice, new_flag_slice) = if i == leaf_level {
            (
                bytes.get_mut(first_byte_at_height(new_i)..)?,
                flags.get_mut(first_node_at_height(new_i)..)?,
            )
        } else {
            (
                bytes.get_mut(byte_range_at_height(new_i))?,
                flags.get_mut(node_range_at_height(new_i))?,
            )
        };

        new_byte_slice
            .get_mut(0..old_byte_slice.len())?
            .copy_from_slice(old_byte_slice);
        new_flag_slice
            .get_mut(0..old_flag_slice.len())?
            .copy_from_slice(old_flag_slice);
    }

    Some((bytes, flags))
}

/// New vec is smaller than old vec.
pub fn shrink_merkle_cache(
    from_bytes: &[u8],
    from_flags: &[bool],
    from_height: usize,
    to_height: usize,
    to_nodes: usize,
) -> Option<(Vec<u8>, Vec<bool>)> {
    let mut bytes = vec![0; to_nodes * HASHSIZE];
    let mut flags = vec![true; to_nodes];

    let leaf_level = to_height;

    for i in 0..=leaf_level as usize {
        let from_i = i + from_height - to_height;
        let (from_byte_slice, from_flag_slice) = if from_i == leaf_level {
            (
                from_bytes.get(first_byte_at_height(from_i)..)?,
                from_flags.get(first_node_at_height(from_i)..)?,
            )
        } else {
            (
                from_bytes.get(byte_range_at_height(from_i))?,
                from_flags.get(node_range_at_height(from_i))?,
            )
        };

        let (to_byte_slice, to_flag_slice) = if i == leaf_level {
            (
                bytes.get_mut(first_byte_at_height(i)..)?,
                flags.get_mut(first_node_at_height(i)..)?,
            )
        } else {
            (
                bytes.get_mut(byte_range_at_height(i))?,
                flags.get_mut(node_range_at_height(i))?,
            )
        };

        to_byte_slice.copy_from_slice(from_byte_slice.get(0..to_byte_slice.len())?);
        to_flag_slice.copy_from_slice(from_flag_slice.get(0..to_flag_slice.len())?);
    }

    Some((bytes, flags))
}

fn nodes_in_tree_of_height(h: usize) -> usize {
    2 * (1 << h) - 1
}

fn byte_range_at_height(h: usize) -> Range<usize> {
    let node_range = node_range_at_height(h);
    node_range.start * HASHSIZE..node_range.end * HASHSIZE
}

fn node_range_at_height(h: usize) -> Range<usize> {
    first_node_at_height(h)..last_node_at_height(h) + 1
}

fn first_byte_at_height(h: usize) -> usize {
    first_node_at_height(h) * HASHSIZE
}

fn first_node_at_height(h: usize) -> usize {
    (1 << h) - 1
}

fn last_node_at_height(h: usize) -> usize {
    (1 << (h + 1)) - 2
}

#[cfg(test)]
mod test {
    use super::*;

    #[test]
    fn can_grow_and_shrink_three_levels() {
        let small: usize = 1;
        let big: usize = 15;

        let original_bytes = vec![42; small * HASHSIZE];
        let original_flags = vec![false; small];

        let (grown_bytes, grown_flags) = grow_merkle_cache(
            &original_bytes,
            &original_flags,
            (small + 1).trailing_zeros() as usize - 1,
            (big + 1).trailing_zeros() as usize - 1,
        )
        .unwrap();

        let mut expected_bytes = vec![];
        let mut expected_flags = vec![];
        // First level
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        // Second level
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        expected_flags.push(true);
        // Third level
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        // Fourth level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);

        assert_eq!(expected_bytes, grown_bytes);
        assert_eq!(expected_flags, grown_flags);

        let (shrunk_bytes, shrunk_flags) = shrink_merkle_cache(
            &grown_bytes,
            &grown_flags,
            (big + 1).trailing_zeros() as usize - 1,
            (small + 1).trailing_zeros() as usize - 1,
            small,
        )
        .unwrap();

        assert_eq!(original_bytes, shrunk_bytes);
        assert_eq!(original_flags, shrunk_flags);
    }

    #[test]
    fn can_grow_and_shrink_one_level() {
        let small: usize = 7;
        let big: usize = 15;

        let original_bytes = vec![42; small * HASHSIZE];
        let original_flags = vec![false; small];

        let (grown_bytes, grown_flags) = grow_merkle_cache(
            &original_bytes,
            &original_flags,
            (small + 1).trailing_zeros() as usize - 1,
            (big + 1).trailing_zeros() as usize - 1,
        )
        .unwrap();

        let mut expected_bytes = vec![];
        let mut expected_flags = vec![];
        // First level
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(true);
        // Second level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(true);
        // Third level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        // Fourth level
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![42; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_bytes.append(&mut vec![0; 32]);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(false);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);
        expected_flags.push(true);

        assert_eq!(expected_bytes, grown_bytes);
        assert_eq!(expected_flags, grown_flags);

        let (shrunk_bytes, shrunk_flags) = shrink_merkle_cache(
            &grown_bytes,
            &grown_flags,
            (big + 1).trailing_zeros() as usize - 1,
            (small + 1).trailing_zeros() as usize - 1,
            small,
        )
        .unwrap();

        assert_eq!(original_bytes, shrunk_bytes);
        assert_eq!(original_flags, shrunk_flags);
    }
}
<|endoftext|>


<commit_before>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Provides an implementation of the audio_streams::shm_streams::ShmStream trait using the VioS
//! client.
//! Given that the VioS server doesn't emit an event when the next buffer is expected, this
//! implementation uses thread::sleep to drive the frame timings.

use super::shm_vios::{VioSClient, VioSStreamParams};

use crate::virtio::snd::constants::*;

use audio_streams::shm_streams::{BufferSet, ServerRequest, ShmStream, ShmStreamSource};
use audio_streams::{BoxError, SampleFormat, StreamDirection, StreamEffect};

use base::{error, SharedMemory, SharedMemoryUnix};

use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use std::sync::Arc;
use std::time::{Duration, Instant};

use sys_util::{Error as SysError, SharedMemory as SysSharedMemory};

use super::shm_vios::{Error, Result};

// This is the error type used in audio_streams::shm_streams. Unfortunately, it's not declared
// public there so it needs to be re-declared here. It also prevents the usage of anyhow::Error.
type GenericResult<T> = std::result::Result<T, BoxError>;

/// Adapter that provides the ShmStreamSource trait around the VioS backend.
pub struct VioSShmStreamSource {
    vios_client: Arc<VioSClient>,
}

impl VioSShmStreamSource {
    /// Creates a new stream source given the path to the audio server's socket.
    pub fn new<P: AsRef<Path>>(server: P) -> Result<VioSShmStreamSource> {
        Ok(Self {
            vios_client: Arc::new(VioSClient::try_new(server)?),
        })
    }
}

fn from_sample_format(format: SampleFormat) -> u8 {
    match format {
        SampleFormat::U8 => VIRTIO_SND_PCM_FMT_U8,
        SampleFormat::S16LE => VIRTIO_SND_PCM_FMT_U16,
        SampleFormat::S24LE => VIRTIO_SND_PCM_FMT_U24,
        SampleFormat::S32LE => VIRTIO_SND_PCM_FMT_U32,
    }
}

fn virtio_frame_rate(frame_rate: u32) -> GenericResult<u8> {
    Ok(match frame_rate {
        5512u32 => VIRTIO_SND_PCM_RATE_5512,
        8000u32 => VIRTIO_SND_PCM_RATE_8000,
        11025u32 => VIRTIO_SND_PCM_RATE_11025,
        16000u32 => VIRTIO_SND_PCM_RATE_16000,
        22050u32 => VIRTIO_SND_PCM_RATE_22050,
        32000u32 => VIRTIO_SND_PCM_RATE_32000,
        44100u32 => VIRTIO_SND_PCM_RATE_44100,
        48000u32 => VIRTIO_SND_PCM_RATE_48000,
        64000u32 => VIRTIO_SND_PCM_RATE_64000,
        88200u32 => VIRTIO_SND_PCM_RATE_88200,
        96000u32 => VIRTIO_SND_PCM_RATE_96000,
        176400u32 => VIRTIO_SND_PCM_RATE_176400,
        192000u32 => VIRTIO_SND_PCM_RATE_192000,
        384000u32 => VIRTIO_SND_PCM_RATE_384000,
        _ => {
            return Err(Box::new(Error::UnsupportedFrameRate(frame_rate)));
        }
    })
}

impl ShmStreamSource for VioSShmStreamSource {
    /// Creates a new stream
    #[allow(clippy::too_many_arguments)]
    fn new_stream(
        &mut self,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        _effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        _buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        let virtio_dir = match direction {
            StreamDirection::Playback => VIRTIO_SND_D_OUTPUT,
            StreamDirection::Capture => VIRTIO_SND_D_INPUT,
        };
        match self.vios_client.get_unused_stream_id(virtio_dir) {
            Some(stream_id) => {
                self.vios_client.prepare_stream(stream_id)?;
                let frame_size = num_channels * format.sample_bytes();
                let period_bytes = (frame_size * buffer_size) as u32;
                let params = VioSStreamParams {
                    buffer_bytes: 2 * period_bytes,
                    period_bytes,
                    features: 0u32,
                    tubes: num_channels as u8,
                    format: from_sample_format(format),
                    rate: virtio_frame_rate(frame_rate)?,
                };
                self.vios_client.set_stream_parameters(stream_id, params)?;
                self.vios_client.start_stream(stream_id)?;
                VioSndShmStream::new(
                    buffer_size,
                    num_channels,
                    format,
                    frame_rate,
                    stream_id,
                    direction,
                    self.vios_client.clone(),
                    client_shm,
                )
            }
            None => Err(Box::new(Error::NoStreamsAvailable)),
        }
    }

    /// Get a list of file descriptors used by the implementation.
    ///
    /// Returns any open file descriptors needed by the implementation.
    /// This list helps users of the ShmStreamSource enter Linux jails without
    /// closing needed file descriptors.
    fn keep_fds(&self) -> Vec<RawFd> {
        self.vios_client.keep_fds()
    }
}

/// Adapter around a VioS stream that implements the ShmStream trait.
pub struct VioSndShmStream {
    num_channels: usize,
    frame_rate: u32,
    buffer_size: usize,
    frame_size: usize,
    interval: Duration,
    next_frame: Duration,
    start_time: Instant,
    stream_id: u32,
    direction: StreamDirection,
    vios_client: Arc<VioSClient>,
    client_shm: SharedMemory,
}

impl VioSndShmStream {
    /// Creates a new shm stream.
    fn new(
        buffer_size: usize,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        stream_id: u32,
        direction: StreamDirection,
        vios_client: Arc<VioSClient>,
        client_shm: &SysSharedMemory,
    ) -> GenericResult<Box<dyn ShmStream>> {
        let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);

        let dup_fd = unsafe {
            // Safe because dup doesn't affect memory and client_shm should wrap a known valid file
            // descriptor
            libc::dup(client_shm.as_raw_fd())
        };
        if dup_fd < 0 {
            return Err(Box::new(Error::DupError(SysError::last())));
        }
        let file = unsafe {
            // safe because we checked the result of libc::dup()
            File::from_raw_fd(dup_fd)
        };
        let client_shm_clone =
            SharedMemory::from_file(file).map_err(|e| Error::BaseMmapError(e))?;

        Ok(Box::new(Self {
            num_channels,
            frame_rate,
            buffer_size,
            frame_size: format.sample_bytes() * num_channels,
            interval,
            next_frame: interval,
            start_time: Instant::now(),
            stream_id,
            direction,
            vios_client,
            client_shm: client_shm_clone,
        }))
    }
}

impl ShmStream for VioSndShmStream {
    fn frame_size(&self) -> usize {
        self.frame_size
    }

    fn num_channels(&self) -> usize {
        self.num_channels
    }

    fn frame_rate(&self) -> u32 {
        self.frame_rate
    }

    /// Waits until the next time a frame should be sent to the server. The server may release the
    /// previous buffer much sooner than it needs the next one, so this function may sleep to wait
    /// for the right time.
    fn wait_for_next_action_with_timeout(
        &mut self,
        timeout: Duration,
    ) -> GenericResult<Option<ServerRequest>> {
        let elapsed = self.start_time.elapsed();
        if elapsed < self.next_frame {
            if timeout < self.next_frame - elapsed {
                std::thread::sleep(timeout);
                return Ok(None);
            } else {
                std::thread::sleep(self.next_frame - elapsed);
            }
        }
        self.next_frame += self.interval;
        Ok(Some(ServerRequest::new(self.buffer_size, self)))
    }
}

impl BufferSet for VioSndShmStream {
    fn callback(&mut self, offset: usize, frames: usize) -> GenericResult<()> {
        match self.direction {
            StreamDirection::Playback => {
                self.vios_client.inject_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
            StreamDirection::Capture => {
                self.vios_client.request_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
        }
        Ok(())
    }

    fn ignore(&mut self) -> GenericResult<()> {
        Ok(())
    }
}

impl Drop for VioSndShmStream {
    fn drop(&mut self) {
        let stream_id = self.stream_id;
        if let Err(e) = self
            .vios_client
            .stop_stream(stream_id)
            .and_then(|_| self.vios_client.release_stream(stream_id))
        {
            error!("Failed to stop and release stream {}: {}", stream_id, e);
        }
    }
}
<commit_msg>Ensure streams are marked as unused on creation error<commit_after>// Copyright 2020 The Chromium OS Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

//! Provides an implementation of the audio_streams::shm_streams::ShmStream trait using the VioS
//! client.
//! Given that the VioS server doesn't emit an event when the next buffer is expected, this
//! implementation uses thread::sleep to drive the frame timings.

use super::shm_vios::{VioSClient, VioSStreamParams};

use crate::virtio::snd::constants::*;

use audio_streams::shm_streams::{BufferSet, ServerRequest, ShmStream, ShmStreamSource};
use audio_streams::{BoxError, SampleFormat, StreamDirection, StreamEffect};

use base::{error, SharedMemory, SharedMemoryUnix};

use std::fs::File;
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
use std::path::Path;
use std::sync::Arc;
use std::time::{Duration, Instant};

use sys_util::{Error as SysError, SharedMemory as SysSharedMemory};

use super::shm_vios::{Error, Result};

// This is the error type used in audio_streams::shm_streams. Unfortunately, it's not declared
// public there so it needs to be re-declared here. It also prevents the usage of anyhow::Error.
type GenericResult<T> = std::result::Result<T, BoxError>;

/// Adapter that provides the ShmStreamSource trait around the VioS backend.
pub struct VioSShmStreamSource {
    vios_client: Arc<VioSClient>,
}

impl VioSShmStreamSource {
    /// Creates a new stream source given the path to the audio server's socket.
    pub fn new<P: AsRef<Path>>(server: P) -> Result<VioSShmStreamSource> {
        Ok(Self {
            vios_client: Arc::new(VioSClient::try_new(server)?),
        })
    }
}

fn from_sample_format(format: SampleFormat) -> u8 {
    match format {
        SampleFormat::U8 => VIRTIO_SND_PCM_FMT_U8,
        SampleFormat::S16LE => VIRTIO_SND_PCM_FMT_U16,
        SampleFormat::S24LE => VIRTIO_SND_PCM_FMT_U24,
        SampleFormat::S32LE => VIRTIO_SND_PCM_FMT_U32,
    }
}

fn virtio_frame_rate(frame_rate: u32) -> GenericResult<u8> {
    Ok(match frame_rate {
        5512u32 => VIRTIO_SND_PCM_RATE_5512,
        8000u32 => VIRTIO_SND_PCM_RATE_8000,
        11025u32 => VIRTIO_SND_PCM_RATE_11025,
        16000u32 => VIRTIO_SND_PCM_RATE_16000,
        22050u32 => VIRTIO_SND_PCM_RATE_22050,
        32000u32 => VIRTIO_SND_PCM_RATE_32000,
        44100u32 => VIRTIO_SND_PCM_RATE_44100,
        48000u32 => VIRTIO_SND_PCM_RATE_48000,
        64000u32 => VIRTIO_SND_PCM_RATE_64000,
        88200u32 => VIRTIO_SND_PCM_RATE_88200,
        96000u32 => VIRTIO_SND_PCM_RATE_96000,
        176400u32 => VIRTIO_SND_PCM_RATE_176400,
        192000u32 => VIRTIO_SND_PCM_RATE_192000,
        384000u32 => VIRTIO_SND_PCM_RATE_384000,
        _ => {
            return Err(Box::new(Error::UnsupportedFrameRate(frame_rate)));
        }
    })
}

impl ShmStreamSource for VioSShmStreamSource {
    /// Creates a new stream
    #[allow(clippy::too_many_arguments)]
    fn new_stream(
        &mut self,
        direction: StreamDirection,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        buffer_size: usize,
        _effects: &[StreamEffect],
        client_shm: &SysSharedMemory,
        _buffer_offsets: [u64; 2],
    ) -> GenericResult<Box<dyn ShmStream>> {
        let virtio_dir = match direction {
            StreamDirection::Playback => VIRTIO_SND_D_OUTPUT,
            StreamDirection::Capture => VIRTIO_SND_D_INPUT,
        };
        let frame_size = num_channels * format.sample_bytes();
        let period_bytes = (frame_size * buffer_size) as u32;
        let stream_id = self
            .vios_client
            .get_unused_stream_id(virtio_dir)
            .ok_or(Box::new(Error::NoStreamsAvailable))?;
        // Create the stream object before any errors can be returned to guarantee the stream will
        // be released in all cases
        let stream_box = VioSndShmStream::new(
            buffer_size,
            num_channels,
            format,
            frame_rate,
            stream_id,
            direction,
            self.vios_client.clone(),
            client_shm,
        );
        self.vios_client.prepare_stream(stream_id)?;
        let params = VioSStreamParams {
            buffer_bytes: 2 * period_bytes,
            period_bytes,
            features: 0u32,
            tubes: num_channels as u8,
            format: from_sample_format(format),
            rate: virtio_frame_rate(frame_rate)?,
        };
        self.vios_client.set_stream_parameters(stream_id, params)?;
        self.vios_client.start_stream(stream_id)?;
        stream_box
    }

    /// Get a list of file descriptors used by the implementation.
    ///
    /// Returns any open file descriptors needed by the implementation.
    /// This list helps users of the ShmStreamSource enter Linux jails without
    /// closing needed file descriptors.
    fn keep_fds(&self) -> Vec<RawFd> {
        self.vios_client.keep_fds()
    }
}

/// Adapter around a VioS stream that implements the ShmStream trait.
pub struct VioSndShmStream {
    num_channels: usize,
    frame_rate: u32,
    buffer_size: usize,
    frame_size: usize,
    interval: Duration,
    next_frame: Duration,
    start_time: Instant,
    stream_id: u32,
    direction: StreamDirection,
    vios_client: Arc<VioSClient>,
    client_shm: SharedMemory,
}

impl VioSndShmStream {
    /// Creates a new shm stream.
    fn new(
        buffer_size: usize,
        num_channels: usize,
        format: SampleFormat,
        frame_rate: u32,
        stream_id: u32,
        direction: StreamDirection,
        vios_client: Arc<VioSClient>,
        client_shm: &SysSharedMemory,
    ) -> GenericResult<Box<dyn ShmStream>> {
        let interval = Duration::from_millis(buffer_size as u64 * 1000 / frame_rate as u64);

        let dup_fd = unsafe {
            // Safe because dup doesn't affect memory and client_shm should wrap a known valid file
            // descriptor
            libc::dup(client_shm.as_raw_fd())
        };
        if dup_fd < 0 {
            return Err(Box::new(Error::DupError(SysError::last())));
        }
        let file = unsafe {
            // safe because we checked the result of libc::dup()
            File::from_raw_fd(dup_fd)
        };
        let client_shm_clone =
            SharedMemory::from_file(file).map_err(|e| Error::BaseMmapError(e))?;

        Ok(Box::new(Self {
            num_channels,
            frame_rate,
            buffer_size,
            frame_size: format.sample_bytes() * num_channels,
            interval,
            next_frame: interval,
            start_time: Instant::now(),
            stream_id,
            direction,
            vios_client,
            client_shm: client_shm_clone,
        }))
    }
}

impl ShmStream for VioSndShmStream {
    fn frame_size(&self) -> usize {
        self.frame_size
    }

    fn num_channels(&self) -> usize {
        self.num_channels
    }

    fn frame_rate(&self) -> u32 {
        self.frame_rate
    }

    /// Waits until the next time a frame should be sent to the server. The server may release the
    /// previous buffer much sooner than it needs the next one, so this function may sleep to wait
    /// for the right time.
    fn wait_for_next_action_with_timeout(
        &mut self,
        timeout: Duration,
    ) -> GenericResult<Option<ServerRequest>> {
        let elapsed = self.start_time.elapsed();
        if elapsed < self.next_frame {
            if timeout < self.next_frame - elapsed {
                std::thread::sleep(timeout);
                return Ok(None);
            } else {
                std::thread::sleep(self.next_frame - elapsed);
            }
        }
        self.next_frame += self.interval;
        Ok(Some(ServerRequest::new(self.buffer_size, self)))
    }
}

impl BufferSet for VioSndShmStream {
    fn callback(&mut self, offset: usize, frames: usize) -> GenericResult<()> {
        match self.direction {
            StreamDirection::Playback => {
                self.vios_client.inject_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
            StreamDirection::Capture => {
                self.vios_client.request_audio_data(
                    self.stream_id,
                    &mut self.client_shm,
                    offset,
                    frames * self.frame_size,
                )?;
            }
        }
        Ok(())
    }

    fn ignore(&mut self) -> GenericResult<()> {
        Ok(())
    }
}

impl Drop for VioSndShmStream {
    fn drop(&mut self) {
        let stream_id = self.stream_id;
        if let Err(e) = self
            .vios_client
            .stop_stream(stream_id)
            .and_then(|_| self.vios_client.release_stream(stream_id))
        {
            error!("Failed to stop and release stream {}: {}", stream_id, e);
        }
    }
}
<|endoftext|>


<commit_before>extern crate pretty_env_logger;
extern crate env_logger;
#[macro_use] extern crate log;

use env_logger::Target;

mod one {
    pub fn deep() {
        trace!("one level deep!");
        trace!("one level deep!");
    }
}

fn main() {

    pretty_env_logger::formatted_builder().unwrap()
        //let's just set some random stuff.. for more see
        //https://docs.rs/env_logger/0.5.0-rc.1/env_logger/struct.Builder.html
        .target(Target::Stdout)
        .parse("with_builder_1=trace")
        .init();

    info!("such information");
    info!("such information");
    warn!("o_O");
    warn!("o_O");
    error!("boom");
    error!("boom");
    debug!("deboogging");
    debug!("deboogging");
    self::one::deep();
}
<commit_msg>fix with_builder_1 example (#25)<commit_after>extern crate pretty_env_logger;
extern crate env_logger;
#[macro_use] extern crate log;

use env_logger::Target;

mod one {
    pub fn deep() {
        trace!("one level deep!");
        trace!("one level deep!");
    }
}

fn main() {

    pretty_env_logger::formatted_builder()
        //let's just set some random stuff.. for more see
        //https://docs.rs/env_logger/0.5.0-rc.1/env_logger/struct.Builder.html
        .target(Target::Stdout)
        .parse("with_builder_1=trace")
        .init();

    info!("such information");
    info!("such information");
    warn!("o_O");
    warn!("o_O");
    error!("boom");
    error!("boom");
    debug!("deboogging");
    debug!("deboogging");
    self::one::deep();
}
<|endoftext|>


<commit_before>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Blockchain explorer module provides api for getting information about blocks and transactions
//! from the blockchain.

use serde_json::Value;

use std::cmp;

use storage::ListProof;
use crypto::Hash;
use blockchain::{Schema, Blockchain, Block, TxLocation};
use messages::Precommit;
// TODO: if explorer is usable anywhere else, remove `ApiError` dependencies.
use api::ApiError;

/// Blockchain explorer.
#[derive(Debug)]
pub struct BlockchainExplorer<'a> {
    blockchain: &'a Blockchain,
}

/// Block information.
#[derive(Debug, Serialize)]
pub struct BlockInfo {
    block: Block,
    precommits: Vec<Precommit>,
    txs: Vec<Hash>,
}

/// Transaction information.
#[derive(Debug, Serialize)]
pub struct TxInfo {
    content: Value,
    location: TxLocation,
    proof_to_block_merkle_root: ListProof<Hash>,
}

impl<'a> BlockchainExplorer<'a> {
    /// Creates a new `BlockchainExplorer` instance.
    pub fn new(blockchain: &'a Blockchain) -> Self {
        BlockchainExplorer { blockchain: blockchain }
    }

    /// Returns information about the transaction identified by the hash.
    pub fn tx_info(&self, tx_hash: &Hash) -> Result<Option<TxInfo>, ApiError> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let tx = schema.transactions().get(tx_hash);
        let res = match tx {
            None => None,
            Some(raw_tx) => {
                let box_transaction = self.blockchain.tx_from_raw(raw_tx.clone()).ok_or_else(|| {
                    ApiError::Service(format!("Service not found for tx: {:?}", raw_tx).into())
                })?;
                let content = box_transaction.info();

                let location = schema.tx_location_by_tx_hash().get(tx_hash).expect(
                    &format!(
                        "Not found tx_hash location: {:?}",
                        tx_hash
                    ),
                );

                let block_height = location.block_height();
                let tx_index = location.position_in_block();
                let proof = schema.block_txs(block_height).get_proof(tx_index);
                let tx_info = TxInfo {
                    content: content,
                    location: location,
                    proof_to_block_merkle_root: proof,
                };
                Some(tx_info)
            }
        };
        Ok(res)
    }

    /// Returns block information for the specified height or `None` if there is no such block.
    pub fn block_info(&self, height: u64) -> Option<BlockInfo> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let txs_table = schema.block_txs(height);
        let block_proof = schema.block_and_precommits(height);
        match block_proof {
            None => None,
            Some(proof) => {
                let bl = BlockInfo {
                    block: proof.block,
                    precommits: proof.precommits,
                    txs: txs_table.iter().collect(),
                };
                Some(bl)
            }
        }
    }

    /// Returns the list of blocks in the given range.
    pub fn blocks_range(
        &self,
        count: u64,
        upper: Option<u64>,
        skip_empty_blocks: bool,
    ) -> Vec<Block> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let hashes = schema.block_hashes_by_height();
        let blocks = schema.blocks();

        let max_len = hashes.len();
        let upper = upper.map(|x| cmp::min(x, max_len)).unwrap_or(max_len);
        let lower = upper.checked_sub(count).unwrap_or(0);

        let mut v = Vec::new();
        for height in (lower..upper).rev() {
            let block_txs = schema.block_txs(height);
            if skip_empty_blocks && block_txs.is_empty() {
                continue;
            }
            let block_hash = hashes.get(height).expect(&format!(
                "Block not found, height:{:?}",
                height
            ));
            let block = blocks.get(&block_hash).expect(&format!(
                "Block not found, hash:{:?}",
                block_hash
            ));
            v.push(block)
        }
        v
    }
}
<commit_msg>Make explorer structures more public<commit_after>// Copyright 2017 The Exonum Team
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//   http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Blockchain explorer module provides api for getting information about blocks and transactions
//! from the blockchain.

use serde_json::Value;

use std::cmp;

use storage::ListProof;
use crypto::Hash;
use blockchain::{Schema, Blockchain, Block, TxLocation};
use messages::Precommit;
// TODO: if explorer is usable anywhere else, remove `ApiError` dependencies.
use api::ApiError;

/// Blockchain explorer.
#[derive(Debug)]
pub struct BlockchainExplorer<'a> {
    blockchain: &'a Blockchain,
}

/// Block information.
#[derive(Debug, Serialize)]
pub struct BlockInfo {
    /// Block header from blockchain.
    pub block: Block,
    /// List of precommit for this block.
    pub precommits: Vec<Precommit>,
    /// List of hashes for transactions that was executed into this block.
    pub txs: Vec<Hash>,
}

/// Transaction information.
#[derive(Debug, Serialize)]
pub struct TxInfo {
    /// `JSON` serialized transaction
    pub content: Value,
    /// Transaction location in block
    pub location: TxLocation,
    /// Proof that transaction really exist in database
    pub proof_to_block_merkle_root: ListProof<Hash>,
}

impl<'a> BlockchainExplorer<'a> {
    /// Creates a new `BlockchainExplorer` instance.
    pub fn new(blockchain: &'a Blockchain) -> Self {
        BlockchainExplorer { blockchain: blockchain }
    }

    /// Returns information about the transaction identified by the hash.
    pub fn tx_info(&self, tx_hash: &Hash) -> Result<Option<TxInfo>, ApiError> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let tx = schema.transactions().get(tx_hash);
        let res = match tx {
            None => None,
            Some(raw_tx) => {
                let box_transaction = self.blockchain.tx_from_raw(raw_tx.clone()).ok_or_else(|| {
                    ApiError::Service(format!("Service not found for tx: {:?}", raw_tx).into())
                })?;
                let content = box_transaction.info();

                let location = schema.tx_location_by_tx_hash().get(tx_hash).expect(
                    &format!(
                        "Not found tx_hash location: {:?}",
                        tx_hash
                    ),
                );

                let block_height = location.block_height();
                let tx_index = location.position_in_block();
                let proof = schema.block_txs(block_height).get_proof(tx_index);
                let tx_info = TxInfo {
                    content: content,
                    location: location,
                    proof_to_block_merkle_root: proof,
                };
                Some(tx_info)
            }
        };
        Ok(res)
    }

    /// Returns block information for the specified height or `None` if there is no such block.
    pub fn block_info(&self, height: u64) -> Option<BlockInfo> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let txs_table = schema.block_txs(height);
        let block_proof = schema.block_and_precommits(height);
        match block_proof {
            None => None,
            Some(proof) => {
                let bl = BlockInfo {
                    block: proof.block,
                    precommits: proof.precommits,
                    txs: txs_table.iter().collect(),
                };
                Some(bl)
            }
        }
    }

    /// Returns the list of blocks in the given range.
    pub fn blocks_range(
        &self,
        count: u64,
        upper: Option<u64>,
        skip_empty_blocks: bool,
    ) -> Vec<Block> {
        let b = self.blockchain.clone();
        let snapshot = b.snapshot();
        let schema = Schema::new(&snapshot);
        let hashes = schema.block_hashes_by_height();
        let blocks = schema.blocks();

        let max_len = hashes.len();
        let upper = upper.map(|x| cmp::min(x, max_len)).unwrap_or(max_len);
        let lower = upper.checked_sub(count).unwrap_or(0);

        let mut v = Vec::new();
        for height in (lower..upper).rev() {
            let block_txs = schema.block_txs(height);
            if skip_empty_blocks && block_txs.is_empty() {
                continue;
            }
            let block_hash = hashes.get(height).expect(&format!(
                "Block not found, height:{:?}",
                height
            ));
            let block = blocks.get(&block_hash).expect(&format!(
                "Block not found, hash:{:?}",
                block_hash
            ));
            v.push(block)
        }
        v
    }
}
<|endoftext|>


<commit_before>
use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::marker::PhantomData;
use std::collections::BTreeMap;
use std::net::SocketAddr;

use config::ConfigFile;
use blockchain::{ConsensusConfig, GenesisConfig};
use node::NodeConfig;
use storage::Storage;
use crypto::{self, PublicKey, SecretKey};

const DEFAULT_EXONUM_LISTEN_PORT: u16 = 6333;

#[derive(Debug)]
pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .value_name("LEVELDB_PATH")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| s.parse().expect("Public api address has incorrect format"))
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| s.parse().expect("Private api address has incorrect format"))
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        Box::new(LevelDB::open(path, options).unwrap())
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::MemoryDB;
        Box::new(MemoryDB::new())
    }
}

#[derive(Serialize, Deserialize)]
pub struct ValidatorIdent {
    addr: SocketAddr,
}

#[derive(Serialize, Deserialize, Default)]
pub struct TemplateConfig {
    validators: BTreeMap<PublicKey, ValidatorIdent>,
    consensus_cfg: ConsensusConfig,
    count: usize
}

#[derive(Serialize, Deserialize)]
pub struct KeyConfig {
    public_key: PublicKey,
    secret_key: SecretKey,
}

pub struct KeyGeneratorCommand;
impl KeyGeneratorCommand
{
    /// Create basic keygen subcommand.
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("keygen")
            .about("Generate basic node secret key.")
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to key config.")
                     .required(true)
                     .index(1))
    }

    /// Path where keychain config should be saved
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Generate and write key config to `keychain()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let (pub_key, sec_key) = crypto::gen_keypair();
        let config = KeyConfig {
            public_key: pub_key,
            secret_key: sec_key,
        };

        ConfigFile::save(&config, Self::keychain(matches)).unwrap();
    }
}

/// implement command for template generating
pub struct GenerateTemplateCommand;
impl GenerateTemplateCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate-template")
            .about("Generate basic template.")
            .arg(Arg::with_name("COUNT")
                     .help("Validator total count.")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template config.")
                     .required(true)
                     .index(2))
    }

    /// Path where template config should be saved
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }
    /// Validator total count
    pub fn count(matches: &ArgMatches) -> usize {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    /// Write default template config into `template()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let mut template = TemplateConfig::default();
        template.count = Self::count(matches);
        ConfigFile::save(&template, Self::template(matches)).unwrap();
    }
}

pub struct PreInitCommand;
impl PreInitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("preinit")
            .about("Preinit configuration, optionaly generate public and secret key.")
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to secret and public key file.")
                     .required(true)
                     .index(2))
             .arg(Arg::with_name("LISTEN_ADDR")
                     .short("a")
                     .long("listen-addr")
                     .value_name("LISTEN_ADDR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("PORT")
                     .short("p")
                     .long("port")
                     .value_name("PORT")
                     .required(false)
                     .takes_value(true))

    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }

    pub fn port(matches: &ArgMatches) -> Option<u16> {
        matches.value_of("PORT").and_then(|port| port.parse().ok())
    }

    pub fn addr(matches: &ArgMatches) -> String {
        matches.value_of("LISTEN_ADDR").unwrap().to_string()
    }

    pub fn execute_default(matches: &ArgMatches) {
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let mut template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();
        let addr = format!("{}:{}", Self::addr(matches),
                     Self::port(matches).unwrap_or(DEFAULT_EXONUM_LISTEN_PORT))
                     .parse()
                     .unwrap();
        if !template.validators.contains_key(&keychain.public_key) {
            if template.validators.len() >= template.count {
                panic!("This template alredy full.");
            }
            let ident = ValidatorIdent {
                addr: addr
            };
            template.validators.insert(keychain.public_key, ident);
        }
        else {
            panic!("This node alredy in template");
        }

        ConfigFile::save(&template, template_path).unwrap();
    }
}

pub struct InitCommand;

impl InitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("init")
            .about("Toolchain to generate configuration")
            .arg(Arg::with_name("FULL_TEMPLATE")
                     .help("Path to full template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to keychain config.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("CONFIG_PATH")
                     .help("Path to node config.")
                     .required(true)
                     .index(3))

    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("FULL_TEMPLATE").unwrap())
    }

    pub fn config<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("CONFIG_PATH").unwrap())
    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn execute_default(matches: &ArgMatches) {
        let config_path = Self::config(matches);
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();

        if template.validators.len() != template.count {
            panic!("Template should be full.");
        }

        let genesis = GenesisConfig::new(template.validators.iter().map(|(k,_)| *k));
        let peers = template.validators.iter().map(|(_,ident)| ident.addr.clone()).collect();
        let validator_ident = template.validators.get(&keychain.public_key).unwrap();

        let config =  NodeConfig {
            listen_address: validator_ident.addr,
            network: Default::default(),
            peers: peers,
            public_key: keychain.public_key,
            secret_key: keychain.secret_key,
            genesis: genesis,
        };

        ConfigFile::save(&config, &config_path).unwrap();
    }

}

pub struct GenerateCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

<commit_msg>fix clippy warnings.<commit_after>
use clap::{SubCommand, App, Arg, ArgMatches};

use std::path::Path;
use std::marker::PhantomData;
use std::collections::BTreeMap;
use std::net::SocketAddr;

use config::ConfigFile;
use blockchain::{ConsensusConfig, GenesisConfig};
use node::NodeConfig;
use storage::Storage;
use crypto::{self, PublicKey, SecretKey};

const DEFAULT_EXONUM_LISTEN_PORT: u16 = 6333;

#[derive(Debug)]
pub struct RunCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

impl<'a, 'b> RunCommand<'a, 'b>
    where 'a: 'b
{
    pub fn new() -> App<'a, 'b> {
        SubCommand::with_name("run")
            .about("Run node with given configuration")
            .arg(Arg::with_name("NODE_CONFIG_PATH")
                     .short("c")
                     .long("node-config")
                     .value_name("NODE_CONFIG_PATH")
                     .help("Path to node configuration file")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("LEVELDB_PATH")
                     .short("d")
                     .long("leveldb-path")
                     .value_name("LEVELDB_PATH")
                     .help("Use leveldb database with the given path")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PUBLIC_API_ADDRESS")
                     .long("public-api-address")
                     .help("Listen address for public api")
                     .required(false)
                     .takes_value(true))
            .arg(Arg::with_name("PRIVATE_API_ADDRESS")
                     .long("private-api-address")
                     .help("Listen address for private api")
                     .required(false)
                     .takes_value(true))
    }

    pub fn node_config_path(matches: &'a ArgMatches<'a>) -> &'a Path {
        matches
            .value_of("NODE_CONFIG_PATH")
            .map(Path::new)
            .expect("Path to node configuration is no setted")
    }

    pub fn node_config(matches: &'a ArgMatches<'a>) -> NodeConfig {
        let path = Self::node_config_path(matches);
        let mut cfg: NodeConfig = ConfigFile::load(path).unwrap();
        // Override api options
        if let Some(addr) = Self::public_api_address(matches) {
            cfg.api.public_api_address = Some(addr);
        }
        if let Some(addr) = Self::private_api_address(matches) {
            cfg.api.private_api_address = Some(addr);
        }
        cfg
    }

    pub fn public_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PUBLIC_API_ADDRESS")
            .map(|s| s.parse().expect("Public api address has incorrect format"))
    }

    pub fn private_api_address(matches: &'a ArgMatches<'a>) -> Option<SocketAddr> {
        matches
            .value_of("PRIVATE_API_ADDRESS")
            .map(|s| s.parse().expect("Private api address has incorrect format"))
    }

    pub fn leveldb_path(matches: &'a ArgMatches<'a>) -> Option<&'a Path> {
        matches.value_of("LEVELDB_PATH").map(Path::new)
    }

    #[cfg(not(feature="memorydb"))]
    pub fn db(matches: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::{LevelDB, LevelDBOptions};

        let path = Self::leveldb_path(matches).unwrap();
        let mut options = LevelDBOptions::new();
        options.create_if_missing = true;
        Box::new(LevelDB::open(path, options).unwrap())
    }

    #[cfg(feature="memorydb")]
    pub fn db(_: &'a ArgMatches<'a>) -> Box<Database> {
        use storage::MemoryDB;
        Box::new(MemoryDB::new())
    }
}

#[derive(Serialize, Deserialize)]
pub struct ValidatorIdent {
    addr: SocketAddr,
}

#[derive(Serialize, Deserialize, Default)]
pub struct TemplateConfig {
    validators: BTreeMap<PublicKey, ValidatorIdent>,
    consensus_cfg: ConsensusConfig,
    count: usize
}

#[derive(Serialize, Deserialize)]
pub struct KeyConfig {
    public_key: PublicKey,
    secret_key: SecretKey,
}

pub struct KeyGeneratorCommand;
impl KeyGeneratorCommand
{
    /// Create basic keygen subcommand.
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("keygen")
            .about("Generate basic node secret key.")
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to key config.")
                     .required(true)
                     .index(1))
    }

    /// Path where keychain config should be saved
    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    /// Generate and write key config to `keychain()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let (pub_key, sec_key) = crypto::gen_keypair();
        let config = KeyConfig {
            public_key: pub_key,
            secret_key: sec_key,
        };

        ConfigFile::save(&config, Self::keychain(matches)).unwrap();
    }
}

/// implement command for template generating
pub struct GenerateTemplateCommand;
impl GenerateTemplateCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("generate-template")
            .about("Generate basic template.")
            .arg(Arg::with_name("COUNT")
                     .help("Validator total count.")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template config.")
                     .required(true)
                     .index(2))
    }

    /// Path where template config should be saved
    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }
    /// Validator total count
    pub fn count(matches: &ArgMatches) -> usize {
        matches.value_of("COUNT").unwrap().parse().unwrap()
    }

    /// Write default template config into `template()` path.
    pub fn execute_default(matches: &ArgMatches) {
        let mut template = TemplateConfig::default();
        template.count = Self::count(matches);
        ConfigFile::save(&template, Self::template(matches)).unwrap();
    }
}

pub struct PreInitCommand;
impl PreInitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("preinit")
            .about("Preinit configuration, optionaly generate public and secret key.")
            .arg(Arg::with_name("TEMPLATE")
                     .help("Path to template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to secret and public key file.")
                     .required(true)
                     .index(2))
             .arg(Arg::with_name("LISTEN_ADDR")
                     .short("a")
                     .long("listen-addr")
                     .value_name("LISTEN_ADDR")
                     .required(true)
                     .takes_value(true))
            .arg(Arg::with_name("PORT")
                     .short("p")
                     .long("port")
                     .value_name("PORT")
                     .required(false)
                     .takes_value(true))

    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("TEMPLATE").unwrap())
    }

    pub fn port(matches: &ArgMatches) -> Option<u16> {
        matches.value_of("PORT").and_then(|port| port.parse().ok())
    }

    pub fn addr(matches: &ArgMatches) -> String {
        matches.value_of("LISTEN_ADDR").unwrap().to_string()
    }

    #[cfg_attr(feature="cargo-clippy", allow(map_entry))]
    pub fn execute_default(matches: &ArgMatches) {
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let mut template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();
        let addr = format!("{}:{}", Self::addr(matches),
                     Self::port(matches).unwrap_or(DEFAULT_EXONUM_LISTEN_PORT))
                     .parse()
                     .unwrap();
        if !template.validators.contains_key(&keychain.public_key) {
            if template.validators.len() >= template.count {
                panic!("This template alredy full.");
            }
            let ident = ValidatorIdent {
                addr: addr
            };
            template.validators.insert(keychain.public_key, ident);
        }
        else {
            panic!("This node alredy in template");
        }

        ConfigFile::save(&template, template_path).unwrap();
    }
}

pub struct InitCommand;

impl InitCommand
{
    pub fn new<'a>() -> App<'a, 'a> {
        SubCommand::with_name("init")
            .about("Toolchain to generate configuration")
            .arg(Arg::with_name("FULL_TEMPLATE")
                     .help("Path to full template")
                     .required(true)
                     .index(1))
            .arg(Arg::with_name("KEYCHAIN")
                     .help("Path to keychain config.")
                     .required(true)
                     .index(2))
            .arg(Arg::with_name("CONFIG_PATH")
                     .help("Path to node config.")
                     .required(true)
                     .index(3))

    }

    pub fn template<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("FULL_TEMPLATE").unwrap())
    }

    pub fn config<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("CONFIG_PATH").unwrap())
    }

    pub fn keychain<'a>(matches: &'a ArgMatches<'a>) -> &'a Path {
        Path::new(matches.value_of("KEYCHAIN").unwrap())
    }

    pub fn execute_default(matches: &ArgMatches) {
        let config_path = Self::config(matches);
        let template_path = Self::template(matches);
        let keychain_path = Self::keychain(matches);

        let template: TemplateConfig = ConfigFile::load(template_path).unwrap();
        let keychain: KeyConfig = ConfigFile::load(keychain_path).unwrap();

        if template.validators.len() != template.count {
            panic!("Template should be full.");
        }

        let genesis = GenesisConfig::new(template.validators.iter().map(|(k,_)| *k));
        let peers = template.validators.iter().map(|(_,ident)| ident.addr).collect();
        let validator_ident = &template.validators[&keychain.public_key];

        let config =  NodeConfig {
            listen_address: validator_ident.addr,
            network: Default::default(),
            peers: peers,
            public_key: keychain.public_key,
            secret_key: keychain.secret_key,
            genesis: genesis,
        };

        ConfigFile::save(&config, config_path).unwrap();
    }

}

pub struct GenerateCommand<'a, 'b>
    where 'a: 'b
{
    _p: PhantomData<App<'a, 'b>>,
}

<|endoftext|>


<commit_before>extern crate libc;
extern crate syscall;

use std::{
    env::{split_paths, var, vars},
    io, mem,
    os::unix::{ffi::OsStrExt, io::RawFd},
    path::PathBuf,
    process::exit,
    slice,
};
use syscall::{waitpid as waitpid_, SigAction};
pub use syscall::{
    wcoredump as wcoredump_, wexitstatus as wexitstatus_, wifcontinued as wifcontinued_,
    wifexited as wifexited_, wifsignaled as wifsignaled_, wifstopped as wifstopped_,
    wstopsig as wstopsig_, wtermsig as wtermsig_, ECHILD, EINTR,
};

pub const PATH_SEPARATOR: &str = ";";
pub const NULL_PATH: &str = "null:";

pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub const SIGHUP: i32 = syscall::SIGHUP as i32;
pub const SIGINT: i32 = syscall::SIGINT as i32;
pub const SIGTERM: i32 = syscall::SIGTERM as i32;
pub const SIGCONT: i32 = syscall::SIGCONT as i32;
pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;
pub const SIGPIPE: i32 = syscall::SIGPIPE as i32;
pub const WUNTRACED: i32 = syscall::WUNTRACED as i32;
pub const WNOHANG: i32 = syscall::WNOHANG as i32;
pub const WCONTINUED: i32 = syscall::WCONTINUED as i32;

pub const STDIN_FILENO: RawFd = 0;
pub const STDOUT_FILENO: RawFd = 1;
pub const STDERR_FILENO: RawFd = 2;

pub fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }

pub fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }

pub fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }

pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }

pub fn fork_exit(status: i32) -> ! { exit(status) }

pub fn wexitstatus(status: i32) -> i32 { wexitstatus_(status as usize) as i32 }
pub fn wtermsig(status: i32) -> i32 { wtermsig_(status as usize) as i32 }
pub fn wstopsig(status: i32) -> i32 { wstopsig_(status as usize) as i32 }
pub fn wifcontinued(status: i32) -> bool { wifcontinued_(status as usize) }
pub fn wifsignaled(status: i32) -> bool { wifsignaled_(status as usize) }
pub fn wifstopped(status: i32) -> bool { wifstopped_(status as usize) }
pub fn wcoredump(status: i32) -> bool { wcoredump_(status as usize) }
pub fn wifexited(status: i32) -> bool { wifexited_(status as usize) }

pub fn waitpid(pid: i32, status: &mut i32, options: i32) -> Result<i32, i32> {
    let mut stat = 0;
    let result = match waitpid_(pid as usize, &mut stat, options as usize) {
        Err(ref error) => Err(error.errno),
        Ok(pid) => Ok(pid as i32),
    };

    *status = stat as i32;
    result
}

pub fn strerror(errno: i32) -> &'static str {
    syscall::error::STR_ERROR
        .get(errno as usize)
        .map(|err| *err)
        .unwrap_or("Unknown Error")
}

pub fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }

pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub fn fork_and_exec<F: Fn(), S: AsRef<str>>(
    prog: &str,
    args: &[S],
    stdin: Option<RawFd>,
    stdout: Option<RawFd>,
    stderr: Option<RawFd>,
    clear_env: bool,
    before_exec: F,
) -> io::Result<u32> {
    unsafe {
        match fork()? {
            0 => {
                if let Some(stdin) = stdin {
                    let _ = dup2(stdin, STDIN_FILENO);
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = dup2(stdout, STDOUT_FILENO);
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = dup2(stderr, STDERR_FILENO);
                    let _ = close(stderr);
                }

                before_exec();

                let error = execve(prog, args, clear_env);
                eprintln!("ion: command exec: {}", error);
                fork_exit(1);
            }
            pid => {
                if let Some(stdin) = stdin {
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = close(stderr);
                }

                Ok(pid)
            }
        }
    }
}

pub fn execve<S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
    // Construct a valid set of arguments to pass to execve. Ensure
    // that the program is the first argument.
    let mut cvt_args: Vec<[usize; 2]> = Vec::with_capacity(args.len());
    cvt_args.push([prog.as_ptr() as usize, prog.len()]);
    for arg in args {
        let arg: &str = arg.as_ref();
        cvt_args.push([arg.as_ptr() as usize, arg.len()]);
    }

    let mut env_args: Vec<[usize; 2]> = Vec::new();
    let mut env_key_value: Vec<String> = Vec::new();
    if !clear_env {
        for (key, value) in vars() {
            env_key_value.push(key + "=" + &value);
        }
        // Can't use the same loop because pushing to a vector may reallocate.
        for env in &env_key_value {
            env_args.push([env.as_ptr() as usize, env.len()]);
        }
    }

    // Get the PathBuf of the program if it exists.
    let prog = if prog.contains(':') || prog.contains('/') {
        // This is a fully specified scheme or path to an
        // executable.
        Some(PathBuf::from(prog))
    } else if let Ok(paths) = var("PATH") {
        // This is not a fully specified scheme or path.
        // Iterate through the possible paths in the
        // env var PATH that this executable may be found
        // in and return the first one found.
        split_paths(&paths)
            .filter_map(|mut path| {
                path.push(prog);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
            .next()
    } else {
        None
    };

    if let Some(prog) = prog {
        let fd = match syscall::open(prog.as_os_str().as_bytes(), syscall::O_RDONLY) {
            Ok(fd) => fd,
            Err(err) => return io::Error::from_raw_os_error(err.errno)
        };

        // If we found the program. Run it!
        let error = syscall::fexec(fd, &cvt_args, &env_args);
        io::Error::from_raw_os_error(error.err().unwrap().errno)
    } else {
        // The binary was not found.
        io::Error::from_raw_os_error(syscall::ENOENT)
    }
}

#[allow(dead_code)]
pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn reset_signal(signal: i32) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }

pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(syscall::dup2(old, new, &[])) }

pub fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }

pub fn isatty(fd: RawFd) -> bool {
    if let Ok(tfd) = syscall::dup(fd, b"termios") {
        let _ = syscall::close(tfd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
    /// controlled
    /// by the shell.
    pub fn unblock() {}
}

pub mod variables {
    use super::libc::{self, c_char};

    pub fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }

    pub fn get_host_name() -> Option<String> {
        let mut host_name = [0u8; 512];

        if unsafe { libc::gethostname(&mut host_name as *mut _ as *mut c_char, host_name.len()) }
            == 0
        {
            let len = host_name
                .iter()
                .position(|i| *i == 0)
                .unwrap_or(host_name.len());

            Some(unsafe { String::from_utf8_unchecked(host_name[..len].to_owned()) })
        } else {
            None
        }
    }
}

pub mod env {
    use std::{env, path::PathBuf};

    pub fn home_dir() -> Option<PathBuf> { env::var_os("HOME").map(PathBuf::from) }
}
<commit_msg>Don't forget to close executable file<commit_after>extern crate libc;
extern crate syscall;

use std::{
    env::{split_paths, var, vars},
    io, mem,
    os::unix::{ffi::OsStrExt, io::RawFd},
    path::PathBuf,
    process::exit,
    slice,
};
use syscall::{waitpid as waitpid_, SigAction};
pub use syscall::{
    wcoredump as wcoredump_, wexitstatus as wexitstatus_, wifcontinued as wifcontinued_,
    wifexited as wifexited_, wifsignaled as wifsignaled_, wifstopped as wifstopped_,
    wstopsig as wstopsig_, wtermsig as wtermsig_, ECHILD, EINTR,
};

pub const PATH_SEPARATOR: &str = ";";
pub const NULL_PATH: &str = "null:";

pub const O_CLOEXEC: usize = syscall::O_CLOEXEC;
pub const SIGHUP: i32 = syscall::SIGHUP as i32;
pub const SIGINT: i32 = syscall::SIGINT as i32;
pub const SIGTERM: i32 = syscall::SIGTERM as i32;
pub const SIGCONT: i32 = syscall::SIGCONT as i32;
pub const SIGSTOP: i32 = syscall::SIGSTOP as i32;
pub const SIGTSTP: i32 = syscall::SIGTSTP as i32;
pub const SIGPIPE: i32 = syscall::SIGPIPE as i32;
pub const WUNTRACED: i32 = syscall::WUNTRACED as i32;
pub const WNOHANG: i32 = syscall::WNOHANG as i32;
pub const WCONTINUED: i32 = syscall::WCONTINUED as i32;

pub const STDIN_FILENO: RawFd = 0;
pub const STDOUT_FILENO: RawFd = 1;
pub const STDERR_FILENO: RawFd = 2;

pub fn geteuid() -> io::Result<u32> { cvt(syscall::geteuid()).map(|pid| pid as u32) }

pub fn getuid() -> io::Result<u32> { cvt(syscall::getuid()).map(|pid| pid as u32) }

pub fn is_root() -> bool { syscall::geteuid().map(|id| id == 0).unwrap_or(false) }

pub unsafe fn fork() -> io::Result<u32> { cvt(syscall::clone(0)).map(|pid| pid as u32) }

pub fn fork_exit(status: i32) -> ! { exit(status) }

pub fn wexitstatus(status: i32) -> i32 { wexitstatus_(status as usize) as i32 }
pub fn wtermsig(status: i32) -> i32 { wtermsig_(status as usize) as i32 }
pub fn wstopsig(status: i32) -> i32 { wstopsig_(status as usize) as i32 }
pub fn wifcontinued(status: i32) -> bool { wifcontinued_(status as usize) }
pub fn wifsignaled(status: i32) -> bool { wifsignaled_(status as usize) }
pub fn wifstopped(status: i32) -> bool { wifstopped_(status as usize) }
pub fn wcoredump(status: i32) -> bool { wcoredump_(status as usize) }
pub fn wifexited(status: i32) -> bool { wifexited_(status as usize) }

pub fn waitpid(pid: i32, status: &mut i32, options: i32) -> Result<i32, i32> {
    let mut stat = 0;
    let result = match waitpid_(pid as usize, &mut stat, options as usize) {
        Err(ref error) => Err(error.errno),
        Ok(pid) => Ok(pid as i32),
    };

    *status = stat as i32;
    result
}

pub fn strerror(errno: i32) -> &'static str {
    syscall::error::STR_ERROR
        .get(errno as usize)
        .map(|err| *err)
        .unwrap_or("Unknown Error")
}

pub fn getpid() -> io::Result<u32> { cvt(syscall::getpid()).map(|pid| pid as u32) }

pub fn kill(pid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(pid as usize, signal as usize)).and(Ok(()))
}

pub fn killpg(pgid: u32, signal: i32) -> io::Result<()> {
    cvt(syscall::kill(-(pgid as isize) as usize, signal as usize)).and(Ok(()))
}

pub fn pipe2(flags: usize) -> io::Result<(RawFd, RawFd)> {
    let mut fds = [0; 2];
    cvt(syscall::pipe2(&mut fds, flags))?;
    Ok((fds[0], fds[1]))
}

pub fn setpgid(pid: u32, pgid: u32) -> io::Result<()> {
    cvt(syscall::setpgid(pid as usize, pgid as usize)).and(Ok(()))
}

pub fn fork_and_exec<F: Fn(), S: AsRef<str>>(
    prog: &str,
    args: &[S],
    stdin: Option<RawFd>,
    stdout: Option<RawFd>,
    stderr: Option<RawFd>,
    clear_env: bool,
    before_exec: F,
) -> io::Result<u32> {
    unsafe {
        match fork()? {
            0 => {
                if let Some(stdin) = stdin {
                    let _ = dup2(stdin, STDIN_FILENO);
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = dup2(stdout, STDOUT_FILENO);
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = dup2(stderr, STDERR_FILENO);
                    let _ = close(stderr);
                }

                before_exec();

                let error = execve(prog, args, clear_env);
                eprintln!("ion: command exec: {}", error);
                fork_exit(1);
            }
            pid => {
                if let Some(stdin) = stdin {
                    let _ = close(stdin);
                }

                if let Some(stdout) = stdout {
                    let _ = close(stdout);
                }

                if let Some(stderr) = stderr {
                    let _ = close(stderr);
                }

                Ok(pid)
            }
        }
    }
}

pub fn execve<S: AsRef<str>>(prog: &str, args: &[S], clear_env: bool) -> io::Error {
    // Construct a valid set of arguments to pass to execve. Ensure
    // that the program is the first argument.
    let mut cvt_args: Vec<[usize; 2]> = Vec::with_capacity(args.len());
    cvt_args.push([prog.as_ptr() as usize, prog.len()]);
    for arg in args {
        let arg: &str = arg.as_ref();
        cvt_args.push([arg.as_ptr() as usize, arg.len()]);
    }

    let mut env_args: Vec<[usize; 2]> = Vec::new();
    let mut env_key_value: Vec<String> = Vec::new();
    if !clear_env {
        for (key, value) in vars() {
            env_key_value.push(key + "=" + &value);
        }
        // Can't use the same loop because pushing to a vector may reallocate.
        for env in &env_key_value {
            env_args.push([env.as_ptr() as usize, env.len()]);
        }
    }

    // Get the PathBuf of the program if it exists.
    let prog = if prog.contains(':') || prog.contains('/') {
        // This is a fully specified scheme or path to an
        // executable.
        Some(PathBuf::from(prog))
    } else if let Ok(paths) = var("PATH") {
        // This is not a fully specified scheme or path.
        // Iterate through the possible paths in the
        // env var PATH that this executable may be found
        // in and return the first one found.
        split_paths(&paths)
            .filter_map(|mut path| {
                path.push(prog);
                if path.exists() {
                    Some(path)
                } else {
                    None
                }
            })
            .next()
    } else {
        None
    };

    if let Some(prog) = prog {
        let fd = match syscall::open(prog.as_os_str().as_bytes(), syscall::O_RDONLY | syscall::O_CLOEXEC) {
            Ok(fd) => fd,
            Err(err) => return io::Error::from_raw_os_error(err.errno)
        };

        // If we found the program. Run it!
        let error = syscall::fexec(fd, &cvt_args, &env_args);

        let _ = syscall::close(fd);

        io::Error::from_raw_os_error(error.err().unwrap().errno)
    } else {
        // The binary was not found.
        io::Error::from_raw_os_error(syscall::ENOENT)
    }
}

#[allow(dead_code)]
pub fn signal(signal: i32, handler: extern "C" fn(i32)) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(handler) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn reset_signal(signal: i32) -> io::Result<()> {
    let new = SigAction {
        sa_handler: unsafe { mem::transmute(syscall::flag::SIG_DFL) },
        sa_mask:    [0; 2],
        sa_flags:   0,
    };
    cvt(syscall::sigaction(signal as usize, Some(&new), None)).and(Ok(()))
}

pub fn tcsetpgrp(tty_fd: RawFd, pgid: u32) -> io::Result<()> {
    let fd = cvt(syscall::dup(tty_fd, b"pgrp"))?;

    let pgid_usize = pgid as usize;
    let res = syscall::write(fd, unsafe {
        slice::from_raw_parts(
            &pgid_usize as *const usize as *const u8,
            mem::size_of::<usize>(),
        )
    });

    let _ = syscall::close(fd);

    cvt(res).and(Ok(()))
}

pub fn dup(fd: RawFd) -> io::Result<RawFd> { cvt(syscall::dup(fd, &[])) }

pub fn dup2(old: RawFd, new: RawFd) -> io::Result<RawFd> { cvt(syscall::dup2(old, new, &[])) }

pub fn close(fd: RawFd) -> io::Result<()> { cvt(syscall::close(fd)).and(Ok(())) }

pub fn isatty(fd: RawFd) -> bool {
    if let Ok(tfd) = syscall::dup(fd, b"termios") {
        let _ = syscall::close(tfd);
        true
    } else {
        false
    }
}

// Support function for converting syscall error to io error
fn cvt(result: Result<usize, syscall::Error>) -> io::Result<usize> {
    result.map_err(|err| io::Error::from_raw_os_error(err.errno))
}

// TODO
pub mod signals {
    pub fn block() {}

    /// Unblocks the SIGTSTP/SIGTTOU/SIGTTIN/SIGCHLD signals so children processes can be
    /// controlled
    /// by the shell.
    pub fn unblock() {}
}

pub mod variables {
    use super::libc::{self, c_char};

    pub fn get_user_home(_username: &str) -> Option<String> {
        // TODO
        None
    }

    pub fn get_host_name() -> Option<String> {
        let mut host_name = [0u8; 512];

        if unsafe { libc::gethostname(&mut host_name as *mut _ as *mut c_char, host_name.len()) }
            == 0
        {
            let len = host_name
                .iter()
                .position(|i| *i == 0)
                .unwrap_or(host_name.len());

            Some(unsafe { String::from_utf8_unchecked(host_name[..len].to_owned()) })
        } else {
            None
        }
    }
}

pub mod env {
    use std::{env, path::PathBuf};

    pub fn home_dir() -> Option<PathBuf> { env::var_os("HOME").map(PathBuf::from) }
}
<|endoftext|>