Skip to content

Commit aab5b26

Browse files
committed
Merge branch 'break-apart-leaf-errors'
2 parents 3799354 + 8f1b537 commit aab5b26

File tree

5 files changed

+69
-92
lines changed

5 files changed

+69
-92
lines changed

src/lib.rs

Lines changed: 9 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -219,56 +219,20 @@ pub enum Error {
219219
InvalidStartArgument(#[error(cause)] widestring::NulError),
220220

221221
/// Invalid raw representation of [`ServiceState`].
222-
#[error(display = "Invalid service state value: {}", _0)]
223-
InvalidServiceState(u32),
224-
225-
/// Invalid raw representation of [`ServiceControl`].
226-
#[error(display = "Invalid service control value: {}", _0)]
227-
InvalidServiceControl(u32),
222+
#[error(display = "Invalid service state value")]
223+
InvalidServiceState(#[error(cause)] service::ParseRawError),
228224

229225
/// Invalid raw representation of [`ServiceStartType`].
230-
#[error(display = "Invalid service start type: {}", _0)]
231-
InvalidServiceStartType(u32),
226+
#[error(display = "Invalid service start value")]
227+
InvalidServiceStartType(#[error(cause)] service::ParseRawError),
232228

233229
/// Invalid raw representation of [`ServiceErrorControl`].
234-
#[error(display = "Invalid service error control type: {}", _0)]
235-
InvalidServiceErrorControl(u32),
236-
237-
/// Failed to send command to service Service deletion to start
238-
#[error(display = "Could not send commands to service")]
239-
ServiceControlFailed(#[error(cause)] std::io::Error),
240-
241-
/// Failed to create service
242-
#[error(display = "Could not create service")]
243-
ServiceCreateFailed(#[error(cause)] std::io::Error),
244-
245-
/// Service deletion failed
246-
#[error(display = "Could not delete service")]
247-
ServiceDeleteFailed(#[error(cause)] std::io::Error),
248-
249-
/// Failed to connect to service manager
250-
#[error(display = "Could not connect to service manager")]
251-
ServiceManagerConnectFailed(#[error(cause)] std::io::Error),
252-
253-
/// Failed to open service
254-
#[error(display = "Could not open service")]
255-
ServiceOpenFailed(#[error(cause)] std::io::Error),
256-
257-
/// Failed to query Service
258-
#[error(display = "Could not query service")]
259-
ServiceQueryFailed(#[error(cause)] std::io::Error),
260-
261-
/// Failed to register service
262-
#[error(display = "Could not register service")]
263-
ServiceRegisterFailed(#[error(cause)] std::io::Error),
264-
265-
/// Service failed to start
266-
#[error(display = "Could not start service")]
267-
ServiceStartFailed(#[error(cause)] std::io::Error),
230+
#[error(display = "Invalid service error control value")]
231+
InvalidServiceErrorControl(#[error(cause)] service::ParseRawError),
268232

269-
/// Failed to set service status
270-
#[error(display = "Could not set service status")]
271-
ServiceStatusFailed(#[error(cause)] std::io::Error),
233+
/// IO error when calling winapi
234+
#[error(display = "IO error in winapi call")]
235+
Winapi(#[error(cause)] std::io::Error),
272236
}
273237

274238
mod sc_handle;

src/service.rs

Lines changed: 51 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use winapi::shared::winerror::{ERROR_SERVICE_SPECIFIC_ERROR, NO_ERROR};
1111
use winapi::um::{winnt, winsvc};
1212

1313
use crate::sc_handle::ScHandle;
14-
use crate::{double_nul_terminated, Error, Result};
14+
use crate::{double_nul_terminated, Error};
1515

1616
bitflags::bitflags! {
1717
/// Enum describing the types of Windows services.
@@ -82,12 +82,12 @@ impl ServiceStartType {
8282
*self as u32
8383
}
8484

85-
pub fn from_raw(raw: u32) -> Result<ServiceStartType> {
85+
pub fn from_raw(raw: u32) -> Result<ServiceStartType, ParseRawError> {
8686
match raw {
8787
x if x == ServiceStartType::AutoStart.to_raw() => Ok(ServiceStartType::AutoStart),
8888
x if x == ServiceStartType::OnDemand.to_raw() => Ok(ServiceStartType::OnDemand),
8989
x if x == ServiceStartType::Disabled.to_raw() => Ok(ServiceStartType::Disabled),
90-
_ => Err(Error::InvalidServiceStartType(raw)),
90+
_ => Err(ParseRawError(raw)),
9191
}
9292
}
9393
}
@@ -109,13 +109,13 @@ impl ServiceErrorControl {
109109
*self as u32
110110
}
111111

112-
pub fn from_raw(raw: u32) -> Result<ServiceErrorControl> {
112+
pub fn from_raw(raw: u32) -> Result<ServiceErrorControl, ParseRawError> {
113113
match raw {
114114
x if x == ServiceErrorControl::Critical.to_raw() => Ok(ServiceErrorControl::Critical),
115115
x if x == ServiceErrorControl::Ignore.to_raw() => Ok(ServiceErrorControl::Ignore),
116116
x if x == ServiceErrorControl::Normal.to_raw() => Ok(ServiceErrorControl::Normal),
117117
x if x == ServiceErrorControl::Severe.to_raw() => Ok(ServiceErrorControl::Severe),
118-
_ => Err(Error::InvalidServiceErrorControl(raw)),
118+
_ => Err(ParseRawError(raw)),
119119
}
120120
}
121121
}
@@ -233,7 +233,12 @@ pub struct ServiceConfig {
233233
}
234234

235235
impl ServiceConfig {
236-
pub unsafe fn from_raw(raw: winsvc::QUERY_SERVICE_CONFIGW) -> Result<ServiceConfig> {
236+
/// Tries to parse a `QUERY_SERVICE_CONFIGW` into Rust [`ServiceConfig`].
237+
///
238+
/// # Errors
239+
///
240+
/// Returns an error if a field inside the `QUERY_SERVICE_CONFIGW` does not have a valid value.
241+
pub unsafe fn from_raw(raw: winsvc::QUERY_SERVICE_CONFIGW) -> crate::Result<ServiceConfig> {
237242
let dependencies = double_nul_terminated::parse_str_ptr(raw.lpDependencies)
238243
.iter()
239244
.map(ServiceDependency::from_system_identifier)
@@ -255,8 +260,10 @@ impl ServiceConfig {
255260

256261
Ok(ServiceConfig {
257262
service_type: ServiceType::from_bits_truncate(raw.dwServiceType),
258-
start_type: ServiceStartType::from_raw(raw.dwStartType)?,
259-
error_control: ServiceErrorControl::from_raw(raw.dwErrorControl)?,
263+
start_type: ServiceStartType::from_raw(raw.dwStartType)
264+
.map_err(Error::InvalidServiceStartType)?,
265+
error_control: ServiceErrorControl::from_raw(raw.dwErrorControl)
266+
.map_err(Error::InvalidServiceErrorControl)?,
260267
executable_path: PathBuf::from(
261268
WideCStr::from_ptr_str(raw.lpBinaryPathName).to_os_string(),
262269
),
@@ -287,8 +294,8 @@ pub enum ServiceControl {
287294
}
288295

289296
impl ServiceControl {
290-
pub fn from_raw(raw_value: u32) -> Result<Self> {
291-
match raw_value {
297+
pub fn from_raw(raw: u32) -> Result<Self, ParseRawError> {
298+
match raw {
292299
x if x == ServiceControl::Continue.to_raw() => Ok(ServiceControl::Continue),
293300
x if x == ServiceControl::Interrogate.to_raw() => Ok(ServiceControl::Interrogate),
294301
x if x == ServiceControl::NetBindAdd.to_raw() => Ok(ServiceControl::NetBindAdd),
@@ -300,7 +307,7 @@ impl ServiceControl {
300307
x if x == ServiceControl::Preshutdown.to_raw() => Ok(ServiceControl::Preshutdown),
301308
x if x == ServiceControl::Shutdown.to_raw() => Ok(ServiceControl::Shutdown),
302309
x if x == ServiceControl::Stop.to_raw() => Ok(ServiceControl::Stop),
303-
other => Err(Error::InvalidServiceControl(other)),
310+
_ => Err(ParseRawError(raw)),
304311
}
305312
}
306313

@@ -323,16 +330,16 @@ pub enum ServiceState {
323330
}
324331

325332
impl ServiceState {
326-
fn from_raw(raw_state: u32) -> Result<Self> {
327-
match raw_state {
333+
fn from_raw(raw: u32) -> Result<Self, ParseRawError> {
334+
match raw {
328335
x if x == ServiceState::Stopped.to_raw() => Ok(ServiceState::Stopped),
329336
x if x == ServiceState::StartPending.to_raw() => Ok(ServiceState::StartPending),
330337
x if x == ServiceState::StopPending.to_raw() => Ok(ServiceState::StopPending),
331338
x if x == ServiceState::Running.to_raw() => Ok(ServiceState::Running),
332339
x if x == ServiceState::ContinuePending.to_raw() => Ok(ServiceState::ContinuePending),
333340
x if x == ServiceState::PausePending.to_raw() => Ok(ServiceState::PausePending),
334341
x if x == ServiceState::Paused.to_raw() => Ok(ServiceState::Paused),
335-
other => Err(Error::InvalidServiceState(other)),
342+
_ => Err(ParseRawError(raw)),
336343
}
337344
}
338345

@@ -477,16 +484,19 @@ impl ServiceStatus {
477484
raw_status
478485
}
479486

480-
fn from_raw(raw_status: winsvc::SERVICE_STATUS) -> Result<Self> {
487+
/// Tries to parse a `SERVICE_STATUS` into a Rust [`ServiceStatus`].
488+
///
489+
/// # Errors
490+
///
491+
/// Returns an error if the `dwCurrentState` field does not represent a valid [`ServiceState`].
492+
fn from_raw(raw: winsvc::SERVICE_STATUS) -> Result<Self, ParseRawError> {
481493
Ok(ServiceStatus {
482-
service_type: ServiceType::from_bits_truncate(raw_status.dwServiceType),
483-
current_state: ServiceState::from_raw(raw_status.dwCurrentState)?,
484-
controls_accepted: ServiceControlAccept::from_bits_truncate(
485-
raw_status.dwControlsAccepted,
486-
),
487-
exit_code: ServiceExitCode::from(&raw_status),
488-
checkpoint: raw_status.dwCheckPoint,
489-
wait_hint: Duration::from_millis(raw_status.dwWaitHint as u64),
494+
service_type: ServiceType::from_bits_truncate(raw.dwServiceType),
495+
current_state: ServiceState::from_raw(raw.dwCurrentState)?,
496+
controls_accepted: ServiceControlAccept::from_bits_truncate(raw.dwControlsAccepted),
497+
exit_code: ServiceExitCode::from(&raw),
498+
checkpoint: raw.dwCheckPoint,
499+
wait_hint: Duration::from_millis(raw.dwWaitHint as u64),
490500
})
491501
}
492502
}
@@ -521,11 +531,11 @@ impl Service {
521531
/// # Ok(())
522532
/// # }
523533
/// ```
524-
pub fn start<S: AsRef<OsStr>>(&self, service_arguments: &[S]) -> Result<()> {
534+
pub fn start<S: AsRef<OsStr>>(&self, service_arguments: &[S]) -> crate::Result<()> {
525535
let wide_service_arguments = service_arguments
526536
.iter()
527537
.map(|s| WideCString::from_str(s).map_err(Error::InvalidStartArgument))
528-
.collect::<Result<Vec<WideCString>>>()?;
538+
.collect::<crate::Result<Vec<WideCString>>>()?;
529539

530540
let mut raw_service_arguments: Vec<*const u16> =
531541
wide_service_arguments.iter().map(|s| s.as_ptr()).collect();
@@ -539,42 +549,42 @@ impl Service {
539549
};
540550

541551
if success == 0 {
542-
Err(Error::ServiceStartFailed(io::Error::last_os_error()))
552+
Err(Error::Winapi(io::Error::last_os_error()))
543553
} else {
544554
Ok(())
545555
}
546556
}
547557

548558
/// Stop the service.
549-
pub fn stop(&self) -> Result<ServiceStatus> {
559+
pub fn stop(&self) -> crate::Result<ServiceStatus> {
550560
self.send_control_command(ServiceControl::Stop)
551561
}
552562

553563
/// Get the service status from the system.
554-
pub fn query_status(&self) -> Result<ServiceStatus> {
564+
pub fn query_status(&self) -> crate::Result<ServiceStatus> {
555565
let mut raw_status = unsafe { mem::zeroed::<winsvc::SERVICE_STATUS>() };
556566
let success = unsafe {
557567
winsvc::QueryServiceStatus(self.service_handle.raw_handle(), &mut raw_status)
558568
};
559569
if success == 0 {
560-
Err(Error::ServiceQueryFailed(io::Error::last_os_error()))
570+
Err(Error::Winapi(io::Error::last_os_error()))
561571
} else {
562-
ServiceStatus::from_raw(raw_status)
572+
ServiceStatus::from_raw(raw_status).map_err(Error::InvalidServiceState)
563573
}
564574
}
565575

566576
/// Delete the service from system registry.
567-
pub fn delete(self) -> Result<()> {
577+
pub fn delete(self) -> crate::Result<()> {
568578
let success = unsafe { winsvc::DeleteService(self.service_handle.raw_handle()) };
569579
if success == 0 {
570-
Err(Error::ServiceDeleteFailed(io::Error::last_os_error()))
580+
Err(Error::Winapi(io::Error::last_os_error()))
571581
} else {
572582
Ok(())
573583
}
574584
}
575585

576586
/// Get the service config from the system.
577-
pub fn query_config(&self) -> Result<ServiceConfig> {
587+
pub fn query_config(&self) -> crate::Result<ServiceConfig> {
578588
// As per docs, the maximum size of data buffer used by QueryServiceConfigW is 8K
579589
let mut data = [0u8; 8096];
580590
let mut bytes_written: u32 = 0;
@@ -589,7 +599,7 @@ impl Service {
589599
};
590600

591601
if success == 0 {
592-
Err(Error::ServiceQueryFailed(io::Error::last_os_error()))
602+
Err(Error::Winapi(io::Error::last_os_error()))
593603
} else {
594604
unsafe {
595605
let raw_config = data.as_ptr() as *const winsvc::QUERY_SERVICE_CONFIGW;
@@ -599,7 +609,7 @@ impl Service {
599609
}
600610

601611
/// Private helper to send the control commands to the system.
602-
fn send_control_command(&self, command: ServiceControl) -> Result<ServiceStatus> {
612+
fn send_control_command(&self, command: ServiceControl) -> crate::Result<ServiceStatus> {
603613
let mut raw_status = unsafe { mem::zeroed::<winsvc::SERVICE_STATUS>() };
604614
let success = unsafe {
605615
winsvc::ControlService(
@@ -610,13 +620,17 @@ impl Service {
610620
};
611621

612622
if success == 0 {
613-
Err(Error::ServiceControlFailed(io::Error::last_os_error()))
623+
Err(Error::Winapi(io::Error::last_os_error()))
614624
} else {
615-
ServiceStatus::from_raw(raw_status)
625+
ServiceStatus::from_raw(raw_status).map_err(Error::InvalidServiceState)
616626
}
617627
}
618628
}
619629

630+
#[derive(err_derive::Error, Debug)]
631+
#[error(display = "Invalid integer value for the target type: {}", _0)]
632+
pub struct ParseRawError(u32);
633+
620634
#[cfg(test)]
621635
mod tests {
622636
use super::*;

src/service_control_handler.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,11 @@ impl ServiceStatusHandle {
1818
}
1919

2020
/// Report the new service status to the system.
21-
pub fn set_service_status(&self, service_status: ServiceStatus) -> Result<()> {
21+
pub fn set_service_status(&self, service_status: ServiceStatus) -> crate::Result<()> {
2222
let mut raw_service_status = service_status.to_raw();
2323
let result = unsafe { winsvc::SetServiceStatus(self.0, &mut raw_service_status) };
2424
if result == 0 {
25-
Err(Error::ServiceStatusFailed(io::Error::last_os_error()))
25+
Err(Error::Winapi(io::Error::last_os_error()))
2626
} else {
2727
Ok(())
2828
}
@@ -115,7 +115,7 @@ where
115115
if status_handle.is_null() {
116116
// Release the `event_handler` in case of an error.
117117
let _: Box<F> = unsafe { Box::from_raw(context) };
118-
Err(Error::ServiceRegisterFailed(io::Error::last_os_error()))
118+
Err(Error::Winapi(io::Error::last_os_error()))
119119
} else {
120120
Ok(ServiceStatusHandle::from_handle(status_handle))
121121
}

src/service_dispatcher.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ pub fn start<T: AsRef<OsStr>>(
106106

107107
let result = unsafe { winsvc::StartServiceCtrlDispatcherW(service_table.as_ptr()) };
108108
if result == 0 {
109-
Err(Error::ServiceStartFailed(io::Error::last_os_error()))
109+
Err(Error::Winapi(io::Error::last_os_error()))
110110
} else {
111111
Ok(())
112112
}

src/service_manager.rs

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,9 +55,7 @@ impl ServiceManager {
5555
};
5656

5757
if handle.is_null() {
58-
Err(Error::ServiceManagerConnectFailed(
59-
io::Error::last_os_error(),
60-
))
58+
Err(Error::Winapi(io::Error::last_os_error()))
6159
} else {
6260
Ok(ServiceManager {
6361
manager_handle: unsafe { ScHandle::new(handle) },
@@ -161,7 +159,8 @@ impl ServiceManager {
161159
launch_command_buffer.push(wide);
162160
}
163161

164-
let launch_command = WideCString::from_wide_str(launch_command_buffer).unwrap();
162+
let launch_command = WideCString::from_wide_str(launch_command_buffer)
163+
.expect("launch_command_buffer invalidly formatted");
165164

166165
let dependency_identifiers: Vec<OsString> = service_info
167166
.dependencies
@@ -194,7 +193,7 @@ impl ServiceManager {
194193
};
195194

196195
if service_handle.is_null() {
197-
Err(Error::ServiceCreateFailed(io::Error::last_os_error()))
196+
Err(Error::Winapi(io::Error::last_os_error()))
198197
} else {
199198
Ok(Service::new(unsafe { ScHandle::new(service_handle) }))
200199
}
@@ -234,7 +233,7 @@ impl ServiceManager {
234233
};
235234

236235
if service_handle.is_null() {
237-
Err(Error::ServiceOpenFailed(io::Error::last_os_error()))
236+
Err(Error::Winapi(io::Error::last_os_error()))
238237
} else {
239238
Ok(Service::new(unsafe { ScHandle::new(service_handle) }))
240239
}

0 commit comments

Comments
 (0)