169 lines
4.7 KiB
Rust
169 lines
4.7 KiB
Rust
use std::path::{Path,PathBuf};
|
|
use std::fs::{self,File};
|
|
use std::process::Command;
|
|
use std::io::{Read,Write,BufReader,BufRead};
|
|
|
|
use Result;
|
|
|
|
pub struct Workdir(PathBuf);
|
|
|
|
impl Workdir {
|
|
pub fn new(base: &str, channel: &str) -> Workdir {
|
|
let mut pb = PathBuf::from(base);
|
|
pb.push(channel);
|
|
Workdir(pb)
|
|
}
|
|
|
|
pub fn find_next_version(&mut self) -> Result<usize> {
|
|
let mut version = 1;
|
|
loop {
|
|
let path = self.0.join(version.to_string());
|
|
if !path.exists() {
|
|
self.set_version(version)?;
|
|
return Ok(version);
|
|
}
|
|
version += 1;
|
|
}
|
|
}
|
|
|
|
pub fn set_version(&mut self, version: usize) -> Result<()> {
|
|
self.0.push(version.to_string());
|
|
fs::create_dir_all(&self.0)?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn filepath(&self, name: &str) -> PathBuf {
|
|
self.0.join(name)
|
|
}
|
|
|
|
}
|
|
|
|
|
|
///
|
|
/// Returns `true` if `path` matches the source field (first field)
|
|
/// of any of the mount lines listed in /proc/mounts
|
|
///
|
|
pub fn is_path_mounted(path: &Path) -> Result<bool> {
|
|
let path_str = path.to_str().unwrap();
|
|
let f = File::open("/proc/mounts")?;
|
|
let reader = BufReader::new(f);
|
|
for line in reader.lines() {
|
|
if let Some(s) = line?.split_whitespace().next() {
|
|
if s == path_str {
|
|
return Ok(true);
|
|
}
|
|
}
|
|
}
|
|
Ok(false)
|
|
}
|
|
|
|
///
|
|
/// Converts a `Path` into `&str` representation, assuming
|
|
/// that it contains valid utf-8
|
|
///
|
|
pub fn path_str(path: &Path) -> &str {
|
|
path.to_str().unwrap()
|
|
}
|
|
|
|
pub fn rootfs_partition_paths() -> Result<Vec<PathBuf>> {
|
|
let mut rootfs_paths = Vec::new();
|
|
for dent in fs::read_dir("/dev/mapper")? {
|
|
let path = dent?.path();
|
|
if is_path_rootfs(&path) {
|
|
rootfs_paths.push(path);
|
|
}
|
|
}
|
|
Ok(rootfs_paths)
|
|
}
|
|
pub fn is_path_rootfs(path: &Path) -> bool {
|
|
path_filename(path).starts_with("citadel-rootfs")
|
|
}
|
|
|
|
fn path_filename(path: &Path) -> &str {
|
|
if let Some(osstr) = path.file_name() {
|
|
if let Some(name) = osstr.to_str() {
|
|
return name;
|
|
}
|
|
}
|
|
""
|
|
}
|
|
|
|
pub fn write_string_to_file(path: &Path, s: &str) -> Result<()> {
|
|
let mut f = File::create(path)?;
|
|
f.write_all(s.as_bytes())?;
|
|
Ok(())
|
|
}
|
|
|
|
pub fn read_file_as_string(path: &Path) -> Result<String> {
|
|
let mut f = File::open(path)?;
|
|
let mut buffer = String::new();
|
|
f.read_to_string(&mut buffer)?;
|
|
Ok(buffer)
|
|
}
|
|
|
|
pub fn run_file_command(path: &Path) -> Result<String> {
|
|
let path = path_str(path);
|
|
let output = try_run_command("/usr/bin/file", &["-b", path])?;
|
|
Ok(output)
|
|
}
|
|
|
|
pub fn run_xz_command(path: &Path, decompress: bool) -> Result<()> {
|
|
let path = path_str(path);
|
|
if decompress {
|
|
let _ = try_run_command("/usr/bin/xz", &["-d", path])?;
|
|
} else {
|
|
let _ = try_run_command("/usr/bin/xz", &["-T0", path])?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
pub fn run_sha256_command(path: &Path) -> Result<String> {
|
|
let path = path_str(path);
|
|
let output = try_run_command("/usr/bin/sha256sum", &[path])?;
|
|
|
|
let v: Vec<&str> = output.split_whitespace().collect();
|
|
Ok(v[0].trim().to_owned())
|
|
}
|
|
|
|
pub fn run_verityformat_command(srcfile: &Path, hashfile: &Path) -> Result<String> {
|
|
let srcfile = path_str(srcfile);
|
|
let hashfile = path_str(hashfile);
|
|
let output = try_run_command("/usr/sbin/veritysetup",
|
|
&["format", srcfile, hashfile])?;
|
|
Ok(output)
|
|
}
|
|
|
|
pub fn run_verityinstall_command(block_device: &Path, salt: &str, data_blocks: usize, hash_offset: usize) -> Result<String> {
|
|
let data_device = path_str(block_device).to_owned();
|
|
let hash_device = path_str(block_device).to_owned();
|
|
let arg1 = format!("--data-blocks={}", data_blocks);
|
|
let arg2 = format!("--hash-offset={}", hash_offset);
|
|
let arg3 = format!("--salt={}", salt);
|
|
let output = try_run_command("/usr/sbin/veritysetup", &[&arg1, &arg2, &arg3, "format", &data_device, &hash_device])?;
|
|
Ok(output)
|
|
}
|
|
|
|
pub fn run_write_image_dd(image_src: &Path, block_device: &Path) -> Result<()> {
|
|
let src = format!("if={}", path_str(image_src));
|
|
let dst = format!("of={}", path_str(block_device));
|
|
let _ = try_run_command("/bin/dd", &[&src, &dst, "bs=4M"])?;
|
|
Ok(())
|
|
}
|
|
|
|
fn try_run_command(cmd_path: &str, args: &[&str]) -> Result<String> {
|
|
let mut cmd = Command::new(cmd_path);
|
|
for arg in args {
|
|
cmd.arg(arg);
|
|
}
|
|
|
|
let result = cmd.output()?;
|
|
|
|
if !result.status.success() {
|
|
let err = String::from_utf8(result.stderr)?;
|
|
let argstr = args.join(" ");
|
|
bail!("{} {} command failed: {}", cmd_path, argstr, err);
|
|
}
|
|
let output = String::from_utf8(result.stdout)?;
|
|
Ok(output)
|
|
}
|