131 lines
3.8 KiB
Rust
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);
|
|
}
|
|
}
|