初步完成
commit
8d8939624b
@ -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"
|
@ -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"
|
@ -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
|
Binary file not shown.
@ -0,0 +1,45 @@
|
||||
use std::{error::Error, fmt::{Debug, Display, Formatter}};
|
||||
use nix::errno::Errno;
|
||||
pub type Result<T> = std::result::Result<T, RockerError>;
|
||||
|
||||
|
||||
#[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<std::io::Error> for RockerError {
|
||||
fn from(value: std::io::Error) -> Self {
|
||||
Self::IoError(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Errno> for RockerError {
|
||||
fn from(err: Errno) -> Self {
|
||||
Self::OtherError(format!("errno: {err}"))
|
||||
}
|
||||
}
|
@ -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<String>,
|
||||
#[arg(long)]
|
||||
image: Option<String>,
|
||||
|
||||
#[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<P: AsRef<Path>>(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<P: AsRef<Path>>(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<P: AsRef<Path>>(path: P) -> Result<()> {
|
||||
fs::create_dir_all(&path)?;
|
||||
fs::set_permissions(&path, PermissionsExt::from_mode(0o777))?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
||||
fn parse_cmd(run: &String) -> Vec<CString>{
|
||||
let args= run
|
||||
.split(" ")
|
||||
.filter_map(|s| {
|
||||
match CString::new(s) {
|
||||
Ok(cs) => {
|
||||
Some(cs)
|
||||
}
|
||||
Err(e) => {
|
||||
println!("{e:?}");
|
||||
None
|
||||
}
|
||||
}
|
||||
})
|
||||
.collect::<Vec<CString>>();
|
||||
args
|
||||
}
|
||||
|
||||
|
||||
fn check_container_is_running(pid: &Pid, main_exe: &Path) -> Result<bool> {
|
||||
// 检查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<String> {
|
||||
// 禁止同时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(())
|
||||
}
|
Loading…
Reference in New Issue