<commit_before>extern crate clap;
extern crate goblin;
extern crate rustc_demangle;
extern crate toml;
extern crate capstone;
#[macro_use] extern crate quick_error;

pub mod symbol;

use clap::{Arg, App, SubCommand, AppSettings};
use symbol::Symbol;

use std::fs::File;
use std::io::{self, Cursor, Read, Seek, ErrorKind};
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
use std::result;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) { from () }
        CapstoneError(err: capstone::error::Error) { from ()}
        UnsupportedBinary { from() }
        SectionlessBinary { description("Cannot analyze and disassemble a sectionless (section stripped) binary") from() }
        StrippedBinary { description("Cannot analyze and disassemble a stripped binary") from() }
    }
}

type Result<T> = result::Result<T, Error>;

/// The command line state we're interested in
pub struct Config {
    pub exports: bool,
    pub demangle: bool,
    pub crate_name: String,
    pub disassemble: bool,
}

/// A fibulurous Trans-Ductinator which hammifies the Symglob
/// - It knows how to return `Symbol`s
/// When a new binary backend becomes available, `impl` a new TransDuctinator!
pub trait TransDuctinator {
    fn get_arch(&self) -> Option<capstone::Arch>;
    fn is_64(&self) -> bool;
    fn symbols(&self, config: &Config) -> Vec<Symbol>;
    fn disassemble(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()>;
    fn print_symbols(&self, config: &Config) {
        for symbol in self.symbols(config) {
            println!("{}", symbol.format(config.demangle, self.is_64()))
        }
    }
    fn run (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        if config.disassemble {
            self.disassemble(bytes, config)?;
        } else {
            self.print_symbols(config);
        }
        Ok(())
    }
}

#[inline]
fn print_disass(bytes: &[u8], capstone: &capstone::Capstone, symbol: Symbol, demangle: bool, is_64: bool) -> Result<()> {
    let offset = symbol.offset as usize;
    let bytes = &bytes[offset .. offset + symbol.size];
    let instructions = capstone.disassemble(bytes, symbol.vaddr)?;
    if !instructions.is_empty() {
        println!("{}:\n{}", symbol.format(demangle, is_64), instructions);
    }
    Ok(())
}

#[inline]
fn bias (sym: &goblin::elf::Sym, section: &goblin::elf::SectionHeader) -> u64 {
    (sym.st_value() - section.sh_addr()) + section.sh_offset()
}

// this is all terribly inefficient right now, primarily due to goblin parsing and reading everything
// on earth. that should be fixed soon with some special magiks
impl TransDuctinator for goblin::elf::Elf {
    fn is_64(&self) -> bool {
        self.is_64
    }
    fn symbols(&self, config: &Config) -> Vec<Symbol> {
        let mut syms = Vec::new();
        let (iter, strtab) = if config.exports {
            (&self.dynsyms, &self.dynstrtab)
        } else {
            (&self.syms, &self.strtab)
        };
        for sym in iter {
            let name = &strtab[sym.st_name() as usize];
            // we skip boring empty symbol names and imports
            if !name.is_empty() && (!config.exports || !sym.is_import()) {
                syms.push(Symbol::new(name, sym.st_value(), sym.st_value(), sym.st_size() as usize));
            }
        }
        syms.sort_by(|s1, s2| s1.offset.cmp(&s2.offset));
        syms
    }

    fn get_arch(&self) -> Option<capstone::Arch> {
        use goblin::elf::header::*;
        use capstone::Arch::*;
        match self.header.e_machine() {
            EM_AARCH64 => Some(ARM64),
            EM_ARM => Some(ARM),
            EM_X86_64 => Some(X86),
            EM_386 => Some(X86),
            _ => None
        }
    }

    fn disassemble (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        let arch = self.get_arch().ok_or(Error::UnsupportedBinary)?;
        let mut capstone = capstone::Capstone::new(arch)?;
        capstone.att();
        let mode = if self.little_endian { capstone::Mode::LittleEndian } else { capstone::Mode::BigEndian };
        capstone.mode(&[mode])?;
        let strtab = &self.strtab;
        let shdr_strtab = &self.shdr_strtab;
        let bytes = bytes.get_ref();
        let section_headers = &self.section_headers;
        if section_headers.len() == 0 { return Err(Error::SectionlessBinary)}
        let sections: Vec<(_, &str)> = section_headers.into_iter().map (| section | {
            let section_name = &shdr_strtab[section.sh_name()];
            (section, section_name)
        }).collect();
        let syms = &self.syms;
        if syms.len() == 0 { return Err(Error::StrippedBinary)}
        // filter the symbols to remove imports and empty symbol names
        let mut elf_syms = syms.into_iter().filter(|sym| !sym.is_import() && !&strtab[sym.st_name()].is_empty()).collect::<Vec<_>>();
        elf_syms.sort_by(|s1, s2| {
            use std::cmp::Ordering::*;
            match s1.st_shndx().cmp(&s2.st_shndx()) {
                Equal => {
                    s1.st_value().cmp(&s2.st_value())
                },
                order => order
            }
        });
        let mut current_section = 0;
        let nsyms = elf_syms.len();
        let mut i = 0;
        for sym in &elf_syms {
            //println!("name: {} st_shndx: {}", &strtab[sym.st_name()],  sym.st_shndx());
            //println!("{} {:?}", &strtab[sym.st_name()], sym);
            let is_last = i >= nsyms - 1;
            let section_index = sym.st_shndx();
            if section_index >= sections.len() { continue }
            let (ref section, ref section_name) = sections[sym.st_shndx() as usize];
            if section.sh_type() != goblin::elf::section_header::SHT_PROGBITS || !valid_disassembly_target(section_name) { continue }
            //if name.is_empty() { name = format!("{}@{}", &dynstrtab[sym.st_name()], section_name)}
            if current_section != section_index {
                current_section = section_index;
                println!("Disassembly of section {}\n", section_name);
                match section_name {
                    // TODO: this is now a _broken_ hack for printing PLT entries (it doesn't print them,
                    // because there are no longer any symbols with the plt section to set off this logic)
                    &".plt" | &".plt.got" => {
                        let start = section.sh_offset();
                        let vaddr = section.sh_addr();
                        let ssize = section.sh_entsize() as usize;
                        let size = section.sh_entsize();
                        let strtab = &self.dynstrtab;
                        let symbol = Symbol::new(&"PLT", start, vaddr, ssize);
                        print_disass(&bytes, &capstone, symbol, config.demangle, self.is_64)?;
                        let mut offset = size;
                        for rela in &self.pltrela {
                            let start = start + offset;
                            let vaddr = vaddr + offset;
                            let symindex = rela.r_sym();
                            let sym = self.dynsyms.get(symindex);
                            let name = &strtab[sym.st_name()];
                            //println!("name: {} offset {:x} size: {} shname: {} shoffset: {:x} shaddr: {:x}", name, rela.r_offset(), size, section_name, section.sh_offset(), section.sh_addr());
                            let symbol = Symbol::new(&name, start, vaddr, ssize);
                            print_disass(&bytes, &capstone, symbol, config.demangle, self.is_64)?;
                            offset += size;
                        }
                    },
                    _ => ()
                }
            }
            // we're not doing plt stuff, so regular disassembly
            let name = &strtab[sym.st_name()];
            if name.is_empty() { continue }
            let mut size = sym.st_size() as usize;
            let offset = bias(&sym, &section);
            // we compute the size of unsized symbols on the fly. it sucks. because elf sucks.
            if size == 0 && !is_last {
                let next_sym = &elf_syms[i + 1];
                //println!("i: {} current {}, name{} next: {:?}", i, current_section, name, next_sym);
                if current_section == next_sym.st_shndx() {
                    let next_offset = bias(&next_sym, &section);
                    size = (next_offset - offset) as usize;
                } else {
                    size = section.sh_size() as usize;
                }
            }
            //println!("offset {:x} size: {} section: {}, sh_type: {}", offset, size, section_name, section_header::sht_to_str(section.sh_type()));
            let symbol = Symbol::new(name, offset, sym.st_value(), size);
            print_disass(&bytes, &capstone, symbol, config.demangle, self.is_64)?;
            i += 1;
        }
        Ok(())
    }
}

fn get_crate_name() -> String {
    let mut toml_fd = File::open("Cargo.toml")
                          .expect("No Cargo.toml file found in root directory...");
    let mut toml = String::new();
    let _ = toml_fd.read_to_string(&mut toml);
    let value: toml::Value = toml.parse().expect("Malformed Cargo.toml file");
    let package_name = value.lookup("package.name")
                            .expect("No package.name in Cargo.toml")
                            .as_str()
                            .unwrap()
                            .to_owned()
        // we only replace this if it's a library..., so this breaks on ourself :/
                            .replace("-", "_");
    package_name
}

fn get_target(crate_name: &str) -> Option<PathBuf> {
    let targets = [Path::new("target").join("debug").join(&crate_name),
                   Path::new("target").join("debug").join(&format!("lib{}.so", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.rlib", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.a", &crate_name))];
    for target in &targets {
        match File::open(&target) {
            Ok(_) => return Some(target.clone()),
            _ => (),
        }
    }
    None
}

fn valid_disassembly_target(name: &str) -> bool {
    match name {
        ".init" | ".plt" | ".plt.got" | ".text" | ".fini" => true,
        _ => false,
    }
}

fn run(fd: &mut File, config: &Config) -> Result<()> {
    // todo write a generic peek function in goblin you jerk
    let mut magic = [0u8; 16];
    let err = ErrorKind::InvalidInput;
    let metadata = fd.metadata()?;
    let mut buffer = Vec::new();
    fd.read_to_end(&mut buffer)?;
    let mut bytes = &mut Cursor::new(&buffer);
    bytes.read(&mut magic)?;
    bytes.seek(SeekFrom::Start(0))?;
    if &magic[0..goblin::archive::SIZEOF_MAGIC] == goblin::archive::MAGIC {
        let archive = goblin::archive::Archive::parse(bytes, metadata.len() as usize)?;
        let bytes = archive.extract(&format!("{}.0.o", &config.crate_name), bytes)?;
        let mut bytes = Cursor::new(&bytes);
        // ideally would pattern match (or just recurse) on the identifier here but we're only supporting elf
        let elf = goblin::elf::Elf::parse(&mut bytes)?;
        elf.run(&mut bytes, config)
    } else if &magic[0..4] == goblin::elf::header::ELFMAG {
        let elf = goblin::elf::Elf::parse(bytes)?;
        elf.run(bytes, config)
    } else {
        Err(Error::from(io::Error::new(err,
                           format!("No binary backend available for target: {:?}", &fd))))
    }
}

fn main() {

    let matches = App::new("cargo-sym")
                      .version("0.0.3")
                      .bin_name("cargo")
                      .settings(&[AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
                      .subcommand(SubCommand::with_name("sym")
                                      .author("m4b <m4b.github.io@gmail.com>")
                                      .about("Prints the debugging symbols in your binary; more \
                                              fancy stuff to come later")
                                      .args(&[Arg::with_name("binary")
                                                  .help("The binary file to read ")
                                                  .required(false)
                                                  .index(1),
                                          Arg::with_name("disassemble")
                                              .short("-d")
                                              .long("disassemble")
                                              .value_name("DISASSEMBLE")
                                              .takes_value(false)
                                              .help("Whether to disassaemble or not "),
                                          Arg::with_name("demangle")
                                                  .short("-C")
                                                  .long("demangle")
                                                  .value_name("DEMANGLE")
                                                  .takes_value(false)
                                                  .help("Whether to demangle or not "),
                                              Arg::with_name("exports")
                                                  .short("-e")
                                                  .long("exports")
                                                  .value_name("EXPORTS")
                                                  .takes_value(false)
                                                  .help("Print the exported symbols that are \
                                                         importable by other binaries")]))
                      .get_matches();

    let crate_name = get_crate_name();
    let matches = matches.subcommand_matches("sym").unwrap();
    let demangle = matches.is_present("demangle");
    let exports = matches.is_present("exports");
    let disassemble = matches.is_present("disassemble");
    let config = Config {
        demangle: demangle,
        exports: exports,
        crate_name: crate_name.to_string(),
        disassemble: disassemble,
    };
    let mut fd = match matches.value_of("binary") {
                     Some(binary) => File::open(Path::new(binary)),
                     _ => File::open(get_target(&crate_name).expect("No valid binary found")),
                 }
                 .expect("Cannot open file");

    run(&mut fd, &config)
        .expect(&format!("Cannot read symbols from: {:?}", &fd));
}
<commit_msg>generify print_disasm -> print_instructions<commit_after>extern crate clap;
extern crate goblin;
extern crate rustc_demangle;
extern crate toml;
extern crate capstone;
#[macro_use] extern crate quick_error;

pub mod symbol;

use clap::{Arg, App, SubCommand, AppSettings};
use symbol::Symbol;

use std::fs::File;
use std::io::{self, Cursor, Read, Seek, ErrorKind};
use std::io::SeekFrom;
use std::path::{Path, PathBuf};
use std::result;

quick_error! {
    #[derive(Debug)]
    pub enum Error {
        Io(err: std::io::Error) { from () }
        CapstoneError(err: capstone::error::Error) { from ()}
        UnsupportedBinary { from() }
        SectionlessBinary { description("Cannot analyze and disassemble a sectionless (section stripped) binary") from() }
        StrippedBinary { description("Cannot analyze and disassemble a stripped binary") from() }
    }
}

type Result<T> = result::Result<T, Error>;

/// The command line state we're interested in
pub struct Config {
    pub exports: bool,
    pub demangle: bool,
    pub crate_name: String,
    pub disassemble: bool,
}

/// A fibulurous Trans-Ductinator which hammifies the Symglob
/// - It knows how to return `Symbol`s _and_ disassemble itself
/// When a new binary backend becomes available, `impl` a new TransDuctinator!
pub trait TransDuctinator {
    fn get_arch(&self) -> Option<capstone::Arch>;
    fn is_64(&self) -> bool;
    fn symbols(&self, config: &Config) -> Vec<Symbol>;
    fn disassemble(&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()>;
    #[inline]
    fn print_instructions(&self, bytes: &[u8], config: &Config, capstone: &capstone::Capstone, symbol: Symbol) -> Result<()> {
        let offset = symbol.offset as usize;
        let bytes = &bytes[offset .. offset + symbol.size];
        let instructions = capstone.disassemble(bytes, symbol.vaddr)?;
        if !instructions.is_empty() {
            println!("{}:\n{}", symbol.format(config.demangle, self.is_64()), instructions);
        }
        Ok(())
    }
    fn print_symbols(&self, config: &Config) {
        for symbol in self.symbols(config) {
            println!("{}", symbol.format(config.demangle, self.is_64()))
        }
    }
    fn run (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        if config.disassemble {
            self.disassemble(bytes, config)?;
        } else {
            self.print_symbols(config);
        }
        Ok(())
    }
}

#[inline]
fn bias (sym: &goblin::elf::Sym, section: &goblin::elf::SectionHeader) -> u64 {
    (sym.st_value() - section.sh_addr()) + section.sh_offset()
}

// this is all terribly inefficient right now, primarily due to goblin parsing and reading everything
// on earth. that should be fixed soon with some special magiks
impl TransDuctinator for goblin::elf::Elf {
    fn is_64(&self) -> bool {
        self.is_64
    }
    fn symbols(&self, config: &Config) -> Vec<Symbol> {
        let mut syms = Vec::new();
        let (iter, strtab) = if config.exports {
            (&self.dynsyms, &self.dynstrtab)
        } else {
            (&self.syms, &self.strtab)
        };
        for sym in iter {
            let name = &strtab[sym.st_name() as usize];
            // we skip boring empty symbol names and imports
            if !name.is_empty() && (!config.exports || !sym.is_import()) {
                syms.push(Symbol::new(name, sym.st_value(), sym.st_value(), sym.st_size() as usize));
            }
        }
        syms.sort_by(|s1, s2| s1.offset.cmp(&s2.offset));
        syms
    }

    fn get_arch(&self) -> Option<capstone::Arch> {
        use goblin::elf::header::*;
        use capstone::Arch::*;
        match self.header.e_machine() {
            EM_AARCH64 => Some(ARM64),
            EM_ARM => Some(ARM),
            EM_X86_64 => Some(X86),
            EM_386 => Some(X86),
            _ => None
        }
    }

    fn disassemble (&self, bytes: &mut Cursor<&Vec<u8>>, config: &Config) -> Result<()> {
        let arch = self.get_arch().ok_or(Error::UnsupportedBinary)?;
        let mut capstone = capstone::Capstone::new(arch)?;
        capstone.att();
        let mode = if self.little_endian { capstone::Mode::LittleEndian } else { capstone::Mode::BigEndian };
        capstone.mode(&[mode])?;
        let strtab = &self.strtab;
        let shdr_strtab = &self.shdr_strtab;
        let bytes = bytes.get_ref();
        let section_headers = &self.section_headers;
        if section_headers.len() == 0 { return Err(Error::SectionlessBinary)}
        let sections: Vec<(_, &str)> = section_headers.into_iter().map (| section | {
            let section_name = &shdr_strtab[section.sh_name()];
            (section, section_name)
        }).collect();
        let syms = &self.syms;
        if syms.len() == 0 { return Err(Error::StrippedBinary)}
        // filter the symbols to remove imports and empty symbol names
        let mut elf_syms = syms.into_iter().filter(|sym| !sym.is_import() && !&strtab[sym.st_name()].is_empty()).collect::<Vec<_>>();
        elf_syms.sort_by(|s1, s2| {
            use std::cmp::Ordering::*;
            match s1.st_shndx().cmp(&s2.st_shndx()) {
                Equal => {
                    s1.st_value().cmp(&s2.st_value())
                },
                order => order
            }
        });
        let mut current_section = 0;
        let nsyms = elf_syms.len();
        let mut i = 0;
        for sym in &elf_syms {
            //println!("name: {} st_shndx: {}", &strtab[sym.st_name()],  sym.st_shndx());
            //println!("{} {:?}", &strtab[sym.st_name()], sym);
            let is_last = i >= nsyms - 1;
            let section_index = sym.st_shndx();
            if section_index >= sections.len() { continue }
            let (ref section, ref section_name) = sections[sym.st_shndx() as usize];
            if section.sh_type() != goblin::elf::section_header::SHT_PROGBITS || !valid_disassembly_target(section_name) { continue }
            //if name.is_empty() { name = format!("{}@{}", &dynstrtab[sym.st_name()], section_name)}
            if current_section != section_index {
                current_section = section_index;
                println!("Disassembly of section {}\n", section_name);
                match section_name {
                    // TODO: this is now a _broken_ hack for printing PLT entries (it doesn't print them,
                    // because there are no longer any symbols with the plt section to set off this logic)
                    &".plt" | &".plt.got" => {
                        let start = section.sh_offset();
                        let vaddr = section.sh_addr();
                        let ssize = section.sh_entsize() as usize;
                        let size = section.sh_entsize();
                        let strtab = &self.dynstrtab;
                        let symbol = Symbol::new(&"PLT", start, vaddr, ssize);
                        self.print_instructions(&bytes, config, &capstone, symbol)?;
                        let mut offset = size;
                        for rela in &self.pltrela {
                            let start = start + offset;
                            let vaddr = vaddr + offset;
                            let symindex = rela.r_sym();
                            let sym = self.dynsyms.get(symindex);
                            let name = &strtab[sym.st_name()];
                            //println!("name: {} offset {:x} size: {} shname: {} shoffset: {:x} shaddr: {:x}", name, rela.r_offset(), size, section_name, section.sh_offset(), section.sh_addr());
                            let symbol = Symbol::new(&name, start, vaddr, ssize);
                            self.print_instructions(&bytes, config, &capstone, symbol)?;
                            offset += size;
                        }
                    },
                    _ => ()
                }
            }
            // we're not doing plt stuff, so regular disassembly
            let name = &strtab[sym.st_name()];
            if name.is_empty() { continue }
            let mut size = sym.st_size() as usize;
            let offset = bias(&sym, &section);
            // we compute the size of unsized symbols on the fly. it sucks. because elf sucks.
            if size == 0 && !is_last {
                let next_sym = &elf_syms[i + 1];
                //println!("i: {} current {}, name{} next: {:?}", i, current_section, name, next_sym);
                if current_section == next_sym.st_shndx() {
                    let next_offset = bias(&next_sym, &section);
                    size = (next_offset - offset) as usize;
                } else {
                    size = section.sh_size() as usize;
                }
            }
            //println!("offset {:x} size: {} section: {}, sh_type: {}", offset, size, section_name, section_header::sht_to_str(section.sh_type()));
            let symbol = Symbol::new(name, offset, sym.st_value(), size);
            self.print_instructions(&bytes, config, &capstone, symbol)?;
            i += 1;
        }
        Ok(())
    }
}

fn get_crate_name() -> String {
    let mut toml_fd = File::open("Cargo.toml")
                          .expect("No Cargo.toml file found in root directory...");
    let mut toml = String::new();
    let _ = toml_fd.read_to_string(&mut toml);
    let value: toml::Value = toml.parse().expect("Malformed Cargo.toml file");
    let package_name = value.lookup("package.name")
                            .expect("No package.name in Cargo.toml")
                            .as_str()
                            .unwrap()
                            .to_owned()
        // we only replace this if it's a library..., so this breaks on ourself :/
                            .replace("-", "_");
    package_name
}

fn get_target(crate_name: &str) -> Option<PathBuf> {
    let targets = [Path::new("target").join("debug").join(&crate_name),
                   Path::new("target").join("debug").join(&format!("lib{}.so", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.rlib", &crate_name)),
                   Path::new("target").join("debug").join(&format!("lib{}.a", &crate_name))];
    for target in &targets {
        match File::open(&target) {
            Ok(_) => return Some(target.clone()),
            _ => (),
        }
    }
    None
}

fn valid_disassembly_target(name: &str) -> bool {
    match name {
        ".init" | ".plt" | ".plt.got" | ".text" | ".fini" => true,
        _ => false,
    }
}

fn run(fd: &mut File, config: &Config) -> Result<()> {
    // todo write a generic peek function in goblin you jerk
    let mut magic = [0u8; 16];
    let err = ErrorKind::InvalidInput;
    let metadata = fd.metadata()?;
    let mut buffer = Vec::new();
    fd.read_to_end(&mut buffer)?;
    let mut bytes = &mut Cursor::new(&buffer);
    bytes.read(&mut magic)?;
    bytes.seek(SeekFrom::Start(0))?;
    if &magic[0..goblin::archive::SIZEOF_MAGIC] == goblin::archive::MAGIC {
        let archive = goblin::archive::Archive::parse(bytes, metadata.len() as usize)?;
        let bytes = archive.extract(&format!("{}.0.o", &config.crate_name), bytes)?;
        let mut bytes = Cursor::new(&bytes);
        // ideally would pattern match (or just recurse) on the identifier here but we're only supporting elf
        let elf = goblin::elf::Elf::parse(&mut bytes)?;
        elf.run(&mut bytes, config)
    } else if &magic[0..4] == goblin::elf::header::ELFMAG {
        let elf = goblin::elf::Elf::parse(bytes)?;
        elf.run(bytes, config)
    } else {
        Err(Error::from(io::Error::new(err,
                           format!("No binary backend available for target: {:?}", &fd))))
    }
}

fn main() {

    let matches = App::new("cargo-sym")
                      .version("0.0.3")
                      .bin_name("cargo")
                      .settings(&[AppSettings::GlobalVersion, AppSettings::SubcommandRequired])
                      .subcommand(SubCommand::with_name("sym")
                                      .author("m4b <m4b.github.io@gmail.com>")
                                      .about("Prints the debugging symbols in your binary; more \
                                              fancy stuff to come later")
                                      .args(&[Arg::with_name("binary")
                                                  .help("The binary file to read ")
                                                  .required(false)
                                                  .index(1),
                                          Arg::with_name("disassemble")
                                              .short("-d")
                                              .long("disassemble")
                                              .value_name("DISASSEMBLE")
                                              .takes_value(false)
                                              .help("Whether to disassaemble or not "),
                                          Arg::with_name("demangle")
                                                  .short("-C")
                                                  .long("demangle")
                                                  .value_name("DEMANGLE")
                                                  .takes_value(false)
                                                  .help("Whether to demangle or not "),
                                              Arg::with_name("exports")
                                                  .short("-e")
                                                  .long("exports")
                                                  .value_name("EXPORTS")
                                                  .takes_value(false)
                                                  .help("Print the exported symbols that are \
                                                         importable by other binaries")]))
                      .get_matches();

    let crate_name = get_crate_name();
    let matches = matches.subcommand_matches("sym").unwrap();
    let demangle = matches.is_present("demangle");
    let exports = matches.is_present("exports");
    let disassemble = matches.is_present("disassemble");
    let config = Config {
        demangle: demangle,
        exports: exports,
        crate_name: crate_name.to_string(),
        disassemble: disassemble,
    };
    let mut fd = match matches.value_of("binary") {
                     Some(binary) => File::open(Path::new(binary)),
                     _ => File::open(get_target(&crate_name).expect("No valid binary found")),
                 }
                 .expect("Cannot open file");

    run(&mut fd, &config)
        .expect(&format!("Cannot read symbols from: {:?}", &fd));
}
<|endoftext|>


<commit_before>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(rows: uint) -> Collisions {
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    let mut bytes = Vec::from_elem(16 - rows, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    loop {
        copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
        copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
            copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    for i in range(0, len) {
        let i = len - 1 - i;

        if num[i] == 255 {
            continue;
        }

        num[i] += 1;

        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    false
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(14);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<commit_msg>move out state creation<commit_after>/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */

extern crate "rust-md2" as md2;

use md2::{S, S2, md2_compress};
use std::collections::HashMap;
use std::collections::hash_map::{Occupied, Vacant};
use std::slice::bytes::copy_memory;

type Collision = Vec<Vec<u8>>;
type Collisions = Vec<Collision>;

fn find_collisions(rows: uint) -> Collisions {
    let mut values = create_initial_state(rows);
    let mut bytes = Vec::from_elem(16 - rows, 0u8);
    let mut collisions: HashMap<Vec<u8>,Collision> = HashMap::new();

    loop {
        copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
        copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

        for row in range(rows + 1, 18) {
            // Fill row.
            for i in range(1, 49) {
                values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
            }

            // Next t value.
            values[row + 1][0] = values[row][48] + (row as u8) - 1;
        }

        let key = Vec::from_fn(17 - rows, |row| values[rows + 2 + row][0]);

        match collisions.entry(key) {
            Vacant(entry) => { entry.set(vec!(bytes.clone())); },
            Occupied(mut entry) => { entry.get_mut().push(bytes.clone()); }
        };

        if !increase(bytes.as_mut_slice()) {
            break;
        }
    }

    // Compute original messages for each collision.
    collisions.values().filter(|x| x.len() > 1).map(|collision| {
        collision.iter().map(|bytes| {
            copy_memory(values[rows].slice_mut(17, 17 + 16 - rows), bytes.as_slice());
            copy_memory(values[rows].slice_mut(17 + 16, 17 + 16 - rows + 16), bytes.as_slice());

            // Fill upper rectangles.
            for row in range(0, rows) {
                let row2 = rows - row;
                for col in range(17, 32 - row2 + 2) {
                    values[row2 - 1][col] = S[values[row2][col - 1] as uint] ^ values[row2][col];
                }
            }

            values[0].slice(17, 33).to_vec()
        }).collect()
    }).collect()
}

fn create_initial_state(rows: uint) -> [[u8, ..49], ..19] {
    let mut values = [[0u8, ..49], ..19];

    for row in range(1, rows + 1) {
      // Fill row of T1.
      for i in range(1, 17) {
          values[row][i] = S[values[row][i - 1] as uint] ^ values[row - 1][i];
      }

      // Last bytes are equal.
      values[row][32] = values[row][16];
      values[row][48] = values[row][16];

      // Next t value.
      values[row + 1][0] = values[row][48] + (row as u8) - 1;
    }

    // Compute triangles.
    for col in range(0, rows) {
      for row in range(0, rows - col - 1) {
        let row2 = rows - row;
        values[row2][32 - col - 1] = S2[(values[row2][32 - col] ^ values[row2 - 1][32 - col]) as uint];
        values[row2][48 - col - 1] = S2[(values[row2][48 - col] ^ values[row2 - 1][48 - col]) as uint];
      }
    }

    values
}

fn increase(num: &mut [u8]) -> bool {
    let len = num.len();

    for i in range(0, len) {
        let i = len - 1 - i;

        if num[i] == 255 {
            continue;
        }

        num[i] += 1;

        for i in range(i + 1, len) {
            num[i] = 0;
        }

        return true;
    }

    false
}

fn check_collisions(collisions: &Collisions) -> bool {
    let empty = [0u8, ..16];

    for collision in collisions.iter() {
        let mut first_hash: Option<[u8, ..16]> = None;

        for msg in collision.iter() {
            let md2 = md2_compress(&empty, msg.as_slice());

            match first_hash {
                Some(hash) => {
                    if hash != md2 {
                        return false;
                    }
                }
                None => first_hash = Some(md2)
            };
        }
    }

    true
}

fn main() {
    let collisions = find_collisions(14);
    if !check_collisions(&collisions) {
        panic!("invalid collision found :(");
    }

    println!("Found {} collisions.", collisions.iter().count());
}
<|endoftext|>


<commit_before>extern crate iron;
extern crate router;
extern crate params;
extern crate serde;
extern crate serde_json;
extern crate url;
extern crate mote;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::collections::BTreeMap;
use std::io::Read;

use iron::headers::ContentType;
use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use router::Router;
use url::Url;
use std::sync::Mutex;

mod google_actions;
use google_actions::*;

mod smart_home;
use smart_home::*;

struct Hub {
    devices: Mutex<Vec<Device>>,
}

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        println!("hub handler");
        let mut body = String::new();
        req.body.read_to_string(&mut body).unwrap();
        let action_request: ActionRequest = serde_json::from_str(&body).unwrap();

        println!("action_request: {:?}", action_request);

        for input in action_request.inputs {
            if input.intent == "action.devices.SYNC" {
                let mut response = SyncResponse {
                    request_id: action_request.request_id.clone(),
                    payload: SyncResponsePayload {
                        agent_user_id: "1111".to_string(),
                        devices: vec![],
                    },
                };

                let ref devices = *self.devices.lock().unwrap();
                for device in devices {
                    match device {
                        &Device::Light(ref light) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: light.id.clone(),
                                type_: light.type_.name(),
                                traits: light.available_light_modes
                                    .iter()
                                    .map(LightMode::name)
                                    .collect(),
                                name: Name {
                                    default_name: vec![light.name.to_string()],
                                    name: Some(light.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                            })
                        }
                        &Device::Thermostat(ref thermostat) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: thermostat.id.clone(),
                                type_: "".to_string(), // XXX
                                traits: vec!["action.devices.traits.TemperatureSetting"
                                                 .to_string()],
                                name: Name {
                                    default_name: vec![thermostat.name.to_string()],
                                    name: Some(thermostat.name.clone()),
                                    nicknames: vec![],
                                },
                                // TODO: attributes.
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                            })
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "action.devices.QUERY" {
                let mut response = QueryResponse {
                    request_id: action_request.request_id.clone(),
                    payload: QueryResponsePayload { devices: btreemap!{} },
                };

                let ref devices = *self.devices.lock().unwrap();
                if let Some(payload) = input.payload {
                    for request_device in payload.devices {
                        for device in devices {
                            match device {
                                &Device::Light(ref light) => {
                                    if light.id == request_device.id {}
                                    let light_status = &light.status;
                                    response.payload
                                        .devices
                                        .insert(light.id.clone(),
                                                DeviceStates {
                                                    online: Some(true),
                                                    on: Some(light_status.on),
                                                    brightness: Some(light_status.brightness),
                                                    color: Some(Color {
                                                        name: None,
                                                        temperature: None,
                                                        spectrum_rgb:
                                                            Some(light_status.spectrum_rgb),
                                                    }),
                                                });
                                }
                                &Device::Thermostat(ref thermostat) => {
                                    // TODO
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "action.devices.EXECUTE" {
                let mut response = ExecuteResponse {
                    request_id: action_request.request_id.clone(),
                    payload: ExecuteResponsePayload {
                        error_code: None,
                        debug_string: None,
                        commands: vec![],
                    },
                };

                if let Some(ref p) = input.payload {
                    for command in &p.commands {
                        println!("command: {:?}", command);
                        for execution in &command.execution {
                            let ref mut devices = *self.devices.lock().unwrap();
                            for device in devices {
                                match device {
                                    &mut Device::Light(ref mut light) => {
                                        println!("execution: {:?}", execution);
                                        if let Some(s) = execution.params.on {
                                            light.set_on(s);
                                        }
                                        if let Some(s) = execution.params.brightness {
                                            light.set_brightness(s);
                                        }
                                        if let Some(ref s) = execution.params.color {
                                            if let Some(s) = s.spectrum_rgb {
                                                light.set_spectrum_rgb(s);
                                            }
                                        }
                                    }
                                    &mut Device::Thermostat(ref thermostat) => {}
                                }
                            }
                        }
                        for request_device in &command.devices {
                            println!("device: {:?}", request_device);
                            let ref devices = *self.devices.lock().unwrap();
                            for device in devices {
                                match device {
                                    &Device::Light(ref light) => {
                                        response.payload.commands.push(ExecuteResponseCommand {
                                            ids: vec![light.id.clone()],
                                            status: "SUCCESS".to_string(),
                                            states: DeviceStates {
                                                online: Some(true),
                                                on: Some(light.status.on),
                                                brightness: Some(light.status.brightness),
                                                color: Some(Color {
                                                    name: None,
                                                    temperature: None,
                                                    spectrum_rgb: Some(light.status.spectrum_rgb),
                                                }),
                                            },
                                        });
                                    }
                                    &Device::Thermostat(ref thermostat) => {
                                        // TODO
                                    }
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            }
        }

        let mut rsp = Response::with((status::Ok, "ACTION"));
        rsp.headers.set(ContentType::json());
        Ok(rsp)
    }
}

fn main() {
    let hub = Hub {
        devices: Mutex::new(vec![Device::Light(Light {
                                     id: "11".to_string(),
                                     name: "TV lights".to_string(),
                                     status: LightStatus::default(),
                                     type_: LightType::Light,
                                     available_light_modes: vec![LightMode::OnOff,
                                                                 LightMode::Brightness,
                                                                 LightMode::ColorSpectrum],
                                     mote: mote::Mote::new("/dev/ttyACM0"),
                                 })]),
    };
    let mut control = Router::new();
    control.get("/auth", auth_handler, "auth")
        .post("/token", token_handler, "token")
        .get("/login", login_handler, "login")
        .post("/action", hub, "post action")
        .get("/action", get_action_handler, "get action")
        .get("/", index_handler, "index");
    println!("Listening on port 1234");
    Iron::new(control)
        .http("0.0.0.0:1234")
        .unwrap();
}

fn auth_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["response_type"]);
    let _ = map.find(&["client_id"]);
    let redirect_uri = map.find(&["redirect_uri"]);
    let scope = map.find(&["scope"]);
    let state = map.find(&["state"]);

    println!("uri: {:?}", redirect_uri);
    println!("scope: {:?}", scope);

    let s = match state {
        Some(&params::Value::String(ref x)) => x,
        _ => "",
    };

    let u = match redirect_uri {
        Some(&params::Value::String(ref x)) => {
            let mut url = Url::parse(&x).unwrap();
            url.set_query(Some(&format!("code=123&state={}", s)));
            url
        }
        _ => Url::parse("").unwrap(),
    };

    let uu = iron::Url::from_generic_url(u).unwrap();

    Ok(Response::with((status::Found, Redirect(uu))))
}

fn token_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["grant_type"]);
    let _ = map.find(&["code"]);
    let _ = map.find(&["redirect_uri"]);
    let _ = map.find(&["client_id"]);

    let auth_response = AuthResponse {
        token_type: "bearer".to_string(),
        access_token: "xxx".to_string(),
        refresh_token: "yyy".to_string(),
        expires_in: 1000000,
    };

    let res = serde_json::to_string(&auth_response).unwrap_or("".to_string());

    Ok(Response::with((status::Ok, res)))
}

fn login_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["username"]);
    let _ = map.find(&["password"]);

    Ok(Response::with((status::Ok, "login")))
}

fn index_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "index")))
}

fn get_action_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get action")))
}
<commit_msg>match light by id<commit_after>extern crate iron;
extern crate router;
extern crate params;
extern crate serde;
extern crate serde_json;
extern crate url;
extern crate mote;

#[macro_use]
extern crate serde_derive;

#[macro_use]
extern crate maplit;

use std::collections::BTreeMap;
use std::io::Read;

use iron::headers::ContentType;
use iron::middleware::Handler;
use iron::modifiers::Redirect;
use iron::prelude::*;
use iron::status;
use router::Router;
use url::Url;
use std::sync::Mutex;

mod google_actions;
use google_actions::*;

mod smart_home;
use smart_home::*;

struct Hub {
    devices: Mutex<Vec<Device>>,
}

impl Handler for Hub {
    fn handle(&self, req: &mut Request) -> IronResult<Response> {
        println!("hub handler");
        let mut body = String::new();
        req.body.read_to_string(&mut body).unwrap();
        let action_request: ActionRequest = serde_json::from_str(&body).unwrap();

        println!("action_request: {:?}", action_request);

        for input in action_request.inputs {
            if input.intent == "action.devices.SYNC" {
                let mut response = SyncResponse {
                    request_id: action_request.request_id.clone(),
                    payload: SyncResponsePayload {
                        agent_user_id: "1111".to_string(),
                        devices: vec![],
                    },
                };

                let ref devices = *self.devices.lock().unwrap();
                for device in devices {
                    match device {
                        &Device::Light(ref light) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: light.id.clone(),
                                type_: light.type_.name(),
                                traits: light.available_light_modes
                                    .iter()
                                    .map(LightMode::name)
                                    .collect(),
                                name: Name {
                                    default_name: vec![light.name.to_string()],
                                    name: Some(light.name.clone()),
                                    nicknames: vec![],
                                },
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                            })
                        }
                        &Device::Thermostat(ref thermostat) => {
                            response.payload.devices.push(SyncResponseDevice {
                                id: thermostat.id.clone(),
                                type_: "".to_string(), // XXX
                                traits: vec!["action.devices.traits.TemperatureSetting"
                                                 .to_string()],
                                name: Name {
                                    default_name: vec![thermostat.name.to_string()],
                                    name: Some(thermostat.name.clone()),
                                    nicknames: vec![],
                                },
                                // TODO: attributes.
                                will_report_state: false,
                                device_info: None,
                                room_hint: None,
                                structure_hint: None,
                            })
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "action.devices.QUERY" {
                let mut response = QueryResponse {
                    request_id: action_request.request_id.clone(),
                    payload: QueryResponsePayload { devices: btreemap!{} },
                };

                let ref devices = *self.devices.lock().unwrap();
                if let Some(payload) = input.payload {
                    for request_device in payload.devices {
                        for device in devices {
                            match device {
                                &Device::Light(ref light) => {
                                    if light.id == request_device.id {
                                        let light_status = &light.status;
                                        response.payload
                                            .devices
                                            .insert(light.id.clone(),
                                                    DeviceStates {
                                                        online: Some(true),
                                                        on: Some(light_status.on),
                                                        brightness: Some(light_status.brightness),
                                                        color: Some(Color {
                                                            name: None,
                                                            temperature: None,
                                                            spectrum_rgb:
                                                                Some(light_status.spectrum_rgb),
                                                        }),
                                                    });
                                    }
                                }
                                &Device::Thermostat(ref thermostat) => {
                                    // TODO
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            } else if input.intent == "action.devices.EXECUTE" {
                let mut response = ExecuteResponse {
                    request_id: action_request.request_id.clone(),
                    payload: ExecuteResponsePayload {
                        error_code: None,
                        debug_string: None,
                        commands: vec![],
                    },
                };

                if let Some(ref p) = input.payload {
                    for command in &p.commands {
                        println!("command: {:?}", command);
                        for execution in &command.execution {
                            let ref mut devices = *self.devices.lock().unwrap();
                            for device in devices {
                                match device {
                                    &mut Device::Light(ref mut light) => {
                                        println!("execution: {:?}", execution);
                                        if let Some(s) = execution.params.on {
                                            light.set_on(s);
                                        }
                                        if let Some(s) = execution.params.brightness {
                                            light.set_brightness(s);
                                        }
                                        if let Some(ref s) = execution.params.color {
                                            if let Some(s) = s.spectrum_rgb {
                                                light.set_spectrum_rgb(s);
                                            }
                                        }
                                    }
                                    &mut Device::Thermostat(ref thermostat) => {}
                                }
                            }
                        }
                        for request_device in &command.devices {
                            println!("device: {:?}", request_device);
                            let ref devices = *self.devices.lock().unwrap();
                            for device in devices {
                                match device {
                                    &Device::Light(ref light) => {
                                        response.payload.commands.push(ExecuteResponseCommand {
                                            ids: vec![light.id.clone()],
                                            status: "SUCCESS".to_string(),
                                            states: DeviceStates {
                                                online: Some(true),
                                                on: Some(light.status.on),
                                                brightness: Some(light.status.brightness),
                                                color: Some(Color {
                                                    name: None,
                                                    temperature: None,
                                                    spectrum_rgb: Some(light.status.spectrum_rgb),
                                                }),
                                            },
                                        });
                                    }
                                    &Device::Thermostat(ref thermostat) => {
                                        // TODO
                                    }
                                }
                            }
                        }
                    }
                }

                let res = serde_json::to_string(&response).unwrap_or("".to_string());
                println!("action_response: {:?}", res);
                let mut rsp = Response::with((status::Ok, res));
                rsp.headers.set(ContentType::json());
                return Ok(rsp);
            }
        }

        let mut rsp = Response::with((status::Ok, "ACTION"));
        rsp.headers.set(ContentType::json());
        Ok(rsp)
    }
}

fn main() {
    let hub = Hub {
        devices: Mutex::new(vec![Device::Light(Light {
                                     id: "11".to_string(),
                                     name: "TV lights".to_string(),
                                     status: LightStatus::default(),
                                     type_: LightType::Light,
                                     available_light_modes: vec![LightMode::OnOff,
                                                                 LightMode::Brightness,
                                                                 LightMode::ColorSpectrum],
                                     mote: mote::Mote::new("/dev/ttyACM0"),
                                 })]),
    };
    let mut control = Router::new();
    control.get("/auth", auth_handler, "auth")
        .post("/token", token_handler, "token")
        .get("/login", login_handler, "login")
        .post("/action", hub, "post action")
        .get("/action", get_action_handler, "get action")
        .get("/", index_handler, "index");
    println!("Listening on port 1234");
    Iron::new(control)
        .http("0.0.0.0:1234")
        .unwrap();
}

fn auth_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["response_type"]);
    let _ = map.find(&["client_id"]);
    let redirect_uri = map.find(&["redirect_uri"]);
    let scope = map.find(&["scope"]);
    let state = map.find(&["state"]);

    println!("uri: {:?}", redirect_uri);
    println!("scope: {:?}", scope);

    let s = match state {
        Some(&params::Value::String(ref x)) => x,
        _ => "",
    };

    let u = match redirect_uri {
        Some(&params::Value::String(ref x)) => {
            let mut url = Url::parse(&x).unwrap();
            url.set_query(Some(&format!("code=123&state={}", s)));
            url
        }
        _ => Url::parse("").unwrap(),
    };

    let uu = iron::Url::from_generic_url(u).unwrap();

    Ok(Response::with((status::Found, Redirect(uu))))
}

fn token_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["grant_type"]);
    let _ = map.find(&["code"]);
    let _ = map.find(&["redirect_uri"]);
    let _ = map.find(&["client_id"]);

    let auth_response = AuthResponse {
        token_type: "bearer".to_string(),
        access_token: "xxx".to_string(),
        refresh_token: "yyy".to_string(),
        expires_in: 1000000,
    };

    let res = serde_json::to_string(&auth_response).unwrap_or("".to_string());

    Ok(Response::with((status::Ok, res)))
}

fn login_handler(req: &mut Request) -> IronResult<Response> {
    let map = req.get_ref::<params::Params>().unwrap();

    let _ = map.find(&["username"]);
    let _ = map.find(&["password"]);

    Ok(Response::with((status::Ok, "login")))
}

fn index_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "index")))
}

fn get_action_handler(_: &mut Request) -> IronResult<Response> {
    Ok(Response::with((status::Ok, "get action")))
}
<|endoftext|>


<commit_before>// PactHash
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # PactHash
//!
//! This is a rewrite of Matt Corallo's compacthashtool in Rust, designed to be
//! API compatible.
//!

#![crate_name = "pacthash"]

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![deny(missing_docs)]

#[cfg(not(test))]
use std::env;

extern crate bitcoin;
extern crate getopts;
extern crate rand;
extern crate rustc_serialize as serialize;
extern crate secp256k1;

use bitcoin::blockdata::script::Script;
use bitcoin::network::constants::Network;
use bitcoin::util::address::{Privkey, Address};
use bitcoin::util::base58::{FromBase58, ToBase58};
use bitcoin::util::contracthash::{tweak_keys, tweak_secret_key, untemplate};
use rand::{Rng, OsRng};
use secp256k1::Secp256k1;
use serialize::hex::FromHex;

use contract::{Contract, Nonce};

#[macro_use] pub mod macros;
pub mod contract;

/// Modes that the program can run in
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Mode {
    /// Generate a redeem script and corresponding P2SH address
    GenAddress,
    /// Generate a private key
    GenPrivkey
}

#[cfg(not(test))]
fn main() {
    let prog = env::args().next().unwrap();
    let args: Vec<_> = env::args().skip(1).collect();
    let mut rng = OsRng::new().unwrap(); // panic immediately if we can't get a RNG

    // Parse options
    let mut opts = getopts::Options::new();
    opts.optflag("c", "gen-address", "Generate a redemption script and corresponding address");
    opts.optflag("g", "gen-privkey", "Generate a private key");
    opts.optopt("r", "redeem-script", "Specify a hex-encode redemption script for -g mode.", "redemption script");
    opts.optopt("p", "private-key", "Specify a base58-encoded private key for -c mode.", "redemption script");
    opts.optopt("d", "p2sh-address", "Specify a contract as a P2SH address.", "P2SH address");
    opts.optopt("a", "ascii-contract", "Specify a contract as an ASCII string.", "text");
    opts.optopt("f", "hex-contract", "Specify a contract as an hexadecimal string.", "hex");
    opts.optopt("n", "nonce", "Specify a hex-encoded nonce.", "nonce");
    opts.optflag("h", "help", "Print this help message and exit.");
    opts.optflag("t", "testnet", "Set the tool to testnet mode (defaults to main)");

    let short_usage = format!("{} [-t] <-c|-g> <-f contract|-d p2sh -n nonce|-a ascii -n nonce>", prog);
    let full_usage = opts.usage(&short_usage);

    let matches = match opts.parse(&args[..]) {
        Ok(m) => m,
        Err(e) => {
            println!("Argument error: {}", e);
            println!("{}", full_usage);
            return;
        }
    };

    if matches.opt_present("h") {
        println!("{}", full_usage);
        return;
    }

    // ** Validate command-line options **
    let network = if matches.opt_present("t") { Network::Testnet } else { Network::Bitcoin };

    // Mode
    let mode = match (matches.opt_present("c"), matches.opt_present("g")) {
        (false, false) => {
            println!("One of -g or -c must be specified.");
            println!("{}", full_usage);
            return;
        }
        (true, true) => {
            println!("At most one of -g or -c may be specified.");
            println!("{}", full_usage);
            return;
        }
        (true, false) => Mode::GenPrivkey,
        (false, true) => Mode::GenAddress,
    };

    // Redeem script (required for -g, not allowed for -c)
    let redeem_script = match (mode, matches.opt_str("r")) {
        (Mode::GenAddress, Some(x)) => {
            match x.from_hex() {
                Ok(data) => Some(Script::from(data)),
                Err(e) => {
                    println!("option to -r could not be parsed as hex: {}.", e);
                    return;
                }
            }
        }
        (Mode::GenAddress, None) => {
            println!("-r must be specified in -g mode.");
            println!("{}", full_usage);
            return;
        }
        (Mode::GenPrivkey, None) => None,
        (Mode::GenPrivkey, Some(_)) => {
            println!("-r may only be used in -g mode.");
            println!("{}", full_usage);
            return;
        }
    };

    // Privkey (required for -c, not allowed for -g)
    let private_key = match (mode, matches.opt_str("p")) {
        (Mode::GenPrivkey, Some(x)) => {
            let decode: Result<Privkey, _> = FromBase58::from_base58check(&x[..]);
            match decode {
                Ok(key) => {
                    if key.network != network {
                        println!("Private key network did not match tool mode (did you forget -t?).");
                        return;
                    }
                    Some(key)
                }
                Err(e) => {
                    println!("option to -p could not be parsed as a private key: {:?}.", e);
                    return;
                }
            }
        }
        (Mode::GenPrivkey, None) => {
            println!("-p must be specified in -c mode.");
            println!("{}", full_usage);
            return;
        }
        (Mode::GenAddress, None) => None,
        (Mode::GenAddress, Some(_)) => {
            println!("-p may only be used in -c mode.");
            println!("{}", full_usage);
            return;
        }
    };

    // mode, full contract, nonce, p2sh-address contract, ascii contract
    let contract = match (mode, matches.opt_str("f"), matches.opt_str("n"), matches.opt_str("d"), matches.opt_str("a")) {
        // Full contract obviates everything else
        (_, Some(hex), None, None, None) => {
            match Contract::from_hex(&hex) {
                Ok(data) => data,
                Err(e) => {
                    println!("option to -f could not be parsed as a contract: {:?}.", e);
                    return;
                }
            }
        }
        // P2SH requires a nonce, but in generate mode we may make one
        (mode, None, nonce, Some(hex), None) => {
            if mode == Mode::GenPrivkey && nonce.is_none() {
                println!("-n is required when using -c and -d");
                println!("{}", full_usage);
                return;
            }
            // Now we know if we're missing a nonce we're allowed to generate it
            let nonce = match nonce {
                Some(hex) => {
                    match Nonce::from_hex(&hex) {
                        Ok(data) => data,
                        Err(e) => {
                            println!("option to -n could not be parsed as a nonce: {:?}.", e);
                            return;
                        }
                    }
                }
                None => rng.gen()
            };
            match Contract::from_p2sh_base58_str(&hex, nonce, network) {
                Ok(contract) => contract,
                Err(e) => {
                    println!("option to -d could not be parsed as a P2SH contract: {:?}.", e);
                    return;
                }
            }
        }
        // ASCII requires a nonce, but in generate mode we may make one
        (mode, None, nonce, None, Some(ascii)) => {
            if mode == Mode::GenPrivkey && nonce.is_none() {
                println!("-n is required when using -c and -a");
                println!("{}", full_usage);
                return;
            }
            // Now we know if we're missing a nonce we're allowed to generate it
            let nonce = match nonce {
                Some(hex) => {
                    match Nonce::from_hex(&hex) {
                        Ok(data) => data,
                        Err(e) => {
                            println!("option to -n could not be parsed as a nonce: {:?}.", e);
                            return;
                        }
                    }
                }
                None => rng.gen()
            };
            match Contract::from_ascii_str(&ascii, nonce) {
                Ok(contract) => contract,
                Err(e) => {
                    println!("option to -a could not be parsed as a contract: {:?}.", e);
                    return;
                }
            }
        }
        // Every other usage is illegal
        _ => {
            println!("Must specify exactly one of: -f; -a -n; or -d -n");
            println!("{}", full_usage);
            return;
        }
    };

    // OKAY. At this point we have actually parsed everything and can be assured that we have what we need.
    // ** Actual program starts now **
    let secp = Secp256k1::new();
    match mode {
        Mode::GenAddress => {
            let redeem_script = redeem_script.unwrap();

            match untemplate(&redeem_script) {
                Ok((template, keys)) => {
                    let keys = match tweak_keys(&secp, &keys, &contract.serialize()[..]) {
                        Ok(keys) => keys,
                        Err(e) => {
                            println!("Unable to tweak keys: {:?}", e);
                            return;
                        }
                    };
                    let new_script = match template.to_script(&keys) {
                        Ok(script) => script,
                        Err(e) => {
                            println!("Unable to put tweaked keys back into the redemption script: {:?}", e);
                            return;
                        }
                    };
                    match network {
                        Network::Bitcoin => println!("Using mainnet!"),
                        Network::Testnet => println!("Using testnet!"),
                    }
                    println!("Nonce: {:x}", Nonce::from_contract(&contract));
                    println!("Modified redeem script: {:x}", new_script);
                    println!("Modified redeem script as P2SH address: {}", Address::from_script(network, &new_script).to_base58check());
                }
                Err(e) => {
                    println!("Unable to extract keys from redemption script: {:?}", e);
                    return;
                }
            }
        }
        Mode::GenPrivkey => {
            let private_key = private_key.unwrap();

            // Compute tweaked key
            let tweaked_key = match tweak_secret_key(&secp, &private_key.key, &contract.serialize()[..]) {
                Ok(key) => key,
                Err(e) => {
                    println!("Failed to tweak private key: {:?}", e);
                    return;
                }
            };
            // Turn it into a WIF privkey
            let tweaked_privkey = Privkey {
                compressed: true,
                network: network,
                key: tweaked_key
            };

            match network {
                Network::Bitcoin => println!("Using mainnet!"),
                Network::Testnet => println!("Using testnet!"),
            }
            println!("New secret key: {}", tweaked_privkey.to_base58check());
        }
    }
}

<commit_msg>Remove superfluous `mode` from tuple in `main.rs`<commit_after>// PactHash
// Written in 2015 by
//   Andrew Poelstra <apoelstra@wpsoftware.net>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the CC0 Public Domain Dedication
// along with this software.
// If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
//

//! # PactHash
//!
//! This is a rewrite of Matt Corallo's compacthashtool in Rust, designed to be
//! API compatible.
//!

#![crate_name = "pacthash"]

// Coding conventions
#![deny(non_upper_case_globals)]
#![deny(non_camel_case_types)]
#![deny(non_snake_case)]
#![deny(unused_mut)]
#![deny(missing_docs)]

#[cfg(not(test))]
use std::env;

extern crate bitcoin;
extern crate getopts;
extern crate rand;
extern crate rustc_serialize as serialize;
extern crate secp256k1;

use bitcoin::blockdata::script::Script;
use bitcoin::network::constants::Network;
use bitcoin::util::address::{Privkey, Address};
use bitcoin::util::base58::{FromBase58, ToBase58};
use bitcoin::util::contracthash::{tweak_keys, tweak_secret_key, untemplate};
use rand::{Rng, OsRng};
use secp256k1::Secp256k1;
use serialize::hex::FromHex;

use contract::{Contract, Nonce};

#[macro_use] pub mod macros;
pub mod contract;

/// Modes that the program can run in
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
pub enum Mode {
    /// Generate a redeem script and corresponding P2SH address
    GenAddress,
    /// Generate a private key
    GenPrivkey
}

#[cfg(not(test))]
fn main() {
    let prog = env::args().next().unwrap();
    let args: Vec<_> = env::args().skip(1).collect();
    let mut rng = OsRng::new().unwrap(); // panic immediately if we can't get a RNG

    // Parse options
    let mut opts = getopts::Options::new();
    opts.optflag("c", "gen-address", "Generate a redemption script and corresponding address");
    opts.optflag("g", "gen-privkey", "Generate a private key");
    opts.optopt("r", "redeem-script", "Specify a hex-encode redemption script for -g mode.", "redemption script");
    opts.optopt("p", "private-key", "Specify a base58-encoded private key for -c mode.", "redemption script");
    opts.optopt("d", "p2sh-address", "Specify a contract as a P2SH address.", "P2SH address");
    opts.optopt("a", "ascii-contract", "Specify a contract as an ASCII string.", "text");
    opts.optopt("f", "hex-contract", "Specify a contract as an hexadecimal string.", "hex");
    opts.optopt("n", "nonce", "Specify a hex-encoded nonce.", "nonce");
    opts.optflag("h", "help", "Print this help message and exit.");
    opts.optflag("t", "testnet", "Set the tool to testnet mode (defaults to main)");

    let short_usage = format!("{} [-t] <-c|-g> <-f contract|-d p2sh -n nonce|-a ascii -n nonce>", prog);
    let full_usage = opts.usage(&short_usage);

    let matches = match opts.parse(&args[..]) {
        Ok(m) => m,
        Err(e) => {
            println!("Argument error: {}", e);
            println!("{}", full_usage);
            return;
        }
    };

    if matches.opt_present("h") {
        println!("{}", full_usage);
        return;
    }

    // ** Validate command-line options **
    let network = if matches.opt_present("t") { Network::Testnet } else { Network::Bitcoin };

    // Mode
    let mode = match (matches.opt_present("c"), matches.opt_present("g")) {
        (false, false) => {
            println!("One of -g or -c must be specified.");
            println!("{}", full_usage);
            return;
        }
        (true, true) => {
            println!("At most one of -g or -c may be specified.");
            println!("{}", full_usage);
            return;
        }
        (true, false) => Mode::GenPrivkey,
        (false, true) => Mode::GenAddress,
    };

    // Redeem script (required for -g, not allowed for -c)
    let redeem_script = match (mode, matches.opt_str("r")) {
        (Mode::GenAddress, Some(x)) => {
            match x.from_hex() {
                Ok(data) => Some(Script::from(data)),
                Err(e) => {
                    println!("option to -r could not be parsed as hex: {}.", e);
                    return;
                }
            }
        }
        (Mode::GenAddress, None) => {
            println!("-r must be specified in -g mode.");
            println!("{}", full_usage);
            return;
        }
        (Mode::GenPrivkey, None) => None,
        (Mode::GenPrivkey, Some(_)) => {
            println!("-r may only be used in -g mode.");
            println!("{}", full_usage);
            return;
        }
    };

    // Privkey (required for -c, not allowed for -g)
    let private_key = match (mode, matches.opt_str("p")) {
        (Mode::GenPrivkey, Some(x)) => {
            let decode: Result<Privkey, _> = FromBase58::from_base58check(&x[..]);
            match decode {
                Ok(key) => {
                    if key.network != network {
                        println!("Private key network did not match tool mode (did you forget -t?).");
                        return;
                    }
                    Some(key)
                }
                Err(e) => {
                    println!("option to -p could not be parsed as a private key: {:?}.", e);
                    return;
                }
            }
        }
        (Mode::GenPrivkey, None) => {
            println!("-p must be specified in -c mode.");
            println!("{}", full_usage);
            return;
        }
        (Mode::GenAddress, None) => None,
        (Mode::GenAddress, Some(_)) => {
            println!("-p may only be used in -c mode.");
            println!("{}", full_usage);
            return;
        }
    };

    // full contract, nonce, p2sh-address contract, ascii contract
    let contract = match (matches.opt_str("f"), matches.opt_str("n"), matches.opt_str("d"), matches.opt_str("a")) {
        // Full contract obviates everything else
        (Some(hex), None, None, None) => {
            match Contract::from_hex(&hex) {
                Ok(data) => data,
                Err(e) => {
                    println!("option to -f could not be parsed as a contract: {:?}.", e);
                    return;
                }
            }
        }
        // P2SH requires a nonce, but in generate mode we may make one
        (None, nonce, Some(hex), None) => {
            if mode == Mode::GenPrivkey && nonce.is_none() {
                println!("-n is required when using -c and -d");
                println!("{}", full_usage);
                return;
            }
            // Now we know if we're missing a nonce we're allowed to generate it
            let nonce = match nonce {
                Some(hex) => {
                    match Nonce::from_hex(&hex) {
                        Ok(data) => data,
                        Err(e) => {
                            println!("option to -n could not be parsed as a nonce: {:?}.", e);
                            return;
                        }
                    }
                }
                None => rng.gen()
            };
            match Contract::from_p2sh_base58_str(&hex, nonce, network) {
                Ok(contract) => contract,
                Err(e) => {
                    println!("option to -d could not be parsed as a P2SH contract: {:?}.", e);
                    return;
                }
            }
        }
        // ASCII requires a nonce, but in generate mode we may make one
        (None, nonce, None, Some(ascii)) => {
            if mode == Mode::GenPrivkey && nonce.is_none() {
                println!("-n is required when using -c and -a");
                println!("{}", full_usage);
                return;
            }
            // Now we know if we're missing a nonce we're allowed to generate it
            let nonce = match nonce {
                Some(hex) => {
                    match Nonce::from_hex(&hex) {
                        Ok(data) => data,
                        Err(e) => {
                            println!("option to -n could not be parsed as a nonce: {:?}.", e);
                            return;
                        }
                    }
                }
                None => rng.gen()
            };
            match Contract::from_ascii_str(&ascii, nonce) {
                Ok(contract) => contract,
                Err(e) => {
                    println!("option to -a could not be parsed as a contract: {:?}.", e);
                    return;
                }
            }
        }
        // Every other usage is illegal
        _ => {
            println!("Must specify exactly one of: -f; -a -n; or -d -n");
            println!("{}", full_usage);
            return;
        }
    };

    // OKAY. At this point we have actually parsed everything and can be assured that we have what we need.
    // ** Actual program starts now **
    let secp = Secp256k1::new();
    match mode {
        Mode::GenAddress => {
            let redeem_script = redeem_script.unwrap();

            match untemplate(&redeem_script) {
                Ok((template, keys)) => {
                    let keys = match tweak_keys(&secp, &keys, &contract.serialize()[..]) {
                        Ok(keys) => keys,
                        Err(e) => {
                            println!("Unable to tweak keys: {:?}", e);
                            return;
                        }
                    };
                    let new_script = match template.to_script(&keys) {
                        Ok(script) => script,
                        Err(e) => {
                            println!("Unable to put tweaked keys back into the redemption script: {:?}", e);
                            return;
                        }
                    };
                    match network {
                        Network::Bitcoin => println!("Using mainnet!"),
                        Network::Testnet => println!("Using testnet!"),
                    }
                    println!("Nonce: {:x}", Nonce::from_contract(&contract));
                    println!("Modified redeem script: {:x}", new_script);
                    println!("Modified redeem script as P2SH address: {}", Address::from_script(network, &new_script).to_base58check());
                }
                Err(e) => {
                    println!("Unable to extract keys from redemption script: {:?}", e);
                    return;
                }
            }
        }
        Mode::GenPrivkey => {
            let private_key = private_key.unwrap();

            // Compute tweaked key
            let tweaked_key = match tweak_secret_key(&secp, &private_key.key, &contract.serialize()[..]) {
                Ok(key) => key,
                Err(e) => {
                    println!("Failed to tweak private key: {:?}", e);
                    return;
                }
            };
            // Turn it into a WIF privkey
            let tweaked_privkey = Privkey {
                compressed: true,
                network: network,
                key: tweaked_key
            };

            match network {
                Network::Bitcoin => println!("Using mainnet!"),
                Network::Testnet => println!("Using testnet!"),
            }
            println!("New secret key: {}", tweaked_privkey.to_base58check());
        }
    }
}

<|endoftext|>


<commit_before>#[macro_use]
extern crate clap;

fn main() {
    let matches = clap_app!(myapp =>
        (@arg ARCHIVE: +required ... "Archives to extract")
    ).get_matches();

	for arch in matches.values_of("ARCHIVE").unwrap() {
		println!("Extract {}", arch);
    }
}
<commit_msg>Extract tar archives<commit_after>#[macro_use]
extern crate clap;

use std::process::Command;

fn main() {
    let matches = clap_app!(myapp =>
        (@arg ARCHIVE: +required ... "Archives to extract")
    ).get_matches();

    for arch in matches.values_of("ARCHIVE").unwrap() {
        println!("Extract {}", arch);
        if arch.ends_with(".tgz") {
            let status = Command::new("tar")
                .arg("-xf")
                .arg(arch)
                .status()
                .expect("Failed to launch tar");
            assert!(status.success(), "tar wasn't successful");
        } else {
            println!("Can't handle {}", arch);
        }
    }
}
<|endoftext|>