Optimized and improved the code

Optimized and improved the code for killing core processes in non-Windows environments. Now uses a shell script for precise processing.
pull/7673/head
2dust 2025-07-30 19:52:45 +08:00
parent 6715d7dce6
commit 3d23f3e3a2
9 changed files with 170 additions and 46 deletions

View File

@ -223,4 +223,28 @@ public static class FileManager
// ignored // ignored
} }
} }
/// <summary>
/// Creates a Linux shell file with the specified contents.
/// </summary>
/// <param name="fileName"></param>
/// <param name="contents"></param>
/// <param name="overwrite"></param>
/// <returns></returns>
public static async Task<string> CreateLinuxShellFile(string fileName, string contents, bool overwrite)
{
var shFilePath = Utils.GetBinConfigPath(fileName);
// Check if the file already exists and if we should overwrite it
if (!overwrite && File.Exists(shFilePath))
{
return shFilePath;
}
File.Delete(shFilePath);
await File.WriteAllTextAsync(shFilePath, contents);
await Utils.SetLinuxChmod(shFilePath);
return shFilePath;
}
} }

View File

@ -38,6 +38,8 @@ public class Global
public const string PacFileName = NamespaceSample + "pac"; public const string PacFileName = NamespaceSample + "pac";
public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh"; public const string ProxySetOSXShellFileName = NamespaceSample + "proxy_set_osx_sh";
public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh"; public const string ProxySetLinuxShellFileName = NamespaceSample + "proxy_set_linux_sh";
public const string KillAsSudoOSXShellFileName = NamespaceSample + "kill_as_sudo_osx_sh";
public const string KillAsSudoLinuxShellFileName = NamespaceSample + "kill_as_sudo_linux_sh";
public const string DefaultSecurity = "auto"; public const string DefaultSecurity = "auto";
public const string DefaultNetwork = "tcp"; public const string DefaultNetwork = "tcp";

View File

@ -1,6 +1,7 @@
using System.Diagnostics; using System.Diagnostics;
using System.Text; using System.Text;
using CliWrap; using CliWrap;
using CliWrap.Buffered;
namespace ServiceLib.Handler; namespace ServiceLib.Handler;
@ -11,6 +12,7 @@ public class CoreAdminHandler
private Config _config; private Config _config;
private Action<bool, string>? _updateFunc; private Action<bool, string>? _updateFunc;
private int _linuxSudoPid = -1; private int _linuxSudoPid = -1;
private const string _tag = "CoreAdminHandler";
public async Task Init(Config config, Action<bool, string> updateFunc) public async Task Init(Config config, Action<bool, string> updateFunc)
{ {
@ -31,8 +33,11 @@ public class CoreAdminHandler
public async Task<Process?> RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath) public async Task<Process?> RunProcessAsLinuxSudo(string fileName, CoreInfo coreInfo, string configPath)
{ {
StringBuilder sb = new();
sb.AppendLine("#!/bin/bash");
var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}"; var cmdLine = $"{fileName.AppendQuotes()} {string.Format(coreInfo.Arguments, Utils.GetBinConfigPath(configPath).AppendQuotes())}";
var shFilePath = await CreateLinuxShellFile(cmdLine, "run_as_sudo.sh"); sb.AppendLine($"sudo -S {cmdLine}");
var shFilePath = await FileManager.CreateLinuxShellFile("run_as_sudo.sh", sb.ToString(), true);
Process proc = new() Process proc = new()
{ {
@ -87,35 +92,24 @@ public class CoreAdminHandler
return; return;
} }
var cmdLine = $"pkill -P {_linuxSudoPid} ; kill {_linuxSudoPid}"; try
var shFilePath = await CreateLinuxShellFile(cmdLine, "kill_as_sudo.sh"); {
var shellFileName = Utils.IsOSX() ? Global.KillAsSudoOSXShellFileName : Global.KillAsSudoLinuxShellFileName;
var shFilePath = await FileManager.CreateLinuxShellFile("kill_as_sudo.sh", EmbedUtils.GetEmbedText(shellFileName), true);
await Cli.Wrap(shFilePath) var arg = new List<string>() { "-c", $"sudo -S {shFilePath} {_linuxSudoPid}" };
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd)) var result = await Cli.Wrap(Global.LinuxBash)
.ExecuteAsync(); .WithArguments(arg)
.WithStandardInputPipe(PipeSource.FromString(AppHandler.Instance.LinuxSudoPwd))
.ExecuteBufferedAsync();
UpdateFunc(false, result.StandardOutput.ToString());
}
catch (Exception ex)
{
Logging.SaveLog(_tag, ex);
}
_linuxSudoPid = -1; _linuxSudoPid = -1;
} }
private async Task<string> CreateLinuxShellFile(string cmdLine, string fileName)
{
var shFilePath = Utils.GetBinConfigPath(fileName);
File.Delete(shFilePath);
var sb = new StringBuilder();
sb.AppendLine("#!/bin/sh");
if (Utils.IsAdministrator())
{
sb.AppendLine($"{cmdLine}");
}
else
{
sb.AppendLine($"sudo -S {cmdLine}");
}
await File.WriteAllTextAsync(shFilePath, sb.ToString());
await Utils.SetLinuxChmod(shFilePath);
return shFilePath;
}
} }

View File

@ -18,14 +18,7 @@ public class ProxySettingLinux
private static async Task ExecCmd(List<string> args) private static async Task ExecCmd(List<string> args)
{ {
var fileName = Utils.GetBinConfigPath(_proxySetFileName); var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName), false);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetLinuxShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
await Utils.GetCliWrapOutput(fileName, args); await Utils.GetCliWrapOutput(fileName, args);
} }

View File

@ -23,14 +23,7 @@ public class ProxySettingOSX
private static async Task ExecCmd(List<string> args) private static async Task ExecCmd(List<string> args)
{ {
var fileName = Utils.GetBinConfigPath(_proxySetFileName); var fileName = await FileManager.CreateLinuxShellFile(_proxySetFileName, EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName), false);
if (!File.Exists(fileName))
{
var contents = EmbedUtils.GetEmbedText(Global.ProxySetOSXShellFileName);
await File.AppendAllTextAsync(fileName, contents);
await Utils.SetLinuxChmod(fileName);
}
await Utils.GetCliWrapOutput(fileName, args); await Utils.GetCliWrapOutput(fileName, args);
} }

View File

@ -0,0 +1,61 @@
#!/bin/bash
#
# Process Terminator Script for Linux
# This script forcibly terminates a process and all its child processes
#
# Check if PID argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <PID>"
exit 1
fi
PID=$1
# Validate that input is a valid PID (numeric)
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
echo "Error: The PID must be a numeric value"
exit 1
fi
# Check if the process exists
if ! ps -p $PID > /dev/null; then
echo "Warning: No process found with PID $PID"
exit 0
fi
# Recursive function to find and kill all child processes
kill_children() {
local parent=$1
local children=$(ps -o pid --no-headers --ppid "$parent")
# Output information about processes being terminated
echo "Processing children of PID: $parent..."
# Process each child
for child in $children; do
# Recursively find and kill child's children first
kill_children "$child"
# Force kill the child process
echo "Terminating child process: $child"
kill -9 "$child" 2>/dev/null || true
done
}
echo "============================================"
echo "Starting termination of process $PID and all its children"
echo "============================================"
# Find and kill all child processes
kill_children "$PID"
# Finally kill the main process
echo "Terminating main process: $PID"
kill -9 "$PID" 2>/dev/null || true
echo "============================================"
echo "Process $PID and all its children have been terminated"
echo "============================================"
exit 0

View File

@ -0,0 +1,56 @@
#!/bin/bash
#
# Process Terminator Script for macOS
# This script forcibly terminates a process and all its descendant processes
#
# Check if PID argument is provided
if [ $# -ne 1 ]; then
echo "Usage: $0 <PID>"
exit 1
fi
PID=$1
# Validate that input is a valid PID (numeric)
if ! [[ "$PID" =~ ^[0-9]+$ ]]; then
echo "Error: The PID must be a numeric value"
exit 1
fi
# Check if the process exists
if ! ps -p $PID > /dev/null; then
echo "Warning: No process found with PID $PID"
exit 0
fi
# Recursive function to find and kill all descendant processes
kill_descendants() {
local parent=$1
# Use ps -eo pid,ppid for macOS compatibility
local children=$(ps -eo pid=,ppid= | awk -v ppid=$parent '$2==ppid {print $1}')
echo "Processing children of PID: $parent..."
for child in $children; do
kill_descendants "$child"
echo "Terminating child process: $child"
kill -9 "$child" 2>/dev/null || true
done
}
echo "============================================"
echo "Starting termination of process $PID and all its descendants"
echo "============================================"
# Find and kill all descendant processes
kill_descendants "$PID"
# Finally kill the main process
echo "Terminating main process: $PID"
kill -9 "$PID" 2>/dev/null || true
echo "============================================"
echo "Process $PID and all its descendants have been terminated"
echo "============================================"
exit 0

View File

@ -28,6 +28,8 @@
<EmbeddedResource Include="Sample\custom_routing_white" /> <EmbeddedResource Include="Sample\custom_routing_white" />
<EmbeddedResource Include="Sample\dns_singbox_normal" /> <EmbeddedResource Include="Sample\dns_singbox_normal" />
<EmbeddedResource Include="Sample\dns_v2ray_normal" /> <EmbeddedResource Include="Sample\dns_v2ray_normal" />
<EmbeddedResource Include="Sample\kill_as_sudo_linux_sh" />
<EmbeddedResource Include="Sample\kill_as_sudo_osx_sh" />
<EmbeddedResource Include="Sample\pac" /> <EmbeddedResource Include="Sample\pac" />
<EmbeddedResource Include="Sample\proxy_set_linux_sh" /> <EmbeddedResource Include="Sample\proxy_set_linux_sh" />
<EmbeddedResource Include="Sample\proxy_set_osx_sh" /> <EmbeddedResource Include="Sample\proxy_set_osx_sh" />

View File

@ -66,8 +66,7 @@ public partial class SudoPasswordInputView : UserControl
{ {
// Use sudo echo command to verify password // Use sudo echo command to verify password
var arg = new List<string>() { "-c", "sudo -S echo SUDO_CHECK" }; var arg = new List<string>() { "-c", "sudo -S echo SUDO_CHECK" };
var result = await CliWrap.Cli var result = await CliWrap.Cli.Wrap(Global.LinuxBash)
.Wrap(Global.LinuxBash)
.WithArguments(arg) .WithArguments(arg)
.WithStandardInputPipe(CliWrap.PipeSource.FromString(password)) .WithStandardInputPipe(CliWrap.PipeSource.FromString(password))
.ExecuteBufferedAsync(); .ExecuteBufferedAsync();