mirror of https://github.com/winsw/winsw
commit
6280a688ed
|
@ -426,7 +426,7 @@ namespace winsw
|
|||
_wrapperServiceStatus.waitHint = effectiveWaitHint;
|
||||
// WriteEvent("SignalShutdownPending " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
||||
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOP_PENDING;
|
||||
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
||||
Advapi32.SetServiceStatus(handle, _wrapperServiceStatus);
|
||||
}
|
||||
|
||||
private void SignalShutdownComplete()
|
||||
|
@ -435,7 +435,7 @@ namespace winsw
|
|||
_wrapperServiceStatus.checkPoint++;
|
||||
// WriteEvent("SignalShutdownComplete " + wrapperServiceStatus.checkPoint + ":" + wrapperServiceStatus.waitHint);
|
||||
_wrapperServiceStatus.currentState = (int)State.SERVICE_STOPPED;
|
||||
Advapi32.SetServiceStatus(handle, ref _wrapperServiceStatus);
|
||||
Advapi32.SetServiceStatus(handle, _wrapperServiceStatus);
|
||||
}
|
||||
|
||||
private void StartProcess(Process processToStart, string arguments, string executable, LogHandler? logHandler, bool redirectStdin)
|
||||
|
@ -796,8 +796,7 @@ namespace winsw
|
|||
|
||||
// run restart from another process group. see README.md for why this is useful.
|
||||
|
||||
STARTUPINFO si = default;
|
||||
bool result = Kernel32.CreateProcess(null, descriptor.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, 0x200/*CREATE_NEW_PROCESS_GROUP*/, IntPtr.Zero, null, ref si, out _);
|
||||
bool result = Kernel32.CreateProcess(null, descriptor.ExecutablePath + " restart", IntPtr.Zero, IntPtr.Zero, false, Kernel32.CREATE_NEW_PROCESS_GROUP, IntPtr.Zero, null, default, out _);
|
||||
if (!result)
|
||||
{
|
||||
throw new Exception("Failed to invoke restart: " + Marshal.GetLastWin32Error());
|
||||
|
|
|
@ -1,59 +0,0 @@
|
|||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
namespace winsw
|
||||
{
|
||||
public static class SigIntHelper
|
||||
{
|
||||
private const string KERNEL32 = "kernel32.dll";
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true)]
|
||||
private static extern bool AttachConsole(uint dwProcessId);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true)]
|
||||
private static extern bool FreeConsole();
|
||||
|
||||
[DllImport(KERNEL32)]
|
||||
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate? HandlerRoutine, bool Add);
|
||||
|
||||
// Delegate type to be used as the Handler Routine for SCCH
|
||||
private delegate bool ConsoleCtrlDelegate(CtrlTypes CtrlType);
|
||||
|
||||
// Enumerated type for the control messages sent to the handler routine
|
||||
private enum CtrlTypes : uint
|
||||
{
|
||||
CTRL_C_EVENT = 0,
|
||||
CTRL_BREAK_EVENT,
|
||||
CTRL_CLOSE_EVENT,
|
||||
CTRL_LOGOFF_EVENT = 5,
|
||||
CTRL_SHUTDOWN_EVENT
|
||||
}
|
||||
|
||||
[DllImport(KERNEL32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);
|
||||
|
||||
/// <summary>
|
||||
/// Uses the native funciton "AttachConsole" to attach the thread to the executing process to try to trigger a CTRL_C event (SIGINT). If the application
|
||||
/// doesn't honor the event and shut down gracefully, the. wait period will time out after 15 seconds.
|
||||
/// </summary>
|
||||
/// <param name="process">The process to attach to and send the SIGINT</param>
|
||||
/// <returns>True if the process shut down successfully to the SIGINT, false if it did not.</returns>
|
||||
public static bool SendSIGINTToProcess(Process process, TimeSpan shutdownTimeout)
|
||||
{
|
||||
if (AttachConsole((uint)process.Id))
|
||||
{
|
||||
// Disable Ctrl-C handling for our program
|
||||
SetConsoleCtrlHandler(null, true);
|
||||
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
||||
|
||||
process.WaitForExit((int)shutdownTimeout.TotalMilliseconds);
|
||||
|
||||
return process.HasExited;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -35,7 +35,7 @@ namespace winsw.Native
|
|||
public void Dispose()
|
||||
{
|
||||
if (_handle != IntPtr.Zero)
|
||||
Advapi32.CloseServiceHandle(_handle);
|
||||
_ = Advapi32.CloseServiceHandle(_handle);
|
||||
_handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
@ -71,7 +71,7 @@ namespace winsw.Native
|
|||
Marshal.StructureToPtr(actions[i], new IntPtr(sfa.lpsaActions.ToInt64() + i * len), false);
|
||||
}
|
||||
|
||||
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_FAILURE_ACTIONS, ref sfa))
|
||||
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_FAILURE_ACTIONS, sfa))
|
||||
throw new Exception("Failed to change the failure actions", new Win32Exception());
|
||||
}
|
||||
finally
|
||||
|
@ -94,7 +94,7 @@ namespace winsw.Native
|
|||
fDelayedAutostart = enabled
|
||||
};
|
||||
|
||||
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, ref settings))
|
||||
if (!Advapi32.ChangeServiceConfig2(Handle, SERVICE_CONFIG_INFOLEVEL.SERVICE_CONFIG_DELAYED_AUTO_START_INFO, settings))
|
||||
{
|
||||
throw new Exception("Failed to change the DelayedAutoStart setting", new Win32Exception());
|
||||
}
|
||||
|
@ -103,7 +103,7 @@ namespace winsw.Native
|
|||
public void Dispose()
|
||||
{
|
||||
if (Handle != IntPtr.Zero)
|
||||
Advapi32.CloseServiceHandle(Handle);
|
||||
_ = Advapi32.CloseServiceHandle(Handle);
|
||||
Handle = IntPtr.Zero;
|
||||
}
|
||||
}
|
||||
|
@ -174,19 +174,16 @@ namespace winsw.Native
|
|||
// StringBuilder and size for the domain name
|
||||
StringBuilder domainName = new StringBuilder();
|
||||
int nameSize = 0;
|
||||
// account-type variable for lookup
|
||||
int accountType = 0;
|
||||
|
||||
// get required buffer size
|
||||
Advapi32.LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize, ref accountType);
|
||||
_ = Advapi32.LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, out _);
|
||||
|
||||
// allocate buffers
|
||||
domainName = new StringBuilder(nameSize);
|
||||
sid = Marshal.AllocHGlobal(sidSize);
|
||||
|
||||
// lookup the SID for the account
|
||||
bool result = Advapi32.LookupAccountName(string.Empty, accountName, sid, ref sidSize, domainName, ref nameSize,
|
||||
ref accountType);
|
||||
bool result = Advapi32.LookupAccountName(null, accountName, sid, ref sidSize, domainName, ref nameSize, out _);
|
||||
|
||||
// say what you're doing
|
||||
// Console.WriteLine("LookupAccountName result = " + result);
|
||||
|
@ -195,13 +192,11 @@ namespace winsw.Native
|
|||
|
||||
if (!result)
|
||||
{
|
||||
winErrorCode = Kernel32.GetLastError();
|
||||
winErrorCode = Marshal.GetLastWin32Error();
|
||||
Console.WriteLine("LookupAccountName failed: " + winErrorCode);
|
||||
}
|
||||
else
|
||||
{
|
||||
// initialize an empty unicode-string
|
||||
LSA_UNICODE_STRING systemName = default;
|
||||
// combine all policies
|
||||
const int access = (int)(
|
||||
LSA_AccessPolicy.POLICY_AUDIT_LOG_ADMIN |
|
||||
|
@ -220,18 +215,8 @@ namespace winsw.Native
|
|||
);
|
||||
// initialize a pointer for the policy handle
|
||||
|
||||
// these attributes are not used, but LsaOpenPolicy wants them to exists
|
||||
LSA_OBJECT_ATTRIBUTES objectAttributes = new LSA_OBJECT_ATTRIBUTES
|
||||
{
|
||||
Length = 0,
|
||||
RootDirectory = IntPtr.Zero,
|
||||
Attributes = 0,
|
||||
SecurityDescriptor = IntPtr.Zero,
|
||||
SecurityQualityOfService = IntPtr.Zero
|
||||
};
|
||||
|
||||
// get a policy handle
|
||||
uint resultPolicy = Advapi32.LsaOpenPolicy(ref systemName, ref objectAttributes, access, out IntPtr policyHandle);
|
||||
uint resultPolicy = Advapi32.LsaOpenPolicy(default, default, access, out IntPtr policyHandle);
|
||||
winErrorCode = Advapi32.LsaNtStatusToWinError(resultPolicy);
|
||||
|
||||
if (winErrorCode != 0)
|
||||
|
@ -257,7 +242,7 @@ namespace winsw.Native
|
|||
Console.WriteLine("LsaAddAccountRights failed: " + winErrorCode);
|
||||
}
|
||||
|
||||
Advapi32.LsaClose(policyHandle);
|
||||
_ = Advapi32.LsaClose(policyHandle);
|
||||
}
|
||||
|
||||
Advapi32.FreeSid(sid);
|
||||
|
@ -273,52 +258,56 @@ namespace winsw.Native
|
|||
/// </summary>
|
||||
public class Advapi32
|
||||
{
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, IntPtr lpInfo);
|
||||
private const string Advapi32LibraryName = "advapi32.dll";
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_FAILURE_ACTIONS sfa);
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "ChangeServiceConfig2W")]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, in SERVICE_FAILURE_ACTIONS lpInfo);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, ref SERVICE_DELAYED_AUTO_START sfa);
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "ChangeServiceConfig2W")]
|
||||
internal static extern bool ChangeServiceConfig2(IntPtr hService, SERVICE_CONFIG_INFOLEVEL dwInfoLevel, in SERVICE_DELAYED_AUTO_START lpInfo);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
internal static extern IntPtr OpenSCManager(string? machineName, string? databaseName, uint dwAccess);
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenSCManagerW")]
|
||||
internal static extern IntPtr OpenSCManager(string? lpMachineName, string? lpDatabaseName, uint dwDesiredAccess);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "OpenServiceW")]
|
||||
internal static extern IntPtr OpenService(IntPtr hSCManager, string lpServiceName, uint dwDesiredAccess);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true)]
|
||||
internal static extern bool CloseServiceHandle(IntPtr hSCObject);
|
||||
|
||||
[DllImport("advapi32.DLL")]
|
||||
public static extern bool SetServiceStatus(IntPtr hServiceStatus, ref SERVICE_STATUS lpServiceStatus);
|
||||
[DllImport(Advapi32LibraryName)]
|
||||
public static extern bool SetServiceStatus(IntPtr hServiceStatus, in SERVICE_STATUS lpServiceStatus);
|
||||
|
||||
[DllImport("advapi32.dll", PreserveSig = true)]
|
||||
internal static extern uint LsaOpenPolicy(ref LSA_UNICODE_STRING SystemName, ref LSA_OBJECT_ATTRIBUTES ObjectAttributes, int DesiredAccess,
|
||||
[DllImport(Advapi32LibraryName)]
|
||||
internal static extern uint LsaOpenPolicy(
|
||||
in LSA_UNICODE_STRING SystemName,
|
||||
in LSA_OBJECT_ATTRIBUTES ObjectAttributes,
|
||||
int DesiredAccess,
|
||||
out IntPtr PolicyHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true, PreserveSig = true)]
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true)]
|
||||
internal static extern uint LsaAddAccountRights(IntPtr PolicyHandle, IntPtr AccountSid, LSA_UNICODE_STRING[] UserRights, uint CountOfRights);
|
||||
|
||||
[DllImport("advapi32")]
|
||||
[DllImport(Advapi32LibraryName)]
|
||||
internal static extern void FreeSid(IntPtr pSid);
|
||||
|
||||
[DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true, PreserveSig = true)]
|
||||
internal static extern bool LookupAccountName(string lpSystemName, string lpAccountName, IntPtr psid, ref int cbsid, StringBuilder domainName,
|
||||
ref int cbdomainLength, ref int use);
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "LookupAccountNameW")]
|
||||
internal static extern bool LookupAccountName(
|
||||
string? lpSystemName,
|
||||
string lpAccountName,
|
||||
IntPtr psid,
|
||||
ref int cbsid,
|
||||
StringBuilder domainName,
|
||||
ref int cbdomainLength,
|
||||
out int use);
|
||||
|
||||
[DllImport("advapi32.dll")]
|
||||
[DllImport(Advapi32LibraryName)]
|
||||
internal static extern bool IsValidSid(IntPtr pSid);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = true)]
|
||||
[DllImport(Advapi32LibraryName, SetLastError = true)]
|
||||
internal static extern uint LsaClose(IntPtr ObjectHandle);
|
||||
|
||||
[DllImport("advapi32.dll", SetLastError = false)]
|
||||
[DllImport(Advapi32LibraryName, SetLastError = false)]
|
||||
internal static extern uint LsaNtStatusToWinError(uint status);
|
||||
}
|
||||
|
||||
|
@ -584,9 +573,7 @@ namespace winsw.Native
|
|||
/// </summary>
|
||||
public int dwResetPeriod;
|
||||
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string lpRebootMsg;
|
||||
[MarshalAs(UnmanagedType.LPWStr)]
|
||||
public string lpCommand;
|
||||
public int cActions;
|
||||
public IntPtr/*SC_ACTION[]*/ lpsaActions;
|
||||
|
@ -596,7 +583,6 @@ namespace winsw.Native
|
|||
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
|
||||
public struct SERVICE_DELAYED_AUTO_START
|
||||
{
|
||||
[MarshalAs(UnmanagedType.Bool)]
|
||||
public bool fDelayedAutostart;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,24 +9,25 @@ namespace winsw.Native
|
|||
/// </summary>
|
||||
public class Kernel32
|
||||
{
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
public const uint CREATE_NEW_PROCESS_GROUP = 0x00000200;
|
||||
|
||||
private const string Kernel32LibraryName = "kernel32.dll";
|
||||
|
||||
[DllImport(Kernel32LibraryName, SetLastError = true)]
|
||||
public static extern bool SetStdHandle(int nStdHandle, SafeFileHandle handle);
|
||||
|
||||
[DllImport("kernel32.dll", SetLastError = true)]
|
||||
[DllImport(Kernel32LibraryName, SetLastError = true, CharSet = CharSet.Unicode, EntryPoint = "CreateProcessW")]
|
||||
public static extern bool CreateProcess(
|
||||
string? lpApplicationName,
|
||||
string lpCommandLine,
|
||||
string? lpCommandLine,
|
||||
IntPtr lpProcessAttributes,
|
||||
IntPtr lpThreadAttributes,
|
||||
bool bInheritHandles,
|
||||
uint dwCreationFlags,
|
||||
IntPtr lpEnvironment,
|
||||
string? lpCurrentDirectory,
|
||||
[In] ref STARTUPINFO lpStartupInfo,
|
||||
in STARTUPINFO lpStartupInfo,
|
||||
out PROCESS_INFORMATION lpProcessInformation);
|
||||
|
||||
[DllImport("kernel32.dll")]
|
||||
public static extern int GetLastError();
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
|
|
@ -2,7 +2,6 @@
|
|||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using log4net;
|
||||
using winsw.Native;
|
||||
|
||||
namespace winsw.Util
|
||||
{
|
||||
|
@ -10,15 +9,15 @@ namespace winsw.Util
|
|||
{
|
||||
private static readonly ILog Logger = LogManager.GetLogger(typeof(SigIntHelper));
|
||||
|
||||
private const string KERNEL32 = "kernel32.dll";
|
||||
private const string Kernel32LibraryName = "kernel32.dll";
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true)]
|
||||
[DllImport(Kernel32LibraryName, SetLastError = true)]
|
||||
private static extern bool AttachConsole(uint dwProcessId);
|
||||
|
||||
[DllImport(KERNEL32, SetLastError = true, ExactSpelling = true)]
|
||||
[DllImport(Kernel32LibraryName, SetLastError = true)]
|
||||
private static extern bool FreeConsole();
|
||||
|
||||
[DllImport(KERNEL32)]
|
||||
[DllImport(Kernel32LibraryName)]
|
||||
private static extern bool SetConsoleCtrlHandler(ConsoleCtrlDelegate? HandlerRoutine, bool Add);
|
||||
|
||||
// Delegate type to be used as the Handler Routine for SCCH
|
||||
|
@ -34,8 +33,7 @@ namespace winsw.Util
|
|||
CTRL_SHUTDOWN_EVENT
|
||||
}
|
||||
|
||||
[DllImport(KERNEL32)]
|
||||
[return: MarshalAs(UnmanagedType.Bool)]
|
||||
[DllImport(Kernel32LibraryName)]
|
||||
private static extern bool GenerateConsoleCtrlEvent(CtrlTypes dwCtrlEvent, uint dwProcessGroupId);
|
||||
|
||||
/// <summary>
|
||||
|
@ -49,8 +47,8 @@ namespace winsw.Util
|
|||
if (AttachConsole((uint)process.Id))
|
||||
{
|
||||
// Disable Ctrl-C handling for our program
|
||||
SetConsoleCtrlHandler(null, true);
|
||||
GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
||||
_ = SetConsoleCtrlHandler(null, true);
|
||||
_ = GenerateConsoleCtrlEvent(CtrlTypes.CTRL_C_EVENT, 0);
|
||||
|
||||
process.WaitForExit((int)shutdownTimeout.TotalMilliseconds);
|
||||
|
||||
|
@ -58,7 +56,7 @@ namespace winsw.Util
|
|||
bool success = FreeConsole();
|
||||
if (!success)
|
||||
{
|
||||
long errorCode = Kernel32.GetLastError();
|
||||
long errorCode = Marshal.GetLastWin32Error();
|
||||
Logger.Warn("Failed to detach from console. Error code: " + errorCode);
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue