use super::Cmd; use clap::{Arg, Command}; use std::{ env, io, os::unix::{fs, process::CommandExt}, process, }; #[derive(Debug, Default)] pub struct Chroot; impl Cmd for Chroot { fn cli(&self) -> clap::Command { Command::new("chroot") .about("run command or interactive shell with special root directory") .author("Nathan Fisher") .version(env!("CARGO_PKG_VERSION")) .args([ Arg::new("dir") .short('d') .long("directory") .help("change to this directory after performing the chroot instead of '/'") .value_name("DIRECTORY"), Arg::new("newroot") .value_name("NEWROOT") .num_args(1) .required(true), Arg::new("command") .value_name("COMMAND") .num_args(1) .required(false), Arg::new("arg") .value_name("ARG") .num_args(1..) .requires("command") .allow_hyphen_values(true) .required(false), ]) } fn run(&self, matches: &clap::ArgMatches) -> Result<(), Box> { let Some(newroot) = matches.get_one::("newroot") else { return Err(io::Error::new(io::ErrorKind::Other, "no new root given").into()); }; let mut command = if let Some(c) = matches.get_one::("command") { process::Command::new(c) } else if let Ok(s) = env::var("SHELL") { process::Command::new(s) } else { process::Command::new("/bin/sh") }; let mut command = &mut command; if let Some(mut args) = matches.get_many::("arg") { command = command.args(&mut args); } fs::chroot(newroot)?; if let Some(d) = matches.get_one::("dir") { env::set_current_dir(d)?; } else { env::set_current_dir("/")?; } return Err(command.exec().into()); } fn path(&self) -> Option { Some(shitbox::Path::UsrSbin) } }