forked from Hyperion/HyperionOS
Compare commits
77 Commits
Test
...
bb14ea34c3
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bb14ea34c3 | ||
|
|
149fb18564 | ||
| 10bc775e64 | |||
| 287b146621 | |||
|
|
371954373e | ||
|
|
ecef2c6cb0 | ||
|
|
6770533581 | ||
| 19a9c72c6d | |||
| fdb18d4ac5 | |||
|
|
303449e13c | ||
| b6d1b9398f | |||
| bb829cdd8e | |||
| 6b9bed5047 | |||
|
|
753c34bffa | ||
| 403178c832 | |||
| 33cd291c21 | |||
| 1c4f48bd65 | |||
| ec5e63898d | |||
| ea2a0e0e94 | |||
| 4f50d90b79 | |||
| bf1dc9da7a | |||
| 1a455a6025 | |||
| c9ac447484 | |||
| cb73f49962 | |||
| d9caf655fb | |||
| 1c3d2c8b48 | |||
| 9bd9cdaba4 | |||
| 72bfce7b08 | |||
| 6e48fcd5b9 | |||
| 2d98ff64ce | |||
| 6a14b87f44 | |||
| 63bcc2df5c | |||
| fd7ee1aa3b | |||
| 1073362007 | |||
| da5ad3b5cb | |||
| e77fbcaf5d | |||
| 111fe764f8 | |||
|
|
83857d7e87 | ||
| 83814311e5 | |||
| 55fdddeff8 | |||
| 1b21c87654 | |||
| df4823940d | |||
| 70532f6e2c | |||
| bd8fe50770 | |||
| e5d6ec9725 | |||
| c620c4f1ba | |||
| 6b48e80157 | |||
| fbbb8b8d65 | |||
|
|
a88bdc9639 | ||
| 96c22f5237 | |||
| 231b0ced48 | |||
| 4100ecf0a1 | |||
|
|
968f4c54d7 | ||
| 70526c76ba | |||
| 3a8be2bdb7 | |||
| efffc8f0d2 | |||
| b48f926053 | |||
| 7d8055a703 | |||
| 1141193fc8 | |||
| 6e363a688e | |||
| 6a3c19a8a8 | |||
|
|
e63d49dc98 | ||
|
|
c854b1eab8 | ||
| df1fa69402 | |||
| 443149fe8d | |||
| 16e4f6b789 | |||
| e203f9f36d | |||
| 0d46054e56 | |||
| f76f77f770 | |||
| efe273f2fe | |||
| 4b2be8be44 | |||
| 9b268810a7 | |||
| e63bb275a0 | |||
| cf2eba6052 | |||
| 5a4bd5ee11 | |||
| 6d9d02edf7 | |||
| 7bc6d87322 |
9
.gitignore
vendored
Normal file
9
.gitignore
vendored
Normal file
@@ -0,0 +1,9 @@
|
||||
# Build output
|
||||
/Build/
|
||||
/build/
|
||||
Build/
|
||||
build/
|
||||
|
||||
# VSCodeCounter
|
||||
/.VSCodeCounter/
|
||||
.VSCodeCounter/
|
||||
10
.vscode/settings.json
vendored
Normal file
10
.vscode/settings.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"Lua.diagnostics.globals": [
|
||||
"isEqualToAny",
|
||||
"isEqualToAll",
|
||||
"syscall",
|
||||
"printf",
|
||||
"printInline",
|
||||
"toHex"
|
||||
]
|
||||
}
|
||||
164
.vscode/tasks.json
vendored
Normal file
164
.vscode/tasks.json
vendored
Normal file
@@ -0,0 +1,164 @@
|
||||
{
|
||||
"version": "2.0.0",
|
||||
"tasks": [
|
||||
{
|
||||
"label": "Build (Minfiyed)",
|
||||
"type": "shell",
|
||||
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}\\scripts\\buildMini.ps1"
|
||||
]
|
||||
},
|
||||
|
||||
"linux": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildMini.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"osx": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildMini.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
|
||||
{
|
||||
"label": "Build (Source)",
|
||||
"type": "shell",
|
||||
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}\\scripts\\build.ps1"
|
||||
]
|
||||
},
|
||||
|
||||
"linux": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/build.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"osx": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/build.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"group": {
|
||||
"kind": "build",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
|
||||
{
|
||||
"label": "Test (Minfiyed)",
|
||||
"type": "shell",
|
||||
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}\\scripts\\buildMiniTest.ps1"
|
||||
]
|
||||
},
|
||||
|
||||
"linux": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildMiniTest.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"osx": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildMiniTest.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
},
|
||||
|
||||
{
|
||||
"label": "Test (Source)",
|
||||
"type": "shell",
|
||||
|
||||
"windows": {
|
||||
"command": "powershell",
|
||||
"args": [
|
||||
"-NoProfile",
|
||||
"-ExecutionPolicy",
|
||||
"Bypass",
|
||||
"-File",
|
||||
"${workspaceFolder}\\scripts\\buildTest.ps1"
|
||||
]
|
||||
},
|
||||
|
||||
"linux": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildTest.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"osx": {
|
||||
"command": "bash",
|
||||
"args": [
|
||||
"${workspaceFolder}/scripts/buildTest.sh"
|
||||
]
|
||||
},
|
||||
|
||||
"group": {
|
||||
"kind": "test",
|
||||
"isDefault": true
|
||||
},
|
||||
"presentation": {
|
||||
"reveal": "always",
|
||||
"panel": "shared"
|
||||
},
|
||||
"problemMatcher": []
|
||||
}
|
||||
]
|
||||
}
|
||||
45
README.md
45
README.md
@@ -1,3 +1,46 @@
|
||||
# HyperionOS
|
||||
|
||||
A OS made for lua enviroments.
|
||||
HyperionOS is a modular, hybrid kernel operating system written entirely in Lua. It features a custom task scheduler, virtual filesystem, syscall interface, and separates core functionality from user-space services.
|
||||
|
||||
---
|
||||
|
||||
## Features
|
||||
|
||||
- Functionality is split into kernel modules (`.kmod`)
|
||||
- Task-based lightweight thread/task preemptive scheduler with process isolation and IPC support
|
||||
- Virtual filesystem unified interface for disk, RAM, and virtual filesystems
|
||||
- TTY & Shell
|
||||
|
||||
---
|
||||
|
||||
## Kernel Modules
|
||||
|
||||
Modules are loaded in priority order from `/lib/modules/`.
|
||||
|
||||
You can add your own `.kmod` files to extend kernel functionality without modifying the core.
|
||||
|
||||
---
|
||||
|
||||
## Debugging & Logging
|
||||
|
||||
The kernel logs to `/var/log/syslog.log` during runtime.
|
||||
you can add to it by doing `syscall.log(text, tag, color)`
|
||||
|
||||
---
|
||||
|
||||
## Contributing
|
||||
|
||||
Contributions are welcome, though please follow these guidelines:
|
||||
|
||||
1. No AI-generated kernel code, keep the core human written.
|
||||
2. Modularize, new features should go into kernel modules where possible.
|
||||
3. Document, update comments and docs when adding/changing functionality.
|
||||
4. Test, ensure your changes don’t break existing functionality.
|
||||
|
||||
Add your name to `contributors.md` when your PR is merged.
|
||||
|
||||
---
|
||||
|
||||
## License
|
||||
|
||||
This project is licensed under the MIT License. See the LICENSE file for details.
|
||||
|
||||
295
Src/Hyperion-bash/bin/bash
Normal file
295
Src/Hyperion-bash/bin/bash
Normal file
@@ -0,0 +1,295 @@
|
||||
--:Minify:--
|
||||
syscall.open("/dev/tty/TTY1","r") --stdin (Device 0)
|
||||
syscall.open("/dev/tty/TTY1","w") --stdout (Device 1)
|
||||
syscall.open("/dev/null","w") --stderr (device 2)
|
||||
|
||||
local success, errorMsg = xpcall(function()
|
||||
|
||||
|
||||
|
||||
local fs = require("sys.fs")
|
||||
|
||||
syscall.devctl(1,"clear")
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"spos",1,1)
|
||||
print("HyperionOS Bash Shell")
|
||||
|
||||
local userhost = (syscall.getUsername() or "Unknown").."@"..(syscall.getHostname() or "Unknown")
|
||||
local commandHistory = {}
|
||||
local terminate = false
|
||||
syscall.setEnviron("SHELL","rtbash")
|
||||
syscall.setEnviron("PATH","/bin/")
|
||||
syscall.chdir("/")
|
||||
local oldWD = ""
|
||||
|
||||
for i = 1, 16 do
|
||||
syscall.devctl(1,"sbgc",i)
|
||||
printInline(" ");
|
||||
end
|
||||
print("\n")
|
||||
|
||||
syscall.sigcatch(function(sig)
|
||||
if sig == 1 then
|
||||
terminate = true
|
||||
end
|
||||
end)
|
||||
|
||||
local builtinCmds = {}
|
||||
|
||||
builtinCmds.cd = function(path)
|
||||
local cwd = syscall.getcwd()
|
||||
local dirIn = (path or "")
|
||||
if dirIn == "-" then
|
||||
if oldWD == "" then
|
||||
print("bash-cd: No previous working directory set.")
|
||||
else
|
||||
print(oldWD)
|
||||
syscall.chdir(oldWD)
|
||||
oldWD = cwd
|
||||
end
|
||||
return
|
||||
end
|
||||
local dirInMod = dirIn
|
||||
if dirIn:sub(1, 1) ~= "/" then dirInMod = cwd .. "/" .. dirIn end
|
||||
local parts = {}
|
||||
for part in dirInMod:gmatch("[^/]+") do
|
||||
if part == ".." then
|
||||
if #parts > 0 then table.remove(parts) end
|
||||
elseif part ~= "." and part ~= "" then
|
||||
table.insert(parts, part)
|
||||
end
|
||||
end
|
||||
local normDir = "/" .. table.concat(parts, "/")
|
||||
if normDir:sub(#normDir, #normDir) ~= "/" then normDir = normDir .. "/" end
|
||||
|
||||
if not fs.isDir(normDir) then
|
||||
print("bash-cd: "..dirIn..": No such directory.")
|
||||
return
|
||||
end
|
||||
oldWD = cwd
|
||||
syscall.chdir(normDir)
|
||||
end
|
||||
|
||||
|
||||
local function getUserInput()
|
||||
syscall.devctl(1,"sfgc",3)
|
||||
printInline(userhost)
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
printInline(":")
|
||||
syscall.devctl(1,"sfgc",10)
|
||||
printInline(syscall.getcwd())
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
printInline("$ ")
|
||||
local curOffsetStr = syscall.devctl(1, "gpos")
|
||||
local curOffsetX = tonumber(curOffsetStr:sub(1, curOffsetStr:find(";")-1))
|
||||
local curOffsetY = tonumber(curOffsetStr:sub(curOffsetStr:find(";")+1))
|
||||
|
||||
local input = ""
|
||||
local blinkState = false
|
||||
local cursorPos = 1
|
||||
local history = 0
|
||||
|
||||
while true do
|
||||
local key=syscall.read(0)
|
||||
if key then
|
||||
if key == "\19" then --TODO: REPLACE WITH LEFT ARROW
|
||||
if cursorPos > 1 then
|
||||
cursorPos = cursorPos - 1
|
||||
end
|
||||
elseif key == "\20" then --TODO: REPLACE WITH RIGHT ARROW
|
||||
if cursorPos <= #input then
|
||||
cursorPos = cursorPos + 1
|
||||
end
|
||||
elseif key == "\17" then --TODO: REPLACE WITH UP ARROW
|
||||
if history < #commandHistory then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = history + 1
|
||||
input = commandHistory[#commandHistory - history + 1]
|
||||
cursorPos = #input + 1
|
||||
end
|
||||
elseif key == "\18" then --TODO: REPLACE WITH DOWN ARROW
|
||||
if history > 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = history - 1
|
||||
input = commandHistory[#commandHistory - history + 1]
|
||||
cursorPos = #input + 1
|
||||
elseif history == 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = 0
|
||||
input = ""
|
||||
cursorPos = 1
|
||||
end
|
||||
elseif key == "\b" then
|
||||
if cursorPos > 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
input = string.sub(input, 1, cursorPos-2)..string.sub(input, cursorPos)
|
||||
cursorPos = cursorPos - 1
|
||||
end
|
||||
elseif key == "\n" then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
print(input.." ")
|
||||
return input
|
||||
else
|
||||
input = string.sub(input, 1, cursorPos-1)..key..string.sub(input, cursorPos)
|
||||
cursorPos = cursorPos + 1
|
||||
end
|
||||
local screenSizeStr = syscall.devctl(1, "size")
|
||||
local sizeX = tonumber(screenSizeStr:sub(1, screenSizeStr:find(";")-1))
|
||||
local sizeY = tonumber(screenSizeStr:sub(screenSizeStr:find(";")+1))
|
||||
local totalChars = sizeX * sizeY
|
||||
local eocCharNum = ((curOffsetY - 1) * sizeX) + curOffsetX + #input
|
||||
if eocCharNum >= totalChars then
|
||||
syscall.devctl(1,"spos",sizeX,sizeY)
|
||||
printInline(" ")
|
||||
curOffsetY = curOffsetY - 1
|
||||
end
|
||||
end
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline(string.sub(input, 1, cursorPos-1))
|
||||
if blinkState then
|
||||
syscall.devctl(1,"sfgc",16)
|
||||
syscall.devctl(1,"sbgc",1)
|
||||
end
|
||||
if cursorPos > #input then
|
||||
printInline(" ")
|
||||
else
|
||||
printInline(string.sub(input, cursorPos, cursorPos))
|
||||
end
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sbgc",16)
|
||||
printInline(string.sub(input, cursorPos+1))
|
||||
if cursorPos <= #input then
|
||||
printInline(" ")
|
||||
end
|
||||
local curBlink = ((math.floor(syscall.getUptime() / 500) % 2) == 0)
|
||||
if curBlink ~= blinkState then
|
||||
blinkState = curBlink
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function runCommand(command)
|
||||
do
|
||||
local func = load("return " .. command, "@equation", "t", {})
|
||||
if func then
|
||||
local success, result = pcall(func)
|
||||
if success and type(result) == "number" then
|
||||
print(result)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
terminate = false
|
||||
local args = string.split(command, " ")
|
||||
if builtinCmds[args[1]] then
|
||||
local success, msg = pcall(builtinCmds[args[1]], table.unpack(args, 2))
|
||||
if not success then
|
||||
local errSL = string.sub(msg, string.find(msg, "]") + 2)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
printInline(args[1]..": Program runtime error on line ")
|
||||
print(string.sub(errSL, 1, string.find(errSL, ":") - 1))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
print(string.sub(errSL, string.find(errSL, ":") + 1))
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
local cmdPath = ""
|
||||
if string.find(args[1], "/") then
|
||||
if fs.exists(args[1]) then
|
||||
cmdPath = args[1]
|
||||
end
|
||||
else
|
||||
local paths = string.split(syscall.getEnviron("PATH"), ":")
|
||||
for _, path in pairs(paths) do
|
||||
if fs.exists(path..args[1]) then
|
||||
cmdPath = path..args[1]
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if cmdPath == "" then
|
||||
print(args[1]..": Command not found")
|
||||
return
|
||||
end
|
||||
|
||||
local progName = string.sub(cmdPath, #cmdPath - string.find(string.reverse(cmdPath), "/") + 2)
|
||||
|
||||
local text = fs.readAllText(cmdPath)
|
||||
local program, err = load(text, progName)
|
||||
if not program then
|
||||
local errSL = string.sub(err, string.find(err, ":") + 1)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
printInline(progName..": Program load error on line ")
|
||||
print(string.sub(errSL, 1, string.find(errSL, ":") - 1))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
print(string.sub(errSL, string.find(errSL, ":") + 1))
|
||||
return
|
||||
end
|
||||
|
||||
local proc = syscall.spawn(function(...)
|
||||
syscall.open("/dev/tty/TTY1","r")
|
||||
syscall.open("/dev/tty/TTY1","w")
|
||||
syscall.open("/dev/null","w")
|
||||
local success, msg = pcall(program, ...)
|
||||
if not success then
|
||||
local errSL = string.sub(msg, string.find(msg, ":") + 1)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
printInline(progName..": Program runtime error on line ")
|
||||
print(string.sub(errSL, 1, string.find(errSL, ":") - 1))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
print(string.sub(errSL, string.find(errSL, ":") + 1))
|
||||
end
|
||||
end, progName, nil, {table.unpack(args, 2)})
|
||||
|
||||
while true do
|
||||
local exited, code = syscall.collect(proc)
|
||||
if exited then
|
||||
if code then
|
||||
print("\nTask exited with code:\n"..tostring(code))
|
||||
end
|
||||
return
|
||||
end
|
||||
if terminate then
|
||||
local success, err = syscall.kill(proc)
|
||||
if success then
|
||||
syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
print("\nProgram Terminated.")
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
end
|
||||
terminate = false
|
||||
break
|
||||
end
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
local command = getUserInput()
|
||||
if command ~= "" then
|
||||
if command ~= commandHistory[#commandHistory] then
|
||||
table.insert(commandHistory, command)
|
||||
end
|
||||
runCommand(command)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
--ERROR HANDLING
|
||||
end, debug.traceback)
|
||||
|
||||
if not success then
|
||||
syscall.log("Error running shell: "..errorMsg, "ERROR")
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
syscall.devctl(1,"sbgc",16)
|
||||
print()
|
||||
print("Error running shell: ")
|
||||
print(errorMsg)
|
||||
end
|
||||
94
Src/Hyperion-bash/bin/bashex
Normal file
94
Src/Hyperion-bash/bin/bashex
Normal file
@@ -0,0 +1,94 @@
|
||||
--:Minify:--
|
||||
syscall.open("/dev/tty/TTY1","r")
|
||||
syscall.open("/dev/tty/TTY1","w")
|
||||
syscall.open("/dev/null","r")
|
||||
syscall.devctl(1,"clear")
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"spos",1,1)
|
||||
print("HyperionOS Bash Shell")
|
||||
local str=""
|
||||
local stopInput=false
|
||||
local proc=0
|
||||
local fs=require("sys.fs")
|
||||
local timeout=false
|
||||
syscall.setEnviron("SHELL","simpleshell")
|
||||
printInline("> ")
|
||||
syscall.sigcatch(function(sig)
|
||||
if sig==1 then
|
||||
syscall.kill(proc)
|
||||
print("Terminated")
|
||||
printInline("> ")
|
||||
stopInput=false
|
||||
end
|
||||
end)
|
||||
|
||||
while true do
|
||||
if not stopInput then
|
||||
local input=syscall.read(0)
|
||||
if input then
|
||||
if input=="\b" then
|
||||
if #str>0 then
|
||||
str=str:sub(1,#str-1)
|
||||
printInline("\b")
|
||||
end
|
||||
elseif input=="\n" then
|
||||
print("")
|
||||
stopInput=true
|
||||
if str == "" then
|
||||
printInline("> ")
|
||||
stopInput=false
|
||||
else
|
||||
local path=nil
|
||||
local split=string.split(str, " ")
|
||||
if fs.exists("/bin/"..split[1]) then
|
||||
path="/bin/"..split[1]
|
||||
elseif fs.exists("/bin/"..split[1]..".lua") then
|
||||
path="/bin/"..split[1]..".lua"
|
||||
end
|
||||
if not path then
|
||||
print("Program not found")
|
||||
printInline("> ")
|
||||
stopInput=false
|
||||
else
|
||||
local text = fs.readAllText(path)
|
||||
local program, err = load(text, path)
|
||||
if not program then
|
||||
print(err)
|
||||
printInline("> ")
|
||||
end
|
||||
proc = syscall.spawn(function(...)
|
||||
syscall.open("/dev/tty/TTY1","r")
|
||||
syscall.open("/dev/tty/TTY1","w")
|
||||
syscall.open("/dev/null","w")
|
||||
program(...)
|
||||
end, path, nil, {table.unpack(split, 2)})
|
||||
end
|
||||
str=""
|
||||
end
|
||||
else
|
||||
str=str..input
|
||||
printInline(input)
|
||||
end
|
||||
timeout=false
|
||||
else
|
||||
timeout=true
|
||||
end
|
||||
else
|
||||
local exited, code = syscall.collect(proc)
|
||||
if exited then
|
||||
if code then
|
||||
print("\nTask exited with code:\n"..tostring(code))
|
||||
end
|
||||
printInline("> ")
|
||||
stopInput=false
|
||||
end
|
||||
timeout=true
|
||||
end
|
||||
if timeout then
|
||||
if stopInput then
|
||||
sleep(.5)
|
||||
else
|
||||
sleep(.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
24
Src/Hyperion-bash/bin/cat
Normal file
24
Src/Hyperion-bash/bin/cat
Normal file
@@ -0,0 +1,24 @@
|
||||
local args = {...}
|
||||
local name = syscall.getTask(syscall.getpid()).name
|
||||
local fs = require("sys.fs")
|
||||
local filePath = (args[1] or "")
|
||||
if filePath:sub(1, 1) ~= "/" then
|
||||
filePath = syscall.getcwd().."/"..filePath
|
||||
end
|
||||
|
||||
if not fs.exists(filePath) and args[1] then
|
||||
print(name..": Cannot access '"..args[1].."': No such file.")
|
||||
return
|
||||
end
|
||||
|
||||
local file = 0
|
||||
if args[1] then
|
||||
file = syscall.open(filePath, "r")
|
||||
end
|
||||
local content=""
|
||||
while content~=nil or file == 0 do
|
||||
content=syscall.read(file, 1024)
|
||||
printInline(content)
|
||||
end
|
||||
syscall.close(file)
|
||||
print("")
|
||||
1
Src/Hyperion-bash/bin/clear
Normal file
1
Src/Hyperion-bash/bin/clear
Normal file
@@ -0,0 +1 @@
|
||||
syscall.devctl(1,"clear")
|
||||
2
Src/Hyperion-bash/bin/echo
Normal file
2
Src/Hyperion-bash/bin/echo
Normal file
@@ -0,0 +1,2 @@
|
||||
local args = {...}
|
||||
print(table.concat(args, " "))
|
||||
145
Src/Hyperion-bash/bin/ls
Normal file
145
Src/Hyperion-bash/bin/ls
Normal file
@@ -0,0 +1,145 @@
|
||||
local cloptions = {
|
||||
a = false,
|
||||
h = false,
|
||||
l = false,
|
||||
help = false,
|
||||
}
|
||||
|
||||
local inpArgs = {...}
|
||||
local args = {}
|
||||
local name = syscall.getTask(syscall.getpid()).name
|
||||
|
||||
local optToSet = false
|
||||
for _, v in pairs(inpArgs) do
|
||||
if optToSet then
|
||||
cloptions[optToSet] = v
|
||||
optToSet = false
|
||||
elseif v:sub(1, 2) == "--" then
|
||||
local opt = v:sub(3)
|
||||
if cloptions[opt] == nil then
|
||||
print(name..": unrecognized option '"..v.."'.")
|
||||
if cloptions.help ~= nil then
|
||||
print("try '"..name.." --help' for more information.")
|
||||
end
|
||||
return
|
||||
elseif cloptions[opt] == false then
|
||||
cloptions[opt] = true
|
||||
else
|
||||
optToSet = opt
|
||||
end
|
||||
elseif v:sub(1, 1) == "-" then
|
||||
for i = 2, #v do
|
||||
local opt = v:sub(i, i)
|
||||
if cloptions[opt] == nil then
|
||||
print(name..": invalid option '-"..opt.."'.")
|
||||
if cloptions.help ~= nil then
|
||||
print("try '"..name.." --help' for more information.")
|
||||
end
|
||||
return
|
||||
else
|
||||
cloptions[opt] = true
|
||||
end
|
||||
end
|
||||
else
|
||||
table.insert(args, v)
|
||||
end
|
||||
end
|
||||
|
||||
if cloptions.help then
|
||||
print("Usage: "..name.." [OPTION]... [DIR]")
|
||||
print("List all entries in the specified DIRectory, or cwd if not specified")
|
||||
print("\nOptions:")
|
||||
print(" -a Do not ignore entries starting with .")
|
||||
print(" -h with -l, print sizes in a human readble format")
|
||||
print(" -l Use a long listing format")
|
||||
print(" --help Display this help and exit")
|
||||
return
|
||||
end
|
||||
|
||||
local fs = require("sys.fs")
|
||||
local dir = (args[1] or "")
|
||||
if dir:sub(1, 1) ~= "/" then
|
||||
dir = syscall.getcwd().."/"..dir
|
||||
end
|
||||
|
||||
if dir:sub(#dir, #dir) ~= "/" then
|
||||
dir = dir.."/"
|
||||
end
|
||||
|
||||
if not fs.isDir(dir) then
|
||||
print(name..": Cannot access '"..args[1].."': No such directory.")
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
local screenSizeStr = syscall.devctl(1, "size")
|
||||
local sizeX = tonumber(screenSizeStr:sub(1, screenSizeStr:find(";")-1))
|
||||
local sizeY = tonumber(screenSizeStr:sub(screenSizeStr:find(";")+1))
|
||||
|
||||
local list = fs.list(dir)
|
||||
if not cloptions.a then
|
||||
for i = #list, 1, -1 do
|
||||
if list[i]:sub(1, 1) == "." then
|
||||
table.remove(list, i)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local colWidth = 0
|
||||
local numCols = 1
|
||||
if not cloptions.l then
|
||||
for _, item in pairs(list) do
|
||||
if #item + 2 > colWidth then
|
||||
colWidth = #item + 2
|
||||
end
|
||||
end
|
||||
numCols = math.floor(sizeX / colWidth)
|
||||
end
|
||||
|
||||
local sizePrefixes = {"K", "M", "G"}
|
||||
|
||||
for i,v in ipairs(list) do
|
||||
local fileStats = syscall.stat(dir..v)
|
||||
local isDir = fs.isDir(dir..v)
|
||||
if cloptions.l then
|
||||
if isDir then
|
||||
printInline("d")
|
||||
else
|
||||
printInline("-")
|
||||
end
|
||||
printInline("------ ")
|
||||
printInline(fileStats.owner.." ")
|
||||
printInline(fileStats.group.." ")
|
||||
local size = fileStats.size
|
||||
if cloptions.h then
|
||||
local scale = 0
|
||||
while size > 1024 do
|
||||
size = size / 1024
|
||||
scale = scale + 1
|
||||
end
|
||||
if scale > 0 then
|
||||
if size < 10 then
|
||||
size = math.floor(size).."."..math.floor((size * 10) % 10)..sizePrefixes[scale]
|
||||
else
|
||||
size = math.floor(size)..sizePrefixes[scale]
|
||||
end
|
||||
end
|
||||
end
|
||||
printInline(size.." ")
|
||||
printInline(math.floor(fileStats.modified / 1000).." ")
|
||||
end
|
||||
if isDir then
|
||||
syscall.devctl(1,"sfgc",4)
|
||||
else
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
end
|
||||
printInline(v)
|
||||
printInline((" "):rep(colWidth - #v))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
if i % numCols == 0 then
|
||||
print("")
|
||||
end
|
||||
end
|
||||
if #list % numCols ~= 0 then
|
||||
print("")
|
||||
end
|
||||
149
Src/Hyperion-bash/bin/lua
Normal file
149
Src/Hyperion-bash/bin/lua
Normal file
@@ -0,0 +1,149 @@
|
||||
syscall.devctl(1,"sfgc",7)
|
||||
print("HyperionOS Lua prompt.")
|
||||
print("Call exit() to exit.")
|
||||
|
||||
local commandHistory = {}
|
||||
local luaEnv=setmetatable({
|
||||
["exit"] = setmetatable({}, {
|
||||
__tostring = function() return "Call exit() to exit." end,
|
||||
__call = function() syscall.exit() end,
|
||||
}),
|
||||
["_echo"] = function(...)
|
||||
return ...
|
||||
end,
|
||||
},{__index=_ENV})
|
||||
|
||||
local function getUserInput()
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
printInline("lua> ")
|
||||
local curOffsetStr = syscall.devctl(1, "gpos")
|
||||
local curOffsetX = tonumber(curOffsetStr:sub(1, curOffsetStr:find(";")-1))
|
||||
local curOffsetY = tonumber(curOffsetStr:sub(curOffsetStr:find(";")+1))
|
||||
|
||||
local input = ""
|
||||
local blinkState = false
|
||||
local cursorPos = 1
|
||||
local history = 0
|
||||
|
||||
while true do
|
||||
local key=syscall.read(0)
|
||||
if key then
|
||||
if key == "\19" then --TODO: REPLACE WITH LEFT ARROW
|
||||
if cursorPos > 1 then
|
||||
cursorPos = cursorPos - 1
|
||||
end
|
||||
elseif key == "\20" then --TODO: REPLACE WITH RIGHT ARROW
|
||||
if cursorPos <= #input then
|
||||
cursorPos = cursorPos + 1
|
||||
end
|
||||
elseif key == "\17" then --TODO: REPLACE WITH UP ARROW
|
||||
if history < #commandHistory then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = history + 1
|
||||
input = commandHistory[#commandHistory - history + 1]
|
||||
cursorPos = #input + 1
|
||||
end
|
||||
elseif key == "\18" then --TODO: REPLACE WITH DOWN ARROW
|
||||
if history > 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = history - 1
|
||||
input = commandHistory[#commandHistory - history + 1]
|
||||
cursorPos = #input + 1
|
||||
elseif history == 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
history = 0
|
||||
input = ""
|
||||
cursorPos = 1
|
||||
end
|
||||
elseif key == "\b" then
|
||||
if cursorPos > 1 then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline((" "):rep(#input + 1))
|
||||
input = string.sub(input, 1, cursorPos-2)..string.sub(input, cursorPos)
|
||||
cursorPos = cursorPos - 1
|
||||
end
|
||||
elseif key == "\n" then
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
print(input.." ")
|
||||
return input
|
||||
else
|
||||
input = string.sub(input, 1, cursorPos-1)..key..string.sub(input, cursorPos)
|
||||
cursorPos = cursorPos + 1
|
||||
end
|
||||
local screenSizeStr = syscall.devctl(1, "size")
|
||||
local sizeX = tonumber(screenSizeStr:sub(1, screenSizeStr:find(";")-1))
|
||||
local sizeY = tonumber(screenSizeStr:sub(screenSizeStr:find(";")+1))
|
||||
local totalChars = sizeX * sizeY
|
||||
local eocCharNum = ((curOffsetY - 1) * sizeX) + curOffsetX + #input
|
||||
if eocCharNum >= totalChars then
|
||||
syscall.devctl(1,"spos",sizeX,sizeY)
|
||||
printInline(" ")
|
||||
curOffsetY = curOffsetY - 1
|
||||
end
|
||||
end
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
printInline(string.sub(input, 1, cursorPos-1))
|
||||
if blinkState then
|
||||
syscall.devctl(1,"sfgc",16)
|
||||
syscall.devctl(1,"sbgc",1)
|
||||
end
|
||||
if cursorPos > #input then
|
||||
printInline(" ")
|
||||
else
|
||||
printInline(string.sub(input, cursorPos, cursorPos))
|
||||
end
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sbgc",16)
|
||||
printInline(string.sub(input, cursorPos+1))
|
||||
if cursorPos <= #input then
|
||||
printInline(" ")
|
||||
end
|
||||
local curBlink = ((math.floor(syscall.getUptime() / 500) % 2) == 0)
|
||||
if curBlink ~= blinkState then
|
||||
blinkState = curBlink
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function runCode(code)
|
||||
local func, err = load(code, "@lua", "t", luaEnv)
|
||||
local isReturn = false
|
||||
if load("return "..code) then
|
||||
func, err = load("return _echo("..code.."\n)", "@lua", "t", luaEnv)
|
||||
isReturn = true
|
||||
end
|
||||
if not func then
|
||||
local errSL = string.sub(err, string.find(err, ":") + 1)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
printInline("@lua: Load error on line ")
|
||||
print(string.sub(errSL, 1, string.find(errSL, ":") - 1))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
print(string.sub(errSL, string.find(errSL, ":") + 1))
|
||||
return
|
||||
end
|
||||
|
||||
local success, msg = xpcall(func, debug.traceback)
|
||||
if not success then
|
||||
local errSL = string.sub(msg, string.find(msg, ":") + 1)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
printInline("@lua: Runtime error on line ")
|
||||
print(string.sub(errSL, 1, string.find(errSL, ":") - 1))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
print(string.sub(errSL, string.find(errSL, ":") + 1))
|
||||
elseif isReturn then
|
||||
print(tostring(msg))
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
local code = getUserInput()
|
||||
if code ~= "" then
|
||||
if code ~= commandHistory[#commandHistory] then
|
||||
table.insert(commandHistory, code)
|
||||
end
|
||||
runCode(code)
|
||||
end
|
||||
end
|
||||
50
Src/Hyperion-bash/bin/luaold
Normal file
50
Src/Hyperion-bash/bin/luaold
Normal file
@@ -0,0 +1,50 @@
|
||||
--:Minify:--
|
||||
print("HyperionOS lua")
|
||||
local str=""
|
||||
local stopInput=false
|
||||
local timeout=false
|
||||
local luaEnv=setmetatable({},{__index=_ENV})
|
||||
printInline("> ")
|
||||
while true do
|
||||
local input=syscall.read(0)
|
||||
if input then
|
||||
if input=="\b" then
|
||||
if #str>0 then
|
||||
str=str:sub(1,#str-1)
|
||||
printInline("\b")
|
||||
end
|
||||
elseif input=="\n" then
|
||||
print("")
|
||||
stopInput=true
|
||||
if str == "" then
|
||||
printInline("> ")
|
||||
stopInput=false
|
||||
elseif str == "exit()" then
|
||||
break
|
||||
else
|
||||
local func=load(str,"@Lua","t",luaEnv)
|
||||
local ok,err = xpcall(func, debug.traceback)
|
||||
if not ok then
|
||||
print(err)
|
||||
end
|
||||
printInline("\n> ")
|
||||
str=""
|
||||
end
|
||||
str=""
|
||||
else
|
||||
str=str..input
|
||||
printInline(input)
|
||||
end
|
||||
timeout=false
|
||||
else
|
||||
timeout=true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
if stopInput then
|
||||
sleep(.5)
|
||||
else
|
||||
sleep(.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
23
Src/Hyperion-bash/bin/mkdir
Normal file
23
Src/Hyperion-bash/bin/mkdir
Normal file
@@ -0,0 +1,23 @@
|
||||
local args = {...}
|
||||
local name = syscall.getTask(syscall.getpid()).name
|
||||
if #args == 0 then
|
||||
print(name..": Missing operand.")
|
||||
return
|
||||
end
|
||||
|
||||
local fs = require("sys.fs")
|
||||
local newDir = args[1]
|
||||
if newDir:sub(1, 1) ~= "/" then
|
||||
newDir = syscall.getcwd().."/"..newDir
|
||||
end
|
||||
|
||||
if newDir:sub(#newDir, #newDir) ~= "/" then
|
||||
newDir = newDir.."/"
|
||||
end
|
||||
|
||||
if fs.isDir(newDir) then
|
||||
print(name..": Cannot create directory '"..args[1].."': Directory already exists.")
|
||||
return
|
||||
end
|
||||
|
||||
fs.mkdir(newDir)
|
||||
18
Src/Hyperion-bash/bin/neofetch
Normal file
18
Src/Hyperion-bash/bin/neofetch
Normal file
@@ -0,0 +1,18 @@
|
||||
local userhost = (syscall.getUsername() or "Unknown").."@"..(syscall.getHostname() or "Unknown")
|
||||
print(".. *. .. | "..userhost)
|
||||
print(" *= +@* +* | "..string.rep("-",#userhost))
|
||||
print(" .@#. -@@@= :#@. | OS: "..(syscall.version() or "Unknown"))
|
||||
print(" =@@+ *@@@# +@@= | Host: "..(syscall.getHost() or "Unknown"))
|
||||
print(" %@@%: *@@@# -%@@% | Uptime: "..(syscall.getUptime() or "Unknown"))
|
||||
print(" :@@@@+ *@@@# .*@@@@: | Tasks: "..tostring((#syscall.getTasks() or "Unknown")))
|
||||
print(" :*@@@%- *@@@# -@@@@*: | Packages: ".."Unknown")
|
||||
print(" =%@@#. *@@@# .#@@%= | Shell: "..(syscall.getEnviron("SHELL") or "Unknown"))
|
||||
print(" :=. :*@@= *@@@# =@@+: .=: | ")
|
||||
print(" %@#=..*# +@@@# #*..=#@# | ")
|
||||
print(" .@@@@+=# .%@%: #=+@@@@. | ")
|
||||
print(" .....=# -@= *+...:. | ")
|
||||
print(" -*%*-@= - =@-*%*- | ")
|
||||
print(" -@*. -@%. :%@- :*@- | ")
|
||||
print(" .#@#@* | ")
|
||||
print(" -#- | ")
|
||||
print(" | ")
|
||||
4
Src/Hyperion-bash/bin/ps
Normal file
4
Src/Hyperion-bash/bin/ps
Normal file
@@ -0,0 +1,4 @@
|
||||
for i,v in ipairs(syscall.getTasks()) do
|
||||
local task = syscall.getTask(v)
|
||||
print(task.pid,task.username,task.name,task.status)
|
||||
end
|
||||
1
Src/Hyperion-bash/bin/pwd
Normal file
1
Src/Hyperion-bash/bin/pwd
Normal file
@@ -0,0 +1 @@
|
||||
print(syscall.getcwd())
|
||||
4
Src/Hyperion-bash/bin/startup/runShell.lua
Normal file
4
Src/Hyperion-bash/bin/startup/runShell.lua
Normal file
@@ -0,0 +1,4 @@
|
||||
local fs = require("sys.fs")
|
||||
local bashStr = fs.readAllText("/bin/bash")
|
||||
local bashFun = load(bashStr)
|
||||
syscall.spawn(bashFun, "bash")
|
||||
1
Src/Hyperion-bash/bin/startup/test.lua
Normal file
1
Src/Hyperion-bash/bin/startup/test.lua
Normal file
@@ -0,0 +1 @@
|
||||
syscall.chown("/bin", 0, 0)
|
||||
5
Src/Hyperion-bash/bin/sysdump
Normal file
5
Src/Hyperion-bash/bin/sysdump
Normal file
@@ -0,0 +1,5 @@
|
||||
local syscalls=syscall.sysdump()
|
||||
for i=1, #syscalls do
|
||||
print(syscalls[i])
|
||||
end
|
||||
print("Total # of syscalls: "..tostring(#syscalls))
|
||||
1
Src/Hyperion-bash/bin/whoami
Normal file
1
Src/Hyperion-bash/bin/whoami
Normal file
@@ -0,0 +1 @@
|
||||
print((syscall.getUsername() or "Unknown"))
|
||||
8
Src/Hyperion-bash/bin/yes
Normal file
8
Src/Hyperion-bash/bin/yes
Normal file
@@ -0,0 +1,8 @@
|
||||
local args = {...}
|
||||
while true do
|
||||
if #args == 0 then
|
||||
print("y")
|
||||
else
|
||||
print(table.concat(args, " "))
|
||||
end
|
||||
end
|
||||
137
Src/Hyperion-core/lib/bit32
Normal file
137
Src/Hyperion-core/lib/bit32
Normal file
@@ -0,0 +1,137 @@
|
||||
--:Minify:--
|
||||
|
||||
local bit32 = {}
|
||||
|
||||
local MOD32 = 2^32
|
||||
local MOD31 = 2^31
|
||||
|
||||
local function norm(x)
|
||||
return x % MOD32
|
||||
end
|
||||
|
||||
-- Convert number to bit table
|
||||
local function tobits(x)
|
||||
x = norm(x)
|
||||
local t = {}
|
||||
for i = 0, 31 do
|
||||
local b = x % 2
|
||||
t[i] = b
|
||||
x = (x - b) / 2
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
-- Convert bit table to number
|
||||
local function frombits(t)
|
||||
local x = 0
|
||||
local p = 1
|
||||
for i = 0, 31 do
|
||||
if t[i] == 1 then
|
||||
x = x + p
|
||||
end
|
||||
p = p * 2
|
||||
end
|
||||
return norm(x)
|
||||
end
|
||||
|
||||
-- ===== Logical ops =====
|
||||
|
||||
function bit32.band(...)
|
||||
local args = {...}
|
||||
if #args == 0 then return 0xFFFFFFFF end
|
||||
local bits = tobits(args[1])
|
||||
for i = 2, #args do
|
||||
local b = tobits(args[i])
|
||||
for j = 0, 31 do
|
||||
bits[j] = (bits[j] == 1 and b[j] == 1) and 1 or 0
|
||||
end
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
function bit32.bor(...)
|
||||
local args = {...}
|
||||
if #args == 0 then return 0 end
|
||||
local bits = tobits(args[1])
|
||||
for i = 2, #args do
|
||||
local b = tobits(args[i])
|
||||
for j = 0, 31 do
|
||||
bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
|
||||
end
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
function bit32.bxor(...)
|
||||
local args = {...}
|
||||
if #args == 0 then return 0 end
|
||||
local bits = tobits(args[1])
|
||||
for i = 2, #args do
|
||||
local b = tobits(args[i])
|
||||
for j = 0, 31 do
|
||||
bits[j] = (bits[j] ~= b[j]) and 1 or 0
|
||||
end
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
function bit32.bnot(x)
|
||||
local bits = tobits(x)
|
||||
for i = 0, 31 do
|
||||
bits[i] = bits[i] == 1 and 0 or 1
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
-- ===== Shifts =====
|
||||
|
||||
function bit32.lshift(x, n)
|
||||
return norm(norm(x) * 2^n)
|
||||
end
|
||||
|
||||
function bit32.rshift(x, n)
|
||||
return math.floor(norm(x) / 2^n)
|
||||
end
|
||||
|
||||
function bit32.arshift(x, n)
|
||||
x = norm(x)
|
||||
if x >= MOD31 then
|
||||
return math.floor((x - MOD32) / 2^n)
|
||||
else
|
||||
return math.floor(x / 2^n)
|
||||
end
|
||||
end
|
||||
|
||||
-- ===== Rotates =====
|
||||
|
||||
function bit32.lrotate(x, n)
|
||||
n = n % 32
|
||||
x = norm(x)
|
||||
local left = (x * 2^n) % MOD32
|
||||
local right = math.floor(x / 2^(32 - n))
|
||||
return norm(left + right)
|
||||
end
|
||||
|
||||
function bit32.rrotate(x, n)
|
||||
n = n % 32
|
||||
x = norm(x)
|
||||
local right = math.floor(x / 2^n)
|
||||
local left = (x * 2^(32 - n)) % MOD32
|
||||
return norm(left + right)
|
||||
end
|
||||
|
||||
-- ===== Bit fields =====
|
||||
|
||||
function bit32.extract(x, field, width)
|
||||
width = width or 1
|
||||
return bit32.band(bit32.rshift(x, field), 2^width - 1)
|
||||
end
|
||||
|
||||
function bit32.replace(x, v, field, width)
|
||||
width = width or 1
|
||||
local mask = bit32.lshift(2^width - 1, field)
|
||||
x = bit32.band(x, bit32.bnot(mask))
|
||||
return bit32.bor(x, bit32.lshift(v, field))
|
||||
end
|
||||
|
||||
return bit32
|
||||
117
Src/Hyperion-core/lib/crypto/blake2s
Normal file
117
Src/Hyperion-core/lib/crypto/blake2s
Normal file
@@ -0,0 +1,117 @@
|
||||
--:Minify:--
|
||||
-- blake2s.lua
|
||||
-- Pure Lua 5.2, 32-bit only, supports keyed hashing
|
||||
|
||||
local bit32 = require("bit32")
|
||||
local band, bor, bxor = bit32.band, bit32.bor, bit32.bxor
|
||||
local rshift, lshift = bit32.rshift, bit32.lshift
|
||||
|
||||
local MOD32 = 2^32
|
||||
|
||||
local function rotr(x, n)
|
||||
return bor(rshift(x, n), lshift(x, 32 - n))
|
||||
end
|
||||
|
||||
local IV = {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
}
|
||||
|
||||
local SIGMA = {
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
|
||||
{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
|
||||
{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
|
||||
{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
|
||||
{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
|
||||
{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
|
||||
{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
|
||||
{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
|
||||
{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}
|
||||
}
|
||||
|
||||
local function G(v, a, b, c, d, x, y)
|
||||
v[a] = (v[a] + v[b] + x) % MOD32
|
||||
v[d] = rotr(bxor(v[d], v[a]), 16)
|
||||
v[c] = (v[c] + v[d]) % MOD32
|
||||
v[b] = rotr(bxor(v[b], v[c]), 12)
|
||||
v[a] = (v[a] + v[b] + y) % MOD32
|
||||
v[d] = rotr(bxor(v[d], v[a]), 8)
|
||||
v[c] = (v[c] + v[d]) % MOD32
|
||||
v[b] = rotr(bxor(v[b], v[c]), 7)
|
||||
end
|
||||
|
||||
local function compress(h, block, t, last)
|
||||
local v = {}
|
||||
for i = 1, 8 do v[i] = h[i] end
|
||||
for i = 1, 8 do v[i + 8] = IV[i] end
|
||||
|
||||
v[13] = bxor(v[13], t)
|
||||
if last then
|
||||
v[15] = bxor(v[15], 0xFFFFFFFF)
|
||||
end
|
||||
|
||||
local m = {}
|
||||
for i = 0, 15 do
|
||||
local p = i * 4 + 1
|
||||
m[i] =
|
||||
(block:byte(p) or 0) +
|
||||
((block:byte(p + 1) or 0) * 0x100) +
|
||||
((block:byte(p + 2) or 0) * 0x10000) +
|
||||
((block:byte(p + 3) or 0) * 0x1000000)
|
||||
end
|
||||
|
||||
for r = 1, 10 do
|
||||
local s = SIGMA[r]
|
||||
G(v,1,5,9,13, m[s[1]], m[s[2]])
|
||||
G(v,2,6,10,14, m[s[3]], m[s[4]])
|
||||
G(v,3,7,11,15, m[s[5]], m[s[6]])
|
||||
G(v,4,8,12,16, m[s[7]], m[s[8]])
|
||||
G(v,1,6,11,16, m[s[9]], m[s[10]])
|
||||
G(v,2,7,12,13, m[s[11]], m[s[12]])
|
||||
G(v,3,8,9,14, m[s[13]], m[s[14]])
|
||||
G(v,4,5,10,15, m[s[15]], m[s[16]])
|
||||
end
|
||||
|
||||
for i = 1, 8 do
|
||||
h[i] = bxor(h[i], v[i], v[i + 8])
|
||||
end
|
||||
end
|
||||
|
||||
local function blake2s(msg, key)
|
||||
key = key or ""
|
||||
|
||||
local h = {}
|
||||
for i = 1, 8 do h[i] = IV[i] end
|
||||
|
||||
local outlen = 32 -- bytes
|
||||
h[1] = bxor(
|
||||
h[1],
|
||||
0x01010000 + lshift(#key, 8) + outlen
|
||||
)
|
||||
|
||||
local t = 0
|
||||
|
||||
if #key > 0 then
|
||||
local block = key .. string.rep("\0", 64 - #key)
|
||||
t = #key
|
||||
compress(h, block, t, false)
|
||||
end
|
||||
|
||||
for i = 1, #msg, 64 do
|
||||
local block = msg:sub(i, i + 63)
|
||||
if #block < 64 then
|
||||
block = block .. string.rep("\0", 64 - #block)
|
||||
end
|
||||
t = t + math.min(64, #msg - i + 1)
|
||||
compress(h, block, t, i + 64 > #msg)
|
||||
end
|
||||
|
||||
local out = ""
|
||||
for i = 1, 8 do
|
||||
out = out .. string.format("%08x", h[i])
|
||||
end
|
||||
return out
|
||||
end
|
||||
|
||||
return blake2s
|
||||
6
Src/Hyperion-core/lib/io
Normal file
6
Src/Hyperion-core/lib/io
Normal file
@@ -0,0 +1,6 @@
|
||||
local io = {}
|
||||
local fs = require("sys.fs")
|
||||
|
||||
function io.open(path, mode)
|
||||
return fs.open(path, mode)
|
||||
end
|
||||
3544
Src/Hyperion-core/lib/store/LibDeflate
Normal file
3544
Src/Hyperion-core/lib/store/LibDeflate
Normal file
File diff suppressed because it is too large
Load Diff
9
Src/Hyperion-core/lib/store/deflate
Normal file
9
Src/Hyperion-core/lib/store/deflate
Normal file
@@ -0,0 +1,9 @@
|
||||
local deflate=require("LibDeflate")
|
||||
local lib={}
|
||||
lib.compress=function(data)
|
||||
return deflate:CompressDeflate(data)
|
||||
end
|
||||
lib.decompress=function(data)
|
||||
return deflate:DecompressDeflate(data)
|
||||
end
|
||||
return lib
|
||||
143
Src/Hyperion-core/lib/sys/fs
Normal file
143
Src/Hyperion-core/lib/sys/fs
Normal file
@@ -0,0 +1,143 @@
|
||||
--:Minify:--
|
||||
local fs={}
|
||||
|
||||
-- "open" : open
|
||||
-- "read" : read
|
||||
-- "write" : write
|
||||
-- "close" : close
|
||||
|
||||
function fs.open(path, mode)
|
||||
local fd=syscall.open(path,mode)
|
||||
local ret={
|
||||
close=function()
|
||||
-- close file
|
||||
return syscall.close(fd)
|
||||
end,
|
||||
flush=function()
|
||||
-- close and reopen file to flush buffers
|
||||
syscall.fsync(fd)
|
||||
end
|
||||
}
|
||||
if mode=="r" then
|
||||
ret.read=function(count)
|
||||
local data = syscall.read(fd,count)
|
||||
return data
|
||||
end
|
||||
ret.readAll=function(chunkSize)
|
||||
local chunks={} -- to store read chunks
|
||||
while true do
|
||||
local chunk=syscall.read(fd,chunkSize or 65536)
|
||||
if chunk==nil or #chunk==0 then break end
|
||||
table.insert(chunks,chunk)
|
||||
end
|
||||
return table.concat(chunks)
|
||||
end
|
||||
ret.readLine = function(chunkSize)
|
||||
local buffer = {} -- stores leftover data
|
||||
local buffer_str = "" -- concatenated buffer
|
||||
local chunk_size = chunkSize or 65536 -- adjust chunk size for performance
|
||||
local eof = false
|
||||
|
||||
while true do
|
||||
-- Try to find a newline in the current buffer
|
||||
local line_end = buffer_str:find("\n")
|
||||
if line_end then
|
||||
local line = buffer_str:sub(1, line_end - 1)
|
||||
buffer_str = buffer_str:sub(line_end + 1)
|
||||
return line
|
||||
end
|
||||
|
||||
-- If EOF was reached previously and buffer is empty, stop
|
||||
if eof then
|
||||
if buffer_str ~= "" then
|
||||
local last_line = buffer_str
|
||||
buffer_str = ""
|
||||
return last_line
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end
|
||||
|
||||
-- Read the next chunk
|
||||
local chunk = syscall.read(fd, chunk_size)
|
||||
if not chunk or chunk == "" then
|
||||
eof = true
|
||||
else
|
||||
buffer_str = buffer_str .. chunk
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif mode=="w" then
|
||||
ret.write=function(data)
|
||||
-- write data to file
|
||||
return syscall.write(fd,data)
|
||||
end
|
||||
elseif mode=="a" then
|
||||
ret.write=function(data)
|
||||
-- append data to file
|
||||
return syscall.write(fd,data)
|
||||
end
|
||||
else
|
||||
error("Invalid mode '"..mode.."'",2)
|
||||
end
|
||||
return ret
|
||||
end
|
||||
|
||||
function fs.readAllText(path)
|
||||
local file=fs.open(path,"r")
|
||||
if not file then return false end
|
||||
local content=file.readAll()
|
||||
file.close()
|
||||
return content
|
||||
end
|
||||
|
||||
function fs.writeAllText(path, data)
|
||||
local file=fs.open(path,"w")
|
||||
file.write(data)
|
||||
file.close()
|
||||
end
|
||||
|
||||
function fs.appendAllText(path, data)
|
||||
local file=fs.open(path,"a")
|
||||
if not file then return false end
|
||||
file.write(data)
|
||||
file.close()
|
||||
end
|
||||
|
||||
function fs.mkdir(path)
|
||||
return syscall.mkdir(path)
|
||||
end
|
||||
|
||||
function fs.remove(path)
|
||||
return syscall.remove(path)
|
||||
end
|
||||
|
||||
function fs.list(path)
|
||||
return syscall.listdir(path)
|
||||
end
|
||||
|
||||
function fs.type(path)
|
||||
return syscall.type(path)
|
||||
end
|
||||
|
||||
function fs.stat(path)
|
||||
return syscall.stat(path)
|
||||
end
|
||||
|
||||
function fs.exists(path)
|
||||
return syscall.exists(path)
|
||||
end
|
||||
|
||||
function fs.getcwd()
|
||||
return syscall.getcwd()
|
||||
end
|
||||
|
||||
function fs.chdir(path)
|
||||
return syscall.chdir(path)
|
||||
end
|
||||
|
||||
function fs.isDir(path)
|
||||
return syscall.type(path) == "directory"
|
||||
end
|
||||
|
||||
return fs
|
||||
6
Src/Hyperion-core/lib/sys/hpv
Normal file
6
Src/Hyperion-core/lib/sys/hpv
Normal file
@@ -0,0 +1,6 @@
|
||||
local sys = {}
|
||||
local fs = require("sys.fs")
|
||||
|
||||
|
||||
|
||||
return sys
|
||||
5
Src/Hyperion-core/lib/sys/init
Normal file
5
Src/Hyperion-core/lib/sys/init
Normal file
@@ -0,0 +1,5 @@
|
||||
local sys = {}
|
||||
sys.fs = require("sys.fs")
|
||||
sys.hpv = require("sys.hpv")
|
||||
sys.ipc = require("sys.ipc")
|
||||
return sys
|
||||
3
Src/Hyperion-core/lib/sys/ipc
Normal file
3
Src/Hyperion-core/lib/sys/ipc
Normal file
@@ -0,0 +1,3 @@
|
||||
local ipc = {}
|
||||
|
||||
return ipc
|
||||
71
Src/Hyperion-core/lib/sys/term
Normal file
71
Src/Hyperion-core/lib/sys/term
Normal file
@@ -0,0 +1,71 @@
|
||||
local term = {}
|
||||
|
||||
function term.clear()
|
||||
coroutine.yield("VFS_write", 1, "\27C\25")
|
||||
end
|
||||
|
||||
function term.setCursorPos(x, y)
|
||||
coroutine.yield("VFS_write", 1, "\27cs"..tostring(y)..";"..tostring(x).."\25")
|
||||
end
|
||||
|
||||
function term.size()
|
||||
coroutine.yield("VFS_write", 1, "\27ts\25")
|
||||
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
|
||||
if not ok then error("Failed to get terminal size") end
|
||||
local x, y = string.match(data, "%R(%d+);(%d+)\25")
|
||||
return tonumber(x), tonumber(y)
|
||||
end
|
||||
|
||||
function term.getCursorPos()
|
||||
coroutine.yield("VFS_write", 1, "\27gc\25")
|
||||
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
|
||||
if not ok then error("Failed to get cursor position") end
|
||||
local y, x = string.match(data, "%R(%d+);(%d+)\25")
|
||||
return tonumber(x), tonumber(y)
|
||||
end
|
||||
|
||||
function term.write(data)
|
||||
coroutine.yield("VFS_write", 1, data)
|
||||
end
|
||||
|
||||
function term.setTextColor(color)
|
||||
local ok, err = coroutine.yield("VFS_type", 1)
|
||||
if not ok then error(err) end
|
||||
if ok ~= "tty" then return end
|
||||
coroutine.yield("VFS_write", 1, "\27f"..tostring(color).."\25")
|
||||
end
|
||||
|
||||
function term.setBackgroundColor(color)
|
||||
local ok, err = coroutine.yield("VFS_type", 1)
|
||||
if not ok then error(err) end
|
||||
if ok ~= "tty" then return end
|
||||
coroutine.yield("VFS_write", 1, "\27b"..tostring(color).."\25")
|
||||
end
|
||||
|
||||
function term.isColor()
|
||||
local ok, err = coroutine.yield("VFS_type", 1)
|
||||
if not ok then error(err) end
|
||||
return ok == "tty"
|
||||
end
|
||||
|
||||
function term.scroll(n)
|
||||
coroutine.yield("VFS_write", 1, "\27S"..tostring(n).."\25")
|
||||
end
|
||||
|
||||
function term.setDefault(color, layer)
|
||||
if layer then
|
||||
coroutine.yield("VFS_write", 1, "\27F"..tostring(color).."\25")
|
||||
else
|
||||
coroutine.yield("VFS_write", 1, "\27B"..tostring(color).."\25")
|
||||
end
|
||||
end
|
||||
|
||||
function term.showCursor(show)
|
||||
if show then
|
||||
coroutine.yield("VFS_write", 1, "\27sc\25")
|
||||
else
|
||||
coroutine.yield("VFS_write", 1, "\27hc\25")
|
||||
end
|
||||
end
|
||||
|
||||
return term
|
||||
43
Src/Hyperion-core/sbin/init.lua
Normal file
43
Src/Hyperion-core/sbin/init.lua
Normal file
@@ -0,0 +1,43 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local fs=require("sys.fs")
|
||||
|
||||
for i,v in pairs(kernel.processes) do
|
||||
kernel.log("Spawning kernel task "..i)
|
||||
syscall.spawn(function()
|
||||
local status, err = pcall(v)
|
||||
if not status then
|
||||
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR")
|
||||
else
|
||||
kernel.log("Successfully executed kernel task: " .. i, "INFO")
|
||||
end
|
||||
end, i)
|
||||
end
|
||||
|
||||
local files = fs.list("/bin/startup")
|
||||
if not files then error("Failed to list /bin/startup") end
|
||||
for i,v in ipairs(files) do
|
||||
if v:sub(-4) == ".lua" then
|
||||
local filepath = "/bin/startup/" .. v
|
||||
kernel.log("Executing startup script: " .. filepath, "INFO")
|
||||
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
|
||||
if not startupFunc then
|
||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR")
|
||||
else
|
||||
syscall.spawn(function()
|
||||
syscall.setuid(1)
|
||||
local status, err = pcall(startupFunc)
|
||||
if not status then
|
||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR")
|
||||
else
|
||||
kernel.log("Successfully executed startup script: " .. filepath, "INFO")
|
||||
end
|
||||
end, "startup:" .. v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
while true do
|
||||
sleep(1)
|
||||
kernel.saveLog()
|
||||
end
|
||||
309
Src/Hyperion-firmware-cct/boot/cct/boot.lua
Normal file
309
Src/Hyperion-firmware-cct/boot/cct/boot.lua
Normal file
@@ -0,0 +1,309 @@
|
||||
-- :Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
local os = os
|
||||
local function write(text)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
local function displaySuperBadError(err)
|
||||
term.setBackgroundColor(0x1)
|
||||
term.setTextColor(0x4)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
term.write("A critical error occurred while loading the system:")
|
||||
term.setCursorPos(1, 3)
|
||||
write(err)
|
||||
while true do end
|
||||
end
|
||||
|
||||
term.setCursorBlink(false)
|
||||
local ok, err = xpcall(function()
|
||||
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
||||
|
||||
local lua = {
|
||||
coroutine = true,
|
||||
debug = true,
|
||||
_VERSION = true,
|
||||
assert = true,
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
gcinfo = true,
|
||||
getfenv = true,
|
||||
getmetatable = true,
|
||||
ipairs = true,
|
||||
__inext = true,
|
||||
load = true,
|
||||
math = true,
|
||||
next = true,
|
||||
pairs = true,
|
||||
pcall = true,
|
||||
rawequal = true,
|
||||
rawget = true,
|
||||
rawlen = true,
|
||||
rawset = true,
|
||||
select = true,
|
||||
setfenv = true,
|
||||
setmetatable = true,
|
||||
string = true,
|
||||
table = true,
|
||||
tonumber = true,
|
||||
tostring = true,
|
||||
type = true,
|
||||
xpcall = true,
|
||||
_G = true
|
||||
}
|
||||
|
||||
local debug = debug
|
||||
for i, v in pairs(_G) do
|
||||
if not lua[i] or lua[i] == nil then
|
||||
apis[i] = v
|
||||
_G[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local acekeys={
|
||||
[apis.keys.enter]="\n",
|
||||
[apis.keys.tab]="\t",
|
||||
[apis.keys.backspace]="\b",
|
||||
[apis.keys.up]="\17",
|
||||
[apis.keys.down]="\18",
|
||||
[apis.keys.left]="\19",
|
||||
[apis.keys.right]="\20",
|
||||
}
|
||||
|
||||
function sleep(time)
|
||||
local stoptime = apis.os.clock() + (time)
|
||||
while stoptime > apis.os.clock() do end
|
||||
end
|
||||
|
||||
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
|
||||
local function getFile(path)
|
||||
local file = apis.fs.open(path, "r")
|
||||
if not file then
|
||||
displaySuperBadError("Could not open file: " .. path)
|
||||
end
|
||||
local content = file.readAll()
|
||||
file.close()
|
||||
return content
|
||||
end
|
||||
|
||||
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
|
||||
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
|
||||
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
|
||||
|
||||
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
else
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
getEEPROM = function() return getFile("/startup.lua") end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open("/startup.lua", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end
|
||||
}
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
|
||||
{
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
clear = function()
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
end,
|
||||
setCursorPos = function(_, x, y)
|
||||
apis.term.setCursorPos(x, y)
|
||||
end,
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(colors[color])
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(colors[color])
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return icolors[apis.term.getBackgroundColor()]
|
||||
end,
|
||||
getTextColor = function()
|
||||
return icolors[apis.term.getTextColor()]
|
||||
end
|
||||
}, computer, fs, "$")
|
||||
if not ok then displaySuperBadError(err) end
|
||||
end)
|
||||
|
||||
-- time is in milliseconds
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = computer.time()
|
||||
debug.sethook(co, function()
|
||||
if computer.time() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
local ret = {coroutine.resume(co, ...)}
|
||||
if ret[1] and ret[2] == "timeout" then
|
||||
return "timeout"
|
||||
elseif ret[1] == false then
|
||||
return "error", ret[2]
|
||||
else
|
||||
debug.sethook(co)
|
||||
return "success", table.unpack(ret, 2)
|
||||
end
|
||||
end
|
||||
|
||||
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
|
||||
while true do
|
||||
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||
apis.os.queueEvent("NoSleep")
|
||||
local exit = false
|
||||
while not exit do
|
||||
local event = {coroutine.yield()}
|
||||
if event[1] == "key" then
|
||||
queueEvent("keyPressed", 1, event[2])
|
||||
if acekeys[event[2]] then
|
||||
queueEvent("keyTyped", 1, acekeys[event[2]])
|
||||
end
|
||||
elseif event[1] == "char" then
|
||||
queueEvent("keyTyped", 1, event[2])
|
||||
elseif event[1] == "key_up" then
|
||||
queueEvent("keyReleased", 1, event[2])
|
||||
elseif event[1] == "disk" then
|
||||
queueEvent("componentAdded", "disk")
|
||||
elseif event[1] == "disk_eject" then
|
||||
queueEvent("componentRemoved", "disk")
|
||||
elseif event[1] == "NoSleep" then
|
||||
exit = true
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield() end
|
||||
@@ -1,3 +1,6 @@
|
||||
--:Minify:--
|
||||
sleep(1)
|
||||
local BOOT_DRIVE_PATH=({...})[1] or "/$"
|
||||
-- UnBIOS by JackMacWindows
|
||||
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
|
||||
-- To use, just place a `bios.lua` in the root of the drive, and run this program
|
||||
@@ -13,7 +16,6 @@
|
||||
-- * `turtle.equip[Left|Right]`
|
||||
-- Licensed under the MIT license
|
||||
local args = {...}
|
||||
if _HOST:find("UnBIOS") then return end
|
||||
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
|
||||
local t = {}
|
||||
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
|
||||
@@ -29,7 +31,6 @@ if _G.commands then _G.commands = _G.commands.native end
|
||||
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
|
||||
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
|
||||
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
|
||||
_G._HOST = _G._HOST .. " (UnBIOS)"
|
||||
-- Set up TLCO
|
||||
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
|
||||
-- this would cause `parallel` to throw an error, but we replace `error` with an
|
||||
@@ -58,22 +59,22 @@ function _G.term.native()
|
||||
term.setCursorPos(1, 1)
|
||||
term.setCursorBlink(true)
|
||||
term.clear()
|
||||
local file = fs.open("/disk/boot/cc/preboot.cc", "r")
|
||||
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
|
||||
if file == nil then
|
||||
term.setCursorBlink(false)
|
||||
term.setTextColor(16384)
|
||||
term.write("Could not find /boot/cc/bootloader.cc. UnBIOS cannot continue.")
|
||||
term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")
|
||||
term.setCursorPos(1, 2)
|
||||
term.write("Press any key to continue")
|
||||
coroutine.yield("key")
|
||||
os.shutdown()
|
||||
end
|
||||
local fn, err = loadstring(file.readAll(), "@preboot.cc")
|
||||
local fn, err = loadstring(file.readAll(), "@bootloader")
|
||||
file.close()
|
||||
if fn == nil then
|
||||
term.setCursorBlink(false)
|
||||
term.setTextColor(16384)
|
||||
term.write("Could not load /boot/cc/bootloader.cc. UnBIOS cannot continue.")
|
||||
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
|
||||
term.setCursorPos(1, 2)
|
||||
term.write(err)
|
||||
term.setCursorPos(1, 3)
|
||||
@@ -85,7 +86,7 @@ function _G.term.native()
|
||||
local oldshutdown = os.shutdown
|
||||
os.shutdown = function()
|
||||
os.shutdown = oldshutdown
|
||||
return fn(table.unpack(args))
|
||||
return fn(BOOT_DRIVE_PATH)
|
||||
end
|
||||
end
|
||||
if debug then
|
||||
155
Src/Hyperion-firmware-cct/boot/cct/initdisks
Normal file
155
Src/Hyperion-firmware-cct/boot/cct/initdisks
Normal file
@@ -0,0 +1,155 @@
|
||||
-- :Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.getType(name)
|
||||
if native.isPresent(name) then return native.getType(name) end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and
|
||||
native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getTypeRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getNames()
|
||||
local names = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then table.insert(names, side) end
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local hubSides = native.call(side, "getConnectedSides")
|
||||
for _, hubSide in ipairs(hubSides) do
|
||||
table.insert(names, hubSide)
|
||||
end
|
||||
end
|
||||
end
|
||||
return names
|
||||
end
|
||||
|
||||
local disks = {}
|
||||
local internal = {}
|
||||
|
||||
local function norm(path)
|
||||
if not path or path == "" then return "/" end
|
||||
return fs.combine("/", path)
|
||||
end
|
||||
|
||||
local function createDisk(id, basePath, readonly, periph)
|
||||
basePath = norm(basePath)
|
||||
|
||||
local disk = {address = id, isReadOnly = function() return readonly end}
|
||||
|
||||
function disk:spaceUsed()
|
||||
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
|
||||
end
|
||||
|
||||
function disk:spaceTotal() return fs.getCapacity(basePath) end
|
||||
|
||||
function disk:list(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) or not fs.isDir(p) then
|
||||
return nil, "not directory"
|
||||
end
|
||||
return fs.list(p)
|
||||
end
|
||||
|
||||
function disk:fileExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and not fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:directoryExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:type(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) then
|
||||
return nil
|
||||
elseif fs.isDir(p) then
|
||||
return "directory"
|
||||
else
|
||||
return "file"
|
||||
end
|
||||
end
|
||||
|
||||
function disk:makeDirectory(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
fs.makeDir(p)
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:remove(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if fs.exists(p) then fs.delete(p) end
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:setLabel(label) periph.setLabel(label) end
|
||||
|
||||
function disk:getLabel(label) return periph.getLabel() end
|
||||
|
||||
function disk:attributes(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.attributes(p)
|
||||
end
|
||||
|
||||
function disk:open(path, mode)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.open(p, mode)
|
||||
end
|
||||
|
||||
return disk
|
||||
end
|
||||
|
||||
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
setLabel = function(label)
|
||||
local h = fs.open("/.label", "w")
|
||||
h.write(label)
|
||||
h.close()
|
||||
end,
|
||||
getLabel = function()
|
||||
local h = fs.open("/.label", "r")
|
||||
if not h then return "$" end
|
||||
local label = h.readAll()
|
||||
h.close()
|
||||
return label
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
for id, _ in pairs(disks) do
|
||||
if not peripheral.getType(id) then disks[id] = nil end
|
||||
end
|
||||
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == "disk" then
|
||||
if not disks[name] then
|
||||
local mount = disk.getMountPath(name)
|
||||
if mount then
|
||||
disks[name] = createDisk(name, mount, false, disk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function iter()
|
||||
refresh()
|
||||
local combined = {}
|
||||
|
||||
for id, obj in pairs(internal) do combined[id] = obj end
|
||||
for id, obj in pairs(disks) do combined[id] = obj end
|
||||
|
||||
return pairs(combined)
|
||||
end
|
||||
|
||||
return {refresh = refresh, list = iter}
|
||||
363
Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod
Normal file
363
Src/Hyperion-firmware-cct/lib/modules/CC-Tweaked/25_tty.kmod
Normal file
@@ -0,0 +1,363 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
local peripheral={}
|
||||
|
||||
function peripheral.getNames()
|
||||
local results = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then
|
||||
table.insert(results, side)
|
||||
if native.hasType(side, "peripheral_hub") then
|
||||
local remote = native.call(side, "getNamesRemote")
|
||||
for _, name in ipairs(remote) do
|
||||
table.insert(results, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
return results
|
||||
end
|
||||
|
||||
function peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then -- Peripheral name passed
|
||||
if native.isPresent(peripheral) then
|
||||
return native.getType(peripheral)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "getTypeRemote", peripheral)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return table.unpack(mt.types)
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then -- Peripheral name passed
|
||||
if native.isPresent(peripheral) then
|
||||
return native.hasType(peripheral, peripheral_type)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
else
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.types[peripheral_type] ~= nil
|
||||
end
|
||||
end
|
||||
|
||||
function peripheral.getMethods(name)
|
||||
if native.isPresent(name) then
|
||||
return native.getMethods(name)
|
||||
end
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "getMethodsRemote", name)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.call(name, method, ...)
|
||||
if native.isPresent(name) then
|
||||
return native.call(name, method, ...)
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return native.call(side, "callRemote", name, method, ...)
|
||||
end
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
function peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.getType(name) }
|
||||
for i = 1, #types do types[types[i]] = true end
|
||||
local result = setmetatable({}, {
|
||||
__name = "peripheral",
|
||||
name = name,
|
||||
type = types[1],
|
||||
types = types,
|
||||
})
|
||||
for _, method in ipairs(methods) do
|
||||
result[method] = function(...)
|
||||
return peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
|
||||
for i = 1, #text do
|
||||
local c = text:sub(i, i)
|
||||
|
||||
if c == "\n" then
|
||||
y = y + 1
|
||||
x = 1
|
||||
elseif c == "\t" then
|
||||
local tabSize = 4
|
||||
local spaces = tabSize - ((x - 1) % tabSize)
|
||||
term.write(string.rep(" ", spaces))
|
||||
x = x + spaces
|
||||
elseif c == "\b" then
|
||||
if x > 1 then
|
||||
x = x - 1
|
||||
term.setCursorPos(x, y)
|
||||
term.write(" ")
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
else
|
||||
if x <= w and y <= h then
|
||||
term.setCursorPos(x, y)
|
||||
term.write(c)
|
||||
x = x + 1
|
||||
end
|
||||
end
|
||||
|
||||
if x > w then
|
||||
x = 1
|
||||
y = y + 1
|
||||
end
|
||||
|
||||
if y - 1 >= h then
|
||||
term.scroll(1)
|
||||
y = h
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
end
|
||||
|
||||
term.setCursorPos(x, y)
|
||||
end
|
||||
|
||||
kernel.devfs.data.tty={}
|
||||
local ctrl,alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
if bool then
|
||||
return "T"
|
||||
else
|
||||
return "F"
|
||||
end
|
||||
end
|
||||
|
||||
local function newtty(obj, id, ev)
|
||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
local rv=""
|
||||
for i=1, amount or 1 do
|
||||
local event = {ev()}
|
||||
if event[1] then
|
||||
rv=rv..event[1]
|
||||
end
|
||||
end
|
||||
if rv=="" then rv=nil end
|
||||
return rv
|
||||
end,
|
||||
write=function(content)
|
||||
write(content, obj)
|
||||
end,
|
||||
size=function()
|
||||
local s={obj.getSize()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
clear=function()
|
||||
obj.clear()
|
||||
obj.setCursorPos(1,1)
|
||||
end,
|
||||
gpos=function()
|
||||
local s={obj.getCursorPos()}
|
||||
return table.concat(s,";")
|
||||
end,
|
||||
spos=function(x,y)
|
||||
return obj.setCursorPos(x,y)
|
||||
end,
|
||||
sfgc=function(c)
|
||||
return obj.setTextColor(colors[c])
|
||||
end,
|
||||
sbgc=function(c)
|
||||
return obj.setBackgroundColor(colors[c])
|
||||
end,
|
||||
gfgc=function()
|
||||
return icolors[obj.getTextColor()]
|
||||
end,
|
||||
gbgc=function()
|
||||
return icolors[obj.getBackgroundColor()]
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
return h
|
||||
elseif mode=="r" then
|
||||
h["write"]=nil
|
||||
return h
|
||||
elseif mode=="w" then
|
||||
h["read"]=nil
|
||||
return h
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local fifo = kernel.newFifo()
|
||||
|
||||
kernel.processes.cctmond = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.computer:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
-- Update modifier keys
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = true
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = true
|
||||
end
|
||||
|
||||
-- Handle Ctrl+C
|
||||
if ctrl and charOrKey == apis.keys.c then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1) -- SIGINT
|
||||
end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = false
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then fifo.push(charOrKey) end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newtty(apis.term, "TTY1", fifo.pop)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
v.setTextScale(.5)
|
||||
v.write("Initializing...")
|
||||
newtty(v,"TTY"..tostring(i+1),function () end)
|
||||
end
|
||||
@@ -0,0 +1,26 @@
|
||||
local args={...}
|
||||
local kernel=args[1]
|
||||
local driver={}
|
||||
|
||||
driver.name="CCT Term Module"
|
||||
driver.version="0.1.0"
|
||||
driver.type="gpio"
|
||||
driver.description="CCT redstone Module Kernel Module"
|
||||
driver.arch="cct"
|
||||
driver.author="HyperionOS Dev Team"
|
||||
driver.license="MIT"
|
||||
driver.api={}
|
||||
|
||||
function driver.load()
|
||||
-- will
|
||||
end
|
||||
|
||||
function driver.unload()
|
||||
-- Nothing to unload
|
||||
end
|
||||
|
||||
function driver.main()
|
||||
-- Nothing to run
|
||||
end
|
||||
|
||||
-- kernel.drivers.register(driver)
|
||||
@@ -1,6 +1,3 @@
|
||||
local biosData = ({...})[1]
|
||||
local apis={}
|
||||
|
||||
local lua = {
|
||||
coroutine = true,
|
||||
debug = true,
|
||||
@@ -31,20 +28,14 @@ local lua = {
|
||||
tonumber = true,
|
||||
tostring = true,
|
||||
type = true,
|
||||
xpcall = true
|
||||
xpcall = true,
|
||||
_G=true
|
||||
}
|
||||
|
||||
for i,v in ipairs(_G) do
|
||||
if not lua[i] then
|
||||
local apis={}
|
||||
for i,v in pairs(_G) do
|
||||
if not lua[i] or lua[i]==nil then
|
||||
apis[i]=v
|
||||
_G[i]=nil
|
||||
end
|
||||
end
|
||||
|
||||
local function getFile(path)
|
||||
return biosData.bootDrive:open(path).read()
|
||||
end
|
||||
|
||||
local computer = apis.component.getFirst("computer")
|
||||
local kernel = load(getFile("/boot/Hyprkrnl.sys"), "@kernel", "t", _G)
|
||||
kernel("ac", apis, biosData.bootDrive.id, apis.component.getFirst("screen"), computer.getMachineEvent)
|
||||
end
|
||||
18
Src/Hyperion-firmware-oc/boot/oc/eeprom
Normal file
18
Src/Hyperion-firmware-oc/boot/oc/eeprom
Normal file
@@ -0,0 +1,18 @@
|
||||
checkArg=nil
|
||||
local oldcomputer=computer
|
||||
_G.computer=nil
|
||||
local os=os
|
||||
_G.os=nil
|
||||
|
||||
function component.wrap(address)
|
||||
local methods=oldcomponent.methods(address)
|
||||
local object={}
|
||||
for _,method in ipairs(methods) do
|
||||
object[method]=function(_,...)
|
||||
return oldcomponent.invoke(address,method,...)
|
||||
end
|
||||
end
|
||||
return object
|
||||
end
|
||||
|
||||
local
|
||||
1
Src/Hyperion-firmware-oc/boot/oc/initfs.lua
Normal file
1
Src/Hyperion-firmware-oc/boot/oc/initfs.lua
Normal file
@@ -0,0 +1 @@
|
||||
local fs={}
|
||||
3
Src/Hyperion-kernel/boot/fstab
Normal file
3
Src/Hyperion-kernel/boot/fstab
Normal file
@@ -0,0 +1,3 @@
|
||||
U $;/
|
||||
U devfs0000;/dev/
|
||||
U tmpfs0000;/tmp/
|
||||
84
Src/Hyperion-kernel/boot/initfs
Normal file
84
Src/Hyperion-kernel/boot/initfs
Normal file
@@ -0,0 +1,84 @@
|
||||
-- :Minify:--
|
||||
local fs = {}
|
||||
local disks = {}
|
||||
local mounts = {}
|
||||
|
||||
local function resolve(path)
|
||||
local mountPoint = "/"
|
||||
for mount, disk in pairs(mounts) do
|
||||
if path:sub(1, #mount) == mount then
|
||||
if not mountPoint or #mount > #mountPoint then
|
||||
mountPoint = mount
|
||||
end
|
||||
end
|
||||
end
|
||||
local newPath = path:sub(#mountPoint + 1)
|
||||
return disks[mounts[mountPoint]], newPath
|
||||
end
|
||||
|
||||
function fs.update(initdisks)
|
||||
disks = {}
|
||||
for k, v in initdisks.list() do disks[k] = v end
|
||||
end
|
||||
|
||||
function fs.exists(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:directoryExists(newPath) or disk:fileExists(newPath)
|
||||
end
|
||||
|
||||
function fs.isFile(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:fileExists(newPath)
|
||||
end
|
||||
|
||||
function fs.isDir(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:directoryExists(newPath)
|
||||
end
|
||||
|
||||
function fs.list(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:list(newPath)
|
||||
end
|
||||
|
||||
function fs.makeDir(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:makeDirectory(newPath)
|
||||
end
|
||||
|
||||
function fs.remove(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:remove(newPath)
|
||||
end
|
||||
|
||||
function fs.readAllText(path)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "r")
|
||||
if not handle then return nil end
|
||||
local content = handle.readAll()
|
||||
handle.close()
|
||||
return content
|
||||
end
|
||||
|
||||
function fs.writeAllText(path, text)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "w")
|
||||
handle.write(text)
|
||||
handle.close()
|
||||
end
|
||||
|
||||
function fs.appendAllText(path, text)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "a")
|
||||
handle.write(text)
|
||||
handle.close()
|
||||
end
|
||||
|
||||
function fs.load(path) return load(fs.readAllText(path), path) end
|
||||
|
||||
function fs.mount(disk, mountPoint)
|
||||
if not disks[disk] then return end
|
||||
mounts[mountPoint] = disk
|
||||
end
|
||||
|
||||
return fs
|
||||
273
Src/Hyperion-kernel/boot/kernel.lua
Normal file
273
Src/Hyperion-kernel/boot/kernel.lua
Normal file
@@ -0,0 +1,273 @@
|
||||
--:Minify:--
|
||||
local args = {...}
|
||||
local apis = args[1]
|
||||
local disks = args[2]
|
||||
local arch = args[3]
|
||||
local screen = args[5]
|
||||
local computer = args[6]
|
||||
local ifs = args[7]
|
||||
local kernel = {}
|
||||
kernel.LOG_Text=""
|
||||
kernel.version="HyperionOS V1.0.0"
|
||||
kernel.process = "Kernel"
|
||||
kernel.users={[0]="root",[1]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
kernel.groups = {}
|
||||
kernel.uid = 0
|
||||
kernel.gid = 0
|
||||
kernel.status = "start"
|
||||
kernel.key = {}
|
||||
kernel.cache = {}
|
||||
kernel.cache.preload = {}
|
||||
kernel._G=_G
|
||||
kernel.sleep=sleep
|
||||
|
||||
_G.sleep=nil
|
||||
local windowsExp = false
|
||||
|
||||
function kernel.log(msg, level, c)
|
||||
c=c or 12
|
||||
kernel.LOG_Text = kernel.LOG_Text..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||
if kernel.status == "start" then
|
||||
screen:setTextColor(c)
|
||||
screen:print(string.format("%X",c-1).." "..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||
elseif kernel.status == "term" then
|
||||
kernel.standbyTask=kernel.currentTask
|
||||
kernel.currentTask=kernel.kernelTask
|
||||
kernel.vfs.devctl(1,"sfgc",c)
|
||||
kernel.vfs.write(1,string.format("%X",c-1).." "..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||
kernel.currentTask=kernel.standbyTask
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.PANIC(msg)
|
||||
if kernel.status~="Panic" then
|
||||
kernel.log("PANIC: "..msg, "PANIC")
|
||||
pcall(kernel["saveLog"])
|
||||
kernel.status="Panic"
|
||||
kernel.reason=msg
|
||||
screen:setTextColor(2)
|
||||
screen:setBackgroundColor(16)
|
||||
screen:clear()
|
||||
screen:setCursorPos(1,1)
|
||||
screen:print(kernel.LOG_Text)
|
||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||
screen:print("Press any key to continue...")
|
||||
kernel.exitMain = true
|
||||
end
|
||||
while true do
|
||||
local event={computer:getMachineEvent()}
|
||||
if event[1]=="keyPressed" then
|
||||
break
|
||||
end
|
||||
end
|
||||
computer:reboot()
|
||||
end
|
||||
kernel.panic=kernel.PANIC
|
||||
|
||||
if windowsExp then
|
||||
screen:setTextColor(1)
|
||||
screen:setBackgroundColor(4)
|
||||
screen:clear()
|
||||
local w,h = screen:getSize()
|
||||
screen:setCursorPos(3,5)
|
||||
screen:print(":(")
|
||||
screen:setCursorPos(3,7)
|
||||
screen:print("Your PC ran into a problem and needs to restart. We're just collecting some error")
|
||||
screen:setCursorPos(3,8)
|
||||
screen:print("info, and then we'll restart for you.\n")
|
||||
screen:setCursorPos(3,h-5)
|
||||
screen:print("Stop code: average windows experience")
|
||||
screen:setCursorPos(1,h)
|
||||
screen:print("Press any key to continue... jk reboot it yourself lazy")
|
||||
while true do end
|
||||
end
|
||||
|
||||
kernel.log("Kernel loaded.")
|
||||
kernel.log("Mounting init disks...")
|
||||
disks.refresh()
|
||||
ifs.update(disks)
|
||||
kernel.disks={}
|
||||
for _,v in disks.list() do
|
||||
kernel.disks[v.address] = v
|
||||
end
|
||||
ifs.mount("$", "/")
|
||||
|
||||
local fstab=ifs.readAllText("/boot/fstab")
|
||||
local split = function(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
local c = string.sub(str,i,i)
|
||||
if #rv ~= maxResultCountOrNil and c == delim then
|
||||
table.insert(rv, buf)
|
||||
buf = ""
|
||||
else
|
||||
buf = buf..c
|
||||
end
|
||||
end
|
||||
table.insert(rv, buf)
|
||||
return rv
|
||||
end
|
||||
|
||||
if not ifs.isFile("/boot/boot.cfg") then
|
||||
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR", 2)
|
||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||
end
|
||||
|
||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||
if not initCfgFunc then
|
||||
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
|
||||
end
|
||||
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local initCfgStatus, config = pcall(initCfgFunc)
|
||||
if not initCfgStatus then
|
||||
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
|
||||
end
|
||||
kernel.config = config
|
||||
|
||||
for i,v in ipairs(split(fstab,"\n")) do
|
||||
if v:sub(1,1)=="U" then
|
||||
local id=""
|
||||
for i=3,#v do
|
||||
if v:sub(i,i)==";" then
|
||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
|
||||
id=v:sub(3,i-1)
|
||||
end
|
||||
end
|
||||
local path=v:sub(#id+4)
|
||||
ifs.mount(id,path)
|
||||
::endline::
|
||||
end
|
||||
end
|
||||
kernel.log("Disks initialized")
|
||||
|
||||
function kernel.saveLog()
|
||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||
end
|
||||
|
||||
function kernel.newFifo()
|
||||
local fifo = {}
|
||||
fifo.push=function(data)
|
||||
table.insert(fifo, data)
|
||||
end
|
||||
fifo.pop=function()
|
||||
return table.remove(fifo,1)
|
||||
end
|
||||
return fifo
|
||||
end
|
||||
|
||||
function kernel.newUUID()
|
||||
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
|
||||
local uuid = ""
|
||||
for i = 1, #template do
|
||||
local c = template:sub(i,i)
|
||||
if c == "x" then
|
||||
uuid = uuid .. string.format("%x", math.random(0, 15))
|
||||
elseif c == "y" then
|
||||
uuid = uuid .. string.format("%x", math.random(8, 11))
|
||||
else
|
||||
uuid = uuid .. c
|
||||
end
|
||||
end
|
||||
return uuid
|
||||
end
|
||||
|
||||
kernel.syscalls={}
|
||||
local modules={[0]={}}
|
||||
for i=0, 100 do
|
||||
modules[i]={}
|
||||
end
|
||||
|
||||
kernel.log("Gathering modules")
|
||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
for _,v in ipairs(ifs.list("/lib/modules/"..i)) do
|
||||
local prior=tonumber(v:sub(1,2))
|
||||
modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
|
||||
end
|
||||
end
|
||||
|
||||
kernel.ifs=ifs
|
||||
kernel.apis=apis
|
||||
kernel.computer=computer
|
||||
kernel.arch=arch
|
||||
kernel.initdisks=disks
|
||||
kernel.screen=screen
|
||||
kernel.processes={}
|
||||
kernel.fstab=fstab
|
||||
|
||||
kernel.kernelTask = {
|
||||
name="kernel",
|
||||
status="R",
|
||||
pid=0,
|
||||
tgid=0,
|
||||
uid=0,
|
||||
fd={},
|
||||
exit="",
|
||||
sleep=0,
|
||||
ivs=0,
|
||||
vs=0,
|
||||
children={},
|
||||
syscallReturn={},
|
||||
cwd="/",
|
||||
timeSlice=0,
|
||||
lastTime=0,
|
||||
totalTime=0,
|
||||
numRuns=0
|
||||
}
|
||||
kernel.currentTask = kernel.kernelTask
|
||||
|
||||
function kernel.shutdown()
|
||||
kernel.computer:shutdown()
|
||||
end
|
||||
|
||||
function kernel.reboot()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
|
||||
kernel.syscalls["time"]=function() return kernel.computer:time() end
|
||||
kernel.syscalls["log"]=kernel.log
|
||||
kernel.syscalls["getUptime"]=function() return kernel.computer:clock() end
|
||||
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||
kernel.syscalls["version"]=function() return kernel.version end
|
||||
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
|
||||
kernel.syscalls["arch"]=function() return arch end
|
||||
kernel.syscalls["sysdump"]=function()
|
||||
local rv={}
|
||||
for i,v in pairs(kernel.syscalls) do
|
||||
rv[#rv+1] = i
|
||||
end
|
||||
return rv
|
||||
end
|
||||
kernel.syscalls["test"]=function() return true end
|
||||
|
||||
kernel.log("Running modules")
|
||||
for _,p in ipairs(modules) do
|
||||
for _,v in ipairs(p) do
|
||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 5) end
|
||||
local code=ifs.readAllText(v)
|
||||
if not code then
|
||||
kernel.log("ModuReadErr: "..v, "WARN", 8)
|
||||
goto skip
|
||||
end
|
||||
local func,err=load(code,"@"..v)
|
||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
|
||||
local status, err = xpcall(func,debug.traceback, kernel)
|
||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 5) end
|
||||
::skip::
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Kernel initialized successfully.")
|
||||
kernel.status="running"
|
||||
kernel.main()
|
||||
if kernel.status=="panic" then
|
||||
kernel.panic()
|
||||
end
|
||||
kernel.PANIC("Execution complete")
|
||||
11
Src/Hyperion-kernel/boot/safeboot.cfg
Normal file
11
Src/Hyperion-kernel/boot/safeboot.cfg
Normal file
@@ -0,0 +1,11 @@
|
||||
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
|
||||
|
||||
-- This file is auto-generated during the build process.
|
||||
-- DEFAULT BOOT CONFIGURATION FILE
|
||||
return {
|
||||
initPath = "/sbin/init.lua",
|
||||
maxOpenFiles = 128,
|
||||
maxFilesPerTask = 16,
|
||||
preempt=true
|
||||
}
|
||||
1
Src/Hyperion-kernel/etc/passwd
Normal file
1
Src/Hyperion-kernel/etc/passwd
Normal file
@@ -0,0 +1 @@
|
||||
0:0:root:/root:/bin/bash
|
||||
225
Src/Hyperion-kernel/lib/modules/Hyperion/01_stdlib.kmod
Normal file
225
Src/Hyperion-kernel/lib/modules/Hyperion/01_stdlib.kmod
Normal file
@@ -0,0 +1,225 @@
|
||||
-- :Minify:--
|
||||
function string.hasSuffix(str, suffix)
|
||||
return string.sub(str, #suffix + 1) == suffix
|
||||
end
|
||||
|
||||
function string.hasPrefix(str, prefix)
|
||||
return string.sub(str, 1, #prefix) == prefix
|
||||
end
|
||||
|
||||
function string.getSuffix(str, prefix) return string.sub(str, #prefix + 1) end
|
||||
|
||||
function string.getPrefix(str, suffix) return string.sub(str, 1, #suffix) end
|
||||
|
||||
function string.join(str, ...) return table.concat(table.pack(str, ...)) end
|
||||
|
||||
function string.delim(str, ...) return table.concat(table.pack(...), str) end
|
||||
|
||||
function string.split(str, delim, maxResultCountOrNil)
|
||||
assert(#delim == 1, "only delim len 1 supported for now")
|
||||
maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
|
||||
local rv = {}
|
||||
local buf = ""
|
||||
for i = 1, #str do
|
||||
local c = string.sub(str, i, i)
|
||||
if #rv ~= maxResultCountOrNil and c == delim then
|
||||
table.insert(rv, buf)
|
||||
buf = ""
|
||||
else
|
||||
buf = buf .. c
|
||||
end
|
||||
end
|
||||
table.insert(rv, buf)
|
||||
return rv
|
||||
end
|
||||
|
||||
function table.deepcopy(orig, copies)
|
||||
copies = copies or {}
|
||||
|
||||
if type(orig) ~= 'table' then
|
||||
return orig
|
||||
elseif copies[orig] then
|
||||
return copies[orig]
|
||||
end
|
||||
|
||||
local copy = {}
|
||||
copies[orig] = copy
|
||||
|
||||
for k, v in next, orig, nil do
|
||||
local copied_key = table.deepcopy(k, copies)
|
||||
local copied_val = table.deepcopy(v, copies)
|
||||
copy[copied_key] = copied_val
|
||||
end
|
||||
|
||||
return copy
|
||||
end
|
||||
|
||||
function table.hasKey(tabl, query)
|
||||
for i, v in pairs(tabl) do if i == query then return v end end
|
||||
return false
|
||||
end
|
||||
|
||||
function table.hasVal(tabl, query)
|
||||
for i, v in pairs(tabl) do if v == query then return i end end
|
||||
return false
|
||||
end
|
||||
|
||||
local function serialize(tbl, seen)
|
||||
seen = seen or {}
|
||||
|
||||
-- If we've seen this table before, return a placeholder to prevent infinite loops
|
||||
if seen[tbl] then return '"[Circular Reference]"' end
|
||||
|
||||
-- Mark this table as seen
|
||||
seen[tbl] = true
|
||||
|
||||
local output = "{"
|
||||
local first = true
|
||||
|
||||
for i, v in pairs(tbl) do
|
||||
-- Handle comma placement more cleanly
|
||||
if not first then output = output .. "," end
|
||||
first = false
|
||||
|
||||
-- Serialize Key
|
||||
if type(i) == "string" then
|
||||
output = output .. "[\"" .. i .. "\"]="
|
||||
elseif type(i) == "number" then
|
||||
output = output .. "[" .. tostring(i) .. "]="
|
||||
end
|
||||
|
||||
-- Serialize Value
|
||||
if type(v) == "table" then
|
||||
-- Pass the 'seen' table down to the recursive call
|
||||
output = output .. serialize(v, seen)
|
||||
elseif type(v) == "string" then
|
||||
output = output .. "[=[" .. v .. "]=]"
|
||||
elseif type(v) == "number" or type(v) == "boolean" then
|
||||
output = output .. tostring(v)
|
||||
elseif type(v) == "function" then
|
||||
output = output .. "\"" .. tostring(v) .. "\""
|
||||
elseif type(v) == "thread" then
|
||||
output = output .. "\"" .. tostring(v) .. "\""
|
||||
else
|
||||
error("serialization of type \"" .. type(v) .. "\" is not supported")
|
||||
end
|
||||
end
|
||||
|
||||
seen[tbl] = nil
|
||||
|
||||
output = output .. "}"
|
||||
return output
|
||||
end
|
||||
|
||||
local oldtype = type
|
||||
local oldgetmetatable = getmetatable
|
||||
function type(object, trueType)
|
||||
if trueType then return oldtype(object) end
|
||||
if oldtype(object) ~= "table" then
|
||||
return oldtype(object)
|
||||
else
|
||||
if oldtype(oldgetmetatable(object)) == "table" then
|
||||
local metatable = oldgetmetatable(object)
|
||||
---@diagnostic disable-next-line: need-check-nil
|
||||
if metatable.__type then return metatable.__type end
|
||||
else
|
||||
return "table"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function getmetatable(object)
|
||||
if oldtype(object) ~= "table" then return end
|
||||
if oldtype(oldgetmetatable(object)) == "table" then
|
||||
if oldgetmetatable(object).__isuserdata then
|
||||
if oldtype(oldgetmetatable(object).__usermeta) == "function" then
|
||||
return oldgetmetatable(object).__usermeta()
|
||||
else
|
||||
return oldgetmetatable(object).__usermeta
|
||||
end
|
||||
else
|
||||
return oldgetmetatable(object)
|
||||
end
|
||||
else
|
||||
return oldgetmetatable(object)
|
||||
end
|
||||
end
|
||||
|
||||
function isEqualToAny(a, ...)
|
||||
local args = {...}
|
||||
for i = 0, #args do if a == args[i] then return true end end
|
||||
return false
|
||||
end
|
||||
|
||||
function isEqualToAll(a, ...)
|
||||
local args = {...}
|
||||
for i = 0, #args do if a ~= args[i] then return false end end
|
||||
return true
|
||||
end
|
||||
|
||||
function table.keys(t)
|
||||
local a = {}
|
||||
for n in pairs(t) do table.insert(a, n) end
|
||||
return a
|
||||
end
|
||||
|
||||
function table.values(t)
|
||||
local a = {}
|
||||
for _, n in pairs(t) do table.insert(a, n) end
|
||||
return a
|
||||
end
|
||||
|
||||
function table.indexOf(t, value)
|
||||
for i, v in ipairs(t) do if v == value then return i end end
|
||||
return -1
|
||||
end
|
||||
|
||||
function string.replace(s, target, repl)
|
||||
local result = {}
|
||||
local i = 1
|
||||
local n = #s
|
||||
local t_len = #target
|
||||
|
||||
while i <= n do
|
||||
local match = true
|
||||
if i + t_len - 1 <= n then
|
||||
for j = 1, t_len do
|
||||
if s:sub(i + j - 1, i + j - 1) ~= target:sub(j, j) then
|
||||
match = false
|
||||
break
|
||||
end
|
||||
end
|
||||
else
|
||||
match = false
|
||||
end
|
||||
|
||||
if match then
|
||||
table.insert(result, repl)
|
||||
i = i + t_len
|
||||
else
|
||||
table.insert(result, s:sub(i, i))
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
return table.concat(result)
|
||||
end
|
||||
|
||||
function toHex(num)
|
||||
return string.format("%X", num)
|
||||
end
|
||||
|
||||
syscall = setmetatable({}, {
|
||||
__index = function(self, name)
|
||||
return function(...)
|
||||
local res = table.pack(coroutine.yield("syscall", name, ...))
|
||||
if res[1] then
|
||||
return table.unpack(res, 2, res.n)
|
||||
else
|
||||
error(res[2], 2)
|
||||
end
|
||||
end
|
||||
end
|
||||
})
|
||||
|
||||
table.serialize = serialize
|
||||
629
Src/Hyperion-kernel/lib/modules/Hyperion/10_vfs.kmod
Normal file
629
Src/Hyperion-kernel/lib/modules/Hyperion/10_vfs.kmod
Normal file
@@ -0,0 +1,629 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
local vfs = {}
|
||||
kernel.vfs = vfs
|
||||
vfs.mounts = {["$"] = "/"}
|
||||
vfs.disks = kernel.disks
|
||||
|
||||
-- Path normalization
|
||||
local function normalizePath(path)
|
||||
local task = kernel.currentTask
|
||||
local cwd = task.cwd or "/"
|
||||
if path:sub(1, 1) ~= "/" then path = cwd .. "/" .. path end
|
||||
local parts = {}
|
||||
for part in path:gmatch("[^/]+") do
|
||||
if part == ".." then
|
||||
if #parts > 0 then table.remove(parts) end
|
||||
elseif part ~= "." and part ~= "" then
|
||||
table.insert(parts, part)
|
||||
end
|
||||
end
|
||||
return "/" .. table.concat(parts, "/")
|
||||
end
|
||||
|
||||
function vfs.splitPath(path)
|
||||
local rv=string.split(path,"/")
|
||||
while table.indexOf(rv, "") ~= -1 do
|
||||
table.remove(rv, table.indexOf(rv, ""))
|
||||
end
|
||||
return rv
|
||||
end
|
||||
|
||||
-- Resolve mount and disk path
|
||||
local function resolvePath(path)
|
||||
path = normalizePath(path)
|
||||
|
||||
local mountPoint = nil
|
||||
local mountId = nil
|
||||
|
||||
for id, mp in pairs(vfs.mounts) do
|
||||
if path == mp or (mp == "/" and path:sub(1, 1) == "/") or path:sub(1, #mp + 1) == mp .. "/" then
|
||||
if not mountPoint or #mp > #mountPoint then
|
||||
mountPoint = mp
|
||||
mountId = id
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not mountId then
|
||||
error("ENODEV")
|
||||
end
|
||||
|
||||
local diskPath = path:sub(#mountPoint + 1)
|
||||
if diskPath == "" then
|
||||
diskPath = "/"
|
||||
end
|
||||
|
||||
if kernel.config.logPathResolution then
|
||||
kernel.log("Path '"..path.."' resolved to disk '"..mountId.."' and path '"..diskPath.."'")
|
||||
end
|
||||
|
||||
return vfs.disks[mountId], diskPath
|
||||
end
|
||||
|
||||
-- Allocate file descriptor for current task
|
||||
local function allocFD(task)
|
||||
local fd = 0
|
||||
while task.fd[fd] do fd = fd + 1 end
|
||||
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
||||
return fd
|
||||
end
|
||||
|
||||
-- System-wide open file limit
|
||||
local total = 0
|
||||
local function checkSystemLimit()
|
||||
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
||||
end
|
||||
|
||||
-- File object constructor
|
||||
local function newFileObj(handle, mode, path, meta, type)
|
||||
return {
|
||||
handle = handle,
|
||||
mode = mode,
|
||||
path = path,
|
||||
meta = meta,
|
||||
type = type,
|
||||
refcount = 1
|
||||
}
|
||||
end
|
||||
|
||||
function vfs.newfd(fdobj)
|
||||
checkSystemLimit()
|
||||
total=total+1
|
||||
local fd = allocFD(kernel.currentTask)
|
||||
kernel.currentTask.fd[fd]=fdobj
|
||||
end
|
||||
|
||||
-- Parse metafile
|
||||
local function parseMetafile(file)
|
||||
if not file or file == "" then return {} end
|
||||
|
||||
local ret = {}
|
||||
local pointer = 1
|
||||
|
||||
while pointer <= #file do
|
||||
local namelen = file:byte(pointer)
|
||||
pointer = pointer + 1
|
||||
|
||||
local name = file:sub(pointer, pointer + namelen - 1)
|
||||
pointer = pointer + namelen
|
||||
|
||||
local owner = file:byte(pointer)
|
||||
local group = file:byte(pointer + 1)
|
||||
local perms = file:byte(pointer + 2)
|
||||
pointer = pointer + 3
|
||||
|
||||
local cmetalen = file:byte(pointer)
|
||||
pointer = pointer + 1
|
||||
|
||||
local cmeta = ""
|
||||
if cmetalen > 0 then
|
||||
cmeta = file:sub(pointer, pointer + cmetalen - 1)
|
||||
pointer = pointer + cmetalen
|
||||
end
|
||||
|
||||
ret[name] = {owner = owner, group = group, perms = perms, cmeta = cmeta}
|
||||
end
|
||||
|
||||
return ret
|
||||
end
|
||||
|
||||
-- Build metafile
|
||||
local function makeMetafile(meta)
|
||||
local file = ""
|
||||
for name, m in pairs(meta) do
|
||||
local entry = ""
|
||||
entry = entry .. string.char(#name) .. name
|
||||
entry = entry .. string.char(m.owner, m.group, m.perms)
|
||||
entry = entry .. string.char(#m.cmeta) .. m.cmeta
|
||||
file = file .. entry
|
||||
end
|
||||
return file
|
||||
end
|
||||
|
||||
-- Get file metadata object
|
||||
local function getFileMeta(path)
|
||||
local disk, fullPath = resolvePath(path)
|
||||
fullPath = normalizePath(fullPath)
|
||||
|
||||
local parts = {}
|
||||
for p in fullPath:gmatch("[^/]+") do table.insert(parts, p) end
|
||||
|
||||
-- default fallback
|
||||
local default = {owner = 0, group = 0, perms = 63, cmeta = ""}
|
||||
|
||||
-- walk from deepest parent upward
|
||||
for i = #parts, 1, -1 do
|
||||
local parent = "/" .. table.concat(parts, "/", 1, i - 1)
|
||||
if parent ~= "/" then parent = parent .. "/" end
|
||||
|
||||
local target = parts[i]
|
||||
if target == ".meta" then error("Cannot open metafile") end
|
||||
local metaPath = parent .. ".meta"
|
||||
|
||||
if disk:fileExists(metaPath) then
|
||||
local f = disk:open(metaPath, "r")
|
||||
local text = f.read(65535)
|
||||
f.close()
|
||||
|
||||
local parsed = parseMetafile(text)
|
||||
if parsed[target] then return parsed[target] end
|
||||
end
|
||||
end
|
||||
|
||||
return default
|
||||
end
|
||||
|
||||
local function ensureParentMeta(path)
|
||||
local disk, fullPath = resolvePath(path)
|
||||
fullPath = normalizePath(fullPath)
|
||||
|
||||
-- split parent + name
|
||||
local parent, name = fullPath:match("^(.*)/([^/]+)$")
|
||||
if not parent then
|
||||
parent = "/"
|
||||
name = fullPath:gsub("^/", "")
|
||||
end
|
||||
|
||||
if name == ".meta" then error("Cannot open metafile") end
|
||||
|
||||
if parent ~= "/" and parent:sub(-1) ~= "/" then parent = parent .. "/" end
|
||||
|
||||
local metaPath = parent .. ".meta"
|
||||
|
||||
if not disk:fileExists(metaPath) then
|
||||
local f = disk:open(metaPath, "w")
|
||||
f.write("")
|
||||
f.close()
|
||||
end
|
||||
|
||||
return metaPath, name
|
||||
end
|
||||
|
||||
-- Permission checking
|
||||
local function checkperms(meta, mode)
|
||||
local modes = {
|
||||
r = {owner = 5, group = 3, everyone = 1},
|
||||
w = {owner = 4, group = 2, everyone = 0},
|
||||
a = {owner = 4, group = 2, everyone = 0}
|
||||
}
|
||||
|
||||
local bits = meta.perms
|
||||
local function bit_is_set(num, bit)
|
||||
return math.floor(num / (2 ^ bit)) % 2 == 1
|
||||
end
|
||||
|
||||
if kernel.uid == 0 then return true end
|
||||
if kernel.uid == meta.owner and bit_is_set(bits, modes[mode].owner) then
|
||||
return true
|
||||
end
|
||||
|
||||
if meta.group and kernel.groups then
|
||||
for _, gid in ipairs(kernel.groups) do
|
||||
if gid == meta.group and bit_is_set(bits, modes[mode].group) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if bit_is_set(bits, modes[mode].everyone) then return true end
|
||||
error("EACCES")
|
||||
end
|
||||
|
||||
-- mounts
|
||||
local function normalizeMountPoint(path)
|
||||
path = normalizePath(path)
|
||||
if path ~= "/" and path:sub(-1) == "/" then path = path:sub(1, -2) end
|
||||
return path
|
||||
end
|
||||
|
||||
local required = {
|
||||
"open",
|
||||
"type",
|
||||
"list",
|
||||
"attributes",
|
||||
"fileExists",
|
||||
"makeDirectory",
|
||||
"remove"
|
||||
}
|
||||
|
||||
local function check(disk)
|
||||
for _, name in ipairs(required) do
|
||||
if type(disk[name]) ~= "function" then
|
||||
error("Invalid disk: missing method '" .. name .. "'")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function vfs.mount(target, diskOrId)
|
||||
if kernel.uid ~= 0 then error("EPERM") end
|
||||
if not target then error("EINVAL") end
|
||||
|
||||
target = normalizeMountPoint(target)
|
||||
if not vfs.exists(target) then vfs.mkdir(target) end
|
||||
if vfs.type(target) ~= "directory" then error("EINVAL") end
|
||||
|
||||
local disk
|
||||
local id
|
||||
|
||||
if type(diskOrId) == "string" then
|
||||
disk = kernel.disks[diskOrId]
|
||||
if not disk then error("ENODEV") end
|
||||
check(disk)
|
||||
id = diskOrId
|
||||
elseif type(diskOrId) == "table" then
|
||||
check(disk)
|
||||
disk = diskOrId
|
||||
id = disk.address
|
||||
vfs.disks[id] = disk
|
||||
else
|
||||
error("EINVAL")
|
||||
end
|
||||
|
||||
-- Prevent shadowing an existing mount
|
||||
for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
|
||||
|
||||
vfs.mounts[id] = target
|
||||
return true
|
||||
end
|
||||
|
||||
function vfs.umount(target)
|
||||
if kernel.uid ~= 0 then error("EPERM") end
|
||||
if not target then error("EINVAL") end
|
||||
|
||||
target = normalizeMountPoint(target)
|
||||
|
||||
for id, mp in pairs(vfs.mounts) do
|
||||
if mp == target then
|
||||
if id == "$" then error("EBUSY") end -- root fs
|
||||
vfs.mounts[id] = nil
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
error("EINVAL")
|
||||
end
|
||||
|
||||
-- Open file
|
||||
function vfs.open(path, mode)
|
||||
checkSystemLimit()
|
||||
local task = kernel.currentTask
|
||||
local fd = allocFD(task)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if not disk then error("NODISK") end
|
||||
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, mode)
|
||||
|
||||
local handle
|
||||
if disk:type(diskPath)~="directory" then
|
||||
handle = disk:open(diskPath, mode)
|
||||
if type(handle)~="table" then error("ENFILE") end
|
||||
end
|
||||
|
||||
task.fd[fd] = newFileObj(handle, mode, path, meta, disk:type(diskPath))
|
||||
if not disk.isvirt then
|
||||
total = total + 1
|
||||
end
|
||||
return fd
|
||||
end
|
||||
|
||||
-- Read
|
||||
function vfs.read(fd, count)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.read then error("EBADF") end
|
||||
return file.handle.read(count or 1)
|
||||
end
|
||||
|
||||
-- Write
|
||||
function vfs.write(fd, content)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.write then error("EBADF") end
|
||||
return file.handle.write(content)
|
||||
end
|
||||
|
||||
-- Pread / Pwrite
|
||||
function vfs.pread(fd, count, offset)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.read then error("EBADF") end
|
||||
if not file.handle.seek then error("EBADF") end
|
||||
file.handle.seek("set", offset)
|
||||
return file.handle.read(count or 1)
|
||||
end
|
||||
|
||||
function vfs.pwrite(fd, content, offset)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.write then error("EBADF") end
|
||||
if not file.handle.seek then error("EBADF") end
|
||||
file.handle.seek("set", offset)
|
||||
return file.handle.write(content)
|
||||
end
|
||||
|
||||
-- Seek
|
||||
function vfs.lseek(fd, offset, whence)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.seek then error("EBADF") end
|
||||
return file.handle.seek(whence or "set", offset)
|
||||
end
|
||||
|
||||
-- Fsync
|
||||
function vfs.fsync(fd)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if not file.handle.flush then error("EBADF") end
|
||||
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
|
||||
file.handle.flush()
|
||||
end
|
||||
|
||||
-- Close
|
||||
function vfs.close(fd)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
|
||||
task.fd[fd] = nil
|
||||
total = total - 1
|
||||
|
||||
file.refcount = file.refcount - 1
|
||||
if file.refcount <= 0 then
|
||||
if file.handle.close then
|
||||
file.handle.close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Sendfile
|
||||
function vfs.sendfile(outfd, infd, count)
|
||||
local task = kernel.currentTask
|
||||
local inFile = task.fd[infd]
|
||||
local outFile = task.fd[outfd]
|
||||
if not inFile or not outFile then error("EBADF") end
|
||||
if not inFile.handle.read then error("EBADF") end
|
||||
if not outFile.handle.write then error("EBADF") end
|
||||
local data = inFile.handle.read(count or 1024)
|
||||
if not data or data == "" then return end
|
||||
return outFile.handle.write(data)
|
||||
end
|
||||
|
||||
-- Stat / Fstat
|
||||
function vfs.stat(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
local attrs = disk:attributes(diskPath)
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
created = attrs.created,
|
||||
owner = meta.owner,
|
||||
group = meta.group,
|
||||
xattr = meta.cmeta
|
||||
}
|
||||
end
|
||||
|
||||
function vfs.fstat(fd)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
local disk, path = resolvePath(file.path)
|
||||
local attrs = disk:attributes(path)
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
created = attrs.created,
|
||||
owner = file.meta.owner,
|
||||
group = file.meta.group,
|
||||
xattr = file.meta.cmeta
|
||||
}
|
||||
end
|
||||
|
||||
-- Directory operations
|
||||
function vfs.listdir(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if disk:type(diskPath) ~= "directory" then error("ENOENT") end
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, "r")
|
||||
local list = disk:list(diskPath)
|
||||
if table.indexOf(list, ".meta") ~= -1 then
|
||||
table.remove(list, table.indexOf(list, ".meta"))
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
function vfs.mkdir(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, "w")
|
||||
disk:makeDirectory(diskPath)
|
||||
end
|
||||
|
||||
function vfs.remove(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, "w")
|
||||
disk:remove(diskPath)
|
||||
end
|
||||
|
||||
-- Permission functions
|
||||
function vfs.chmod(path, perms)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
|
||||
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
|
||||
meta.perms = perms
|
||||
|
||||
local mpath, target = ensureParentMeta(path)
|
||||
|
||||
local mf = disk:open(mpath, "r")
|
||||
local text = mf.read(65535)
|
||||
mf.close()
|
||||
|
||||
local parsed = parseMetafile(text)
|
||||
parsed[target] = meta
|
||||
|
||||
local f = disk:open(mpath, "w")
|
||||
f.write(makeMetafile(parsed))
|
||||
f.close()
|
||||
end
|
||||
|
||||
function vfs.fchmod(fd, perms)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
vfs.chmod(file.path, perms)
|
||||
end
|
||||
|
||||
function vfs.chown(path, uid, gid)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
|
||||
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
|
||||
meta.owner = uid
|
||||
meta.group = gid
|
||||
|
||||
local mpath, target = ensureParentMeta(path)
|
||||
|
||||
local mf = disk:open(mpath, "r")
|
||||
local text = mf.read(65535)
|
||||
mf.close()
|
||||
|
||||
local parsed = parseMetafile(text)
|
||||
parsed[target] = meta
|
||||
|
||||
local f = disk:open(mpath, "w")
|
||||
f.write(makeMetafile(parsed))
|
||||
f.close()
|
||||
end
|
||||
|
||||
function vfs.fchown(fd, uid, gid)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
vfs.chown(file.path, uid, gid)
|
||||
end
|
||||
|
||||
function vfs.exists(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, "r")
|
||||
return disk:fileExists(diskPath)
|
||||
end
|
||||
|
||||
function vfs.type(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
checkperms(meta, "r")
|
||||
return disk:type(diskPath)
|
||||
end
|
||||
|
||||
function vfs.getcwd() return kernel.currentTask.cwd end
|
||||
|
||||
function vfs.chdir(path) kernel.currentTask.cwd = path end
|
||||
|
||||
function vfs.dup(oldfd)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[oldfd]
|
||||
if not file then error("EBADF") end
|
||||
|
||||
checkSystemLimit()
|
||||
|
||||
local newfd = allocFD(task)
|
||||
file.refcount = file.refcount + 1
|
||||
task.fd[newfd] = file
|
||||
total = total + 1
|
||||
|
||||
return newfd
|
||||
end
|
||||
|
||||
function vfs.dup2(oldfd, newfd)
|
||||
local task = kernel.currentTask
|
||||
local file = task.fd[oldfd]
|
||||
if not file then error("EBADF") end
|
||||
if newfd < 0 or newfd >= kernel.config.maxFilesPerTask then
|
||||
error("EBADF")
|
||||
end
|
||||
|
||||
if oldfd == newfd then
|
||||
return newfd
|
||||
end
|
||||
|
||||
if task.fd[newfd] then
|
||||
vfs.close(newfd)
|
||||
end
|
||||
|
||||
checkSystemLimit()
|
||||
|
||||
file.refcount = file.refcount + 1
|
||||
task.fd[newfd] = file
|
||||
total = total + 1
|
||||
|
||||
return newfd
|
||||
end
|
||||
|
||||
function vfs.devctl(fd, method, ...)
|
||||
if not kernel.currentTask.fd[fd] then error("EBADF") end
|
||||
if not kernel.currentTask.fd[fd].handle[method] then error("EINVAL") end
|
||||
return kernel.currentTask.fd[fd].handle[method](...)
|
||||
end
|
||||
|
||||
-- Export syscalls
|
||||
local sys = kernel.syscalls
|
||||
sys["open"] = vfs.open
|
||||
sys["close"] = vfs.close
|
||||
sys["read"] = vfs.read
|
||||
sys["write"] = vfs.write
|
||||
sys["pread"] = vfs.pread
|
||||
sys["pwrite"] = vfs.pwrite
|
||||
sys["lseek"] = vfs.lseek
|
||||
sys["fsync"] = vfs.fsync
|
||||
sys["sendfile"] = vfs.sendfile
|
||||
sys["stat"] = vfs.stat
|
||||
sys["fstat"] = vfs.fstat
|
||||
sys["mkdir"] = vfs.mkdir
|
||||
sys["remove"] = vfs.remove
|
||||
sys["listdir"] = vfs.listdir
|
||||
sys["chmod"] = vfs.chmod
|
||||
sys["fchmod"] = vfs.fchmod
|
||||
sys["chown"] = vfs.chown
|
||||
sys["fchown"] = vfs.fchown
|
||||
sys["exists"] = vfs.exists
|
||||
sys["type"] = vfs.type
|
||||
sys["mount"] = vfs.mount
|
||||
sys["umount"] = vfs.umount
|
||||
sys["getcwd"] = vfs.getcwd
|
||||
sys["chdir"] = vfs.chdir
|
||||
sys["dup"] = vfs.dup
|
||||
sys["dup2"] = vfs.dup2
|
||||
sys["devctl"] = vfs.devctl
|
||||
|
||||
kernel.log("VFS module loaded")
|
||||
40
Src/Hyperion-kernel/lib/modules/Hyperion/11_require.kmod
Normal file
40
Src/Hyperion-kernel/lib/modules/Hyperion/11_require.kmod
Normal file
@@ -0,0 +1,40 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
local cache = {}
|
||||
kernel.searchpaths = {
|
||||
"/lib/?.lua", "/lib/?", "/usr/lib/?.lua", "/usr/lib/?",
|
||||
"/usr/local/lib/?.lua", "/usr/local/lib/?", "?.lua", "?"
|
||||
}
|
||||
|
||||
function require(module, ...)
|
||||
if cache[module] then return cache[module] end
|
||||
local modpath = module:gsub("%.", "/")
|
||||
local failed = {}
|
||||
for _, path in ipairs(kernel.searchpaths) do
|
||||
local full_path = string.replace(path, "?", modpath)
|
||||
if full_path:sub(1, 1) ~= "/" then
|
||||
full_path = kernel.currentTask.cwd .. full_path
|
||||
end
|
||||
|
||||
if kernel.vfs.exists(full_path) then
|
||||
if kernel.vfs.type(full_path) == "directory" then
|
||||
full_path = full_path .. "/init"
|
||||
end
|
||||
|
||||
if kernel.vfs.exists(full_path) then
|
||||
local handle = kernel.vfs.open(full_path, "r")
|
||||
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
||||
kernel.vfs.close(handle)
|
||||
|
||||
return
|
||||
assert(load(file_content, full_path, "t", kernel._U))(...)
|
||||
else
|
||||
table.insert(failed, full_path)
|
||||
end
|
||||
else
|
||||
table.insert(failed, full_path)
|
||||
end
|
||||
end
|
||||
|
||||
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
|
||||
end
|
||||
147
Src/Hyperion-kernel/lib/modules/Hyperion/12_devfs.kmod
Normal file
147
Src/Hyperion-kernel/lib/modules/Hyperion/12_devfs.kmod
Normal file
@@ -0,0 +1,147 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "devfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("EACCES") end
|
||||
proxy.remove = function() error("EACCES") end
|
||||
proxy.setLabel = function() error("EACCES") end
|
||||
proxy.getLabel = function() return "devfs" end
|
||||
proxy.attributes = function(path) return {
|
||||
size = 0,
|
||||
modified = 0,
|
||||
created = 0,
|
||||
} end
|
||||
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("open", mode)
|
||||
end
|
||||
error("ENFILE")
|
||||
end
|
||||
|
||||
function proxy:type(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return "directory"
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENFILE") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "function" then
|
||||
return step[steps[#steps]]("type", mode)
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return "directory"
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then
|
||||
return table.keys(data)
|
||||
end
|
||||
for i=1, #steps-1 do
|
||||
local dat = step[steps[i]]
|
||||
if type(dat) ~= "table" then error("ENOENT") end
|
||||
step=dat
|
||||
end
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return table.keys(step[steps[#steps]])
|
||||
end
|
||||
error("ENOENT")
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
local ok = pcall(function()
|
||||
return self:type(path)
|
||||
end)
|
||||
return ok
|
||||
end
|
||||
|
||||
function data.random(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(math.random(0, 255))
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.null(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount) end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function data.zero(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
return {
|
||||
read=function(amount)
|
||||
local str = ""
|
||||
for i=1, amount or 1 do
|
||||
str=str..string.char(0)
|
||||
end
|
||||
return str
|
||||
end
|
||||
}
|
||||
elseif mode=="w" or mode=="a" then
|
||||
return {
|
||||
write=function() end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data["disk"]={}
|
||||
kernel.devfs={}
|
||||
kernel.devfs.data=data
|
||||
kernel.devfs.proxy=proxy
|
||||
kernel.disks["devfs0000"]=proxy
|
||||
129
Src/Hyperion-kernel/lib/modules/Hyperion/12_tmpfs.kmod
Normal file
129
Src/Hyperion-kernel/lib/modules/Hyperion/12_tmpfs.kmod
Normal file
@@ -0,0 +1,129 @@
|
||||
local kernel = ...
|
||||
|
||||
local proxy = {}
|
||||
local data = {}
|
||||
|
||||
proxy.address = "tmpfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
|
||||
-- Space functions (just placeholders)
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
|
||||
-- Writable operations
|
||||
proxy.makeDirectory = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
if not step[steps[i]] then
|
||||
step[steps[i]] = {}
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
end
|
||||
|
||||
proxy.remove = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
step[steps[#steps]] = nil
|
||||
end
|
||||
|
||||
proxy.setLabel = function(_, label) end
|
||||
proxy.getLabel = function() return "tmpfs" end
|
||||
|
||||
proxy.attributes = function(_, path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
return {
|
||||
size = type(step) == "string" and #step or 0,
|
||||
modified = 0,
|
||||
created = 0,
|
||||
}
|
||||
end
|
||||
|
||||
-- Open files
|
||||
function proxy:open(path, mode)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps-1 do
|
||||
if not step[steps[i]] then
|
||||
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
|
||||
elseif type(step[steps[i]]) ~= "table" then
|
||||
error("ENOTDIR")
|
||||
end
|
||||
step = step[steps[i]]
|
||||
end
|
||||
local filename = steps[#steps]
|
||||
|
||||
if mode == "r" then
|
||||
if type(step[filename]) ~= "string" then error("ENOENT") end
|
||||
local content = step[filename]
|
||||
local pos = 1
|
||||
return {
|
||||
read = function(amount)
|
||||
amount = amount or #content
|
||||
local chunk = content:sub(pos, pos+amount-1)
|
||||
pos = pos + #chunk
|
||||
return chunk
|
||||
end
|
||||
}
|
||||
elseif mode == "w" then
|
||||
step[filename] = ""
|
||||
return {
|
||||
write = function(str)
|
||||
step[filename] = str
|
||||
end
|
||||
}
|
||||
elseif mode == "a" then
|
||||
if type(step[filename]) ~= "string" then step[filename] = "" end
|
||||
return {
|
||||
write = function(str)
|
||||
step[filename] = step[filename] .. str
|
||||
end
|
||||
}
|
||||
else
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
|
||||
function proxy:type(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
if #steps == 0 then return "directory" end
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then return false end
|
||||
end
|
||||
if type(step) == "table" then return "directory" end
|
||||
if type(step) == "string" then return "file" end
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
local steps = kernel.vfs.splitPath(path)
|
||||
local step = data
|
||||
for i=1,#steps do
|
||||
step = step[steps[i]]
|
||||
if not step then error("ENOENT") end
|
||||
end
|
||||
if type(step) ~= "table" then error("ENOTDIR") end
|
||||
local keys = {}
|
||||
for k,_ in pairs(step) do table.insert(keys, k) end
|
||||
return keys
|
||||
end
|
||||
|
||||
function proxy:fileExists(path)
|
||||
return pcall(function() return self:type(path) end)
|
||||
end
|
||||
|
||||
kernel.disks["tmpfs0000"] = proxy
|
||||
22
Src/Hyperion-kernel/lib/modules/Hyperion/14_keventd.kmod
Normal file
22
Src/Hyperion-kernel/lib/modules/Hyperion/14_keventd.kmod
Normal file
@@ -0,0 +1,22 @@
|
||||
---- :Minify:--
|
||||
--local kernel = ...
|
||||
--
|
||||
--local timeout = false
|
||||
--kernel.processes.keventd = function()
|
||||
-- while true do
|
||||
-- local event = {kernel.computer:getMachineEvent()}
|
||||
-- if event[1] then
|
||||
-- if event[1] == "keyTyped" then
|
||||
-- if event[3] == "\x1b^s" then
|
||||
-- kernel.shutdown()
|
||||
-- elseif event[3] == "\x1b^r" then
|
||||
-- kernel.reboot()
|
||||
-- end
|
||||
-- end
|
||||
-- timeout = false
|
||||
-- else
|
||||
-- timeout = true
|
||||
-- end
|
||||
-- if timeout then sleep(.05) end
|
||||
-- end
|
||||
--end
|
||||
34
Src/Hyperion-kernel/lib/modules/Hyperion/19_fstab.kmod
Normal file
34
Src/Hyperion-kernel/lib/modules/Hyperion/19_fstab.kmod
Normal file
@@ -0,0 +1,34 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local function trim(str)
|
||||
local s, e = 1, #str
|
||||
while s <= e and (str:sub(s,s) == " " or str:sub(s,s) == "\t") do s = s + 1 end
|
||||
while e >= s and (str:sub(e,e) == " " or str:sub(e,e) == "\t" or str:sub(e,e) == "\n" or str:sub(e,e) == "\r") do e = e - 1 end
|
||||
if s > e then return "" end
|
||||
return str:sub(s,e)
|
||||
end
|
||||
|
||||
for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
||||
line = trim(line)
|
||||
if line ~= "" and line:sub(1,1) == "U" then
|
||||
local semicolon_pos
|
||||
for i = 3, #line do
|
||||
if line:sub(i,i) == ";" then
|
||||
semicolon_pos = i
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
if not semicolon_pos or semicolon_pos == 3 then
|
||||
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 8)
|
||||
else
|
||||
local id = line:sub(3, semicolon_pos - 1)
|
||||
local path = trim(line:sub(semicolon_pos + 1))
|
||||
kernel.log("Mounted "..id.." to "..path)
|
||||
if id ~= "$" then
|
||||
kernel.vfs.mount(path, id)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
27
Src/Hyperion-kernel/lib/modules/Hyperion/20_signals.kmod
Normal file
27
Src/Hyperion-kernel/lib/modules/Hyperion/20_signals.kmod
Normal file
@@ -0,0 +1,27 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local signal = {}
|
||||
kernel.signal=signal
|
||||
|
||||
function signal.sigsend(pid, sig)
|
||||
if sig<0 or sig>256 then error("EINVAL") end
|
||||
local task = kernel.tasks[tostring(pid)]
|
||||
if not task then error("ENOENT") end
|
||||
if not task.sigq then return end
|
||||
task.sigq[#task.sigq+1] = sig
|
||||
end
|
||||
|
||||
function signal.sigcatch(handler)
|
||||
kernel.currentTask.sigh=handler
|
||||
if not kernel.currentTask.sigq then kernel.currentTask.sigq={} end
|
||||
end
|
||||
|
||||
function signal.sigignore()
|
||||
kernel.currentTask.sigh=nil
|
||||
kernel.currentTask.sigq=nil
|
||||
end
|
||||
|
||||
local s=kernel.syscalls
|
||||
s["sigsend"] = signal.sigsend
|
||||
s["sigcatch"] = signal.sigcatch
|
||||
s["sigignore"] = signal.sigignore
|
||||
14
Src/Hyperion-kernel/lib/modules/Hyperion/20_socket.kmod
Normal file
14
Src/Hyperion-kernel/lib/modules/Hyperion/20_socket.kmod
Normal file
@@ -0,0 +1,14 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local socket = {}
|
||||
|
||||
function socket.socket()
|
||||
|
||||
end
|
||||
|
||||
function socket.bind()
|
||||
|
||||
end
|
||||
|
||||
kernel.socket=socket
|
||||
kernel.log("Loaded socket module")
|
||||
6
Src/Hyperion-kernel/lib/modules/Hyperion/26_tty.kmod
Normal file
6
Src/Hyperion-kernel/lib/modules/Hyperion/26_tty.kmod
Normal file
@@ -0,0 +1,6 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
kernel.vfs.open("/dev/null", "r")
|
||||
kernel.vfs.open("/dev/tty/TTY1", "w")
|
||||
kernel.vfs.open("/dev/null", "w")
|
||||
kernel.status="term"
|
||||
56
Src/Hyperion-kernel/lib/modules/Hyperion/30_userspace.kmod
Normal file
56
Src/Hyperion-kernel/lib/modules/Hyperion/30_userspace.kmod
Normal file
@@ -0,0 +1,56 @@
|
||||
-- :Minify:--
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
kernel._G = _G
|
||||
|
||||
local function readonly(tbl)
|
||||
return setmetatable({}, {
|
||||
__index = function(_, key)
|
||||
local value = tbl[key]
|
||||
if type(value) == "table" then return readonly(value) end
|
||||
return value
|
||||
end,
|
||||
|
||||
__newindex = function(t, k, v)
|
||||
if kernel.config.allowGlobalOverwrites or
|
||||
kernel.allowGlobalOverwrites then
|
||||
rawset(tbl, k, v)
|
||||
return
|
||||
end
|
||||
error("Attempt to modify global variable '" .. k .. "'", 2)
|
||||
end,
|
||||
|
||||
__pairs = function()
|
||||
local function iter(_, key)
|
||||
local nextKey, value = next(tbl, key)
|
||||
if type(value) == "table" then
|
||||
value = readonly(value)
|
||||
end
|
||||
return nextKey, value
|
||||
end
|
||||
return iter, tbl, nil
|
||||
end,
|
||||
|
||||
__ipairs = function()
|
||||
local i = 0
|
||||
return function()
|
||||
i = i + 1
|
||||
local value = tbl[i]
|
||||
if value == nil then return end
|
||||
if type(value) == "table" then
|
||||
value = readonly(value)
|
||||
end
|
||||
return i, value
|
||||
end
|
||||
end,
|
||||
|
||||
__len = function() return #tbl end,
|
||||
|
||||
__metatable = false
|
||||
})
|
||||
end
|
||||
|
||||
kernel._U = readonly(kernel._G)
|
||||
kernel.allowGlobalOverwrites = true
|
||||
kernel._U._G = kernel._U
|
||||
kernel.allowGlobalOverwrites = false
|
||||
232
Src/Hyperion-kernel/lib/modules/Hyperion/40_auth.kmod
Normal file
232
Src/Hyperion-kernel/lib/modules/Hyperion/40_auth.kmod
Normal file
@@ -0,0 +1,232 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
local auth = {}
|
||||
kernel.auth = auth
|
||||
|
||||
-- @SPSF work here
|
||||
|
||||
-- needed
|
||||
|
||||
-- login -- sets the current proccess to the specifyed user id
|
||||
-- setPassword -- sets the password for specifiyed user id
|
||||
-- setUsername -- sets
|
||||
-- newUser -- sets
|
||||
|
||||
-- PASSWD FILE FORMAT
|
||||
-- uid:gid:username:homedir:shell
|
||||
|
||||
-- SHADOW FILE FORMAT
|
||||
-- uid:salt:hash
|
||||
|
||||
local function getFile(path)
|
||||
local file = kernel.vfs.open(path, "r")
|
||||
if not file then error("Failed to open file: "..path) end
|
||||
local content = kernel.vfs.read(file, 1024000)
|
||||
kernel.vfs.close(file)
|
||||
return content
|
||||
end
|
||||
|
||||
local blake2s
|
||||
do
|
||||
local MOD32 = 2^32
|
||||
local function norm(x)
|
||||
return x % MOD32
|
||||
end
|
||||
|
||||
local function tobits(x)
|
||||
x = norm(x)
|
||||
local t = {}
|
||||
for i = 0, 31 do
|
||||
local b = x % 2
|
||||
t[i] = b
|
||||
x = (x - b) / 2
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
local function frombits(t)
|
||||
local x = 0
|
||||
local p = 1
|
||||
for i = 0, 31 do
|
||||
if t[i] == 1 then
|
||||
x = x + p
|
||||
end
|
||||
p = p * 2
|
||||
end
|
||||
return norm(x)
|
||||
end
|
||||
|
||||
local function bor(...)
|
||||
local args = {...}
|
||||
if #args == 0 then return 0 end
|
||||
local bits = tobits(args[1])
|
||||
for i = 2, #args do
|
||||
local b = tobits(args[i])
|
||||
for j = 0, 31 do
|
||||
bits[j] = (bits[j] == 1 or b[j] == 1) and 1 or 0
|
||||
end
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
local function bxor(...)
|
||||
local args = {...}
|
||||
if #args == 0 then return 0 end
|
||||
local bits = tobits(args[1])
|
||||
for i = 2, #args do
|
||||
local b = tobits(args[i])
|
||||
for j = 0, 31 do
|
||||
bits[j] = (bits[j] ~= b[j]) and 1 or 0
|
||||
end
|
||||
end
|
||||
return frombits(bits)
|
||||
end
|
||||
|
||||
local function lshift(x, n)
|
||||
return norm(norm(x) * 2^n)
|
||||
end
|
||||
|
||||
local function rshift(x, n)
|
||||
return math.floor(norm(x) / 2^n)
|
||||
end
|
||||
|
||||
local function rotr(x, n)
|
||||
return bor(rshift(x, n), lshift(x, 32 - n))
|
||||
end
|
||||
|
||||
local IV = {
|
||||
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
|
||||
0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
|
||||
}
|
||||
|
||||
local SIGMA = {
|
||||
{0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15},
|
||||
{14,10,4,8,9,15,13,6,1,12,0,2,11,7,5,3},
|
||||
{11,8,12,0,5,2,15,13,10,14,3,6,7,1,9,4},
|
||||
{7,9,3,1,13,12,11,14,2,6,5,10,4,0,15,8},
|
||||
{9,0,5,7,2,4,10,15,14,1,11,12,6,8,3,13},
|
||||
{2,12,6,10,0,11,8,3,4,13,7,5,15,14,1,9},
|
||||
{12,5,1,15,14,13,4,10,0,7,6,3,9,2,8,11},
|
||||
{13,11,7,14,12,1,3,9,5,0,15,4,8,6,2,10},
|
||||
{6,15,14,9,11,3,0,8,12,2,13,7,1,4,10,5},
|
||||
{10,2,8,4,7,6,1,5,15,11,9,14,3,12,13,0}
|
||||
}
|
||||
|
||||
local function G(v, a, b, c, d, x, y)
|
||||
v[a] = (v[a] + v[b] + x) % MOD32
|
||||
v[d] = rotr(bxor(v[d], v[a]), 16)
|
||||
v[c] = (v[c] + v[d]) % MOD32
|
||||
v[b] = rotr(bxor(v[b], v[c]), 12)
|
||||
v[a] = (v[a] + v[b] + y) % MOD32
|
||||
v[d] = rotr(bxor(v[d], v[a]), 8)
|
||||
v[c] = (v[c] + v[d]) % MOD32
|
||||
v[b] = rotr(bxor(v[b], v[c]), 7)
|
||||
end
|
||||
|
||||
local function compress(h, block, t, last)
|
||||
local v = {}
|
||||
for i = 1, 8 do v[i] = h[i] end
|
||||
for i = 1, 8 do v[i + 8] = IV[i] end
|
||||
|
||||
v[13] = bxor(v[13], t)
|
||||
if last then
|
||||
v[15] = bxor(v[15], 0xFFFFFFFF)
|
||||
end
|
||||
|
||||
local m = {}
|
||||
for i = 0, 15 do
|
||||
local p = i * 4 + 1
|
||||
m[i] =
|
||||
(block:byte(p) or 0) +
|
||||
((block:byte(p + 1) or 0) * 0x100) +
|
||||
((block:byte(p + 2) or 0) * 0x10000) +
|
||||
((block:byte(p + 3) or 0) * 0x1000000)
|
||||
end
|
||||
|
||||
for r = 1, 10 do
|
||||
local s = SIGMA[r]
|
||||
G(v,1,5,9,13, m[s[1]], m[s[2]])
|
||||
G(v,2,6,10,14, m[s[3]], m[s[4]])
|
||||
G(v,3,7,11,15, m[s[5]], m[s[6]])
|
||||
G(v,4,8,12,16, m[s[7]], m[s[8]])
|
||||
G(v,1,6,11,16, m[s[9]], m[s[10]])
|
||||
G(v,2,7,12,13, m[s[11]], m[s[12]])
|
||||
G(v,3,8,9,14, m[s[13]], m[s[14]])
|
||||
G(v,4,5,10,15, m[s[15]], m[s[16]])
|
||||
end
|
||||
|
||||
for i = 1, 8 do
|
||||
h[i] = bxor(h[i], v[i], v[i + 8])
|
||||
end
|
||||
end
|
||||
|
||||
function blake2s(msg, key)
|
||||
key = key or ""
|
||||
|
||||
local h = {}
|
||||
for i = 1, 8 do h[i] = IV[i] end
|
||||
|
||||
local outlen = 32 -- bytes
|
||||
h[1] = bxor(
|
||||
h[1],
|
||||
0x01010000 + lshift(#key, 8) + outlen
|
||||
)
|
||||
|
||||
local t = 0
|
||||
|
||||
if #key > 0 then
|
||||
local block = key .. string.rep("\0", 64 - #key)
|
||||
t = #key
|
||||
compress(h, block, t, false)
|
||||
end
|
||||
|
||||
for i = 1, #msg, 64 do
|
||||
local block = msg:sub(i, i + 63)
|
||||
if #block < 64 then
|
||||
block = block .. string.rep("\0", 64 - #block)
|
||||
end
|
||||
t = t + math.min(64, #msg - i + 1)
|
||||
compress(h, block, t, i + 64 > #msg)
|
||||
end
|
||||
|
||||
local out = ""
|
||||
for i = 1, 8 do
|
||||
out = out .. string.format("%08x", h[i])
|
||||
end
|
||||
return out
|
||||
end
|
||||
end
|
||||
|
||||
if not blake2s then error("Failed to load blake2s") end
|
||||
|
||||
if not kernel.vfs.exists("/etc/pam.d/secret") then
|
||||
kernel.log("PAM SECRET REGENERATING PLEASE USE ROOT")
|
||||
local key = ""
|
||||
for i=1, 256 do
|
||||
key=key..string.char(math.random(0,255))
|
||||
end
|
||||
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
|
||||
kernel.vfs.write(handle, key)
|
||||
kernel.vfs.close(handle)
|
||||
end
|
||||
|
||||
local pepper = getFile("/etc/pam.d/secret")
|
||||
local passwdFile = getFile("/etc/passwd")
|
||||
local shadowFile = getFile("/etc/shadow")
|
||||
local passwdLines = string.split(passwdFile,"\n")
|
||||
local shadowLines = string.split(shadowFile,"\n")
|
||||
local passwd,shadow={},{}
|
||||
|
||||
for _,v in ipairs(passwdLines) do
|
||||
passwd[#passwd+1]=string.split(v,":")
|
||||
end
|
||||
|
||||
for _,v in ipairs(shadowLines) do
|
||||
shadow[#shadow+1]=string.split(v,":")
|
||||
end
|
||||
|
||||
for i,v in pairs(passwd) do
|
||||
kernel.users[tonumber(v[1])]=v[3]
|
||||
end
|
||||
kernel.passwd=passwd
|
||||
|
||||
447
Src/Hyperion-kernel/lib/modules/Hyperion/45_hypervisor.kmod
Normal file
447
Src/Hyperion-kernel/lib/modules/Hyperion/45_hypervisor.kmod
Normal file
@@ -0,0 +1,447 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
local tasks = {}
|
||||
local sys = {}
|
||||
local nextpid = 2
|
||||
kernel.exitMain = false
|
||||
|
||||
function sys.spawn(func, name, envars, args, tgid)
|
||||
local id = nextpid
|
||||
nextpid = nextpid + 1
|
||||
|
||||
tasks[tostring(id)] = {
|
||||
coro = coroutine.create(function()
|
||||
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {}))
|
||||
if not ok then
|
||||
if kernel.config.logTaskExit then
|
||||
kernel.log(
|
||||
"Task " .. tostring(id) .. " exited with err: " ..
|
||||
tostring(err), "ERROR", 2)
|
||||
end
|
||||
|
||||
if type(err) == "number" then
|
||||
tasks[tostring(id)].exit = err
|
||||
end
|
||||
else
|
||||
if kernel.config.logTaskExit then
|
||||
if err then
|
||||
kernel.log("Task " .. tostring(id) ..
|
||||
" exited with code: " .. tostring(err),
|
||||
"INFO")
|
||||
else
|
||||
kernel.log("Task " .. tostring(id) ..
|
||||
" exited without code", "INFO")
|
||||
end
|
||||
end
|
||||
|
||||
if type(err) == "number" then
|
||||
tasks[tostring(id)].exit = err
|
||||
end
|
||||
end
|
||||
for v, _ in ipairs(tasks[tostring(id)].fd) do pcall(kernel.vfs.close,v) end
|
||||
tasks[tostring(id)].status = "Z"
|
||||
|
||||
end),
|
||||
name = name or ("task" .. tostring(id)),
|
||||
envars = envars or kernel.currentTask.envars,
|
||||
args = args or {},
|
||||
status = "R",
|
||||
pid = id,
|
||||
tgid = tgid or kernel.currentTask.tgid,
|
||||
uid = kernel.uid,
|
||||
fd = {},
|
||||
sleep = 0,
|
||||
ivs = 0,
|
||||
vs = 0,
|
||||
children = {},
|
||||
parent = kernel.currentTask,
|
||||
siblings = kernel.currentTask.children,
|
||||
syscallReturn = {},
|
||||
cwd = kernel.currentTask.cwd,
|
||||
timeSlice = 0,
|
||||
lastTime = 0,
|
||||
totalTime = 0,
|
||||
numRuns = 0
|
||||
}
|
||||
|
||||
table.insert(kernel.currentTask.children, tasks[tostring(id)])
|
||||
return id
|
||||
end
|
||||
|
||||
function sys.sleep(s)
|
||||
kernel.currentTask.status = "S"
|
||||
kernel.currentTask.sleep = kernel.computer:time() + s * 1000
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
function sys.getTask(pid)
|
||||
if tasks[tostring(pid)] then
|
||||
local task = tasks[tostring(pid)]
|
||||
local children = {}
|
||||
local siblings = {}
|
||||
|
||||
for i, v in ipairs(task.children) do children[i] = v.pid end
|
||||
for i, v in ipairs(task.siblings) do siblings[i] = v.pid end
|
||||
|
||||
return {
|
||||
name = task.name,
|
||||
status = task.status,
|
||||
pid = task.pid,
|
||||
tgid = task.tgid,
|
||||
username = kernel.users[task.uid],
|
||||
uid = task.uid,
|
||||
exit = task.exit,
|
||||
sleep = task.sleep,
|
||||
ivs = task.ivs,
|
||||
vs = task.vs,
|
||||
children = children,
|
||||
siblings = siblings,
|
||||
parent = task.parent.pid,
|
||||
cwd = task.cwd,
|
||||
term = task.term
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
function sys.collect(pid)
|
||||
local children = {}
|
||||
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
|
||||
|
||||
if not tasks[tostring(pid)] then
|
||||
return false, "Task does not exist"
|
||||
|
||||
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) then
|
||||
return false, "You do not own this task"
|
||||
|
||||
elseif tasks[tostring(pid)].status ~= "Z" then
|
||||
return false, "Task must exit to collect status"
|
||||
|
||||
else
|
||||
tasks[tostring(pid)].reapTime = 0
|
||||
return true, tasks[tostring(pid)].exit
|
||||
end
|
||||
end
|
||||
|
||||
function sys.kill(pid)
|
||||
local children = {}
|
||||
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
|
||||
|
||||
if not tasks[tostring(pid)] then
|
||||
return false, "Task does not exist"
|
||||
|
||||
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and kernel.uid ~= 0 then
|
||||
return false, "You do not own this task"
|
||||
|
||||
elseif tasks[tostring(pid)].status == "Z" then
|
||||
return false, "Task is already dead"
|
||||
|
||||
else
|
||||
tasks[tostring(pid)].status = "Z"
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function sys.stop(pid)
|
||||
local children = {}
|
||||
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
|
||||
|
||||
if not tasks[tostring(pid)] then
|
||||
return false, "Task does not exist"
|
||||
|
||||
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and kernel.uid ~= 0 then
|
||||
return false, "You do not own this task"
|
||||
|
||||
elseif tasks[tostring(pid)].status ~= "R" then
|
||||
return false, "Cannot stop non running task"
|
||||
|
||||
else
|
||||
tasks[tostring(pid)].status = "T"
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function sys.continue(pid)
|
||||
local children = {}
|
||||
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
|
||||
if not tasks[tostring(pid)] then
|
||||
return false, "Task does not exist"
|
||||
|
||||
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and kernel.uid ~= 0 then
|
||||
return false, "You do not own this task"
|
||||
|
||||
elseif tasks[tostring(pid)].status ~= "T" then
|
||||
return false, "Task is not stopped"
|
||||
|
||||
else
|
||||
tasks[tostring(pid)].status = "R"
|
||||
return true
|
||||
end
|
||||
end
|
||||
|
||||
function sys.getpid() return kernel.currentTask.pid end
|
||||
|
||||
function sys.getppid() return kernel.currentTask.parent.pid end
|
||||
|
||||
function sys.getTasks()
|
||||
local ret = {}
|
||||
for i, v in pairs(tasks) do ret[#ret + 1] = v.pid end
|
||||
return ret
|
||||
end
|
||||
|
||||
function sys.getEnviron(key) return kernel.currentTask.envars[key] end
|
||||
|
||||
function sys.setEnviron(key, value) kernel.currentTask.envars[key] = value end
|
||||
|
||||
function sys.exit(code)
|
||||
if kernel.config.logTaskExit then
|
||||
if code then
|
||||
kernel.log("Task " .. tostring(kernel.currentTask.pid) .. " exited with code: " .. tostring(code), "INFO")
|
||||
else
|
||||
kernel.log("Task " .. tostring(kernel.currentTask.pid) .. " exited without code", "INFO")
|
||||
end
|
||||
end
|
||||
|
||||
tasks[tostring(kernel.currentTask.pid)].status = "Z"
|
||||
if type(code) == "number" then
|
||||
tasks[tostring(kernel.currentTask.pid)].exit = code
|
||||
end
|
||||
end
|
||||
|
||||
function sys.setuid(uid)
|
||||
if kernel.uid ~= 0 then error("EACCES") end
|
||||
kernel.currentTask.uid = uid
|
||||
end
|
||||
|
||||
function sys.getuid() return kernel.currentTask.uid end
|
||||
|
||||
local sysc = kernel.syscalls
|
||||
sysc["spawn"] = sys.spawn
|
||||
sysc["sleep"] = sys.sleep
|
||||
sysc["getTask"] = sys.getTask
|
||||
sysc["collect"] = sys.collect
|
||||
sysc["kill"] = sys.kill
|
||||
sysc["stop"] = sys.stop
|
||||
sysc["continue"] = sys.continue
|
||||
sysc["getpid"] = sys.getpid
|
||||
sysc["getppid"] = sys.getppid
|
||||
sysc["getTasks"] = sys.getTasks
|
||||
sysc["setEnviron"] = sys.setEnviron
|
||||
sysc["getEnviron"] = sys.getEnviron
|
||||
sysc["exit"] = sys.exit
|
||||
sysc["setuid"] = sys.setuid
|
||||
sysc["getuid"] = sys.getuid
|
||||
kernel._G.sleep = function(...) coroutine.yield("syscall", "sleep", ...) end
|
||||
|
||||
local function reapDeadTasks()
|
||||
for pid, task in pairs(tasks) do
|
||||
if task.status == "Z" and not task.reapTime then
|
||||
kernel.currentTask = task
|
||||
kernel.uid = task.uid
|
||||
kernel.process = task.name
|
||||
task.coro = nil
|
||||
task.ivs = nil
|
||||
task.vs = nil
|
||||
task.args = nil
|
||||
task.envars = nil
|
||||
task.cwd = nil
|
||||
task.numRuns = nil
|
||||
task.totalTime = nil
|
||||
task.lastTime = nil
|
||||
task.timeSlice = nil
|
||||
task.syscallReturn = nil
|
||||
task.sleep = nil
|
||||
task.fd = nil
|
||||
task.reapTime = kernel.computer:time() + 30000
|
||||
|
||||
elseif task.reapTime and kernel.computer:time() > task.reapTime and
|
||||
task.status == "Z" then
|
||||
for _, child in ipairs(task.children) do
|
||||
child.parent = tasks["1"]
|
||||
child.siblings = tasks["1"].children
|
||||
table.insert(tasks["1"].children, child)
|
||||
end
|
||||
|
||||
for i, sibling in ipairs(task.siblings) do
|
||||
if sibling.pid == task.pid then
|
||||
table.remove(task.siblings, i)
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
tasks[pid] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local alpha = 0.85
|
||||
local C_target = 0.01
|
||||
local Tmin = 0.0005
|
||||
local Tmax = 0.5
|
||||
local lambda_budget = 0.08
|
||||
local lambda_clamp = 0.03
|
||||
local lambda_var = 0.02
|
||||
local k_min = 0.5
|
||||
local k_max = 0.5
|
||||
local B = 0.01
|
||||
|
||||
function kernel.main()
|
||||
while not kernel.exitMain do
|
||||
local N = 0
|
||||
local Tmin_hit = 0
|
||||
local Tmax_hit = 0
|
||||
local totalTaskTime = 0
|
||||
local taskTimes = {}
|
||||
|
||||
for pid, task in pairs(tasks) do
|
||||
if task.status == "S" then
|
||||
if kernel.computer:time() >= task.sleep then
|
||||
task.status = "R"
|
||||
task.sleep = 0
|
||||
end
|
||||
end
|
||||
if task.status == "R" then
|
||||
kernel.currentTask = task
|
||||
kernel.uid = task.uid
|
||||
kernel.process = task.name
|
||||
N = N + 1
|
||||
|
||||
-- assign adaptive time slice
|
||||
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
||||
|
||||
if task.sigq and #task.sigq~=0 and task.sigh then
|
||||
local coro = coroutine.create(task.sigh)
|
||||
if kernel.config.preempt then
|
||||
coroutine.resumeWithTimeout(coro, task.timeSlice, table.remove(task.sigq, 1))
|
||||
else
|
||||
coroutine.resume(coro, table.remove(task.sigq, 1))
|
||||
end
|
||||
end
|
||||
|
||||
-- check for exit/stop
|
||||
if task.status=="R" then
|
||||
-- measure execution time
|
||||
local startTime = kernel.computer:time()
|
||||
local ret
|
||||
if kernel.config.preempt then
|
||||
ret = {
|
||||
coroutine.resumeWithTimeout(
|
||||
task.coro,
|
||||
task.timeSlice,
|
||||
table.unpack(task.syscallReturn)
|
||||
)
|
||||
}
|
||||
else
|
||||
ret = {
|
||||
coroutine.resume(
|
||||
task.coro,
|
||||
table.unpack(task.syscallReturn)
|
||||
)
|
||||
}
|
||||
end
|
||||
|
||||
local elapsed = kernel.computer:time() - startTime
|
||||
task.lastTime = elapsed
|
||||
task.totalTime = (task.totalTime or 0) + elapsed
|
||||
task.numRuns = (task.numRuns or 0) + 1
|
||||
|
||||
taskTimes[#taskTimes + 1] = elapsed
|
||||
totalTaskTime = totalTaskTime + elapsed
|
||||
|
||||
if elapsed <= Tmin then Tmin_hit = Tmin_hit + 1 end
|
||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
||||
|
||||
-- handle task results
|
||||
if ret[1] == "error" or ret[1] == false then
|
||||
kernel.log("processHandlerException: " .. ret[2], "ERROR", 2)
|
||||
task.status = "Z"
|
||||
task.exit = "processHandlerException: " .. ret[2]
|
||||
|
||||
elseif ret[1] == "timeout" then
|
||||
task.ivs = task.ivs + 1
|
||||
task.syscallReturn = {}
|
||||
|
||||
elseif ret[1] == "success" or ret[1] == true then
|
||||
task.vs = task.vs + 1
|
||||
|
||||
if ret[2] == "syscall" then
|
||||
if kernel.syscalls[ret[3]] then
|
||||
if kernel.config.debugSyscalls then
|
||||
kernel.log("Task " .. task.pid .. " invoking syscall: " .. ret[3], "DBUG", 5)
|
||||
|
||||
for i = 4, #ret do
|
||||
kernel.log(" inval[" .. tostring(i - 3) .. "] = " .. tostring(ret[i]), "DBUG", 5)
|
||||
end
|
||||
end
|
||||
|
||||
local sysret = {
|
||||
xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))
|
||||
}
|
||||
|
||||
if kernel.config.debugSyscalls then
|
||||
if not sysret[1] then
|
||||
kernel.log(
|
||||
"Task " .. task.pid .. " syscall " .. ret[3] .. " failed: " .. tostring(sysret[2]), "ERROR", 2
|
||||
)
|
||||
|
||||
else
|
||||
kernel.log(
|
||||
"Task " .. task.pid .. " syscall " .. ret[3] .. " completed returning " .. tostring(#sysret - 1) .. " values", "DBUG", 5
|
||||
)
|
||||
|
||||
for i = 2, #sysret do
|
||||
if type(sysret[i]) == "table" then
|
||||
kernel.log(
|
||||
" retval[" .. tostring(i - 1) .. "] = " .. table.serialize(sysret[i]),"DBUG", 5
|
||||
)
|
||||
|
||||
else
|
||||
kernel.log(
|
||||
" retval[" .. tostring(i - 1) .. "] = " .. tostring(sysret[i]), "DBUG", 5
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if not sysret[1] then
|
||||
task.syscallReturn = {false, sysret[2]}
|
||||
|
||||
else
|
||||
task.syscallReturn = {
|
||||
true, table.unpack(sysret, 2)
|
||||
}
|
||||
end
|
||||
else
|
||||
task.syscallReturn = {
|
||||
false, "Unknown syscall: " .. tostring(ret[3])
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
|
||||
local T_prev_var = 0
|
||||
|
||||
for _, t in ipairs(taskTimes) do
|
||||
T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
|
||||
end
|
||||
if N > 0 then T_prev_var = T_prev_var / N end
|
||||
|
||||
if N > 0 then
|
||||
local f_clamp = k_min * (Tmin_hit / N) - k_max * (Tmax_hit / N)
|
||||
local B_budget = (C_target * (N ^ (alpha - 1))) /
|
||||
math.max(T_prev_avg, 1e-8)
|
||||
B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp -
|
||||
lambda_var * T_prev_var
|
||||
end
|
||||
|
||||
-- clean up dead tasks
|
||||
reapDeadTasks()
|
||||
end
|
||||
end
|
||||
|
||||
kernel.tasks = tasks
|
||||
kernel.hpv = sys
|
||||
7
Src/Hyperion-kernel/lib/modules/Hyperion/47_dbg.kmod
Normal file
7
Src/Hyperion-kernel/lib/modules/Hyperion/47_dbg.kmod
Normal file
@@ -0,0 +1,7 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local debug=debug
|
||||
kernel._G.debug={
|
||||
getinfo=debug.getinfo,
|
||||
traceback=debug.traceback
|
||||
}
|
||||
15
Src/Hyperion-kernel/lib/modules/Hyperion/50_gpio.kmod
Normal file
15
Src/Hyperion-kernel/lib/modules/Hyperion/50_gpio.kmod
Normal file
@@ -0,0 +1,15 @@
|
||||
local kernel=...
|
||||
local sysc=kernel.syscalls
|
||||
kernel.gpio={}
|
||||
|
||||
sysc["gpio_write"]=function(pin, data)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("w", data)
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_read"]=function(pin)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("r")
|
||||
end
|
||||
end
|
||||
24
Src/Hyperion-kernel/lib/modules/Hyperion/70_stdlibadv.kmod
Normal file
24
Src/Hyperion-kernel/lib/modules/Hyperion/70_stdlibadv.kmod
Normal file
@@ -0,0 +1,24 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
function print(...)
|
||||
local args = {...}
|
||||
local output = ""
|
||||
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
|
||||
output = output:sub(1, -2)
|
||||
syscall.write(1, output.."\n")
|
||||
end
|
||||
|
||||
function printf(fmt, ...)
|
||||
coroutine.yield()
|
||||
local output = string.format(fmt, ...)
|
||||
syscall.write(1, output.."\n")
|
||||
end
|
||||
|
||||
function printInline(...)
|
||||
coroutine.yield()
|
||||
local args = {...}
|
||||
local output = ""
|
||||
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
|
||||
output = output:sub(1, -2)
|
||||
syscall.write(1, output)
|
||||
end
|
||||
47
Src/Hyperion-kernel/lib/modules/Hyperion/90_init.kmod
Normal file
47
Src/Hyperion-kernel/lib/modules/Hyperion/90_init.kmod
Normal file
@@ -0,0 +1,47 @@
|
||||
-- :Minify:--
|
||||
local kernel = ...
|
||||
kernel.log("Loading init system...")
|
||||
kernel.log("InitPath: " .. kernel.config.initPath)
|
||||
|
||||
local handle = kernel.vfs.open(kernel.config.initPath, "r")
|
||||
local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
||||
kernel.vfs.close(handle)
|
||||
|
||||
local initFunc, err = load(data, "@sysinit", "t", kernel._U)
|
||||
if not initFunc then error("Failed to load init system: " .. err) end
|
||||
|
||||
kernel.tasks["1"] = {
|
||||
coro = coroutine.create(function()
|
||||
local ok, err = xpcall(initFunc, debug.traceback, kernel)
|
||||
if not ok then
|
||||
kernel.panic("Init system crashed: " .. tostring(err))
|
||||
else
|
||||
kernel.panic("Init system exited: " .. tostring(err))
|
||||
end
|
||||
end),
|
||||
|
||||
name = "sysinit",
|
||||
status = "R",
|
||||
pid = 1,
|
||||
tgid = 1,
|
||||
uid = 0,
|
||||
fd = {},
|
||||
envars = {},
|
||||
args = {},
|
||||
exit = "",
|
||||
sleep = 0,
|
||||
ivs = 0,
|
||||
vs = 0,
|
||||
parent = kernel.kernelTask,
|
||||
siblings = kernel.kernelTask.children,
|
||||
children = {},
|
||||
syscallReturn = {},
|
||||
cwd = "/",
|
||||
timeSlice = 0,
|
||||
lastTime = 0,
|
||||
totalTime = 0,
|
||||
numRuns = 0
|
||||
}
|
||||
|
||||
kernel.log("created init task with PID 1")
|
||||
kernel.log("Initializing init system...")
|
||||
23
Test/HyperionOS-units/bin/hunit
Normal file
23
Test/HyperionOS-units/bin/hunit
Normal file
@@ -0,0 +1,23 @@
|
||||
local fs=require("sys.fs")
|
||||
local units=fs.list("/usr/lib/hunit/")
|
||||
fs.mkdir("/tmp/hunit/")
|
||||
local errors={}
|
||||
for i,v in ipairs(units) do
|
||||
print("running unit "..v)
|
||||
local code=fs.readAllText("/usr/lib/hunit/"..v)
|
||||
local func, err=load(code, "@"..v)
|
||||
if not func then
|
||||
print(" [ERROR]:"..err)
|
||||
end
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err=pcall(func)
|
||||
if not ok then
|
||||
print(" [ERROR]:"..err)
|
||||
table.insert(errors, v)
|
||||
else
|
||||
print(" [SUCCESS]")
|
||||
end
|
||||
end
|
||||
|
||||
print(tostring(#errors).." units failed")
|
||||
return 0
|
||||
3
Test/HyperionOS-units/usr/lib/hunit/dir.unit
Normal file
3
Test/HyperionOS-units/usr/lib/hunit/dir.unit
Normal file
@@ -0,0 +1,3 @@
|
||||
local fs = require("sys.fs")
|
||||
assert(fs.mkdir("/tmp/hunit/testdir"), "failed to make directory")
|
||||
assert(fs.isDir("/tmp/hunit/testdir"), "directory does not exist")
|
||||
10
Test/HyperionOS-units/usr/lib/hunit/file.unit
Normal file
10
Test/HyperionOS-units/usr/lib/hunit/file.unit
Normal file
@@ -0,0 +1,10 @@
|
||||
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "w")
|
||||
syscall.VFS_write(fd, "This is a test file")
|
||||
syscall.VFS_close(fd)
|
||||
local fd = syscall.VFS_open("/tmp/hunit/testfile.txt", "r")
|
||||
local text = syscall.VFS_read(fd, 64)
|
||||
syscall.VFS_close(fd)
|
||||
|
||||
if text~="This is a test file" then
|
||||
error("File failed to write/read")
|
||||
end
|
||||
1
contributors.md
Normal file
1
contributors.md
Normal file
@@ -0,0 +1 @@
|
||||
# Contributors
|
||||
@@ -1,34 +0,0 @@
|
||||
readAllText(dir) Returns string:contents
|
||||
reads all text from directory on disk
|
||||
|
||||
writeAllText(dir, content) Returns nil
|
||||
writes all content to file
|
||||
|
||||
appendAllText(dir, content) Returns nil
|
||||
appends all content to file
|
||||
|
||||
getAtributes(dir) Returns table:atributes
|
||||
returns atributes of a file or directory
|
||||
|
||||
list(dir) Returns table:files
|
||||
returns contents of directory
|
||||
|
||||
mkdir(dir) Returns nil
|
||||
makes specified directory
|
||||
|
||||
mkfile(dir) Returns nil
|
||||
makes specified file
|
||||
|
||||
-------------------------------------------------------
|
||||
Atributes table
|
||||
number:size
|
||||
size of file in bytes
|
||||
|
||||
number:owner
|
||||
owner UUID
|
||||
|
||||
number:group
|
||||
group UUID
|
||||
|
||||
number:perms
|
||||
file perms 0-21
|
||||
@@ -1,16 +0,0 @@
|
||||
# drivers
|
||||
---
|
||||
|
||||
## driver types
|
||||
---
|
||||
|
||||
```
|
||||
http - internet
|
||||
lan - local networks
|
||||
fs - filesystems
|
||||
disk - normal disks
|
||||
udisk - byte array disks
|
||||
terminal - screens that only support text
|
||||
```
|
||||
|
||||
### Driver APIS
|
||||
@@ -1,8 +0,0 @@
|
||||
print(text) Returns nil
|
||||
Prints text to the terminal with a trailing \n
|
||||
|
||||
printInline(text) Returns nil
|
||||
Same as print without the trailing \n
|
||||
|
||||
clear() Returns nil
|
||||
Clears screen
|
||||
14
docs/kernel/Syscalls/README.md
Normal file
14
docs/kernel/Syscalls/README.md
Normal file
@@ -0,0 +1,14 @@
|
||||
# Syscalls
|
||||
---
|
||||
|
||||
Syscalls allow for tasks to request somthing only the kernel can do (ex: reading a file).
|
||||
|
||||
Syscalls can be called in 2 ways, ```syscall.{id / name}(args...)``` or ```coroutine.yeild("syscall", {name / id}, args...)```.
|
||||
|
||||
Syscalls are also implemented as functions in
|
||||
```
|
||||
sleep(ms)
|
||||
print(...)
|
||||
printInline(...)
|
||||
printf(fmt, ...)
|
||||
```
|
||||
1
docs/kernel/Syscalls/VFS.md
Normal file
1
docs/kernel/Syscalls/VFS.md
Normal file
@@ -0,0 +1 @@
|
||||
This file contains documentation for VFS syscalls
|
||||
2
docs/kernel/Tasks/privacy.md
Normal file
2
docs/kernel/Tasks/privacy.md
Normal file
@@ -0,0 +1,2 @@
|
||||
# Task privacy
|
||||
---
|
||||
32
docs/kernel/boot.cfg.md
Normal file
32
docs/kernel/boot.cfg.md
Normal file
@@ -0,0 +1,32 @@
|
||||
# boot.cfg docs
|
||||
|
||||
The /boot/boot.cfg file contains configs for booting
|
||||
|
||||
```
|
||||
initPath<String>
|
||||
path that init takes to load the init system (systemd)
|
||||
|
||||
allowGloabalOverwrites<bool>
|
||||
allow modifying of gloabal env (usually for debug purposes)
|
||||
|
||||
enableAdvanacedDebug<bool>
|
||||
allow debug into the kernel
|
||||
|
||||
maxOpenFiles<num>
|
||||
maximum open files for the whole system
|
||||
|
||||
maxFilesPerTask<num>
|
||||
maximum open files for each task
|
||||
|
||||
preempt<bool>
|
||||
enable/disable preemptive multitasking
|
||||
|
||||
debugSyscalls<bool>
|
||||
logs syscalls and their return values aswell as what task executed them
|
||||
|
||||
logTaskExit<bool>
|
||||
logs task exits and errors
|
||||
|
||||
showModLoad<bool>
|
||||
log module loads
|
||||
```
|
||||
17
docs/kernel/bootloaders/diskAPI
Normal file
17
docs/kernel/bootloaders/diskAPI
Normal file
@@ -0,0 +1,17 @@
|
||||
--- Disk API Documentation ---
|
||||
string address = "EXAMPLE_DISK_ADDRESS"
|
||||
function disk:isReadOnly()
|
||||
function disk:spaceUsed()
|
||||
function disk:spaceTotal()
|
||||
function disk:list(path)
|
||||
function disk:fileExists(path)
|
||||
function disk:directoryExists(path)
|
||||
function disk:makeDirectory(path)
|
||||
function disk:remove(path)
|
||||
function disk:setLabel(label)
|
||||
function disk:getLabel(label)
|
||||
function disk:size(path)
|
||||
function disk:open(path, mode)
|
||||
function file:read(handle, count)
|
||||
function file:write(handle, data)
|
||||
function file:close(handle)
|
||||
14
docs/kernel/signals/list.md
Normal file
14
docs/kernel/signals/list.md
Normal file
@@ -0,0 +1,14 @@
|
||||
256 signals
|
||||
|
||||
| ID | Name / Description |
|
||||
| -- | ---------------------------------------------------------------------------------------------------------------------------|
|
||||
| 01 | SIGINT / send with ctrl + c
|
||||
| 02 |
|
||||
| 03 |
|
||||
| 04 |
|
||||
| 05 |
|
||||
| 06 |
|
||||
| 07 |
|
||||
| 08 |
|
||||
| 09 |
|
||||
| 0A |
|
||||
16
docs/terminal/palette_16.txt
Normal file
16
docs/terminal/palette_16.txt
Normal file
@@ -0,0 +1,16 @@
|
||||
0: #000000
|
||||
1: #FFFFFF
|
||||
2: #FF0000
|
||||
3: #00FF00
|
||||
4: #0000FF
|
||||
5: #00FFFF
|
||||
6: #FF00FF
|
||||
7: #FFFF00
|
||||
8: #FF6D00
|
||||
9: #6DFF55
|
||||
10: #24FFFF
|
||||
11: #924900
|
||||
12: #6D6D55
|
||||
13: #DBDBAA
|
||||
14: #6D00FF
|
||||
15: #B6FF00
|
||||
44
scripts/build.ps1
Normal file
44
scripts/build.ps1
Normal file
@@ -0,0 +1,44 @@
|
||||
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
# Clean Build folder
|
||||
if (Test-Path $buildRoot) {
|
||||
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
42
scripts/build.sh
Normal file
42
scripts/build.sh
Normal file
@@ -0,0 +1,42 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
TEST_ROOT="$(realpath "$SCRIPT_ROOT/../src")"
|
||||
BUILD_ROOT="$SCRIPT_ROOT/../Build"
|
||||
|
||||
if [[ -d "$BUILD_ROOT" ]]; then
|
||||
rm -rf "$BUILD_ROOT"
|
||||
fi
|
||||
mkdir -p "$BUILD_ROOT"
|
||||
|
||||
echo "Building from $TEST_ROOT"
|
||||
echo "Output to $BUILD_ROOT"
|
||||
echo ""
|
||||
|
||||
for folder in "$TEST_ROOT"/*/; do
|
||||
[[ -d "$folder" ]] || continue
|
||||
|
||||
folder_root="$folder"
|
||||
package_name="$(basename "$folder_root")"
|
||||
echo "== Package: $package_name =="
|
||||
|
||||
find "$folder_root" -type f | while IFS= read -r src; do
|
||||
rel="${src#$folder_root}"
|
||||
dst="$BUILD_ROOT/$rel"
|
||||
dst_dir="$(dirname "$dst")"
|
||||
|
||||
if [[ ! -d "$dst_dir" ]]; then
|
||||
mkdir -p "$dst_dir"
|
||||
fi
|
||||
|
||||
echo "Processing: $rel"
|
||||
echo " > Copying"
|
||||
cp -f "$src" "$dst"
|
||||
done
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Build complete."
|
||||
57
scripts/buildMini.ps1
Normal file
57
scripts/buildMini.ps1
Normal file
@@ -0,0 +1,57 @@
|
||||
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
# Clean Build folder
|
||||
if (Test-Path $buildRoot) {
|
||||
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
|
||||
# Read first 3 lines
|
||||
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||
|
||||
if ($header -match "--:Minify:--") {
|
||||
Write-Host " > Minifying"
|
||||
$content = luamin -f "$src"
|
||||
|
||||
# UTF8 encoding without BOM because it breaks lua
|
||||
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||
}
|
||||
else {
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
50
scripts/buildMini.sh
Normal file
50
scripts/buildMini.sh
Normal file
@@ -0,0 +1,50 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
TEST_ROOT="$(realpath "$SCRIPT_ROOT/../src")"
|
||||
BUILD_ROOT="$SCRIPT_ROOT/../Build"
|
||||
|
||||
if [[ -d "$BUILD_ROOT" ]]; then
|
||||
rm -rf "$BUILD_ROOT"
|
||||
fi
|
||||
mkdir -p "$BUILD_ROOT"
|
||||
|
||||
echo "Building from $TEST_ROOT"
|
||||
echo "Output to $BUILD_ROOT"
|
||||
echo ""
|
||||
|
||||
for folder in "$TEST_ROOT"/*/; do
|
||||
[[ -d "$folder" ]] || continue
|
||||
|
||||
folder_root="$folder"
|
||||
package_name="$(basename "$folder_root")"
|
||||
echo "== Package: $package_name =="
|
||||
|
||||
find "$folder_root" -type f | while IFS= read -r src; do
|
||||
rel="${src#$folder_root}"
|
||||
dst="$BUILD_ROOT/$rel"
|
||||
dst_dir="$(dirname "$dst")"
|
||||
|
||||
if [[ ! -d "$dst_dir" ]]; then
|
||||
mkdir -p "$dst_dir"
|
||||
fi
|
||||
|
||||
echo "Processing: $rel"
|
||||
|
||||
header="$(head -n 3 "$src" 2>/dev/null || true)"
|
||||
|
||||
if echo "$header" | grep -q -- "--:Minify:--"; then
|
||||
echo " > Minifying"
|
||||
luamin -f "$src" > "$dst"
|
||||
else
|
||||
echo " > Copying"
|
||||
cp -f "$src" "$dst"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Build complete."
|
||||
108
scripts/buildMiniTest.ps1
Normal file
108
scripts/buildMiniTest.ps1
Normal file
@@ -0,0 +1,108 @@
|
||||
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
# Clean Build folder
|
||||
if (Test-Path $buildRoot) {
|
||||
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
|
||||
# Read first 3 lines
|
||||
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||
|
||||
if ($header -match "--:Minify:--") {
|
||||
Write-Host " > Minifying"
|
||||
$content = luamin -f "$src"
|
||||
|
||||
# UTF8 encoding without BOM because it breaks lua
|
||||
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||
}
|
||||
else {
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
|
||||
$testRoot = Join-Path $PSScriptRoot "..\test"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
|
||||
# Read first 3 lines
|
||||
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||
|
||||
if ($header -match "--:Minify:--") {
|
||||
Write-Host " > Minifying"
|
||||
$content = luamin -f "$src"
|
||||
|
||||
# UTF8 encoding without BOM because it breaks lua
|
||||
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||
}
|
||||
else {
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
}
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
55
scripts/buildMiniTest.sh
Normal file
55
scripts/buildMiniTest.sh
Normal file
@@ -0,0 +1,55 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
build_from_root() {
|
||||
local TEST_ROOT
|
||||
TEST_ROOT="$(realpath "$1")"
|
||||
local BUILD_ROOT="$SCRIPT_ROOT/../Build"
|
||||
|
||||
if [[ -d "$BUILD_ROOT" ]]; then
|
||||
rm -rf "$BUILD_ROOT"
|
||||
fi
|
||||
mkdir -p "$BUILD_ROOT"
|
||||
|
||||
echo "Building from $TEST_ROOT"
|
||||
echo "Output to $BUILD_ROOT"
|
||||
echo ""
|
||||
|
||||
for folder in "$TEST_ROOT"/*/; do
|
||||
[[ -d "$folder" ]] || continue
|
||||
|
||||
local package_name
|
||||
package_name="$(basename "$folder")"
|
||||
echo "== Package: $package_name =="
|
||||
|
||||
find "$folder" -type f | while IFS= read -r src; do
|
||||
rel="${src#$folder}"
|
||||
dst="$BUILD_ROOT/$rel"
|
||||
dst_dir="$(dirname "$dst")"
|
||||
|
||||
mkdir -p "$dst_dir"
|
||||
|
||||
echo "Processing: $rel"
|
||||
|
||||
header="$(head -n 3 "$src" 2>/dev/null || true)"
|
||||
|
||||
if echo "$header" | grep -q -- "--:Minify:--"; then
|
||||
echo " > Minifying"
|
||||
luamin -f "$src" > "$dst"
|
||||
else
|
||||
echo " > Copying"
|
||||
cp -f "$src" "$dst"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Build complete."
|
||||
}
|
||||
|
||||
build_from_root "$SCRIPT_ROOT/../src"
|
||||
|
||||
build_from_root "$SCRIPT_ROOT/../test"
|
||||
83
scripts/buildTest.ps1
Normal file
83
scripts/buildTest.ps1
Normal file
@@ -0,0 +1,83 @@
|
||||
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
# Clean Build folder
|
||||
if (Test-Path $buildRoot) {
|
||||
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
|
||||
|
||||
$testRoot = Join-Path $PSScriptRoot "..\test"
|
||||
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||
|
||||
$testRoot = Resolve-Path $testRoot
|
||||
|
||||
Write-Host "Building from $testRoot"
|
||||
Write-Host "Output to $buildRoot"
|
||||
Write-Host ""
|
||||
|
||||
# Each top-level folder in test/
|
||||
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||
|
||||
$folderRoot = $_.FullName
|
||||
Write-Host "== Package: $($_.Name) =="
|
||||
|
||||
# Walk files inside this folder
|
||||
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||
|
||||
$src = $_.FullName
|
||||
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||
$dst = Join-Path $buildRoot $rel
|
||||
$dstDir = Split-Path $dst
|
||||
|
||||
if (-not (Test-Path $dstDir)) {
|
||||
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||
}
|
||||
|
||||
Write-Host "Processing: $rel"
|
||||
|
||||
Write-Host " > Copying"
|
||||
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
}
|
||||
|
||||
Write-Host "Build complete."
|
||||
69
scripts/buildTest.sh
Normal file
69
scripts/buildTest.sh
Normal file
@@ -0,0 +1,69 @@
|
||||
#!/usr/bin/env bash
|
||||
set -e
|
||||
|
||||
SCRIPT_ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
|
||||
TEST_ROOT="$(realpath "$SCRIPT_ROOT/../src")"
|
||||
BUILD_ROOT="$(realpath "$SCRIPT_ROOT/../Build" 2>/dev/null || echo "$SCRIPT_ROOT/../Build")"
|
||||
|
||||
if [[ -d "$BUILD_ROOT" ]]; then
|
||||
rm -rf "$BUILD_ROOT"
|
||||
fi
|
||||
mkdir -p "$BUILD_ROOT"
|
||||
|
||||
echo "Building from $TEST_ROOT"
|
||||
echo "Output to $BUILD_ROOT"
|
||||
echo ""
|
||||
|
||||
for folder in "$TEST_ROOT"/*/; do
|
||||
[[ -d "$folder" ]] || continue
|
||||
|
||||
package_name="$(basename "$folder")"
|
||||
echo "== Package: $package_name =="
|
||||
|
||||
find "$folder" -type f | while read -r src; do
|
||||
rel="${src#$folder}"
|
||||
dst="$BUILD_ROOT/$rel"
|
||||
dst_dir="$(dirname "$dst")"
|
||||
|
||||
mkdir -p "$dst_dir"
|
||||
|
||||
echo "Processing: $rel"
|
||||
echo " > Copying"
|
||||
cp -f "$src" "$dst"
|
||||
done
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Build complete."
|
||||
|
||||
TEST_ROOT="$(realpath "$SCRIPT_ROOT/../test")"
|
||||
BUILD_ROOT="$(realpath "$SCRIPT_ROOT/../Build" 2>/dev/null || echo "$SCRIPT_ROOT/../Build")"
|
||||
|
||||
echo "Building from $TEST_ROOT"
|
||||
echo "Output to $BUILD_ROOT"
|
||||
echo ""
|
||||
|
||||
for folder in "$TEST_ROOT"/*/; do
|
||||
[[ -d "$folder" ]] || continue
|
||||
|
||||
package_name="$(basename "$folder")"
|
||||
echo "== Package: $package_name =="
|
||||
|
||||
find "$folder" -type f | while read -r src; do
|
||||
rel="${src#$folder}"
|
||||
dst="$BUILD_ROOT/$rel"
|
||||
dst_dir="$(dirname "$dst")"
|
||||
|
||||
mkdir -p "$dst_dir"
|
||||
|
||||
echo "Processing: $rel"
|
||||
echo " > Copying"
|
||||
cp -f "$src" "$dst"
|
||||
done
|
||||
|
||||
echo ""
|
||||
done
|
||||
|
||||
echo "Build complete."
|
||||
10
spm/pkg/HyperionOS-bash.pkg
Normal file
10
spm/pkg/HyperionOS-bash.pkg
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"Name": "HyperionOS bash",
|
||||
"Version": "1.0.0",
|
||||
"Publishers": ["HyperionOS Dev Team"],
|
||||
"Description": "Basic bash shell for HyperionOS",
|
||||
"Dependencies": [
|
||||
"HyperionOS"
|
||||
],
|
||||
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm/tar/HyperionOS-kernel.tar.gz"
|
||||
}
|
||||
10
spm/pkg/HyperionOS-core.pkg
Normal file
10
spm/pkg/HyperionOS-core.pkg
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"Name": "HyperionOS core",
|
||||
"Version": "1.0.0",
|
||||
"Publishers": ["HyperionOS Dev Team"],
|
||||
"Description": "Core system files and librarys for HyperionOS",
|
||||
"Dependencies": [
|
||||
"HyperionOS"
|
||||
],
|
||||
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm/tar/HyperionOS-core.tar.gz"
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user