6 Commits

Author SHA1 Message Date
Leonmmcoset
ec7e0978d3 增加设置项MaxLoginAttempts(默认3) 2026-02-28 19:39:48 +08:00
Leonmmcoset
c5fc081977 hex命令 2026-02-28 19:24:02 +08:00
Leonmmcoset
58df162054 多任务 2026-02-28 16:30:25 +08:00
Leonmmcoset
02ff8295ef 修复help命令 2026-02-27 22:42:26 +08:00
Leonmmcoset
b67e0e7a03 更新help命令列表 2026-02-27 22:33:39 +08:00
Leonmmcoset
fefb7e737a lua2cla&cla命令 2026-02-27 21:39:22 +08:00
21 changed files with 1281 additions and 30 deletions

View File

@@ -1 +1 @@
2026-02-26 20:25:24
2026-02-28 19:35:58

View File

@@ -1 +1 @@
c1e0651
c5fc081

View File

@@ -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");
// 如果用户输入了exitShell.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();
}
}
}

View File

@@ -11,7 +11,8 @@ namespace CMLeonOS.Settings
private static Dictionary<string, string> defaultSettings = new Dictionary<string, string>
{
{ "LoggerEnabled", "true" }
{ "LoggerEnabled", "true" },
{ "MaxLoginAttempts", "3" }
};
public static bool LoggerEnabled
@@ -31,6 +32,26 @@ namespace CMLeonOS.Settings
}
}
public static int MaxLoginAttempts
{
get
{
if (settings.TryGetValue("MaxLoginAttempts", out string value))
{
if (int.TryParse(value, out int result))
{
return result;
}
}
return 3;
}
set
{
settings["MaxLoginAttempts"] = value.ToString();
SaveSettings();
}
}
public static void LoadSettings()
{
settings.Clear();

184
System/Process.cs Normal file
View File

@@ -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<string> 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()}");
}
}
}
}
}

92
System/ProcessManager.cs Normal file
View File

@@ -0,0 +1,92 @@
using System.Collections.Generic;
namespace CMLeonOS
{
public static class ProcessManager
{
public static List<Process> Processes = new List<Process>();
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<T>()
{
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();
}
}
}
}

63
System/ShellProcess.cs Normal file
View File

@@ -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}");
}
}
}

View File

@@ -6,6 +6,7 @@ using System.Text;
using System.Threading;
using Sys = Cosmos.System;
using CMLeonOS.Logger;
using CMLeonOS.Settings;
namespace CMLeonOS
{
@@ -25,6 +26,7 @@ namespace CMLeonOS
public bool fixmode = Kernel.FixMode;
private User currentLoggedInUser;
private static CMLeonOS.Logger.Logger _logger = CMLeonOS.Logger.Logger.Instance;
private Dictionary<string, int> loginAttempts = new Dictionary<string, int>();
public User CurrentLoggedInUser
{
@@ -593,13 +595,37 @@ namespace CMLeonOS
if (foundUser.Password != hashedInputPassword)
{
string usernameLower = username.ToLower();
if (!loginAttempts.ContainsKey(usernameLower))
{
loginAttempts[usernameLower] = 0;
}
loginAttempts[usernameLower]++;
int attempts = loginAttempts[usernameLower];
int maxAttempts = Settings.SettingsManager.MaxLoginAttempts;
if (attempts >= maxAttempts)
{
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write($"Maximum login attempts ({maxAttempts}) reached. ");
global::System.Console.SetCursorPosition(17, 25);
global::System.Console.Write("Please restart to enter password again. ");
global::System.Threading.Thread.Sleep(3000);
Sys.Power.Reboot();
}
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Red, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write("Invalid password. ");
global::System.Console.Write($"Invalid password. Attempts: {attempts}/{maxAttempts} ");
global::System.Threading.Thread.Sleep(1000);
return false;
}
loginAttempts.Remove(username.ToLower());
CMLeonOS.UI.TUIHelper.SetColors(global::System.ConsoleColor.Green, global::System.ConsoleColor.Black);
global::System.Console.SetCursorPosition(17, 24);
global::System.Console.Write("Login successful! ");

View File

@@ -329,6 +329,60 @@ nano <file>
nano myfile.txt
```
### hex
使用16进制编辑器编辑二进制文件。
**用法:**
```bash
hex <filename>
```
**示例:**
```bash
hex test.bin
hex kernel.sys
```
**控制键:**
- `↑ ↓ ← →` - 移动光标
- `Page Up / Page Down` - 滚动视图
- `0-9, A-F` - 编辑字节值
- `S` - 保存文件
- `Q` - 退出编辑器
**说明:**
- 显示文件的16进制字节值和对应的ASCII字符
- 每行显示16个字节分为8个字节一组
- 显示每行的偏移地址8位16进制
- 光标位置用白色背景高亮显示
- 文件修改后显示 [MODIFIED] 标记
- 支持查看和编辑任意大小的二进制文件
- 按 S 键保存修改到文件
- 按 Q 键退出编辑器(不保存修改)
**界面示例:**
```
====================================
Hex Editor
====================================
File: test.bin
Size: 256 bytes [MODIFIED]
00000000 48 65 6C 6C 6F 20 57 6F 72 6C 64 21 00 00 00 00 |Hello World.....|
00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
Cursor: 0x00000000 (0)
Value: 0x48
Controls:
Arrow Keys - Move cursor
Page Up/Down - Scroll view
0-9, A-F - Edit byte
S - Save file
Q - Quit
```
## 用户管理命令
### user
@@ -498,6 +552,41 @@ lua <file>
lua script.lua
```
### lua2cla
将 Lua 文件转换为 CMLeonOS Lua 应用格式(.cla
**用法:**
```bash
lua2cla <lua_file>
```
**示例:**
```bash
lua2cla app.lua
```
**说明:**
- 文件头为 `CMLeonOS_CLA`
- 转换后的文件可以通过 `cla` 命令运行
### cla
运行 CMLeonOS Lua 应用格式(.cla文件。
**用法:**
```bash
cla <cla_file>
```
**示例:**
```bash
cla app.cla
```
**说明:**
- 运行 .cla 格式的加密 Lua 应用
- 自动解密并执行 Lua 代码
- 文件头必须为 `CMLeonOS_CLA`
### com
执行命令脚本文件。
@@ -636,7 +725,7 @@ app list # 列出所有可用应用
app install <name> # 安装应用
app uninstall <name> # 卸载应用
app installed # 列出已安装应用
app help # 显示帮助信息
app help # 显示帮助信息
```
**示例:**

View File

@@ -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;
}

View File

@@ -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;
@@ -190,6 +196,12 @@ namespace CMLeonOS.shell
case "lua":
shell.ExecuteLuaScript(args);
break;
case "lua2cla":
shell.ConvertLuaToCla(args);
break;
case "cla":
shell.RunClaFile(args);
break;
case "testgui":
shell.ProcessTestGui();
break;
@@ -202,6 +214,9 @@ namespace CMLeonOS.shell
case "snake":
shell.PlaySnake();
break;
case "hex":
shell.EditHexFile(args);
break;
case "alias":
shell.ProcessAlias(args);
break;

View File

@@ -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 = "<process_id>",
Description = "Kill a process by ID"
},
new CommandInfo
{
Command = "matrix",
Parameters = "",
@@ -284,6 +296,12 @@ namespace CMLeonOS.Commands
Description = "Search text in file"
},
new CommandInfo
{
Command = "hex",
Parameters = "<filename>",
Description = "Hexadecimal file editor"
},
new CommandInfo
{
Command = "ping",
Parameters = "<ip>",
@@ -369,6 +387,18 @@ namespace CMLeonOS.Commands
Description = "Execute Lua script"
},
new CommandInfo
{
Command = "lua2cla",
Parameters = "<lua_file>",
Description = "Convert Lua to CLA format"
},
new CommandInfo
{
Command = "cla",
Parameters = "<cla_file>",
Description = "Run CLA application"
},
new CommandInfo
{
Command = "version",
Parameters = "",
@@ -391,7 +421,7 @@ namespace CMLeonOS.Commands
{
Command = "help",
Parameters = "<page>",
Description = "Show help page (1-3)",
Description = "Show help page (1-5)",
SubCommands = new[] { new SubCommandInfo { Command = "help all", Description = "Show all help pages" } }
}
};
@@ -471,24 +501,32 @@ namespace CMLeonOS.Commands
pageNumber = 1;
}
int startIndex = (pageNumber - 1) * CommandsPerPage;
int endIndex = Math.Min(startIndex + CommandsPerPage, allCommands.Count);
Console.WriteLine("====================================");
Console.WriteLine($" Help - Page {pageNumber}/{totalPages}");
Console.WriteLine("====================================");
Console.WriteLine();
int linesOnPage = 0;
for (int i = startIndex; i < endIndex; i++)
int currentLine = 0;
for (int i = 0; i < allCommands.Count; i++)
{
int cmdLines = GetCommandLinesCount(allCommands[i]);
if (linesOnPage + cmdLines > CommandsPerPage)
if (currentLine + cmdLines <= (pageNumber - 1) * CommandsPerPage)
{
currentLine += cmdLines;
continue;
}
if (linesOnPage >= CommandsPerPage)
{
break;
}
DisplayCommand(allCommands[i]);
linesOnPage += cmdLines;
currentLine += cmdLines;
}
if (pageNumber < totalPages)

View File

@@ -0,0 +1,82 @@
using System;
using System.IO;
using System.Text;
using UniLua;
namespace CMLeonOS.Commands.Script
{
public static class ClaCommand
{
private const string FILE_HEADER = "CMLeonOS_CLA";
private static readonly byte[] ENCRYPTION_KEY = { 0x55, 0xAA, 0x33, 0xCC, 0x77, 0x88, 0x11, 0x22, 0x44, 0x66, 0x99, 0xBB };
public static void RunClaFile(string args, CMLeonOS.FileSystem fileSystem, Shell shell, Action<string> showError, Action<string> showWarning)
{
if (string.IsNullOrEmpty(args))
{
showError(UsageGenerator.GenerateSimpleUsage("cla", "<cla_file>"));
showError("Example: cla app.cla");
return;
}
string claFilePath = fileSystem.GetFullPath(args);
if (!File.Exists(claFilePath))
{
showError($"Error: CLA file not found: {args}");
return;
}
if (!claFilePath.EndsWith(".cla", StringComparison.OrdinalIgnoreCase))
{
showError("Error: Input file must have .cla extension");
return;
}
try
{
string luaContent = DecryptClaFile(claFilePath);
if (string.IsNullOrEmpty(luaContent))
{
showError("Error: Failed to decrypt CLA file or file is corrupted");
return;
}
LuaCommand.ExecuteLuaCode(luaContent, fileSystem, shell, showError, showWarning);
}
catch (Exception ex)
{
showError($"Error running CLA file: {ex.Message}");
}
}
private static string DecryptClaFile(string claFilePath)
{
using (BinaryReader reader = new BinaryReader(File.OpenRead(claFilePath)))
{
byte[] headerBytes = reader.ReadBytes(FILE_HEADER.Length);
string header = Encoding.ASCII.GetString(headerBytes);
if (header != FILE_HEADER)
{
throw new Exception("Invalid CLA file format: Missing or incorrect header");
}
byte[] encryptedData = reader.ReadBytes((int)(reader.BaseStream.Length - reader.BaseStream.Position));
return DecryptData(encryptedData);
}
}
private static string DecryptData(byte[] data)
{
for (int i = 0; i < data.Length; i++)
{
int keyIndex = i % ENCRYPTION_KEY.Length;
data[i] = (byte)(data[i] ^ ENCRYPTION_KEY[keyIndex]);
}
return Encoding.UTF8.GetString(data);
}
}
}

View File

@@ -0,0 +1,70 @@
using System;
using System.IO;
using System.Text;
namespace CMLeonOS.Commands.Script
{
public static class Lua2ClaCommand
{
private const string FILE_HEADER = "CMLeonOS_CLA";
private static readonly byte[] ENCRYPTION_KEY = { 0x55, 0xAA, 0x33, 0xCC, 0x77, 0x88, 0x11, 0x22, 0x44, 0x66, 0x99, 0xBB };
public static void ConvertLuaToCla(string args, CMLeonOS.FileSystem fileSystem, Action<string> showError, Action<string> showSuccess)
{
if (string.IsNullOrEmpty(args))
{
showError(UsageGenerator.GenerateSimpleUsage("lua2cla", "<lua_file>"));
showError("Example: lua2cla app.lua");
return;
}
string luaFilePath = fileSystem.GetFullPath(args);
if (!File.Exists(luaFilePath))
{
showError($"Error: Lua file not found: {args}");
return;
}
if (!luaFilePath.EndsWith(".lua", StringComparison.OrdinalIgnoreCase))
{
showError("Error: Input file must have .lua extension");
return;
}
try
{
string luaContent = File.ReadAllText(luaFilePath);
byte[] encryptedData = EncryptData(luaContent);
string claFilePath = luaFilePath.Substring(0, luaFilePath.Length - 4) + ".cla";
using (BinaryWriter writer = new BinaryWriter(File.Create(claFilePath)))
{
writer.Write(Encoding.ASCII.GetBytes(FILE_HEADER));
writer.Write(encryptedData);
}
showSuccess($"Successfully converted: {args} -> {Path.GetFileName(claFilePath)}");
Console.WriteLine($"Output file: {claFilePath}");
}
catch (Exception ex)
{
showError($"Error converting file: {ex.Message}");
}
}
private static byte[] EncryptData(string content)
{
byte[] data = Encoding.UTF8.GetBytes(content);
for (int i = 0; i < data.Length; i++)
{
int keyIndex = i % ENCRYPTION_KEY.Length;
data[i] = (byte)(data[i] ^ ENCRYPTION_KEY[keyIndex]);
}
return data;
}
}
}

View File

@@ -116,6 +116,60 @@ namespace CMLeonOS.Commands.Script
}
}
public static void ExecuteLuaCode(string code, CMLeonOS.FileSystem fileSystem, Shell shell, Action<string> showError, Action<string> showWarning)
{
if (string.IsNullOrWhiteSpace(code))
{
showWarning("Lua code is empty");
return;
}
try
{
ILuaState lua = LuaAPI.NewState();
lua.L_OpenLibs();
UniLua.ThreadStatus loadResult = lua.L_LoadString(code);
if (loadResult == UniLua.ThreadStatus.LUA_OK)
{
UniLua.ThreadStatus callResult = lua.PCall(0, 0, 0);
if (callResult == UniLua.ThreadStatus.LUA_OK)
{
}
else
{
string errorMsg = lua.ToString(-1);
if (string.IsNullOrWhiteSpace(errorMsg))
{
showError($"Script execution error: Unknown error");
}
else
{
showError($"Script execution error: {errorMsg}");
}
}
}
else
{
string errorMsg = lua.ToString(-1);
if (string.IsNullOrWhiteSpace(errorMsg))
{
showError($"Script load error: Unknown error");
}
else
{
showError($"Script load error: {errorMsg}");
}
}
}
catch (Exception ex)
{
showError($"Lua execution error: {ex.Message}");
}
}
private static void EnterLuaShell(Action<string> showError)
{
Console.WriteLine("====================================");

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class KillCommand
{
public static void KillProcess(string args, Action<string> showError, Action<string> showWarning)
{
try
{
if (string.IsNullOrWhiteSpace(args))
{
showError("Usage: kill <process_id>");
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}");
}
}
}
}

View File

@@ -0,0 +1,57 @@
using System;
namespace CMLeonOS.Commands.System
{
public static class PsCommand
{
public static void ShowProcesses(Action<string> showError, Action<string> 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}");
}
}
}
}

View File

@@ -58,6 +58,18 @@ namespace CMLeonOS.Commands
Console.WriteLine("Error: LoggerEnabled must be 'true' or 'false'");
}
}
else if (key.ToLower() == "maxloginattempts")
{
if (int.TryParse(value, out int attempts) && attempts > 0)
{
SettingsManager.MaxLoginAttempts = attempts;
Console.WriteLine($"MaxLoginAttempts set to {attempts}");
}
else
{
Console.WriteLine("Error: MaxLoginAttempts must be a positive integer");
}
}
else
{
SettingsManager.SetSetting(key, value);

View File

@@ -0,0 +1,49 @@
using System;
using System.IO;
namespace CMLeonOS.Commands.Utility
{
public static class HexCommand
{
public static void EditHexFile(string args)
{
try
{
if (string.IsNullOrWhiteSpace(args))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine("Usage: hex <filename>");
Console.WriteLine("Example: hex test.bin");
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
Console.ResetColor();
return;
}
string filePath = args.Trim();
if (!File.Exists(filePath))
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"File not found: {filePath}");
Console.ResetColor();
return;
}
var editor = new HexEditor(filePath);
editor.Run();
}
catch (Exception ex)
{
Console.ForegroundColor = ConsoleColor.Red;
Console.WriteLine($"Error opening hex editor: {ex.Message}");
Console.ResetColor();
}
}
}
}

View File

@@ -0,0 +1,258 @@
using System;
using System.IO;
namespace CMLeonOS.Commands.Utility
{
public class HexEditor
{
private byte[] data;
private int cursorPosition;
private int viewOffset;
private int bytesPerLine = 16;
private int bytesPerGroup = 2;
private string filePath;
private bool modified;
private bool running;
public HexEditor(string path)
{
filePath = path;
if (File.Exists(path))
{
data = File.ReadAllBytes(path);
}
else
{
data = new byte[256];
}
cursorPosition = 0;
viewOffset = 0;
modified = false;
running = true;
}
public void Run()
{
Console.Clear();
Console.WriteLine("====================================");
Console.WriteLine(" Hex Editor");
Console.WriteLine("====================================");
Console.WriteLine();
Console.WriteLine("File: " + filePath);
Console.WriteLine("Size: " + data.Length + " bytes");
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
Console.WriteLine();
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
while (running)
{
Display();
HandleInput();
}
}
private void Display()
{
Console.Clear();
Console.WriteLine("====================================");
Console.WriteLine(" Hex Editor");
Console.WriteLine("====================================");
Console.WriteLine();
Console.WriteLine("File: " + filePath);
Console.WriteLine("Size: " + data.Length + " bytes");
if (modified)
{
Console.Write(" [MODIFIED]");
}
Console.WriteLine();
Console.WriteLine();
int lines = (int)Math.Ceiling((double)data.Length / bytesPerLine);
int startLine = viewOffset / bytesPerLine;
int endLine = Math.Min(startLine + 20, lines);
for (int line = startLine; line < endLine; line++)
{
int offset = line * bytesPerLine;
if (offset >= data.Length) break;
Console.Write(offset.ToString("X8") + " ");
for (int i = 0; i < bytesPerLine; i++)
{
int byteOffset = offset + i;
if (byteOffset >= data.Length)
{
Console.Write(" ");
}
else
{
byte b = data[byteOffset];
bool isCursor = (byteOffset == cursorPosition);
if (isCursor)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
}
Console.Write(b.ToString("X2") + " ");
if (isCursor)
{
Console.ResetColor();
}
if ((i + 1) % bytesPerGroup == 0)
{
Console.Write(" ");
}
}
}
Console.Write(" |");
for (int i = 0; i < bytesPerLine; i++)
{
int byteOffset = offset + i;
if (byteOffset >= data.Length)
{
Console.Write(" ");
}
else
{
byte b = data[byteOffset];
bool isCursor = (byteOffset == cursorPosition);
if (isCursor)
{
Console.BackgroundColor = ConsoleColor.White;
Console.ForegroundColor = ConsoleColor.Black;
}
char c = (b >= 32 && b <= 126) ? (char)b : '.';
Console.Write(c);
if (isCursor)
{
Console.ResetColor();
}
}
}
Console.WriteLine("|");
}
Console.WriteLine();
Console.WriteLine("Cursor: 0x" + cursorPosition.ToString("X8") + " (" + cursorPosition + ")");
Console.WriteLine("Value: 0x" + data[cursorPosition].ToString("X2"));
Console.WriteLine();
Console.WriteLine("Controls:");
Console.WriteLine(" Arrow Keys - Move cursor");
Console.WriteLine(" Page Up/Down - Scroll view");
Console.WriteLine(" 0-9, A-F - Edit byte");
Console.WriteLine(" S - Save file");
Console.WriteLine(" Q - Quit");
}
private void HandleInput()
{
var key = Console.ReadKey(true);
switch (key.Key)
{
case ConsoleKey.UpArrow:
cursorPosition = Math.Max(0, cursorPosition - bytesPerLine);
break;
case ConsoleKey.DownArrow:
cursorPosition = Math.Min(data.Length - 1, cursorPosition + bytesPerLine);
break;
case ConsoleKey.LeftArrow:
cursorPosition = Math.Max(0, cursorPosition - 1);
break;
case ConsoleKey.RightArrow:
cursorPosition = Math.Min(data.Length - 1, cursorPosition + 1);
break;
case ConsoleKey.PageUp:
viewOffset = Math.Max(0, viewOffset - (bytesPerLine * 20));
break;
case ConsoleKey.PageDown:
viewOffset = Math.Min(data.Length - 1, viewOffset + (bytesPerLine * 20));
break;
case ConsoleKey.D0:
case ConsoleKey.D1:
case ConsoleKey.D2:
case ConsoleKey.D3:
case ConsoleKey.D4:
case ConsoleKey.D5:
case ConsoleKey.D6:
case ConsoleKey.D7:
case ConsoleKey.D8:
case ConsoleKey.D9:
int digit = key.KeyChar - '0';
EditByte(digit);
break;
case ConsoleKey.A:
EditByte(10);
break;
case ConsoleKey.B:
EditByte(11);
break;
case ConsoleKey.C:
EditByte(12);
break;
case ConsoleKey.D:
EditByte(13);
break;
case ConsoleKey.E:
EditByte(14);
break;
case ConsoleKey.F:
EditByte(15);
break;
case ConsoleKey.S:
SaveFile();
break;
case ConsoleKey.Q:
running = false;
break;
}
}
private void EditByte(int value)
{
if (cursorPosition >= 0 && cursorPosition < data.Length)
{
data[cursorPosition] = (byte)value;
modified = true;
}
}
private void SaveFile()
{
try
{
File.WriteAllBytes(filePath, data);
modified = false;
Console.WriteLine();
Console.WriteLine("File saved successfully!");
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
catch (Exception ex)
{
Console.WriteLine();
Console.WriteLine("Error saving file: " + ex.Message);
Console.WriteLine("Press any key to continue...");
Console.ReadKey(true);
}
}
}
}

View File

@@ -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);
}
}
@@ -407,9 +407,9 @@ namespace CMLeonOS
"rmdir", "cat", "version", "about", "head", "tail", "wc", "cp",
"mv", "rename", "touch", "find", "tree", "grep", "getdisk", "user",
"cpass", "hostname", "ipconfig", "setdns", "setgateway", "nslookup",
"ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "branswe",
"beep", "env", "whoami", "uptime", "alias",
"unalias", "base64", "testgui"
"ping", "wget", "ftp", "tcpserver", "tcpclient", "lua", "lua2cla", "cla",
"branswe", "beep", "env", "whoami", "uptime", "alias",
"unalias", "base64", "testgui", "ps", "kill", "hex"
};
}
@@ -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,21 @@ 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 EditHexFile(string args)
{
Commands.Utility.HexCommand.EditHexFile(args);
}
public void CreateFTP()
{
Console.WriteLine("====================================");
@@ -1502,6 +1570,16 @@ namespace CMLeonOS
Commands.Script.LuaCommand.ExecuteLuaScript(args, fileSystem, this, ShowError, ShowWarning);
}
public void ConvertLuaToCla(string args)
{
Commands.Script.Lua2ClaCommand.ConvertLuaToCla(args, fileSystem, ShowError, ShowSuccess);
}
public void RunClaFile(string args)
{
Commands.Script.ClaCommand.RunClaFile(args, fileSystem, this, ShowError, ShowWarning);
}
public void ProcessTestGui()
{
Commands.TestGuiCommand.RunTestGui();