From d5cad5e63d4db101ca1fc90de123d1927bdd6f80 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 30 Jan 2025 09:52:14 +0100 Subject: [PATCH 1/3] treewide: group import statements std, external, crate This was done using the unstable rustfmt option[1] group_imports that requires a nightly toolchain, thus it was run manually. [1]: https://rust-lang.github.io/rustfmt/?version=v1.8.0&search=import#group_imports Signed-off-by: Stefan Kerkmann --- src/cmdline.rs | 4 +++- src/dmverity.rs | 15 +++++++++------ src/main.rs | 20 +++++++++++--------- src/mount.rs | 11 +++++++---- src/systemd.rs | 13 ++++++++----- src/usbg_9pfs.rs | 11 +++++++---- 6 files changed, 45 insertions(+), 29 deletions(-) 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..15e3795 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,13 +1,5 @@ // 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; @@ -19,6 +11,16 @@ 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")] diff --git a/src/mount.rs b/src/mount.rs index 8b20dd3..43a55f8 100644 --- a/src/mount.rs +++ b/src/mount.rs @@ -1,11 +1,14 @@ // 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::{mkdir, Result}; + pub fn do_mount( src: Option<&str>, dst: &str, diff --git a/src/systemd.rs b/src/systemd.rs index 7866fd2..8469a09 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -1,14 +1,17 @@ // 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::{mkdir, 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..601a925 100644 --- a/src/usbg_9pfs.rs +++ b/src/usbg_9pfs.rs @@ -1,13 +1,16 @@ // 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::os::unix::fs::symlink; use std::{thread, time}; +use log::debug; + +use crate::cmdline::CmdlineOptions; +use crate::mount::mount_apivfs; +use crate::{mkdir, Result}; + fn write_file>(path: &str, content: C) -> Result<()> { write(path, content).map_err(|e| format!("Failed to write to {path}: {e}").into()) } From ed59bf57a490f4584c9f180574b52a726676a163 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Thu, 30 Jan 2025 18:11:32 +0100 Subject: [PATCH 2/3] treewide: refactor mkdir and read_file mkdir, read_file write_file augment the error case with the path in the error case. This is useful as we otherwise don't know which location failed. This commit refactors the functions to take any argument that coerces into a Path - which is implemented by many types. mkdir now uses create_dir_all as it is not meant to fail if the directory already exists. Signed-off-by: Stefan Kerkmann --- src/main.rs | 17 +++-------------- src/mount.rs | 3 ++- src/systemd.rs | 3 ++- src/usbg_9pfs.rs | 9 +++------ src/util.rs | 36 ++++++++++++++++++++++++++++++++++++ 5 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 src/util.rs diff --git a/src/main.rs b/src/main.rs index 15e3795..ee5e25e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -5,7 +5,7 @@ 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}; @@ -25,6 +25,7 @@ use nix::unistd::{chdir, chroot, dup2, execv, unlink}; use systemd::{mount_systemd, shutdown}; #[cfg(feature = "usb9pfs")] use usbg_9pfs::prepare_9pfs_gadget; +use util::read_file; mod cmdline; #[cfg(feature = "dmverity")] @@ -34,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 43a55f8..65a0caf 100644 --- a/src/mount.rs +++ b/src/mount.rs @@ -7,7 +7,8 @@ use log::debug; use nix::mount::{mount, MsFlags}; use crate::cmdline::CmdlineOptions; -use crate::{mkdir, Result}; +use crate::util::mkdir; +use crate::Result; pub fn do_mount( src: Option<&str>, diff --git a/src/systemd.rs b/src/systemd.rs index 8469a09..1a295f1 100644 --- a/src/systemd.rs +++ b/src/systemd.rs @@ -10,7 +10,8 @@ use nix::sys::reboot::{reboot, RebootMode}; use crate::cmdline::CmdlineOptions; use crate::mount::do_mount; -use crate::{mkdir, Result}; +use crate::util::mkdir; +use crate::Result; pub fn mount_systemd(options: &mut CmdlineOptions) -> Result<()> { do_mount( diff --git a/src/usbg_9pfs.rs b/src/usbg_9pfs.rs index 601a925..fe96c90 100644 --- a/src/usbg_9pfs.rs +++ b/src/usbg_9pfs.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: GPL-2.0-only -use std::fs::{read_dir, write}; +use std::fs::read_dir; use std::os::unix::ffi::OsStrExt; use std::os::unix::fs::symlink; use std::{thread, time}; @@ -9,11 +9,8 @@ use log::debug; use crate::cmdline::CmdlineOptions; use crate::mount::mount_apivfs; -use crate::{mkdir, Result}; - -fn write_file>(path: &str, content: C) -> Result<()> { - write(path, content).map_err(|e| format!("Failed to write to {path}: {e}").into()) -} +use crate::util::{mkdir, write_file}; +use crate::Result; fn setup_9pfs_gadget(device: &String) -> Result<()> { debug!("Initializing USB 9pfs gadget ..."); 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() + }) +} From 592fac3f2be946dd0794a4c6a64dbaceaeab0c99 Mon Sep 17 00:00:00 2001 From: Stefan Kerkmann Date: Fri, 31 Jan 2025 13:57:39 +0100 Subject: [PATCH 3/3] 9pfs: wip --- src/usbg_9pfs.rs | 57 ++++++++++++++++++++++++------------------------ 1 file changed, 29 insertions(+), 28 deletions(-) diff --git a/src/usbg_9pfs.rs b/src/usbg_9pfs.rs index fe96c90..b85c548 100644 --- a/src/usbg_9pfs.rs +++ b/src/usbg_9pfs.rs @@ -1,9 +1,9 @@ // SPDX-License-Identifier: GPL-2.0-only use std::fs::read_dir; -use std::os::unix::ffi::OsStrExt; use std::os::unix::fs::symlink; -use std::{thread, time}; +use std::thread; +use std::time::Duration; use log::debug; @@ -12,15 +12,24 @@ use crate::mount::mount_apivfs; use crate::util::{mkdir, write_file}; use crate::Result; -fn setup_9pfs_gadget(device: &String) -> 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) }