Skip to content

Commit

Permalink
wip: continue sysinfo impl
Browse files Browse the repository at this point in the history
  • Loading branch information
cilki committed Jan 4, 2025
1 parent a5589ff commit fd71f4c
Show file tree
Hide file tree
Showing 24 changed files with 534 additions and 351 deletions.
2 changes: 2 additions & 0 deletions sandpolis/src/agent/layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,5 @@ pub mod desktop;
pub mod package;
#[cfg(feature = "layer-shell")]
pub mod shell;
#[cfg(feature = "layer-sysinfo")]
pub mod sysinfo;
1 change: 1 addition & 0 deletions sandpolis/src/agent/layer/sysinfo/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub mod os;
39 changes: 39 additions & 0 deletions sandpolis/src/agent/layer/sysinfo/os/memory.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
use crate::agent::Monitor;
use crate::core::database::Document;
use crate::core::layer::sysinfo::os::memory::MemoryData;
use anyhow::Result;
use sysinfo::{MemoryRefreshKind, RefreshKind, System};
use tracing::trace;

pub struct MemoryMonitor {
document: Document<MemoryData>,
system: System,
}

impl MemoryMonitor {
pub fn new(document: Document<MemoryData>) -> Self {
Self {
document,
system: System::new_with_specifics(
RefreshKind::nothing().with_memory(MemoryRefreshKind::everything()),
),
}
}
}

impl Monitor for MemoryMonitor {
fn refresh(&mut self) -> Result<()> {
self.system.refresh_memory();
self.document.mutate(|data| {
data.total = self.system.total_memory();
data.free = self.system.free_memory();
data.swap_free = self.system.free_swap();
data.swap_total = self.system.total_swap();

trace!(data = ?data, "Polled memory info");
Ok(())
});

Ok(())
}
}
2 changes: 2 additions & 0 deletions sandpolis/src/agent/layer/sysinfo/os/mod.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
pub mod memory;
pub mod user;
19 changes: 19 additions & 0 deletions sandpolis/src/agent/layer/sysinfo/os/user.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
use crate::agent::Monitor;
use crate::core::database::{Collection, Oid};
use crate::core::layer::sysinfo::os::user::UserData;
use anyhow::Result;
use sysinfo::{User, Users};

impl Monitor for Collection<UserData> {
fn refresh(&self) -> Result<()> {
for user in Users::new_with_refreshed_list().list() {
self.document(**user.id())?.mutate(|data| {
data.uid = **user.id() as u64;
data.gid = *user.group_id() as u64;
data.username = Some(user.name().to_string());
Ok(())
});
}
Ok(())
}
}
4 changes: 4 additions & 0 deletions sandpolis/src/agent/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -255,3 +255,7 @@ pub async fn main(args: CommandLine) -> Result<()> {

return Ok(());
}

pub trait Monitor {
fn refresh(&mut self) -> Result<()>;
}
130 changes: 122 additions & 8 deletions sandpolis/src/core/database.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
use anyhow::{bail, Result};
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
use std::marker::PhantomData;
use std::{path::Path, sync::Arc};
use tracing::debug;

Expand Down Expand Up @@ -39,16 +42,127 @@ impl Database {
})
}

pub fn instance(&self, id: impl Into<InstanceId>) -> Result<InstanceData> {
let id = id.into();
let db = self.db.open_tree(id)?;
pub fn instance(&self, id: impl Into<InstanceId>) -> Result<Oid> {
Ok(Oid {
db: self.db.open_tree(id.into())?,
path: vec!['/' as u8],
})
}
}

/// Identifies an object in the database.
#[derive(Clone)]
pub struct Oid(Vec<u8>);

impl Oid {
pub fn extend(mut self, extension: &str) -> Result<Oid> {
self.path.push('/' as u8);
self.path.extend_from_slice(extension.as_bytes());
Ok(self)
}

pub fn extend_id(mut self, id: u64) -> Result<Oid<T>> {
// Prohibit multiple IDs
for byte in self.path.iter().rev() {
if *byte == ':' as u8 {
// TODO
}
}

self.path.push(':' as u8);
self.path.extend_from_slice(&id.to_be_bytes());
Ok(self)
}

pub fn history(&self) -> Oid {
let mut path = "/history".as_bytes().to_vec();
path.extend_from_slice(&self.0);
Oid(path)
}
}

impl From<u32> for Oid {
fn from(value: u32) -> Self {
Oid(value.to_be_bytes().to_vec())
}
}

impl AsRef<[u8]> for Oid {
fn as_ref(&self) -> &[u8] {
&self.0
}
}

#[derive(Clone)]
pub struct Collection<T>
where
T: Serialize + DeserializeOwned + Clone,
{
db: sled::Tree,
oid: Oid,
data: PhantomData<T>,
}

impl<T: Serialize + DeserializeOwned + Clone> Collection<T> {
pub fn get_document<I>(&self, id: I) -> Result<Option<Document<T>>>
where
I: Into<Oid>,
{
let oid = self.oid.extend_id(id.into())?;

Ok(if let Some(data) = db.get("instance")? {
serde_json::from_slice::<InstanceData>(&data)?
Ok(if let Some(data) = self.db.get(&oid)? {
Some(Document {
db: self.db.clone(),
data: serde_cbor::from_slice::<T>(&data)?,
oid,
})
} else {
let instance = InstanceData::new();
db.insert("local", serde_json::to_vec(&instance)?)?;
instance
None
})
}
}

impl<T: Serialize + DeserializeOwned + Clone + Default> Collection<T> {
pub fn document<I>(&self, id: I) -> Result<Document<T>>
where
I: Into<Oid>,
{
let oid = self.oid.extend_id(id.into())?;

Ok(Document {
db: self.db.clone(),
data: if let Some(data) = self.db.get(&oid)? {
serde_cbor::from_slice::<T>(&data)?
} else {
T::default()
},
oid,
})
}
}

#[derive(Clone)]
pub struct Document<T>
where
T: Serialize + DeserializeOwned + Clone,
{
db: sled::Tree,
oid: Oid,
data: T,
}

impl<T: Serialize + DeserializeOwned + Clone> Document<T> {
pub fn mutate<F>(&mut self, mutator: F) -> Result<()>
where
F: Fn(&mut T) -> Result<()>,
{
// Create a copy so we can tell what changed
let mut object = self.data.clone();
mutator(&mut object)?;

// TODO detect changes and update history as part of a transaction

self.db.insert(&self.oid, serde_cbor::to_vec(&object)?)?;
Ok(())
}
}
2 changes: 2 additions & 0 deletions sandpolis/src/core/layer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ pub mod package;
pub mod probe;
#[cfg(feature = "layer-shell")]
pub mod shell;
#[cfg(feature = "layer-sysinfo")]
pub mod sysinfo;
#[cfg(feature = "layer-tunnel")]
pub mod tunnel;

Expand Down
90 changes: 29 additions & 61 deletions sandpolis/src/core/layer/sysinfo/hardware/battery.rs
Original file line number Diff line number Diff line change
@@ -1,69 +1,37 @@
pub struct Battery {
/// Manufacturer's name
pub manufacturer: Option<String>,
/// Manufacturer's name
pub manufacturer: Option<String>,

/// The date the battery was manufactured UNIX Epoch
pub manufacture_date: Option<u64>,
/// The date the battery was manufactured UNIX Epoch
pub manufacture_date: Option<u64>,

/// Model number
pub model: Option<String>,
/// Model number
pub model: Option<String>,

/// Serial number
pub serial_number: Option<String>,
/// Serial number
pub serial_number: Option<String>,

/// Number of charge/discharge cycles
pub cycle_count: Option<u64>,
/// Number of charge/discharge cycles
pub cycle_count: Option<u64>,

/// Whether the battery is currently being changed by a power source
pub charging: Option<bool>,
/// Whether the battery is currently being changed by a power source
pub charging: Option<bool>,

/// Whether the battery is completely charged
pub charged: Option<bool>,
}
/// Whether the battery is completely charged
pub charged: Option<bool>,

/// Maximum capacity specification in mAh
pub specified_capacity: Option<u32>,

/// Actual maximum capacity in mAh
pub actual_capacity: Option<u32>,

{
"collection": true,
"attributes": [
{
"name": "charged",
"type": "java.lang.Boolean",
"description": "Whether the battery is completely charged",
"osquery": "battery.charged"
},
{
"name": "designed_capacity",
"type": "java.lang.Integer",
"description": "The battery's designed capacity in mAh",
"osquery": "battery.designed_capacity"
},
{
"name": "max_capacity",
"type": "java.lang.Integer",
"description": "The battery's actual capacity when it is fully charged in mAh",
"osquery": "battery.max_capacity"
},
{
"name": "current_capacity",
"type": "java.lang.Integer",
"description": "The battery's current charged capacity in mAh",
"osquery": "battery.current_capacity"
},
{
"name": "percent_remaining",
"type": "java.lang.Integer",
"description": "The percentage of battery remaining before it is drained",
"osquery": "battery.percent_remaining"
},
{
"name": "amperage",
"type": "java.lang.Integer",
"description": "The battery's current amperage in mA",
"osquery": "battery.amperage"
},
{
"name": "voltage",
"type": "java.lang.Integer",
"description": "The battery's current voltage in mV",
"osquery": "battery.voltage"
}
]}
/// Current capacity in mAh
pub remaining_capacity: Option<u32>,

/// Amperage in mA
pub current: Option<u32>,

/// Voltage in mV
pub voltage: Option<u32>,
}
40 changes: 21 additions & 19 deletions sandpolis/src/core/layer/sysinfo/hardware/cpu.rs
Original file line number Diff line number Diff line change
@@ -1,21 +1,23 @@
/// null
pub model: java.lang.String,
/// null
pub vendor: java.lang.String,
/// The specified frequency in Hertz
pub frequency_spec: java.lang.Integer,
/// The size of the L1 cache in bytes
pub l1_cache: java.lang.Integer,
/// The size of the L2 cache in bytes
pub l2_cache: java.lang.Integer,
/// The size of the L3 cache in bytes
pub l3_cache: java.lang.Integer,
/// The size of the L4 cache in bytes
pub l4_cache: java.lang.Integer,
pub struct CpuData {
/// null
pub model: Option<String>,
/// null
pub vendor: Option<String>,
/// The specified frequency in Hertz
pub frequency_spec: u64,
/// The size of the L1 cache in bytes
pub l1_cache: u64,
/// The size of the L2 cache in bytes
pub l2_cache: u64,
/// The size of the L3 cache in bytes
pub l3_cache: u64,
/// The size of the L4 cache in bytes
pub l4_cache: u64,
}

pub struct Core {
/// The core's usage between 0.0 and 1.0
pub usage: java.lang.Double,
/// The core's temperature in Celsius
pub temperature: java.lang.Double,
pub struct CpuCoreData {
/// The core's usage between 0.0 and 1.0
pub usage: Double,
/// The core's temperature in Celsius
pub temperature: Double,
}
Loading

0 comments on commit fd71f4c

Please sign in to comment.