Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 9 additions & 3 deletions updatehub/src/object/installer/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
use super::{Context, Error, Result};
use crate::{
object::{Info, Installer},
utils::{self, definitions::TargetTypeExt, log::LogContent},
utils::{
self,
definitions::{Access, TargetTypeExt},
log::LogContent,
},
};
use pkg_schema::{definitions, objects};
use slog_scope::info;
Expand All @@ -20,8 +24,10 @@ impl Installer for objects::Copy {
async fn check_requirements(&self, _: &Context) -> Result<()> {
info!("'copy' handle checking requirements");

if let definitions::TargetType::Device(_) =
self.target_type.valid().log_error_msg("device failed vaidation")?
if let definitions::TargetType::Device(_) = self
.target_type
.valid(Access::for_format(self.target_format.should_format))
.log_error_msg("device failed vaidation")?
{
utils::fs::ensure_disk_space(
&self.target_type.get_target()?,
Expand Down
7 changes: 5 additions & 2 deletions updatehub/src/object/installer/flash.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@
use super::{Context, Error, Result};
use crate::{
object::{Info, Installer},
utils::{self, definitions::TargetTypeExt},
utils::{
self,
definitions::{Access, TargetTypeExt},
},
};

use pkg_schema::{definitions, objects};
Expand All @@ -21,7 +24,7 @@ impl Installer for objects::Flash {

match self.target {
definitions::TargetType::Device(_) | definitions::TargetType::MTDName(_) => {
self.target.valid()?;
self.target.valid(Access::Exclusive)?;
utils::fs::ensure_disk_space(
&self.target.get_target()?,
self.required_install_size(),
Expand Down
23 changes: 19 additions & 4 deletions updatehub/src/object/installer/imxkobs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,26 @@ use pkg_schema::objects;
use slog_scope::info;
use std::{fmt::Write as _, path::PathBuf};

/// Device `kobs-ng` writes to when the object does not name one.
const DEFAULT_CHIP_0_DEVICE_PATH: &str = "/dev/mtd0";

/// Device `kobs-ng` writes the bootstream to, which it falls back to on its own
/// when the object names none.
fn chip_0_path(obj: &objects::Imxkobs) -> PathBuf {
obj.chip_0_device_path.clone().unwrap_or_else(|| PathBuf::from(DEFAULT_CHIP_0_DEVICE_PATH))
}

#[async_trait::async_trait(?Send)]
impl Installer for objects::Imxkobs {
async fn check_requirements(&self, _: &Context) -> Result<()> {
info!("'imxkobs' handle checking requirements");
utils::fs::is_executable_in_path("kobs-ng").log_error_msg("kobs-ng not in PATH")?;

for chip in [Some(chip_0_path(self)), self.chip_1_device_path.clone()].into_iter().flatten()
{
utils::fs::ensure_not_mounted(&chip).log_error_msg("target device is in use")?;
}

Ok(())
}

Expand All @@ -25,8 +39,7 @@ impl Installer for objects::Imxkobs {

let should_skip_install =
super::should_skip_install(&self.install_if_different, &self.sha256sum, async {
let path =
self.chip_0_device_path.clone().unwrap_or_else(|| PathBuf::from("/dev/mtd0"));
let path = chip_0_path(self);
let f = path.file_name().ok_or(Error::InvalidPath)?;
let mut file_name = f.to_os_string();
file_name.push("ro");
Expand Down Expand Up @@ -85,8 +98,10 @@ mod tests {
install_if_different: None,
padding_1k: true,
search_exponent: 2,
chip_0_device_path: Some(PathBuf::from("/dev/sda1")),
chip_1_device_path: Some(PathBuf::from("/dev/sda2")),
// Inexistent on purpose, a real device could be in use on the host
// running the tests and the requirements check would reject it.
chip_0_device_path: Some(PathBuf::from("/dev/updatehub-chip-0")),
chip_1_device_path: Some(PathBuf::from("/dev/updatehub-chip-1")),
}
}

Expand Down
2 changes: 1 addition & 1 deletion updatehub/src/object/installer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,7 @@ where
}

#[cfg(test)]
mod tests {
pub(crate) mod tests {
use super::*;
use lazy_static::lazy_static;
use std::{
Expand Down
8 changes: 6 additions & 2 deletions updatehub/src/object/installer/raw.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
use super::{Context, Error, Result};
use crate::{
object::{Info, Installer},
utils::{self, definitions::TargetTypeExt, log::LogContent},
utils::{
self,
definitions::{Access, TargetTypeExt},
log::LogContent,
},
};
use pkg_schema::{definitions, objects};
use slog_scope::info;
Expand All @@ -22,7 +26,7 @@ impl Installer for objects::Raw {
info!("'raw' handle checking requirements");

if let definitions::TargetType::Device(dev) =
self.target_type.valid().log_error_msg("device failed vaidation")?
self.target_type.valid(Access::Exclusive).log_error_msg("device failed vaidation")?
{
utils::fs::ensure_disk_space(dev, self.required_install_size())
.log_error_msg("not enough disk space")?;
Expand Down
9 changes: 7 additions & 2 deletions updatehub/src/object/installer/raw_delta.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,12 @@
use super::{Context, Error, Result};
use crate::{
object::Installer,
utils::{self, definitions::TargetTypeExt, delta, log::LogContent},
utils::{
self,
definitions::{Access, TargetTypeExt},
delta,
log::LogContent,
},
};

use pkg_schema::{definitions, objects};
Expand All @@ -17,7 +22,7 @@ impl Installer for objects::RawDelta {
info!("'raw-delta' handle checking requirements");

if let definitions::TargetType::Device(dev) =
self.target.valid().log_error_msg("device failed validation")?
self.target.valid(Access::Exclusive).log_error_msg("device failed validation")?
{
let seed = get_seed_path(self, context);
let required_size = delta::get_required_size(&seed, dev)
Expand Down
10 changes: 8 additions & 2 deletions updatehub/src/object/installer/tarball.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
use super::{Context, Result};
use crate::{
object::{Info, Installer},
utils::{self, definitions::TargetTypeExt, log::LogContent},
utils::{
self,
definitions::{Access, TargetTypeExt},
log::LogContent,
},
};
use pkg_schema::{definitions, objects};
use slog_scope::info;
Expand All @@ -24,7 +28,9 @@ impl Installer for objects::Tarball {
self.required_install_size(),
)
.log_error_msg("not enough disk space")?;
self.target.valid().log_error_msg("device failed validation")?;
self.target
.valid(Access::for_format(self.target_format.should_format))
.log_error_msg("device failed validation")?;
Ok(())
}
}
Expand Down
8 changes: 6 additions & 2 deletions updatehub/src/object/installer/ubifs.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,11 @@
use super::{Context, Error, Result};
use crate::{
object::{Info, Installer},
utils::{self, definitions::TargetTypeExt, log::LogContent},
utils::{
self,
definitions::{Access, TargetTypeExt},
log::LogContent,
},
};
use pkg_schema::{definitions, objects};
use slog_scope::info;
Expand All @@ -20,7 +24,7 @@ impl Installer for objects::Ubifs {
utils::fs::is_executable_in_path("ubinfo").log_error_msg("ubinfo not on PATH")?;

if let definitions::TargetType::UBIVolume(_) =
self.target.valid().log_error_msg("device failed validation")?
self.target.valid(Access::Exclusive).log_error_msg("device failed validation")?
{
utils::fs::ensure_disk_space(&self.target.get_target()?, self.required_install_size())
.log_error_msg("not enough disk space")?;
Expand Down
31 changes: 27 additions & 4 deletions updatehub/src/utils/definitions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,44 @@
// SPDX-License-Identifier: Apache-2.0

use super::{Error, Result};
use crate::utils::mtd;
use crate::utils::{fs, mtd};
use pkg_schema::definitions::{
TargetType,
target_permissions::{Gid, Uid},
};
use std::path::PathBuf;

/// How a handler reaches its target, which decides whether a filesystem the
/// system already has mounted on it is acceptable.
pub(crate) enum Access {
/// The handler writes the device itself, so nothing else may be using it.
Exclusive,
/// The handler writes through a filesystem it mounts, which is safe to do
/// even on a device already mounted elsewhere.
ThroughFilesystem,
}

impl Access {
/// Formatting rewrites the whole filesystem, so it takes the device for
/// itself even on a handler otherwise going through a mount.
pub(crate) fn for_format(should_format: bool) -> Access {
if should_format { Access::Exclusive } else { Access::ThroughFilesystem }
}
}

/// Utility functions for [TargetType](pkg_schema::definitions::TargetType)
pub(crate) trait TargetTypeExt {
/// Checks whether the device is valid to start installation, i.e.,
/// device exists, use have write permission.
fn valid(&self) -> Result<&Self>;
/// device exists, use have write permission, and is free of mounted
/// filesystems when the handler asks for [Access::Exclusive].
fn valid(&self, access: Access) -> Result<&Self>;

/// Gets device's path for mounting.
fn get_target(&self) -> Result<PathBuf>;
}

impl TargetTypeExt for TargetType {
fn valid(&self) -> Result<&Self> {
fn valid(&self, access: Access) -> Result<&Self> {
let device = self.get_target()?;

if !device.exists() {
Expand All @@ -32,6 +51,10 @@ impl TargetTypeExt for TargetType {
return Err(Error::MissingWritePermission(device));
}

if let Access::Exclusive = access {
fs::ensure_not_mounted(&device)?;
}

Ok(self)
}

Expand Down
Loading