mirror of https://github.com/winsw/winsw
Remove dependency on Win32_Process
parent
8beb21568e
commit
846fff5124
|
@ -334,7 +334,7 @@ namespace winsw
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Log.Debug("ProcessKill " + _process.Id);
|
Log.Debug("ProcessKill " + _process.Id);
|
||||||
ProcessHelper.StopProcessAndChildren(_process.Id, _descriptor.StopTimeout, _descriptor.StopParentProcessFirst);
|
ProcessHelper.StopProcessAndChildren(_process, _descriptor.StopTimeout, _descriptor.StopParentProcessFirst);
|
||||||
ExtensionManager.FireOnProcessTerminated(_process);
|
ExtensionManager.FireOnProcessTerminated(_process);
|
||||||
}
|
}
|
||||||
catch (InvalidOperationException)
|
catch (InvalidOperationException)
|
||||||
|
|
|
@ -4,5 +4,6 @@
|
||||||
{
|
{
|
||||||
internal const string Advapi32 = "advapi32.dll";
|
internal const string Advapi32 = "advapi32.dll";
|
||||||
internal const string Kernel32 = "kernel32.dll";
|
internal const string Kernel32 = "kernel32.dll";
|
||||||
|
internal const string NtDll = "ntdll.dll";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,12 +24,36 @@ namespace winsw.Native
|
||||||
[DllImport(Libraries.Kernel32)]
|
[DllImport(Libraries.Kernel32)]
|
||||||
internal static extern IntPtr GetCurrentProcess();
|
internal static extern IntPtr GetCurrentProcess();
|
||||||
|
|
||||||
|
[DllImport(Libraries.NtDll)]
|
||||||
|
internal static extern int NtQueryInformationProcess(
|
||||||
|
IntPtr processHandle,
|
||||||
|
PROCESSINFOCLASS processInformationClass,
|
||||||
|
out PROCESS_BASIC_INFORMATION processInformation,
|
||||||
|
int processInformationLength,
|
||||||
|
IntPtr returnLength = default);
|
||||||
|
|
||||||
[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 IntPtr tokenHandle);
|
out IntPtr tokenHandle);
|
||||||
|
|
||||||
|
internal enum PROCESSINFOCLASS
|
||||||
|
{
|
||||||
|
ProcessBasicInformation = 0,
|
||||||
|
}
|
||||||
|
|
||||||
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
|
internal unsafe struct PROCESS_BASIC_INFORMATION
|
||||||
|
{
|
||||||
|
private readonly IntPtr Reserved1;
|
||||||
|
private readonly IntPtr PebBaseAddress;
|
||||||
|
private readonly IntPtr Reserved2_1;
|
||||||
|
private readonly IntPtr Reserved2_2;
|
||||||
|
internal readonly IntPtr UniqueProcessId;
|
||||||
|
internal readonly IntPtr InheritedFromUniqueProcessId;
|
||||||
|
}
|
||||||
|
|
||||||
internal struct PROCESS_INFORMATION
|
internal struct PROCESS_INFORMATION
|
||||||
{
|
{
|
||||||
public IntPtr ProcessHandle;
|
public IntPtr ProcessHandle;
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Management;
|
|
||||||
using System.Threading;
|
using System.Threading;
|
||||||
using log4net;
|
using log4net;
|
||||||
|
using static winsw.Native.ProcessApis;
|
||||||
|
|
||||||
namespace winsw.Util
|
namespace winsw.Util
|
||||||
{
|
{
|
||||||
|
@ -18,30 +19,48 @@ namespace winsw.Util
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets all children of the specified process.
|
/// Gets all children of the specified process.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pid">Process PID</param>
|
/// <param name="processId">Process PID</param>
|
||||||
/// <returns>List of child process PIDs</returns>
|
/// <returns>List of child process PIDs</returns>
|
||||||
public static List<int> GetChildPids(int pid)
|
private static unsafe List<Process> GetChildProcesses(int processId)
|
||||||
{
|
{
|
||||||
var childPids = new List<int>();
|
var children = new List<Process>();
|
||||||
|
|
||||||
try
|
foreach (Process process in Process.GetProcesses())
|
||||||
{
|
{
|
||||||
string query = "SELECT * FROM Win32_Process WHERE ParentProcessID = " + pid;
|
IntPtr handle;
|
||||||
using ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
|
try
|
||||||
using ManagementObjectCollection results = searcher.Get();
|
|
||||||
foreach (ManagementBaseObject wmiObject in results)
|
|
||||||
{
|
{
|
||||||
var childProcessId = wmiObject["ProcessID"];
|
handle = process.Handle;
|
||||||
Logger.Info("Found child process: " + childProcessId + " Name: " + wmiObject["Name"]);
|
}
|
||||||
childPids.Add(Convert.ToInt32(childProcessId));
|
catch (Win32Exception)
|
||||||
|
{
|
||||||
|
process.Dispose();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NtQueryInformationProcess(
|
||||||
|
handle,
|
||||||
|
PROCESSINFOCLASS.ProcessBasicInformation,
|
||||||
|
out PROCESS_BASIC_INFORMATION information,
|
||||||
|
sizeof(PROCESS_BASIC_INFORMATION)) != 0)
|
||||||
|
{
|
||||||
|
Logger.Warn("Failed to locate children of the process with PID=" + processId + ". Child processes won't be terminated");
|
||||||
|
process.Dispose();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((int)information.InheritedFromUniqueProcessId == processId)
|
||||||
|
{
|
||||||
|
Logger.Info("Found child process: " + process.Id + " Name: " + process.ProcessName);
|
||||||
|
children.Add(process);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
process.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Logger.Warn("Failed to locate children of the process with PID=" + pid + ". Child processes won't be terminated", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return childPids;
|
return children;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -50,22 +69,18 @@ namespace winsw.Util
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="pid">PID of the process</param>
|
/// <param name="pid">PID of the process</param>
|
||||||
/// <param name="stopTimeout">Stop timeout</param>
|
/// <param name="stopTimeout">Stop timeout</param>
|
||||||
public static void StopProcess(int pid, TimeSpan stopTimeout)
|
public static void StopProcess(Process process, TimeSpan stopTimeout)
|
||||||
{
|
{
|
||||||
Logger.Info("Stopping process " + pid);
|
Logger.Info("Stopping process " + process.Id);
|
||||||
Process proc;
|
|
||||||
try
|
if (process.HasExited)
|
||||||
{
|
{
|
||||||
proc = Process.GetProcessById(pid);
|
Logger.Info("Process " + process.Id + " is already stopped");
|
||||||
}
|
|
||||||
catch (ArgumentException ex)
|
|
||||||
{
|
|
||||||
Logger.Info("Process " + pid + " is already stopped", ex);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// (bool sent, bool exited)
|
// (bool sent, bool exited)
|
||||||
KeyValuePair<bool, bool> result = SignalHelper.SendCtrlCToProcess(proc, stopTimeout);
|
KeyValuePair<bool, bool> result = SignalHelper.SendCtrlCToProcess(process, stopTimeout);
|
||||||
bool exited = result.Value;
|
bool exited = result.Value;
|
||||||
if (!exited)
|
if (!exited)
|
||||||
{
|
{
|
||||||
|
@ -74,13 +89,13 @@ namespace winsw.Util
|
||||||
bool sent = result.Key;
|
bool sent = result.Key;
|
||||||
if (sent)
|
if (sent)
|
||||||
{
|
{
|
||||||
Logger.Warn("Process " + pid + " did not respond to Ctrl+C signal - Killing as fallback");
|
Logger.Warn("Process " + process.Id + " did not respond to Ctrl+C signal - Killing as fallback");
|
||||||
}
|
}
|
||||||
proc.Kill();
|
process.Kill();
|
||||||
}
|
}
|
||||||
catch (Exception ex)
|
catch (Exception ex)
|
||||||
{
|
{
|
||||||
if (!proc.HasExited)
|
if (!process.HasExited)
|
||||||
{
|
{
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -100,23 +115,23 @@ namespace winsw.Util
|
||||||
/// <param name="pid">Process PID</param>
|
/// <param name="pid">Process PID</param>
|
||||||
/// <param name="stopTimeout">Stop timeout (for each process)</param>
|
/// <param name="stopTimeout">Stop timeout (for each process)</param>
|
||||||
/// <param name="stopParentProcessFirst">If enabled, the perent process will be terminated before its children on all levels</param>
|
/// <param name="stopParentProcessFirst">If enabled, the perent process will be terminated before its children on all levels</param>
|
||||||
public static void StopProcessAndChildren(int pid, TimeSpan stopTimeout, bool stopParentProcessFirst)
|
public static void StopProcessAndChildren(Process process, TimeSpan stopTimeout, bool stopParentProcessFirst)
|
||||||
{
|
{
|
||||||
if (!stopParentProcessFirst)
|
if (!stopParentProcessFirst)
|
||||||
{
|
{
|
||||||
foreach (var childPid in GetChildPids(pid))
|
foreach (Process child in GetChildProcesses(process.Id))
|
||||||
{
|
{
|
||||||
StopProcessAndChildren(childPid, stopTimeout, stopParentProcessFirst);
|
StopProcessAndChildren(child, stopTimeout, stopParentProcessFirst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StopProcess(pid, stopTimeout);
|
StopProcess(process, stopTimeout);
|
||||||
|
|
||||||
if (stopParentProcessFirst)
|
if (stopParentProcessFirst)
|
||||||
{
|
{
|
||||||
foreach (var childPid in GetChildPids(pid))
|
foreach (Process child in GetChildProcesses(process.Id))
|
||||||
{
|
{
|
||||||
StopProcessAndChildren(childPid, stopTimeout, stopParentProcessFirst);
|
StopProcessAndChildren(child, stopTimeout, stopParentProcessFirst);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,7 +15,6 @@
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
||||||
<PackageReference Include="System.Diagnostics.EventLog" Version="4.7.0" />
|
<PackageReference Include="System.Diagnostics.EventLog" Version="4.7.0" />
|
||||||
<PackageReference Include="System.Management" Version="4.7.0" />
|
|
||||||
<PackageReference Include="System.Security.AccessControl" Version="4.7.0" />
|
<PackageReference Include="System.Security.AccessControl" Version="4.7.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
@ -32,7 +31,6 @@
|
||||||
|
|
||||||
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
|
<ItemGroup Condition="'$(TargetFramework)' != 'netcoreapp3.1'">
|
||||||
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" />
|
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.0" />
|
||||||
<Reference Include="System.Management" />
|
|
||||||
<Reference Include="System.ServiceProcess" />
|
<Reference Include="System.ServiceProcess" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|
|
@ -276,7 +276,7 @@ namespace winsw.Plugins.RunawayProcessKiller
|
||||||
bldr.Append(proc);
|
bldr.Append(proc);
|
||||||
|
|
||||||
Logger.Warn(bldr.ToString());
|
Logger.Warn(bldr.ToString());
|
||||||
ProcessHelper.StopProcessAndChildren(pid, this.StopTimeout, this.StopParentProcessFirst);
|
ProcessHelper.StopProcessAndChildren(proc, this.StopTimeout, this.StopParentProcessFirst);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|
|
@ -110,7 +110,7 @@ $@"<service>
|
||||||
if (!proc.HasExited)
|
if (!proc.HasExited)
|
||||||
{
|
{
|
||||||
Console.Error.WriteLine("Test: Killing runaway process with ID=" + proc.Id);
|
Console.Error.WriteLine("Test: Killing runaway process with ID=" + proc.Id);
|
||||||
ProcessHelper.StopProcessAndChildren(proc.Id, TimeSpan.FromMilliseconds(100), false);
|
ProcessHelper.StopProcessAndChildren(proc, TimeSpan.FromMilliseconds(100), false);
|
||||||
if (!proc.HasExited)
|
if (!proc.HasExited)
|
||||||
{
|
{
|
||||||
// The test is failed here anyway, but we add additional diagnostics info
|
// The test is failed here anyway, but we add additional diagnostics info
|
||||||
|
|
Loading…
Reference in New Issue