Files
SXP-Service-watcher/src/util.rs
2025-09-29 17:25:59 +02:00

131 lines
3.8 KiB
Rust

use std::{ptr::null_mut, time::Duration};
use winapi::{
shared::minwindef::DWORD,
um::{
errhandlingapi::GetLastError,
winsvc::{
CloseServiceHandle, ControlService, OpenSCManagerW, OpenServiceW, QueryServiceStatus, StartServiceW, SC_HANDLE__, SC_MANAGER_CONNECT, SERVICE_CONTROL_STOP, SERVICE_QUERY_STATUS, SERVICE_START, SERVICE_STOP
},
},
};
use widestring::U16CString;
const SERVICE_STATUS_RUNNING: u32 = 0x00000004;
const SERVICE_STATUS_STOPPED: u32 = 0x00000001;
fn open_sc_manager(desired_access: DWORD) -> Result<*mut SC_HANDLE__, DWORD> {
let sc_manager_handle = unsafe { OpenSCManagerW(null_mut(), null_mut(), desired_access) };
if sc_manager_handle.is_null() {
Err(unsafe { GetLastError() })
} else {
Ok(sc_manager_handle)
}
}
fn open_service(
sc_manager_handle: *mut SC_HANDLE__,
service_name: &str,
desired_access: DWORD,
) -> Result<*mut SC_HANDLE__, DWORD> {
let service_name_wstr = U16CString::from_str(service_name).unwrap();
let service_handle = unsafe {
OpenServiceW(
sc_manager_handle,
service_name_wstr.as_ptr(),
desired_access,
)
};
if service_handle.is_null() {
Err(unsafe { GetLastError() })
} else {
Ok(service_handle)
}
}
fn start_service(service_handle: *mut SC_HANDLE__) -> Result<(), DWORD> {
let result = unsafe { StartServiceW(service_handle, 0, null_mut()) };
if result == 0 {
Err(unsafe { GetLastError() })
} else {
Ok(())
}
}
fn stop_service(service_handle: *mut SC_HANDLE__) -> Result<(), DWORD> {
let mut service_status = unsafe { std::mem::zeroed() };
let result = unsafe {
ControlService(
service_handle,
SERVICE_CONTROL_STOP,
&mut service_status,
)
};
if result == 0 {
Err(unsafe { GetLastError() })
} else {
Ok(())
}
}
fn query_service_status(service_handle: *mut SC_HANDLE__) -> Result<DWORD, DWORD> {
let mut service_status = unsafe { std::mem::zeroed() };
let result = unsafe { QueryServiceStatus(service_handle, &mut service_status) };
if result == 0 {
Err(unsafe { GetLastError() })
} else {
Ok(service_status.dwCurrentState)
}
}
pub fn restart_service(service_name: String) {
let sc_manager_handle = open_sc_manager(SC_MANAGER_CONNECT).unwrap();
let service_handle = open_service(
sc_manager_handle,
service_name.as_str(),
SERVICE_QUERY_STATUS | SERVICE_START | SERVICE_STOP,
)
.unwrap();
let service_status_res = query_service_status(service_handle);
if let Err(e) = service_status_res {
error!("Failed to query service status. Error code: {e}");
return;
}
let service_status = service_status_res.unwrap();
if service_status == SERVICE_STATUS_RUNNING {
// Stop the service
match stop_service(service_handle) {
Ok(_) => info!("Service stopped successfully."),
Err(error) => info!("Failed to stop service. Error: {}", error),
}
info!("Waiting for service being stopped successfully");
std::thread::sleep(Duration::from_secs(10));
// Start the service
match start_service(service_handle) {
Ok(_) => info!("Service started successfully."),
Err(error) => info!("Failed to start service. Error: {}", error),
}
}
if service_status == SERVICE_STATUS_STOPPED {
// Start the service
match start_service(service_handle) {
Ok(_) => info!("Service started successfully."),
Err(error) => info!("Failed to start service. Error: {}", error),
}
}
// Close the service and SCM handles
unsafe {
CloseServiceHandle(service_handle);
CloseServiceHandle(sc_manager_handle);
}
}