Page Menu
Home
Phorge
Search
Configure Global Search
Log In
Files
F2880355
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Flag For Later
Award Token
Size
13 KB
Referenced Files
None
Subscribers
None
View Options
diff --git a/src/cc/process.cc b/src/cc/process.cc
index 266f363..bd52079 100644
--- a/src/cc/process.cc
+++ b/src/cc/process.cc
@@ -1,54 +1,73 @@
#include "../include/process.h"
#include <fcntl.h>
#include <unistd.h>
+#include <sys/wait.h>
+#include <signal.h>
#include <iostream>
namespace process {
+volatile sig_atomic_t childExitStatus = 0;
+
+void sigchld_handler(int signo) {
+ (void)signo;
+ int status;
+ while (waitpid(-1, &status, WNOHANG) > 0) {
+ childExitStatus = status;
+ }
+}
+
void Runner::New(const std::string &name, const std::string &logPath) {
std::string stdoutFileName = logPath + "/" + name + "-out.log";
std::string stderrFileName = logPath + "/" + name + "-error.log";
stdout_fd = open(stdoutFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
stderr_fd = open(stderrFileName.c_str(), O_WRONLY | O_CREAT | O_APPEND, 0644);
+
+ struct sigaction sa;
+ sa.sa_handler = sigchld_handler;
+ sigemptyset(&sa.sa_mask);
+ sa.sa_flags = SA_RESTART | SA_NOCLDSTOP;
+ if (sigaction(SIGCHLD, &sa, NULL) == -1) {
+ std::cerr << "[PMC] (cc) Error setting up SIGCHLD handler\n";
+ }
}
Runner::~Runner() {
if (stdout_fd != -1) {
close(stdout_fd);
}
if (stderr_fd != -1) {
close(stderr_fd);
}
}
int64_t Runner::Run(const std::string &command) {
pid_t pid = fork();
if (pid == -1) {
std::cerr << "[PMC] (cc) Unable to fork\n";
return -1;
} else if (pid == 0) {
setsid();
close(STDIN_FILENO);
close(STDOUT_FILENO);
close(STDERR_FILENO);
dup2(stdout_fd, STDOUT_FILENO);
dup2(stderr_fd, STDERR_FILENO);
if (execl("/bin/bash", "bash", "-c", command.c_str(), (char *)nullptr) == -1) {
std::cerr << "[PMC] (cc) Unable to execute the command\n";
exit(EXIT_FAILURE);
}
} else {
+ close(stdout_fd);
+ close(stderr_fd);
+
return pid;
}
- close(stdout_fd);
- close(stderr_fd);
-
return -1;
-}}
-
+}}
diff --git a/src/daemon/fork.rs b/src/daemon/fork.rs
index 6b19a40..73c0504 100644
--- a/src/daemon/fork.rs
+++ b/src/daemon/fork.rs
@@ -1,46 +1,62 @@
use global_placeholders::global;
-use std::ffi::CString;
+use std::{ffi::CString, process::exit};
pub enum Fork {
Parent(libc::pid_t),
Child,
}
pub fn chdir() -> Result<libc::c_int, i32> {
let dir = CString::new(global!("pmc.base")).expect("CString::new failed");
let res = unsafe { libc::chdir(dir.as_ptr()) };
match res {
-1 => Err(-1),
res => Ok(res),
}
}
pub fn fork() -> Result<Fork, i32> {
let res = unsafe { libc::fork() };
match res {
-1 => Err(-1),
0 => Ok(Fork::Child),
res => Ok(Fork::Parent(res)),
}
}
pub fn setsid() -> Result<libc::pid_t, i32> {
let res = unsafe { libc::setsid() };
match res {
-1 => Err(-1),
res => Ok(res),
}
}
pub fn close_fd() -> Result<(), i32> {
match unsafe { libc::close(0) } {
-1 => Err(-1),
_ => match unsafe { libc::close(1) } {
-1 => Err(-1),
_ => match unsafe { libc::close(2) } {
-1 => Err(-1),
_ => Ok(()),
},
},
}
}
+
+pub fn daemon(nochdir: bool, noclose: bool) -> Result<Fork, i32> {
+ match fork() {
+ Ok(Fork::Parent(_)) => exit(0),
+ Ok(Fork::Child) => setsid().and_then(|_| {
+ if !nochdir {
+ chdir()?;
+ }
+ if !noclose {
+ close_fd()?;
+ }
+ fork()
+ }),
+ Err(n) => Err(n),
+ }
+}
diff --git a/src/daemon/mod.rs b/src/daemon/mod.rs
index 173f388..21c826c 100644
--- a/src/daemon/mod.rs
+++ b/src/daemon/mod.rs
@@ -1,79 +1,69 @@
mod fork;
mod pid;
use crate::helpers;
use crate::process::Runner;
-use fork::{chdir, close_fd, fork, setsid, Fork};
+use fork::{daemon, Fork};
use global_placeholders::global;
use macros_rs::crashln;
-use std::{fs, thread::sleep, time::Duration};
+use std::{fs, process, thread::sleep, time::Duration};
extern "C" fn handle_termination_signal(_: libc::c_int) {
pid::remove();
- unsafe {
- libc::_exit(0);
- }
+ unsafe { libc::_exit(0) }
}
-pub fn start<F: Fn(i32)>(commands: F) {
+pub fn restore() {
+ println!("{} Spawning PMC daemon with pmc_home={}", *helpers::SUCCESS, global!("pmc.base"));
if pid::exists() {
match fs::read_to_string(global!("pmc.pid")) {
Ok(pid) => {
if let Ok(pid) = pid.trim().parse::<i32>() {
- match pid::running(pid) {
- true => commands(pid),
- false => pid::remove(),
+ if !pid::running(pid) {
+ pid::remove()
+ } else {
+ crashln!("{} The daemon is already running with PID {pid}", *helpers::FAIL)
}
}
}
Err(err) => crashln!("{} Failed to read existing PID from file: {err}", *helpers::FAIL),
}
}
- println!("{} Spawning PMC daemon with pmc_home={}", *helpers::SUCCESS, global!("pmc.base"));
- match fork() {
+ println!("{} PMC Successfully daemonized", *helpers::SUCCESS);
+ match daemon(false, false) {
+ Ok(Fork::Parent(_)) => {}
Ok(Fork::Child) => {
unsafe { libc::signal(libc::SIGTERM, handle_termination_signal as usize) };
+ pid::write(process::id());
- match setsid() {
- Ok(pid) => {
- log::trace!("Child process started with PID {}", pid);
- println!("{} PMC Successfully daemonized", *helpers::SUCCESS);
- pid::write(pid);
- }
- Err(err) => crashln!("{} setsid() failed with error: {}", *helpers::FAIL, err),
- }
-
- // if let Err(err) = chdir().and_then(|_| close_fd()).and_then(|_| fork().map_err(|err| err)) {
- // crashln!("{} Daemon creation failed with error: {}", *helpers::FAIL, err);
- // }
+ loop {
+ let runner = Runner::new();
+ if !runner.list().is_empty() {
+ for (id, item) in runner.list() {
+ let mut runner = Runner::new();
+ let name = &Some(item.name.clone());
- match chdir().and_then(|_| fork().map_err(|err| err)) {
- Ok(_status) => loop {
- let runner = Runner::new();
- if !runner.list().is_empty() {
- for (id, item) in runner.list() {
- let mut runner = Runner::new();
- let name = &Some(item.name.clone());
+ println!("name: {}, pid:{}, running: {}", item.name, item.pid, item.running);
- if let Ok(id) = id.trim().parse::<usize>() {
- if item.running {
- if !pid::running(item.pid as i32) {
- println!("restarted {}", item.pid);
- runner.restart(id, name);
- }
+ if let Ok(id) = id.trim().parse::<usize>() {
+ if item.running {
+ println!("running_pid: {}, id: {id}", pid::running(item.pid as i32));
+ if !pid::running(item.pid as i32) {
+ println!("restarted {}", item.pid);
+ runner.restart(id, name);
}
}
}
}
+ }
- sleep(Duration::from_secs(5));
- },
- Err(err) => crashln!("{} Daemon creation failed with error: {}", *helpers::FAIL, err),
+ sleep(Duration::from_secs(1));
}
}
- Ok(Fork::Parent(pid)) => commands(pid),
- Err(err) => crashln!("{} Daemon creation failed with error code: {}", *helpers::FAIL, err),
+ Err(err) => {
+ crashln!("{} Daemon creation failed with code {err}", *helpers::FAIL)
+ }
}
}
diff --git a/src/daemon/pid.rs b/src/daemon/pid.rs
index 883d794..e28aa8b 100644
--- a/src/daemon/pid.rs
+++ b/src/daemon/pid.rs
@@ -1,20 +1,20 @@
use crate::helpers;
use global_placeholders::global;
use macros_rs::crashln;
use std::fs;
pub fn exists() -> bool { fs::metadata(global!("pmc.pid")).is_ok() }
pub fn running(pid: i32) -> bool { unsafe { libc::kill(pid, 0) == 0 } }
-pub fn write(pid: i32) {
+pub fn write(pid: u32) {
if let Err(err) = fs::write(global!("pmc.pid"), pid.to_string()) {
crashln!("{} Failed to write PID to file: {}", *helpers::FAIL, err);
}
}
pub fn remove() {
log::debug!("Stale PID file detected. Removing the PID file.");
if let Err(err) = fs::remove_file(global!("pmc.pid")) {
crashln!("{} Failed to remove PID file: {}", *helpers::FAIL, err);
}
}
diff --git a/src/main.rs b/src/main.rs
index f19d315..c53ec3a 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,143 +1,136 @@
mod cli;
mod daemon;
mod file;
mod globals;
mod helpers;
mod process;
mod structs;
use crate::file::Exists;
use crate::structs::Args;
use clap::{Parser, Subcommand};
use clap_verbosity_flag::Verbosity;
use global_placeholders::global;
use macros_rs::{str, string};
-use std::process::exit;
fn validate_id_script(s: &str) -> Result<Args, String> {
if let Ok(id) = s.parse::<usize>() {
Ok(Args::Id(id))
} else {
Ok(Args::Script(s.to_owned()))
}
}
#[derive(Parser)]
#[command(version = str!(cli::get_version(false)))]
struct Cli {
#[command(subcommand)]
command: Commands,
#[clap(flatten)]
verbose: Verbosity,
}
#[derive(Subcommand)]
enum Daemon {
/// Start all processes
StartAll,
/// Stop all processes
StopAll,
/// Reset process index
ResetIndex,
/// Restore daemon
Restore,
/// Check daemon
Health,
}
// add pmc restore command
#[derive(Subcommand)]
enum Commands {
/// Start/Restart a process
#[command(alias = "restart")]
Start {
#[arg(long, help = "process name")]
name: Option<String>,
#[clap(value_parser = validate_id_script)]
args: Option<Args>,
},
/// Stop/Kill a process
#[command(alias = "kill")]
Stop { id: usize },
/// Stop then remove a process
#[command(alias = "rm")]
Remove { id: usize },
/// Get env of a process
#[command(alias = "cmdline")]
Env { id: usize },
/// Get information of a process
#[command(alias = "info")]
Details { id: usize },
/// List all processes
#[command(alias = "ls")]
List {
#[arg(long, default_value_t = string!(""), help = "format output")]
format: String,
},
/// Get logs from a process
Logs {
id: usize,
#[arg(long, default_value_t = 15, help = "")]
lines: usize,
},
/// Daemon management
Daemon {
#[command(subcommand)]
command: Daemon,
},
}
fn main() {
globals::init();
let cli = Cli::parse();
let mut env = env_logger::Builder::new();
env.filter_level(cli.verbose.log_level_filter()).init();
if !Exists::folder(global!("pmc.logs")).unwrap() {
std::fs::create_dir_all(global!("pmc.logs")).unwrap();
log::info!("Created PMC log directory");
}
- daemon::start(move |pid| {
- log::trace!("Parent process started with PID {pid}");
-
- match &cli.command {
- Commands::Start { name, args } => cli::start(name, args),
- Commands::Stop { id } => cli::stop(id),
- Commands::Remove { id } => cli::remove(id),
- Commands::Env { id } => cli::env(id),
- Commands::Details { id } => cli::info(id),
- Commands::List { format } => cli::list(format),
- Commands::Logs { id, lines } => cli::logs(id, lines),
- Commands::Daemon { command } => match command {
- Daemon::StartAll => {}
- Daemon::StopAll => {}
- Daemon::ResetIndex => {}
- Daemon::Restore => {}
- Daemon::Health => {}
- },
- };
-
- exit(0);
- });
+ match &cli.command {
+ Commands::Start { name, args } => cli::start(name, args),
+ Commands::Stop { id } => cli::stop(id),
+ Commands::Remove { id } => cli::remove(id),
+ Commands::Env { id } => cli::env(id),
+ Commands::Details { id } => cli::info(id),
+ Commands::List { format } => cli::list(format),
+ Commands::Logs { id, lines } => cli::logs(id, lines),
+ Commands::Daemon { command } => match command {
+ Daemon::StartAll => {}
+ Daemon::StopAll => {}
+ Daemon::ResetIndex => {}
+ Daemon::Restore => daemon::restore(),
+ Daemon::Health => {}
+ },
+ };
}
#[cxx::bridge]
pub mod service {
unsafe extern "C++" {
include!("pmc/src/include/process.h");
include!("pmc/src/include/bridge.h");
pub fn stop(pid: i64) -> i64;
pub fn run(name: &str, log_path: &str, command: &str) -> i64;
}
}
File Metadata
Details
Attached
Mime Type
text/x-diff
Expires
Thu, Mar 19, 10:17 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
506485
Default Alt Text
(13 KB)
Attached To
Mode
rPMC Process Management Controller
Attached
Detach File
Event Timeline
Log In to Comment