Skip to content

Commit

Permalink
rm daemon
Browse files Browse the repository at this point in the history
  • Loading branch information
doriancodes committed Dec 16, 2024
1 parent cab6747 commit 63b026a
Show file tree
Hide file tree
Showing 2 changed files with 74 additions and 184 deletions.
76 changes: 4 additions & 72 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ use anyhow::Result;
use clap::{Parser, Subcommand};
use env_logger;
use froggr::modules::namespace::BindMode;
use froggr::modules::session::Session;
use froggr::{FilesystemManager, NineP};
use log::{info, error, LevelFilter};
use session::Session;
use std::path::PathBuf;
use std::env;
use tokio::signal;
Expand Down Expand Up @@ -51,18 +51,6 @@ enum Commands {
#[arg(default_value = "localhost")]
node_id: String,
},
/// Start a new session daemon
Session {
/// Root directory for the session (defaults to current directory)
#[arg(short = 'r', long = "root")]
root: Option<PathBuf>,
/// PID file location (defaults to /tmp/froggr.pid, or /var/run/froggr.pid if running as root)
#[arg(long)]
pid_file: Option<PathBuf>,
/// Run with elevated privileges (stores PID in /var/run)
#[arg(long)]
privileged: bool,
},
}

#[tokio::main]
Expand All @@ -83,60 +71,6 @@ async fn main() -> Result<()> {
info!("Starting froggr...");

match &cli.command {
Commands::Session { root, pid_file, privileged } => {
info!("Initializing session...");

// Use provided root or current directory
let root_path = match root {
Some(path) => path.clone(),
None => env::current_dir()?,
};

// Determine PID file location
let pid_path = match (pid_file, privileged) {
(Some(path), false) => path.clone(),
(Some(path), true) => {
if !nix::unistd::Uid::effective().is_root() {
return Err(anyhow::anyhow!("Privileged mode requires root permissions"));
}
path.clone()
},
(None, true) => {
if !nix::unistd::Uid::effective().is_root() {
return Err(anyhow::anyhow!("Privileged mode requires root permissions"));
}
PathBuf::from("/var/run/froggr.pid")
},
(None, false) => PathBuf::from("/tmp/froggr.pid"),
};

info!("Using root directory: {}", root_path.display());

// Start a new session
let session = Session::new(&root_path)?;
info!("Session started with root directory: {}", root_path.display());

// Write PID file
let pid = std::process::id().to_string().into_bytes();
std::fs::write(&pid_path, pid)?;
info!("PID file written to: {}", pid_path.display());

info!("Session running. Press Ctrl+C to stop.");

// Wait for shutdown signal
signal::ctrl_c().await?;
info!("Received shutdown signal");

// Clean shutdown
session.shutdown()?;

// Cleanup PID file
if pid_path.exists() {
std::fs::remove_file(pid_path)?;
}

info!("Session terminated");
}
Commands::Bind {
before,
after,
Expand All @@ -152,10 +86,9 @@ async fn main() -> Result<()> {
_ => BindMode::Before,
};

let hello_fs = NineP::new(target.clone())?;
let fs_mngr = FilesystemManager::new(hello_fs);
let session = Session::new(target.clone())?;

fs_mngr.bind(source.as_path(), target.as_path(), bind_mode)?;
session.fs_manager.bind(source.as_path(), target.as_path(), bind_mode)?;
info!(
"Successfully bound {} to {}",
source.display(),
Expand All @@ -167,8 +100,7 @@ async fn main() -> Result<()> {
mount_point,
node_id,
} => {
let hello_fs = NineP::new(source.clone())?;
let fs_mngr = FilesystemManager::new(hello_fs);
let session = Session::new(source.clone())?;

fs_mngr.mount(&source.as_path(), &mount_point.as_path(), &node_id)?;
info!(
Expand Down
182 changes: 70 additions & 112 deletions src/modules/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,184 +5,142 @@ use std::sync::atomic::{AtomicBool, Ordering};
use anyhow::Result;
use log::{info, error};
use std::path::{Path, PathBuf};
use std::fs;
use libc::{SIGINT, SIGTERM};
use signal_hook::iterator::Signals;
use anyhow::anyhow;
use crate::FilesystemManager;

#[derive(Debug)]
enum DaemonMessage {
enum SessionMessage {
Mount {
source: PathBuf,
target: PathBuf,
node_id: String,
},
Bind {
source: PathBuf,
target: PathBuf,
mode: crate::modules::namespace::BindMode,
},
Unmount {
path: PathBuf,
},
Shutdown,
}

/// A filesystem session manager that handles communication with a background daemon.
///
/// The Session struct manages a background daemon process that handles filesystem
/// operations. It provides a clean interface for:
/// - Mounting and unmounting filesystems
/// - Managing daemon lifecycle
/// - Handling inter-process communication
/// A filesystem state manager that handles mounting and binding operations.
pub struct Session {
root: PathBuf,
daemon_tx: Sender<DaemonMessage>,
daemon_thread: JoinHandle<()>,
pub fs_manager: FilesystemManager,
message_tx: Sender<SessionMessage>,
message_thread: JoinHandle<()>,
is_running: Arc<AtomicBool>,
}

impl Session {
/// Creates a new Session with the specified root directory.
///
/// # Arguments
///
/// * `root` - The root directory path for this session
///
/// # Returns
///
/// A Result containing the new Session instance or an error if initialization fails
///
/// # Example
///
/// ```no_run
/// use std::path::Path;
/// use froggr::modules::session::Session;
///
/// let session = Session::new(Path::new("/tmp/session")).unwrap();
/// ```
pub fn new<P: AsRef<Path>>(root: P) -> Result<Self> {
let root = root.as_ref().to_path_buf();
let fs = crate::NineP::new(root.clone())?;
let fs_manager = FilesystemManager::new(fs);

let (tx, rx) = channel();
let is_running = Arc::new(AtomicBool::new(true));
let is_running_clone = is_running.clone();
let fs_manager_clone = fs_manager.clone();

// Start the daemon thread
let daemon_thread = thread::spawn(move || {
Self::run_daemon(rx, is_running_clone);
let message_thread = thread::spawn(move || {
Self::run_message_handler(rx, is_running_clone, fs_manager_clone);
});

info!("Session daemon started in {}", root.display());
info!("Session started in {}", root.display());

Ok(Self {
root,
daemon_tx: tx,
daemon_thread,
fs_manager,
message_tx: tx,
message_thread,
is_running,
})
}

fn run_daemon(rx: Receiver<DaemonMessage>, is_running: Arc<AtomicBool>) {
let mut signals = Signals::new(&[SIGINT, SIGTERM]).unwrap();
let signal_handler = thread::spawn(move || {
for sig in signals.forever() {
match sig {
SIGINT | SIGTERM => {
info!("Daemon received shutdown signal");
return;
}
_ => {}
}
}
});

fn run_message_handler(
rx: Receiver<SessionMessage>,
is_running: Arc<AtomicBool>,
fs_manager: FilesystemManager,
) {
while is_running.load(Ordering::SeqCst) {
match rx.recv() {
Ok(message) => match message {
DaemonMessage::Mount { source, target, node_id } => {
info!("Daemon received mount request: {:?} -> {:?} (node: {})",
SessionMessage::Mount { source, target, node_id } => {
info!("Processing mount request: {:?} -> {:?} (node: {})",
source, target, node_id);
}
DaemonMessage::Unmount { path } => {
info!("Daemon received unmount request: {:?}", path);
}
DaemonMessage::Shutdown => {
info!("Daemon received shutdown message");
if let Err(e) = fs_manager.mount(&source, &target, &node_id) {
error!("Mount failed: {}", e);
}
},
SessionMessage::Bind { source, target, mode } => {
info!("Processing bind request: {:?} -> {:?}", source, target);
if let Err(e) = fs_manager.bind(&source, &target, mode) {
error!("Bind failed: {}", e);
}
},
SessionMessage::Unmount { path } => {
info!("Processing unmount request: {:?}", path);
if let Err(e) = fs_manager.unmount(&path, None) {
error!("Unmount failed: {}", e);
}
},
SessionMessage::Shutdown => {
info!("Received shutdown message");
break;
}
},
Err(e) => {
error!("Daemon channel error: {}", e);
error!("Message channel error: {}", e);
break;
}
}
}

is_running.store(false, Ordering::SeqCst);
signal_handler.join().unwrap();
info!("Session daemon stopped");
}

/// Requests the daemon to mount a filesystem.
///
/// # Arguments
///
/// * `source` - The source directory to mount
/// * `mount_point` - Where to mount the filesystem
/// * `node_id` - Identifier for the node (usually hostname)
///
/// # Returns
///
/// A Result indicating success or failure of sending the mount request
pub fn mount(&self, source: &Path, mount_point: &Path, node_id: &str) -> Result<()> {
info!("Sending mount request to daemon");
self.daemon_tx.send(DaemonMessage::Mount {
/// Mount a filesystem at the specified path
pub fn mount(&self, source: &Path, target: &Path, node_id: &str) -> Result<()> {
self.message_tx.send(SessionMessage::Mount {
source: source.to_path_buf(),
target: mount_point.to_path_buf(),
target: target.to_path_buf(),
node_id: node_id.to_string(),
})?;
Ok(())
}

/// Requests the daemon to unmount a filesystem.
///
/// # Arguments
///
/// * `path` - The path to unmount
///
/// # Returns
///
/// A Result indicating success or failure of sending the unmount request
/// Bind a source path to a target path
pub fn bind(&self, source: &Path, target: &Path, mode: crate::modules::namespace::BindMode) -> Result<()> {
self.message_tx.send(SessionMessage::Bind {
source: source.to_path_buf(),
target: target.to_path_buf(),
mode,
})?;
Ok(())
}

/// Unmount a filesystem at the specified path
pub fn unmount(&self, path: &Path) -> Result<()> {
let abs_path = fs::canonicalize(path)?;

info!("Sending unmount request to daemon");
self.daemon_tx.send(DaemonMessage::Unmount {
path: abs_path,
self.message_tx.send(SessionMessage::Unmount {
path: path.to_path_buf(),
})?;
Ok(())
}

/// Shuts down the session and its daemon process.
///
/// This method:
/// 1. Sends a shutdown message to the daemon
/// 2. Waits for the daemon thread to complete
/// 3. Cleans up resources
///
/// # Returns
///
/// A Result indicating success or failure of the shutdown process
/// Shutdown the session
pub fn shutdown(mut self) -> Result<()> {
info!("Shutting down session");
self.daemon_tx.send(DaemonMessage::Shutdown)?;
if let Ok(thread) = std::mem::replace(&mut self.daemon_thread, thread::spawn(|| {})).join() {
Ok(())
} else {
Err(anyhow!("Failed to join daemon thread"))
}
self.message_tx.send(SessionMessage::Shutdown)?;
let thread = std::mem::replace(&mut self.message_thread, thread::spawn(|| {}));
thread.join().map_err(|_| anyhow::anyhow!("Failed to join message thread"))?;
Ok(())
}
}

impl Drop for Session {
fn drop(&mut self) {
self.is_running.store(false, Ordering::SeqCst);
if let Err(e) = self.daemon_tx.send(DaemonMessage::Shutdown) {
if let Err(e) = self.message_tx.send(SessionMessage::Shutdown) {
error!("Error sending shutdown message: {}", e);
}
}
Expand Down

0 comments on commit 63b026a

Please sign in to comment.