mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
add firmware updater (#2455)
This commit is contained in:
@@ -11,6 +11,7 @@ use crate::context::{DiagnosticContext, InstallContext, SetupContext};
|
|||||||
use crate::disk::fsck::RepairStrategy;
|
use crate::disk::fsck::RepairStrategy;
|
||||||
use crate::disk::main::DEFAULT_PASSWORD;
|
use crate::disk::main::DEFAULT_PASSWORD;
|
||||||
use crate::disk::REPAIR_DISK_PATH;
|
use crate::disk::REPAIR_DISK_PATH;
|
||||||
|
use crate::firmware::update_firmware;
|
||||||
use crate::init::STANDBY_MODE_PATH;
|
use crate::init::STANDBY_MODE_PATH;
|
||||||
use crate::net::web_server::WebServer;
|
use crate::net::web_server::WebServer;
|
||||||
use crate::shutdown::Shutdown;
|
use crate::shutdown::Shutdown;
|
||||||
@@ -19,7 +20,14 @@ use crate::util::Invoke;
|
|||||||
use crate::{Error, ErrorKind, ResultExt, OS_ARCH};
|
use crate::{Error, ErrorKind, ResultExt, OS_ARCH};
|
||||||
|
|
||||||
#[instrument(skip_all)]
|
#[instrument(skip_all)]
|
||||||
async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<(), Error> {
|
async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error> {
|
||||||
|
if update_firmware().await?.0 {
|
||||||
|
return Ok(Some(Shutdown {
|
||||||
|
export_args: None,
|
||||||
|
restart: true,
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
Command::new("ln")
|
Command::new("ln")
|
||||||
.arg("-sf")
|
.arg("-sf")
|
||||||
.arg("/usr/lib/embassy/scripts/fake-apt")
|
.arg("/usr/lib/embassy/scripts/fake-apt")
|
||||||
@@ -146,7 +154,7 @@ async fn setup_or_init(cfg_path: Option<PathBuf>) -> Result<(), Error> {
|
|||||||
crate::init::init(&cfg).await?;
|
crate::init::init(&cfg).await?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(None)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn run_script_if_exists<P: AsRef<Path>>(path: P) {
|
async fn run_script_if_exists<P: AsRef<Path>>(path: P) {
|
||||||
@@ -180,7 +188,8 @@ async fn inner_main(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error
|
|||||||
|
|
||||||
run_script_if_exists("/media/embassy/config/preinit.sh").await;
|
run_script_if_exists("/media/embassy/config/preinit.sh").await;
|
||||||
|
|
||||||
let res = if let Err(e) = setup_or_init(cfg_path.clone()).await {
|
let res = match setup_or_init(cfg_path.clone()).await {
|
||||||
|
Err(e) => {
|
||||||
async move {
|
async move {
|
||||||
tracing::error!("{}", e.source);
|
tracing::error!("{}", e.source);
|
||||||
tracing::debug!("{}", e.source);
|
tracing::debug!("{}", e.source);
|
||||||
@@ -218,8 +227,8 @@ async fn inner_main(cfg_path: Option<PathBuf>) -> Result<Option<Shutdown>, Error
|
|||||||
Ok(shutdown)
|
Ok(shutdown)
|
||||||
}
|
}
|
||||||
.await
|
.await
|
||||||
} else {
|
}
|
||||||
Ok(None)
|
Ok(s) => Ok(s),
|
||||||
};
|
};
|
||||||
|
|
||||||
run_script_if_exists("/media/embassy/config/postinit.sh").await;
|
run_script_if_exists("/media/embassy/config/postinit.sh").await;
|
||||||
|
|||||||
@@ -41,8 +41,10 @@ pub fn exit(#[context] ctx: DiagnosticContext) -> Result<(), Error> {
|
|||||||
pub fn restart(#[context] ctx: DiagnosticContext) -> Result<(), Error> {
|
pub fn restart(#[context] ctx: DiagnosticContext) -> Result<(), Error> {
|
||||||
ctx.shutdown
|
ctx.shutdown
|
||||||
.send(Some(Shutdown {
|
.send(Some(Shutdown {
|
||||||
datadir: ctx.datadir.clone(),
|
export_args: ctx
|
||||||
disk_guid: ctx.disk_guid.clone(),
|
.disk_guid
|
||||||
|
.clone()
|
||||||
|
.map(|guid| (guid, ctx.datadir.clone())),
|
||||||
restart: true,
|
restart: true,
|
||||||
}))
|
}))
|
||||||
.expect("receiver dropped");
|
.expect("receiver dropped");
|
||||||
|
|||||||
82
backend/src/firmware.rs
Normal file
82
backend/src/firmware.rs
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
use std::path::Path;
|
||||||
|
use std::process::Stdio;
|
||||||
|
|
||||||
|
use async_compression::tokio::bufread::GzipDecoder;
|
||||||
|
use tokio::fs::File;
|
||||||
|
use tokio::io::{AsyncRead, AsyncWriteExt, BufReader};
|
||||||
|
use tokio::process::Command;
|
||||||
|
|
||||||
|
use crate::disk::fsck::RequiresReboot;
|
||||||
|
use crate::prelude::*;
|
||||||
|
use crate::util::Invoke;
|
||||||
|
|
||||||
|
pub async fn update_firmware() -> Result<RequiresReboot, Error> {
|
||||||
|
let product_name = String::from_utf8(
|
||||||
|
Command::new("dmidecode")
|
||||||
|
.arg("-s")
|
||||||
|
.arg("system-product-name")
|
||||||
|
.invoke(ErrorKind::Firmware)
|
||||||
|
.await?,
|
||||||
|
)?
|
||||||
|
.trim()
|
||||||
|
.to_owned();
|
||||||
|
if product_name.is_empty() {
|
||||||
|
return Ok(RequiresReboot(false));
|
||||||
|
}
|
||||||
|
let firmware_dir = Path::new("/usr/lib/embassy/firmware").join(&product_name);
|
||||||
|
if tokio::fs::metadata(&firmware_dir).await.is_ok() {
|
||||||
|
let current_firmware = String::from_utf8(
|
||||||
|
Command::new("dmidecode")
|
||||||
|
.arg("-s")
|
||||||
|
.arg("bios-version")
|
||||||
|
.invoke(ErrorKind::Firmware)
|
||||||
|
.await?,
|
||||||
|
)?
|
||||||
|
.trim()
|
||||||
|
.to_owned();
|
||||||
|
if tokio::fs::metadata(firmware_dir.join(format!("{current_firmware}.rom.gz")))
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
&& tokio::fs::metadata(firmware_dir.join(format!("{current_firmware}.rom")))
|
||||||
|
.await
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
|
let mut firmware_read_dir = tokio::fs::read_dir(&firmware_dir).await?;
|
||||||
|
while let Some(entry) = firmware_read_dir.next_entry().await? {
|
||||||
|
let filename = entry.file_name().to_string_lossy().into_owned();
|
||||||
|
let rdr: Option<Box<dyn AsyncRead + Unpin>> = if filename.ends_with(".rom.gz") {
|
||||||
|
Some(Box::new(GzipDecoder::new(BufReader::new(
|
||||||
|
File::open(entry.path()).await?,
|
||||||
|
))))
|
||||||
|
} else if filename.ends_with(".rom") {
|
||||||
|
Some(Box::new(File::open(entry.path()).await?))
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
};
|
||||||
|
if let Some(mut rdr) = rdr {
|
||||||
|
let mut flashrom = Command::new("flashrom")
|
||||||
|
.arg("-p")
|
||||||
|
.arg("internal")
|
||||||
|
.arg("-w-")
|
||||||
|
.stdin(Stdio::piped())
|
||||||
|
.spawn()?;
|
||||||
|
let mut rom_dest = flashrom.stdin.take().or_not_found("stdin")?;
|
||||||
|
tokio::io::copy(&mut rdr, &mut rom_dest).await?;
|
||||||
|
rom_dest.flush().await?;
|
||||||
|
rom_dest.shutdown().await?;
|
||||||
|
drop(rom_dest);
|
||||||
|
let o = flashrom.wait_with_output().await?;
|
||||||
|
if !o.status.success() {
|
||||||
|
return Err(Error::new(
|
||||||
|
eyre!("{}", std::str::from_utf8(&o.stderr)?),
|
||||||
|
ErrorKind::Firmware,
|
||||||
|
));
|
||||||
|
} else {
|
||||||
|
return Ok(RequiresReboot(true));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(RequiresReboot(false))
|
||||||
|
}
|
||||||
@@ -28,6 +28,7 @@ pub mod developer;
|
|||||||
pub mod diagnostic;
|
pub mod diagnostic;
|
||||||
pub mod disk;
|
pub mod disk;
|
||||||
pub mod error;
|
pub mod error;
|
||||||
|
pub mod firmware;
|
||||||
pub mod hostname;
|
pub mod hostname;
|
||||||
pub mod init;
|
pub mod init;
|
||||||
pub mod inspect;
|
pub mod inspect;
|
||||||
|
|||||||
@@ -13,8 +13,7 @@ use crate::{Error, OS_ARCH};
|
|||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Shutdown {
|
pub struct Shutdown {
|
||||||
pub datadir: PathBuf,
|
pub export_args: Option<(Arc<String>, PathBuf)>,
|
||||||
pub disk_guid: Option<Arc<String>>,
|
|
||||||
pub restart: bool,
|
pub restart: bool,
|
||||||
}
|
}
|
||||||
impl Shutdown {
|
impl Shutdown {
|
||||||
@@ -55,8 +54,8 @@ impl Shutdown {
|
|||||||
tracing::debug!("{:?}", e);
|
tracing::debug!("{:?}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if let Some(guid) = &self.disk_guid {
|
if let Some((guid, datadir)) = &self.export_args {
|
||||||
if let Err(e) = export(guid, &self.datadir).await {
|
if let Err(e) = export(guid, datadir).await {
|
||||||
tracing::error!("Error Exporting Volume Group: {}", e);
|
tracing::error!("Error Exporting Volume Group: {}", e);
|
||||||
tracing::debug!("{:?}", e);
|
tracing::debug!("{:?}", e);
|
||||||
}
|
}
|
||||||
@@ -93,8 +92,7 @@ impl Shutdown {
|
|||||||
pub async fn shutdown(#[context] ctx: RpcContext) -> Result<(), Error> {
|
pub async fn shutdown(#[context] ctx: RpcContext) -> Result<(), Error> {
|
||||||
ctx.shutdown
|
ctx.shutdown
|
||||||
.send(Some(Shutdown {
|
.send(Some(Shutdown {
|
||||||
datadir: ctx.datadir.clone(),
|
export_args: Some((ctx.disk_guid.clone(), ctx.datadir.clone())),
|
||||||
disk_guid: Some(ctx.disk_guid.clone()),
|
|
||||||
restart: false,
|
restart: false,
|
||||||
}))
|
}))
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
@@ -106,8 +104,7 @@ pub async fn shutdown(#[context] ctx: RpcContext) -> Result<(), Error> {
|
|||||||
pub async fn restart(#[context] ctx: RpcContext) -> Result<(), Error> {
|
pub async fn restart(#[context] ctx: RpcContext) -> Result<(), Error> {
|
||||||
ctx.shutdown
|
ctx.shutdown
|
||||||
.send(Some(Shutdown {
|
.send(Some(Shutdown {
|
||||||
datadir: ctx.datadir.clone(),
|
export_args: Some((ctx.disk_guid.clone(), ctx.datadir.clone())),
|
||||||
disk_guid: Some(ctx.disk_guid.clone()),
|
|
||||||
restart: true,
|
restart: true,
|
||||||
}))
|
}))
|
||||||
.map_err(|_| ())
|
.map_err(|_| ())
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ cifs-utils
|
|||||||
containerd.io
|
containerd.io
|
||||||
cryptsetup
|
cryptsetup
|
||||||
curl
|
curl
|
||||||
|
dmidecode
|
||||||
docker-ce
|
docker-ce
|
||||||
docker-ce-cli
|
docker-ce-cli
|
||||||
docker-compose-plugin
|
docker-compose-plugin
|
||||||
@@ -16,6 +17,7 @@ dosfstools
|
|||||||
e2fsprogs
|
e2fsprogs
|
||||||
ecryptfs-utils
|
ecryptfs-utils
|
||||||
exfatprogs
|
exfatprogs
|
||||||
|
flashrom
|
||||||
grub-common
|
grub-common
|
||||||
htop
|
htop
|
||||||
httpdirfs
|
httpdirfs
|
||||||
|
|||||||
BIN
build/lib/firmware/librem_mini_v2/PureBoot-Release-28.1.rom.gz
Normal file
BIN
build/lib/firmware/librem_mini_v2/PureBoot-Release-28.1.rom.gz
Normal file
Binary file not shown.
@@ -79,6 +79,7 @@ pub enum ErrorKind {
|
|||||||
Zram = 67,
|
Zram = 67,
|
||||||
Lshw = 68,
|
Lshw = 68,
|
||||||
CpuSettings = 69,
|
CpuSettings = 69,
|
||||||
|
Firmware = 70,
|
||||||
}
|
}
|
||||||
impl ErrorKind {
|
impl ErrorKind {
|
||||||
pub fn as_str(&self) -> &'static str {
|
pub fn as_str(&self) -> &'static str {
|
||||||
@@ -153,6 +154,7 @@ impl ErrorKind {
|
|||||||
Zram => "Zram Error",
|
Zram => "Zram Error",
|
||||||
Lshw => "LSHW Error",
|
Lshw => "LSHW Error",
|
||||||
CpuSettings => "CPU Settings Error",
|
CpuSettings => "CPU Settings Error",
|
||||||
|
Firmware => "Firmware Error",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user