<commit_before>#[link(name="wc", vers="1.0.0", author="Boden Garman")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Boden Garman <bpgarman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, File, result};
use std::io::buffered::BufferedReader;
use std::str::from_utf8_slice_opt;
use extra::getopts::{groups, Matches};

struct Result {
    filename: ~str,
    bytes: uint,
    chars: uint,
    lines: uint,
    words: uint,
    max_line_length: uint,
}

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("c", "bytes", "print the byte counts"),
        groups::optflag("m", "chars", "print the character counts"),
        groups::optflag("l", "lines", "print the newline counts"),
        groups::optflag("L", "max-line-length", "print the length of the longest line"),
        groups::optflag("w", "words", "print the word counts"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                   "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println("");
        print(groups::usage("Print newline, word and byte counts for each FILE", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }

    if (matches.opt_present("version")) {
        println("cat 1.0.0");
        return;
    }

    let mut files = matches.free.clone();
    if files.is_empty() {
        files = ~[~"-"];
    }

    wc(files, &matches);
}

static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;
static SPACE: u8 = ' ' as u8;
static TAB: u8 = '\t' as u8;
static SYN: u8 = 0x16 as u8;
static FF: u8 = 0x0C as u8;

fn is_word_seperator(byte: u8) -> bool {
    byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF
}

pub fn wc(files: ~[~str], matches: &Matches) {
    let mut total_line_count: uint = 0;
    let mut total_word_count: uint = 0;
    let mut total_char_count: uint = 0;
    let mut total_byte_count: uint = 0;
    let mut total_longest_line_length: uint = 0;

    let mut results: ~[Result] = ~[];
    let mut max_str_len: uint = 0;

    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        let mut line_count: uint = 0;
        let mut word_count: uint = 0;
        let mut byte_count: uint = 0;
        let mut char_count: uint = 0;
        let mut current_char_count: uint = 0;
        let mut longest_line_length: uint = 0;

        loop {
            // reading from a TTY seems to raise a condition on, rather than return Some(0) like a file.
            // hence the option wrapped in a result here
            match result(| | reader.read_until(LF)) {
                Ok(Some(raw_line)) => {
                    line_count += 1;
                    byte_count += raw_line.iter().len();

                    // try and convert the bytes to UTF-8 first
                    match from_utf8_slice_opt(raw_line) {
                        Some(line) => {
                            word_count += line.word_iter().len();
                            current_char_count = line.iter().len();
                            char_count += current_char_count;
                        },
                        None => {
                            word_count += raw_line.split_iter(|&x| is_word_seperator(x)).len();
                            for byte in raw_line.iter() {
                                match byte.is_ascii() {
                                    true => {
                                        current_char_count += 1;
                                    }
                                    false => { }
                                }
                            }
                            char_count += current_char_count;
                        }
                    }

                    if (current_char_count > longest_line_length) {
                        longest_line_length = current_char_count;
                    }
                },
                _ => break
            }

        }

        results.push(Result {
            filename: path.clone(),
            bytes: byte_count,
            chars: char_count,
            lines: line_count,
            words: word_count,
            max_line_length: longest_line_length,
        });

        total_line_count += line_count;
        total_word_count += word_count;
        total_char_count += char_count;
        total_byte_count += byte_count;

        if (longest_line_length > total_longest_line_length) {
            total_longest_line_length = longest_line_length;
        }

        // used for formatting
        max_str_len = total_byte_count.to_str().len();
    }

    for result in results.iter() {
        print_stats(&result.filename, result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len);
    }

    if (files.len() > 1) {
        print_stats(&~"total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len);
    }
}

fn print_stats(filename: &~str, line_count: uint, word_count: uint, char_count: uint,
    byte_count: uint, longest_line_length: uint, matches: &Matches, max_str_len: uint) {
    if (matches.opt_present("lines")) {
        print!("{:1$}", line_count, max_str_len);
    }
    if (matches.opt_present("words")) {
        print!("{:1$}", word_count, max_str_len);
    }
    if (matches.opt_present("bytes")) {
        print!("{:1$}", byte_count, max_str_len + 1);
    }
    if (matches.opt_present("chars")) {
        print!("{:1$}", char_count, max_str_len);
    }
    if (matches.opt_present("max-line-length")) {
        print!("{:1$}", longest_line_length, max_str_len);
    }

    // defaults
    if (!matches.opt_present("bytes") && !matches.opt_present("chars") && !matches.opt_present("lines")
        && !matches.opt_present("words") && !matches.opt_present("max-line-length")) {
        print!("{:1$}", line_count, max_str_len);
        print!("{:1$}", word_count, max_str_len + 1);
        print!("{:1$}", byte_count, max_str_len + 1);
    }

    if (*filename != ~"-") {
        println!(" {}", *filename);
    }
    else {
        println("");
    }
}

fn open(path: ~str) -> Option<BufferedReader<~Reader>> {
    if "-" == path {
        let reader = ~stdin() as ~Reader;
        return Some(BufferedReader::new(reader));
    }

    match result(|| File::open(&std::path::Path::new(path.as_slice()))) {
        Ok(fd) => {
            let reader = ~fd as ~Reader;
            return Some(BufferedReader::new(reader));
        },
        Err(e) => {
            writeln!(&mut stderr() as &mut Writer, "wc: {0:s}: {1:s}", path, e.desc.to_str());
            os::set_exit_status(1);
        }
    }

    None
}
<commit_msg>Fixed line count<commit_after>#[link(name="wc", vers="1.0.0", author="Boden Garman")];

/*
 * This file is part of the uutils coreutils package.
 *
 * (c) Boden Garman <bpgarman@gmail.com>
 *
 * For the full copyright and license information, please view the LICENSE
 * file that was distributed with this source code.
 */

extern mod extra;

use std::os;
use std::io::{stdin, stderr, File, result};
use std::io::buffered::BufferedReader;
use std::str::from_utf8_slice_opt;
use extra::getopts::{groups, Matches};

struct Result {
    filename: ~str,
    bytes: uint,
    chars: uint,
    lines: uint,
    words: uint,
    max_line_length: uint,
}

fn main() {
    let args = os::args();
    let program = args[0].clone();
    let opts = ~[
        groups::optflag("c", "bytes", "print the byte counts"),
        groups::optflag("m", "chars", "print the character counts"),
        groups::optflag("l", "lines", "print the newline counts"),
        groups::optflag("L", "max-line-length", "print the length of the longest line"),
        groups::optflag("w", "words", "print the word counts"),
        groups::optflag("h", "help", "display this help and exit"),
        groups::optflag("V", "version", "output version information and exit"),
    ];

    let matches = match groups::getopts(args.tail(), opts) {
        Ok(m) => m,
        Err(f) => {
            writeln!(&mut stderr() as &mut Writer,
                   "Invalid options\n{}", f.to_err_msg());
            os::set_exit_status(1);
            return
        }
    };

    if matches.opt_present("help") {
        println("Usage:");
        println!("  {0:s} [OPTION]... [FILE]...", program);
        println("");
        print(groups::usage("Print newline, word and byte counts for each FILE", opts));
        println("");
        println("With no FILE, or when FILE is -, read standard input.");
        return;
    }

    if (matches.opt_present("version")) {
        println("wc 1.0.0");
        return;
    }

    let mut files = matches.free.clone();
    if files.is_empty() {
        files = ~[~"-"];
    }

    wc(files, &matches);
}

static CR: u8 = '\r' as u8;
static LF: u8 = '\n' as u8;
static SPACE: u8 = ' ' as u8;
static TAB: u8 = '\t' as u8;
static SYN: u8 = 0x16 as u8;
static FF: u8 = 0x0C as u8;

fn is_word_seperator(byte: u8) -> bool {
    byte == SPACE || byte == TAB || byte == CR || byte == SYN || byte == FF
}

pub fn wc(files: ~[~str], matches: &Matches) {
    let mut total_line_count: uint = 0;
    let mut total_word_count: uint = 0;
    let mut total_char_count: uint = 0;
    let mut total_byte_count: uint = 0;
    let mut total_longest_line_length: uint = 0;

    let mut results: ~[Result] = ~[];
    let mut max_str_len: uint = 0;

    for path in files.iter() {
        let mut reader = match open(path.to_owned()) {
            Some(f) => f,
            None => { continue }
        };

        let mut line_count: uint = 0;
        let mut word_count: uint = 0;
        let mut byte_count: uint = 0;
        let mut char_count: uint = 0;
        let mut current_char_count: uint = 0;
        let mut longest_line_length: uint = 0;

        loop {
            // reading from a TTY seems to raise a condition on, rather than return Some(0) like a file.
            // hence the option wrapped in a result here
            match result(| | reader.read_until(LF)) {
                Ok(Some(raw_line)) => {
                    // GNU 'wc' only counts lines that end in LF as lines
                    if (raw_line.iter().last().unwrap() == &LF) {
                        line_count += 1;
                    }

                    byte_count += raw_line.iter().len();

                    // try and convert the bytes to UTF-8 first
                    match from_utf8_slice_opt(raw_line) {
                        Some(line) => {
                            word_count += line.word_iter().len();
                            current_char_count = line.iter().len();
                            char_count += current_char_count;
                        },
                        None => {
                            word_count += raw_line.split_iter(|&x| is_word_seperator(x)).len();
                            for byte in raw_line.iter() {
                                match byte.is_ascii() {
                                    true => {
                                        current_char_count += 1;
                                    }
                                    false => { }
                                }
                            }
                            char_count += current_char_count;
                        }
                    }

                    if (current_char_count > longest_line_length) {
                        longest_line_length = current_char_count;
                    }
                },
                _ => break
            }

        }

        results.push(Result {
            filename: path.clone(),
            bytes: byte_count,
            chars: char_count,
            lines: line_count,
            words: word_count,
            max_line_length: longest_line_length,
        });

        total_line_count += line_count;
        total_word_count += word_count;
        total_char_count += char_count;
        total_byte_count += byte_count;

        if (longest_line_length > total_longest_line_length) {
            total_longest_line_length = longest_line_length;
        }

        // used for formatting
        max_str_len = total_byte_count.to_str().len();
    }

    for result in results.iter() {
        print_stats(&result.filename, result.lines, result.words, result.chars, result.bytes, result.max_line_length, matches, max_str_len);
    }

    if (files.len() > 1) {
        print_stats(&~"total", total_line_count, total_word_count, total_char_count, total_byte_count, total_longest_line_length, matches, max_str_len);
    }
}

fn print_stats(filename: &~str, line_count: uint, word_count: uint, char_count: uint,
    byte_count: uint, longest_line_length: uint, matches: &Matches, max_str_len: uint) {
    if (matches.opt_present("lines")) {
        print!("{:1$}", line_count, max_str_len);
    }
    if (matches.opt_present("words")) {
        print!("{:1$}", word_count, max_str_len);
    }
    if (matches.opt_present("bytes")) {
        print!("{:1$}", byte_count, max_str_len + 1);
    }
    if (matches.opt_present("chars")) {
        print!("{:1$}", char_count, max_str_len);
    }
    if (matches.opt_present("max-line-length")) {
        print!("{:1$}", longest_line_length, max_str_len);
    }

    // defaults
    if (!matches.opt_present("bytes") && !matches.opt_present("chars") && !matches.opt_present("lines")
        && !matches.opt_present("words") && !matches.opt_present("max-line-length")) {
        print!("{:1$}", line_count, max_str_len);
        print!("{:1$}", word_count, max_str_len + 1);
        print!("{:1$}", byte_count, max_str_len + 1);
    }

    if (*filename != ~"-") {
        println!(" {}", *filename);
    }
    else {
        println("");
    }
}

fn open(path: ~str) -> Option<BufferedReader<~Reader>> {
    if "-" == path {
        let reader = ~stdin() as ~Reader;
        return Some(BufferedReader::new(reader));
    }

    match result(|| File::open(&std::path::Path::new(path.as_slice()))) {
        Ok(fd) => {
            let reader = ~fd as ~Reader;
            return Some(BufferedReader::new(reader));
        },
        Err(e) => {
            writeln!(&mut stderr() as &mut Writer, "wc: {0:s}: {1:s}", path, e.desc.to_str());
            os::set_exit_status(1);
        }
    }

    None
}
<|endoftext|>


<commit_before>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::cache::INTERNER;
use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
        && build
            .hosts
            .iter()
            .map(|host| {
                build
                    .config
                    .target_config
                    .get(host)
                    .map(|config| config.llvm_config.is_none())
                    .unwrap_or(true)
            })
            .any(|build_llvm_ourselves| build_llvm_ourselves);
    if building_llvm || build.config.any_sanitizers_enabled() {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.npm = build
        .config
        .npm
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("npm"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
        // Externally configured LLVM requires FileCheck to exist
        let filecheck = build.llvm_filecheck(build.build);
        if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
            panic!("FileCheck executable {:?} does not exist", filecheck);
        }
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        build
            .config
            .target_config
            .entry(*target)
            .or_insert_with(|| Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(*target).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<commit_msg>Don't require cmake on Windows when LLVM isn't being built<commit_after>//! Sanity checking performed by rustbuild before actually executing anything.
//!
//! This module contains the implementation of ensuring that the build
//! environment looks reasonable before progressing. This will verify that
//! various programs like git and python exist, along with ensuring that all C
//! compilers for cross-compiling are found.
//!
//! In theory if we get past this phase it's a bug if a build fails, but in
//! practice that's likely not true!

use std::collections::HashMap;
use std::env;
use std::ffi::{OsStr, OsString};
use std::fs;
use std::path::PathBuf;
use std::process::Command;

use build_helper::{output, t};

use crate::cache::INTERNER;
use crate::config::Target;
use crate::Build;

pub struct Finder {
    cache: HashMap<OsString, Option<PathBuf>>,
    path: OsString,
}

impl Finder {
    pub fn new() -> Self {
        Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() }
    }

    pub fn maybe_have<S: Into<OsString>>(&mut self, cmd: S) -> Option<PathBuf> {
        let cmd: OsString = cmd.into();
        let path = &self.path;
        self.cache
            .entry(cmd.clone())
            .or_insert_with(|| {
                for path in env::split_paths(path) {
                    let target = path.join(&cmd);
                    let mut cmd_exe = cmd.clone();
                    cmd_exe.push(".exe");

                    if target.is_file()                   // some/path/git
                    || path.join(&cmd_exe).exists()   // some/path/git.exe
                    || target.join(&cmd_exe).exists()
                    // some/path/git/git.exe
                    {
                        return Some(target);
                    }
                }
                None
            })
            .clone()
    }

    pub fn must_have<S: AsRef<OsStr>>(&mut self, cmd: S) -> PathBuf {
        self.maybe_have(&cmd).unwrap_or_else(|| {
            panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref());
        })
    }
}

pub fn check(build: &mut Build) {
    let path = env::var_os("PATH").unwrap_or_default();
    // On Windows, quotes are invalid characters for filename paths, and if
    // one is present as part of the PATH then that can lead to the system
    // being unable to identify the files properly. See
    // https://github.com/rust-lang/rust/issues/34959 for more details.
    if cfg!(windows) && path.to_string_lossy().contains('\"') {
        panic!("PATH contains invalid character '\"'");
    }

    let mut cmd_finder = Finder::new();
    // If we've got a git directory we're gonna need git to update
    // submodules and learn about various other aspects.
    if build.rust_info.is_git() {
        cmd_finder.must_have("git");
    }

    // We need cmake, but only if we're actually building LLVM or sanitizers.
    let building_llvm = build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm"))
        && build
            .hosts
            .iter()
            .map(|host| {
                build
                    .config
                    .target_config
                    .get(host)
                    .map(|config| config.llvm_config.is_none())
                    .unwrap_or(true)
            })
            .any(|build_llvm_ourselves| build_llvm_ourselves);
    let need_cmake = building_llvm || build.config.any_sanitizers_enabled();
    if need_cmake {
        cmd_finder.must_have("cmake");
    }

    build.config.python = build
        .config
        .python
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| env::var_os("BOOTSTRAP_PYTHON").map(PathBuf::from)) // set by bootstrap.py
        .or_else(|| Some(cmd_finder.must_have("python")));

    build.config.nodejs = build
        .config
        .nodejs
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("node"))
        .or_else(|| cmd_finder.maybe_have("nodejs"));

    build.config.npm = build
        .config
        .npm
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("npm"));

    build.config.gdb = build
        .config
        .gdb
        .take()
        .map(|p| cmd_finder.must_have(p))
        .or_else(|| cmd_finder.maybe_have("gdb"));

    // We're gonna build some custom C code here and there, host triples
    // also build some C++ shims for LLVM so we need a C++ compiler.
    for target in &build.targets {
        // On emscripten we don't actually need the C compiler to just
        // build the target artifacts, only for testing. For the sake
        // of easier bot configuration, just skip detection.
        if target.contains("emscripten") {
            continue;
        }

        // We don't use a C compiler on wasm32
        if target.contains("wasm32") {
            continue;
        }

        if !build.config.dry_run {
            cmd_finder.must_have(build.cc(*target));
            if let Some(ar) = build.ar(*target) {
                cmd_finder.must_have(ar);
            }
        }
    }

    for host in &build.hosts {
        if !build.config.dry_run {
            cmd_finder.must_have(build.cxx(*host).unwrap());
        }
    }

    if build.config.rust_codegen_backends.contains(&INTERNER.intern_str("llvm")) {
        // Externally configured LLVM requires FileCheck to exist
        let filecheck = build.llvm_filecheck(build.build);
        if !filecheck.starts_with(&build.out) && !filecheck.exists() && build.config.codegen_tests {
            panic!("FileCheck executable {:?} does not exist", filecheck);
        }
    }

    for target in &build.targets {
        // Can't compile for iOS unless we're on macOS
        if target.contains("apple-ios") && !build.build.contains("apple-darwin") {
            panic!("the iOS target is only supported on macOS");
        }

        build
            .config
            .target_config
            .entry(*target)
            .or_insert_with(|| Target::from_triple(&target.triple));

        if target.contains("-none-") || target.contains("nvptx") {
            if build.no_std(*target) == Some(false) {
                panic!("All the *-none-* and nvptx* targets are no-std targets")
            }
        }

        // Make sure musl-root is valid
        if target.contains("musl") {
            // If this is a native target (host is also musl) and no musl-root is given,
            // fall back to the system toolchain in /usr before giving up
            if build.musl_root(*target).is_none() && build.config.build == *target {
                let target = build.config.target_config.entry(*target).or_default();
                target.musl_root = Some("/usr".into());
            }
            match build.musl_libdir(*target) {
                Some(libdir) => {
                    if fs::metadata(libdir.join("libc.a")).is_err() {
                        panic!("couldn't find libc.a in musl libdir: {}", libdir.display());
                    }
                }
                None => panic!(
                    "when targeting MUSL either the rust.musl-root \
                            option or the target.$TARGET.musl-root option must \
                            be specified in config.toml"
                ),
            }
        }

        if need_cmake && target.contains("msvc") {
            // There are three builds of cmake on windows: MSVC, MinGW, and
            // Cygwin. The Cygwin build does not have generators for Visual
            // Studio, so detect that here and error.
            let out = output(Command::new("cmake").arg("--help"));
            if !out.contains("Visual Studio") {
                panic!(
                    "
cmake does not support Visual Studio generators.

This is likely due to it being an msys/cygwin build of cmake,
rather than the required windows version, built using MinGW
or Visual Studio.

If you are building under msys2 try installing the mingw-w64-x86_64-cmake
package instead of cmake:

$ pacman -R cmake && pacman -S mingw-w64-x86_64-cmake
"
                );
            }
        }
    }

    if let Some(ref s) = build.config.ccache {
        cmd_finder.must_have(s);
    }

    if build.config.channel == "stable" {
        let stage0 = t!(fs::read_to_string(build.src.join("src/stage0.txt")));
        if stage0.contains("\ndev:") {
            panic!(
                "bootstrapping from a dev compiler in a stable release, but \
                    should only be bootstrapping from a released compiler!"
            );
        }
    }
}
<|endoftext|>


<commit_before>use std::io::{self, Error};
use libc::{c_char, c_int, c_ulong, c_void, close, recvfrom, sendto, socket};

#[cfg(target_os = "linux")]
use libc::{sockaddr_ll, socklen_t, AF_AX25, AF_PACKET, SOCK_RAW};
#[cfg(target_os = "linux")]
use std::mem;
#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

#[cfg(target_os = "linux")]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        use std::fs::File;
        use std::io::{BufReader, BufRead};

        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }
}

#[cfg(not(target_os = "linux"))]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        Err(Error::new(ErrorKind::NotFound))
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        Err(Error::new(ErrorKind::NotFound))
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        Ok(Vec::new())
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        Err(Error::new(ErrorKind::NotConnected))
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        Err(Error::new(ErrorKind::NotConnected))
    }
}

#[cfg(target_os = "linux")]
fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Ok(addr) = String::from_utf8(addr_utf8) {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<commit_msg>Create errors correctly<commit_after>use libc::{c_char, c_int, c_ulong};
use std::io::{self, Error};

#[cfg(target_os = "linux")]
use libc::{
    c_void, close, recvfrom, sendto, sockaddr_ll, socket, socklen_t, AF_AX25, AF_PACKET, SOCK_RAW,
};
#[cfg(not(target_os = "linux"))]
use std::io::ErrorKind;
#[cfg(target_os = "linux")]
use std::mem;

const ETH_P_AX25: u16 = 0x0002; // from if_ether.h for SOCK_RAW
const SIOCGIFHWADDR: c_ulong = 0x8927; // from sockios.h in the linux kernel
const SIOCGIFINDEX: c_ulong = 0x8933;

/// An active AX.25 network interface, e.g. "ax0"
pub struct NetDev {
    pub name: String,
    pub ifindex: i32,
}

/// An open socket for sending and receiving AX.25 frames
pub struct Ax25RawSocket {
    fd: i32,
}

#[cfg(target_os = "linux")]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        match unsafe { socket(AF_PACKET, SOCK_RAW, ETH_P_AX25.to_be() as i32) } {
            -1 => Err(Error::last_os_error()),
            fd => Ok(Ax25RawSocket { fd }),
        }
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        match unsafe { close(self.fd) } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        use std::fs::File;
        use std::io::{BufRead, BufReader};

        let dev_file = File::open("/proc/net/dev")?;
        let mut devices: Vec<NetDev> = Vec::new();
        let reader = BufReader::new(dev_file);
        let lines = reader.lines();
        for l in lines.skip(2) {
            if let Ok(line) = l {
                let device_name = line.trim().split(':').next().unwrap();
                if let Some(net_dev) = get_ax25_netdev(&device_name, self.fd) {
                    devices.push(net_dev);
                }
            }
        }
        Ok(devices)
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        // The Linux interface demands a single null byte prefix on the actual packet
        let mut prefixed_frame: Vec<u8> = Vec::with_capacity(frame.len() + 1);
        prefixed_frame.push(0);
        prefixed_frame.extend(frame.iter().cloned());

        let sa = sockaddr_ll {
            sll_family: AF_PACKET as u16,
            sll_protocol: ETH_P_AX25.to_be(),
            sll_ifindex: ifindex,
            sll_hatype: 0,
            sll_pkttype: 0,
            sll_halen: 0,
            sll_addr: [0; 8],
        };

        match unsafe {
            let sa_ptr = &sa as *const libc::sockaddr_ll as *const libc::sockaddr;
            sendto(
                self.fd,
                prefixed_frame.as_ptr() as *const c_void,
                prefixed_frame.len(),
                0,
                sa_ptr,
                mem::size_of_val(&sa) as socklen_t,
            )
        } {
            -1 => Err(Error::last_os_error()),
            _ => Ok(()),
        }
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        let mut buf: [u8; 1024] = [0; 1024];
        // Not sure we need the address but it might come in handy someday
        let mut addr_struct: sockaddr_ll = unsafe { mem::zeroed() };
        let len: usize;
        unsafe {
            let sa_ptr = &mut addr_struct as *mut libc::sockaddr_ll as *mut libc::sockaddr;
            let mut sa_in_sz: socklen_t = mem::size_of::<sockaddr_ll>() as socklen_t;
            len = match recvfrom(
                self.fd,
                buf.as_mut_ptr() as *mut c_void,
                buf.len(),
                0,
                sa_ptr,
                &mut sa_in_sz,
            ) {
                -1 => return Err(Error::last_os_error()),
                len => len as usize,
            };
        }
        let valid_buf = &buf[0..len];

        // In practice AF_PACKET gives us one leading one null byte
        // These are unhelpful so we will skip all leading null bytes
        let filtered: Vec<u8> = valid_buf.iter().skip_while(|&c| *c == 0).cloned().collect();
        Ok(filtered)
    }
}

#[cfg(not(target_os = "linux"))]
impl Ax25RawSocket {
    /// Create a new socket for sending and receiving raw AX.25 frames. This requires root or CAP_NET_ADMIN.
    pub fn new() -> io::Result<Ax25RawSocket> {
        Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
    }

    /// Close an open AX.25 socket.
    pub fn close(&mut self) -> io::Result<()> {
        Err(Error::new(ErrorKind::NotFound, "only supported on linux"))
    }

    /// Find all AX.25 interfaces on the system
    pub fn list_ax25_interfaces(&self) -> io::Result<Vec<NetDev>> {
        Ok(Vec::new())
    }

    /// Send a frame to a particular interface, specified by its index
    pub fn send_frame(&self, frame: &[u8], ifindex: i32) -> io::Result<()> {
        Err(Error::new(
            ErrorKind::NotConnected,
            "only supported on linux",
        ))
    }

    /// Block to receive an incoming AX.25 frame from any interface
    pub fn receive_frame(&self) -> io::Result<Vec<u8>> {
        Err(Error::new(
            ErrorKind::NotConnected,
            "only supported on linux",
        ))
    }
}

#[cfg(target_os = "linux")]
fn get_ax25_netdev(name: &str, fd: i32) -> Option<NetDev> {
    let mut req = ifreq::default();
    let if_name = name.to_owned();
    for (d, s) in req.ifr_name.iter_mut().zip(if_name.as_bytes()) {
        *d = *s as c_char;
    }

    if unsafe { ioctl(fd, SIOCGIFHWADDR, &mut req) } == -1 {
        return None;
    }
    if req.data.address_family() as i32 != AF_AX25 {
        return None;
    }
    let hw_addr = match req.data.ax25_address() {
        Some(addr) => addr,
        None => return None,
    };

    if unsafe { ioctl(fd, SIOCGIFINDEX, &mut req) } == -1 {
        return None;
    }
    let ifindex = req.data.ifindex();

    Some(NetDev {
        name: hw_addr,
        ifindex,
    })
}

extern "C" {
    fn ioctl(fd: c_int, request: c_ulong, ifreq: *mut ifreq) -> c_int;
}

#[repr(C)]
struct ifreq {
    ifr_name: [c_char; 16],
    data: ifreq_union,
}

impl Default for ifreq {
    fn default() -> ifreq {
        ifreq {
            ifr_name: [0; 16],
            data: ifreq_union::default(),
        }
    }
}

#[repr(C)]
struct ifreq_union {
    data: [u8; 24],
}

impl Default for ifreq_union {
    fn default() -> ifreq_union {
        ifreq_union { data: [0; 24] }
    }
}

impl ifreq_union {
    fn ifindex(&self) -> c_int {
        c_int::from_be(
            ((self.data[0] as c_int) << 24)
                + ((self.data[1] as c_int) << 16)
                + ((self.data[2] as c_int) << 8)
                + (self.data[3] as c_int),
        )
    }

    fn address_family(&self) -> u16 {
        u16::from_be(((self.data[0] as u16) << 8) + (self.data[1] as u16))
    }

    fn ax25_address(&self) -> Option<String> {
        let mut addr_utf8: Vec<u8> = self.data[2..8]
            .iter()
            .rev()
            .map(|&c| c >> 1)
            .skip_while(|&c| c == 0)
            .collect::<Vec<u8>>();
        addr_utf8.reverse();
        let ssid = (self.data[8] >> 1) & 0x0f;
        if let Ok(addr) = String::from_utf8(addr_utf8) {
            return Some(format!("{}-{}", addr, ssid));
        }
        None
    }
}
<|endoftext|>


<commit_before>use std::collections::HashMap;
use std::string::FromUtf8Error;

use simple_bencode;
use simple_bencode::Value as BValue;
use simple_bencode::decoding_helpers::HelperDecodeError;

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
#[derive(Clone)]
pub struct RoutePacket {
    pub query: Option<String>,
    pub encoding_index: Option<i64>,
    pub encoding_scheme: Option<Vec<u8>>,
    pub nodes: Option<Vec<u8>>,
    pub node_protocol_versions: Option<Vec<u8>>,
    pub target_address: Option<Vec<u8>>,
    pub transaction_id: Vec<u8>,
    pub protocol_version: i64,
}

pub enum DecodeError {
    BencodeDecodeError(simple_bencode::DecodeError),
    BadType(String),
    MissingKey(String),
    UnicodeDecodeError(FromUtf8Error),
}

impl RoutePacket {
    pub fn decode(v: &[u8]) -> Result<RoutePacket, HelperDecodeError> {
        let bvalue = simple_bencode::decode(v);
        let mut map = match bvalue {
            Ok(BValue::Dictionary(map)) => map,
            Ok(v) => return Err(HelperDecodeError::BadType(format!("Expected dict at root, got: {:?}", v))),
            Err(e) => return Err(HelperDecodeError::BencodeDecodeError(e)),
        };
        //println!("{:?}", map);
        //println!("{:?}", map.keys().collect::<Vec<_>>().into_iter().map(|v| String::from_utf8(v.clone()).unwrap()).collect::<Vec<String>>()); // DEBUG: to show the keys in the messages
        let query = try!(simple_bencode::decoding_helpers::pop_value_utf8_string_option(&mut map, "q".to_owned()));
        let encoding_index = try!(simple_bencode::decoding_helpers::pop_value_integer_option(&mut map, "ei".to_owned()));
        let encoding_scheme = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "es".to_owned()));
        let nodes = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "n".to_owned()));
        let node_protocol_versions = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "np".to_owned()));
        let target_address = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "tar".to_owned()));
        let transaction_id = try!(simple_bencode::decoding_helpers::pop_value_bytestring(&mut map, "txid".to_owned()));
        let protocol_version = try!(simple_bencode::decoding_helpers::pop_value_integer(&mut map, "p".to_owned()));
        Ok(RoutePacket {
            query: query,
            encoding_index: encoding_index,
            encoding_scheme: encoding_scheme,
            nodes: nodes,
            node_protocol_versions: node_protocol_versions,
            target_address: target_address,
            transaction_id: transaction_id,
            protocol_version: protocol_version,
            })
    }

    pub fn encode(self) -> Vec<u8> {
        let mut map = HashMap::new();
        self.query.map(|q| map.insert(b"q".to_vec(), BValue::String(q.into_bytes().to_vec())));
        self.encoding_index.map(|ei| map.insert(b"ei".to_vec(), BValue::Integer(ei)));
        self.encoding_scheme.map(|es| map.insert(b"es".to_vec(), BValue::String(es)));
        self.nodes.map(|n| map.insert(b"n".to_vec(), BValue::String(n)));
        self.node_protocol_versions.map(|np| map.insert(b"np".to_vec(), BValue::String(np)));
        self.target_address.map(|tar| map.insert(b"tar".to_vec(), BValue::String(tar)));
        map.insert(b"txid".to_vec(), BValue::String(self.transaction_id));
        map.insert(b"p".to_vec(), BValue::Integer(self.protocol_version));
        simple_bencode::encode(&BValue::Dictionary(map))
    }
}

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

    #[test]
    fn test_fn() {
        let s = "d1:q2:fn3:tar16:abcdefghhijklmno4:txid5:12345e".as_bytes();
        let m = RoutePacket::FindNode {
            target_address: "abcdefghhijklmno".to_owned(),
            transaction_id: b"12345".to_vec()
        };

        let s_decoded = RoutePacket::decode(s);
        let m_encoded = m.clone().encode();

        assert_eq!(s_decoded.unwrap(), m);
        assert_eq!(m_encoded, s);
    }

    #[test]
    fn test_n() {
        let s = "d1:n80:cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde23456784:txid5:12345e".as_bytes();
        let m = RoutePacket::Nodes {
            nodes: "cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde2345678".to_owned(),
            transaction_id: b"12345".to_vec()
        };

        let s_decoded = RoutePacket::decode(s);
        let m_encoded = m.clone().encode();

        assert_eq!(s_decoded.unwrap(), m);
        assert_eq!(m_encoded, s);
    }

    #[test]
    fn test_gp() {
        let s = b"d002:eii0e2:es5:a\x14E\x81\x001:pi17e1:q2:gp3:tar8:\x00\x00\x00\x00\x00\x00\x00\x004:txid12:\x0b\xf2\x17\xf4\x92\xa4\xc4d\xc6\x03[\xdde";

        RoutePacket::decode(s).unwrap();
    }
}
<commit_msg>Fix RoutePacket tests.<commit_after>use std::collections::HashMap;
use std::string::FromUtf8Error;

use simple_bencode;
use simple_bencode::Value as BValue;
use simple_bencode::decoding_helpers::HelperDecodeError;

#[derive(Debug)]
#[derive(Eq)]
#[derive(PartialEq)]
#[derive(Clone)]
pub struct RoutePacket {
    pub query: Option<String>,
    pub encoding_index: Option<i64>,
    pub encoding_scheme: Option<Vec<u8>>,
    pub nodes: Option<Vec<u8>>,
    pub node_protocol_versions: Option<Vec<u8>>,
    pub target_address: Option<Vec<u8>>,
    pub transaction_id: Vec<u8>,
    pub protocol_version: i64,
}

pub enum DecodeError {
    BencodeDecodeError(simple_bencode::DecodeError),
    BadType(String),
    MissingKey(String),
    UnicodeDecodeError(FromUtf8Error),
}

impl RoutePacket {
    pub fn decode(v: &[u8]) -> Result<RoutePacket, HelperDecodeError> {
        let bvalue = simple_bencode::decode(v);
        let mut map = match bvalue {
            Ok(BValue::Dictionary(map)) => map,
            Ok(v) => return Err(HelperDecodeError::BadType(format!("Expected dict at root, got: {:?}", v))),
            Err(e) => return Err(HelperDecodeError::BencodeDecodeError(e)),
        };
        //println!("{:?}", map);
        //println!("{:?}", map.keys().collect::<Vec<_>>().into_iter().map(|v| String::from_utf8(v.clone()).unwrap()).collect::<Vec<String>>()); // DEBUG: to show the keys in the messages
        let query = try!(simple_bencode::decoding_helpers::pop_value_utf8_string_option(&mut map, "q".to_owned()));
        let encoding_index = try!(simple_bencode::decoding_helpers::pop_value_integer_option(&mut map, "ei".to_owned()));
        let encoding_scheme = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "es".to_owned()));
        let nodes = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "n".to_owned()));
        let node_protocol_versions = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "np".to_owned()));
        let target_address = try!(simple_bencode::decoding_helpers::pop_value_bytestring_option(&mut map, "tar".to_owned()));
        let transaction_id = try!(simple_bencode::decoding_helpers::pop_value_bytestring(&mut map, "txid".to_owned()));
        let protocol_version = try!(simple_bencode::decoding_helpers::pop_value_integer(&mut map, "p".to_owned()));
        Ok(RoutePacket {
            query: query,
            encoding_index: encoding_index,
            encoding_scheme: encoding_scheme,
            nodes: nodes,
            node_protocol_versions: node_protocol_versions,
            target_address: target_address,
            transaction_id: transaction_id,
            protocol_version: protocol_version,
            })
    }

    pub fn encode(self) -> Vec<u8> {
        let mut map = HashMap::new();
        self.query.map(|q| map.insert(b"q".to_vec(), BValue::String(q.into_bytes().to_vec())));
        self.encoding_index.map(|ei| map.insert(b"ei".to_vec(), BValue::Integer(ei)));
        self.encoding_scheme.map(|es| map.insert(b"es".to_vec(), BValue::String(es)));
        self.nodes.map(|n| map.insert(b"n".to_vec(), BValue::String(n)));
        self.node_protocol_versions.map(|np| map.insert(b"np".to_vec(), BValue::String(np)));
        self.target_address.map(|tar| map.insert(b"tar".to_vec(), BValue::String(tar)));
        map.insert(b"txid".to_vec(), BValue::String(self.transaction_id));
        map.insert(b"p".to_vec(), BValue::Integer(self.protocol_version));
        simple_bencode::encode(&BValue::Dictionary(map))
    }
}

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

    #[test]
    fn test_fn() {
        let s = "d1:pi18e1:q2:fn3:tar16:abcdefghhijklmno4:txid5:12345e".as_bytes();
        let m = RoutePacket {
            query: Some("fn".to_owned()),
            encoding_index: None,
            encoding_scheme: None,
            nodes: None,
            node_protocol_versions: None,
            target_address: Some(b"abcdefghhijklmno".to_vec()),
            transaction_id: b"12345".to_vec(),
            protocol_version: 18,
        };

        let s_decoded = RoutePacket::decode(s);
        let m_encoded = m.clone().encode();

        assert_eq!(s_decoded.unwrap(), m);
        assert_eq!(m_encoded, s);
    }

    #[test]
    fn test_n() {
        let s = "d1:n80:cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde23456781:pi18e4:txid5:12345e".as_bytes();
        let m = RoutePacket {
            query: None,
            encoding_index: None,
            encoding_scheme: None,
            nodes: Some(b"cdefghijklmnopqrstuvwxyzabcdefghi1234567qponmlkjihgzyxwvutsrstuvwxyzabcde2345678".to_vec()),
            node_protocol_versions: None,
            target_address: None,
            transaction_id: b"12345".to_vec(),
            protocol_version: 18,
        };

        let s_decoded = RoutePacket::decode(s);
        let m_encoded = m.clone().encode();

        assert_eq!(s_decoded.unwrap(), m);
        assert_eq!(m_encoded, s);
    }

    #[test]
    fn test_gp() {
        let s = b"d002:eii0e2:es5:a\x14E\x81\x001:pi17e1:q2:gp3:tar8:\x00\x00\x00\x00\x00\x00\x00\x004:txid12:\x0b\xf2\x17\xf4\x92\xa4\xc4d\xc6\x03[\xdde";

        RoutePacket::decode(s).unwrap();
    }
}
<|endoftext|>


<commit_before>// Copyright 2014 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.

// Verifies that the expected token errors for `extern crate` are
// raised

extern crate foo {} //~ERROR expected one of `=`, `;`, found `{`
<commit_msg>Update a test error message<commit_after>// Copyright 2014 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.

// Verifies that the expected token errors for `extern crate` are
// raised

extern crate foo {} //~ERROR expected `;`, found `{`
<|endoftext|>


<commit_before>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
extern crate dotenv;

use self::dotenv::dotenv;

pub use self::websocket::message::OwnedMessage;
use self::websocket::server::{WsServer, InvalidConnection};
use self::websocket::async::{Server, MessageCodec};
use self::websocket::client::async::Framed;
use self::websocket::server::NoTlsAcceptor;

use self::tokio_core::reactor::{Handle, Core};
use self::tokio_core::net::{TcpStream, TcpListener};

use self::futures::{Future, Sink, Stream};
use self::futures::sync::mpsc;
use self::futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::fmt::Debug;
use std::net::SocketAddr;

use util::read_env_var;

pub type SendChannel = mpsc::UnboundedSender<OwnedMessage>;
pub trait EventHandler {
    type Id: Send + Sync + Clone;
    fn new() -> Self;
    fn main_loop(&self);
    fn on_message(&self, id: Self::Id, msg: OwnedMessage);
    fn on_connect(&self, addr: SocketAddr, send_channel: SendChannel) -> Option<Self::Id>;
    fn on_disconnect(&self, id: Self::Id);
}

pub fn execute<T>()
where
    T: EventHandler + Send + Sync + 'static,
{
    dotenv().ok();

    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();

    let server = build_server(&handle);
    let pool = CpuPool::new(3);
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();
    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    let event_handler = T::new();
    let event_handler = Arc::new(event_handler);

    let event_handler_inner = event_handler.clone();
    let handle_inner = handle.clone();
    // Handle new connection
    let connection_handler = server
        .incoming()
        .map(|(upgrade, addr)| Some((upgrade, addr)))
        .or_else(|InvalidConnection { error, .. }| {
            println!("Client failed to connect: {}", error);
            Ok(None)
        })
        .for_each(move |conn| {
            if conn.is_none() {
                return Ok(());
            }
            let (upgrade, addr) = conn.unwrap();
            let event_handler = event_handler_inner.clone();
            let receive_channel = receive_channel_out.clone();
            let send_channel = send_channel_out.clone();
            let f = upgrade.accept().and_then(move |(framed, _)| {
                let (conn_out, conn_in) = mpsc::unbounded();
                let res = event_handler.on_connect(addr, conn_out);
                if let Some(id) = res {
                    let (sink, stream) = framed.split();
                    send_channel
                        .send((id.clone(), conn_in, sink))
                        .wait()
                        .unwrap();
                    receive_channel.send((id, stream)).wait().unwrap();
                }
                Ok(())
            });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|e: ()| e);

    // Handle receiving messages from a client
    let event_handler_inner = event_handler.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let event_handler = event_handler_inner.clone();
            remote_inner.spawn(move |_| {
                stream
                    .for_each(move |msg| {
                        let id = id.clone();
                        if let OwnedMessage::Close(_) = msg {
                            event_handler.on_disconnect(id);
                        } else {
                            event_handler.on_message(id, msg);
                        }
                        Ok(())
                    })
                    .map_err(|e| println!("Error while receiving messages: {}", e))
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while receiving messages: {:?}", e));

    // Handle sending messages to a client
    let event_handler_inner = event_handler.clone();
    let send_handler = pool.spawn_fn(move || {
        let remote = remote.clone();
        let event_handler = event_handler_inner.clone();
        type SinkContent = Framed<TcpStream, MessageCodec<OwnedMessage>>;
        type SplitSink = futures::stream::SplitSink<SinkContent>;
        send_channel_in.for_each(
            move |(id, conn_in, sink): (T::Id,
                                        mpsc::UnboundedReceiver<OwnedMessage>,
                                        SplitSink)| {
                let sink = Arc::new(RwLock::new(sink));
                let event_handler = event_handler.clone();
                remote.spawn(move |_| {
                    conn_in.for_each(move |msg: OwnedMessage| {
                        let mut sink = sink.write().unwrap();
                        let ok_send = sink.start_send(msg).is_ok();
                        let ok_poll = sink.poll_complete().is_ok();
                        if !ok_send || !ok_poll {
                            println!("Failed to send, kicking client");
                            event_handler.on_disconnect(id.clone());
                        }
                        Ok(())
                    })
                });
                Ok(())
            },
        )
    }).map_err(|e| println!("Error while sending messages: {:?}", e));

    // Run main loop
    let main_fn = pool.spawn_fn(move || {
        event_handler.main_loop();
        Ok::<(), ()>(())
    }).map_err(|e| println!("Error in main callback function: {:?}", e));

    let handlers = main_fn.select2(connection_handler.select2(
        receive_handler.select(send_handler),
    ));

    core.run(handlers)
        .map_err(|_| println!("Unspecified error while running core loop"))
        .unwrap();
}

pub fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
where
    F: Future<Item = I, Error = E> + 'static,
    E: Debug,
{
    handle.spawn(
        f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
            .map(move |_| ()),
    );
}

fn build_server(handle: &Handle) -> WsServer<NoTlsAcceptor, TcpListener> {
    let address = format!("localhost:{}", read_env_var("CORE_PORT"));
    Server::bind(address, handle).expect("Failed to create server")
}
<commit_msg>Core: Add client interaction messages<commit_after>extern crate websocket;
extern crate futures;
extern crate futures_cpupool;
extern crate tokio_core;
extern crate serde;
extern crate serde_json;
extern crate dotenv;

use self::dotenv::dotenv;

pub use self::websocket::message::OwnedMessage;
use self::websocket::server::{WsServer, InvalidConnection};
use self::websocket::async::{Server, MessageCodec};
use self::websocket::client::async::Framed;
use self::websocket::server::NoTlsAcceptor;

use self::tokio_core::reactor::{Handle, Core};
use self::tokio_core::net::{TcpStream, TcpListener};

use self::futures::{Future, Sink, Stream};
use self::futures::sync::mpsc;
use self::futures_cpupool::CpuPool;

use std::sync::{RwLock, Arc};
use std::fmt::Debug;
use std::net::SocketAddr;
use std::fmt::Display;

use util::read_env_var;

pub type SendChannel = mpsc::UnboundedSender<OwnedMessage>;
pub trait EventHandler {
    type Id: Send + Sync + Clone + Debug + Display;
    fn new() -> Self;
    fn main_loop(&self);
    fn on_message(&self, id: Self::Id, msg: OwnedMessage);
    fn on_connect(&self, addr: SocketAddr, send_channel: SendChannel) -> Option<Self::Id>;
    fn on_disconnect(&self, id: Self::Id);
}

pub fn execute<T>()
where
    T: EventHandler + Send + Sync + 'static,
{
    dotenv().ok();

    let mut core = Core::new().expect("Failed to create Tokio event loop");
    let handle = core.handle();
    let remote = core.remote();

    let server = build_server(&handle);
    let pool = CpuPool::new(3);
    let (receive_channel_out, receive_channel_in) = mpsc::unbounded();
    let (send_channel_out, send_channel_in) = mpsc::unbounded();

    let event_handler = T::new();
    let event_handler = Arc::new(event_handler);

    let event_handler_inner = event_handler.clone();
    let handle_inner = handle.clone();
    // Handle new connection
    let connection_handler = server
        .incoming()
        .map(|(upgrade, addr)| Some((upgrade, addr)))
        .or_else(|InvalidConnection { error, .. }| {
            println!("Client failed to connect: {}", error);
            Ok(None)
        })
        .for_each(move |conn| {
            if conn.is_none() {
                return Ok(());
            }
            let (upgrade, addr) = conn.unwrap();
            let event_handler = event_handler_inner.clone();
            let receive_channel = receive_channel_out.clone();
            let send_channel = send_channel_out.clone();
            let f = upgrade.accept().and_then(move |(framed, _)| {
                let (conn_out, conn_in) = mpsc::unbounded();
                let res = event_handler.on_connect(addr, conn_out);
                if let Some(id) = res {
                    println!("Client {}: Connect", id);
                    let (sink, stream) = framed.split();
                    send_channel
                        .send((id.clone(), conn_in, sink))
                        .wait()
                        .unwrap();
                    receive_channel.send((id, stream)).wait().unwrap();
                }
                Ok(())
            });
            spawn_future(f, "Handle new connection", &handle_inner);
            Ok(())
        })
        .map_err(|e: ()| e);

    // Handle receiving messages from a client
    let event_handler_inner = event_handler.clone();
    let remote_inner = remote.clone();
    let receive_handler = pool.spawn_fn(|| {
        receive_channel_in.for_each(move |(id, stream)| {
            let event_handler = event_handler_inner.clone();
            remote_inner.spawn(move |_| {
                stream
                    .for_each(move |msg| {
                        let id = id.clone();
                        if let OwnedMessage::Close(_) = msg {
                            println!("Client {}: Disconnect", id);
                            event_handler.on_disconnect(id);
                        } else {
                            println!("Client {}: Received message {:?}", id, msg);
                            event_handler.on_message(id, msg);
                        }
                        Ok(())
                    })
                    .map_err(|e| println!("Error while receiving messages: {}", e))
            });
            Ok(())
        })
    }).map_err(|e| println!("Error while receiving messages: {:?}", e));

    // Handle sending messages to a client
    let event_handler_inner = event_handler.clone();
    let send_handler = pool.spawn_fn(move || {
        let remote = remote.clone();
        let event_handler = event_handler_inner.clone();
        type SinkContent = Framed<TcpStream, MessageCodec<OwnedMessage>>;
        type SplitSink = futures::stream::SplitSink<SinkContent>;
        send_channel_in.for_each(
            move |(id, conn_in, sink): (T::Id,
                                        mpsc::UnboundedReceiver<OwnedMessage>,
                                        SplitSink)| {
                let sink = Arc::new(RwLock::new(sink));
                let event_handler = event_handler.clone();
                remote.spawn(move |_| {
                    conn_in.for_each(move |msg: OwnedMessage| {
                        let mut sink = sink.write().unwrap();
                        let ok_send = sink.start_send(msg).is_ok();
                        let ok_poll = sink.poll_complete().is_ok();
                        if !ok_send || !ok_poll {
                            println!(
                                "Client {}: Forced disconnect (failed to receive message)",
                                id
                            );
                            event_handler.on_disconnect(id.clone());
                        }
                        Ok(())
                    })
                });
                Ok(())
            },
        )
    }).map_err(|e| println!("Error while sending messages: {:?}", e));

    // Run main loop
    let main_fn = pool.spawn_fn(move || {
        event_handler.main_loop();
        Ok::<(), ()>(())
    }).map_err(|e| println!("Error in main callback function: {:?}", e));

    let handlers = main_fn.select2(connection_handler.select2(
        receive_handler.select(send_handler),
    ));

    core.run(handlers)
        .map_err(|_| println!("Unspecified error while running core loop"))
        .unwrap();
}

pub fn spawn_future<F, I, E>(f: F, desc: &'static str, handle: &Handle)
where
    F: Future<Item = I, Error = E> + 'static,
    E: Debug,
{
    handle.spawn(
        f.map_err(move |e| println!("Error in {}: '{:?}'", desc, e))
            .map(move |_| ()),
    );
}

fn build_server(handle: &Handle) -> WsServer<NoTlsAcceptor, TcpListener> {
    let address = format!("localhost:{}", read_env_var("CORE_PORT"));
    Server::bind(address, handle).expect("Failed to create server")
}
<|endoftext|>


<commit_before>// Copyright 2022 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.

use std::io;
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixListener;
use std::path::{Path, PathBuf};

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{get_max_open_files, RawDescriptor, UnlinkUnixListener};
use cros_async::Executor;
use minijail::{self, Minijail};

use crate::virtio::vhost::user::device::fs::{FsBackend, Options};
use crate::virtio::vhost::user::device::handler::{DeviceRequestHandler, VhostUserBackend};
use crate::virtio::vhost::user::device::vvu::pci::VvuPciDevice;

fn default_uidmap() -> String {
    let euid = unsafe { libc::geteuid() };
    format!("{} {} 1", euid, euid)
}

fn default_gidmap() -> String {
    let egid = unsafe { libc::getegid() };
    format!("{} {} 1", egid, egid)
}

fn jail_and_fork(
    mut keep_rds: Vec<RawDescriptor>,
    dir_path: PathBuf,
    uid_map: Option<String>,
    gid_map: Option<String>,
) -> anyhow::Result<i32> {
    // Create new minijail sandbox
    let mut j = Minijail::new()?;

    j.namespace_pids();
    j.namespace_user();
    j.namespace_user_disable_setgroups();
    j.uidmap(&uid_map.unwrap_or_else(default_uidmap))?;
    j.gidmap(&gid_map.unwrap_or_else(default_gidmap))?;
    j.run_as_init();

    j.namespace_vfs();
    j.namespace_net();
    j.no_new_privs();

    // Only pivot_root if we are not re-using the current root directory.
    if dir_path != Path::new("/") {
        // It's safe to call `namespace_vfs` multiple times.
        j.namespace_vfs();
        j.enter_pivot_root(&dir_path)?;
    }
    j.set_remount_mode(libc::MS_SLAVE);

    let limit = get_max_open_files().context("failed to get max open files")?;
    j.set_rlimit(libc::RLIMIT_NOFILE as i32, limit, limit)?;
    // vvu locks around 512k memory. Just give 1M.
    j.set_rlimit(libc::RLIMIT_MEMLOCK as i32, 1 << 20, 1 << 20)?;

    // Make sure there are no duplicates in keep_rds
    keep_rds.dedup();

    // fork on the jail here
    let pid = unsafe { j.fork(Some(&keep_rds))? };

    if pid > 0 {
        unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM) };
    }

    if pid < 0 {
        bail!("Fork error! {}", std::io::Error::last_os_error());
    }

    Ok(pid)
}

/// Starts a vhost-user fs device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn start_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };

    base::syslog::init().context("Failed to initialize syslog")?;

    let ex = Executor::new().context("Failed to create executor")?;
    let fs_device = FsBackend::new(&ex, &opts.tag)?;

    let mut keep_rds = fs_device.keep_rds.clone();
    let listener = match opts.socket {
        None => None,
        Some(socket) => {
            // Create and bind unix socket
            let l = UnixListener::bind(socket).map(UnlinkUnixListener)?;
            keep_rds.push(l.as_raw_fd());
            Some(l)
        }
    };
    base::syslog::push_descriptors(&mut keep_rds);

    let handler = DeviceRequestHandler::new(fs_device);

    let pid = jail_and_fork(keep_rds, opts.shared_dir, opts.uid_map, opts.gid_map)?;

    // Parent, nothing to do but wait and then exit
    if pid != 0 {
        unsafe { libc::waitpid(pid, std::ptr::null_mut(), 0) };
        return Ok(());
    }

    // We need to set the no setuid fixup secure bit so that we don't drop capabilities when
    // changing the thread uid/gid. Without this, creating new entries can fail in some corner
    // cases.
    const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;

    // TODO(crbug.com/1199487): Remove this once libc provides the wrapper for all targets.
    #[cfg(target_os = "linux")]
    {
        // Safe because this doesn't modify any memory and we check the return value.
        let mut securebits = unsafe { libc::prctl(libc::PR_GET_SECUREBITS) };
        if securebits < 0 {
            bail!(io::Error::last_os_error());
        }
        securebits |= SECBIT_NO_SETUID_FIXUP;
        // Safe because this doesn't modify any memory and we check the return value.
        let ret = unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) };
        if ret < 0 {
            bail!(io::Error::last_os_error());
        }
    }

    let res = match (listener, opts.vfio) {
        (Some(l), None) => ex.run_until(handler.run_with_listener(l, &ex))?,
        (None, Some(vfio)) => {
            let device = VvuPciDevice::new(&vfio, FsBackend::MAX_QUEUE_NUM)?;
            ex.run_until(handler.run_vvu(device, &ex))?
        }
        _ => Err(anyhow!("exactly one of `--socket` or `--vfio` is required")),
    };
    res
}
<commit_msg>devices: vhost-user: fs: open vvu device outside jail.<commit_after>// Copyright 2022 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.

use std::io;
use std::os::unix::io::AsRawFd;
use std::os::unix::net::UnixListener;
use std::path::{Path, PathBuf};

use anyhow::{anyhow, bail, Context};
use argh::FromArgs;
use base::{get_max_open_files, AsRawDescriptor, RawDescriptor, UnlinkUnixListener};
use cros_async::Executor;
use minijail::{self, Minijail};

use crate::virtio::vhost::user::device::fs::{FsBackend, Options};
use crate::virtio::vhost::user::device::handler::{DeviceRequestHandler, VhostUserBackend};
use crate::virtio::vhost::user::device::vvu::pci::VvuPciDevice;

fn default_uidmap() -> String {
    let euid = unsafe { libc::geteuid() };
    format!("{} {} 1", euid, euid)
}

fn default_gidmap() -> String {
    let egid = unsafe { libc::getegid() };
    format!("{} {} 1", egid, egid)
}

fn jail_and_fork(
    mut keep_rds: Vec<RawDescriptor>,
    dir_path: PathBuf,
    uid_map: Option<String>,
    gid_map: Option<String>,
) -> anyhow::Result<i32> {
    // Create new minijail sandbox
    let mut j = Minijail::new()?;

    j.namespace_pids();
    j.namespace_user();
    j.namespace_user_disable_setgroups();
    j.uidmap(&uid_map.unwrap_or_else(default_uidmap))?;
    j.gidmap(&gid_map.unwrap_or_else(default_gidmap))?;
    j.run_as_init();

    j.namespace_vfs();
    j.namespace_net();
    j.no_new_privs();

    // Only pivot_root if we are not re-using the current root directory.
    if dir_path != Path::new("/") {
        // It's safe to call `namespace_vfs` multiple times.
        j.namespace_vfs();
        j.enter_pivot_root(&dir_path)?;
    }
    j.set_remount_mode(libc::MS_SLAVE);

    let limit = get_max_open_files().context("failed to get max open files")?;
    j.set_rlimit(libc::RLIMIT_NOFILE as i32, limit, limit)?;
    // vvu locks around 512k memory. Just give 1M.
    j.set_rlimit(libc::RLIMIT_MEMLOCK as i32, 1 << 20, 1 << 20)?;

    // Make sure there are no duplicates in keep_rds
    keep_rds.dedup();

    // fork on the jail here
    let pid = unsafe { j.fork(Some(&keep_rds))? };

    if pid > 0 {
        unsafe { libc::prctl(libc::PR_SET_PDEATHSIG, libc::SIGTERM) };
    }

    if pid < 0 {
        bail!("Fork error! {}", std::io::Error::last_os_error());
    }

    Ok(pid)
}

/// Starts a vhost-user fs device.
/// Returns an error if the given `args` is invalid or the device fails to run.
pub fn start_device(program_name: &str, args: &[&str]) -> anyhow::Result<()> {
    let opts = match Options::from_args(&[program_name], args) {
        Ok(opts) => opts,
        Err(e) => {
            if e.status.is_err() {
                bail!(e.output);
            } else {
                println!("{}", e.output);
            }
            return Ok(());
        }
    };

    base::syslog::init().context("Failed to initialize syslog")?;

    let ex = Executor::new().context("Failed to create executor")?;
    let fs_device = FsBackend::new(&ex, &opts.tag)?;

    let mut keep_rds = fs_device.keep_rds.clone();
    let listener = match opts.socket {
        None => None,
        Some(socket) => {
            // Create and bind unix socket
            let l = UnixListener::bind(socket).map(UnlinkUnixListener)?;
            keep_rds.push(l.as_raw_fd());
            Some(l)
        }
    };
    let device = match opts.vfio {
        None => None,
        Some(vfio) => {
            let d = VvuPciDevice::new(&vfio, FsBackend::MAX_QUEUE_NUM)?;
            keep_rds.extend(d.irqs.iter().map(|e| e.as_raw_descriptor()));
            keep_rds.extend(d.notification_evts.iter().map(|e| e.as_raw_descriptor()));
            keep_rds.push(d.vfio_dev.device_file().as_raw_fd());
            Some(d)
        }
    };
    base::syslog::push_descriptors(&mut keep_rds);

    let handler = DeviceRequestHandler::new(fs_device);

    let pid = jail_and_fork(keep_rds, opts.shared_dir, opts.uid_map, opts.gid_map)?;

    // Parent, nothing to do but wait and then exit
    if pid != 0 {
        unsafe { libc::waitpid(pid, std::ptr::null_mut(), 0) };
        return Ok(());
    }

    // We need to set the no setuid fixup secure bit so that we don't drop capabilities when
    // changing the thread uid/gid. Without this, creating new entries can fail in some corner
    // cases.
    const SECBIT_NO_SETUID_FIXUP: i32 = 1 << 2;

    // TODO(crbug.com/1199487): Remove this once libc provides the wrapper for all targets.
    #[cfg(target_os = "linux")]
    {
        // Safe because this doesn't modify any memory and we check the return value.
        let mut securebits = unsafe { libc::prctl(libc::PR_GET_SECUREBITS) };
        if securebits < 0 {
            bail!(io::Error::last_os_error());
        }
        securebits |= SECBIT_NO_SETUID_FIXUP;
        // Safe because this doesn't modify any memory and we check the return value.
        let ret = unsafe { libc::prctl(libc::PR_SET_SECUREBITS, securebits) };
        if ret < 0 {
            bail!(io::Error::last_os_error());
        }
    }

    let res = match (listener, device) {
        (Some(l), None) => ex.run_until(handler.run_with_listener(l, &ex))?,
        (None, Some(d)) => ex.run_until(handler.run_vvu(d, &ex))?,
        _ => Err(anyhow!("exactly one of `--socket` or `--vfio` is required")),
    };
    res
}
<|endoftext|>


<commit_before>// Copyright 2017 `multipart-async` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 futures::{Future, Stream, Async, Poll};
use futures::Async::*;

use mime::Mime;

use std::{io, mem, str};

use server::boundary::BoundaryFinder;
use server::{BodyChunk, StreamError, Multipart, httparse, twoway};

use self::httparse::EMPTY_HEADER;

use helpers::*;

const MAX_BUF_LEN: usize = 1024;
const MAX_HEADERS: usize = 4;

pub struct NextField<S: Stream> {
    stream: SomeCell<BoundaryFinder<S>>,
    accumulator: Vec<u8>,
    headers: Option<Headers>,
}

pub fn next_field<S: Stream>(stream: BoundaryFinder<S>) -> NextField<S> {
    NextField {
        stream: SomeCell::new(stream, "NextField value already taken"),
        accumulator: Vec::new(),
        headers: None,
    }
}

impl<S: Stream> NextField<S> where S::Item: BodyChunk, S::Error: StreamError {
    fn read_headers(&mut self) -> Poll<Headers, S::Error> {
        if let Some(headers) = self.headers.take() {
            return ready(headers);
        }

        loop {
            let chunk = try_ready!(self.stream.poll())
                .ok_or_else(|| io_error("unexpected end of stream"))?;

            // End of the headers section is signalled by a double-CRLF
            if let Some(header_end) = twoway::find_bytes(chunk.as_slice(), b"\r\n\r\n") {
                // Split after the double-CRLF because we don't want to yield it and httparse expects it
                let (headers, rem) = chunk.split_at(header_end + 4);
                self.stream.try_as_mut()?.push_chunk(rem);

                if !self.accumulator.is_empty() {
                    self.accumulator.extend_from_slice(headers.as_slice());
                    let headers = parse_headers(&self.accumulator)?;
                    self.accumulator.clear();

                    break ready(headers);
                } else {
                    break ready(parse_headers(headers.as_slice())?);
                }
            } else if let Some(split_idx) = header_end_split(&self.accumulator, chunk.as_slice()) {
                let (head, tail) = chunk.split_at(split_idx);
                self.accumulator.extend_from_slice(head.as_slice());
                continue;
            }

            // TODO: edge case where double-CRLF falls on chunk boundaries

            if self.accumulator.len().saturating_add(chunk.len()) > MAX_BUF_LEN {
                return error("headers section too long or trailing double-CRLF missing");
            }

            self.accumulator.extend_from_slice(chunk.as_slice());
        }
    }

    fn read_to_string(&mut self) -> Poll<String, S::Error> {
        loop {
            if self.accumulator.is_empty() {
                self.accumulator = try_ready!(self.stream.poll())
                    .map_or(Vec::new(), BodyChunk::into_vec);
            }

            match try_ready!(self.stream.poll()) {
                Some(chunk) => self.accumulator.extend_from_slice(chunk.as_slice()),
                None => return ready(String::from_utf8(self.take_accumulator())?),
            }
         }
    }

    fn take_accumulator(&mut self) -> Vec<u8> {
        mem::replace(&mut self.accumulator, Vec::new())
    }
}
impl<S: Stream> Future for NextField<S> where S::Item: BodyChunk, S::Error: StreamError {
    type Item = Field<S>;
    type Error = S::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let headers = try_ready!(self.read_headers());

        let data = if let Some(cont_type) = headers.cont_type {
            FieldData::File(FileData {
                content_type: cont_type,
                filename: headers.filename,
                multipart: Multipart { stream: self.stream.try_take()? },
                _priv: (),
            })
        } else if let Ready(text) = self.read_to_string()? {
            FieldData::Text(
                TextData {
                    text: text,
                    multipart: Multipart { stream: self.stream.try_take()? },
                    _priv: (),
                }
            )
        } else {
            self.headers = Some(headers);
            return not_ready();
        };

        ready(Field {
            name: headers.name,
            data: data,
            _priv: (),
        })
    }
}

const CRLF2: &[u8] = b"\r\n\r\n";

/// Check if the double-CRLF falls between chunk boundaries, and if so, the split index of
/// the second boundary
fn header_end_split(first: &[u8], second: &[u8]) -> Option<usize> {
    fn split_subcheck(start: usize, first: &[u8], second: &[u8]) -> bool {
        first.len() >= start && first[first.len() - start ..].iter().chain(second).take(4).eq(CRLF2)
    }

    let len = first.len();

    if split_subcheck(3, first, second) {
        Some(1)
    } else if split_subcheck(2, first, second) {
        Some(2)
    } else if split_subcheck(1, first, second) {
        Some(3)
    } else {
        None
    }
}

fn parse_headers(bytes: &[u8]) -> io::Result<Headers> {
    debug_assert!(bytes.ends_with(b"\r\n\r\n"),
                  "header byte sequence does not end with `\\r\\n\\r\\n`: {}",
                  show_bytes(bytes));

    unimplemented!()
}
    let mut header_buf = [EMPTY_HEADER; MAX_HEADERS];

    let (_, headers) = httparse::parse_headers(bytes, &mut header_buf).map_err(io_error)?;

    let mut out_headers = Headers::default();

    for header in headers {
        let str_val = str::from_utf8(header.value)
            .map_err(|_| io_error("multipart field headers must be UTF-8 encoded"))?
            .trim();

        match header.name {
            "Content-Disposition" => parse_cont_disp_val(str_val, &mut out_headers)?,
            "Content-Type" => out_headers.cont_type = Some(str_val.parse::<Mime>().map_err(io_error)),
        }
    }

    Ok(out_headers)
}

fn parse_cont_disp_val(val: &str, out: &mut Headers) -> io::Result<()> {
    // Only take the first section, the rest can be in quoted strings that we want to handle
    let mut sections = val.splitn(';', 1).map(str::trim);

    match sections.next() {
        Some("form-data") => (),
        Some(other) => error(format!("unexpected multipart field Content-Disposition: {}", other))?,
        None => error("each multipart field requires a Content-Disposition: form-data header")?,
    }

    let keyvals = sections.next().unwrap_or("");

    for section in sections {
        if section.starts_with("name") {
            out.name =
        }
    }

    if out.name.is_empty() {
        return error(format!("expected 'name' attribute in Content-Disposition: {}", val));
    }

    Ok(())
}

fn collect_param_val

#[derive(Default)]
struct Headers {
    name: String,
    cont_type: Option<Mime>,
    filename: Option<String>,
}

pub struct Field<S: Stream> {
    pub name: String,
    pub data: FieldData<S>,
    _priv: (),
}

pub enum FieldData<S: Stream> {
    Text(TextData<S>),
    File(FileData<S>),
}

pub struct TextData<S: Stream> {
    pub text: String,
    pub multipart: Multipart<S>,
    _priv: (),
}

pub struct FileData<S: Stream> {
    pub filename: Option<String>,
    pub content_type: Mime,
    pub multipart: Multipart<S>,
    _priv: (),
}

const CONT_DISP: &str = "Content-Disposition";

#[test]
fn test_header_end_split() {
    assert_eq!(header_end_split(b"\r\n\r", b"\n"), Some(1));
    assert_eq!(header_end_split(b"\r\n", b"\r\n"), Some(2));
    assert_eq!(header_end_split(b"\r", b"\n\r\n"), Some(3));
    assert_eq!(header_end_split(b"\r\n\r\n", b"FOOBAR"), None);
    assert_eq!(header_end_split(b"FOOBAR", b"\r\n\r\n"), None);
}
<commit_msg>Implement field header parsing<commit_after>// Copyright 2017 `multipart-async` Crate Developers
//
// Licensed under the Apache License, Version 2.0, <LICENSE-APACHE or
// http://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 futures::{Future, Stream, Async, Poll};
use futures::Async::*;

use mime::Mime;

use std::{io, mem, str};

use server::boundary::BoundaryFinder;
use server::{BodyChunk, StreamError, Multipart, httparse, twoway};

use self::httparse::EMPTY_HEADER;

use helpers::*;

const MAX_BUF_LEN: usize = 1024;
const MAX_HEADERS: usize = 4;

pub struct NextField<S: Stream> {
    stream: SomeCell<BoundaryFinder<S>>,
    accumulator: Vec<u8>,
    headers: Option<Headers>,
}

pub fn next_field<S: Stream>(stream: BoundaryFinder<S>) -> NextField<S> {
    NextField {
        stream: SomeCell::new(stream, "NextField value already taken"),
        accumulator: Vec::new(),
        headers: None,
    }
}

impl<S: Stream> NextField<S> where S::Item: BodyChunk, S::Error: StreamError {
    fn read_headers(&mut self) -> Poll<Headers, S::Error> {
        if let Some(headers) = self.headers.take() {
            return ready(headers);
        }

        loop {
            let chunk = try_ready!(self.stream.poll())
                .ok_or_else(|| io_error("unexpected end of stream"))?;

            // End of the headers section is signalled by a double-CRLF
            if let Some(header_end) = twoway::find_bytes(chunk.as_slice(), b"\r\n\r\n") {
                // Split after the double-CRLF because we don't want to yield it and httparse expects it
                let (headers, rem) = chunk.split_at(header_end + 4);
                self.stream.try_as_mut()?.push_chunk(rem);

                if !self.accumulator.is_empty() {
                    self.accumulator.extend_from_slice(headers.as_slice());
                    let headers = parse_headers(&self.accumulator)?;
                    self.accumulator.clear();

                    return ready(headers);
                } else {
                    return ready(parse_headers(headers.as_slice())?);
                }
            } else if let Some(split_idx) = header_end_split(&self.accumulator, chunk.as_slice()) {
                let (head, tail) = chunk.split_at(split_idx);
                self.accumulator.extend_from_slice(head.as_slice());
                continue;
            }

            // TODO: edge case where double-CRLF falls on chunk boundaries

            if self.accumulator.len().saturating_add(chunk.len()) > MAX_BUF_LEN {
                return error("headers section too long or trailing double-CRLF missing");
            }

            self.accumulator.extend_from_slice(chunk.as_slice());
        }
    }

    fn read_to_string(&mut self) -> Poll<String, S::Error> {
        loop {
            if self.accumulator.is_empty() {
                self.accumulator = try_ready!(self.stream.poll())
                    .map_or(Vec::new(), BodyChunk::into_vec);
            }

            match try_ready!(self.stream.poll()) {
                Some(chunk) => self.accumulator.extend_from_slice(chunk.as_slice()),
                None => return ready(String::from_utf8(self.take_accumulator())?),
            }
         }
    }

    fn take_accumulator(&mut self) -> Vec<u8> {
        mem::replace(&mut self.accumulator, Vec::new())
    }
}
impl<S: Stream> Future for NextField<S> where S::Item: BodyChunk, S::Error: StreamError {
    type Item = Field<S>;
    type Error = S::Error;

    fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
        let headers = try_ready!(self.read_headers());

        let data = if let Some(cont_type) = headers.cont_type {
            FieldData::File(FileData {
                content_type: cont_type,
                filename: headers.filename,
                multipart: Multipart { stream: self.stream.try_take()? },
                _priv: (),
            })
        } else if let Ready(text) = self.read_to_string()? {
            FieldData::Text(
                TextData {
                    text: text,
                    multipart: Multipart { stream: self.stream.try_take()? },
                    _priv: (),
                }
            )
        } else {
            self.headers = Some(headers);
            return not_ready();
        };

        ready(Field {
            name: headers.name,
            data: data,
            _priv: (),
        })
    }
}

const CRLF2: &[u8] = b"\r\n\r\n";

/// Check if the double-CRLF falls between chunk boundaries, and if so, the split index of
/// the second boundary
fn header_end_split(first: &[u8], second: &[u8]) -> Option<usize> {
    fn split_subcheck(start: usize, first: &[u8], second: &[u8]) -> bool {
        first.len() >= start && first[first.len() - start ..].iter().chain(second).take(4).eq(CRLF2)
    }

    let len = first.len();

    if split_subcheck(3, first, second) {
        Some(1)
    } else if split_subcheck(2, first, second) {
        Some(2)
    } else if split_subcheck(1, first, second) {
        Some(3)
    } else {
        None
    }
}

fn parse_headers(bytes: &[u8]) -> io::Result<Headers> {
    debug_assert!(bytes.ends_with(b"\r\n\r\n"),
                  "header byte sequence does not end with `\\r\\n\\r\\n`: {}",
                  show_bytes(bytes));

    let mut header_buf = [EMPTY_HEADER; MAX_HEADERS];

    let (_, headers) = httparse::parse_headers(bytes, &mut header_buf).map_err(io_error)?;

    let mut out_headers = Headers::default();

    for header in headers {
        let str_val = str::from_utf8(header.value)
            .map_err(|_| io_error("multipart field headers must be UTF-8 encoded"))?
            .trim();

        match header.name {
            "Content-Disposition" => parse_cont_disp_val(str_val, &mut out_headers)?,
            "Content-Type" => out_headers.cont_type = Some(str_val.parse::<Mime>().map_err(io_error)),
        }
    }

    Ok(out_headers)
}

fn parse_cont_disp_val(val: &str, out: &mut Headers) -> io::Result<()> {
    // Only take the first section, the rest can be in quoted strings that we want to handle
    let mut sections = val.splitn(';', 1).map(str::trim);

    match sections.next() {
        Some("form-data") => (),
        Some(other) => error(format!("unexpected multipart field Content-Disposition: {}", other))?,
        None => error("each multipart field requires a Content-Disposition: form-data header")?,
    }

    let mut rem = sections.next().unwrap_or("");

    while let Some((key, val, rest)) = parse_keyval(rem) {
        rem = rest;

        match key {
            "name" => out.name = val.to_string(),
            "filename" => out.filename = Some(val.to_string()),
            other => debug!("unknown key-value pair in Content-Disposition: {:?} = {:?}", key, val),
        }
    }

    if out.name.is_empty() {
        return error(format!("expected 'name' attribute in Content-Disposition: {}", val));
    }

    Ok(())
}

fn parse_keyval(input: &str) -> Option<(&str, &str, &str)> {
    let (name, rest) = try_opt!(param_name(input));
    let (val, rest) = try_opt!(param_val(rest));

    Some((name, val, rest))
}

fn param_name(input: &str) -> Option<(&str, &str)> {
    let mut splits = input.trim_left_matches(&[' ', ';']).splitn('=', 1);

    let name = try_opt!(splits.next()).trim();
    let rem = splits.next().unwrap_or("");

    Some((name, rem))
}

fn param_val(input: &str) -> Option<(&str, &str)> {
    let mut splits = input.splitn(&['"'], 2);

    let token = try_opt!(splits.next()).trim();

    // the value doesn't have to be in quotes if it doesn't contain forbidden chars like `;`
    if !token.is_empty() {
        let mut splits = token.splitn(';', 1);
        let token = try_opt!(splits.next()).trim();
        let rem = splits.next().unwrap_or("");

        return Some((token, rem));
    }

    let qstr = try_opt!(splits.next()).trim();
    let rem = splits.next().unwrap_or_else(|| { warn!("unterminated quote: {:?}", qstr); "" });

    Some((qstr, rem))
}

#[derive(Default)]
struct Headers {
    name: String,
    cont_type: Option<Mime>,
    filename: Option<String>,
}

pub struct Field<S: Stream> {
    pub name: String,
    pub data: FieldData<S>,
    _priv: (),
}

pub enum FieldData<S: Stream> {
    Text(TextData<S>),
    File(FileData<S>),
}

pub struct TextData<S: Stream> {
    pub text: String,
    pub multipart: Multipart<S>,
    _priv: (),
}

pub struct FileData<S: Stream> {
    pub filename: Option<String>,
    pub content_type: Mime,
    pub multipart: Multipart<S>,
    _priv: (),
}

const CONT_DISP: &str = "Content-Disposition";

#[test]
fn test_header_end_split() {
    assert_eq!(header_end_split(b"\r\n\r", b"\n"), Some(1));
    assert_eq!(header_end_split(b"\r\n", b"\r\n"), Some(2));
    assert_eq!(header_end_split(b"\r", b"\n\r\n"), Some(3));
    assert_eq!(header_end_split(b"\r\n\r\n", b"FOOBAR"), None);
    assert_eq!(header_end_split(b"FOOBAR", b"\r\n\r\n"), None);
}
<|endoftext|>