From 3af9166d2c71f15e0737e7bdf5d96210c7b2919a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 12:40:35 +0200 Subject: [PATCH 1/7] Rename fields of `ospect::fs::Mount`. --- crates/ospect/src/fs.rs | 8 +++---- crates/ospect/src/fs/linux.rs | 24 +++++++++---------- crates/ospect/src/fs/macos.rs | 8 +++---- crates/ospect/src/fs/windows.rs | 4 ++-- .../rrg/src/action/deprecated/filesystems.rs | 4 ++-- 5 files changed, 24 insertions(+), 24 deletions(-) diff --git a/crates/ospect/src/fs.rs b/crates/ospect/src/fs.rs index 9784929e..868cca11 100644 --- a/crates/ospect/src/fs.rs +++ b/crates/ospect/src/fs.rs @@ -192,9 +192,9 @@ where #[derive(Debug)] pub struct Mount { /// Name of the mounted device. - pub source: String, + pub name: String, /// Mount point, i.e., where the mounted filesystem is available. - pub target: std::path::PathBuf, + pub path: std::path::PathBuf, /// Type of the mounted filesystem (e.g. `ext4`, `ramfs`, `proc`). pub fs_type: String, } @@ -356,7 +356,7 @@ mod tests { .unwrap() .map(Result::unwrap); - assert!(mounts.find(|mount| mount.target == Path::new("/")).is_some()); + assert!(mounts.find(|mount| mount.path == Path::new("/")).is_some()); } #[cfg(target_family = "windows")] @@ -374,7 +374,7 @@ mod tests { system_drive_path.push(std::path::MAIN_SEPARATOR_STR); assert! { - mounts.find(|mount| &mount.target == &system_drive_path).is_some() + mounts.find(|mount| &mount.path == &system_drive_path).is_some() }; } } diff --git a/crates/ospect/src/fs/linux.rs b/crates/ospect/src/fs/linux.rs index 5323b8d0..c57f5b56 100644 --- a/crates/ospect/src/fs/linux.rs +++ b/crates/ospect/src/fs/linux.rs @@ -222,16 +222,16 @@ impl Mounts { // There is more data in the file but we don't care for the time being // and only "parse" the first three columns. - let source = cols.next() + let name = cols.next() .ok_or_else(|| std::io::ErrorKind::InvalidData)?; - let target = cols.next() + let path = cols.next() .ok_or_else(|| std::io::ErrorKind::InvalidData)?; let fs_type = cols.next() .ok_or_else(|| std::io::ErrorKind::InvalidData)?; Ok(Mount { - source: source.into(), - target: target.into(), + name: name.into(), + path: path.into(), fs_type: fs_type.into(), }) } @@ -414,23 +414,23 @@ proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0 let mut mounts = Mounts::new(MTAB.as_bytes()); let mount = mounts.next().unwrap().unwrap(); - assert_eq!(mount.source, "sysfs"); - assert_eq!(mount.target, Path::new("/sys")); + assert_eq!(mount.name, "sysfs"); + assert_eq!(mount.path, Path::new("/sys")); assert_eq!(mount.fs_type, "sysfs"); let mount = mounts.next().unwrap().unwrap(); - assert_eq!(mount.source, "proc"); - assert_eq!(mount.target, Path::new("/proc")); + assert_eq!(mount.name, "proc"); + assert_eq!(mount.path, Path::new("/proc")); assert_eq!(mount.fs_type, "proc"); let mount = mounts.next().unwrap().unwrap(); - assert_eq!(mount.source, "/dev/foobar"); - assert_eq!(mount.target, Path::new("/")); + assert_eq!(mount.name, "/dev/foobar"); + assert_eq!(mount.path, Path::new("/")); assert_eq!(mount.fs_type, "ext4"); let mount = mounts.next().unwrap().unwrap(); - assert_eq!(mount.source, "/dev/quux"); - assert_eq!(mount.target, Path::new("/usr/quux")); + assert_eq!(mount.name, "/dev/quux"); + assert_eq!(mount.path, Path::new("/usr/quux")); assert_eq!(mount.fs_type, "ext4"); assert!(mounts.next().is_none()); diff --git a/crates/ospect/src/fs/macos.rs b/crates/ospect/src/fs/macos.rs index 1b34006c..5951c19f 100644 --- a/crates/ospect/src/fs/macos.rs +++ b/crates/ospect/src/fs/macos.rs @@ -244,11 +244,11 @@ pub fn mounts() -> std::io::Result>> // safety invariants required by the `from_ptr` call are met. Note that // `statfs` is now on the stack, so the lifetime of this reference is // valid until the end of this scope. - let source = unsafe { + let name = unsafe { std::ffi::CStr::from_ptr(statfs.f_mntfromname.as_ptr()) }.to_string_lossy(); // SAFETY: Same as above. - let target = unsafe { + let path = unsafe { std::ffi::CStr::from_ptr(statfs.f_mntonname.as_ptr()) }.to_bytes(); // SAFETY: Same as above. @@ -259,8 +259,8 @@ pub fn mounts() -> std::io::Result>> use std::os::unix::ffi::OsStrExt as _; mounts.push(Mount { - source: source.into_owned(), - target: PathBuf::from(OsStr::from_bytes(target)), + name: name.into_owned(), + path: PathBuf::from(OsStr::from_bytes(path)), fs_type: fs_type.into_owned(), }); } diff --git a/crates/ospect/src/fs/windows.rs b/crates/ospect/src/fs/windows.rs index cbd2f0aa..702f04b0 100644 --- a/crates/ospect/src/fs/windows.rs +++ b/crates/ospect/src/fs/windows.rs @@ -62,9 +62,9 @@ pub fn mounts() -> std::io::Result>> for mount_point in VolumeMountPoints::new(&name_buf)? { results.push(Ok(Mount { - source: OsString::from_wide(&name_buf[0..name_len]) + name: OsString::from_wide(&name_buf[0..name_len]) .to_string_lossy().into_owned(), - target: mount_point, + path: mount_point, fs_type: OsString::from_wide(&fs_type_buf[0..fs_type_len]) .to_string_lossy().into_owned(), })); diff --git a/crates/rrg/src/action/deprecated/filesystems.rs b/crates/rrg/src/action/deprecated/filesystems.rs index fd0023df..b86eb7c5 100644 --- a/crates/rrg/src/action/deprecated/filesystems.rs +++ b/crates/rrg/src/action/deprecated/filesystems.rs @@ -90,8 +90,8 @@ impl crate::response::Item for Response { // when `mount_point` and `device` fields of `Filesystem` message // will have `bytes` type instead of `string`. let mut proto = rrg_proto::sysinfo::Filesystem::new(); - proto.set_device(self.mount_info.source); - proto.set_mount_point(self.mount_info.target.to_string_lossy().into_owned()); + proto.set_device(self.mount_info.name); + proto.set_mount_point(self.mount_info.path.to_string_lossy().into_owned()); proto.set_field_type(self.mount_info.fs_type); proto From 0e31483622f6780007871320710df51622849bde Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 13:38:31 +0200 Subject: [PATCH 2/7] Define proto message for mount information. --- proto/rrg/fs.proto | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/proto/rrg/fs.proto b/proto/rrg/fs.proto index 67386734..ed85e001 100644 --- a/proto/rrg/fs.proto +++ b/proto/rrg/fs.proto @@ -70,3 +70,13 @@ message FileExtAttr { // This can be an arbitrary sequence of bytes both on macOS and Linux. bytes value = 2; } + +// Information about a mounted filesystem. +message Mount { + // Name or other identifier of the mounted device. + string name = 1; + // Path at which the mounted filesystem is available (a mount point). + Path path = 2; + // Type of the mounted filesystem (e.g. `ext4`, `ramfs`, `NTFS`). + string fs_type = 3; +} From bad2277a702614b537c400d45d27ddc3b0194dda Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 13:44:08 +0200 Subject: [PATCH 3/7] Implement proto conversion for mount information. --- crates/rrg-proto/src/lib.rs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/crates/rrg-proto/src/lib.rs b/crates/rrg-proto/src/lib.rs index 59ae2295..a927b8f1 100644 --- a/crates/rrg-proto/src/lib.rs +++ b/crates/rrg-proto/src/lib.rs @@ -105,6 +105,18 @@ pub mod v2 { } } + impl From for fs::Mount { + + fn from(mount: ospect::fs::Mount) -> fs::Mount { + let mut proto = fs::Mount::default(); + proto.set_name(mount.name); + proto.set_path(mount.path.into()); + proto.set_fs_type(mount.fs_type); + + proto + } + } + impl From for net::IpAddress { fn from(addr: std::net::Ipv4Addr) -> net::IpAddress { From 845c87b7c3373abacf41a17729ad95e1d6ab046a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 14:07:34 +0200 Subject: [PATCH 4/7] Prepare boilerplate for `list_mounts`. --- crates/rrg-proto/build.rs | 1 + crates/rrg/Cargo.toml | 2 ++ crates/rrg/src/action.rs | 7 +++++++ crates/rrg/src/action/list_mounts.rs | 26 ++++++++++++++++++++++++++ crates/rrg/src/request.rs | 4 ++++ proto/rrg.proto | 2 ++ proto/rrg/action/list_mounts.proto | 11 +++++++++++ 7 files changed, 53 insertions(+) create mode 100644 crates/rrg/src/action/list_mounts.rs create mode 100644 proto/rrg/action/list_mounts.proto diff --git a/crates/rrg-proto/build.rs b/crates/rrg-proto/build.rs index 11cd82a6..a7657995 100644 --- a/crates/rrg-proto/build.rs +++ b/crates/rrg-proto/build.rs @@ -32,6 +32,7 @@ const PROTOS_V2: &'static [&'static str] = &[ "../../proto/rrg/action/get_system_metadata.proto", "../../proto/rrg/action/list_connections.proto", "../../proto/rrg/action/list_interfaces.proto", + "../../proto/rrg/action/list_mounts.proto", ]; fn main() { diff --git a/crates/rrg/Cargo.toml b/crates/rrg/Cargo.toml index 759a52dc..7d3ef0dc 100644 --- a/crates/rrg/Cargo.toml +++ b/crates/rrg/Cargo.toml @@ -13,6 +13,7 @@ default = [ "action-get_filesystem_timeline", "action-list_connections", "action-list_interfaces", + "action-list_mounts", # These actions are deprecated (awaiting migration to the new protocol). "action-insttime", @@ -31,6 +32,7 @@ action-get_file_contents = ["dep:sha2"] action-get_filesystem_timeline = ["dep:flate2", "dep:sha2"] action-list_connections = [] action-list_interfaces = [] +action-list_mounts = [] # These actions are deprecated (awaiting migration to the new protocol). action-insttime = [] diff --git a/crates/rrg/src/action.rs b/crates/rrg/src/action.rs index 966522ba..4e514eeb 100644 --- a/crates/rrg/src/action.rs +++ b/crates/rrg/src/action.rs @@ -36,6 +36,9 @@ pub mod list_connections; #[cfg(feature = "action-list_interfaces")] pub mod list_interfaces; +#[cfg(feature = "action-list_mounts")] +pub mod list_mounts; + use log::info; /// Dispatches the given `request` to an appropriate action handler. @@ -86,6 +89,10 @@ where ListInterfaces => { handle(session, request, self::list_interfaces::handle) } + #[cfg(feature = "action-list_mounts")] + ListMounts => { + handle(session, request, self::list_mounts::handle) + } // We allow `unreachable_patterns` because otherwise we get a warning if // we compile with all the actions enabled. #[allow(unreachable_patterns)] diff --git a/crates/rrg/src/action/list_mounts.rs b/crates/rrg/src/action/list_mounts.rs new file mode 100644 index 00000000..c1cd2a39 --- /dev/null +++ b/crates/rrg/src/action/list_mounts.rs @@ -0,0 +1,26 @@ +// Copyright 2023 Google LLC +// +// Use of this source code is governed by an MIT-style license that can be found +// in the LICENSE file or at https://opensource.org/licenses/MIT. + +/// A result of the `list_mounts` action. +struct Item { + // TODO(@panhania): Add actual data. +} + +// Handles invocations of the `list_mounts` action. +pub fn handle(_session: &mut S, _: ()) -> crate::session::Result<()> +where + S: crate::session::Session, +{ + todo!() +} + +impl crate::response::Item for Item { + + type Proto = rrg_proto::v2::list_mounts::Result; + + fn into_proto(self) -> rrg_proto::v2::list_mounts::Result { + todo!() + } +} diff --git a/crates/rrg/src/request.rs b/crates/rrg/src/request.rs index fe01966f..0155e888 100644 --- a/crates/rrg/src/request.rs +++ b/crates/rrg/src/request.rs @@ -33,6 +33,8 @@ pub enum Action { ListNamedPipes, /// List network interfaces available on the system. ListInterfaces, + /// List filesystem mounts available on the system. + ListMounts, /// List users available on the system. ListUsers, /// Get the snapshot of the entire filesystem. @@ -52,6 +54,7 @@ impl std::fmt::Display for Action { Action::ListConnections => write!(fmt, "list_connections"), Action::ListNamedPipes => write!(fmt, "list_named_pipes"), Action::ListInterfaces => write!(fmt, "list_interfaces"), + Action::ListMounts => write!(fmt, "list_mounts"), Action::ListUsers => write!(fmt, "list_users"), Action::GetFilesystemTimeline => write!(fmt, "get_filesystem_timeline"), } @@ -95,6 +98,7 @@ impl TryFrom for Action { LIST_CONNECTIONS => Ok(Action::ListConnections), LIST_NAMED_PIPES => Ok(Action::ListNamedPipes), LIST_INTERFACES => Ok(Action::ListInterfaces), + LIST_MOUNTS => Ok(Action::ListMounts), LIST_USERS => Ok(Action::ListUsers), GET_FILESYSTEM_TIMELINE => Ok(Action::GetFilesystemTimeline), _ => { diff --git a/proto/rrg.proto b/proto/rrg.proto index fc15c665..29f83d49 100644 --- a/proto/rrg.proto +++ b/proto/rrg.proto @@ -36,6 +36,8 @@ enum Action { GET_FILESYSTEM_TIMELINE = 10; // List network interfaces available on the system. LIST_INTERFACES = 11; + // List filesystem mounts available on the system. + LIST_MOUNTS = 12; // TODO: Define more actions that should be supported. diff --git a/proto/rrg/action/list_mounts.proto b/proto/rrg/action/list_mounts.proto new file mode 100644 index 00000000..ba666fc2 --- /dev/null +++ b/proto/rrg/action/list_mounts.proto @@ -0,0 +1,11 @@ +// Copyright 2023 Google LLC +// +// Use of this source code is governed by an MIT-style license that can be found +// in the LICENSE file or at https://opensource.org/licenses/MIT. +syntax = "proto3"; + +package rrg.action.list_mounts; + +message Result { + // TODO(@panhania): Add mount information. +} From 523668f344f2245898c9fbbaa7121073cbdb67fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 14:21:10 +0200 Subject: [PATCH 5/7] Implement the `list_mounts` action. --- crates/rrg/src/action/list_mounts.rs | 29 ++++++++++++++++++++++++---- proto/rrg/action/list_mounts.proto | 5 ++++- 2 files changed, 29 insertions(+), 5 deletions(-) diff --git a/crates/rrg/src/action/list_mounts.rs b/crates/rrg/src/action/list_mounts.rs index c1cd2a39..e138cc85 100644 --- a/crates/rrg/src/action/list_mounts.rs +++ b/crates/rrg/src/action/list_mounts.rs @@ -5,15 +5,33 @@ /// A result of the `list_mounts` action. struct Item { - // TODO(@panhania): Add actual data. + // Information about the individual filesystem mount. + mount: ospect::fs::Mount, } // Handles invocations of the `list_mounts` action. -pub fn handle(_session: &mut S, _: ()) -> crate::session::Result<()> +pub fn handle(session: &mut S, _: ()) -> crate::session::Result<()> where S: crate::session::Session, { - todo!() + let mounts = ospect::fs::mounts() + .map_err(crate::session::Error::action)?; + + for mount in mounts { + let mount = match mount { + Ok(mount) => mount, + Err(error) => { + log::warn!("failed to obtain mount information: {}", error); + continue; + } + }; + + session.reply(Item { + mount, + })?; + } + + Ok(()) } impl crate::response::Item for Item { @@ -21,6 +39,9 @@ impl crate::response::Item for Item { type Proto = rrg_proto::v2::list_mounts::Result; fn into_proto(self) -> rrg_proto::v2::list_mounts::Result { - todo!() + let mut proto = rrg_proto::v2::list_mounts::Result::default(); + proto.set_mount(self.mount.into()); + + proto } } diff --git a/proto/rrg/action/list_mounts.proto b/proto/rrg/action/list_mounts.proto index ba666fc2..455c95b6 100644 --- a/proto/rrg/action/list_mounts.proto +++ b/proto/rrg/action/list_mounts.proto @@ -6,6 +6,9 @@ syntax = "proto3"; package rrg.action.list_mounts; +import "rrg/fs.proto"; + message Result { - // TODO(@panhania): Add mount information. + // Information about the individual filesystem mount. + rrg.fs.Mount mount = 1; } From 9637009acbd59f414a2cca470fd8a19d033ddab3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 14:25:51 +0200 Subject: [PATCH 6/7] Reuse mount listing test from deprecated action. --- crates/rrg/src/action/deprecated/filesystems.rs | 7 ------- crates/rrg/src/action/list_mounts.rs | 13 +++++++++++++ 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/crates/rrg/src/action/deprecated/filesystems.rs b/crates/rrg/src/action/deprecated/filesystems.rs index b86eb7c5..a29b6a89 100644 --- a/crates/rrg/src/action/deprecated/filesystems.rs +++ b/crates/rrg/src/action/deprecated/filesystems.rs @@ -103,13 +103,6 @@ mod tests { use super::*; - #[test] - fn test_if_any_filesystem_exists() { - let mut session = session::FakeSession::new(); - assert!(handle(&mut session, ()).is_ok()); - assert_ne!(session.reply_count(), 0); - } - #[cfg(feature = "test-fuse")] #[test] fn test_fuse_filesystem() { diff --git a/crates/rrg/src/action/list_mounts.rs b/crates/rrg/src/action/list_mounts.rs index e138cc85..253dde7b 100644 --- a/crates/rrg/src/action/list_mounts.rs +++ b/crates/rrg/src/action/list_mounts.rs @@ -45,3 +45,16 @@ impl crate::response::Item for Item { proto } } + +#[cfg(test)] +mod tests { + + use super::*; + + #[test] + fn test_if_any_filesystem_exists() { + let mut session = crate::session::FakeSession::new(); + assert!(handle(&mut session, ()).is_ok()); + assert_ne!(session.reply_count(), 0); + } +} From c664a2721d696353a2eed94aef91cd01b0586f4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C5=81ukasz=20Hanuszczak?= Date: Fri, 20 Oct 2023 14:31:11 +0200 Subject: [PATCH 7/7] Adjust code style of a `list_mounts` test. --- crates/rrg/src/action/list_mounts.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/crates/rrg/src/action/list_mounts.rs b/crates/rrg/src/action/list_mounts.rs index 253dde7b..a690be53 100644 --- a/crates/rrg/src/action/list_mounts.rs +++ b/crates/rrg/src/action/list_mounts.rs @@ -52,9 +52,10 @@ mod tests { use super::*; #[test] - fn test_if_any_filesystem_exists() { + fn handle_some_mount() { let mut session = crate::session::FakeSession::new(); assert!(handle(&mut session, ()).is_ok()); - assert_ne!(session.reply_count(), 0); + + assert!(session.reply_count() > 0); } }