244 lines
6.6 KiB
Rust
244 lines
6.6 KiB
Rust
use std::{
|
|
fs::{self, File},
|
|
io::BufWriter,
|
|
path::{Path, PathBuf},
|
|
};
|
|
|
|
use walkdir::WalkDir;
|
|
|
|
use crate::{
|
|
build::{c, cargo::CargoBuilder},
|
|
check::AllOk,
|
|
env::BuildEnv,
|
|
error::Error,
|
|
util,
|
|
};
|
|
|
|
use super::InitrdGenerated;
|
|
|
|
const PROGRAMS: &[(&str, &str)] = &[
|
|
// init
|
|
("init", "init"),
|
|
("rc", "sbin/rc"),
|
|
("service", "sbin/service"),
|
|
("logd", "sbin/logd"),
|
|
("kmod", "sbin/kmod"),
|
|
// shell
|
|
("shell", "bin/sh"),
|
|
// sysutils
|
|
("mount", "sbin/mount"),
|
|
("login", "sbin/login"),
|
|
("strace", "bin/strace"),
|
|
("ls", "bin/ls"),
|
|
("mv", "bin/mv"),
|
|
("ln", "bin/ln"),
|
|
("mkdir", "bin/mkdir"),
|
|
("touch", "bin/touch"),
|
|
("rm", "bin/rm"),
|
|
("cat", "bin/cat"),
|
|
("hexd", "bin/hexd"),
|
|
("dd", "bin/dd"),
|
|
("random", "bin/random"),
|
|
("view", "bin/view"),
|
|
("grep", "bin/grep"),
|
|
("chmod", "bin/chmod"),
|
|
("sha256sum", "bin/sha256sum"),
|
|
("sysmon", "bin/sysmon"),
|
|
("date", "bin/date"),
|
|
("sync", "bin/sync"),
|
|
("sleep", "bin/sleep"),
|
|
("lspci", "bin/lspci"),
|
|
("ps", "bin/ps"),
|
|
("top", "bin/top"),
|
|
("tst", "bin/tst"),
|
|
("md2txt", "bin/md2txt"),
|
|
// netutils
|
|
("netconf", "sbin/netconf"),
|
|
("dhcp-client", "sbin/dhcp-client"),
|
|
("nc", "bin/nc"),
|
|
("http", "bin/http"),
|
|
("dnsq", "bin/dnsq"),
|
|
("ping", "bin/ping"),
|
|
("ncap", "sbin/ncap"),
|
|
// colors
|
|
("colors", "bin/colors"),
|
|
("colors-bar", "bin/colors-bar"),
|
|
("term", "bin/term"),
|
|
// red
|
|
("red", "bin/red"),
|
|
// rdb
|
|
("rdb", "bin/rdb"),
|
|
// rsh
|
|
("rsh", "bin/rsh"),
|
|
("rshd", "sbin/rshd"),
|
|
// crypt
|
|
("crypt", "bin/crypt"),
|
|
("dyn-loader", "libexec/dyn-loader"),
|
|
// TODO: proper process for C program builds
|
|
];
|
|
|
|
fn build_userspace(
|
|
env: &BuildEnv,
|
|
extra: &mut Vec<(PathBuf, PathBuf)>,
|
|
_: AllOk,
|
|
) -> Result<(), Error> {
|
|
log::info!("Building userspace");
|
|
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace"))?;
|
|
CargoBuilder::Userspace(env).build(env.workspace_root.join("userspace/dynload-program"))?;
|
|
|
|
if env.config.components(env).libc || env.config.components(env).libcxx {
|
|
c::build_c(env, extra)?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn build_rootfs<S: AsRef<Path>, D: AsRef<Path>>(
|
|
env: &BuildEnv,
|
|
install_extra: Vec<(PathBuf, PathBuf)>,
|
|
build_dir: S,
|
|
rootfs_dir: D,
|
|
_: AllOk,
|
|
) -> Result<(), Error> {
|
|
let user_dir = env.workspace_root.join("userspace");
|
|
let build_dir = build_dir.as_ref();
|
|
let rootfs_dir = rootfs_dir.as_ref();
|
|
|
|
log::info!("Building rootfs: {}", rootfs_dir.display());
|
|
|
|
for dir in ["sbin", "bin", "dev", "sys", "tmp", "mnt"] {
|
|
fs::create_dir_all(rootfs_dir.join(dir))?;
|
|
File::create(rootfs_dir.join(dir).join(".do_not_remove"))?;
|
|
}
|
|
|
|
// TODO grab this from cargo somehow?
|
|
for &(src, dst) in PROGRAMS {
|
|
let src_path = build_dir.join(src);
|
|
let dst_path = rootfs_dir.join(dst);
|
|
|
|
if let Some(dst_parent) = dst_path.parent() {
|
|
fs::create_dir_all(dst_parent)?;
|
|
}
|
|
|
|
log::trace!(
|
|
"Install binary: {} -> {}",
|
|
src_path.display(),
|
|
dst_path.display()
|
|
);
|
|
util::copy_file(src_path, dst_path)?;
|
|
}
|
|
|
|
if let Ok(read_dir) = fs::read_dir("userspace/scripts") {
|
|
for entry in read_dir {
|
|
let Ok(entry) = entry else {
|
|
continue;
|
|
};
|
|
let path = entry.path();
|
|
let Some(filename) = path.file_name() else {
|
|
continue;
|
|
};
|
|
|
|
fs::copy(&path, rootfs_dir.join("bin").join(filename))?;
|
|
}
|
|
}
|
|
|
|
// TODO this is a temporary hack
|
|
fs::create_dir_all(rootfs_dir.join("lib"))?;
|
|
// TODO other architectures
|
|
util::copy_file(
|
|
env.workspace_root.join(format!(
|
|
"userspace/dynload-program/target/{}-unknown-yggdrasil/{}/dynload-program",
|
|
env.arch.name(),
|
|
env.profile.name()
|
|
)),
|
|
rootfs_dir.join("dynload-program"),
|
|
)?;
|
|
|
|
let libstd_so = env.workspace_root.join(format!(
|
|
"toolchain/build/host/stage1-std/{}-unknown-yggdrasil/release/libstd.so",
|
|
env.arch.name()
|
|
));
|
|
|
|
util::copy_file(libstd_so, rootfs_dir.join("lib/libstd.so"))?;
|
|
|
|
log::info!("Installing extras");
|
|
for (src, dst) in install_extra {
|
|
util::copy_file(src, rootfs_dir.join(dst))?;
|
|
}
|
|
|
|
util::copy_file(&env.kernel_symbol_file, rootfs_dir.join("kernel.sym"))?;
|
|
|
|
// Copy /etc
|
|
util::copy_dir_recursive(user_dir.join("etc"), rootfs_dir.join("etc"))?;
|
|
|
|
// Copy architecture-specific directories
|
|
let arch_dir = user_dir.join("arch").join(env.arch.name());
|
|
let arch_rc_d = arch_dir.join("rc.d");
|
|
let arch_inittab = arch_dir.join("inittab");
|
|
|
|
if arch_rc_d.exists() {
|
|
util::copy_dir_recursive(arch_rc_d, rootfs_dir.join("etc/rc.d"))?;
|
|
}
|
|
if arch_inittab.exists() {
|
|
util::copy_file(arch_inittab, rootfs_dir.join("etc/inittab"))?;
|
|
}
|
|
|
|
Ok(())
|
|
}
|
|
|
|
fn pack_initrd<P: AsRef<Path>>(env: &BuildEnv, rootfs_dir: P) -> Result<InitrdGenerated, Error> {
|
|
let initrd_tar = env.userspace_output_dir.join("initrd.tar");
|
|
|
|
log::info!("Building initrd");
|
|
|
|
let tar = File::create(&initrd_tar)?;
|
|
let tar = BufWriter::new(tar);
|
|
let mut tar = tar::Builder::new(tar);
|
|
|
|
for entry in WalkDir::new(&rootfs_dir)
|
|
.follow_links(false)
|
|
.into_iter()
|
|
.filter(|e| e.as_ref().map(|e| !e.file_type().is_dir()).unwrap_or(false))
|
|
{
|
|
let entry = entry?;
|
|
let src_path = entry.path();
|
|
let rel_path = src_path
|
|
.strip_prefix(&rootfs_dir)
|
|
.map_err(|_| Error::InvalidPath(src_path.into()))?;
|
|
|
|
if entry.file_type().is_file() {
|
|
let mut file = File::open(entry.path())?;
|
|
tar.append_file(rel_path, &mut file)?;
|
|
} else if entry.file_type().is_symlink() {
|
|
let target = fs::read_link(entry.path())?;
|
|
let mut header = tar::Header::new_ustar();
|
|
header.set_entry_type(tar::EntryType::symlink());
|
|
header.set_mode(0o755);
|
|
tar.append_link(&mut header, rel_path, target)?;
|
|
} else {
|
|
todo!()
|
|
}
|
|
}
|
|
|
|
Ok(InitrdGenerated(initrd_tar))
|
|
}
|
|
|
|
pub fn build_initrd(
|
|
env: &BuildEnv,
|
|
mut install_extra: Vec<(PathBuf, PathBuf)>,
|
|
check: AllOk,
|
|
) -> Result<InitrdGenerated, Error> {
|
|
let rootfs_dir = env.userspace_output_dir.join("rootfs");
|
|
|
|
build_userspace(env, &mut install_extra, check)?;
|
|
|
|
build_rootfs(
|
|
env,
|
|
install_extra,
|
|
&env.userspace_output_dir,
|
|
&rootfs_dir,
|
|
check,
|
|
)?;
|
|
pack_initrd(env, rootfs_dir)
|
|
}
|