mirror of
https://github.com/Start9Labs/start-os.git
synced 2026-03-26 02:11:53 +00:00
Bugfix/disable uasp (#878)
* usbstoraged * set quirks on demand * remove reference to usbstoraged.service * comments * use sysfs instead of modprobe and address comments * fix ro fs and missing comma * Apply suggestions from code review * don't recurse overlayroot * sleep before reconnect * reset twice * sync between writes * fix build * fix build * adds drive to storage quirk whitelist * long sleep * another thing to try * fix: Ensure that the changes take effect Co-authored-by: Keagan McClelland <keagan.mcclelland@gmail.com> Co-authored-by: Justin Miller <dragondef@gmail.com>
This commit is contained in:
@@ -14,8 +14,11 @@ use crate::util::{display_serializable, IoFormat, Version};
|
||||
use crate::Error;
|
||||
|
||||
pub mod main;
|
||||
pub mod quirks;
|
||||
pub mod util;
|
||||
|
||||
pub const BOOT_RW_PATH: &'static str = "/media/boot-rw";
|
||||
|
||||
#[command(subcommands(list, backup_info))]
|
||||
pub fn disk() -> Result<(), Error> {
|
||||
Ok(())
|
||||
|
||||
155
appmgr/src/disk/quirks.rs
Normal file
155
appmgr/src/disk/quirks.rs
Normal file
@@ -0,0 +1,155 @@
|
||||
use std::num::ParseIntError;
|
||||
use std::path::Path;
|
||||
use std::time::Duration;
|
||||
|
||||
use color_eyre::eyre::eyre;
|
||||
use tokio::io::AsyncWriteExt;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::BOOT_RW_PATH;
|
||||
use crate::util::AtomicFile;
|
||||
use crate::Error;
|
||||
|
||||
pub const QUIRK_PATH: &'static str = "/sys/module/usb_storage/parameters/quirks";
|
||||
|
||||
pub const WHITELIST: [(VendorId, ProductId); 4] = [
|
||||
(VendorId(0x1d6b), ProductId(0x0002)), // root hub usb2
|
||||
(VendorId(0x1d6b), ProductId(0x0003)), // root hub usb3
|
||||
(VendorId(0x2109), ProductId(0x3431)),
|
||||
(VendorId(0x1058), ProductId(0x262f)), // western digital black HDD
|
||||
];
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct VendorId(u16);
|
||||
impl std::str::FromStr for VendorId {
|
||||
type Err = ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
u16::from_str_radix(s.trim(), 16).map(VendorId)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for VendorId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:04x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Default, PartialEq, Eq)]
|
||||
pub struct ProductId(u16);
|
||||
impl std::str::FromStr for ProductId {
|
||||
type Err = ParseIntError;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
u16::from_str_radix(s.trim(), 16).map(ProductId)
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for ProductId {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "{:04x}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Quirks(Vec<(VendorId, ProductId)>);
|
||||
impl Quirks {
|
||||
pub fn add(&mut self, vendor: VendorId, product: ProductId) {
|
||||
self.0.push((vendor, product));
|
||||
}
|
||||
pub fn contains(&self, vendor: VendorId, product: ProductId) -> bool {
|
||||
self.0.contains(&(vendor, product))
|
||||
}
|
||||
}
|
||||
impl std::fmt::Display for Quirks {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let mut comma = false;
|
||||
for (vendor, product) in &self.0 {
|
||||
if comma {
|
||||
write!(f, ",")?;
|
||||
} else {
|
||||
comma = true;
|
||||
}
|
||||
write!(f, "{}:{}:u", vendor, product)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
impl std::str::FromStr for Quirks {
|
||||
type Err = Error;
|
||||
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
||||
let s = s.trim();
|
||||
let mut quirks = Vec::new();
|
||||
for item in s.split(",") {
|
||||
if let [vendor, product, "u"] = item.splitn(3, ":").collect::<Vec<_>>().as_slice() {
|
||||
quirks.push((vendor.parse()?, product.parse()?));
|
||||
} else {
|
||||
return Err(Error::new(
|
||||
eyre!("Invalid quirk: `{}`", item),
|
||||
crate::ErrorKind::DiskManagement,
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(Quirks(quirks))
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn update_quirks(quirks: &mut Quirks) -> Result<(), Error> {
|
||||
let mut usb_devices = tokio::fs::read_dir("/sys/bus/usb/devices/").await?;
|
||||
while let Some(usb_device) = usb_devices.next_entry().await? {
|
||||
if tokio::fs::metadata(usb_device.path().join("idVendor"))
|
||||
.await
|
||||
.is_err()
|
||||
{
|
||||
continue;
|
||||
}
|
||||
let vendor = tokio::fs::read_to_string(usb_device.path().join("idVendor"))
|
||||
.await?
|
||||
.parse()?;
|
||||
let product = tokio::fs::read_to_string(usb_device.path().join("idProduct"))
|
||||
.await?
|
||||
.parse()?;
|
||||
if WHITELIST.contains(&(vendor, product)) || quirks.contains(vendor, product) {
|
||||
continue;
|
||||
}
|
||||
quirks.add(vendor, product);
|
||||
tokio::fs::write(QUIRK_PATH, quirks.to_string()).await?;
|
||||
|
||||
reconnect_usb(usb_device.path()).await?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(usb_device_path))]
|
||||
pub async fn reconnect_usb(usb_device_path: impl AsRef<Path>) -> Result<(), Error> {
|
||||
let authorized_path = usb_device_path.as_ref().join("authorized");
|
||||
let mut authorized_file = tokio::fs::File::create(&authorized_path).await?;
|
||||
authorized_file.write_all(b"0").await?;
|
||||
authorized_file.sync_all().await?;
|
||||
drop(authorized_file);
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
let mut authorized_file = tokio::fs::File::create(&authorized_path).await?;
|
||||
authorized_file.write_all(b"1").await?;
|
||||
authorized_file.sync_all().await?;
|
||||
tokio::time::sleep(Duration::from_secs(1)).await;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn fetch_quirks() -> Result<Quirks, Error> {
|
||||
Ok(tokio::fs::read_to_string(QUIRK_PATH).await?.parse()?)
|
||||
}
|
||||
|
||||
#[instrument]
|
||||
pub async fn save_quirks(quirks: &Quirks) -> Result<(), Error> {
|
||||
let orig_path = Path::new(BOOT_RW_PATH).join("cmdline.txt.orig");
|
||||
let target_path = Path::new(BOOT_RW_PATH).join("cmdline.txt");
|
||||
if tokio::fs::metadata(&orig_path).await.is_err() {
|
||||
tokio::fs::copy(&target_path, &orig_path).await?;
|
||||
}
|
||||
let cmdline = tokio::fs::read_to_string(&orig_path).await?;
|
||||
let mut target = AtomicFile::new(&target_path).await?;
|
||||
target
|
||||
.write_all(format!("usb-storage.quirks={} {}", quirks, cmdline).as_bytes())
|
||||
.await?;
|
||||
target.save().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
@@ -22,6 +22,7 @@ use tokio::process::Command;
|
||||
use tokio::sync::Mutex;
|
||||
use tracing::instrument;
|
||||
|
||||
use super::quirks::{fetch_quirks, save_quirks, update_quirks};
|
||||
use super::BackupInfo;
|
||||
use crate::auth::check_password;
|
||||
use crate::middleware::encrypt::{decrypt_slice, encrypt_slice};
|
||||
@@ -206,6 +207,9 @@ pub async fn pvscan() -> Result<BTreeMap<PathBuf, Option<String>>, Error> {
|
||||
|
||||
#[instrument]
|
||||
pub async fn list() -> Result<Vec<DiskInfo>, Error> {
|
||||
let mut quirks = fetch_quirks().await?;
|
||||
update_quirks(&mut quirks).await?;
|
||||
save_quirks(&mut quirks).await?;
|
||||
let disk_guids = pvscan().await?;
|
||||
let disks = tokio_stream::wrappers::ReadDirStream::new(
|
||||
tokio::fs::read_dir(DISK_PATH)
|
||||
|
||||
3
build/fstab
Normal file
3
build/fstab
Normal file
@@ -0,0 +1,3 @@
|
||||
LABEL=green / ext4 discard,errors=remount-ro 0 1
|
||||
LABEL=system-boot /media/boot-rw vfat defaults 0 1
|
||||
/media/boot-rw /boot/firmware none defaults,bind,ro 0 0
|
||||
@@ -47,7 +47,7 @@ ControlPort 9051
|
||||
CookieAuthentication 1
|
||||
EOF
|
||||
|
||||
echo 'overlayroot="tmpfs"' > /etc/overlayroot.local.conf
|
||||
echo 'overlayroot="tmpfs":swap=1,recurse=0' > /etc/overlayroot.local.conf
|
||||
systemctl disable initialization.service
|
||||
sync
|
||||
reboot
|
||||
|
||||
@@ -21,8 +21,11 @@ sudo e2label ${OUTPUT_DEVICE}p4 blue
|
||||
mkdir -p /tmp/eos-mnt
|
||||
sudo mount ${OUTPUT_DEVICE}p1 /tmp/eos-mnt
|
||||
|
||||
sudo sed -i 's/^/usb-storage.quirks=152d:0562:u /g' /tmp/eos-mnt/cmdline.txt
|
||||
sudo sed -i 's/LABEL=writable/LABEL=green/g' /tmp/eos-mnt/cmdline.txt
|
||||
# create a copy of the cmdline *without* the quirk string, so that it can be easily amended
|
||||
sudo cp /tmp/eos-mnt/cmdline.txt /tmp/eos-mnt/cmdline.txt.orig
|
||||
sudo sed -i 's/^/usb-storage.quirks=152d:0562:u /g' /tmp/eos-mnt/cmdline.txt
|
||||
|
||||
cat /tmp/eos-mnt/config.txt | grep -v "dtoverlay=" | sudo tee /tmp/eos-mnt/config.txt.tmp
|
||||
echo "dtoverlay=pwm-2chan" | sudo tee -a /tmp/eos-mnt/config.txt.tmp
|
||||
sudo mv /tmp/eos-mnt/config.txt.tmp /tmp/eos-mnt/config.txt
|
||||
@@ -35,8 +38,8 @@ sudo umount /tmp/eos-mnt
|
||||
|
||||
sudo mount ${OUTPUT_DEVICE}p3 /tmp/eos-mnt
|
||||
|
||||
sudo sed -i 's/LABEL=writable/LABEL=green/g' /tmp/eos-mnt/etc/fstab
|
||||
sudo sed -i 's/LABEL=system-boot\(\s\+\S\+\s\+\S\+\s\+\)defaults/LABEL=system-boot\1defaults,ro/g' /tmp/eos-mnt/etc/fstab
|
||||
sudo mkdir /tmp/eos-mnt/media/boot-rw
|
||||
sudo cp build/fstab /tmp/eos-mnt/etc/fstab
|
||||
# Enter the appmgr directory, copy over the built EmbassyOS binaries and systemd services, edit the nginx config, then create the .ssh directory
|
||||
cd appmgr/
|
||||
|
||||
|
||||
Reference in New Issue
Block a user