Skip to content
Draft
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
4 changes: 3 additions & 1 deletion src/cmdline.rs
Original file line number Diff line number Diff line change
@@ -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<String>,
pub rootfstype: Option<String>,
Expand Down
15 changes: 9 additions & 6 deletions src/dmverity.rs
Original file line number Diff line number Diff line change
@@ -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;

Expand Down
37 changes: 14 additions & 23 deletions src/main.rs
Original file line number Diff line number Diff line change
@@ -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")]
Expand All @@ -32,22 +35,10 @@ mod mount;
mod systemd;
#[cfg(feature = "usb9pfs")]
mod usbg_9pfs;
mod util;

type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;

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<String, String> {
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.
Expand Down
12 changes: 8 additions & 4 deletions src/mount.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
14 changes: 9 additions & 5 deletions src/systemd.rs
Original file line number Diff line number Diff line change
@@ -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,
Expand Down
73 changes: 37 additions & 36 deletions src/usbg_9pfs.rs
Original file line number Diff line number Diff line change
@@ -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<C: AsRef<[u8]>>(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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks wrong. In the else case, the string is converted multiple times.


mount_apivfs("/sys/kernel/config", "configfs")?;

Expand All @@ -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}");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think @a3f said, that this name does not really matter, so maybe just use a fixed name.
@a3f, what do you think?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was mistaken. If I change this to something different from the first argument of the mount call, mounting fails.

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)?;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, the file name read above is not necessarily UTF-8, so converting it into a String is technically not correct.


thread::sleep(Duration::from_secs(1));

options.root = Some(udc);

let d = time::Duration::new(1, 0);
thread::sleep(d);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unrelated, this should be a separate commit.

Ok(())
}

pub fn prepare_9pfs_gadget(options: &CmdlineOptions) -> Result<bool> {
pub fn prepare_9pfs_gadget(options: &mut CmdlineOptions) -> Result<bool> {
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)
}
Expand Down
36 changes: 36 additions & 0 deletions src/util.rs
Original file line number Diff line number Diff line change
@@ -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<Path>) -> 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<Path>) -> Result<String> {
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<C: AsRef<[u8]>>(path: impl AsRef<Path>, content: C) -> Result<()> {
write(&path, content).map_err(|e| {
format!(
"Failed to write to {}: {e}",
path.as_ref().to_string_lossy()
)
.into()
})
}