<commit_before>use std::process::Command;

extern crate pkg_config;

const C_IN:   &'static str = "include/include_ffi.h";
const RS_OUT: &'static str = "src/raw.rs";

fn main() {
    let libffi = pkg_config::probe_library("libffi").expect("libffi");

    let mut command = Command::new("bindgen");
    command.arg(format!("--output={}", RS_OUT))
           .arg(C_IN)
           .arg("--");
    for path in &libffi.include_paths {
        command.arg(format!("-I{}", path.display()));
    }

    let status = command.status().expect("bindgen");
    assert!(status.success());

    for lib in &libffi.libs {
        println!("cargo:rustc-link-lib={}", lib);
    }

    for path in &libffi.link_paths {
        println!("cargo:rustc-link-search={}", path.display());
    }
}

<commit_msg>Added better message to panic that happens if bindgen can't be run while building.<commit_after>use std::process::Command;

extern crate pkg_config;

const C_IN:   &'static str = "include/include_ffi.h";
const RS_OUT: &'static str = "src/raw.rs";

fn main() {
    let libffi = pkg_config::probe_library("libffi").expect("libffi");

    let mut command = Command::new("bindgen");
    command.arg(format!("--output={}", RS_OUT))
           .arg(C_IN)
           .arg("--");
    for path in &libffi.include_paths {
        command.arg(format!("-I{}", path.display()));
    }

    let status = command.status()
        .expect("Could not run bindgen. Do you have it installed?");
    assert!(status.success());

    for lib in &libffi.libs {
        println!("cargo:rustc-link-lib={}", lib);
    }

    for path in &libffi.link_paths {
        println!("cargo:rustc-link-search={}", path.display());
    }
}

<|endoftext|>


<commit_before>// spell-checker:ignore (vars) krate

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    // println!("cargo:warning=Running build.rs");

    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
    const FEATURE_PREFIX: &str = "feat_";
    const OVERRIDE_PREFIX: &str = "uu_";

    let out_dir = env::var("OUT_DIR").unwrap();
    // println!("cargo:warning=out_dir={}", out_dir);
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap().replace('\\', "/");
    // println!("cargo:warning=manifest_dir={}", manifest_dir);
    let util_tests_dir = format!("{}/tests/by-util", manifest_dir);
    // println!("cargo:warning=util_tests_dir={}", util_tests_dir);

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) {
            let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" | "selinux" => continue, // common/standard feature names
                "nightly" | "test_unimplemented" => continue, // crate-local custom features
                "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test'
                s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets
                _ => {}             // util feature name
            }
            crates.push(krate);
        }
    }
    crates.sort();

    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
    let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap();

    mf.write_all(
        "type UtilityMap<T> = phf::Map<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\
         \n\
         fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n"
            .as_bytes(),
    )
    .unwrap();

    let mut phf_map = phf_codegen::Map::<&str>::new();
    for krate in &crates {
        let map_value = format!("({krate}::uumain, {krate}::uu_app)", krate = krate);
        match krate.as_ref() {
            // 'test' is named uu_test to avoid collision with rust core crate 'test'.
            // It can also be invoked by name '[' for the '[ expr ] syntax'.
            "uu_test" => {
                phf_map.entry("test", &map_value);
                phf_map.entry("[", &map_value);

                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_test.rs\"]\nmod test_test;\n",
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            k if k.starts_with(OVERRIDE_PREFIX) => {
                phf_map.entry(&k[OVERRIDE_PREFIX.len()..], &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{k}.rs\"]\nmod test_{k};\n",
                        k = &krate[OVERRIDE_PREFIX.len()..],
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            "false" | "true" => {
                phf_map.entry(
                    krate,
                    &format!("(r#{krate}::uumain, r#{krate}::uu_app)", krate = krate),
                );
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            "hashsum" => {
                phf_map.entry(
                    krate,
                    &format!("({krate}::uumain, {krate}::uu_app_custom)", krate = krate),
                );

                let map_value = format!("({krate}::uumain, {krate}::uu_app_common)", krate = krate);
                phf_map.entry("md5sum", &map_value);
                phf_map.entry("sha1sum", &map_value);
                phf_map.entry("sha224sum", &map_value);
                phf_map.entry("sha256sum", &map_value);
                phf_map.entry("sha384sum", &map_value);
                phf_map.entry("sha512sum", &map_value);
                phf_map.entry("sha3sum", &map_value);
                phf_map.entry("sha3-224sum", &map_value);
                phf_map.entry("sha3-256sum", &map_value);
                phf_map.entry("sha3-384sum", &map_value);
                phf_map.entry("sha3-512sum", &map_value);
                phf_map.entry("shake128sum", &map_value);
                phf_map.entry("shake256sum", &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            _ => {
                phf_map.entry(krate, &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
        }
    }
    write!(mf, "{}", phf_map.build()).unwrap();
    mf.write_all(b"\n}\n").unwrap();

    mf.flush().unwrap();
    tf.flush().unwrap();
}
<commit_msg>Added b2sum and b3sum utility entries<commit_after>// spell-checker:ignore (vars) krate

use std::env;
use std::fs::File;
use std::io::Write;
use std::path::Path;

pub fn main() {
    // println!("cargo:warning=Running build.rs");

    if let Ok(profile) = env::var("PROFILE") {
        println!("cargo:rustc-cfg=build={:?}", profile);
    }

    const ENV_FEATURE_PREFIX: &str = "CARGO_FEATURE_";
    const FEATURE_PREFIX: &str = "feat_";
    const OVERRIDE_PREFIX: &str = "uu_";

    let out_dir = env::var("OUT_DIR").unwrap();
    // println!("cargo:warning=out_dir={}", out_dir);
    let manifest_dir = env::var("CARGO_MANIFEST_DIR").unwrap().replace('\\', "/");
    // println!("cargo:warning=manifest_dir={}", manifest_dir);
    let util_tests_dir = format!("{}/tests/by-util", manifest_dir);
    // println!("cargo:warning=util_tests_dir={}", util_tests_dir);

    let mut crates = Vec::new();
    for (key, val) in env::vars() {
        if val == "1" && key.starts_with(ENV_FEATURE_PREFIX) {
            let krate = key[ENV_FEATURE_PREFIX.len()..].to_lowercase();
            match krate.as_ref() {
                "default" | "macos" | "unix" | "windows" | "selinux" => continue, // common/standard feature names
                "nightly" | "test_unimplemented" => continue, // crate-local custom features
                "test" => continue, // over-ridden with 'uu_test' to avoid collision with rust core crate 'test'
                s if s.starts_with(FEATURE_PREFIX) => continue, // crate feature sets
                _ => {}             // util feature name
            }
            crates.push(krate);
        }
    }
    crates.sort();

    let mut mf = File::create(Path::new(&out_dir).join("uutils_map.rs")).unwrap();
    let mut tf = File::create(Path::new(&out_dir).join("test_modules.rs")).unwrap();

    mf.write_all(
        "type UtilityMap<T> = phf::Map<&'static str, (fn(T) -> i32, fn() -> App<'static>)>;\n\
         \n\
         fn util_map<T: uucore::Args>() -> UtilityMap<T> {\n"
            .as_bytes(),
    )
    .unwrap();

    let mut phf_map = phf_codegen::Map::<&str>::new();
    for krate in &crates {
        let map_value = format!("({krate}::uumain, {krate}::uu_app)", krate = krate);
        match krate.as_ref() {
            // 'test' is named uu_test to avoid collision with rust core crate 'test'.
            // It can also be invoked by name '[' for the '[ expr ] syntax'.
            "uu_test" => {
                phf_map.entry("test", &map_value);
                phf_map.entry("[", &map_value);

                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_test.rs\"]\nmod test_test;\n",
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            k if k.starts_with(OVERRIDE_PREFIX) => {
                phf_map.entry(&k[OVERRIDE_PREFIX.len()..], &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{k}.rs\"]\nmod test_{k};\n",
                        k = &krate[OVERRIDE_PREFIX.len()..],
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            "false" | "true" => {
                phf_map.entry(
                    krate,
                    &format!("(r#{krate}::uumain, r#{krate}::uu_app)", krate = krate),
                );
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            "hashsum" => {
                phf_map.entry(
                    krate,
                    &format!("({krate}::uumain, {krate}::uu_app_custom)", krate = krate),
                );

                let map_value = format!("({krate}::uumain, {krate}::uu_app_common)", krate = krate);
                phf_map.entry("md5sum", &map_value);
                phf_map.entry("sha1sum", &map_value);
                phf_map.entry("sha224sum", &map_value);
                phf_map.entry("sha256sum", &map_value);
                phf_map.entry("sha384sum", &map_value);
                phf_map.entry("sha512sum", &map_value);
                phf_map.entry("sha3sum", &map_value);
                phf_map.entry("sha3-224sum", &map_value);
                phf_map.entry("sha3-256sum", &map_value);
                phf_map.entry("sha3-384sum", &map_value);
                phf_map.entry("sha3-512sum", &map_value);
                phf_map.entry("shake128sum", &map_value);
                phf_map.entry("shake256sum", &map_value);
                phf_map.entry("b2sum", &map_value);
                phf_map.entry("b3sum", &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
            _ => {
                phf_map.entry(krate, &map_value);
                tf.write_all(
                    format!(
                        "#[path=\"{dir}/test_{krate}.rs\"]\nmod test_{krate};\n",
                        krate = krate,
                        dir = util_tests_dir,
                    )
                    .as_bytes(),
                )
                .unwrap();
            }
        }
    }
    write!(mf, "{}", phf_map.build()).unwrap();
    mf.write_all(b"\n}\n").unwrap();

    mf.flush().unwrap();
    tf.flush().unwrap();
}
<|endoftext|>


<commit_before>extern crate case;
extern crate hyper;
extern crate rustc_serialize;

use std::collections::HashMap;
use case::CaseExt;
use rustc_serialize::json::Json;
use hyper::Client;
use std::env;
use std::fs::File;
use std::io::{Result, Read, Write};
use std::path::Path;

/// generate an enum of Events
fn main() {

    let events = vec!["commit_comment",
                      "create",
                      "delete",
                      "deployment",
                      "deployment_status",
                      "fork",
                      "gollum",
                      "issue_comment",
                      "issues",
                      "member",
                      "membership",
                      "page_build",
                      "ping",
                      "public",
                      "pull_request",
                      "pull_request_review_comment",
                      "push",
                      "release",
                      "repository",
                      "status",
                      "team_add",
                      "watch"];

    if let Ok(_) = env::var("FETCH_PAYLOAD_DATA") {
        fetch_payload_data(&events).unwrap();
    }
    generate(&events).unwrap();
}

fn fetch_payload_data(events: &Vec<&str>) -> Result<()> {
    let data_dir = Path::new("data");
    let client = Client::new();
    for event in events {
        let src = format!("https://raw.githubusercontent.com/github/developer.github.\
                           com/master/lib/webhooks/{}.payload.json",
                          event);
        let mut res = client.get(&src)
                            .send()
                            .unwrap();
        let mut buf = String::new();
        try!(res.read_to_string(&mut buf));
        let outfile = data_dir.join(format!("{}.json", event));
        let mut f = try!(File::create(outfile));
        try!(f.write_all(buf.as_bytes()));
    }
    Ok(())
}

fn generate(events: &Vec<&str>) -> Result<()> {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("events.rs");
    let mut f = try!(File::create(&dest_path));

    try!(f.write_all(b"/// An enumeration of possible github events
#[derive(Debug, RustcDecodable)]
pub enum Event {
"));
    let mut defs = HashMap::new();
    for event in events {
        let mut data = try!(File::open(format!("data/{}.json", event)));
        let mut buf = String::new();
        try!(data.read_to_string(&mut buf));
        let parsed = Json::from_str(&buf).unwrap();
        let enum_name = container_name(event);
        try!(f.write_all(format!("  {} ", enum_name).as_bytes()));
        try!(f.write_all(b"{"));

        match parsed {
            Json::Object(obj) => {
                for (k, v) in obj {
                    try!(f.write_all(format!("
    {}: {},",
                                             field_name(&k),
                                             value(&enum_name, &mut defs, &k, &v))
                                         .as_bytes()))
                }
            }
            _ => (),
        }
        try!(f.write_all(b"
  },
"));
    }
    try!(f.write_all(b"}

"));

    try!(print_structs(&mut f, defs, &mut vec![], 0));
    Ok(())
}

fn print_structs(f: &mut File,
                 defs: HashMap<String, Json>,
                 generated: &mut Vec<String>,
                 depth: usize)
                 -> Result<()> {
    let mut aux = HashMap::new();
    for (struct_name, json) in defs.iter() {
        if generated.contains(&struct_name) {
            continue;
        }
        println!("struct {}", struct_name);
        try!(f.write_all(format!("
#[derive(Default, Debug, RustcDecodable)]
pub struct {} ",
                                 struct_name)
                             .as_bytes()));
        try!(f.write_all(b"{"));
        match json {
            &Json::Object(ref obj) => {
                for (k, v) in obj {
                    try!(f.write_all(format!("
  pub {}: {},",
                                             field_name(&k),
                                             value(&struct_name, &mut aux, &k, &v))
                                         .as_bytes()))
                }
            }
            _ => (),
        }

        try!(f.write_all(b"
}
"));
        generated.push(struct_name.clone());
    }
    if !aux.is_empty() {
        try!(print_structs(f, aux, generated, depth + 1));
    }
    Ok(())
}

fn value(container: &String, defs: &mut HashMap<String, Json>, k: &str, j: &Json) -> String {
    match j {
        &Json::I64(_) => "i64".to_owned(),
        &Json::U64(_) => "u64".to_owned(),
        &Json::F64(_) => "f64".to_owned(),
        &Json::String(_) => "String".to_owned(),
        &Json::Boolean(_) => "bool".to_owned(),
        &Json::Array(ref jv) => {
            if jv.is_empty() {
                "Vec<String>".to_owned() // this is just a guess!
            } else {
                format!("Vec<{}>", value(&container, defs, k, &jv[0]))
            }
        }
        obj @ &Json::Object(_) => {
            if "payload" == k {
                "HashMap<String, String>".to_owned()
            } else {
                let struct_name = match container_name(k) {
                    ref recursive if recursive == container => format!("{}Inner", recursive),
                    valid => valid,
                };
                defs.insert(struct_name.clone(), obj.clone());
                struct_name
            }
        }
        &Json::Null => "Option<String>".to_owned(),
    }
}

fn container_name(field: &str) -> String {
    if "self" == field {
        "SelfLink".to_owned()
    } else {
        field.to_camel()
    }
}

/// works around conflicts with reservied words
fn field_name(s: &str) -> String {
    let reserved = vec!["ref", "self", "type"];
    if reserved.contains(&s) {
        format!("_{}", s)
    } else {
        s.to_owned()
    }
}
<commit_msg>determinism<commit_after>extern crate case;
extern crate hyper;
extern crate rustc_serialize;

use std::collections::BTreeMap;
use case::CaseExt;
use rustc_serialize::json::Json;
use hyper::Client;
use std::env;
use std::fs::File;
use std::io::{Result, Read, Write};
use std::path::Path;

/// generate an enum of Events
fn main() {

    let events = vec!["commit_comment",
                      "create",
                      "delete",
                      "deployment",
                      "deployment_status",
                      "fork",
                      "gollum",
                      "issue_comment",
                      "issues",
                      "member",
                      "membership",
                      "page_build",
                      "ping",
                      "public",
                      "pull_request",
                      "pull_request_review_comment",
                      "push",
                      "release",
                      "repository",
                      "status",
                      "team_add",
                      "watch"];

    if let Ok(_) = env::var("FETCH_PAYLOAD_DATA") {
        fetch_payload_data(&events).unwrap();
    }
    generate(&events).unwrap();
}

fn fetch_payload_data(events: &Vec<&str>) -> Result<()> {
    let data_dir = Path::new("data");
    let client = Client::new();
    for event in events {
        let src = format!("https://raw.githubusercontent.com/github/developer.github.\
                           com/master/lib/webhooks/{}.payload.json",
                          event);
        let mut res = client.get(&src)
                            .send()
                            .unwrap();
        let mut buf = String::new();
        try!(res.read_to_string(&mut buf));
        let outfile = data_dir.join(format!("{}.json", event));
        let mut f = try!(File::create(outfile));
        try!(f.write_all(buf.as_bytes()));
    }
    Ok(())
}

fn generate(events: &Vec<&str>) -> Result<()> {
    let out_dir = env::var("OUT_DIR").unwrap();
    let dest_path = Path::new(&out_dir).join("events.rs");
    let mut f = try!(File::create(&dest_path));

    try!(f.write_all(b"/// An enumeration of possible github events
#[derive(Debug, RustcDecodable)]
pub enum Event {
"));
    let mut defs = BTreeMap::new();
    for event in events {
        let mut data = try!(File::open(format!("data/{}.json", event)));
        let mut buf = String::new();
        try!(data.read_to_string(&mut buf));
        let parsed = Json::from_str(&buf).unwrap();
        let enum_name = container_name(event);
        try!(f.write_all(format!("  {} ", enum_name).as_bytes()));
        try!(f.write_all(b"{"));

        match parsed {
            Json::Object(obj) => {
                for (k, v) in obj {
                    try!(f.write_all(format!("
    {}: {},",
                                             field_name(&k),
                                             value(&enum_name, &mut defs, &k, &v))
                                         .as_bytes()))
                }
            }
            _ => (),
        }
        try!(f.write_all(b"
  },
"));
    }
    try!(f.write_all(b"}

"));

    try!(print_structs(&mut f, defs, &mut vec![], 0));
    Ok(())
}

fn print_structs(f: &mut File,
                 defs: BTreeMap<String, Json>,
                 generated: &mut Vec<String>,
                 depth: usize)
                 -> Result<()> {
    let mut aux = BTreeMap::new();
    for (struct_name, json) in defs.iter() {
        if generated.contains(&struct_name) {
            continue;
        }
        println!("struct {}", struct_name);
        try!(f.write_all(format!("
#[derive(Default, Debug, RustcDecodable)]
pub struct {} ",
                                 struct_name)
                             .as_bytes()));
        try!(f.write_all(b"{"));
        match json {
            &Json::Object(ref obj) => {
                for (k, v) in obj {
                    try!(f.write_all(format!("
  pub {}: {},",
                                             field_name(&k),
                                             value(&struct_name, &mut aux, &k, &v))
                                         .as_bytes()))
                }
            }
            _ => (),
        }

        try!(f.write_all(b"
}
"));
        generated.push(struct_name.clone());
    }
    if !aux.is_empty() {
        try!(print_structs(f, aux, generated, depth + 1));
    }
    Ok(())
}

fn value(container: &String, defs: &mut BTreeMap<String, Json>, k: &str, j: &Json) -> String {
    match j {
        &Json::I64(_) => "i64".to_owned(),
        &Json::U64(_) => "u64".to_owned(),
        &Json::F64(_) => "f64".to_owned(),
        &Json::String(_) => "String".to_owned(),
        &Json::Boolean(_) => "bool".to_owned(),
        &Json::Array(ref jv) => {
            if jv.is_empty() {
                "Vec<String>".to_owned() // this is just a guess!
            } else {
                format!("Vec<{}>", value(&container, defs, k, &jv[0]))
            }
        }
        obj @ &Json::Object(_) => {
            if "payload" == k {
                "HashMap<String, String>".to_owned()
            } else {
                let struct_name = match container_name(k) {
                    ref recursive if recursive == container => format!("{}Inner", recursive),
                    valid => valid,
                };
                defs.insert(struct_name.clone(), obj.clone());
                struct_name
            }
        }
        &Json::Null => "Option<String>".to_owned(),
    }
}

fn container_name(field: &str) -> String {
    if "self" == field {
        "SelfLink".to_owned()
    } else {
        field.to_camel()
    }
}

/// works around conflicts with reservied words
fn field_name(s: &str) -> String {
    let reserved = vec!["ref", "self", "type"];
    if reserved.contains(&s) {
        format!("_{}", s)
    } else {
        s.to_owned()
    }
}
<|endoftext|>


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

extern crate gcc;

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if target.contains("msvc") && host.contains("windows") {
        let mut config = gcc::Config::new();
        config.file("src/util_helpers.asm");
        config.file("src/aesni_helpers.asm");
        if target.contains("x86_64") {
            config.define("X64", None);
        }
        config.compile("lib_rust_crypto_helpers.a");
    }
    else {
        let mut cfg = gcc::Config::new();
        cfg.file("src/util_helpers.c");
        cfg.file("src/aesni_helpers.c");
        // gcc can't build this library so, unless the user has explicitly
        // specified a different C compiler, use clang.
        if env::var_os("CC").is_none() {
            cfg.compiler(Path::new("clang"));
        }
        cfg.compile("lib_rust_crypto_helpers.a");
    }
}

<commit_msg>Only use Clang on OpenBSD - default to cc (generally GCC) on other platforms<commit_after>// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

extern crate gcc;

use std::env;
use std::path::Path;

fn main() {
    let target = env::var("TARGET").unwrap();
    let host = env::var("HOST").unwrap();
    if target.contains("msvc") && host.contains("windows") {
        let mut config = gcc::Config::new();
        config.file("src/util_helpers.asm");
        config.file("src/aesni_helpers.asm");
        if target.contains("x86_64") {
            config.define("X64", None);
        }
        config.compile("lib_rust_crypto_helpers.a");
    }
    else {
        let mut cfg = gcc::Config::new();
        cfg.file("src/util_helpers.c");
        cfg.file("src/aesni_helpers.c");
        if env::var_os("CC").is_none() {
            if host.contains("openbsd") {
                // Use clang on openbsd since there have been reports that
                // GCC doesn't like some of the assembly that we use on that
                // platform.
                cfg.compiler(Path::new("clang"));
            } else {
                cfg.compiler(Path::new("cc"));
            }
        }
        cfg.compile("lib_rust_crypto_helpers.a");
    }
}

<|endoftext|>


<commit_before>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system cups
    // shared library.
    println!("cargo:rustc-link-lib=cups");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // These fail with size issues.
        .opaque_type("__msfilterreq")
        .opaque_type("group_req")
        .opaque_type("group_source_req")
        // This fails with "`IPPORT_RESERVED` already defined" on Linux.
        .hide_type("IPPORT_RESERVED")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<commit_msg>Blacklist layout tests, still broken on nightly.<commit_after>extern crate bindgen;

use std::env;
use std::path::PathBuf;

fn main() {
    // Tell cargo to tell rustc to link the system cups
    // shared library.
    println!("cargo:rustc-link-lib=cups");

    // The bindgen::Builder is the main entry point
    // to bindgen, and lets you build up options for
    // the resulting bindings.
    let bindings = bindgen::Builder::default()
        // The input header we would like to generate
        // bindings for.
        .header("wrapper.h")
        // These fail with size issues.
        .opaque_type("__msfilterreq")
        .opaque_type("group_req")
        .opaque_type("group_source_req")
        // bindgen layout tests fail on Rust nightly >1.21.0
        // "thread 'bindgen_test_layout_max_align_t' panicked at
        // 'assertion failed: `(left == right)`"
        .layout_tests(false)
        // This fails with "`IPPORT_RESERVED` already defined" on Linux.
        .hide_type("IPPORT_RESERVED")
        // Finish the builder and generate the bindings.
        .generate()
        // Unwrap the Result and panic on failure.
        .expect("Unable to generate bindings");

    // Write the bindings to the $OUT_DIR/bindings.rs file.
    let out_path = PathBuf::from(env::var("OUT_DIR").unwrap());
    bindings
        .write_to_file(out_path.join("bindings.rs"))
        .expect("Couldn't write bindings!");
}
<|endoftext|>


<commit_before>use arch::cpu::context::InterruptFrame;
use super::pics::end_pic_interrupt;

use io::term::CONSOLE;
use io::keyboard;

use vga::Color;

use core::fmt;
use core::fmt::Write;

pub type InterruptHandler = extern "C" fn (*const InterruptFrame);
pub type ErrorCodeHandler = extern "C" fn (*const InterruptFrame, usize);

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

bitflags! {
   flags PageFaultErrorCode: u32 {
       /// If 1, the error was caused by a page that was present.
       /// Otherwise, the page was non-present.
       const PRESENT = 1 << 0
     , /// If 1, the error was caused by a read. If 0, the cause was a write.
       const READ_WRITE = 1 << 1
     , /// If 1, the error was caused during user-mode execution.
       /// If 0, the processor was in kernel mode.
       const USER_MODE = 1 << 2
     , /// If 1, the fault was caused by reserved bits set to 1 during a fetch.
       const RESERVED = 1 << 3
     , /// If 1, the fault was caused during an instruction fetch.
       const INST_FETCH = 1 << 4
     , /// If 1, there was a protection key violation.
       const PROTECTION = 1 << 5
   }
}

impl fmt::Display for PageFaultErrorCode {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!( f, "Caused by {}{}{} during a {}{} executing in {} mode."
             , if self.contains(PRESENT) { "a present page" }
               else { "a non-present page" }
             , if self.contains(PROTECTION) { " protection-key violation" }
               else { "" }
             , if self.contains(RESERVED) { " reserved bits set to one "}
               else { "" }
             , if self.contains(READ_WRITE) { "read" } else { "write" }
             , if self.contains(INST_FETCH) { " in an instruction fetch"}
               else { "" }
             , if self.contains(USER_MODE) { "user" } else { "kernel" }            )
   }
}

#[no_mangle] #[inline(never)]
pub extern "C" fn keyboard(_frame: *const InterruptFrame) {
   println!("keyboard happened");
   if let Some(input) = keyboard::read_char() {
       if input == '\r' {
           println!("");
       } else {
           print!("{}", input);
       }
   }
   // send the PICs the end interrupt signal
   unsafe {
       end_pic_interrupt(0x21);
   }
}

/// Handles page fault exceptions
#[no_mangle] #[inline(never)]
pub extern "C" fn page_fault( _frame: *const InterruptFrame, error_code: usize) {
   let _ = write!( CONSOLE.lock()
                          .set_colors(Color::White, Color::Blue)
                       //   .clear()
                 , "PAGE FAULT EXCEPTION\nCode: {:#x}\n\n{}"
                 , error_code
                 , PageFaultErrorCode::from_bits_truncate(error_code as u32)
                 );
   // TODO: stack dumps please

   loop { }
}

#[no_mangle] #[inline(never)]
pub extern "C" fn test(_frame: *const InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   println!("{:>47}", "[ OKAY ]");
   // send the PICs the end interrupt signal
   unsafe {
       end_pic_interrupt(0xff);
   }
}

macro_rules! make_handlers {
    ( $(ex $ex_num:expr, $name:ident),+ ) => {
        $(
            #[no_mangle]
            pub extern "C" fn $name(frame: *const InterruptFrame) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "{} EXCEPTION: {}\n\
                                     {} on vector {}\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                     , ex_info.name, ex_info.mnemonic
                                     , ex_info.irq_type
                                     , $ex_num
                                     , ex_info.source
                                     , *frame);
                    loop { }
                }
            }
        )+
    };
    ( $(err $ex_num:expr, $name:ident) ,+ ) => {
        $(
            #[no_mangle]
            pub extern "C" fn $name( frame: *const InterruptFrame
                                   , err_code: usize) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "{} EXCEPTION: {}\n\
                                     {} on vector {} with error code {:#x}\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                  , ex_info.name, ex_info.mnemonic
                                  , ex_info.irq_type
                                  , $ex_num, err_code
                                  , ex_info.source
                                  , *frame);
                    loop { }
                }
            }
        )+
    };
}
make_handlers! { ex 0, ex0
               , ex 1, ex1
               , ex 2, ex2
                // ex 3 is breakpoint
               , ex 4, ex4
               , ex 5, ex5
               , ex 6, ex6
               , ex 7, ex7
               , ex 16, ex16
               , ex 18, ex18
               , ex 19, ex19
               }
make_handlers! { err 8, ex8
               , err 10, ex10
               , err 11, ex11
               , err 12, ex12
               , err 13, ex13
               , err 17, ex17 }
<commit_msg>[x86_all] exception messages slightly prettier<commit_after>use arch::cpu::context::InterruptFrame;
use super::pics::end_pic_interrupt;

use io::term::CONSOLE;

use vga::Color;

use core::fmt;
use core::fmt::Write;

pub type InterruptHandler = extern "C" fn (*const InterruptFrame);
pub type ErrorCodeHandler = extern "C" fn (*const InterruptFrame, usize);

#[derive(Debug)]
pub struct ExceptionInfo { pub name: &'static str
                         , pub mnemonic: &'static str
                         , pub irq_type: &'static str
                         , pub source: &'static str
                         }

/// x86 exceptions.
///
/// Taken from the list at
/// [http://wiki.osdev.org/Exceptions](http://wiki.osdev.org/Exceptions)
pub static EXCEPTIONS: [ExceptionInfo; 20]
    = [ ExceptionInfo { name: "Divide-By-Zero Error"
                      , mnemonic: "#DE", irq_type: "Fault"
                      , source: "DIV or IDIV instruction" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "#DB", irq_type: "Fault/trap"
                      , source: "Reserved for Intel use" }
      , ExceptionInfo { name: "Non-Maskable Interrupt"
                      , mnemonic: "NMI", irq_type: "Interrupt"
                      , source: "Non-maskable external interrupt" }
      , ExceptionInfo { name: "Breakpoint"
                      , mnemonic: "#BP", irq_type: "Trap"
                      , source: "INT 3 instruction" }
      , ExceptionInfo { name: "Overflow"
                      , mnemonic: "#OF", irq_type: "Trap"
                      , source: "INTO instruction" }
      , ExceptionInfo { name: "BOUND Range Exceeded"
                      , mnemonic: "#BR", irq_type: "Fault"
                      , source: "BOUND instruction" }
      , ExceptionInfo { name: "Undefined Opcode"
                     , mnemonic: "#UD", irq_type: "Fault"
                     , source: "UD2 instruction or reserved opcode" }
      , ExceptionInfo { name: "Device Not Available"
                      , mnemonic: "#NM", irq_type: "Fault"
                      , source: "Floating-point or WAIT/FWAIT instruction\
                                 (no math coprocessor)" }
      , ExceptionInfo { name: "Double Fault"
                      , mnemonic: "#DF", irq_type: "Abort"
                      , source: "Any instruction that can generate an\
                                 exception, a NMI, or an INTR" }
      , ExceptionInfo { name: "Coprocessor Segment Overrun"
                      , mnemonic: "", irq_type: "Fault"
                      , source: "Any floating-point instruction" }
      , ExceptionInfo { name: "Invalid TSS"
                      , mnemonic: "#TS", irq_type: "Fault"
                      , source: "Task switch or TSS access" }
      , ExceptionInfo { name: "Segment Not Present"
                      , mnemonic: "#NP", irq_type: "Fault"
                      , source: "Loading segment registers or accessing\
                                 system segments" }
      , ExceptionInfo { name: "Stack-Segment Fault"
                      , mnemonic: "#SS", irq_type: "Fault"
                      , source: "Stack operations and SS register loads" }
      , ExceptionInfo { name: "General Protection"
                      , mnemonic: "#GP", irq_type: "Fault"
                      , source: "Any memory reference or other protection\
                                 checks" }
      , ExceptionInfo { name: "Page Fault"
                      , mnemonic: "#PF", irq_type: "Fault"
                      , source: "Any memory reference" }
      , ExceptionInfo { name: "RESERVED"
                      , mnemonic: "", irq_type: ""
                      , source: "RESERVED FOR INTEL USE \n This should never \
                                 happen. Something is very wrong." }
      , ExceptionInfo { name: "x87 FPU Floating-Point Error (Math Fault)"
                      , mnemonic: "#MF", irq_type: "Fault"
                      , source: "x87 FPU floating-point or WAIT/FWAIT\
                                 instruction" }
      , ExceptionInfo { name: "Alignment Check"
                      , mnemonic: "#AC", irq_type: "Fault"
                      , source: "Any data reference in memory" }
      , ExceptionInfo { name: "Machine Check"
                      , mnemonic: "#MC", irq_type: "Abort"
                      , source: "Model-dependent" }
      , ExceptionInfo { name: "SIMD Floating-Point Exception"
                      , mnemonic: "#XM", irq_type: "Fault"
                      , source: "SSE/SSE2/SSE3 floating-point instructions" }
       ];

bitflags! {
   flags PageFaultErrorCode: u32 {
       /// If 1, the error was caused by a page that was present.
       /// Otherwise, the page was non-present.
       const PRESENT = 1 << 0
     , /// If 1, the error was caused by a read. If 0, the cause was a write.
       const READ_WRITE = 1 << 1
     , /// If 1, the error was caused during user-mode execution.
       /// If 0, the processor was in kernel mode.
       const USER_MODE = 1 << 2
     , /// If 1, the fault was caused by reserved bits set to 1 during a fetch.
       const RESERVED = 1 << 3
     , /// If 1, the fault was caused during an instruction fetch.
       const INST_FETCH = 1 << 4
     , /// If 1, there was a protection key violation.
       const PROTECTION = 1 << 5
   }
}

impl fmt::Display for PageFaultErrorCode {
   fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
       write!( f, "Caused by {}{}{} during a {}{} executing in {} mode."
             , if self.contains(PRESENT) { "a present page" }
               else { "a non-present page" }
             , if self.contains(PROTECTION) { " protection-key violation" }
               else { "" }
             , if self.contains(RESERVED) { " reserved bits set to one "}
               else { "" }
             , if self.contains(READ_WRITE) { "read" } else { "write" }
             , if self.contains(INST_FETCH) { " in an instruction fetch"}
               else { "" }
             , if self.contains(USER_MODE) { "user" } else { "kernel" }            )
   }
}

#[no_mangle] #[inline(never)]
pub extern "C" fn keyboard(_frame: *const InterruptFrame) {
    use io::keyboard;

    println!("keyboard happened");
    if let Some(input) = keyboard::read_char() {
        if input == '\r' {
            println!("");
        } else {
            print!("{}", input);
        }
    }
   // send the PICs the end interrupt signal
   unsafe {
       end_pic_interrupt(0x21);
   }
}

/// Handles page fault exceptions
#[no_mangle] #[inline(never)]
pub extern "C" fn page_fault( frame: *const InterruptFrame, error_code: usize) {
   unsafe {
       let _ = write!( CONSOLE.lock()
                          .set_colors(Color::White, Color::Blue)
                       //   .clear()
                 , "IT'S NOT MY FAULT: Page Fault at {:p} \
                    \nError code: {:#x}\n\n{}\n{:?}"
                 , (*frame).rip
                 , error_code
                 , PageFaultErrorCode::from_bits_truncate(error_code as u32)
                 , *frame
                 );
    }
   // TODO: stack dumps please

   loop { }
}

#[no_mangle] #[inline(never)]
pub extern "C" fn test(_frame: *const InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   println!("{:>47}", "[ OKAY ]");
   // send the PICs the end interrupt signal
   unsafe {
       end_pic_interrupt(0xff);
   }
}

#[no_mangle] #[inline(never)]
pub extern "C" fn empty_handler(_frame: *const InterruptFrame) {
   // assert_eq!(state.int_id, 0x80);
   println!("interrupt");
   // send the PICs the end interrupt signal
   // unsafe {
   //     end_pic_interrupt(0xff);
   // }
}

macro_rules! make_handlers {
    ( $(ex $ex_num:expr, $name:ident),+ ) => {
        $(
            #[no_mangle]
            pub extern "C" fn $name(frame: *const InterruptFrame) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                     Exception on vector {}.\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                     , ex_info.name, ex_info.irq_type
                                     , (*frame).rip
                                     , $ex_num
                                     , ex_info.source
                                     , *frame);
                    loop { }
                }
            }
        )+
    };
    ( $(err $ex_num:expr, $name:ident) ,+ ) => {
        $(
            #[no_mangle]
            pub extern "C" fn $name( frame: *const InterruptFrame
                                   , err_code: usize) {
                unsafe {
                    let ex_info = &EXCEPTIONS[$ex_num];
                    // let cr_state = control_regs::dump();
                    let _ = write!( CONSOLE.lock()
                                           .set_colors(Color::White, Color::Blue)
                                  , "EVERYTHING IS FINE: {}{} at {:p}\n\
                                     Exception on vector {} with error code {:#x}.\n\
                                     Source: {}.\nThis is fine.\n\n\
                                     {:?}"
                                  , ex_info.name, ex_info.irq_type
                                  , (*frame).rip
                                  , $ex_num, err_code
                                  , ex_info.source
                                  , *frame);
                    loop { }
                }
            }
        )+
    };
}
make_handlers! { ex 0, ex0
               , ex 1, ex1
               , ex 2, ex2
                // ex 3 is breakpoint
               , ex 4, ex4
               , ex 5, ex5
               , ex 6, ex6
               , ex 7, ex7
               , ex 16, ex16
               , ex 18, ex18
               , ex 19, ex19
               }
make_handlers! { err 8, ex8
               , err 10, ex10
               , err 11, ex11
               , err 12, ex12
               , err 13, ex13
               , err 17, ex17 }
<|endoftext|>


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

use crate::sys::ffi;
use crate::sys::system::get_sys_value;

use crate::ProcessorExt;

use libc::c_char;
use std::mem;
use std::ops::Deref;
use std::sync::Arc;

pub struct UnsafePtr<T>(*mut T);

unsafe impl<T> Send for UnsafePtr<T> {}
unsafe impl<T> Sync for UnsafePtr<T> {}

impl<T> Deref for UnsafePtr<T> {
    type Target = *mut T;

    fn deref(&self) -> &*mut T {
        &self.0
    }
}

pub struct ProcessorData {
    pub cpu_info: UnsafePtr<i32>,
    pub num_cpu_info: u32,
}

impl ProcessorData {
    pub fn new(cpu_info: *mut i32, num_cpu_info: u32) -> ProcessorData {
        ProcessorData {
            cpu_info: UnsafePtr(cpu_info),
            num_cpu_info,
        }
    }
}

impl Drop for ProcessorData {
    fn drop(&mut self) {
        if !self.cpu_info.0.is_null() {
            let prev_cpu_info_size = std::mem::size_of::<i32>() as u32 * self.num_cpu_info;
            unsafe {
                ffi::vm_deallocate(ffi::mach_task_self(), self.cpu_info.0, prev_cpu_info_size);
            }
            self.cpu_info.0 = std::ptr::null_mut();
        }
    }
}

/// Struct containing a processor information.
pub struct Processor {
    name: String,
    cpu_usage: f32,
    processor_data: Arc<ProcessorData>,
    frequency: u64,
    vendor_id: String,
    brand: String,
}

impl Processor {
    pub(crate) fn new(
        name: String,
        processor_data: Arc<ProcessorData>,
        frequency: u64,
        vendor_id: String,
        brand: String,
    ) -> Processor {
        Processor {
            name,
            cpu_usage: 0f32,
            processor_data,
            frequency,
            vendor_id,
            brand,
        }
    }

    pub(crate) fn set_cpu_usage(&mut self, cpu_usage: f32) {
        self.cpu_usage = cpu_usage;
    }

    pub(crate) fn update(&mut self, cpu_usage: f32, processor_data: Arc<ProcessorData>) {
        self.cpu_usage = cpu_usage;
        self.processor_data = processor_data;
    }

    pub(crate) fn get_data(&self) -> Arc<ProcessorData> {
        Arc::clone(&self.processor_data)
    }
}

impl ProcessorExt for Processor {
    fn get_cpu_usage(&self) -> f32 {
        self.cpu_usage
    }

    fn get_name(&self) -> &str {
        &self.name
    }

    /// Returns the processor frequency in MHz.
    fn get_frequency(&self) -> u64 {
        self.frequency
    }

    fn get_vendor_id(&self) -> &str {
        &self.vendor_id
    }

    fn get_brand(&self) -> &str {
        &self.brand
    }
}

pub fn get_cpu_frequency() -> u64 {
    let mut speed: u64 = 0;
    let mut len = std::mem::size_of::<u64>();
    unsafe {
        libc::sysctlbyname(
            b"hw.cpufrequency\0".as_ptr() as *const c_char,
            &mut speed as *mut _ as _,
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    speed / 1_000_000
}

pub fn init_processors(port: libc::mach_port_t) -> (Processor, Vec<Processor>) {
    let mut num_cpu = 0;
    let mut processors = Vec::new();
    let mut pourcent = 0f32;
    let mut mib = [0, 0];

    let (vendor_id, brand) = get_vendor_id_and_brand();
    let frequency = get_cpu_frequency();

    unsafe {
        if !get_sys_value(
            libc::CTL_HW as _,
            libc::HW_NCPU as _,
            mem::size_of::<u32>(),
            &mut num_cpu as *mut _ as *mut _,
            &mut mib,
        ) {
            num_cpu = 1;
        }

        let mut num_cpu_u = 0u32;
        let mut cpu_info: *mut i32 = std::ptr::null_mut();
        let mut num_cpu_info = 0u32;

        if ffi::host_processor_info(
            port,
            libc::PROCESSOR_CPU_LOAD_INFO,
            &mut num_cpu_u as *mut u32,
            &mut cpu_info as *mut *mut i32,
            &mut num_cpu_info as *mut u32,
        ) == ffi::KERN_SUCCESS
        {
            let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info));
            for i in 0..num_cpu {
                let mut p = Processor::new(
                    format!("{}", i + 1),
                    Arc::clone(&proc_data),
                    frequency,
                    vendor_id.clone(),
                    brand.clone(),
                );
                let in_use = *cpu_info
                    .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_USER as isize)
                    + *cpu_info.offset(
                        (libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_SYSTEM as isize,
                    )
                    + *cpu_info
                        .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_NICE as isize);
                let total = in_use
                    + *cpu_info
                        .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_IDLE as isize);
                p.set_cpu_usage(in_use as f32 / total as f32 * 100.);
                pourcent += p.get_cpu_usage();
                processors.push(p);
            }
        }
    }
    let mut global_processor = Processor::new(
        "0".to_owned(),
        Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)),
        frequency,
        vendor_id,
        brand,
    );
    global_processor.set_cpu_usage(pourcent / processors.len() as f32);

    (global_processor, processors)
}

fn get_sysctl_str(s: &[u8]) -> String {
    let mut len = 0;

    unsafe {
        libc::sysctlbyname(
            s.as_ptr() as *const c_char,
            std::ptr::null_mut(),
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    if len < 1 {
        return String::new();
    }
    let mut buf = Vec::with_capacity(len);
    unsafe {
        libc::sysctlbyname(
            s.as_ptr() as *const c_char,
            buf.as_mut_ptr() as _,
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    if len > 0 {
        unsafe {
            buf.set_len(len);
        }
        while buf.last() == Some(&b'\0') {
            buf.pop();
        }
        String::from_utf8(buf).unwrap_or_else(|_| String::new())
    } else {
        String::new()
    }
}

pub fn get_vendor_id_and_brand() -> (String, String) {
    (
        get_sysctl_str(b"machdep.cpu.brand_string\0"),
        get_sysctl_str(b"machdep.cpu.vendor\0"),
    )
}
<commit_msg>Fix cpu.get_brand() returning empty string on M1<commit_after>//
// Sysinfo
//
// Copyright (c) 2015 Guillaume Gomez
//

use crate::sys::ffi;
use crate::sys::system::get_sys_value;

use crate::ProcessorExt;

use libc::c_char;
use std::mem;
use std::ops::Deref;
use std::sync::Arc;

pub struct UnsafePtr<T>(*mut T);

unsafe impl<T> Send for UnsafePtr<T> {}
unsafe impl<T> Sync for UnsafePtr<T> {}

impl<T> Deref for UnsafePtr<T> {
    type Target = *mut T;

    fn deref(&self) -> &*mut T {
        &self.0
    }
}

pub struct ProcessorData {
    pub cpu_info: UnsafePtr<i32>,
    pub num_cpu_info: u32,
}

impl ProcessorData {
    pub fn new(cpu_info: *mut i32, num_cpu_info: u32) -> ProcessorData {
        ProcessorData {
            cpu_info: UnsafePtr(cpu_info),
            num_cpu_info,
        }
    }
}

impl Drop for ProcessorData {
    fn drop(&mut self) {
        if !self.cpu_info.0.is_null() {
            let prev_cpu_info_size = std::mem::size_of::<i32>() as u32 * self.num_cpu_info;
            unsafe {
                ffi::vm_deallocate(ffi::mach_task_self(), self.cpu_info.0, prev_cpu_info_size);
            }
            self.cpu_info.0 = std::ptr::null_mut();
        }
    }
}

/// Struct containing a processor information.
pub struct Processor {
    name: String,
    cpu_usage: f32,
    processor_data: Arc<ProcessorData>,
    frequency: u64,
    vendor_id: String,
    brand: String,
}

impl Processor {
    pub(crate) fn new(
        name: String,
        processor_data: Arc<ProcessorData>,
        frequency: u64,
        vendor_id: String,
        brand: String,
    ) -> Processor {
        Processor {
            name,
            cpu_usage: 0f32,
            processor_data,
            frequency,
            vendor_id,
            brand,
        }
    }

    pub(crate) fn set_cpu_usage(&mut self, cpu_usage: f32) {
        self.cpu_usage = cpu_usage;
    }

    pub(crate) fn update(&mut self, cpu_usage: f32, processor_data: Arc<ProcessorData>) {
        self.cpu_usage = cpu_usage;
        self.processor_data = processor_data;
    }

    pub(crate) fn get_data(&self) -> Arc<ProcessorData> {
        Arc::clone(&self.processor_data)
    }
}

impl ProcessorExt for Processor {
    fn get_cpu_usage(&self) -> f32 {
        self.cpu_usage
    }

    fn get_name(&self) -> &str {
        &self.name
    }

    /// Returns the processor frequency in MHz.
    fn get_frequency(&self) -> u64 {
        self.frequency
    }

    fn get_vendor_id(&self) -> &str {
        &self.vendor_id
    }

    fn get_brand(&self) -> &str {
        &self.brand
    }
}

pub fn get_cpu_frequency() -> u64 {
    let mut speed: u64 = 0;
    let mut len = std::mem::size_of::<u64>();
    unsafe {
        libc::sysctlbyname(
            b"hw.cpufrequency\0".as_ptr() as *const c_char,
            &mut speed as *mut _ as _,
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    speed / 1_000_000
}

pub fn init_processors(port: libc::mach_port_t) -> (Processor, Vec<Processor>) {
    let mut num_cpu = 0;
    let mut processors = Vec::new();
    let mut pourcent = 0f32;
    let mut mib = [0, 0];

    let (vendor_id, brand) = get_vendor_id_and_brand();
    let frequency = get_cpu_frequency();

    unsafe {
        if !get_sys_value(
            libc::CTL_HW as _,
            libc::HW_NCPU as _,
            mem::size_of::<u32>(),
            &mut num_cpu as *mut _ as *mut _,
            &mut mib,
        ) {
            num_cpu = 1;
        }

        let mut num_cpu_u = 0u32;
        let mut cpu_info: *mut i32 = std::ptr::null_mut();
        let mut num_cpu_info = 0u32;

        if ffi::host_processor_info(
            port,
            libc::PROCESSOR_CPU_LOAD_INFO,
            &mut num_cpu_u as *mut u32,
            &mut cpu_info as *mut *mut i32,
            &mut num_cpu_info as *mut u32,
        ) == ffi::KERN_SUCCESS
        {
            let proc_data = Arc::new(ProcessorData::new(cpu_info, num_cpu_info));
            for i in 0..num_cpu {
                let mut p = Processor::new(
                    format!("{}", i + 1),
                    Arc::clone(&proc_data),
                    frequency,
                    vendor_id.clone(),
                    brand.clone(),
                );
                let in_use = *cpu_info
                    .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_USER as isize)
                    + *cpu_info.offset(
                        (libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_SYSTEM as isize,
                    )
                    + *cpu_info
                        .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_NICE as isize);
                let total = in_use
                    + *cpu_info
                        .offset((libc::CPU_STATE_MAX * i) as isize + libc::CPU_STATE_IDLE as isize);
                p.set_cpu_usage(in_use as f32 / total as f32 * 100.);
                pourcent += p.get_cpu_usage();
                processors.push(p);
            }
        }
    }
    let mut global_processor = Processor::new(
        "0".to_owned(),
        Arc::new(ProcessorData::new(::std::ptr::null_mut(), 0)),
        frequency,
        vendor_id,
        brand,
    );
    global_processor.set_cpu_usage(pourcent / processors.len() as f32);

    (global_processor, processors)
}

fn get_sysctl_str(s: &[u8]) -> String {
    let mut len = 0;

    unsafe {
        libc::sysctlbyname(
            s.as_ptr() as *const c_char,
            std::ptr::null_mut(),
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    if len < 1 {
        return String::new();
    }
    let mut buf = Vec::with_capacity(len);
    unsafe {
        libc::sysctlbyname(
            s.as_ptr() as *const c_char,
            buf.as_mut_ptr() as _,
            &mut len,
            std::ptr::null_mut(),
            0,
        );
    }
    if len > 0 {
        unsafe {
            buf.set_len(len);
        }
        while buf.last() == Some(&b'\0') {
            buf.pop();
        }
        String::from_utf8(buf).unwrap_or_else(|_| String::new())
    } else {
        String::new()
    }
}

pub fn get_vendor_id_and_brand() -> (String, String) {
    (
        get_sysctl_str(b"machdep.cpu.vendor\0"),
        get_sysctl_str(b"machdep.cpu.brand_string\0"),
    )
}
<|endoftext|>


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

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::{self, Read};
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs, SocketAddr, SocketAddrV4};
use std::ops::{Deref, DerefMut};
use std::option;
use std::path::Path;
use std::result;
use std::str::FromStr;
use std::sync::Arc;
use std::thread::{self, JoinHandle};

use hcore::service::{ApplicationEnvironment, ServiceGroup};
use iron::prelude::*;
use iron::{headers, status, typemap};
use iron::modifiers::Header;
use persistent;
use prometheus::{self, CounterVec, HistogramVec, TextEncoder, Encoder};
use router::Router;
use serde_json::{self, Value as Json};

use error::{Result, Error, SupError};
use manager;
use manager::service::HealthCheck;
use manager::service::hooks::{self, HealthCheckHook};

static LOGKEY: &'static str = "HG";
const APIDOCS: &'static str = include_str!(concat!(env!("OUT_DIR"), "/api.html"));

// Simple macro to encapsulate the HTTP metrics for each endpoint
macro_rules! with_metrics {
    ($method:expr, $name:expr) => {{
        let mut labels = HashMap::new();
        labels.insert("handler", $name);

        HTTP_COUNTER.with(&labels.clone()).inc();
        let timer = HTTP_REQ_HISTOGRAM.with(&labels).start_timer();
        let result = $method;
        timer.observe_duration();
        result
    }}
}

lazy_static! {
    static ref HTTP_COUNTER: CounterVec = register_counter_vec!(
        opts!(
            "http_requests_total",
            "Total number of HTTP requests made."),
        &["handler"]).unwrap();

    static ref HTTP_REQ_HISTOGRAM: HistogramVec = register_histogram_vec!(
        histogram_opts!(
            "http_request_duration_seconds",
            "HTTP request latencies in seconds."),
        &["handler"]).unwrap();
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ListenAddr(SocketAddr);

impl ListenAddr {
    pub fn new(ip: IpAddr, port: u16) -> ListenAddr {
        ListenAddr(SocketAddr::new(ip, port))
    }
}

impl Default for ListenAddr {
    fn default() -> ListenAddr {
        ListenAddr(SocketAddr::V4(
            SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 9631),
        ))
    }
}

impl Deref for ListenAddr {
    type Target = SocketAddr;

    fn deref(&self) -> &SocketAddr {
        &self.0
    }
}

impl DerefMut for ListenAddr {
    fn deref_mut(&mut self) -> &mut SocketAddr {
        &mut self.0
    }
}

impl FromStr for ListenAddr {
    type Err = SupError;

    fn from_str(val: &str) -> Result<Self> {
        match SocketAddr::from_str(val) {
            Ok(addr) => Ok(ListenAddr(addr)),
            Err(_) => {
                match IpAddr::from_str(val) {
                    Ok(ip) => {
                        let mut addr = ListenAddr::default();
                        addr.set_ip(ip);
                        Ok(addr)
                    }
                    Err(_) => Err(sup_error!(Error::IPFailed)),
                }
            }
        }
    }
}

impl ToSocketAddrs for ListenAddr {
    type Iter = option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
        self.0.to_socket_addrs()
    }
}

impl fmt::Display for ListenAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        write!(f, "{}", self.0)
    }
}

struct ManagerFs;

impl typemap::Key for ManagerFs {
    type Value = manager::FsCfg;
}

pub struct Server(Iron<Chain>, ListenAddr);

impl Server {
    pub fn new(manager_state: Arc<manager::FsCfg>, listen_addr: ListenAddr) -> Self {
        let router =
            router!(
            doc: get "/" => with_metrics!(doc, "doc"),
            butterfly: get "/butterfly" => with_metrics!(butterfly, "butterfly"),
            census: get "/census" => with_metrics!(census, "census"),
            metrics: get "/metrics" => with_metrics!(metrics, "metrics"),
            services: get "/services" => with_metrics!(services, "services"),
            service: get "/services/:svc/:group" => {
                with_metrics!(service, "service")
            },
            service_org: get "/services/:svc/:group/:org" => {
                with_metrics!(service, "service")
            },
            service_config: get "/services/:svc/:group/config" => {
                with_metrics!(config, "config")
            },
            service_health: get "/services/:svc/:group/health" => with_metrics!(health, "health"),
            service_config_org: get "/services/:svc/:group/:org/config" => {
                with_metrics!(config, "config")
            },
            service_health_org: get "/services/:svc/:group/:org/health" => {
                with_metrics!(health, "config")
            }
        );
        let mut chain = Chain::new(router);
        chain.link(persistent::Read::<ManagerFs>::both(manager_state));
        Server(Iron::new(chain), listen_addr)
    }

    pub fn start(self) -> Result<JoinHandle<()>> {
        let handle = thread::Builder::new()
            .name("http-gateway".to_string())
            .spawn(move || {
                self.0.http(*self.1).expect(
                    "unable to start http-gateway thread",
                );
            })?;
        Ok(handle)
    }
}

#[derive(Default, Serialize)]
struct HealthCheckBody {
    stdout: String,
    stderr: String,
}

fn butterfly(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.butterfly_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn census(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.census_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn config(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let service_group = match build_service_group(req) {
        Ok(sg) => sg,
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match service_from_file(&service_group, &state.services_data_path) {
        Ok(Some(service)) => {
            Ok(Response::with((
                status::Ok,
                Header(headers::ContentType::json()),
                service["cfg"].to_string(),
            )))
        }
        Ok(None) => Ok(Response::with(status::NotFound)),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn health(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let (health_file, stdout_path, stderr_path) = match build_service_group(req) {
        Ok(sg) => {
            (
                state.health_check_cache(&sg),
                hooks::stdout_log_path::<HealthCheckHook>(&sg),
                hooks::stderr_log_path::<HealthCheckHook>(&sg),
            )
        }
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match File::open(&health_file) {
        Ok(mut file) => {
            let mut buf = String::new();
            let mut body = HealthCheckBody::default();
            file.read_to_string(&mut buf).unwrap();
            let code = i8::from_str(buf.trim()).unwrap();
            let status: status::Status = HealthCheck::from(code).into();
            if let Ok(mut file) = File::open(&stdout_path) {
                let _ = file.read_to_string(&mut body.stdout);
            }
            if let Ok(mut file) = File::open(&stderr_path) {
                let _ = file.read_to_string(&mut body.stderr);
            }
            Ok(Response::with((
                status,
                Header(headers::ContentType::json()),
                serde_json::to_string(&body).unwrap(),
            )))
        }
        Err(_) => Ok(Response::with(status::NotFound)),
    }
}

fn service(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let service_group = match build_service_group(req) {
        Ok(sg) => sg,
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match service_from_file(&service_group, &state.services_data_path) {
        Ok(Some(service)) => {
            Ok(Response::with((
                status::Ok,
                Header(headers::ContentType::json()),
                service.to_string(),
            )))
        }
        Ok(None) => Ok(Response::with(status::NotFound)),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn services(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.services_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn doc(_req: &mut Request) -> IronResult<Response> {
    Ok(Response::with(
        (status::Ok, Header(headers::ContentType::html()), APIDOCS),
    ))
}

fn metrics(_req: &mut Request) -> IronResult<Response> {
    let mut buffer = vec![];
    let encoder = TextEncoder::new();
    let metric_familys = prometheus::gather();
    encoder.encode(&metric_familys, &mut buffer).unwrap();

    Ok(Response::with(
        (status::Ok, String::from_utf8(buffer).unwrap()),
    ))
}

impl Into<Response> for HealthCheck {
    fn into(self) -> Response {
        let status: status::Status = self.into();
        Response::with(status)
    }
}

impl Into<status::Status> for HealthCheck {
    fn into(self) -> status::Status {
        match self {
            HealthCheck::Ok | HealthCheck::Warning => status::Ok,
            HealthCheck::Critical => status::ServiceUnavailable,
            HealthCheck::Unknown => status::InternalServerError,
        }
    }
}

fn build_service_group(req: &mut Request) -> Result<ServiceGroup> {
    let app_env = match req.extensions.get::<Router>().unwrap().find(
        "application_environment",
    ) {
        Some(s) => {
            match ApplicationEnvironment::from_str(s) {
                Ok(app_env) => Some(app_env),
                Err(_) => None,
            }
        }
        None => None,
    };
    let sg = ServiceGroup::new(
        app_env.as_ref(),
        req.extensions
            .get::<Router>()
            .unwrap()
            .find("svc")
            .unwrap_or(""),
        req.extensions
            .get::<Router>()
            .unwrap()
            .find("group")
            .unwrap_or(""),
        req.extensions.get::<Router>().unwrap().find("org"),
    )?;
    Ok(sg)
}

fn service_from_file<T>(
    service_group: &ServiceGroup,
    services_data_path: T,
) -> result::Result<Option<Json>, io::Error>
where
    T: AsRef<Path>,
{
    match File::open(services_data_path) {
        Ok(file) => {
            match serde_json::from_reader(file) {
                Ok(Json::Array(services)) => {
                    Ok(services.into_iter().find(|s| {
                        s["service_group"] == service_group.as_ref()
                    }))
                }
                _ => Ok(None),
            }
        }
        Err(err) => Err(err),
    }
}
<commit_msg>Expose health-check status in HTTP gateway response<commit_after>// Copyright (c) 2016-2017 Chef Software Inc. and/or applicable contributors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

use std::collections::HashMap;
use std::fmt;
use std::fs::File;
use std::io::{self, Read};
use std::net::{IpAddr, Ipv4Addr, ToSocketAddrs, SocketAddr, SocketAddrV4};
use std::ops::{Deref, DerefMut};
use std::option;
use std::path::Path;
use std::result;
use std::str::FromStr;
use std::sync::Arc;
use std::thread::{self, JoinHandle};

use hcore::service::{ApplicationEnvironment, ServiceGroup};
use iron::prelude::*;
use iron::{headers, status, typemap};
use iron::modifiers::Header;
use persistent;
use prometheus::{self, CounterVec, HistogramVec, TextEncoder, Encoder};
use router::Router;
use serde_json::{self, Value as Json};

use error::{Result, Error, SupError};
use manager;
use manager::service::HealthCheck;
use manager::service::hooks::{self, HealthCheckHook};

static LOGKEY: &'static str = "HG";
const APIDOCS: &'static str = include_str!(concat!(env!("OUT_DIR"), "/api.html"));

// Simple macro to encapsulate the HTTP metrics for each endpoint
macro_rules! with_metrics {
    ($method:expr, $name:expr) => {{
        let mut labels = HashMap::new();
        labels.insert("handler", $name);

        HTTP_COUNTER.with(&labels.clone()).inc();
        let timer = HTTP_REQ_HISTOGRAM.with(&labels).start_timer();
        let result = $method;
        timer.observe_duration();
        result
    }}
}

lazy_static! {
    static ref HTTP_COUNTER: CounterVec = register_counter_vec!(
        opts!(
            "http_requests_total",
            "Total number of HTTP requests made."),
        &["handler"]).unwrap();

    static ref HTTP_REQ_HISTOGRAM: HistogramVec = register_histogram_vec!(
        histogram_opts!(
            "http_request_duration_seconds",
            "HTTP request latencies in seconds."),
        &["handler"]).unwrap();
}

#[derive(PartialEq, Eq, Debug, Clone)]
pub struct ListenAddr(SocketAddr);

impl ListenAddr {
    pub fn new(ip: IpAddr, port: u16) -> ListenAddr {
        ListenAddr(SocketAddr::new(ip, port))
    }
}

impl Default for ListenAddr {
    fn default() -> ListenAddr {
        ListenAddr(SocketAddr::V4(
            SocketAddrV4::new(Ipv4Addr::new(0, 0, 0, 0), 9631),
        ))
    }
}

impl Deref for ListenAddr {
    type Target = SocketAddr;

    fn deref(&self) -> &SocketAddr {
        &self.0
    }
}

impl DerefMut for ListenAddr {
    fn deref_mut(&mut self) -> &mut SocketAddr {
        &mut self.0
    }
}

impl FromStr for ListenAddr {
    type Err = SupError;

    fn from_str(val: &str) -> Result<Self> {
        match SocketAddr::from_str(val) {
            Ok(addr) => Ok(ListenAddr(addr)),
            Err(_) => {
                match IpAddr::from_str(val) {
                    Ok(ip) => {
                        let mut addr = ListenAddr::default();
                        addr.set_ip(ip);
                        Ok(addr)
                    }
                    Err(_) => Err(sup_error!(Error::IPFailed)),
                }
            }
        }
    }
}

impl ToSocketAddrs for ListenAddr {
    type Iter = option::IntoIter<SocketAddr>;

    fn to_socket_addrs(&self) -> io::Result<Self::Iter> {
        self.0.to_socket_addrs()
    }
}

impl fmt::Display for ListenAddr {
    fn fmt(&self, f: &mut fmt::Formatter) -> result::Result<(), fmt::Error> {
        write!(f, "{}", self.0)
    }
}

struct ManagerFs;

impl typemap::Key for ManagerFs {
    type Value = manager::FsCfg;
}

pub struct Server(Iron<Chain>, ListenAddr);

impl Server {
    pub fn new(manager_state: Arc<manager::FsCfg>, listen_addr: ListenAddr) -> Self {
        let router =
            router!(
            doc: get "/" => with_metrics!(doc, "doc"),
            butterfly: get "/butterfly" => with_metrics!(butterfly, "butterfly"),
            census: get "/census" => with_metrics!(census, "census"),
            metrics: get "/metrics" => with_metrics!(metrics, "metrics"),
            services: get "/services" => with_metrics!(services, "services"),
            service: get "/services/:svc/:group" => {
                with_metrics!(service, "service")
            },
            service_org: get "/services/:svc/:group/:org" => {
                with_metrics!(service, "service")
            },
            service_config: get "/services/:svc/:group/config" => {
                with_metrics!(config, "config")
            },
            service_health: get "/services/:svc/:group/health" => with_metrics!(health, "health"),
            service_config_org: get "/services/:svc/:group/:org/config" => {
                with_metrics!(config, "config")
            },
            service_health_org: get "/services/:svc/:group/:org/health" => {
                with_metrics!(health, "config")
            }
        );
        let mut chain = Chain::new(router);
        chain.link(persistent::Read::<ManagerFs>::both(manager_state));
        Server(Iron::new(chain), listen_addr)
    }

    pub fn start(self) -> Result<JoinHandle<()>> {
        let handle = thread::Builder::new()
            .name("http-gateway".to_string())
            .spawn(move || {
                self.0.http(*self.1).expect(
                    "unable to start http-gateway thread",
                );
            })?;
        Ok(handle)
    }
}

#[derive(Default, Serialize)]
struct HealthCheckBody {
    status: String,
    stdout: String,
    stderr: String,
}

fn butterfly(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.butterfly_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn census(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.census_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn config(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let service_group = match build_service_group(req) {
        Ok(sg) => sg,
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match service_from_file(&service_group, &state.services_data_path) {
        Ok(Some(service)) => {
            Ok(Response::with((
                status::Ok,
                Header(headers::ContentType::json()),
                service["cfg"].to_string(),
            )))
        }
        Ok(None) => Ok(Response::with(status::NotFound)),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn health(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let (health_file, stdout_path, stderr_path) = match build_service_group(req) {
        Ok(sg) => {
            (
                state.health_check_cache(&sg),
                hooks::stdout_log_path::<HealthCheckHook>(&sg),
                hooks::stderr_log_path::<HealthCheckHook>(&sg),
            )
        }
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match File::open(&health_file) {
        Ok(mut file) => {
            let mut buf = String::new();
            let mut body = HealthCheckBody::default();
            file.read_to_string(&mut buf).unwrap();
            let code = i8::from_str(buf.trim()).unwrap();
            let health_check = HealthCheck::from(code);
            let http_status: status::Status = HealthCheck::from(code).into();

            body.status = health_check.to_string();
            if let Ok(mut file) = File::open(&stdout_path) {
                let _ = file.read_to_string(&mut body.stdout);
            }
            if let Ok(mut file) = File::open(&stderr_path) {
                let _ = file.read_to_string(&mut body.stderr);
            }

            Ok(Response::with((
                http_status,
                Header(headers::ContentType::json()),
                serde_json::to_string(&body).unwrap(),
            )))
        }
        Err(_) => Ok(Response::with(status::NotFound)),
    }
}

fn service(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    let service_group = match build_service_group(req) {
        Ok(sg) => sg,
        Err(_) => return Ok(Response::with(status::BadRequest)),
    };
    match service_from_file(&service_group, &state.services_data_path) {
        Ok(Some(service)) => {
            Ok(Response::with((
                status::Ok,
                Header(headers::ContentType::json()),
                service.to_string(),
            )))
        }
        Ok(None) => Ok(Response::with(status::NotFound)),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn services(req: &mut Request) -> IronResult<Response> {
    let state = req.get::<persistent::Read<ManagerFs>>().unwrap();
    match File::open(&state.services_data_path) {
        Ok(file) => Ok(Response::with(
            (status::Ok, Header(headers::ContentType::json()), file),
        )),
        Err(_) => Ok(Response::with(status::ServiceUnavailable)),
    }
}

fn doc(_req: &mut Request) -> IronResult<Response> {
    Ok(Response::with(
        (status::Ok, Header(headers::ContentType::html()), APIDOCS),
    ))
}

fn metrics(_req: &mut Request) -> IronResult<Response> {
    let mut buffer = vec![];
    let encoder = TextEncoder::new();
    let metric_familys = prometheus::gather();
    encoder.encode(&metric_familys, &mut buffer).unwrap();

    Ok(Response::with(
        (status::Ok, String::from_utf8(buffer).unwrap()),
    ))
}

impl Into<Response> for HealthCheck {
    fn into(self) -> Response {
        let status: status::Status = self.into();
        Response::with(status)
    }
}

impl Into<status::Status> for HealthCheck {
    fn into(self) -> status::Status {
        match self {
            HealthCheck::Ok | HealthCheck::Warning => status::Ok,
            HealthCheck::Critical => status::ServiceUnavailable,
            HealthCheck::Unknown => status::InternalServerError,
        }
    }
}

fn build_service_group(req: &mut Request) -> Result<ServiceGroup> {
    let app_env = match req.extensions.get::<Router>().unwrap().find(
        "application_environment",
    ) {
        Some(s) => {
            match ApplicationEnvironment::from_str(s) {
                Ok(app_env) => Some(app_env),
                Err(_) => None,
            }
        }
        None => None,
    };
    let sg = ServiceGroup::new(
        app_env.as_ref(),
        req.extensions
            .get::<Router>()
            .unwrap()
            .find("svc")
            .unwrap_or(""),
        req.extensions
            .get::<Router>()
            .unwrap()
            .find("group")
            .unwrap_or(""),
        req.extensions.get::<Router>().unwrap().find("org"),
    )?;
    Ok(sg)
}

fn service_from_file<T>(
    service_group: &ServiceGroup,
    services_data_path: T,
) -> result::Result<Option<Json>, io::Error>
where
    T: AsRef<Path>,
{
    match File::open(services_data_path) {
        Ok(file) => {
            match serde_json::from_reader(file) {
                Ok(Json::Array(services)) => {
                    Ok(services.into_iter().find(|s| {
                        s["service_group"] == service_group.as_ref()
                    }))
                }
                _ => Ok(None),
            }
        }
        Err(err) => Err(err),
    }
}
<|endoftext|>