Feature/efi (#2192)

* update makefile

* fix

* add efi support

* fix efi

* clean up

* add `make update` and `make update-overlay`

* more protections

* update package lock

* rename reflash to indicate it isn't real

* fix authcookie

* Update product.yaml
This commit is contained in:
Aiden McClelland
2023-03-09 00:10:37 -07:00
committed by GitHub
parent bbb9980941
commit c9fceafc16
27 changed files with 584 additions and 171 deletions

View File

@@ -18,15 +18,21 @@ pub mod util;
pub const BOOT_RW_PATH: &str = "/media/boot-rw";
pub const REPAIR_DISK_PATH: &str = "/media/embassy/config/repair-disk";
#[derive(Debug, Default, Deserialize, Serialize)]
#[derive(Clone, Debug, Default, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct OsPartitionInfo {
pub efi: Option<PathBuf>,
pub boot: PathBuf,
pub root: PathBuf,
}
impl OsPartitionInfo {
pub fn contains(&self, logicalname: impl AsRef<Path>) -> bool {
&*self.boot == logicalname.as_ref() || &*self.root == logicalname.as_ref()
self.efi
.as_ref()
.map(|p| p == logicalname.as_ref())
.unwrap_or(false)
|| &*self.boot == logicalname.as_ref()
|| &*self.root == logicalname.as_ref()
}
}

View File

@@ -0,0 +1,40 @@
use std::os::unix::ffi::OsStrExt;
use std::path::Path;
use async_trait::async_trait;
use digest::generic_array::GenericArray;
use digest::{Digest, OutputSizeUser};
use sha2::Sha256;
use super::{FileSystem, MountType, ReadOnly};
use crate::util::Invoke;
use crate::{Error, ResultExt};
pub struct EfiVarFs;
#[async_trait]
impl FileSystem for EfiVarFs {
async fn mount<P: AsRef<Path> + Send + Sync>(
&self,
mountpoint: P,
mount_type: MountType,
) -> Result<(), Error> {
tokio::fs::create_dir_all(mountpoint.as_ref()).await?;
let mut cmd = tokio::process::Command::new("mount");
cmd.arg("-t")
.arg("efivarfs")
.arg("efivarfs")
.arg(mountpoint.as_ref());
if mount_type == ReadOnly {
cmd.arg("-o").arg("ro");
}
cmd.invoke(crate::ErrorKind::Filesystem).await?;
Ok(())
}
async fn source_hash(
&self,
) -> Result<GenericArray<u8, <Sha256 as OutputSizeUser>::OutputSize>, Error> {
let mut sha = Sha256::new();
sha.update("EfiVarFs");
Ok(sha.finalize())
}
}

View File

@@ -11,6 +11,7 @@ pub mod bind;
pub mod block_dev;
pub mod cifs;
pub mod ecryptfs;
pub mod efivarfs;
pub mod httpdirfs;
pub mod label;

View File

@@ -3,6 +3,7 @@ use std::path::{Path, PathBuf};
use std::sync::{Arc, Weak};
use lazy_static::lazy_static;
use models::ResultExt;
use tokio::sync::Mutex;
use tracing::instrument;
@@ -36,9 +37,21 @@ impl MountGuard {
mounted: true,
})
}
pub async fn unmount(mut self) -> Result<(), Error> {
pub async fn unmount(mut self, delete_mountpoint: bool) -> Result<(), Error> {
if self.mounted {
unmount(&self.mountpoint).await?;
if delete_mountpoint {
match tokio::fs::remove_dir(&self.mountpoint).await {
Err(e) if e.raw_os_error() == Some(39) => Ok(()), // directory not empty
a => a,
}
.with_ctx(|_| {
(
crate::ErrorKind::Filesystem,
format!("rm {}", self.mountpoint.display()),
)
})?;
}
self.mounted = false;
}
Ok(())
@@ -60,7 +73,7 @@ impl Drop for MountGuard {
#[async_trait::async_trait]
impl GenericMountGuard for MountGuard {
async fn unmount(mut self) -> Result<(), Error> {
MountGuard::unmount(self).await
MountGuard::unmount(self, false).await
}
}
@@ -111,7 +124,7 @@ impl TmpMountGuard {
}
pub async fn unmount(self) -> Result<(), Error> {
if let Ok(guard) = Arc::try_unwrap(self.guard) {
guard.unmount().await?;
guard.unmount(true).await?;
}
Ok(())
}

View File

@@ -48,15 +48,5 @@ pub async fn unmount<P: AsRef<Path>>(mountpoint: P) -> Result<(), Error> {
.arg(mountpoint.as_ref())
.invoke(crate::ErrorKind::Filesystem)
.await?;
match tokio::fs::remove_dir(mountpoint.as_ref()).await {
Err(e) if e.raw_os_error() == Some(39) => Ok(()), // directory not empty
a => a,
}
.with_ctx(|_| {
(
crate::ErrorKind::Filesystem,
format!("rm {}", mountpoint.as_ref().display()),
)
})?;
Ok(())
}

View File

@@ -23,10 +23,18 @@ use crate::util::serde::IoFormat;
use crate::util::{Invoke, Version};
use crate::{Error, ResultExt as _};
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub enum PartitionTable {
Mbr,
Gpt,
}
#[derive(Clone, Debug, Deserialize, Serialize)]
#[serde(rename_all = "kebab-case")]
pub struct DiskInfo {
pub logicalname: PathBuf,
pub partition_table: Option<PartitionTable>,
pub vendor: Option<String>,
pub model: Option<String>,
pub partitions: Vec<PartitionInfo>,
@@ -61,6 +69,24 @@ lazy_static::lazy_static! {
static ref PARTITION_REGEX: Regex = Regex::new("-part[0-9]+$").unwrap();
}
#[instrument(skip(path))]
pub async fn get_partition_table<P: AsRef<Path>>(path: P) -> Result<Option<PartitionTable>, Error> {
Ok(String::from_utf8(
Command::new("fdisk")
.arg("-l")
.arg(path.as_ref())
.invoke(crate::ErrorKind::BlockDevice)
.await?,
)?
.lines()
.find_map(|l| l.strip_prefix("Disklabel type:"))
.and_then(|t| match t.trim() {
"dos" => Some(PartitionTable::Mbr),
"gpt" => Some(PartitionTable::Gpt),
_ => None,
}))
}
#[instrument(skip(path))]
pub async fn get_vendor<P: AsRef<Path>>(path: P) -> Result<Option<String>, Error> {
let vendor = tokio::fs::read_to_string(
@@ -328,6 +354,16 @@ pub async fn list(os: &OsPartitionInfo) -> Result<Vec<DiskInfo>, Error> {
}
async fn disk_info(disk: PathBuf) -> DiskInfo {
let partition_table = get_partition_table(&disk)
.await
.map_err(|e| {
tracing::warn!(
"Could not get partition table of {}: {}",
disk.display(),
e.source
)
})
.unwrap_or_default();
let vendor = get_vendor(&disk)
.await
.map_err(|e| tracing::warn!("Could not get vendor of {}: {}", disk.display(), e.source))
@@ -342,6 +378,7 @@ async fn disk_info(disk: PathBuf) -> DiskInfo {
.unwrap_or_default();
DiskInfo {
logicalname: disk,
partition_table,
vendor,
model,
partitions: Vec::new(),