diff --git a/agent/src/main.rs b/agent/src/main.rs index 4705440..7f0b2a1 100644 --- a/agent/src/main.rs +++ b/agent/src/main.rs @@ -908,6 +908,7 @@ fn zfs_get(dataset: &str, prop: &str) -> Result { Ok(l[0].to_string()) } +#[cfg_attr(not(target_os = "illumos"), expect(dead_code))] fn zfs_set(dataset: &str, prop: &str, value: &str) -> Result<()> { let out = Command::new("/sbin/zfs") .arg("set") diff --git a/factory/gimlet/Cargo.toml b/factory/gimlet/Cargo.toml index d06386d..3581ebf 100644 --- a/factory/gimlet/Cargo.toml +++ b/factory/gimlet/Cargo.toml @@ -14,7 +14,6 @@ buildomat-types = { path = "../../types" } anyhow = { workspace = true } chrono = { workspace = true } debug_parser = { workspace = true } -devinfo = { workspace = true } dropshot = { workspace = true } getopts = { workspace = true } hyper = { workspace = true } @@ -33,3 +32,6 @@ tokio = { workspace = true } toml = { workspace = true } usdt = { workspace = true } uuid = { workspace = true } + +[target.'cfg(target_os = "illumos")'.dependencies] +devinfo = { workspace = true } diff --git a/factory/gimlet/src/cleanup.rs b/factory/gimlet/src/cleanup.rs index 2919a57..a98ed65 100644 --- a/factory/gimlet/src/cleanup.rs +++ b/factory/gimlet/src/cleanup.rs @@ -11,8 +11,7 @@ use std::{ use anyhow::{anyhow, bail, Result}; use buildomat_common::*; -use crate::{disks, efi}; -use disks::Slot; +use crate::disks::{self, Slot}; #[derive(Debug)] struct Status { @@ -210,7 +209,10 @@ pub fn cleanup() -> Result<()> { Ok(()) } +#[cfg(target_os = "illumos")] fn prepare_m2() -> Result<()> { + use crate::efi; + let disks = disks::list_disks()?; let Some(d) = disks.get(&Slot::M2(0)) else { @@ -305,6 +307,11 @@ fn prepare_m2() -> Result<()> { Ok(()) } +#[cfg(not(target_os = "illumos"))] +fn prepare_m2() -> Result<()> { + bail!("only works on illumos systems"); +} + fn format_disks() -> Result<()> { /* * First, list the disks in the system. We expect there to be two M.2 SSDs diff --git a/factory/gimlet/src/main.rs b/factory/gimlet/src/main.rs index 6271e81..db0562b 100644 --- a/factory/gimlet/src/main.rs +++ b/factory/gimlet/src/main.rs @@ -30,6 +30,7 @@ mod cleanup; mod config; mod db; mod disks; +#[cfg(target_os = "illumos")] mod efi; mod factory; mod host; diff --git a/factory/propolis/src/main.rs b/factory/propolis/src/main.rs index 7e0cde2..3d0aa46 100644 --- a/factory/propolis/src/main.rs +++ b/factory/propolis/src/main.rs @@ -18,6 +18,7 @@ mod nocloud; mod propolis; mod serial; mod svc; +#[cfg(target_os = "illumos")] mod ucred; mod vm; mod zones; diff --git a/factory/propolis/src/serial.rs b/factory/propolis/src/serial.rs index c6eab11..6dfd565 100644 --- a/factory/propolis/src/serial.rs +++ b/factory/propolis/src/serial.rs @@ -10,6 +10,7 @@ use std::{ time::Duration, }; +#[cfg(target_os = "illumos")] use crate::ucred::PeerUCred; use crate::zones::*; use anyhow::{anyhow, bail, Result}; @@ -25,7 +26,7 @@ pub enum SerialData { pub struct SerialForZone { name: String, - zoneid: zoneid_t, + zoneid: ZoneId, rx: tokio::sync::mpsc::Receiver, shutdown: tokio::sync::watch::Sender, inner: Arc, @@ -42,6 +43,7 @@ impl SerialForZone { * Remove the zone from the active set and shut down any socket tasks. */ let mut zones = self.inner.zones.lock().unwrap(); + #[cfg_attr(not(target_os = "illumos"), expect(unused))] let removed = zones.remove(&self.zoneid).unwrap(); assert_eq!(removed.name, self.name); assert_eq!(removed.zoneid, self.zoneid); @@ -69,13 +71,13 @@ pub struct Serial(Arc); #[derive(Clone)] struct Zone { name: String, - zoneid: zoneid_t, + zoneid: ZoneId, tx: tokio::sync::mpsc::Sender, shutdown: tokio::sync::watch::Receiver, } pub struct Inner { - zones: Mutex>, + zones: Mutex>, } impl Serial { @@ -114,10 +116,15 @@ impl Serial { Ok(s0) } + #[cfg_attr(not(target_os = "illumos"), expect(unused))] async fn accept_task(&self, log: Logger, listen: UnixListener) -> ! { loop { - let (sock, zoneid) = match listen.accept().await { + let (sock, zoneid): (UnixStream, ZoneId) = match listen + .accept() + .await + { Ok((sock, _)) => { + #[cfg(target_os = "illumos")] match sock.peer_ucred() { Ok(uc) => { let Some(zoneid) = uc.zoneid() else { @@ -125,7 +132,7 @@ impl Serial { continue; }; - if zoneid == 0 { + if zoneid.0 == 0 { /* * We never want connections from the global * zone. @@ -142,6 +149,12 @@ impl Serial { } } + #[cfg(not(target_os = "illumos"))] + { + error!(log, "only works on illumos"); + continue; + } + /* * Then we need to determine if this is a zone that we * actually want to hear from or not. diff --git a/factory/propolis/src/ucred.rs b/factory/propolis/src/ucred.rs index a1c9c02..3b9caac 100644 --- a/factory/propolis/src/ucred.rs +++ b/factory/propolis/src/ucred.rs @@ -5,7 +5,9 @@ use std::os::fd::AsRawFd; use anyhow::{bail, Result}; -use libc::{getpeerucred, ucred_free, ucred_getzoneid, ucred_t, zoneid_t}; +use libc::{getpeerucred, ucred_free, ucred_getzoneid, ucred_t}; + +use crate::zones::ZoneId; pub trait PeerUCred: AsRawFd { fn peer_ucred(&self) -> Result { @@ -37,7 +39,7 @@ impl Drop for UCred { } impl UCred { - pub fn zoneid(&self) -> Option { + pub fn zoneid(&self) -> Option { let zoneid = unsafe { ucred_getzoneid(self.uc) }; if zoneid < 0 { None diff --git a/factory/propolis/src/zones.rs b/factory/propolis/src/zones.rs index 285a152..15c3a73 100644 --- a/factory/propolis/src/zones.rs +++ b/factory/propolis/src/zones.rs @@ -2,18 +2,40 @@ * Copyright 2024 Oxide Computer Company */ -use std::ffi::CString; - use anyhow::{bail, Result}; -pub use libc::zoneid_t; -#[link(name = "c")] -extern "C" { - fn getzoneidbyname(name: *const libc::c_char) -> zoneid_t; +#[cfg(target_os = "illumos")] +type ZoneIdInner = libc::zoneid_t; +/* + * "Infallible" is the stable equivalent of the never type (!). It can not be + * instantiated, ensuring that we never construct a ZoneId outside illumos. + */ +#[cfg(not(target_os = "illumos"))] +type ZoneIdInner = std::convert::Infallible; + +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +pub struct ZoneId(pub ZoneIdInner); + +impl std::fmt::Display for ZoneId { + #[cfg(target_os = "illumos")] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.0) + } + + #[cfg(not(target_os = "illumos"))] + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + f.write_str("ZoneId") + } } -pub fn zone_name_to_id(name: &str) -> Result> { - let cs = CString::new(name)?; +#[cfg(target_os = "illumos")] +pub fn zone_name_to_id(name: &str) -> Result> { + #[link(name = "c")] + extern "C" { + fn getzoneidbyname(name: *const libc::c_char) -> zoneid_t; + } + + let cs = std::ffi::CString::new(name)?; let id = unsafe { getzoneidbyname(cs.as_ptr()) }; if id < 0 { @@ -30,7 +52,12 @@ pub fn zone_name_to_id(name: &str) -> Result> { bail!("getzoneidbyname({name}): {e}"); } - Ok(Some(id)) + Ok(Some(ZoneId(id))) +} + +#[cfg(not(target_os = "illumos"))] +pub fn zone_name_to_id(_name: &str) -> Result> { + bail!("only works on illumos systems"); } pub fn zone_exists(name: &str) -> Result {