diff --git a/src/cmdline.rs b/src/cmdline.rs index 932fc5d..89db17f 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only -use crate::{read_file, Result}; + use nix::mount::MsFlags; +use crate::{read_file, Result}; + pub struct CmdlineOptions { pub root: Option, pub rootfstype: Option, diff --git a/src/dmverity.rs b/src/dmverity.rs index 3690c7f..ad9fc98 100644 --- a/src/dmverity.rs +++ b/src/dmverity.rs @@ -1,15 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-only -use crate::cmdline::CmdlineOptions; -use crate::{read_file, Result}; + +use std::fs::OpenOptions; +use std::mem::size_of; +use std::os::fd::IntoRawFd; +use std::path::Path; + use getrandom::getrandom; use log::debug; use nix::ioctl_readwrite; use nix::libc::dev_t; use nix::sys::stat::minor; -use std::fs::OpenOptions; -use std::mem::size_of; -use std::os::fd::IntoRawFd; -use std::path::Path; + +use crate::cmdline::CmdlineOptions; +use crate::{read_file, Result}; const DM_VERSION_MAJOR: u32 = 4; diff --git a/src/main.rs b/src/main.rs index 2994db1..ee5e25e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,28 +1,31 @@ // SPDX-License-Identifier: GPL-2.0-only -use cmdline::{parse_cmdline, CmdlineOptions}; -#[cfg(feature = "dmverity")] -use dmverity::prepare_dmverity; -use log::{debug, Level, LevelFilter, Metadata, Record}; -use mount::{mount_move_special, mount_root, mount_special}; -#[cfg(feature = "reboot-on-failure")] -use nix::sys::reboot::{reboot, RebootMode}; -use nix::sys::termios::tcdrain; -use nix::unistd::{chdir, chroot, dup2, execv, unlink}; + use std::borrow::Borrow; use std::env; use std::env::current_exe; use std::ffi::CString; use std::fmt::Write as _; -use std::fs::{create_dir, read_to_string, File, OpenOptions}; +use std::fs::{File, OpenOptions}; use std::io; use std::io::Write as _; use std::os::fd::{AsFd, AsRawFd, RawFd}; use std::os::unix::ffi::OsStrExt; use std::panic::set_hook; + +use cmdline::{parse_cmdline, CmdlineOptions}; +#[cfg(feature = "dmverity")] +use dmverity::prepare_dmverity; +use log::{debug, Level, LevelFilter, Metadata, Record}; +use mount::{mount_move_special, mount_root, mount_special}; +#[cfg(feature = "reboot-on-failure")] +use nix::sys::reboot::{reboot, RebootMode}; +use nix::sys::termios::tcdrain; +use nix::unistd::{chdir, chroot, dup2, execv, unlink}; #[cfg(feature = "systemd")] use systemd::{mount_systemd, shutdown}; #[cfg(feature = "usb9pfs")] use usbg_9pfs::prepare_9pfs_gadget; +use util::read_file; mod cmdline; #[cfg(feature = "dmverity")] @@ -32,22 +35,10 @@ mod mount; mod systemd; #[cfg(feature = "usb9pfs")] mod usbg_9pfs; +mod util; type Result = std::result::Result>; -pub fn mkdir(dir: &str) -> Result<()> { - if let Err(e) = create_dir(dir) { - if e.kind() != io::ErrorKind::AlreadyExists { - return Err(format!("Failed to create {dir}: {e}",).into()); - } - } - Ok(()) -} - -fn read_file(filename: &str) -> std::result::Result { - read_to_string(filename).map_err(|e| format!("Failed to read {filename}: {e}")) -} - /* * Setup stdout/stderr. The kernel will create /dev/console in the * initramfs, so we can use that. diff --git a/src/mount.rs b/src/mount.rs index 8b20dd3..65a0caf 100644 --- a/src/mount.rs +++ b/src/mount.rs @@ -1,11 +1,15 @@ // SPDX-License-Identifier: GPL-2.0-only -use crate::cmdline::CmdlineOptions; -use crate::{mkdir, Result}; -use log::debug; -use nix::mount::{mount, MsFlags}; + use std::fs::remove_dir; use std::path::Path; +use log::debug; +use nix::mount::{mount, MsFlags}; + +use crate::cmdline::CmdlineOptions; +use crate::util::mkdir; +use crate::Result; + pub fn do_mount( src: Option<&str>, dst: &str, diff --git a/src/systemd.rs b/src/systemd.rs index 7866fd2..1a295f1 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -1,14 +1,18 @@ // SPDX-License-Identifier: GPL-2.0-only -use crate::cmdline::CmdlineOptions; -use crate::mount::do_mount; -use crate::{mkdir, Result}; -use nix::mount::{umount, MsFlags}; -use nix::sys::reboot::{reboot, RebootMode}; + use std::collections::BinaryHeap; use std::env; use std::fs::read_to_string; use std::path::Path; +use nix::mount::{umount, MsFlags}; +use nix::sys::reboot::{reboot, RebootMode}; + +use crate::cmdline::CmdlineOptions; +use crate::mount::do_mount; +use crate::util::mkdir; +use crate::Result; + pub fn mount_systemd(options: &mut CmdlineOptions) -> Result<()> { do_mount( Option::<&str>::None, diff --git a/src/usbg_9pfs.rs b/src/usbg_9pfs.rs index c108a43..b85c548 100644 --- a/src/usbg_9pfs.rs +++ b/src/usbg_9pfs.rs @@ -1,26 +1,35 @@ // SPDX-License-Identifier: GPL-2.0-only -use crate::cmdline::CmdlineOptions; -use crate::mount::mount_apivfs; -use crate::{mkdir, Result}; -use log::debug; -use std::fs::{read_dir, write}; -use std::os::unix::ffi::OsStrExt; + +use std::fs::read_dir; use std::os::unix::fs::symlink; -use std::{thread, time}; +use std::thread; +use std::time::Duration; -fn write_file>(path: &str, content: C) -> Result<()> { - write(path, content).map_err(|e| format!("Failed to write to {path}: {e}").into()) -} +use log::debug; -fn setup_9pfs_gadget(device: &String) -> Result<()> { +use crate::cmdline::CmdlineOptions; +use crate::mount::mount_apivfs; +use crate::util::{mkdir, write_file}; +use crate::Result; + +fn setup_9pfs_gadget(options: &mut CmdlineOptions) -> Result<()> { debug!("Initializing USB 9pfs gadget ..."); - let udc = read_dir("/sys/class/udc") - .map_err(|e| format!("Failed to list /sys/class/udc: {e}"))? - .next() - .ok_or("No UDC found to attach the 9pfs gadget".to_string())? - .map_err(|e| format!("Failed to inspect the first entry in /sys/class/udc: {e}"))? - .file_name(); + let udc = if let Some(device) = &options.root { + device.to_owned() + } else { + read_dir("/sys/class/udc") + .map_err(|e| format!("Failed to list /sys/class/udc: {e}"))? + .next() + .ok_or("No UDC found to attach the 9pfs gadget".to_string())? + .map_err(|e| format!("Failed to inspect the first entry in /sys/class/udc: {e}"))? + .file_name() + .into_string() + .map_err(|e| format!("invalid utf-8 in file name: {e:?}"))? + } + .as_bytes() + .escape_ascii() + .to_string(); mount_apivfs("/sys/kernel/config", "configfs")?; @@ -46,38 +55,30 @@ fn setup_9pfs_gadget(device: &String) -> Result<()> { mkdir("/sys/kernel/config/usb_gadget/9pfs/configs/c.1")?; mkdir("/sys/kernel/config/usb_gadget/9pfs/configs/c.1/strings/0x409")?; - let function = format!("/sys/kernel/config/usb_gadget/9pfs/functions/usb9pfs.{device}"); - let link = format!("/sys/kernel/config/usb_gadget/9pfs/configs/c.1/usb9pfs.{device}"); + let function = format!("/sys/kernel/config/usb_gadget/9pfs/functions/usb9pfs.{udc}"); + let link = format!("/sys/kernel/config/usb_gadget/9pfs/configs/c.1/usb9pfs.{udc}"); mkdir(&function)?; symlink(&function, &link)?; - debug!( - "Attaching 9pfs gatget to UDC {}", - udc.as_bytes().escape_ascii() - ); - write_file( - "/sys/kernel/config/usb_gadget/9pfs/UDC", - udc.as_encoded_bytes(), - )?; + debug!("Attaching 9pfs gatget to UDC {udc}",); + write_file("/sys/kernel/config/usb_gadget/9pfs/UDC", &udc)?; + + thread::sleep(Duration::from_secs(1)); + + options.root = Some(udc); - let d = time::Duration::new(1, 0); - thread::sleep(d); Ok(()) } -pub fn prepare_9pfs_gadget(options: &CmdlineOptions) -> Result { +pub fn prepare_9pfs_gadget(options: &mut CmdlineOptions) -> Result { if options.rootfstype.as_deref() == Some("9p") && options .rootflags .as_deref() .is_some_and(|flags| flags.contains("trans=usbg")) { - if let Some(root) = &options.root { - setup_9pfs_gadget(root)?; - Ok(true) - } else { - Err("Missing root= for 9p!".into()) - } + setup_9pfs_gadget(options)?; + Ok(true) } else { Ok(false) } diff --git a/src/util.rs b/src/util.rs new file mode 100644 index 0000000..0f77d42 --- /dev/null +++ b/src/util.rs @@ -0,0 +1,36 @@ +use std::{ + fs::{create_dir_all, read_to_string, write}, + path::Path, +}; + +use crate::Result; + +pub(crate) fn mkdir(dir: impl AsRef) -> Result<()> { + create_dir_all(dir.as_ref()).map_err(|e| { + format!( + "Failed to create directory {}: {e}", + dir.as_ref().to_string_lossy() + ) + .into() + }) +} + +pub(crate) fn read_file(filename: impl AsRef) -> Result { + read_to_string(filename.as_ref()).map_err(|e| { + format!( + "Failed to read {}: {e}", + filename.as_ref().to_string_lossy() + ) + .into() + }) +} + +pub(crate) fn write_file>(path: impl AsRef, content: C) -> Result<()> { + write(&path, content).map_err(|e| { + format!( + "Failed to write to {}: {e}", + path.as_ref().to_string_lossy() + ) + .into() + }) +}