commit 8d8939624b44bb3c0f11e07c08245aa76ba1e257 Author: 阳光少年 <849317537@qq.com> Date: Tue Jul 30 10:07:22 2024 +0000 初步完成 diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..91ca9fe --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,363 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "anstream" +version = "0.6.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64e15c1ab1f89faffbf04a634d5e1962e9074f2741eef6d97f3c4e322426d526" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bec1de6f59aedf83baf9ff929c98f2ad654b97c9510f4e70cf6f661d49fd5b1" + +[[package]] +name = "anstyle-parse" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eb47de1e80c2b463c735db5b217a0ddc39d612e7ac9e2e96a5aed1f57616c1cb" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d36fc52c7f6c869915e99412912f22093507da8d9e942ceaf66fe4b7c14422a" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5bf74e1b6e971609db8ca7a9ce79fd5768ab6ae46441c572e46cf596f59e57f8" +dependencies = [ + "anstyle", + "windows-sys", +] + +[[package]] +name = "bitflags" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "clap" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35723e6a11662c2afb578bcf0b88bf6ea8e21282a953428f240574fcc3a2b5b3" +dependencies = [ + "clap_builder", + "clap_derive", +] + +[[package]] +name = "clap_builder" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49eb96cbfa7cfa35017b7cd548c75b14c3118c98b423041d70562665e07fb0fa" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_derive" +version = "4.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d029b67f89d30bbb547c89fd5161293c0aec155fc691d7924b64550662db93e" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "clap_lex" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1462739cb27611015575c0c11df5df7601141071f07518d56fcc1be504cbec97" + +[[package]] +name = "colorchoice" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3fd119d74b830634cea2a0f58bbd0d54540518a14397557951e79340abc28c0" + +[[package]] +name = "getrandom" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" + +[[package]] +name = "itoa" +version = "1.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b" + +[[package]] +name = "libc" +version = "0.2.155" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97b3888a4aecf77e811145cadf6eef5901f4782c53886191b2f693f24761847c" + +[[package]] +name = "memchr" +version = "2.7.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78ca9ab1a0babb1e7d5695e3530886289c18cf2f87ec19a575a0abdce112e3a3" + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags", + "cfg-if", + "cfg_aliases", + "libc", +] + +[[package]] +name = "proc-macro2" +version = "1.0.86" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e719e8df665df0d1c8fbfd238015744736151d4445ec0836b8e628aae103b77" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fa76aaf39101c457836aec0ce2316dbdc3ab723cdda1c6bd4e6ad4208acaca7" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rocker" +version = "0.1.0" +dependencies = [ + "clap", + "nix", + "serde", + "serde_json", + "toml", + "uuid", +] + +[[package]] +name = "ryu" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" + +[[package]] +name = "serde" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc76f558e0cbb2a839d37354c575f1dc3fdc6546b5be373ba43d95f231bf7c12" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.204" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e0cd7e117be63d3c3678776753929474f3b04a43a080c744d6b0ae2a8c28e222" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.121" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ab380d7d9f22ef3f21ad3e6c1ebe8e4fc7a2000ccba2e4d71fc96f15b2cb609" +dependencies = [ + "itoa", + "memchr", + "ryu", + "serde", +] + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "syn" +version = "2.0.72" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc4b9b9bf2add8093d3f2c0204471e951b2285580335de42f9d2534f3ae7a8af" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "toml" +version = "0.5.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4f7f0dd8d50a853a531c426359045b1998f04219d88799810762cd4ad314234" +dependencies = [ + "serde", +] + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "uuid" +version = "1.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81dfa00651efa65069b0b6b651f4aaa31ba9e3c3ce0137aaad053604ee7e0314" +dependencies = [ + "getrandom", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_gnullvm", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2a01296 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "rocker" +version = "0.1.0" +edition = "2021" + +[dependencies] +uuid = {version = "1.3", features = ["v4"]} +toml = "0.5" +clap = {version = "4.5.0", features = ["derive"]} +nix = {version = "0.29", features = ["sched", "process", "hostname", "mount", "fs", "env", "user", "term"]} +serde = { version = "1.0", features = ["derive"] } +toml = "0.8" \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b77c37d --- /dev/null +++ b/Makefile @@ -0,0 +1,23 @@ +WORKSPACE := /root/rocker + +build: + cargo build --release + +# 创建WORKSPACE 对应的文件夹 +install: build + mkdir -p $(WORKSPACE) + mkdir -p $(WORKSPACE)/images + mkdir -p $(WORKSPACE)/volumes + mkdir -p $(WORKSPACE)/containers + chmod -R 777 $(WORKSPACE) + + cp images/* /root/rocker/images/ + cp target/release/rocker /usr/bin/rocker + + # 创建一个普通用户 + -useradd -g rocker rocker + -groupadd rocker + +clean: + rm -rf $(WORKSPACE) + rm -rf /usr/bin/rocker diff --git a/images/busybox b/images/busybox new file mode 100644 index 0000000..25ba855 Binary files /dev/null and b/images/busybox differ diff --git a/src/config.toml b/src/config.toml new file mode 100644 index 0000000..e69de29 diff --git a/src/error.rs b/src/error.rs new file mode 100644 index 0000000..336ec7d --- /dev/null +++ b/src/error.rs @@ -0,0 +1,45 @@ +use std::{error::Error, fmt::{Debug, Display, Formatter}}; +use nix::errno::Errno; +pub type Result = std::result::Result; + + +#[derive(Debug)] +pub enum RockerError { + IoError(std::io::Error), + OtherError(String), + ErrnoError(Errno) +} + + + +impl Display for RockerError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + Self::IoError(e) => write!(f, "{}", e), + Self::OtherError(s) => write!(f, "{}", s), + Self::ErrnoError(e) => write!(f, "{}", e) + } + } +} + +impl Error for RockerError { + fn source(&self) -> Option<&(dyn Error + 'static)> { + match self { + Self::IoError(e) => Some(e), + Self::OtherError(_) => None, + Self::ErrnoError(e) => Some(e) + } + } +} + +impl From for RockerError { + fn from(value: std::io::Error) -> Self { + Self::IoError(value) + } +} + +impl From for RockerError { + fn from(err: Errno) -> Self { + Self::OtherError(format!("errno: {err}")) + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..10f210c --- /dev/null +++ b/src/main.rs @@ -0,0 +1,311 @@ +use std::arch::asm; +use std::ffi::{CStr, CString}; +use std::fs::File; +use std::os::fd::AsRawFd; +use std::os::unix::fs::PermissionsExt; +use nix::libc::{setgid, CLONE_NEWCGROUP, MS_NODEV, MS_NOSUID}; +use nix::sched::{clone, CloneCb, CloneFlags}; +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::mount::{mount, MntFlags, MsFlags, umount2, umount}; +use nix::env::clearenv; +use nix::pty; +use serde::Deserialize; +use std::path::{Path, PathBuf}; +use clap::Parser; +use error::{Result, RockerError}; +mod error; +use uuid; +use std::{io, fs}; +use toml; +use serde::Deserialize; + +static WORKSPACE: &str = "/root/rocker"; +static USER_NAME: &str = "rocker"; +static mut STACK: [u8; 1024*1024*1] = [0; 1024*1024*1]; +static CLONE_FLAG: i32 = 0b1101100000000100000000000000000; // CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWPID | CLONE_NEWIPC | CLONE_NEWNET; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct RockerArgs { + // --wait/--log --run /bin/bash --image busybox + #[arg(long)] + run: Option, + #[arg(long)] + image: Option, + + #[arg(long)] + log: bool, + #[arg(long)] + wait: bool, +} + + +/// 从images解压到volumes +fn extend_image(image_name: &String) -> Result<(PathBuf)> { + // volumes只读层 + let volume_path = Path::new(WORKSPACE).join("volumes").join(image_name); + if volume_path.exists() { + return Ok(volume_path); + } else { + // std::fs::create_dir_all(&volume_path)?; + // std::fs::set_permissions(&volume_path, PermissionsExt::from_mode(0o777))?; + create_dir_and_set777(&volume_path)?; + } + let volume_path_str = volume_path.to_str().unwrap(); // 安全的unwrap + + // 源文件 + let image_path = Path::new(WORKSPACE).join("images").join(image_name); + if image_path.exists() == false { + return Err(RockerError::from(io::Error::new(io::ErrorKind::NotFound, "未找到镜像"))); + } + let image_path_str = image_path.to_str().unwrap(); // 安全的unwrap + + // 解压缩 + let out = std::process::Command::new("tar") + .arg("-xvf") + .arg(image_path_str) + .arg("-C") + .arg(volume_path_str) + .output()?; + let std_out = String::from_utf8_lossy(&out.stdout); + let std_err = String::from_utf8_lossy(&out.stderr); + if std_err.len() == 0 { + println!("解压缩完毕: {std_out:?}"); + } else { + return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("解压缩镜像失败: {std_err}")))); + } + Ok(volume_path) +} + + +fn init_container_overlay>(volume_path: P, upper_path: P, merged_path: P) -> Result<()> { + let lower_dir = volume_path.as_ref().to_string_lossy().to_string(); + let upper_dir = upper_path.as_ref().to_string_lossy().to_string(); + let merged_dir = merged_path.as_ref().to_string_lossy().to_string(); + + let dirs = format!("lowerdir={lower_dir},upperdir={upper_dir},workdir={merged_dir}"); + println!("dirs: {dirs:?}"); + let out = std::process::Command::new("mount") + .arg("-t") + .arg("overlay") + .arg("overlay") + .arg("-o") + .arg(dirs) + .arg(merged_dir) + .output()?; + + let std_out = String::from_utf8_lossy(&out.stdout); + let std_err = String::from_utf8_lossy(&out.stderr); + + if std_err.len() == 0 { + println!("容器文件系统创建完成: {std_out:?}"); + } else { + return Err(RockerError::from(io::Error::new(io::ErrorKind::Other, format!("容器文件系统创建失败: {std_err:?}")))); + } + Ok(()) +} + +fn init_container_pivot>(merged_path: P) -> Result<()> { + // 在我们没有设置 chroot之前, 需要先把所有挂载点的传播类型改为 private, 避免进程中的系统调用污染全局 + mount(None::<&str>, "/", None::<&str>, MsFlags::MS_PRIVATE | MsFlags::MS_REC, None::<&str>)?; + + // 修改overlayfs 为rootfs + chdir(merged_path.as_ref())?; + let pwd_path = std::env::current_dir()?; + let pwd_str = pwd_path.to_string_lossy().to_string(); + + // 挂载bind + mount(Some(pwd_str.as_str()), pwd_str.as_str(), Some("bind"), MsFlags::MS_BIND | MsFlags::MS_REC, Some(""))?; + + // 创建 rootfs/.pivot_root 目录用于存储 old_root + let pivot_root_dir = format!("{pwd_str}/.pivot_root"); + + // 将系统rootfs切换到新的rootfs, 并设置权限 + std::fs::create_dir(&pivot_root_dir)?; + std::fs::set_permissions(&pivot_root_dir, PermissionsExt::from_mode(0o777))?; + pivot_root(pwd_str.as_str(), pivot_root_dir.as_str())?; + + // 修改当前进程工作目录(注意我们之前已经到rootfs内, 并且把根目录设置完毕了) + chdir("/")?; + + // 卸载 old_root, 并删除临时文件 + umount2(".pivot_root", MntFlags::MNT_DETACH).unwrap(); + std::fs::remove_dir(".pivot_root").unwrap(); + Ok(()) +} + + +fn init_container_mount() -> Result<()> { + // 挂载proc + let mount_flags = MsFlags::MS_NODEV | MsFlags::MS_NOEXEC | MsFlags::MS_NOSUID; + mount(Some("proc"), "/proc", Some("proc"), mount_flags, Some(""))?; + + // 挂载dev + mount(Some("tmpfs"), "/dev", Some("tmpfs"), mount_flags, Some("mode=755"))?; + Ok(()) +} + +fn init_container_log(log: bool) -> Result<()> { + let log_path = Path::new("logs"); + create_dir_and_set777(log_path)?; + let log_fd = File::create(log_path.join("log"))?; + let log_fd_raw = log_fd.as_raw_fd(); + if log { + unsafe { + dup2(log_fd_raw, 1)?; + dup2(log_fd_raw, 2)?; + } + } + Ok(()) +} + +fn init_container_env() -> Result<()> { + unsafe { + clearenv().map_err(|e|RockerError::OtherError(format!("清除env失败: {e:?}")))?; + } + Ok(()) +} +fn init_container_user(uid: Uid, gid: Gid) -> Result<()>{ + unsafe { + setgid(gid.as_raw()); + setgroups(&[gid])?; + } + setuid(uid)?; + Ok(()) +} + +fn create_dir_and_set777>(path: P) -> Result<()> { + fs::create_dir_all(&path)?; + fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?; + Ok(()) +} + + +fn parse_cmd(run: &String) -> Vec{ + let args= run + .split(" ") + .filter_map(|s| { + match CString::new(s) { + Ok(cs) => { + Some(cs) + } + Err(e) => { + println!("{e:?}"); + None + } + } + }) + .collect::>(); + args +} + + +fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result { + // 检查pid对应的exe是否和外部传过来的相同 + let child_exe_s= format!("/proc/{pid}/exe"); + let child_exe_path = Path::new(child_exe_s.as_str()); + let target_child_exe_path = fs::read_link(child_exe_path)?; + if target_child_exe_path != main_exe { + std::thread::sleep(std::time::Duration::from_millis(10)); + return Ok(true); + } + + Ok(false) +} + +fn run_container(cmd: &String, wait:bool, log:bool, volume_path: &PathBuf) -> Result { + // 禁止同时wait和log + if wait && log { + return Err(RockerError::OtherError("--wait/--log 禁止同时使用".to_string())); + } + + // 初始化容器工作目录 + let _container_id = uuid::Uuid::new_v4().to_string(); + 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_and_set777(&container_work_path)?; + create_dir_and_set777(&container_upper_path)?; + create_dir_and_set777(&container_merged_path)?; + + 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 = || { + init_container_overlay(volume_path, &container_upper_path, &container_merged_path).unwrap(); + init_container_pivot(&container_merged_path).unwrap(); + init_container_mount().unwrap(); + init_container_log(log).unwrap(); + init_container_env().unwrap(); + init_container_user(rocker_uid, rocker_gid).unwrap(); + + let cmd_vec = parse_cmd(cmd); + execv(&cmd_vec[0], &cmd_vec).unwrap(); + 0 + }; + + let main_exe = std::env::current_exe()?; + unsafe { + match clone(Box::new(_cb), STACK.as_mut_slice(), CloneFlags::from_bits_truncate(CLONE_FLAG), None) { + Ok(child_pid) => { + println!("clone ok: {child_pid:?}"); + + // check_container_is_running + while let Ok(running) = check_container_is_running(&child_pid, &main_exe) { + if running { + break; + } + } + + // wait + if wait { + match waitpid(child_pid, Some(WaitPidFlag::WUNTRACED)) { + Ok(status) => { + println!("{child_pid:?} exit: {status:?}"); + } + Err(e) => { + return Err(RockerError::OtherError(format!("{child_pid} err: {e}"))); + } + } + } + } + Err(e) => { + return Err(RockerError::OtherError(format!("clone err: {e}"))); + } + } + } + Ok(_container_id) +} + +#[derive(Deserialize)] +struct ContainerInfo { + id: String, + image: String, + volume: String, +} + +fn save_container_info(container_id: &String) -> Result<()> { + let container_info_path = Path::new(WORKSPACE).join("containers").join(container_id).join("container.json"); + let container_info = ContainerInfo { + id: container_id.to_string(), + image: "".to_string(), + volume: "".to_string(), + }; + let toml_str = toml::to_string(&container_info)?; + // println!("") + + Ok(()) +} + + +fn main() -> Result<()>{ + let args = RockerArgs::parse(); + if let (Some(cmd), Some(image_name)) = (&args.run, &args.image) { + let volume_path = extend_image(image_name)?; + let container_id = run_container(cmd, args.wait, args.log, &volume_path)?; + + } + Ok(()) +} \ No newline at end of file