mirror of
https://github.com/Cyrix126/gupaxx.git
synced 2024-12-22 22:59:27 +00:00
helper: start xmrig with sudo, implement [restart_xmrig()]
This commit takes care of correctly starting [sudo] with XMRig as a command argument. The frontend [restart_*] function is also implemented. In XMRig's case, the threads will sleep [3/5 seconds] before [starting/restarting] so that [sudo] has time to open its STDIN. This prevents premature inputs and outputting the password to the STDOUT.
This commit is contained in:
parent
d30fb5563b
commit
a3802ef4f7
4 changed files with 84 additions and 58 deletions
|
@ -232,7 +232,7 @@ impl Gupax {
|
||||||
// Saved [Tab]
|
// Saved [Tab]
|
||||||
ui.group(|ui| {
|
ui.group(|ui| {
|
||||||
let height = ui.available_height()/2.0;
|
let height = ui.available_height()/2.0;
|
||||||
let width = (width/5.0)-(SPACE*1.8);
|
let width = (width/5.0)-(SPACE*1.93);
|
||||||
ui.horizontal(|ui| {
|
ui.horizontal(|ui| {
|
||||||
if ui.add_sized([width, height], SelectableLabel::new(self.tab == Tab::About, "About")).on_hover_text(GUPAX_TAB_ABOUT).clicked() { self.tab = Tab::About; }
|
if ui.add_sized([width, height], SelectableLabel::new(self.tab == Tab::About, "About")).on_hover_text(GUPAX_TAB_ABOUT).clicked() { self.tab = Tab::About; }
|
||||||
ui.separator();
|
ui.separator();
|
||||||
|
|
111
src/helper.rs
111
src/helper.rs
|
@ -43,8 +43,11 @@ use std::{
|
||||||
time::*,
|
time::*,
|
||||||
thread,
|
thread,
|
||||||
};
|
};
|
||||||
|
use crate::{
|
||||||
|
constants::*,
|
||||||
|
SudoState,
|
||||||
|
};
|
||||||
use serde::{Serialize,Deserialize};
|
use serde::{Serialize,Deserialize};
|
||||||
use crate::constants::*;
|
|
||||||
use num_format::{Buffer,Locale};
|
use num_format::{Buffer,Locale};
|
||||||
use log::*;
|
use log::*;
|
||||||
|
|
||||||
|
@ -558,29 +561,32 @@ impl Helper {
|
||||||
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// // The "restart frontend" to a "frontend" function.
|
// The "restart frontend" to a "frontend" function.
|
||||||
// // Basically calls to kill the current p2pool, waits a little, then starts the below function in a a new thread, then exit.
|
// Basically calls to kill the current xmrig, waits a little, then starts the below function in a a new thread, then exit.
|
||||||
// pub fn restart_p2pool(helper: &Arc<Mutex<Self>>, state: &crate::disk::P2pool, path: &std::path::PathBuf) {
|
pub fn restart_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
||||||
// info!("P2Pool | Attempting to restart...");
|
info!("XMRig | Attempting to restart...");
|
||||||
// helper.lock().unwrap().p2pool.lock().unwrap().signal = ProcessSignal::Restart;
|
helper.lock().unwrap().xmrig.lock().unwrap().signal = ProcessSignal::Restart;
|
||||||
// helper.lock().unwrap().p2pool.lock().unwrap().state = ProcessState::Middle;
|
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
||||||
//
|
|
||||||
// let helper = Arc::clone(&helper);
|
|
||||||
// let state = state.clone();
|
|
||||||
// let path = path.clone();
|
|
||||||
// // This thread lives to wait, start p2pool then die.
|
|
||||||
// thread::spawn(move || {
|
|
||||||
// while helper.lock().unwrap().p2pool.lock().unwrap().is_alive() {
|
|
||||||
// warn!("P2Pool | Want to restart but process is still alive, waiting...");
|
|
||||||
// thread::sleep(SECOND);
|
|
||||||
// }
|
|
||||||
// // Ok, process is not alive, start the new one!
|
|
||||||
// Self::start_p2pool(&helper, &state, &path);
|
|
||||||
// });
|
|
||||||
// info!("P2Pool | Restart ... OK");
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub fn start_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) {
|
let helper = Arc::clone(&helper);
|
||||||
|
let state = state.clone();
|
||||||
|
let path = path.clone();
|
||||||
|
// This thread lives to wait, start xmrig then die.
|
||||||
|
thread::spawn(move || {
|
||||||
|
while helper.lock().unwrap().xmrig.lock().unwrap().is_alive() {
|
||||||
|
warn!("XMRig | Want to restart but process is still alive, waiting...");
|
||||||
|
thread::sleep(SECOND);
|
||||||
|
}
|
||||||
|
// We should reallllly sleep so all the components have a chance to catch up.
|
||||||
|
// Premature starting could miss the [sudo] STDIN timeframe and output it to STDOUT.
|
||||||
|
thread::sleep(std::time::Duration::from_secs(3));
|
||||||
|
// Ok, process is not alive, start the new one!
|
||||||
|
Self::start_xmrig(&helper, &state, &path, sudo);
|
||||||
|
});
|
||||||
|
info!("XMRig | Restart ... OK");
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_xmrig(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
||||||
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
helper.lock().unwrap().xmrig.lock().unwrap().state = ProcessState::Middle;
|
||||||
|
|
||||||
let args = Self::build_xmrig_args_and_mutate_img(helper, state, path);
|
let args = Self::build_xmrig_args_and_mutate_img(helper, state, path);
|
||||||
|
@ -596,7 +602,7 @@ impl Helper {
|
||||||
let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_xmrig);
|
let priv_api = Arc::clone(&helper.lock().unwrap().priv_api_xmrig);
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
thread::spawn(move || {
|
thread::spawn(move || {
|
||||||
Self::spawn_xmrig_watchdog(process, gui_api, pub_api, priv_api, args, path);
|
Self::spawn_xmrig_watchdog(process, gui_api, pub_api, priv_api, args, path, sudo);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -606,6 +612,12 @@ impl Helper {
|
||||||
pub fn build_xmrig_args_and_mutate_img(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> Vec<String> {
|
pub fn build_xmrig_args_and_mutate_img(helper: &Arc<Mutex<Self>>, state: &crate::disk::Xmrig, path: &std::path::PathBuf) -> Vec<String> {
|
||||||
let mut args = Vec::with_capacity(500);
|
let mut args = Vec::with_capacity(500);
|
||||||
let path = path.clone();
|
let path = path.clone();
|
||||||
|
// The actual binary we're executing is [sudo], technically
|
||||||
|
// the XMRig path is just an argument to sudo, so add it.
|
||||||
|
// Before that though, add the ["--prompt"] flag and set it
|
||||||
|
// to emptyness so that it doesn't show up in the output.
|
||||||
|
args.push(r#"--prompt="#.to_string());
|
||||||
|
args.push(path.display().to_string());
|
||||||
|
|
||||||
// [Simple]
|
// [Simple]
|
||||||
if state.simple {
|
if state.simple {
|
||||||
|
@ -666,7 +678,7 @@ impl Helper {
|
||||||
|
|
||||||
// The P2Pool watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works.
|
// The P2Pool watchdog. Spawns 1 OS thread for reading a PTY (STDOUT+STDERR), and combines the [Child] with a PTY so STDIN actually works.
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn spawn_xmrig_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubXmrigApi>>, pub_api: Arc<Mutex<PubXmrigApi>>, priv_api: Arc<Mutex<PrivXmrigApi>>, args: Vec<String>, mut path: std::path::PathBuf) {
|
async fn spawn_xmrig_watchdog(process: Arc<Mutex<Process>>, gui_api: Arc<Mutex<PubXmrigApi>>, pub_api: Arc<Mutex<PubXmrigApi>>, priv_api: Arc<Mutex<PrivXmrigApi>>, args: Vec<String>, mut path: std::path::PathBuf, sudo: Arc<Mutex<SudoState>>) {
|
||||||
// 1a. Create PTY
|
// 1a. Create PTY
|
||||||
let pty = portable_pty::native_pty_system();
|
let pty = portable_pty::native_pty_system();
|
||||||
let pair = pty.openpty(portable_pty::PtySize {
|
let pair = pty.openpty(portable_pty::PtySize {
|
||||||
|
@ -676,12 +688,15 @@ impl Helper {
|
||||||
pixel_height: 0,
|
pixel_height: 0,
|
||||||
}).unwrap();
|
}).unwrap();
|
||||||
// 1b. Create command
|
// 1b. Create command
|
||||||
let mut cmd = portable_pty::CommandBuilder::new(path.as_path());
|
let mut cmd = portable_pty::CommandBuilder::new("sudo");
|
||||||
cmd.args(args);
|
cmd.args(args);
|
||||||
cmd.cwd(path.as_path().parent().unwrap());
|
cmd.cwd(path.as_path().parent().unwrap());
|
||||||
// 1c. Create child
|
// 1c. Create child
|
||||||
let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
|
let child_pty = Arc::new(Mutex::new(pair.slave.spawn_command(cmd).unwrap()));
|
||||||
|
|
||||||
|
// 1d. Wait a bit for [sudo].
|
||||||
|
thread::sleep(std::time::Duration::from_secs(3));
|
||||||
|
|
||||||
// 2. Set process state
|
// 2. Set process state
|
||||||
let mut lock = process.lock().unwrap();
|
let mut lock = process.lock().unwrap();
|
||||||
lock.state = ProcessState::Alive;
|
lock.state = ProcessState::Alive;
|
||||||
|
@ -690,6 +705,11 @@ impl Helper {
|
||||||
lock.child = Some(Arc::clone(&child_pty));
|
lock.child = Some(Arc::clone(&child_pty));
|
||||||
let reader = pair.master.try_clone_reader().unwrap(); // Get STDOUT/STDERR before moving the PTY
|
let reader = pair.master.try_clone_reader().unwrap(); // Get STDOUT/STDERR before moving the PTY
|
||||||
lock.stdin = Some(pair.master);
|
lock.stdin = Some(pair.master);
|
||||||
|
|
||||||
|
// 3. Input [sudo] pass, wipe, then drop.
|
||||||
|
writeln!(lock.stdin.as_mut().unwrap(), "{}", sudo.lock().unwrap().pass);
|
||||||
|
SudoState::wipe(&sudo);
|
||||||
|
drop(sudo);
|
||||||
drop(lock);
|
drop(lock);
|
||||||
|
|
||||||
// 3. Spawn PTY read thread
|
// 3. Spawn PTY read thread
|
||||||
|
@ -712,37 +732,38 @@ impl Helper {
|
||||||
// Set timer
|
// Set timer
|
||||||
let now = Instant::now();
|
let now = Instant::now();
|
||||||
|
|
||||||
// Check SIGNAL
|
// Stop on [Stop/Restart] SIGNAL
|
||||||
if process.lock().unwrap().signal == ProcessSignal::Stop {
|
let signal = process.lock().unwrap().signal;
|
||||||
|
if signal == ProcessSignal::Stop || signal == ProcessSignal::Restart {
|
||||||
child_pty.lock().unwrap().kill();
|
child_pty.lock().unwrap().kill();
|
||||||
let exit_status = match child_pty.lock().unwrap().wait() {
|
let exit_status = match child_pty.lock().unwrap().wait() {
|
||||||
Ok(e) => {
|
Ok(e) => {
|
||||||
|
let mut process = process.lock().unwrap();
|
||||||
if e.success() {
|
if e.success() {
|
||||||
process.lock().unwrap().state = ProcessState::Dead; "Successful"
|
if process.signal == ProcessSignal::Stop { process.state = ProcessState::Dead; }
|
||||||
|
"Successful"
|
||||||
} else {
|
} else {
|
||||||
process.lock().unwrap().state = ProcessState::Failed; "Failed"
|
if process.signal == ProcessSignal::Stop { process.state = ProcessState::Failed; }
|
||||||
|
"Failed"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
_ => { process.lock().unwrap().state = ProcessState::Failed; "Unknown Error" },
|
_ => {
|
||||||
|
let mut process = process.lock().unwrap();
|
||||||
|
if process.signal == ProcessSignal::Stop { process.state = ProcessState::Failed; }
|
||||||
|
"Unknown Error"
|
||||||
|
},
|
||||||
};
|
};
|
||||||
let uptime = HumanTime::into_human(start.elapsed());
|
let uptime = HumanTime::into_human(start.elapsed());
|
||||||
info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
|
info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
|
||||||
writeln!(gui_api.lock().unwrap().output, "{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
|
writeln!(gui_api.lock().unwrap().output, "{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
|
||||||
process.lock().unwrap().signal = ProcessSignal::None;
|
let mut process = process.lock().unwrap();
|
||||||
|
match process.signal {
|
||||||
|
ProcessSignal::Stop => process.signal = ProcessSignal::None,
|
||||||
|
ProcessSignal::Restart => process.state = ProcessState::Waiting,
|
||||||
|
_ => (),
|
||||||
|
}
|
||||||
break
|
break
|
||||||
// Check RESTART
|
// Check if the process secretly died without us knowing :)
|
||||||
} else if process.lock().unwrap().signal == ProcessSignal::Restart {
|
|
||||||
child_pty.lock().unwrap().kill();
|
|
||||||
let exit_status = match child_pty.lock().unwrap().wait() {
|
|
||||||
Ok(e) => if e.success() { "Successful" } else { "Failed" },
|
|
||||||
_ => "Unknown Error",
|
|
||||||
};
|
|
||||||
let uptime = HumanTime::into_human(start.elapsed());
|
|
||||||
info!("XMRig | Stopped ... Uptime was: [{}], Exit status: [{}]", uptime, exit_status);
|
|
||||||
writeln!(gui_api.lock().unwrap().output, "{}\nXMRig stopped | Uptime: [{}] | Exit status: [{}]\n{}\n\n\n\n", HORI_CONSOLE, uptime, exit_status, HORI_CONSOLE);
|
|
||||||
process.lock().unwrap().state = ProcessState::Waiting;
|
|
||||||
break
|
|
||||||
// Check if the process is secretly died without us knowing :)
|
|
||||||
} else if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
|
} else if let Ok(Some(code)) = child_pty.lock().unwrap().try_wait() {
|
||||||
let exit_status = match code.success() {
|
let exit_status = match code.success() {
|
||||||
true => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
|
true => { process.lock().unwrap().state = ProcessState::Dead; "Successful" },
|
||||||
|
|
|
@ -965,7 +965,7 @@ impl eframe::App for App {
|
||||||
if ui.add_sized([box_width, height], Button::new(RichText::new("👁").color(color))).on_hover_text(PASSWORD_HIDE).clicked() { sudo.hide = !sudo.hide; }
|
if ui.add_sized([box_width, height], Button::new(RichText::new("👁").color(color))).on_hover_text(PASSWORD_HIDE).clicked() { sudo.hide = !sudo.hide; }
|
||||||
});
|
});
|
||||||
if esc || ui.add_sized([width, height*4.0], Button::new("Leave")).clicked() { self.error_state.reset(); };
|
if esc || ui.add_sized([width, height*4.0], Button::new("Leave")).clicked() { self.error_state.reset(); };
|
||||||
// If [test_sudo()] finished, reset sudo state + error state.
|
// If [test_sudo()] finished, reset error state.
|
||||||
if sudo.success {
|
if sudo.success {
|
||||||
self.error_state.reset();
|
self.error_state.reset();
|
||||||
}
|
}
|
||||||
|
@ -1164,8 +1164,8 @@ impl eframe::App for App {
|
||||||
});
|
});
|
||||||
} else if self.xmrig.lock().unwrap().is_alive() {
|
} else if self.xmrig.lock().unwrap().is_alive() {
|
||||||
if ui.add_sized([width, height], Button::new("⟲")).on_hover_text("Restart XMRig").clicked() {
|
if ui.add_sized([width, height], Button::new("⟲")).on_hover_text("Restart XMRig").clicked() {
|
||||||
// self.error_state.ask_sudo(&self.sudo);
|
self.sudo.lock().unwrap().signal = ProcessSignal::Restart;
|
||||||
// Helper::restart_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path);
|
self.error_state.ask_sudo(&self.sudo);
|
||||||
}
|
}
|
||||||
if ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig").clicked() {
|
if ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig").clicked() {
|
||||||
Helper::stop_xmrig(&self.helper);
|
Helper::stop_xmrig(&self.helper);
|
||||||
|
@ -1179,8 +1179,8 @@ impl eframe::App for App {
|
||||||
ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig");
|
ui.add_sized([width, height], Button::new("⏹")).on_hover_text("Stop XMRig");
|
||||||
});
|
});
|
||||||
if ui.add_sized([width, height], Button::new("⏺")).on_hover_text("Start XMRig").clicked() {
|
if ui.add_sized([width, height], Button::new("⏺")).on_hover_text("Start XMRig").clicked() {
|
||||||
|
self.sudo.lock().unwrap().signal = ProcessSignal::Start;
|
||||||
self.error_state.ask_sudo(&self.sudo);
|
self.error_state.ask_sudo(&self.sudo);
|
||||||
// Helper::start_xmrig(&self.helper, &self.state.xmrig, &self.state.gupax.absolute_xmrig_path);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
21
src/sudo.rs
21
src/sudo.rs
|
@ -42,6 +42,7 @@ pub struct SudoState {
|
||||||
pub hide: bool, // Are we hiding the password?
|
pub hide: bool, // Are we hiding the password?
|
||||||
pub msg: String, // The message shown to the user if unsuccessful
|
pub msg: String, // The message shown to the user if unsuccessful
|
||||||
pub pass: String, // The actual password wrapped in a [SecretVec]
|
pub pass: String, // The actual password wrapped in a [SecretVec]
|
||||||
|
pub signal: ProcessSignal, // Main GUI will set this depending on if we want [Start] or [Restart]
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SudoState {
|
impl SudoState {
|
||||||
|
@ -52,6 +53,7 @@ impl SudoState {
|
||||||
hide: true,
|
hide: true,
|
||||||
msg: "".to_string(),
|
msg: "".to_string(),
|
||||||
pass: String::with_capacity(256),
|
pass: String::with_capacity(256),
|
||||||
|
signal: ProcessSignal::None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -61,15 +63,15 @@ impl SudoState {
|
||||||
let mut state = state.lock().unwrap();
|
let mut state = state.lock().unwrap();
|
||||||
state.testing = false;
|
state.testing = false;
|
||||||
state.success = false;
|
state.success = false;
|
||||||
|
state.signal = ProcessSignal::None;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Swaps the pass with another 256-capacity String,
|
// Swaps the pass with another 256-capacity String,
|
||||||
// zeroizes the old and drops it.
|
// zeroizes the old and drops it.
|
||||||
pub fn wipe(state: &Arc<Mutex<Self>>) {
|
pub fn wipe(state: &Arc<Mutex<Self>>) {
|
||||||
let mut new = String::with_capacity(256);
|
let mut new = String::with_capacity(256);
|
||||||
let mut state = state.lock().unwrap();
|
|
||||||
// new is now == old, and vice-versa.
|
// new is now == old, and vice-versa.
|
||||||
std::mem::swap(&mut new, &mut state.pass);
|
std::mem::swap(&mut new, &mut state.lock().unwrap().pass);
|
||||||
// we're wiping & dropping the old pass here.
|
// we're wiping & dropping the old pass here.
|
||||||
new.zeroize();
|
new.zeroize();
|
||||||
std::mem::drop(new);
|
std::mem::drop(new);
|
||||||
|
@ -127,7 +129,6 @@ impl SudoState {
|
||||||
Ok(Some(code)) => if code.success() {
|
Ok(Some(code)) => if code.success() {
|
||||||
info!("Sudo | Password ... OK!");
|
info!("Sudo | Password ... OK!");
|
||||||
state.lock().unwrap().success = true;
|
state.lock().unwrap().success = true;
|
||||||
crate::helper::Helper::start_xmrig(&helper, &xmrig, &path); //----------- Start XMRig
|
|
||||||
break
|
break
|
||||||
},
|
},
|
||||||
Ok(None) => {
|
Ok(None) => {
|
||||||
|
@ -143,12 +144,16 @@ impl SudoState {
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let mut lock = state.lock().unwrap();
|
|
||||||
if !lock.success { lock.msg = "Incorrect password!".to_string(); }
|
|
||||||
drop(lock);
|
|
||||||
sudo.kill();
|
sudo.kill();
|
||||||
Self::wipe(&state);
|
if state.lock().unwrap().success {
|
||||||
state.lock().unwrap().testing = false;
|
match state.lock().unwrap().signal {
|
||||||
|
ProcessSignal::Restart => crate::helper::Helper::restart_xmrig(&helper, &xmrig, &path, Arc::clone(&state)),
|
||||||
|
_ => crate::helper::Helper::start_xmrig(&helper, &xmrig, &path, Arc::clone(&state)),
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
state.lock().unwrap().msg = "Incorrect password!".to_string();
|
||||||
|
Self::wipe(&state);
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue