Compare commits
3 Commits
ea75e1d744
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
2b27b7b06e
|
|||
|
32e15b1106
|
|||
|
7640952bdc
|
@@ -12,3 +12,8 @@ quirks:
|
||||
# - another-dependency
|
||||
# parameters:
|
||||
# key: value
|
||||
|
||||
linux-riscv:
|
||||
deb:
|
||||
package_directory:
|
||||
- linux-main
|
||||
|
||||
@@ -207,11 +207,22 @@ impl UnshareDriver {
|
||||
cmd.arg("-w").arg(dir);
|
||||
}
|
||||
|
||||
cmd.arg("--").arg("bash").arg("-c").arg(format!(
|
||||
"mount -t proc proc /proc; mkdir /dev/pts; mount -t devpts devpts /dev/pts; touch /dev/ptmx; mount --bind /dev/pts/ptmx /dev/ptmx; {} {}",
|
||||
program,
|
||||
args.iter().map(|a| format!("\"{a}\"")).collect::<Vec<_>>().join(" ")
|
||||
));
|
||||
// Build the bash command: set up /dev/pts and run the program
|
||||
// /proc should already be bind-mounted from the host before entering the namespace
|
||||
let program_args = args
|
||||
.iter()
|
||||
.map(|a| format!("\"{a}\""))
|
||||
.collect::<Vec<_>>()
|
||||
.join(" ");
|
||||
|
||||
cmd.arg("--")
|
||||
.arg("bash")
|
||||
.arg("-c")
|
||||
.arg(format!(
|
||||
"mkdir -p /dev/pts; mount -t devpts devpts /dev/pts 2>/dev/null || true; touch /dev/ptmx; mount --bind /dev/pts/ptmx /dev/ptmx 2>/dev/null || true; {} {}",
|
||||
program,
|
||||
program_args
|
||||
));
|
||||
|
||||
cmd
|
||||
}
|
||||
|
||||
@@ -134,7 +134,12 @@ impl EphemeralContextGuard {
|
||||
|
||||
// Create device nodes in the chroot
|
||||
log::debug!("Creating device nodes in chroot...");
|
||||
Self::create_device_nodes(chroot_path, ctx_for_devices)?;
|
||||
Self::create_device_nodes(chroot_path, ctx_for_devices.clone())?;
|
||||
|
||||
// Bind mount /proc from host into chroot (before entering unshare namespace)
|
||||
// This allows /proc to work in containers where mounting inside unshare fails
|
||||
log::debug!("Bind-mounting /proc into chroot...");
|
||||
Self::bind_mount_proc(chroot_path, ctx_for_devices)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -286,6 +291,43 @@ impl EphemeralContextGuard {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Bind mount /proc from host into the chroot
|
||||
/// This is done before entering the unshare namespace, so it works in containers
|
||||
fn bind_mount_proc(
|
||||
chroot_path: &Path,
|
||||
ctx: Arc<context::Context>,
|
||||
) -> Result<(), Box<dyn Error>> {
|
||||
let proc_path = chroot_path.join("proc");
|
||||
|
||||
// Ensure /proc directory exists in chroot
|
||||
fs::create_dir_all(&proc_path)?;
|
||||
|
||||
// Check if we're running as root
|
||||
let is_root = crate::utils::root::is_root()?;
|
||||
|
||||
// Bind mount host's /proc into chroot (with sudo if not root)
|
||||
let mut cmd = ctx.command(if is_root { "mount" } else { "sudo" });
|
||||
if !is_root {
|
||||
cmd.arg("mount");
|
||||
}
|
||||
let status = cmd
|
||||
.arg("--bind")
|
||||
.arg("/proc")
|
||||
.arg(proc_path.to_string_lossy().to_string())
|
||||
.status()?;
|
||||
|
||||
if !status.success() {
|
||||
log::warn!(
|
||||
"Could not bind-mount /proc into chroot at {}. Some packages may not install correctly.",
|
||||
proc_path.display()
|
||||
);
|
||||
} else {
|
||||
log::debug!("Bind-mounted /proc into chroot at {}", proc_path.display());
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Mark the build as successful, which will trigger chroot cleanup on drop
|
||||
pub fn mark_build_successful(&mut self) {
|
||||
self.build_succeeded = true;
|
||||
@@ -310,6 +352,18 @@ impl Drop for EphemeralContextGuard {
|
||||
// Check if we're running as root to avoid unnecessary sudo
|
||||
let is_root = crate::utils::root::is_root().unwrap_or(false);
|
||||
|
||||
// Unmount /proc from chroot before removing (ignore errors)
|
||||
let proc_path = self.chroot_path.join("proc");
|
||||
let _ = if is_root {
|
||||
self.base_ctx.command("umount").arg(&proc_path).status()
|
||||
} else {
|
||||
self.base_ctx
|
||||
.command("sudo")
|
||||
.arg("umount")
|
||||
.arg(&proc_path)
|
||||
.status()
|
||||
};
|
||||
|
||||
let result = if is_root {
|
||||
self.base_ctx
|
||||
.command("rm")
|
||||
|
||||
@@ -142,12 +142,26 @@ pub async fn build_binary_package(
|
||||
/// Find the current package directory by trying both patterns:
|
||||
/// - package/package
|
||||
/// - package/package-origversion
|
||||
/// - custom directories from quirks configuration
|
||||
pub(crate) fn find_package_directory(
|
||||
parent_dir: &Path,
|
||||
package: &str,
|
||||
version: &str,
|
||||
ctx: &context::Context,
|
||||
) -> Result<PathBuf, Box<dyn Error>> {
|
||||
// Check quirks first for custom package directories
|
||||
let custom_dirs = crate::quirks::get_package_directories(package);
|
||||
for custom_dir in custom_dirs {
|
||||
let package_dir = parent_dir.join(&custom_dir);
|
||||
if ctx.exists(&package_dir)? && ctx.exists(&package_dir.join("debian"))? {
|
||||
log::debug!(
|
||||
"Found package directory via quirks: {}",
|
||||
package_dir.display()
|
||||
);
|
||||
return Ok(package_dir);
|
||||
}
|
||||
}
|
||||
|
||||
// Try package/package pattern first
|
||||
let package_dir = parent_dir.join(package).join(package);
|
||||
if ctx.exists(&package_dir)? && ctx.exists(&package_dir.join("debian"))? {
|
||||
@@ -344,6 +358,10 @@ mod tests {
|
||||
/// It is important to ensure that pkh can cross-compile linux-riscv, as
|
||||
/// for risc-v hardware is still rare and cross-compilation is necessary
|
||||
/// to debug and test
|
||||
/// NOTE: Ideally, we want to run this in CI, but it takes more than 1h
|
||||
/// to fully build the linux-riscv package on an amd64 builder, which is too
|
||||
/// much time
|
||||
#[ignore]
|
||||
#[tokio::test]
|
||||
#[test_log::test]
|
||||
#[cfg(target_arch = "x86_64")]
|
||||
|
||||
@@ -17,6 +17,12 @@ pub struct OperationQuirks {
|
||||
/// Additional parameters for the operation
|
||||
#[serde(default)]
|
||||
pub parameters: HashMap<String, serde_yaml::Value>,
|
||||
|
||||
/// Custom package directories to try when looking for the package source
|
||||
/// This is useful for packages that don't follow the standard naming conventions
|
||||
/// like linux packages that use directories like "linux-main" or other custom names
|
||||
#[serde(default)]
|
||||
pub package_directory: Vec<String>,
|
||||
}
|
||||
|
||||
/// Quirks for a specific package
|
||||
@@ -75,3 +81,31 @@ pub fn get_deb_extra_dependencies(package: &str) -> Vec<String> {
|
||||
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
/// Get package directories from quirks configuration
|
||||
///
|
||||
/// This function returns the list of custom package directories to try
|
||||
/// when looking for the package source directory.
|
||||
///
|
||||
/// # Arguments
|
||||
/// * `package` - The package name
|
||||
///
|
||||
/// # Returns
|
||||
/// * `Vec<String>` - List of package directories to try, or empty vector if none
|
||||
pub fn get_package_directories(package: &str) -> Vec<String> {
|
||||
if let Some(quirks) = get_package_quirks(&QUIRKS_DATA, package) {
|
||||
// Check deb quirks first, then pull quirks
|
||||
if let Some(deb_quirks) = &quirks.deb
|
||||
&& !deb_quirks.package_directory.is_empty()
|
||||
{
|
||||
return deb_quirks.package_directory.clone();
|
||||
}
|
||||
if let Some(pull_quirks) = &quirks.pull
|
||||
&& !pull_quirks.package_directory.is_empty()
|
||||
{
|
||||
return pull_quirks.package_directory.clone();
|
||||
}
|
||||
}
|
||||
|
||||
Vec::new()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user