Add virtio block test util
Change-Id: Icb0fe5d324fa56542cbdad84f70b6e507ffd377d
diff --git a/Cargo.lock b/Cargo.lock
index e12886a..6598979 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -1,4 +1,179 @@
[[package]]
+name = "ansi_term"
+version = "0.11.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "winapi 0.3.6",
+]
+
+[[package]]
+name = "atty"
+version = "0.2.11"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
+ "winapi 0.3.6",
+]
+
+[[package]]
+name = "bitflags"
+version = "1.0.4"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "clap"
+version = "2.32.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
+ "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
+ "strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+ "vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "libc"
+version = "0.2.43"
+
+[[package]]
+name = "libc"
+version = "0.2.43"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
name = "linux_tests"
version = "0.1.0"
+dependencies = [
+ "libc 0.2.43",
+ "structopt 0.2.12",
+]
+[[package]]
+name = "proc-macro2"
+version = "0.4.24"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "quote"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "redox_syscall"
+version = "0.1.42"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "redox_termios"
+version = "0.1.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "strsim"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "structopt"
+version = "0.2.12"
+dependencies = [
+ "clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)",
+ "structopt-derive 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "structopt-derive"
+version = "0.2.12"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "syn"
+version = "0.15.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
+ "quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
+ "unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "termion"
+version = "1.5.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
+ "redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "textwrap"
+version = "0.10.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+dependencies = [
+ "unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
+]
+
+[[package]]
+name = "unicode-width"
+version = "0.1.5"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "unicode-xid"
+version = "0.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "vec_map"
+version = "0.8.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+
+[[package]]
+name = "winapi"
+version = "0.3.6"
+
+[[patch.unused]]
+name = "winapi-build"
+version = "0.3.6"
+
+[[patch.unused]]
+name = "winapi-util"
+version = "0.1.1"
+
+[metadata]
+"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b"
+"checksum atty 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "9a7d5b8723950951411ee34d271d99dddcc2035a16ab25310ea2c8cfd4369652"
+"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
+"checksum clap 2.32.0 (registry+https://github.com/rust-lang/crates.io-index)" = "b957d88f4b6a63b9d70d5f454ac8011819c6efa7727858f458ab71c756ce2d3e"
+"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
+"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
+"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
+"checksum redox_syscall 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "cf8fb82a4d1c9b28f1c26c574a5b541f5ffb4315f6c9a791fa47b6a04438fe93"
+"checksum redox_termios 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7e891cfe48e9100a70a3b6eb652fef28920c117d366339687bd5576160db0f76"
+"checksum strsim 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb4f380125926a99e52bc279241539c018323fab05ad6368b56f93d9369ff550"
+"checksum structopt-derive 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "17ff01fe96de9d16e7372ae5f19dd7ece2c703b51043c3db9ea27f9e393ea311"
+"checksum syn 0.15.23 (registry+https://github.com/rust-lang/crates.io-index)" = "9545a6a093a3f0bd59adb472700acc08cad3776f860f16a897dfce8c88721cbc"
+"checksum termion 1.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "689a3bdfaab439fd92bc87df5c4c78417d3cbe537487274e9b0b2dce76e92096"
+"checksum textwrap 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "307686869c93e71f94da64286f9a9524c0f308a9e1c87a583de8e9c9039ad3f6"
+"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
+"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
+"checksum vec_map 0.8.1 (registry+https://github.com/rust-lang/crates.io-index)" = "05c78687fb1a80548ae3250346c3db86a80a7cdd77bda190189f2d0a0987c81a"
diff --git a/Cargo.toml b/Cargo.toml
index 003dfd4..d401652 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -11,4 +11,11 @@
license = "BSD-3-Clause"
edition = "2018"
-[dependencies]
\ No newline at end of file
+[dependencies]
+structopt = { path = "rust-crates/rustc_deps/vendor/structopt" }
+libc = { path = "rust-crates/rustc_deps/vendor/libc" }
+
+[patch.crates-io]
+winapi = { path = "rust-crates/rustc_deps/tiny_mirrors/winapi" }
+winapi-build = { path = "rust-crates/rustc_deps/tiny_mirrors/winapi-build" }
+winapi-util = { path = "rust-crates/rustc_deps/tiny_mirrors/winapi-util" }
diff --git a/build.sh b/build.sh
index 87e4eae..3557af4 100755
--- a/build.sh
+++ b/build.sh
@@ -37,6 +37,7 @@
mkdir -p ${OUT_DIR}
cp target/${TARGET}/debug/virtio_rng_test_util ${OUT_DIR}
+cp target/${TARGET}/debug/virtio_block_test_util ${OUT_DIR}
declare -r BLOCK_SIZE=4096
declare -r ADDITIONAL_BLOCKS=1024
diff --git a/src/bin/virtio_block_test_util.rs b/src/bin/virtio_block_test_util.rs
new file mode 100644
index 0000000..59d6964
--- /dev/null
+++ b/src/bin/virtio_block_test_util.rs
@@ -0,0 +1,138 @@
+// Copyright 2018 The Fuchsia Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+#![deny(warnings)]
+
+use libc::{self, c_int};
+use std::fs::{self, File, OpenOptions};
+use std::io::{Error, ErrorKind, Read, Seek, SeekFrom, Write};
+use std::os::unix::io::AsRawFd;
+use std::path::Path;
+use structopt::StructOpt;
+
+const DEV_DIR: &str = "/dev";
+
+// Ioctl requests are comprised of 32 bits:
+// [31:30] Access mode
+// [29:16] Size of the parameter structure
+// [15:8] Request type
+// [7:0] Request number
+// For the ioctls we care about here there are no parameters, so we set only a type and a number.
+// See Linux:include/uapi/asm-generic/ioctl.h for more details.
+const TYPE_SHIFT: usize = 8;
+macro_rules! define_ioctl {
+ ($name:ident, $typ:expr, $num:expr, $return_type:ty) => {
+ fn $name(file: &File) -> $return_type {
+ let request: c_int = ($typ << TYPE_SHIFT) | ($num & 0xff);
+ let mut r: $return_type = 0;
+ unsafe {
+ libc::ioctl(file.as_raw_fd(), request, &mut r);
+ }
+ r
+ }
+ };
+}
+
+// Block ioctl types and number are defined in Linux:include/uapi/linux/fs.h.
+define_ioctl!(block_dev_size, 0x12, 96, u64);
+define_ioctl!(block_dev_sector_size, 0x12, 104, u32);
+
+#[derive(StructOpt, Debug)]
+struct Config {
+ block_size: u32,
+ block_count: u64,
+ #[structopt(subcommand)]
+ cmd: Command,
+}
+
+#[derive(StructOpt, Debug)]
+enum Command {
+ #[structopt(name = "check")]
+ Check,
+ #[structopt(name = "read")]
+ Read { offset: u64, expected: u8 },
+ #[structopt(name = "write")]
+ Write { offset: u64, value: u8 },
+}
+
+fn find_block_device(block_size: u32, block_count: u64, write: bool) -> std::io::Result<File> {
+ let dir = Path::new(DEV_DIR);
+ if !dir.is_dir() {
+ return Err(Error::new(
+ ErrorKind::Other,
+ format!("{} is not a directory", DEV_DIR),
+ ));
+ }
+ for entry in fs::read_dir(dir)?.collect::<std::io::Result<Vec<_>>>()? {
+ if !entry
+ .file_name()
+ .to_str()
+ .map_or(false, |f| f.starts_with("vd"))
+ {
+ continue;
+ }
+ let file = OpenOptions::new()
+ .read(true)
+ .write(write)
+ .open(entry.path())?;
+ if block_size != block_dev_sector_size(&file) {
+ continue;
+ }
+ if block_count != block_dev_size(&file) {
+ continue;
+ }
+ return Ok(file);
+ }
+ Err(Error::new(ErrorKind::NotFound, "Block device not found"))
+}
+
+fn read_block(
+ block_dev: &mut File,
+ block_size: u32,
+ offset: u64,
+ expected: u8,
+) -> std::io::Result<()> {
+ block_dev.seek(SeekFrom::Start(offset * block_size as u64))?;
+ let mut data: Vec<u8> = vec![0; block_size as usize];
+ block_dev.read_exact(&mut data)?;
+ if !data.iter().all(|&b| b == expected) {
+ return Err(Error::new(ErrorKind::Other, "Incorrect data read"));
+ }
+ Ok(())
+}
+
+fn write_block(
+ block_dev: &mut File,
+ block_size: u32,
+ offset: u64,
+ value: u8,
+) -> std::io::Result<()> {
+ block_dev.seek(SeekFrom::Start(offset * block_size as u64))?;
+ let data: Vec<u8> = vec![value; block_size as usize];
+ block_dev.write_all(&data)?;
+ block_dev.sync_all()?;
+ Ok(())
+}
+
+fn main() -> std::io::Result<()> {
+ let config = Config::from_args();
+ let write = if let Command::Write { .. } = config.cmd {
+ true
+ } else {
+ false
+ };
+ let mut block_dev = find_block_device(config.block_size, config.block_count, write)?;
+ let result = match config.cmd {
+ Command::Check => Ok(()),
+ Command::Read { offset, expected } => {
+ read_block(&mut block_dev, config.block_size, offset, expected)
+ }
+ Command::Write { offset, value } => {
+ write_block(&mut block_dev, config.block_size, offset, value)
+ }
+ };
+ if result.is_ok() {
+ println!("PASS");
+ }
+ result
+}