exec暂时完成

main
阳光少年 1 year ago
parent 2f30d2b1bc
commit 9b2be9a563

@ -1,10 +1,10 @@
use std::arch::asm; use std::arch::asm;
use std::ffi::{CStr, CString}; use std::ffi::{CStr, CString};
use std::fs::File; use std::fs::File;
use std::os::fd::AsRawFd; use std::os::fd::{AsFd, AsRawFd};
use std::os::unix::fs::PermissionsExt; use std::os::unix::fs::PermissionsExt;
use nix::libc::{self, setgid, CLONE_NEWCGROUP, MS_NODEV, MS_NOSUID}; use nix::libc::{self, setgid, CLONE_NEWCGROUP, MS_NODEV, MS_NOSUID};
use nix::sched::{clone, CloneCb, CloneFlags}; use nix::sched::{clone, CloneCb, CloneFlags, setns};
use nix::sys::signal::{kill, Signal}; use nix::sys::signal::{kill, Signal};
use nix::sys::wait::{wait, waitpid, waitid, WaitPidFlag}; use nix::sys::wait::{wait, waitpid, waitid, WaitPidFlag};
use nix::unistd::{chdir, chroot, dup2, execv, pivot_root, setuid, sleep, Gid, Pid, Uid, User, setgroups}; use nix::unistd::{chdir, chroot, dup2, execv, pivot_root, setuid, sleep, Gid, Pid, Uid, User, setgroups};
@ -40,6 +40,10 @@ struct RockerArgs {
#[arg(long)] #[arg(long)]
env: Option<String>, env: Option<String>,
// --run /bin/bash --exec container_id
#[arg(long)]
exec: Option<String>,
#[arg(long)] #[arg(long)]
log: bool, log: bool,
#[arg(long)] #[arg(long)]
@ -111,6 +115,7 @@ fn init_container_lock<P: AsRef<Path>>(container_work_path:P) -> Result<i32> {
let lock_path_str = lock_path.as_os_str(); let lock_path_str = lock_path.as_os_str();
let oflag = OFlag::O_RDWR | OFlag::O_CREAT; let oflag = OFlag::O_RDWR | OFlag::O_CREAT;
let mode = Mode::empty(); let mode = Mode::empty();
println!("{lock_path_str:?}");
Ok(open(lock_path_str, oflag, mode)?) Ok(open(lock_path_str, oflag, mode)?)
} }
@ -130,11 +135,11 @@ fn init_container_overlay<P: AsRef<Path>>(volume_path: P, upper_path: P, merged_
.arg(merged_dir) .arg(merged_dir)
.output()?; .output()?;
let std_out = String::from_utf8_lossy(&out.stdout); // let std_out = String::from_utf8_lossy(&out.stdout);
let std_err = String::from_utf8_lossy(&out.stderr); let std_err = String::from_utf8_lossy(&out.stderr);
if std_err.len() == 0 { if std_err.len() == 0 {
println!("容器文件系统创建完成: {std_out:?}"); println!("容器文件系统创建完成");
} else { } else {
return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("容器文件系统创建失败: {std_err:?}")))); return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("容器文件系统创建失败: {std_err:?}"))));
} }
@ -288,49 +293,20 @@ fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result<bool> {
Ok(false) Ok(false)
} }
fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf) -> Result<i32> { fn init_exec_ns(pid: i32) -> Result<()>{
// 禁止同时wait和log // 把当前进程加入到指定pid的namespace
if args.wait && args.log { for ns_name in vec!["ipc", "uts", "net", "pid", "mnt"] {
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string())); let ns_path = format!("/proc/{pid}/ns/{ns_name}");
} let ns_fild = File::open(ns_path)?;
setns(ns_fild.as_fd(), CloneFlags::from_bits_retain(0))? }
// 初始化容器工作目录 Ok(())
let container_work_path = Path::new(WORKSPACE).join("containers").join(&_container_id); }
let container_upper_path = container_work_path.join("upper");
let container_merged_path = container_work_path.join("merged");
create_dir(&container_work_path, true)?;
create_dir(&container_upper_path, true)?;
create_dir(&container_merged_path, true)?;
let rocker_user_info = User::from_name(USER_NAME)?.ok_or(RockerError::OtherError(format!("没找到 用户: {USER_NAME}")))?;
let rocker_uid = rocker_user_info.uid;
let rocker_gid = rocker_user_info.gid;
let _cb = || { fn start(is_wait: bool, cb: CloneCb, clong_flags: CloneFlags) -> Result<i32>{
init_container_lock(&container_work_path).unwrap();
init_container_overlay(volume_path, &container_upper_path, &container_merged_path).unwrap();
if let Some(custom_volume) = &args.volume {
init_container_custom_volume(&container_merged_path, custom_volume).unwrap();
}
init_container_pivot(&container_merged_path).unwrap();
init_container_mount().unwrap();
init_container_log(args.log).unwrap();
init_container_env().unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
let cmd_vec = parse_cmd(cmd);
match execv(&cmd_vec[0], &cmd_vec) {
Err(e) => {
println!("execv {cmd_vec:?}失败: {e:?}");
}
_ => {},
};
0
};
let main_exe = std::env::current_exe()?; let main_exe = std::env::current_exe()?;
unsafe { unsafe {
match clone(Box::new(_cb), STACK.as_mut_slice(), CloneFlags::from_bits_truncate(CLONE_FLAG), None) { match clone(cb, STACK.as_mut_slice(), clong_flags, None) {
Ok(child_pid) => { Ok(child_pid) => {
println!("clone ok: {child_pid:?}"); println!("clone ok: {child_pid:?}");
@ -349,7 +325,7 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume
} }
// wait // wait
if args.wait { if is_wait {
match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) { match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) {
Ok(status) => { Ok(status) => {
println!("{child_pid:?} exit: {status:?}"); println!("{child_pid:?} exit: {status:?}");
@ -362,12 +338,81 @@ fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume
Ok(child_pid.as_raw()) Ok(child_pid.as_raw())
} }
Err(e) => { Err(e) => {
return Err(RockerError::OtherError(format!("clone err: {e}"))); Err(RockerError::OtherError(format!("clone err: {e}")))
} }
} }
} }
} }
fn run_container(_container_id: &String, cmd: &String, args: &RockerArgs, volume_path: &PathBuf, is_exec: bool) -> Result<i32> {
// 禁止同时wait和log
if args.wait && args.log {
return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string()));
}
let clone_flags;
// 初始化容器工作目录
let container_work_path = Path::new(WORKSPACE).join("containers").join(&_container_id);
let container_upper_path = container_work_path.join("upper");
let container_merged_path = container_work_path.join("merged");
create_dir(&container_work_path, true)?;
create_dir(&container_upper_path, true)?;
create_dir(&container_merged_path, true)?;
let rocker_user_info = User::from_name(USER_NAME)?.ok_or(RockerError::OtherError(format!("没找到 用户: {USER_NAME}")))?;
let rocker_uid = rocker_user_info.uid;
let rocker_gid = rocker_user_info.gid;
let _cb = if is_exec {
let _cb = move || {
let container_info = get_container_info(_container_id).unwrap();
init_exec_ns(container_info.pid).unwrap();
init_container_env().unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
let cmd_vec = parse_cmd(cmd);
match execv(&cmd_vec[0], &cmd_vec) {
Err(e) => {
println!("execv {cmd_vec:?}失败: {e:?}");
}
_ => {},
};
0isize
};
clone_flags = CloneFlags::empty();
Box::new(_cb) as CloneCb
} else {
let _cb = move || {
init_container_lock(&container_work_path).unwrap();
init_container_overlay(volume_path, &container_upper_path, &container_merged_path).unwrap();
if let Some(custom_volume) = &args.volume {
init_container_custom_volume(&container_merged_path, custom_volume).unwrap();
}
init_container_pivot(&container_merged_path).unwrap();
init_container_mount().unwrap();
init_container_log(args.log).unwrap();
init_container_env().unwrap();
init_container_user(rocker_uid, rocker_gid).unwrap();
let cmd_vec = parse_cmd(cmd);
match execv(&cmd_vec[0], &cmd_vec) {
Err(e) => {
println!("execv {cmd_vec:?}失败: {e:?}");
}
_ => {},
};
0isize
};
clone_flags = CloneFlags::from_bits_truncate(CLONE_FLAG);
Box::new(_cb) as CloneCb
};
start(args.wait, _cb, clone_flags)
}
#[derive(Deserialize, Serialize, Debug, PartialEq)] #[derive(Deserialize, Serialize, Debug, PartialEq)]
enum ContainerStatus { enum ContainerStatus {
READY, READY,
@ -428,8 +473,8 @@ fn get_container_info(container_id: &str) -> Result<ContainerInfo> {
let lock_path = container_work_path.join(LOCK_FILE); let lock_path = container_work_path.join(LOCK_FILE);
let info_str = fs::read_to_string(container_info_path)?; let info_str = fs::read_to_string(container_info_path)?;
let mut container_info: ContainerInfo = toml::from_str(&info_str)?; let mut container_info: ContainerInfo = toml::from_str(&info_str)?;
// 判断是否正在运行, 首先得到该容器所有的fd // 判断是否正在运行, 首先得到该容器进程对应的所有的fd
let proc_fd_path = Path::new("/proc").join(container_info.pid.to_string()).join("fd"); let proc_fd_path = Path::new("/proc").join(container_info.pid.to_string()).join("fd");
let is_running = if let Ok(fd_dir) = fs::read_dir(proc_fd_path) { let is_running = if let Ok(fd_dir) = fs::read_dir(proc_fd_path) {
fd_dir.filter_map(|p|p.ok()) fd_dir.filter_map(|p|p.ok())
@ -475,25 +520,36 @@ fn stop_container(containers_id: &str, is_remove: bool) -> Result<()> {
if let Ok(container_info) = get_container_info(container_id) { if let Ok(container_info) = get_container_info(container_id) {
let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id); let container_work_path = Path::new(WORKSPACE).join("containers").join(container_id);
let container_merged_path = container_work_path.join("merged"); let container_merged_path = container_work_path.join("merged");
println!("container_merged_path: {container_merged_path:?}");
// 正在运行中的需要 kill // 正在运行中的需要 kill
if container_info.status == ContainerStatus::RUNNING { if container_info.status == ContainerStatus::RUNNING {
let _ = kill(Pid::from_raw(container_info.pid), Signal::SIGTERM); let _ = kill(Pid::from_raw(container_info.pid), Signal::SIGTERM);
let pid_path = Path::new("/proc").join(container_info.pid.to_string());
while pid_path.exists() {
std::thread::sleep(std::time::Duration::from_millis(10));
}
} }
// 卸载自定义挂载点 // 卸载自定义挂载点
if container_info.volume != "" { if container_info.volume != "" {
container_info.volume container_info.volume
.split(",") .split(",")
.filter_map(|v| v.split(":").last()) .filter_map(|v| v.split(":").last())
.map(|v| container_merged_path.join(v).to_string_lossy().to_string()) .map(|v| {
if v.starts_with("/") {
container_merged_path.join(&v[1..]).to_string_lossy().to_string()
} else {
container_merged_path.join(v).to_string_lossy().to_string()
}
})
.for_each(|s| { .for_each(|s| {
match umount(s.as_str()) { match umount2(s.as_str(), MntFlags::MNT_DETACH) {
Ok(_) => println!("卸载自定卷"), Ok(_) => println!("卸载自定卷{s}"),
Err(e) => panic!("卸载卷失败: {e:?}"), Err(e) => println!("卸载卷{s}失败: {e:?}"),
} }
}); });
} }
// 卸载overlayfs // 卸载overlayfs
match umount(container_merged_path.to_str().unwrap()) { match umount2(container_merged_path.to_str().unwrap(), MntFlags::MNT_DETACH) {
Ok(_) => println!("卸载overlayfs卷"), Ok(_) => println!("卸载overlayfs卷"),
Err(e) => println!("卸载overlayfs失败: {e:?}"), Err(e) => println!("卸载overlayfs失败: {e:?}"),
} }
@ -522,7 +578,7 @@ fn main() -> Result<()>{
let volume_path = extend_image(image_name)?; let volume_path = extend_image(image_name)?;
let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string(); let container_id = uuid::Uuid::new_v4().to_string()[0..8].to_string();
let mut pid = -1; let mut pid = -1;
match run_container(&container_id,&cmd, &args, &volume_path) { match run_container(&container_id,&cmd, &args, &volume_path, false) {
Ok(child_pid) => { Ok(child_pid) => {
pid = child_pid; pid = child_pid;
} }
@ -540,6 +596,8 @@ fn main() -> Result<()>{
} else if let Some(containers_id) = &args.stop { } else if let Some(containers_id) = &args.stop {
// --stop // --stop
stop_container(containers_id, false)?; stop_container(containers_id, false)?;
} else if let (Some(cmd), Some(container_id)) = (&args.run, &args.exec) {
run_container(container_id, &cmd, &args, &Default::default(), true).unwrap();
} }
// } else if let Some(containers_id) = &args.start { // } else if let Some(containers_id) = &args.start {
// // --start // // --start

Loading…
Cancel
Save