mirror of https://github.com/winsw/winsw
Merge 1df29079af
into 6cf303c1d3
commit
42519c8220
|
@ -5,7 +5,7 @@ using static WinSW.Native.HandleApis;
|
||||||
namespace WinSW.Native
|
namespace WinSW.Native
|
||||||
{
|
{
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
internal readonly ref struct Handle
|
internal readonly struct Handle : IDisposable
|
||||||
{
|
{
|
||||||
private readonly IntPtr handle;
|
private readonly IntPtr handle;
|
||||||
|
|
||||||
|
|
|
@ -34,12 +34,20 @@ namespace WinSW.Native
|
||||||
int processInformationLength,
|
int processInformationLength,
|
||||||
IntPtr returnLength = default);
|
IntPtr returnLength = default);
|
||||||
|
|
||||||
|
[DllImport(Libraries.Kernel32)]
|
||||||
|
internal static extern Handle OpenProcess(ProcessAccess desiredAccess, bool inheritHandle, int processId);
|
||||||
|
|
||||||
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
[DllImport(Libraries.Advapi32, SetLastError = true)]
|
||||||
internal static extern bool OpenProcessToken(
|
internal static extern bool OpenProcessToken(
|
||||||
IntPtr processHandle,
|
IntPtr processHandle,
|
||||||
TokenAccessLevels desiredAccess,
|
TokenAccessLevels desiredAccess,
|
||||||
out Handle tokenHandle);
|
out Handle tokenHandle);
|
||||||
|
|
||||||
|
internal enum ProcessAccess : uint
|
||||||
|
{
|
||||||
|
QueryInformation = 0x0400,
|
||||||
|
}
|
||||||
|
|
||||||
internal enum PROCESSINFOCLASS
|
internal enum PROCESSINFOCLASS
|
||||||
{
|
{
|
||||||
ProcessBasicInformation = 0,
|
ProcessBasicInformation = 0,
|
||||||
|
|
|
@ -26,7 +26,11 @@ namespace WinSW.Util
|
||||||
{
|
{
|
||||||
foreach (var child in GetChildren(process))
|
foreach (var child in GetChildren(process))
|
||||||
{
|
{
|
||||||
StopProcessTree(child, stopTimeout, stopParentProcessFirst);
|
using (child.Key)
|
||||||
|
using (child.Value)
|
||||||
|
{
|
||||||
|
StopProcessTree(child.Key, stopTimeout, stopParentProcessFirst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -36,7 +40,11 @@ namespace WinSW.Util
|
||||||
{
|
{
|
||||||
foreach (var child in GetChildren(process))
|
foreach (var child in GetChildren(process))
|
||||||
{
|
{
|
||||||
StopProcessTree(child, stopTimeout, stopParentProcessFirst);
|
using (child.Key)
|
||||||
|
using (child.Value)
|
||||||
|
{
|
||||||
|
StopProcessTree(child.Key, stopTimeout, stopParentProcessFirst);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -95,47 +103,53 @@ namespace WinSW.Util
|
||||||
Logger.Debug($"Process {process.Id} has already exited.");
|
Logger.Debug($"Process {process.Id} has already exited.");
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe List<Process> GetChildren(Process process)
|
// The handle is to keep a reference to the process.
|
||||||
|
private static unsafe List<KeyValuePair<Process, Handle>> GetChildren(Process process)
|
||||||
{
|
{
|
||||||
var startTime = process.StartTime;
|
var startTime = process.StartTime;
|
||||||
int processId = process.Id;
|
int processId = process.Id;
|
||||||
|
|
||||||
var children = new List<Process>();
|
var children = new List<KeyValuePair<Process, Handle>>();
|
||||||
|
|
||||||
foreach (var other in Process.GetProcesses())
|
foreach (var other in Process.GetProcesses())
|
||||||
{
|
{
|
||||||
|
var handle = OpenProcess(ProcessAccess.QueryInformation, false, other.Id);
|
||||||
|
if (handle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
goto Next;
|
||||||
|
}
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (other.StartTime <= startTime)
|
if (other.StartTime <= startTime)
|
||||||
{
|
{
|
||||||
goto Next;
|
goto Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
var handle = other.Handle;
|
|
||||||
|
|
||||||
if (NtQueryInformationProcess(
|
|
||||||
handle,
|
|
||||||
PROCESSINFOCLASS.ProcessBasicInformation,
|
|
||||||
out var information,
|
|
||||||
sizeof(PROCESS_BASIC_INFORMATION)) != 0)
|
|
||||||
{
|
|
||||||
goto Next;
|
|
||||||
}
|
|
||||||
|
|
||||||
if ((int)information.InheritedFromUniqueProcessId == processId)
|
|
||||||
{
|
|
||||||
Logger.Debug($"Found child process {other.Id}.");
|
|
||||||
children.Add(other);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
Next:
|
|
||||||
other.Dispose();
|
|
||||||
}
|
}
|
||||||
catch (Exception e) when (e is InvalidOperationException || e is Win32Exception)
|
catch (Exception e) when (e is InvalidOperationException || e is Win32Exception)
|
||||||
{
|
{
|
||||||
other.Dispose();
|
goto Next;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (NtQueryInformationProcess(
|
||||||
|
handle,
|
||||||
|
PROCESSINFOCLASS.ProcessBasicInformation,
|
||||||
|
out var information,
|
||||||
|
sizeof(PROCESS_BASIC_INFORMATION)) != 0)
|
||||||
|
{
|
||||||
|
goto Next;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)information.InheritedFromUniqueProcessId == processId)
|
||||||
|
{
|
||||||
|
Logger.Debug($"Found child process {other.Id}.");
|
||||||
|
children.Add(new(other, handle));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Next:
|
||||||
|
other.Dispose();
|
||||||
|
handle.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
return children;
|
return children;
|
||||||
|
|
|
@ -10,6 +10,9 @@ namespace WinSW.Plugins
|
||||||
private const string Kernel32 = "kernel32.dll";
|
private const string Kernel32 = "kernel32.dll";
|
||||||
private const string NTDll = "ntdll.dll";
|
private const string NTDll = "ntdll.dll";
|
||||||
|
|
||||||
|
[DllImport(Kernel32)]
|
||||||
|
internal static extern bool CloseHandle(IntPtr objectHandle);
|
||||||
|
|
||||||
[DllImport(Kernel32)]
|
[DllImport(Kernel32)]
|
||||||
internal static extern int IsWow64Process(IntPtr hProcess, out int Wow64Process);
|
internal static extern int IsWow64Process(IntPtr hProcess, out int Wow64Process);
|
||||||
|
|
||||||
|
@ -53,6 +56,14 @@ namespace WinSW.Plugins
|
||||||
long BufferSize,
|
long BufferSize,
|
||||||
long NumberOfBytesRead = default);
|
long NumberOfBytesRead = default);
|
||||||
|
|
||||||
|
[DllImport(Kernel32)]
|
||||||
|
internal static extern IntPtr OpenProcess(ProcessAccess desiredAccess, bool inheritHandle, int processId);
|
||||||
|
|
||||||
|
internal enum ProcessAccess : uint
|
||||||
|
{
|
||||||
|
QueryInformation = 0x0400,
|
||||||
|
}
|
||||||
|
|
||||||
internal enum PROCESSINFOCLASS
|
internal enum PROCESSINFOCLASS
|
||||||
{
|
{
|
||||||
ProcessBasicInformation = 0,
|
ProcessBasicInformation = 0,
|
||||||
|
|
|
@ -268,39 +268,54 @@ namespace WinSW.Plugins
|
||||||
|
|
||||||
// Ensure the process references the service
|
// Ensure the process references the service
|
||||||
string expectedEnvVarName = WinSWSystem.EnvVarNameServiceId;
|
string expectedEnvVarName = WinSWSystem.EnvVarNameServiceId;
|
||||||
string? affiliatedServiceId = ReadEnvironmentVariable(proc.Handle, expectedEnvVarName);
|
|
||||||
if (affiliatedServiceId is null && this.CheckWinSWEnvironmentVariable)
|
|
||||||
{
|
|
||||||
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
|
|
||||||
+ "The process has not been started by WinSW, hence it won't be terminated.");
|
|
||||||
|
|
||||||
|
var processHandle = OpenProcess(ProcessAccess.QueryInformation, false, pid);
|
||||||
|
if (processHandle == IntPtr.Zero)
|
||||||
|
{
|
||||||
|
Logger.Warn("Cannot get process handle of PID=" + pid + ". Assuming that the process has not been started by WinSW.");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the service ID value
|
try
|
||||||
if (this.CheckWinSWEnvironmentVariable && !this.ServiceId.Equals(affiliatedServiceId))
|
|
||||||
{
|
{
|
||||||
Logger.Warn("The process " + pid + " has been started by Windows service with ID='" + affiliatedServiceId + "'. "
|
string? affiliatedServiceId = ReadEnvironmentVariable(processHandle, expectedEnvVarName);
|
||||||
+ "It is another service (current service id is '" + this.ServiceId + "'), hence the process won't be terminated.");
|
if (affiliatedServiceId is null && this.CheckWinSWEnvironmentVariable)
|
||||||
return;
|
{
|
||||||
}
|
Logger.Warn("The process " + pid + " has no " + expectedEnvVarName + " environment variable defined. "
|
||||||
|
+ "The process has not been started by WinSW, hence it won't be terminated.");
|
||||||
|
|
||||||
// Kill the runaway process
|
return;
|
||||||
var bldr = new StringBuilder("Stopping the runaway process (pid=");
|
}
|
||||||
bldr.Append(pid);
|
|
||||||
bldr.Append(") and its children. Environment was ");
|
// Check the service ID value
|
||||||
if (!this.CheckWinSWEnvironmentVariable)
|
if (this.CheckWinSWEnvironmentVariable && !this.ServiceId.Equals(affiliatedServiceId))
|
||||||
|
{
|
||||||
|
Logger.Warn("The process " + pid + " has been started by Windows service with ID='" + affiliatedServiceId + "'. "
|
||||||
|
+ "It is another service (current service id is '" + this.ServiceId + "'), hence the process won't be terminated.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Kill the runaway process
|
||||||
|
var bldr = new StringBuilder("Stopping the runaway process (pid=");
|
||||||
|
bldr.Append(pid);
|
||||||
|
bldr.Append(") and its children. Environment was ");
|
||||||
|
if (!this.CheckWinSWEnvironmentVariable)
|
||||||
|
{
|
||||||
|
bldr.Append("not ");
|
||||||
|
}
|
||||||
|
|
||||||
|
bldr.Append("checked, affiliated service ID: ");
|
||||||
|
bldr.Append(affiliatedServiceId ?? "undefined");
|
||||||
|
bldr.Append(", process to kill: ");
|
||||||
|
bldr.Append(proc);
|
||||||
|
|
||||||
|
Logger.Warn(bldr.ToString());
|
||||||
|
ProcessHelper.StopProcessTree(proc, this.StopTimeout, this.StopParentProcessFirst);
|
||||||
|
}
|
||||||
|
finally
|
||||||
{
|
{
|
||||||
bldr.Append("not ");
|
_ = CloseHandle(processHandle);
|
||||||
}
|
}
|
||||||
|
|
||||||
bldr.Append("checked, affiliated service ID: ");
|
|
||||||
bldr.Append(affiliatedServiceId ?? "undefined");
|
|
||||||
bldr.Append(", process to kill: ");
|
|
||||||
bldr.Append(proc);
|
|
||||||
|
|
||||||
Logger.Warn(bldr.ToString());
|
|
||||||
ProcessHelper.StopProcessTree(proc, this.StopTimeout, this.StopParentProcessFirst);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
Loading…
Reference in New Issue