1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
|
use windows::{
core::HSTRING,
Win32::{
Foundation,
System::Services,
},
};
lazy_static::lazy_static! {
static ref PSQL_REGEX: regex::Regex = regex::Regex::new(r#"^(?:postgresql|psql|postgres)-.*([\d\.]*)"#).unwrap();
}
pub unsafe fn ensure_postgres_started() -> windows::core::Result<()> {
let sc_manager = Services::OpenSCManagerW(
None,
None,
(Foundation::GENERIC_READ | Foundation::GENERIC_WRITE).0,
)?;
let services = list_services(sc_manager)?;
let mut psql_services =
services.into_iter().filter(|status| PSQL_REGEX.is_match(&status.name)).collect::<Vec<_>>();
match psql_services.len() {
1 => {},
0 => {
log::warn!("unable to identify an installed postgres service");
},
other => {
log::warn!("unable to identify postgres service: {other} potential matches found");
return Ok(());
},
}
let svc = psql_services.remove(0);
log::debug!("identified postgres service: {}", svc.name);
match svc.status.dwCurrentState {
Services::SERVICE_RUNNING => {
log::info!("postgres was already running, done");
return Ok(());
},
Services::SERVICE_START_PENDING => {
log::info!("postgres was already in startup, done");
return Ok(());
},
_ => {
log::info!("postgres is not running: starting it")
},
}
let service =
Services::OpenServiceW(sc_manager, &HSTRING::from(&svc.name), Services::SERVICE_START)?;
Services::StartServiceW(service, None)?;
log::info!("started postgres service");
Services::CloseServiceHandle(service)?;
Services::CloseServiceHandle(sc_manager)?;
Ok(())
}
const RESULT_SIZE: usize = size_of::<Services::ENUM_SERVICE_STATUS_PROCESSW>();
pub struct ServiceStatus {
pub display_name: String,
pub name: String,
pub status: Services::SERVICE_STATUS_PROCESS,
}
pub unsafe fn list_services(
sc_manager: Services::SC_HANDLE,
) -> windows::core::Result<Vec<ServiceStatus>> {
let mut bytes_needed: u32 = 0;
let mut services_returned: u32 = 0;
let mut resume = 0;
let mut svcs = vec![];
loop {
let mut data = [0u8; 256 * 1024];
let result = Services::EnumServicesStatusExW(
sc_manager,
Services::SC_ENUM_PROCESS_INFO,
Services::SERVICE_WIN32,
Services::SERVICE_STATE_ALL,
Some(&mut data),
&mut bytes_needed as *mut _,
&mut services_returned as *mut _,
Some(&mut resume),
None,
);
if let Err(ref e) = result
&& e.code() != Foundation::ERROR_MORE_DATA.to_hresult()
{
return result.map(|_| unreachable!());
}
let data = bytemuck::cast_slice::<u8, [u8; RESULT_SIZE]>(
&data[..services_returned as usize * RESULT_SIZE],
);
let elems = data
.into_iter()
.map(|x| core::mem::transmute::<_, Services::ENUM_SERVICE_STATUS_PROCESSW>(*x))
.map(|x| ServiceStatus {
display_name: x.lpDisplayName.to_string().unwrap(),
name: x.lpServiceName.to_string().unwrap(),
status: x.ServiceStatusProcess,
});
svcs.extend(elems);
if result.is_ok() {
break;
}
}
Ok(svcs)
}
|