From 1810eca676f37414a0ab0a4a07290e2f89034197 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20=C5=81asocha?= Date: Wed, 25 Jan 2023 16:51:23 +0100 Subject: [PATCH 1/5] Adds possibility to configure failure flag --- lib/win32/service.rb | 20 ++++++++++++++++++-- lib/win32/windows/structs.rb | 6 ++++++ 2 files changed, 24 insertions(+), 2 deletions(-) diff --git a/lib/win32/service.rb b/lib/win32/service.rb index af8c5aa..1ba5bb3 100644 --- a/lib/win32/service.rb +++ b/lib/win32/service.rb @@ -272,6 +272,7 @@ class Service # * failure_command => nil, # * failure_actions => nil, # * failure_delay => 0 + # * failure_flag => nil # # Example: # @@ -317,6 +318,7 @@ def initialize(options = {}) "failure_command" => nil, "failure_actions" => nil, "failure_delay" => 0, + "failure_flag" => nil, "host" => nil, "service_name" => nil, } @@ -396,7 +398,7 @@ def initialize(options = {}) end if opts["failure_reset_period"] || opts["failure_reboot_message"] || - opts["failure_command"] || opts["failure_actions"] + opts["failure_command"] || opts["failure_actions"] || opts["failure_flag"] self.class.configure_failure_actions(handle_scs, opts) end ensure @@ -425,6 +427,7 @@ def initialize(options = {}) # * failure_reboot_message # * failure_command # * failure_actions + # * failure_flag # * failure_delay # # Examples: @@ -475,6 +478,7 @@ def self.configure(options = {}) "failure_command" => nil, "failure_actions" => nil, "failure_delay" => 0, + "failure_flag" => nil, "service_name" => nil, "host" => nil, "delayed_start" => false, @@ -579,7 +583,7 @@ def self.configure(options = {}) end if opts["failure_reset_period"] || opts["failure_reboot_message"] || - opts["failure_command"] || opts["failure_actions"] + opts["failure_command"] || opts["failure_actions"] || opts["failure_flag"] configure_failure_actions(handle_scs, opts) end ensure @@ -1397,6 +1401,18 @@ def self.configure_failure_actions(handle_scs, opts) close_service_handle(handle_scs) raise SystemCallError.new("ChangeServiceConfig2", error) end + + unless opts["failure_flag"].nil? + sfaf = SERVICE_FAILURE_ACTIONS_FLAG.new + sfaf[:fFailureActionsOnNonCrashFailures] = opts["failure_flag"] ? 1 : 0 + bool = ChangeServiceConfig2( + handle_scs, + SERVICE_CONFIG_FAILURE_ACTIONS_FLAG, + sfaf + ) + + FFI.raise_windows_error("ChangeServiceConfig2") unless bool + end end # Returns a human readable string indicating the action type. diff --git a/lib/win32/windows/structs.rb b/lib/win32/windows/structs.rb index 48ceaf1..c29d7e8 100644 --- a/lib/win32/windows/structs.rb +++ b/lib/win32/windows/structs.rb @@ -90,6 +90,12 @@ class SERVICE_FAILURE_ACTIONS < FFI::Struct ) end + class SERVICE_FAILURE_ACTIONS_FLAG < FFI::Struct + layout( + :fFailureActionsOnNonCrashFailures, :int + ) + end + class SERVICE_TABLE_ENTRY < FFI::Struct layout( :lpServiceName, :pointer, From 3a541f60ed9e06f4f23487d14438ced60c555f5f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20=C5=81asocha?= Date: Wed, 25 Jan 2023 22:13:22 +0100 Subject: [PATCH 2/5] Make it work with booleans --- lib/win32/service.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/win32/service.rb b/lib/win32/service.rb index 1ba5bb3..514609d 100644 --- a/lib/win32/service.rb +++ b/lib/win32/service.rb @@ -398,7 +398,7 @@ def initialize(options = {}) end if opts["failure_reset_period"] || opts["failure_reboot_message"] || - opts["failure_command"] || opts["failure_actions"] || opts["failure_flag"] + opts["failure_command"] || opts["failure_actions"] || !opts["failure_flag"].nil? self.class.configure_failure_actions(handle_scs, opts) end ensure @@ -583,7 +583,7 @@ def self.configure(options = {}) end if opts["failure_reset_period"] || opts["failure_reboot_message"] || - opts["failure_command"] || opts["failure_actions"] || opts["failure_flag"] + opts["failure_command"] || opts["failure_actions"] || !opts["failure_flag"].nil? configure_failure_actions(handle_scs, opts) end ensure From d9d1842fbc7b7621440f1393f59bbdfcfb1e6aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20=C5=81asocha?= Date: Wed, 25 Jan 2023 22:14:12 +0100 Subject: [PATCH 3/5] Add nonzero win32 exit code when stopping service in ensure block --- lib/win32/daemon.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/win32/daemon.rb b/lib/win32/daemon.rb index b2ff825..eab43ca 100644 --- a/lib/win32/daemon.rb +++ b/lib/win32/daemon.rb @@ -180,9 +180,13 @@ class Daemon # Main loop for the service. while WaitForSingleObject(@@hStopCompletedEvent, 1000) != WAIT_OBJECT_0 end - ensure + # Stop the service. SetTheServiceStatus.call(SERVICE_STOPPED, NO_ERROR, 0, 0) + ensure + # Stop the service. + # This ensures that if the main thread crashes and Service_Main thread is terminated, we will set nonzero win32exitCode + SetTheServiceStatus.call(SERVICE_STOPPED, 1, 0, 0) end end From 9b582e21eb000c11bc95e66c536d37bf371fe3af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Rafa=C5=82=20=C5=81asocha?= Date: Wed, 25 Jan 2023 22:15:25 +0100 Subject: [PATCH 4/5] Bump version so that it's different from rubygems one --- lib/win32/windows/version.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/win32/windows/version.rb b/lib/win32/windows/version.rb index 8a098e4..9aa478e 100644 --- a/lib/win32/windows/version.rb +++ b/lib/win32/windows/version.rb @@ -1,6 +1,6 @@ module Win32 class Service - VERSION = "2.3.2".freeze + VERSION = "2.3.2sf".freeze MAJOR, MINOR, TINY = VERSION.split(".") end end From 50826973ee1b887777cd8f2f666eb61419a306e6 Mon Sep 17 00:00:00 2001 From: Guillaume Petit Date: Fri, 15 Sep 2023 16:34:09 +0200 Subject: [PATCH 5/5] trick to get the service started in no time, don't ask why, you got to believe in it --- lib/win32/daemon.rb | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/win32/daemon.rb b/lib/win32/daemon.rb index eab43ca..5fd5c50 100644 --- a/lib/win32/daemon.rb +++ b/lib/win32/daemon.rb @@ -269,6 +269,10 @@ def mainloop events.put_pointer(FFI::Pointer.size, FFI::Pointer.new(@@hStartEvent)) while (index = WaitForMultipleObjects(2, events, 0, 1000)) == WAIT_TIMEOUT + # applying some magic to delay things, as somehow this while loop + # can enter some kind of deadlock state without this, leading + # to our service not being able to boot + sleep(0.1) end if index == WAIT_FAILED