From 58df1620540d84b23187f95bbea59532c26f69f9 Mon Sep 17 00:00:00 2001 From: Leonmmcoset Date: Sat, 28 Feb 2026 16:30:25 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A4=9A=E4=BB=BB=E5=8A=A1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- BuildTime.txt | 2 +- GitCommit.txt | 2 +- Kernel.cs | 32 +++-- System/Process.cs | 184 +++++++++++++++++++++++++++ System/ProcessManager.cs | 92 ++++++++++++++ System/ShellProcess.cs | 63 +++++++++ interpreter/UniLua/LuaOsLib.cs | 4 +- shell/CommandList.cs | 6 + shell/Commands/Help/Help.cs | 14 +- shell/Commands/System/KillCommand.cs | 57 +++++++++ shell/Commands/System/PsCommand.cs | 57 +++++++++ shell/Shell.cs | 67 +++++++++- 12 files changed, 560 insertions(+), 20 deletions(-) create mode 100644 System/Process.cs create mode 100644 System/ProcessManager.cs create mode 100644 System/ShellProcess.cs create mode 100644 shell/Commands/System/KillCommand.cs create mode 100644 shell/Commands/System/PsCommand.cs diff --git a/BuildTime.txt b/BuildTime.txt index f2b33e9..737410b 100644 --- a/BuildTime.txt +++ b/BuildTime.txt @@ -1 +1 @@ -2026-02-27 22:39:48 \ No newline at end of file +2026-02-28 16:28:03 \ No newline at end of file diff --git a/GitCommit.txt b/GitCommit.txt index 4b426de..2a68d5c 100644 --- a/GitCommit.txt +++ b/GitCommit.txt @@ -1 +1 @@ -b67e0e7 \ No newline at end of file +02ff829 \ No newline at end of file diff --git a/Kernel.cs b/Kernel.cs index 54bbf1b..03c2bcc 100644 --- a/Kernel.cs +++ b/Kernel.cs @@ -28,9 +28,14 @@ namespace CMLeonOS // 创建全局CosmosVFS实例 public static Sys.FileSystem.CosmosVFS fs = new Sys.FileSystem.CosmosVFS(); - public static Shell shell; public static UserSystem userSystem; + public static void ExecuteCommand(string command) + { + var tempShell = new Shell(userSystem); + tempShell.ExecuteCommand(command); + } + public static bool FixMode = false; public static DateTime SystemStartTime; @@ -248,9 +253,6 @@ namespace CMLeonOS _logger.Info("Kernel", $"User '{userSystem.CurrentUsername}' logged in successfully"); - // 登录成功后,初始化Shell - shell = new Shell(userSystem); - // 检查并执行启动脚本 ExecuteStartupScript(); @@ -282,10 +284,14 @@ namespace CMLeonOS Console.WriteLine("A bug brings new wake, a line brings new shine."); } - // 运行Shell(用户可以输入exit退出) - _logger.Info("Kernel", "Starting Shell"); - shell.Run(); - _logger.Info("Kernel", "Shell exited"); + // 运行Shell进程(用户可以输入exit退出) + _logger.Info("Kernel", "Starting Shell process"); + var shellProcess = new ShellProcess(userSystem); + ProcessManager.AddProcess(shellProcess); + shellProcess.TryStart(); + shellProcess.TryRun(); + shellProcess.TryStop(); + _logger.Info("Kernel", "Shell process exited"); // 如果用户输入了exit,Shell.Run()会返回,继续循环 } @@ -442,6 +448,9 @@ namespace CMLeonOS Console.WriteLine("Executing startup script..."); // Console.WriteLine("--------------------------------"); + // 创建临时 Shell 实例来执行启动脚本 + var tempShell = new Shell(userSystem); + // 逐行执行命令 foreach (string line in lines) { @@ -453,7 +462,7 @@ namespace CMLeonOS // 执行命令 // Console.WriteLine($"Executing: {line}"); - shell.ExecuteCommand(line); + tempShell.ExecuteCommand(line); } // Console.WriteLine("--------------------------------"); @@ -536,10 +545,7 @@ namespace CMLeonOS protected override void Run() { - if (shell != null) - { - shell.Run(); - } + ProcessManager.Yield(); } } } diff --git a/System/Process.cs b/System/Process.cs new file mode 100644 index 0000000..fe75121 --- /dev/null +++ b/System/Process.cs @@ -0,0 +1,184 @@ +using System; +using System.Collections.Generic; +using Sys = Cosmos.System; + +namespace CMLeonOS +{ + public enum ProcessType + { + Service, + Application, + Background + } + + public abstract class Process + { + private protected Process(string name, ProcessType type) + { + Name = name; + Type = type; + } + + private protected Process(string name, ProcessType type, Process parent) + { + Name = name; + Type = type; + Parent = parent; + } + + internal ulong Id { get; set; } + + internal List Args { get; private set; } + + internal string Name { get; set; } + + internal ProcessType Type { get; private set; } + + internal DateTime Created { get; private set; } = DateTime.Now; + + internal bool IsRunning { get; private set; } = false; + + internal bool Swept { get; set; } = false; + + internal bool Critical { get; set; } = false; + + internal Process Parent { get; set; } + + public virtual void Start() + { + if (Type == ProcessType.Service) + { + CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service starting: {Name}"); + } + + IsRunning = true; + } + + public abstract void Run(); + + public virtual void Stop() + { + if (Type == ProcessType.Service) + { + CMLeonOS.Logger.Logger.Instance.Info("Process", $"Service stopping: {Name}"); + } + + IsRunning = false; + foreach (Process process in ProcessManager.Processes) + { + if (process.Parent == this && process.IsRunning) + { + process.TryStop(); + } + } + } + + public void TryRun() + { + try + { + Run(); + } + catch (Exception e) + { + if (Critical) + { + Console.Clear(); + Console.BackgroundColor = ConsoleColor.Blue; + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(); + Console.WriteLine("========================================"); + Console.WriteLine(" CRITICAL PROCESS CRASHED"); + Console.WriteLine("========================================"); + Console.WriteLine(); + Console.WriteLine($"Process: {Name}"); + Console.WriteLine($"ID: {Id}"); + Console.WriteLine(); + Console.WriteLine("Error:"); + Console.WriteLine(e.ToString()); + Console.WriteLine(); + Console.WriteLine("Press any key to reboot..."); + Console.ReadKey(); + Sys.Power.Reboot(); + } + else + { + CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed: {e.ToString()}"); + TryStop(); + } + } + } + + public void TryStart() + { + try + { + Start(); + } + catch (Exception e) + { + if (Critical) + { + Console.Clear(); + Console.BackgroundColor = ConsoleColor.Blue; + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(); + Console.WriteLine("========================================"); + Console.WriteLine(" CRITICAL PROCESS CRASHED"); + Console.WriteLine("========================================"); + Console.WriteLine(); + Console.WriteLine($"Process: {Name}"); + Console.WriteLine($"ID: {Id}"); + Console.WriteLine(); + Console.WriteLine("Error:"); + Console.WriteLine(e.ToString()); + Console.WriteLine(); + Console.WriteLine("Press any key to reboot..."); + Console.ReadKey(); + Sys.Power.Reboot(); + } + else + { + CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while starting: {e.ToString()}"); + TryStop(); + } + } + } + + public void TryStop() + { + try + { + Stop(); + } + catch (Exception e) + { + IsRunning = false; + if (Critical) + { + Console.Clear(); + Console.BackgroundColor = ConsoleColor.Blue; + Console.ForegroundColor = ConsoleColor.White; + Console.WriteLine(); + Console.WriteLine("========================================"); + Console.WriteLine(" CRITICAL PROCESS CRASHED"); + Console.WriteLine("========================================"); + Console.WriteLine(); + Console.WriteLine($"Process: {Name}"); + Console.WriteLine($"ID: {Id}"); + Console.WriteLine(); + Console.WriteLine("Error:"); + Console.WriteLine(e.ToString()); + Console.WriteLine(); + Console.WriteLine("Press any key to reboot..."); + Console.ReadKey(); + Sys.Power.Reboot(); + } + else + { + CMLeonOS.Logger.Logger.Instance.Error("Process", $"Process \"{Name}\" ({Id}) crashed while stopping: {e.ToString()}"); + } + } + } + } +} \ No newline at end of file diff --git a/System/ProcessManager.cs b/System/ProcessManager.cs new file mode 100644 index 0000000..6c105e9 --- /dev/null +++ b/System/ProcessManager.cs @@ -0,0 +1,92 @@ +using System.Collections.Generic; + +namespace CMLeonOS +{ + public static class ProcessManager + { + public static List Processes = new List(); + + private static ulong nextProcessId = 0; + + + public static Process AddProcess(Process parent, Process process) + { + process.Parent = parent; + AddProcess(process); + return process; + } + + public static Process AddProcess(Process process) + { + + if (Processes.Contains(process)) + return process; + + process.Id = nextProcessId; + nextProcessId++; + + Processes.Add(process); + + return process; + } + + public static void Sweep() + { + for (int i = Processes.Count - 1; i >= 0; i--) + { + if (!Processes[i].IsRunning) + { + Processes.Remove(Processes[i]); + } + } + } + + public static void Yield() + { + for (int i = Processes.Count - 1; i >= 0; i--) + { + Process process = Processes[i]; + if (process.IsRunning) + { + process.TryRun(); + } + } + } + + public static Process GetProcessById(ulong processId) + { + foreach (Process process in Processes) + { + if (process.Id == processId) return process; + } + return null; + } + + public static Process GetProcessByName(string name) + { + foreach (Process process in Processes) + { + if (process.Name == name) return process; + } + return null; + } + + public static T GetProcess() + { + foreach (Process process in Processes) + { + if (process is T processT) return processT; + } + return default; + } + + public static void StopAll() + { + for (int i = Processes.Count - 1; i >= 0; i--) + { + Process process = Processes[i]; + process.TryStop(); + } + } + } +} \ No newline at end of file diff --git a/System/ShellProcess.cs b/System/ShellProcess.cs new file mode 100644 index 0000000..bac466a --- /dev/null +++ b/System/ShellProcess.cs @@ -0,0 +1,63 @@ +using System; +using System.Collections.Generic; +using CMLeonOS.Commands; +using CMLeonOS.shell; + +namespace CMLeonOS +{ + public class ShellProcess : Process + { + private Shell shell; + + public ShellProcess(UserSystem userSystem) : base("Shell", ProcessType.Application) + { + shell = new Shell(userSystem); + } + + public override void Run() + { + CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process started"); + + try + { + shell.Run(); + } + catch (Exception e) + { + CMLeonOS.Logger.Logger.Instance.Error("Shell", $"Shell crashed: {e.ToString()}"); + } + + CMLeonOS.Logger.Logger.Instance.Info("Shell", "Shell process stopped"); + } + } + + public class CommandProcess : Process + { + private string command; + private string args; + private Shell shell; + + public CommandProcess(string command, string args, Shell shell) : base($"Command_{command}", ProcessType.Application) + { + this.command = command; + this.args = args; + this.shell = shell; + } + + public override void Run() + { + CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Executing command: {command} {args}"); + + try + { + CommandList.ProcessCommand(shell, command, args); + } + catch (Exception e) + { + CMLeonOS.Logger.Logger.Instance.Error($"Command_{command}", $"Command failed: {e.ToString()}"); + } + + CMLeonOS.Logger.Logger.Instance.Info($"Command_{command}", $"Command completed: {command}"); + } + } +} diff --git a/interpreter/UniLua/LuaOsLib.cs b/interpreter/UniLua/LuaOsLib.cs index aa8e12c..4f0e4e7 100644 --- a/interpreter/UniLua/LuaOsLib.cs +++ b/interpreter/UniLua/LuaOsLib.cs @@ -118,7 +118,7 @@ namespace UniLua return 1; } - CMLeonOS.Kernel.shell?.ExecuteCommand(command); + CMLeonOS.Kernel.ExecuteCommand(command); lua.PushBoolean(true); return 1; } @@ -132,7 +132,7 @@ namespace UniLua return 1; } - CMLeonOS.Kernel.shell?.ExecuteCommand($"com {filePath}"); + CMLeonOS.Kernel.ExecuteCommand($"com {filePath}"); lua.PushBoolean(true); return 1; } diff --git a/shell/CommandList.cs b/shell/CommandList.cs index 127d1d9..3ee5a2f 100644 --- a/shell/CommandList.cs +++ b/shell/CommandList.cs @@ -163,6 +163,12 @@ namespace CMLeonOS.shell case "uptime": shell.ShowUptime(); break; + case "ps": + shell.ShowProcesses(); + break; + case "kill": + shell.KillProcess(args); + break; case "grep": shell.GrepFile(args); break; diff --git a/shell/Commands/Help/Help.cs b/shell/Commands/Help/Help.cs index 18e23a0..bc7d2a7 100644 --- a/shell/Commands/Help/Help.cs +++ b/shell/Commands/Help/Help.cs @@ -260,6 +260,18 @@ namespace CMLeonOS.Commands Description = "Show system uptime" }, new CommandInfo + { + Command = "ps", + Parameters = "", + Description = "List all running processes" + }, + new CommandInfo + { + Command = "kill", + Parameters = "", + Description = "Kill a process by ID" + }, + new CommandInfo { Command = "matrix", Parameters = "", @@ -403,7 +415,7 @@ namespace CMLeonOS.Commands { Command = "help", Parameters = "", - Description = "Show help page (1-4)", + Description = "Show help page (1-5)", SubCommands = new[] { new SubCommandInfo { Command = "help all", Description = "Show all help pages" } } } }; diff --git a/shell/Commands/System/KillCommand.cs b/shell/Commands/System/KillCommand.cs new file mode 100644 index 0000000..8e21257 --- /dev/null +++ b/shell/Commands/System/KillCommand.cs @@ -0,0 +1,57 @@ +using System; + +namespace CMLeonOS.Commands.System +{ + public static class KillCommand + { + public static void KillProcess(string args, Action showError, Action showWarning) + { + try + { + if (string.IsNullOrWhiteSpace(args)) + { + showError("Usage: kill "); + showError("Example: kill 123"); + return; + } + + if (!ulong.TryParse(args, out ulong processId)) + { + showError($"Invalid process ID: {args}"); + showError("Process ID must be a number."); + return; + } + + Process process = ProcessManager.GetProcessById(processId); + if (process == null) + { + showError($"Process not found: {processId}"); + showError("Use 'ps' command to list all processes."); + return; + } + + if (process.Name == "Shell") + { + showError("Cannot kill Shell process."); + showError("Use 'exit' command instead."); + return; + } + + if (!process.IsRunning) + { + showWarning($"Process {process.Name} ({processId}) is already stopped."); + return; + } + + CMLeonOS.Logger.Logger.Instance.Info("Kill", $"Killing process: {process.Name} ({processId})"); + process.TryStop(); + + Console.WriteLine($"Process {process.Name} ({processId}) stopped successfully."); + } + catch (Exception ex) + { + showError($"Error killing process: {ex.Message}"); + } + } + } +} diff --git a/shell/Commands/System/PsCommand.cs b/shell/Commands/System/PsCommand.cs new file mode 100644 index 0000000..2b084b5 --- /dev/null +++ b/shell/Commands/System/PsCommand.cs @@ -0,0 +1,57 @@ +using System; + +namespace CMLeonOS.Commands.System +{ + public static class PsCommand + { + public static void ShowProcesses(Action showError, Action showWarning) + { + try + { + Console.WriteLine("===================================="); + Console.WriteLine(" Process List"); + Console.WriteLine("===================================="); + Console.WriteLine(); + + if (ProcessManager.Processes.Count == 0) + { + Console.WriteLine("No processes running."); + Console.WriteLine(); + return; + } + + Console.Write("ID "); + Console.Write("Name "); + Console.Write("Type "); + Console.Write("Parent "); + Console.WriteLine("Status "); + Console.WriteLine("----------------------------------------------------------------------"); + + foreach (var process in ProcessManager.Processes) + { + string parentId = process.Parent != null ? process.Parent.Id.ToString() : "N/A"; + string status = process.IsRunning ? "Running" : "Stopped"; + string type = process.Type.ToString(); + + Console.Write(process.Id.ToString().PadRight(8)); + Console.Write(" "); + Console.Write(process.Name.PadRight(20)); + Console.Write(" "); + Console.Write(type.PadRight(12)); + Console.Write(" "); + Console.Write(parentId.PadRight(8)); + Console.Write(" "); + Console.WriteLine(status); + } + + Console.WriteLine(); + Console.WriteLine("Total processes: " + ProcessManager.Processes.Count); + Console.WriteLine(); + } + catch (Exception ex) + { + showError($"Error listing processes: {ex.Message}"); + } + } + } +} diff --git a/shell/Shell.cs b/shell/Shell.cs index 23a4bf7..5742dfe 100644 --- a/shell/Shell.cs +++ b/shell/Shell.cs @@ -128,7 +128,7 @@ namespace CMLeonOS { var command = parts[0].Trim().ToLower(); var args = parts.Length > 1 ? string.Join(" ", parts, 1, parts.Length - 1).Trim() : ""; - ProcessCommand(command, args); + ProcessCommandAsProcess(command, args); } } @@ -409,7 +409,7 @@ namespace CMLeonOS "cpass", "hostname", "ipconfig", "setdns", "setgateway", "nslookup", "ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "lua2cla", "cla", "branswe", "beep", "env", "whoami", "uptime", "alias", - "unalias", "base64", "testgui" + "unalias", "base64", "testgui", "ps", "kill" }; } @@ -462,6 +462,59 @@ namespace CMLeonOS shell.CommandList.ProcessCommand(this, expandedCommand, expandedArgs); } + public void ProcessCommandAsProcess(string command, string args) + { + string expandedCommand = command; + string expandedArgs = args; + + if (command.StartsWith(":")) + { + string appName = command.Substring(1); + string appPath = "0:\\apps\\" + appName + ".lua"; + + if (System.IO.File.Exists(appPath)) + { + Commands.Script.LuaCommand.ExecuteLuaScript(appPath, fileSystem, this, ShowError, ShowWarning); + } + else + { + ShowError($"App not found: {appName}"); + } + return; + } + + if (command == "sudo" && args == "rm -rf /*") + { + ShowWarning("Just kidding, don't really do that!"); + ShowWarning("System is protected, root directory won't be deleted!"); + return; + } + + string aliasValue = Commands.AliasCommand.GetAlias(command); + if (aliasValue != null) + { + var aliasParts = aliasValue.Split(new char[] { ' ' }, 2, StringSplitOptions.RemoveEmptyEntries); + if (aliasParts.Length > 0) + { + expandedCommand = aliasParts[0]; + if (aliasParts.Length > 1) + { + expandedArgs = aliasParts[1] + (string.IsNullOrEmpty(args) ? "" : " " + args); + } + else + { + expandedArgs = args; + } + } + } + + var commandProcess = new CommandProcess(expandedCommand, expandedArgs, this); + ProcessManager.AddProcess(commandProcess); + commandProcess.TryStart(); + commandProcess.TryRun(); + commandProcess.TryStop(); + } + public void ProcessEcho(string args) { Commands.System.EchoCommand.ProcessEcho(args); @@ -1003,6 +1056,16 @@ namespace CMLeonOS Commands.System.UptimeCommand.ShowUptime(ShowError, ShowWarning); } + public void ShowProcesses() + { + Commands.System.PsCommand.ShowProcesses(ShowError, ShowWarning); + } + + public void KillProcess(string args) + { + Commands.System.KillCommand.KillProcess(args, ShowError, ShowWarning); + } + public void CreateFTP() { Console.WriteLine("====================================");