parent
82aa5b47b1
commit
4c590f57c8
@ -0,0 +1,31 @@
|
|||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
#[derive(StructOpt, Debug)]
|
||||||
|
#[structopt(name = "mkroot")]
|
||||||
|
pub struct Config {
|
||||||
|
/// OS name (for /etc/os-release)
|
||||||
|
#[structopt(long, name = "OSNAME", default_value = "mkroot")]
|
||||||
|
pub osname: String,
|
||||||
|
|
||||||
|
/// OS version (for /etc/os-release)
|
||||||
|
#[structopt(long, name = "OSVERSION", default_value = "1.0")]
|
||||||
|
pub osversion: String,
|
||||||
|
|
||||||
|
/// Verbose
|
||||||
|
#[structopt(short, long)]
|
||||||
|
pub verbose: bool,
|
||||||
|
|
||||||
|
/// Path to LDD
|
||||||
|
#[structopt(long, name = "LDD", default_value = "/usr/bin/ldd", parse(from_os_str))]
|
||||||
|
pub ldd: PathBuf,
|
||||||
|
|
||||||
|
/// Directory for root filesystem
|
||||||
|
#[structopt(required = true, name = "DIR", parse(from_os_str))]
|
||||||
|
pub root_dir: PathBuf,
|
||||||
|
|
||||||
|
/// Files to parse
|
||||||
|
#[structopt(required = true, name = "FILES", parse(from_os_str))]
|
||||||
|
pub files: Vec<PathBuf>,
|
||||||
|
}
|
@ -0,0 +1,72 @@
|
|||||||
|
use std::fs::{create_dir, read_dir};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
static DIRS: &[&str] = &[
|
||||||
|
"bin", "dev", "etc", "home", "lib", "lib64", "proc", "root", "run", "sbin", "sys", "tmp",
|
||||||
|
"usr", "var", "usr/bin",
|
||||||
|
];
|
||||||
|
|
||||||
|
pub fn check(config: &Config) -> MkrootResult<()> {
|
||||||
|
if !&config.root_dir.exists() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
open(&config.root_dir, config.verbose)?;
|
||||||
|
|
||||||
|
for dir in DIRS {
|
||||||
|
let mut d = PathBuf::from(&config.root_dir);
|
||||||
|
d.push(&dir);
|
||||||
|
open(&d, config.verbose)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(dir: &PathBuf, verbose: bool) -> MkrootResult<()> {
|
||||||
|
if dir.exists() {
|
||||||
|
if verbose {
|
||||||
|
println!("Checking directory {}", &dir.display());
|
||||||
|
}
|
||||||
|
if let Err(e) = read_dir(&dir) {
|
||||||
|
return Err(MkrootError::from(format!(
|
||||||
|
"Error opening directory {}: {}",
|
||||||
|
&dir.display(),
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn create(config: &Config) -> MkrootResult<()> {
|
||||||
|
mkdir(&config.root_dir, config.verbose)?;
|
||||||
|
|
||||||
|
for dir in DIRS {
|
||||||
|
let mut d = PathBuf::from(&config.root_dir);
|
||||||
|
d.push(&dir);
|
||||||
|
mkdir(&d, config.verbose)?;
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mkdir(dir: &PathBuf, verbose: bool) -> MkrootResult<()> {
|
||||||
|
if !dir.exists() {
|
||||||
|
if verbose {
|
||||||
|
println!("Creating directory {}", &dir.display());
|
||||||
|
}
|
||||||
|
if let Err(e) = create_dir(&dir) {
|
||||||
|
return Err(MkrootError::from(format!(
|
||||||
|
"Error creating directory {}: {}",
|
||||||
|
&dir.display(),
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -0,0 +1,49 @@
|
|||||||
|
use std::fmt::{Display, Formatter, Result as FmtResult};
|
||||||
|
use std::io::Error as IoError;
|
||||||
|
|
||||||
|
use regex::Error as RegexError;
|
||||||
|
|
||||||
|
pub type MkrootResult<T> = Result<T, MkrootError>;
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum MkrootError {
|
||||||
|
Io(IoError),
|
||||||
|
Regex(RegexError),
|
||||||
|
Custom(String),
|
||||||
|
Empty,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<IoError> for MkrootError {
|
||||||
|
fn from(e: IoError) -> MkrootError {
|
||||||
|
MkrootError::Io(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<RegexError> for MkrootError {
|
||||||
|
fn from(e: RegexError) -> MkrootError {
|
||||||
|
MkrootError::Regex(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<String> for MkrootError {
|
||||||
|
fn from(e: String) -> MkrootError {
|
||||||
|
MkrootError::Custom(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<()> for MkrootError {
|
||||||
|
fn from(_: ()) -> MkrootError {
|
||||||
|
MkrootError::Empty
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MkrootError {
|
||||||
|
fn fmt(&self, f: &mut Formatter) -> FmtResult {
|
||||||
|
match *self {
|
||||||
|
MkrootError::Io(ref e) => Display::fmt(e, f),
|
||||||
|
MkrootError::Regex(ref e) => Display::fmt(e, f),
|
||||||
|
MkrootError::Custom(ref e) => Display::fmt(e, f),
|
||||||
|
MkrootError::Empty => Display::fmt("Empty", f),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,202 @@
|
|||||||
|
use std::fs::{copy as fscopy, File};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
use std::process::Command;
|
||||||
|
|
||||||
|
use regex::Regex;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::error::*;
|
||||||
|
|
||||||
|
pub struct Files {
|
||||||
|
pub bins: Vec<PathBuf>,
|
||||||
|
pub sbins: Vec<PathBuf>,
|
||||||
|
pub libs: Vec<PathBuf>,
|
||||||
|
pub lib64s: Vec<PathBuf>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Files {
|
||||||
|
pub fn gather(config: &Config) -> MkrootResult<Files> {
|
||||||
|
let mut myfiles = Files {
|
||||||
|
bins: Vec::new(),
|
||||||
|
sbins: Vec::new(),
|
||||||
|
libs: Vec::new(),
|
||||||
|
lib64s: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
for file in &config.files {
|
||||||
|
if config.verbose {
|
||||||
|
println!("Checking {}", &file.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
Files::open(&file)?;
|
||||||
|
|
||||||
|
let (libs, lib64s) = Files::libs_from_ldd(&file, &config)?;
|
||||||
|
myfiles.libs.extend(libs);
|
||||||
|
myfiles.lib64s.extend(lib64s);
|
||||||
|
|
||||||
|
if Files::check_sbin(&file) {
|
||||||
|
myfiles.sbins.push(file.to_owned());
|
||||||
|
} else {
|
||||||
|
myfiles.bins.push(file.to_owned());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
myfiles.bins.sort();
|
||||||
|
myfiles.bins.dedup();
|
||||||
|
myfiles.sbins.sort();
|
||||||
|
myfiles.sbins.dedup();
|
||||||
|
myfiles.libs.sort();
|
||||||
|
myfiles.libs.dedup();
|
||||||
|
myfiles.lib64s.sort();
|
||||||
|
myfiles.lib64s.dedup();
|
||||||
|
|
||||||
|
Ok(myfiles)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn open(p: &PathBuf) -> MkrootResult<()> {
|
||||||
|
if let Err(e) = File::open(&p) {
|
||||||
|
return Err(MkrootError::from(format!(
|
||||||
|
"Error opening file ({}): {}",
|
||||||
|
&p.display(),
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn libs_from_ldd(
|
||||||
|
file: &PathBuf,
|
||||||
|
config: &Config,
|
||||||
|
) -> MkrootResult<(Vec<PathBuf>, Vec<PathBuf>)> {
|
||||||
|
let ldd = Files::ldd(&file, &config)?;
|
||||||
|
|
||||||
|
let mut libs: Vec<PathBuf> = Vec::new();
|
||||||
|
let mut lib64s: Vec<PathBuf> = Vec::new();
|
||||||
|
|
||||||
|
if ldd.is_empty() {
|
||||||
|
return Ok((libs, lib64s));
|
||||||
|
}
|
||||||
|
|
||||||
|
let re = Regex::new(r"(^|.* )(?P<path>/.*) \(0x[[:xdigit:]]{16}\)$")?;
|
||||||
|
|
||||||
|
for line in ldd.lines() {
|
||||||
|
let line = String::from(line.trim());
|
||||||
|
|
||||||
|
if let Some(caps) = re.captures(&line) {
|
||||||
|
if let Some(rematch) = caps.name("path") {
|
||||||
|
let match_path = PathBuf::from(rematch.as_str());
|
||||||
|
|
||||||
|
if config.verbose {
|
||||||
|
println!("Adding {}", &match_path.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
if Files::check_lib64(&match_path) {
|
||||||
|
lib64s.push(match_path);
|
||||||
|
} else {
|
||||||
|
libs.push(match_path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok((libs, lib64s))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_lib64(path: &PathBuf) -> bool {
|
||||||
|
for c in path.components() {
|
||||||
|
if c.as_os_str() == "lib64" {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn check_sbin(path: &PathBuf) -> bool {
|
||||||
|
for c in path.components() {
|
||||||
|
if c.as_os_str() == "sbin" {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
false
|
||||||
|
}
|
||||||
|
|
||||||
|
fn ldd(file: &PathBuf, config: &Config) -> MkrootResult<String> {
|
||||||
|
match Command::new(&config.ldd).arg(file).output() {
|
||||||
|
Ok(output) => {
|
||||||
|
if output.status.success() {
|
||||||
|
Ok(String::from_utf8(output.stdout).unwrap_or_default())
|
||||||
|
} else if config.verbose {
|
||||||
|
let mut out = String::from("ldd failed: ");
|
||||||
|
let stdout = String::from_utf8(output.stdout).unwrap_or_default();
|
||||||
|
let stderr = String::from_utf8(output.stderr).unwrap_or_default();
|
||||||
|
|
||||||
|
if !stdout.is_empty() {
|
||||||
|
out = out + "stdout: " + &stdout + " ";
|
||||||
|
}
|
||||||
|
if !stderr.is_empty() {
|
||||||
|
out = out + "stderr: " + &stderr;
|
||||||
|
}
|
||||||
|
|
||||||
|
println!("{}", out.trim());
|
||||||
|
|
||||||
|
Ok(String::new())
|
||||||
|
} else {
|
||||||
|
Ok(String::new())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(e) => Err(MkrootError::from(format!(
|
||||||
|
"Error running ldd ({}): {}",
|
||||||
|
&config.ldd.display(),
|
||||||
|
e
|
||||||
|
))),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn copy(&self, config: &Config) -> MkrootResult<()> {
|
||||||
|
let mut target = PathBuf::from(&config.root_dir);
|
||||||
|
target.push("bin");
|
||||||
|
Files::copy_files(&self.bins, &target, config.verbose)?;
|
||||||
|
|
||||||
|
let mut target = PathBuf::from(&config.root_dir);
|
||||||
|
target.push("sbin");
|
||||||
|
Files::copy_files(&self.sbins, &target, config.verbose)?;
|
||||||
|
|
||||||
|
let mut target = PathBuf::from(&config.root_dir);
|
||||||
|
target.push("libs");
|
||||||
|
Files::copy_files(&self.libs, &target, config.verbose)?;
|
||||||
|
|
||||||
|
let mut target = PathBuf::from(&config.root_dir);
|
||||||
|
target.push("lib64");
|
||||||
|
Files::copy_files(&self.lib64s, &target, config.verbose)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn copy_files(files: &[PathBuf], target: &PathBuf, verbose: bool) -> MkrootResult<()> {
|
||||||
|
for f in files {
|
||||||
|
let mut t = PathBuf::from(&target);
|
||||||
|
if let Some(filename) = &f.file_name() {
|
||||||
|
t.push(filename);
|
||||||
|
|
||||||
|
if verbose {
|
||||||
|
println!("Copying {} to {}", &f.display(), &t.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Err(e) = fscopy(&f, &t) {
|
||||||
|
return Err(MkrootError::from(format!(
|
||||||
|
"Error copying file from {} to {}: {}",
|
||||||
|
&f.display(),
|
||||||
|
&t.display(),
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
} else if verbose {
|
||||||
|
println!("Skipping {}", &f.display());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,5 @@
|
|||||||
|
mod mkroot_files;
|
||||||
|
mod os_release;
|
||||||
|
|
||||||
|
pub use mkroot_files::Files;
|
||||||
|
pub use os_release::os_release;
|
@ -0,0 +1,25 @@
|
|||||||
|
use std::fs::File;
|
||||||
|
use std::io::{BufWriter, Write};
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
use crate::config::Config;
|
||||||
|
use crate::error::MkrootResult;
|
||||||
|
|
||||||
|
pub fn os_release(config: &Config) -> MkrootResult<()> {
|
||||||
|
if config.verbose {
|
||||||
|
println!("Creating file etc/os-release");
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut path = PathBuf::from(&config.root_dir);
|
||||||
|
path.push("etc/os-release");
|
||||||
|
|
||||||
|
let f = File::create(&path)?;
|
||||||
|
let mut writer = BufWriter::new(f);
|
||||||
|
|
||||||
|
writer.write_fmt(format_args!(
|
||||||
|
"NAME=\"{}\"\nVERSION=\"{}\"\n",
|
||||||
|
&config.osname, &config.osversion
|
||||||
|
))?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
@ -0,0 +1,41 @@
|
|||||||
|
extern crate regex;
|
||||||
|
extern crate structopt;
|
||||||
|
|
||||||
|
mod config;
|
||||||
|
mod dirs;
|
||||||
|
mod error;
|
||||||
|
mod files;
|
||||||
|
|
||||||
|
use structopt::StructOpt;
|
||||||
|
|
||||||
|
use config::Config;
|
||||||
|
|
||||||
|
fn main() -> error::MkrootResult<()> {
|
||||||
|
let config: Config = StructOpt::from_args();
|
||||||
|
|
||||||
|
if config.verbose {
|
||||||
|
println!(
|
||||||
|
"Building root fs for {:?} in {}",
|
||||||
|
&config.files,
|
||||||
|
&config.root_dir.display()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
dirs::check(&config)?;
|
||||||
|
let files = files::Files::gather(&config)?;
|
||||||
|
dirs::create(&config)?;
|
||||||
|
files.copy(&config)?;
|
||||||
|
|
||||||
|
if let Err(e) = files::os_release(&config) {
|
||||||
|
return Err(error::MkrootError::from(format!(
|
||||||
|
"Error creating etc/os-release: {}",
|
||||||
|
e
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// cp skel
|
||||||
|
// run ldconfig
|
||||||
|
// set permissions
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
Loading…
Reference in new issue