moved stuff to src/ from test/ and made better build scripts

This commit is contained in:
2026-01-15 10:58:27 -05:00
parent 0d46054e56
commit e203f9f36d
84 changed files with 2095 additions and 3618 deletions

129
.vscode/tasks.json vendored
View File

@@ -1,46 +1,89 @@
{
"version": "2.0.0",
"tasks": [
"version": "2.0.0",
"tasks": [
{
"label": "Build (Minfiyed)",
"type": "shell",
"command": "powershell",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}\\tools\\buildMini.ps1"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
},
{
"label": "Build (Source)",
"type": "shell",
"command": "powershell",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}\\tools\\build.ps1"
],
"group": {
"kind": "build",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
},
{
"label": "Build",
"type": "shell",
"windows": {
"command": "powershell",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-Command",
"if (Test-Path '${workspaceFolder}\\Build') { Remove-Item -LiteralPath '${workspaceFolder}\\Build' -Recurse -Force -ErrorAction SilentlyContinue }; New-Item -ItemType Directory -Path '${workspaceFolder}\\Build' | Out-Null; Get-ChildItem -Path '${workspaceFolder}\\Test' -Directory | ForEach-Object { $base = $_.FullName; Get-ChildItem -Path $base -File -Recurse | ForEach-Object { $rel = $_.FullName.Substring($base.Length).TrimStart(\"\\\"); $destPath = Join-Path '${workspaceFolder}\\Build' $rel; $destDir = Split-Path $destPath; if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir | Out-Null }; Copy-Item -LiteralPath $_.FullName -Destination $destPath -Force } }"
]
},
"linux": {
"command": "bash",
"args": [
"-c",
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
]
},
"osx": {
"command": "bash",
"args": [
"-c",
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
]
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": [],
"group": {
"kind": "build",
"isDefault": true
}
}
]
"label": "Test (Minfiyed)",
"type": "shell",
"command": "powershell",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}\\tools\\buildMiniTest.ps1"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
},
{
"label": "Test (Source)",
"type": "shell",
"command": "powershell",
"args": [
"-NoProfile",
"-ExecutionPolicy",
"Bypass",
"-File",
"${workspaceFolder}\\tools\\buildTest.ps1"
],
"group": {
"kind": "test",
"isDefault": true
},
"presentation": {
"reveal": "always",
"panel": "shared"
},
"problemMatcher": []
}
]
}

View File

@@ -0,0 +1,24 @@
local args={...}
<<<<<<< HEAD
local sys = require("sys")
=======
local os=require("os")
local io=require("io")
local text=""
local blockKeyEvents=false
io.link(io.focas)
os.hookSignal("keyTyped", function(_, screen, key)
if blockKeyEvents then return end
if key == "\n" then
blockKeyEvents=true
elseif key == "\b" then
text=text:sub(1,#text-1)
io.stdout.printInline("\b")
else
text=text..key
io.stdout.printInline(key)
end
end)
>>>>>>> 9b268810a7ea44e586d5faf6e2717f1d02497c03

View File

@@ -1,77 +1 @@
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
local a={}local b={}local c={}local function d(e)local f="/"for g,h in pairs(c)do if e:sub(1,#g)==g then if not f or#g>#f then f=g end end end;local i=e:sub(#f+1)return b[c[f]],i end;function a.update(j)b={}for k,l in j.list()do b[k]=l end end;function a.exists(e)local h,i=d(e)return h:directoryExists(i)or h:fileExists(i)end;function a.isFile(e)local h,i=d(e)return h:fileExists(i)end;function a.isDir(e)local h,i=d(e)return h:directoryExists(i)end;function a.list(e)local h,i=d(e)return h:list(i)end;function a.makeDir(e)local h,i=d(e)return h:makeDirectory(i)end;function a.remove(e)local h,i=d(e)return h:remove(i)end;function a.readAllText(e)local h,i=d(e)local m=h:open(i,"r")if not m then return nil end;local n=m.readAll()m.close()return n end;function a.writeAllText(e,o)local h,i=d(e)local m=h:open(i,"w")m.write(o)m.close()end;function a.appendAllText(e,o)local h,i=d(e)local m=h:open(i,"a")m.write(o)m.close()end;function a.load(e)return load(a.readAllText(e),e)end;function a.mount(h,f)if not b[h]then return end;c[f]=h end;return a

View File

@@ -1,250 +1 @@
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 LOG_Text = ""
local kernel = {}
kernel.process = "Kernel"
kernel.user = "root"
kernel.group = "root"
kernel.groups = {0}
kernel.uid = 0
kernel.gid = 0
kernel.status = "start"
kernel.key = {}
kernel.cache = {}
kernel.cache.preload = {}
kernel._G=_G
kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil
local windowsExp = false
function kernel.log(msg, level)
LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
if kernel.status == "start" then
screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
elseif kernel.status == "init" then
kernel.standbyTask=kernel.currentTask
kernel.currentTask=kernel.kernelTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
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(0)
screen:clear()
screen:setCursorPos(1,1)
screen:print(LOG_Text)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
screen:print("Press any key to continue...")
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")
ifs.writeAllText("/boot/boot.cfg",[[
-- 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.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}
]])
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
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", LOG_Text)
end
ifs.remove("/tmp")
ifs.makeDir("/tmp")
function kernel.newFifo()
local fifo = {}
fifo.push=function(data)
table.insert(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,
user="root",
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
kernel.log("Running modules")
for _,p in ipairs(modules) do
for _,v in ipairs(p) do
local code=ifs.readAllText(v)
if not code then
kernel.log("ModuReadErr: "..v, "WARN")
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
::skip::
end
end
kernel.log("Kernel initialized successfully.")
kernel.main()
kernel.PANIC("Execution complete")
local a={...}local b=a[1]local c=a[2]local d=a[3]local e=a[5]local f=a[6]local g=a[7]local h=""local i={}i.process="Kernel"i.user="root"i.group="root"i.groups={0}i.uid=0;i.gid=0;i.status="start"i.key={}i.cache={}i.cache.preload={}i._G=_G;i.sleep=sleep;i.debug=true;_G.sleep=nil;local j=false;function i.log(k,l)h=h..tostring(f:time()).." "..i.user.." "..i.process.."["..tostring(l or"INFO").."]: "..k.."\n"if i.status=="start"then e:print(tostring(f:time()).." "..i.user.." "..i.process.."["..tostring(l or"INFO").."]: "..k)elseif i.status=="init"then i.standbyTask=i.currentTask;i.currentTask=i.kernelTask;i.tty.print(tostring(f:time()).." "..i.user.." "..i.process.."["..tostring(l or"INFO").."]: "..k)i.currentTask=i.standbyTask end end;function i.PANIC(k)if i.status~="Panic"then i.log("PANIC: "..k,"PANIC")pcall(i["saveLog"])i.status="Panic"i.reason=k;e:setTextColor(2)e:setBackgroundColor(0)e:clear()e:setCursorPos(1,1)e:print(h)e:print("KERNEL PANIC!\n"..k.."\nSystem halted.")e:print("Press any key to continue...")end;while true do local m={f:getMachineEvent()}if m[1]=="keyPressed"then break end end;f:reboot()end;i.panic=i.PANIC;if j then e:setTextColor(1)e:setBackgroundColor(4)e:clear()local n,o=e:getSize()e:setCursorPos(3,5)e:print(":(")e:setCursorPos(3,7)e:print("Your PC ran into a problem and needs to restart. We're just collecting some error")e:setCursorPos(3,8)e:print("info, and then we'll restart for you.\n")e:setCursorPos(3,o-5)e:print("Stop code: average windows experience")e:setCursorPos(1,o)e:print("Press any key to continue... jk reboot it yourself lazy")while true do end end;i.log("Kernel loaded.")i.log("Mounting init disks...")c.refresh()g.update(c)i.disks={}for p,q in c.list()do i.disks[q.address]=q end;g.mount("$","/")local r=g.readAllText("/boot/fstab")local s=function(t,u,v)assert(#u==1,"only delim len 1 supported for now")v=(v or 0)-1;local w={}local x=""for y=1,#t do local z=string.sub(t,y,y)if#w~=v and z==u then table.insert(w,x)x=""else x=x..z end end;table.insert(w,x)return w end;if not g.isFile("/boot/boot.cfg")then i.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg","ERROR")g.writeAllText("/boot/boot.cfg",g.readAllText("/boot/safeboot.cfg"))end;local A,B=load(g.readAllText("/boot/boot.cfg"),"@boot.cfg")if not A then i.PANIC("Failed to load /boot/boot.cfg: "..tostring(B))end;local C,D=pcall(A)if not C then i.PANIC("Error in /boot/boot.cfg: "..tostring(D))end;i.config=D;for y,q in ipairs(s(r,"\n"))do if q:sub(1,1)=="U"then local E=""for y=3,#q do if q:sub(y,y)==";"then if y==3 then i.log("Invalid fstab line... Skipping.","WARN")goto F end;E=q:sub(3,y-1)end end;local G=q:sub(#E+4)g.mount(E,G)::F::end end;i.log("Disks initialized")function i.saveLog()g.writeAllText("/var/log/syslog.log",h)end;g.remove("/tmp")g.makeDir("/tmp")function i.newFifo()local H={}H.push=function(I)table.insert(I)end;H.pop=function()return table.remove(H,1)end;return H end;function i.newUUID()local J="xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"local K=""for y=1,#J do local z=J:sub(y,y)if z=="x"then K=K..string.format("%x",math.random(0,15))elseif z=="y"then K=K..string.format("%x",math.random(8,11))else K=K..z end end;return K end;i.syscalls={}local L={[0]={}}for y=0,100 do L[y]={}end;i.log("Gathering modules")for p,y in ipairs(g.list("/lib/modules"))do for p,q in ipairs(g.list("/lib/modules/"..y))do local M=tonumber(q:sub(1,2))L[M+1][#L[M+1]+1]="/lib/modules/"..y.."/"..q end end;i.ifs=g;i.apis=b;i.computer=f;i.arch=d;i.initdisks=c;i.screen=e;i.processes={}i.fstab=r;i.kernelTask={name="kernel",status="R",pid=0,tgid=0,user="root",uid=0,fd={},exit="",sleep=0,ivs=0,vs=0,children={},syscallReturn={},cwd="/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}i.currentTask=i.kernelTask;i.syscalls["OS_time"]=function()return i.computer:time()end;i.syscalls["OS_log"]=i.log;i.log("Running modules")for p,N in ipairs(L)do for p,q in ipairs(N)do local O=g.readAllText(q)if not O then i.log("ModuReadErr: "..q,"WARN")goto P end;local Q,B=load(O,"@"..q)if not Q then i.panic("ModuLoadErr: "..tostring(B))goto P end;local R,B=xpcall(Q,debug.traceback,i)if not R then i.panic("ModuRunErr: "..tostring(B))end::P::end end;i.log("Kernel initialized successfully.")i.status="running"i.main()i.PANIC("Execution complete")

11
Build/boot/safeboot.cfg Normal file
View 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.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}

View File

@@ -36,7 +36,7 @@ end
local function wrapPeripheral(name)
if native.isPresent(name) then
return native.wrap(name)
return wrapPeripheral(name)
end
for n = 1, #sides do
local side = sides[n]

View File

@@ -1,284 +1 @@
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 string.replace(str, search, replacement)
local rv = ""
local consumedLen = 1
local i = 1
while i<#str do
if string.sub(str, i, i+#search-1) == search then
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
i=i+#search
consumedLen = i
end
i=i+1
end
return rv .. string.sub(str, consumedLen)
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 true
end
end
return false
end
function table.hasVal(tabl, query)
for i,v in pairs(tabl) do
if v==query then
return true
end
end
return false
end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify table proxy", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(table)
local output = "{"
for i,v in pairs(table) do
local coma=true
if type(i) == "string" then
output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end
if type(v) == "table" then
if v == table then
output=string.sub(output,1,#output-(#i+1))
coma=false
else
output=output..serialize(v)
end
elseif type(v) == "string" then
output=output.."[=["..v.."]=]"
elseif type(v) == "number" then
output=output..tostring(v)
elseif type(v) == "boolean" then
if v == true then
output=output.."true"
else
output=output.."false"
end
elseif type(v) == "function" then
output=output..tostring(v)
else
error("serialization of type \""..type(v).."\" is not supported")
end
if coma then
output=output..","
end
end
if #table>0 or string.sub(output,#output,#output) == "," then
output=string.sub(output,1,#output-1)
end
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)
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
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
function string.hasSuffix(a,b)return string.sub(a,#b+1)==b end;function string.hasPrefix(a,c)return string.sub(a,1,#c)==c end;function string.getSuffix(a,c)return string.sub(a,#c+1)end;function string.getPrefix(a,b)return string.sub(a,1,#b)end;function string.join(a,...)return table.concat(table.pack(a,...))end;function string.delim(a,...)return table.concat(table.pack(...),a)end;function string.split(a,d,e)assert(#d==1,"only delim len 1 supported for now")e=(e or 0)-1;local f={}local g=""for h=1,#a do local i=string.sub(a,h,h)if#f~=e and i==d then table.insert(f,g)g=""else g=g..i end end;table.insert(f,g)return f end;function string.replace(a,j,k)local f=""local l=1;local h=1;while h<#a do if string.sub(a,h,h+#j-1)==j then f=f..string.sub(a,l,h-1)..k;h=h+#j;l=h end;h=h+1 end;return f..string.sub(a,l)end;function table.deepcopy(m,n)n=n or{}if type(m)~='table'then return m elseif n[m]then return n[m]end;local o={}n[m]=o;for p,q in next,m,nil do local r=table.deepcopy(p,n)local s=table.deepcopy(q,n)o[r]=s end;return o end;function table.hasKey(t,u)for h,q in pairs(t)do if h==u then return true end end;return false end;function table.hasVal(t,u)for h,q in pairs(t)do if q==u then return true end end;return false end;function table.proxy(v)local w=setmetatable({},{__mode="k"})local function x(y)if type(y)~="table"then return y end;if w[y]then return w[y]end;local z={}w[y]=z;local A;A={__index=function(B,p)local C=y[p]if type(C)=="table"then return x(C)else return C end end,__newindex=function()error("Attempt to modify table proxy",2)end,__pairs=function()return function(B,p)local D,E=next(y,p)if type(E)=="table"then E=x(E)end;return D,E end,nil,nil end,__ipairs=function()local h=0;local F=#y;return function()h=h+1;if h<=F then local q=y[h]if type(q)=="table"then q=x(q)end;return h,q end end end,__metatable=false}setmetatable(z,A)return z end;return x(v)end;local function G(table)local H="{"for h,q in pairs(table)do local I=true;if type(h)=="string"then H=H.."[\""..h.."\"]="elseif type(h)=="number"then H=H.."["..tostring(h).."]="end;if type(q)=="table"then if q==table then H=string.sub(H,1,#H-(#h+1))I=false else H=H..G(q)end elseif type(q)=="string"then H=H.."[=["..q.."]=]"elseif type(q)=="number"then H=H..tostring(q)elseif type(q)=="boolean"then if q==true then H=H.."true"else H=H.."false"end elseif type(q)=="function"then H=H..tostring(q)else error("serialization of type \""..type(q).."\" is not supported")end;if I then H=H..","end end;if#table>0 or string.sub(H,#H,#H)==","then H=string.sub(H,1,#H-1)end;H=H.."}"return H end;local J=type;local K=getmetatable;function type(L,M)if M then return J(L)end;if J(L)~="table"then return J(L)else if J(K(L))=="table"then local N=K(L)if N.__type then return N.__type end else return"table"end end end;function getmetatable(L)if J(L)~="table"then return end;if J(K(L))=="table"then if K(L).__isuserdata then if J(K(L).__usermeta)=="function"then return K(L).__usermeta()else return K(L).__usermeta end else return K(L)end else return K(L)end end;function isEqualToAny(O,...)local P={...}for h=0,#P do if O==P[h]then return true end end;return false end;function isEqualToAll(O,...)local P={...}for h=0,#P do if O~=P[h]then return false end end;return true end;function table.keys(y)local O={}for F in pairs(y)do table.insert(O,F)end;return O end;function table.values(y)local O={}for B,F in pairs(y)do table.insert(O,F)end;return O end;function table.indexOf(y,C)for h,q in ipairs(y)do if q==C then return h end end;return-1 end;syscall=setmetatable({},{__index=function(self,Q)return function(...)local R=table.pack(coroutine.yield("syscall",Q,...))if R[1]then return table.unpack(R,2,R.n)else error(R[2],2)end end end})table.serialize=G

View File

@@ -1,277 +1 @@
local kernel = ...
local vfs = {}
vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks
-- Path handling
local function normalizePath(path)
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, "/") .. (path:sub(-1) == "/" and "/" or "")
end
local function resolvePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path
end
path = normalizePath(path)
local mountPoint = "/"
local mountId = "$"
for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then
mountPoint = v
mountId = k
end
end
local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath
end
-- File object creation
local function newFileObject(disk, handle, mode, path)
return {
disk = disk,
handle = handle,
mode = mode,
path = path,
refcount = 1
}
end
local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function allocFD(task)
-- enforce per-task limit
local count = 0
for _ in pairs(task.fd) do count = count + 1 end
if count >= kernel.config.maxFilesPerTask then
error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function checkSystemLimit()
-- enforce system-wide limit
local total = 0
for _, task in pairs(kernel.tasks or {}) do
for _ in pairs(task.fd) do total = total + 1 end
end
if total >= kernel.config.maxOpenFiles then
error("ENFILE") -- Too many open files in the system
end
end
-- VFS syscalls
function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
end
local handle = disk:open(diskPath, mode)
if not handle then return nil end
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
return fd
end
function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1
if file.refcount == 0 then
file.handle.close()
end
return true
end
function vfs.read(fd, count)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("r") then error("File not open for reading") end
return file.handle.read(count)
end
function vfs.write(fd, data)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("w") then error("File not open for writing") end
return file.handle.write(data)
end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
return file.path
end
-- Filesystem operations
function vfs.mkdir(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:makeDirectory(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:remove(diskPath)
end
function vfs.attributes(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:attributes(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
if not disk then return false end
return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:type(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:type(diskPath)
end
-- CWD
function vfs.getcwd()
return kernel.currentTask.cwd
end
function vfs.setcwd(path)
if path:sub(-1) ~= "/" then path = path .. "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path)
if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
if path:sub(-1) ~= "/" then path = path .. "/" end
for _,v in pairs(vfs.mounts) do
if v == path then error("Mount point already used") end
end
vfs.mounts[diskId] = path
end
function vfs.unmount(path)
if kernel.uid ~= 0 then error("Permission denied") end
for k,v in pairs(vfs.mounts) do
if v == path then
vfs.mounts[k] = nil
return true
end
end
return false
end
function vfs.getMounts()
return vfs.mounts
end
function vfs.virtdisk(obj)
kernel.disks[obj.address] = obj
kernel.log("Registered virtual disk at "..obj.address)
end
-- Redirect file operations to VFS
function vfs.dup(oldfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file
file.refcount = file.refcount + 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 oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
-- Syscall registration
kernel.vfs = vfs
kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded")
local a=...local b={}b.mounts={["$"]="/"}local c=a.disks;local function d(e)local f={}for g in e:gmatch("[^/]+")do if g==".."then if#f>0 then table.remove(f)end elseif g~="."and g~=""then table.insert(f,g)end end;return"/"..table.concat(f,"/")..(e:sub(-1)=="/"and"/"or"")end;local function h(e)local i=a.currentTask;local j=i.cwd or"/"if e:sub(1,1)~="/"then e=j..e end;e=d(e)local k="/"local l="$"for m,n in pairs(b.mounts)do if e:sub(1,#n)==n and#n>#k then k=n;l=m end end;local o=e:sub(#k+1)return c[l],o end;local function p(q,r,s,e)return{disk=q,handle=r,mode=s,path=e,refcount=1}end;local function t(i)local u=0;while i.fd[u]do u=u+1 end;return u end;local function t(i)local v=0;for w in pairs(i.fd)do v=v+1 end;if v>=a.config.maxFilesPerTask then error("EMFILE")end;local u=0;while i.fd[u]do u=u+1 end;return u end;local function x()local y=0;for w,i in pairs(a.tasks or{})do for w in pairs(i.fd)do y=y+1 end end;if y>=a.config.maxOpenFiles then error("ENFILE")end end;function b.open(e,s)local i=a.currentTask;x()local q,o=h(e)if not q then error("No disk mounted for path '"..e.."'")end;local r=q:open(o,s)if not r then return nil end;local z=p(q.address,r,s,e)local u=t(i)i.fd[u]=z;return u end;function b.close(u)local i=a.currentTask;local z=i.fd[u]if not z then error("EBADF")end;i.fd[u]=nil;z.refcount=z.refcount-1;if z.refcount==0 then z.handle.close()end;return true end;function b.read(u,v)local z=a.currentTask.fd[u]if not z then error("EBADF")end;if not z.mode:find("r")then error("File not open for reading")end;return z.handle.read(v)end;function b.write(u,A)local z=a.currentTask.fd[u]if not z then error("EBADF")end;if not z.mode:find("w")then error("File not open for writing")end;return z.handle.write(A)end;function b.whereis(u)local z=a.currentTask.fd[u]if not z then error("EBADF")end;return z.path end;function b.mkdir(e)local q,o=h(e)if not q then error("No disk mounted")end;return q:makeDirectory(o)end;function b.remove(e)local q,o=h(e)if not q then error("No disk mounted")end;return q:remove(o)end;function b.attributes(e)if type(e)=="number"then local z=a.currentTask.fd[e]if not z then error("EBADF")end;return c[z.disk]:attributes(z.path)end;local q,o=h(e)if not q then error("No disk mounted")end;return q:attributes(o)end;function b.list(e)local q,o=h(e)if not q then error("No disk mounted")end;return q:list(o)end;function b.exists(e)local q,o=h(e)if not q then return false end;return q:directoryExists(o)or q:fileExists(o)end;function b.type(e)if type(e)=="number"then local z=a.currentTask.fd[e]if not z then error("EBADF")end;return c[z.disk]:type(z.path)end;local q,o=h(e)if not q then error("No disk mounted")end;return q:type(o)end;function b.getcwd()return a.currentTask.cwd end;function b.setcwd(e)if e:sub(-1)~="/"then e=e.."/"end;if e:sub(1,1)~="/"then e="/"..e end;a.currentTask.cwd=d(e)end;function b.mount(B,e)if a.uid~=0 then error("Permission denied")end;if not c[B]then error("Unknown disk '"..B.."'")end;if e:sub(-1)~="/"then e=e.."/"end;for w,n in pairs(b.mounts)do if n==e then error("Mount point already used")end end;b.mounts[B]=e end;function b.unmount(e)if a.uid~=0 then error("Permission denied")end;for m,n in pairs(b.mounts)do if n==e then b.mounts[m]=nil;return true end end;return false end;function b.getMounts()return b.mounts end;function b.virtdisk(C)a.disks[C.address]=C;a.log("Registered virtual disk at "..C.address)end;function b.dup(D)local i=a.currentTask;local z=i.fd[D]if not z then error("EBADF")end;local E=t(i)i.fd[E]=z;z.refcount=z.refcount+1;return E end;function b.dup2(D,E)local i=a.currentTask;local z=i.fd[D]if not z then error("EBADF")end;if D==E then return E end;if i.fd[E]then b.close(E)end;i.fd[E]=z;z.refcount=z.refcount+1;return E end;a.vfs=b;a.syscalls["VFS_open"]=b.open;a.syscalls["VFS_read"]=b.read;a.syscalls["VFS_write"]=b.write;a.syscalls["VFS_close"]=b.close;a.syscalls["VFS_list"]=b.list;a.syscalls["VFS_type"]=b.type;a.syscalls["VFS_attributes"]=b.attributes;a.syscalls["VFS_mkdir"]=b.mkdir;a.syscalls["VFS_remove"]=b.remove;a.syscalls["VFS_exists"]=b.exists;a.syscalls["VFS_mount"]=b.mount;a.syscalls["VFS_unmount"]=b.unmount;a.syscalls["VFS_getcwd"]=b.getcwd;a.syscalls["VFS_setcwd"]=b.setcwd;a.syscalls["VFS_whereis"]=b.whereis;a.syscalls["VFS_dup"]=b.dup;a.syscalls["VFS_dup2"]=b.dup2;a.log("VFS module loaded")

View File

@@ -1,42 +1 @@
local kernel = ...
local cache = {}
local 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(searchpaths) do
local full_path = string.gsub(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
local a=...local b={}local c={"/lib/?.lua","/lib/?","/usr/lib/?.lua","/usr/lib/?","/usr/local/lib/?.lua","/usr/local/lib/?","?.lua","?"}function require(d,...)if b[d]then return b[d]end;local e=d:gsub("%.","/")local f={}for g,h in ipairs(c)do local i=string.gsub(h,"%?",e)if i:sub(1,1)~="/"then i=a.currentTask.cwd..i end;if a.vfs.exists(i)then if a.vfs.type(i)=="directory"then i=i.."/init"end;if a.vfs.exists(i)then local j=a.vfs.open(i,"r")local k=a.vfs.read(j,1024*1024*4)a.vfs.close(j)return assert(load(k,i,"t",a._U))(...)else table.insert(f,i)end else table.insert(f,i)end end;error("Module not found: "..d.." (searched paths: "..table.concat(f,", ")..")")end

View File

@@ -1,172 +1 @@
local kernel = ...
local proxy = {}
local data = {}
proxy.address = "devfs0000"
proxy.isReadOnly = false
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("Permission denied") end
proxy.remove = function() error("Permission denied") end
proxy.setLabel = function() error("Permission denied") end
proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return {
type = proxy.type(path),
isReadOnly = false,
size = 0,
lastModified = 0,
created = 0,
Permissions = "666",
owner = "root",
group = "root"
} end
local function getNode(path)
local parts = string.split(path, "/")
if parts[1] == "" then
table.remove(parts, 1)
end
local node = data
for _, part in ipairs(parts) do
if node[part] then
node = node[part]
else
return nil
end
end
return node
end
proxy.type = function(path)
local node = getNode(path)
if node then
return node.type
else
return nil
end
end
proxy.list = function(path)
local node = getNode(path)
if node and node.type == "directory" then
local content = table.keys(node)
table.remove(content, table.indexOf(content, "type"))
return content
else
error("Not a directory")
end
end
proxy.open = function(path, mode)
local node = getNode(path)
if node and (node.type == "file" or node.type == "character device") then
if mode == "r" then
return {
read = node.read,
close = function() end
}
elseif mode == "w" then
return {
write = node.write,
close = function() end
}
else
error("Invalid mode")
end
else
error("Not a file"..type(node))
end
end
local function newStringFile(content)
return {
type = "file",
read = function() return content end,
write = function(newContent) content = newContent end
}
end
local function newDirectory()
return {
type = "directory"
}
end
data["random"] = {
type = "character device",
read = function(amount)
local result = ""
for _ = 1, amount do
result = result .. string.char(math.random(0, 255))
end
return result
end,
write = function() error("Permission denied") end
}
data["null"] = {
type = "character device",
read = function() return "" end,
write = function() end
}
data["zero"] = {
type = "character device",
read = function(amount)
return string.rep("\0", amount)
end,
write = function() error("Permission denied") end
}
data["rtc"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["rtc0"] = {
type = "character device",
read = function() return kernel.computer:time() end,
write = function() error("Permission denied") end
}
data["eeprom"] = {
type = "character device",
read = function() return kernel.computer:getEEPROM() end,
write = function(data)
if kernel.uid ~= 0 then
error("Permission denied")
end
kernel.computer:setEEPROM(data)
end
}
local keyboard = kernel.newFifo()
local mouse = kernel.newFifo()
data["input"] = newDirectory()
data["input"]["keyboard"] = {
type = "pipe",
read = function(amount)
return keyboard.pop()
end,
write = function() error("Permission denied") end
}
data["input"]["mouse"] = {
type = "pipe",
read = function(amount)
return mouse.pop()
end,
write = function() error("Permission denied") end
}
data["pts"] = newDirectory()
kernel.devfs = {}
kernel.devfs.keyboard = keyboard
kernel.devfs.mouse = mouse
kernel.devfs.proxy = proxy
kernel.devfs.data = data
kernel.vfs.virtdisk(proxy)
local a=...local b={}local c={}b.address="devfs0000"b.isReadOnly=false;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function()error("Permission denied")end;b.remove=function()error("Permission denied")end;b.setLabel=function()error("Permission denied")end;b.getLabel=function()return"devfs"end;b.attributes=function(d)return{type=b.type(d),isReadOnly=false,size=0,lastModified=0,created=0,Permissions="666",owner="root",group="root"}end;local function e(d)local f=string.split(d,"/")if f[1]==""then table.remove(f,1)end;local g=c;for h,i in ipairs(f)do if g[i]then g=g[i]else return nil end end;return g end;b.type=function(d)local g=e(d)if g then return g.type else return nil end end;b.list=function(d)local g=e(d)if g and g.type=="directory"then local j=table.keys(g)table.remove(j,table.indexOf(j,"type"))return j else error("Not a directory")end end;b.open=function(d,k)local g=e(d)if g and(g.type=="file"or g.type=="character device")then if k=="r"then return{read=g.read,close=function()end}elseif k=="w"then return{write=g.write,close=function()end}else error("Invalid mode")end else error("Not a file"..type(g))end end;local function l(j)return{type="file",read=function()return j end,write=function(m)j=m end}end;local function n()return{type="directory"}end;c["random"]={type="character device",read=function(o)local p=""for h=1,o do p=p..string.char(math.random(0,255))end;return p end,write=function()error("Permission denied")end}c["null"]={type="character device",read=function()return""end,write=function()end}c["zero"]={type="character device",read=function(o)return string.rep("\0",o)end,write=function()error("Permission denied")end}c["rtc"]={type="character device",read=function()return a.computer:time()end,write=function()error("Permission denied")end}c["rtc0"]={type="character device",read=function()return a.computer:time()end,write=function()error("Permission denied")end}c["eeprom"]={type="character device",read=function()return a.computer:getEEPROM()end,write=function(c)if a.uid~=0 then error("Permission denied")end;a.computer:setEEPROM(c)end}local q=a.newFifo()local r=a.newFifo()c["input"]=n()c["input"]["keyboard"]={type="pipe",read=function(o)return q.pop()end,write=function()error("Permission denied")end}c["input"]["mouse"]={type="pipe",read=function(o)return r.pop()end,write=function()error("Permission denied")end}c["pts"]=n()a.devfs={}a.devfs.keyboard=q;a.devfs.mouse=r;a.devfs.proxy=b;a.devfs.data=c;a.vfs.virtdisk(b)

View File

@@ -1,12 +1 @@
local kernel = ...
kernel.processes.keventd = function()
while true do
local event = {kernel.computer:getMachineEvent()}
if event[1] then
if event[1] == "key" or event[1] == "keyPressed" or event[1] == "keyReleased" then
kernel.devfs.keyboard.push(event)
end
end
end
end
local a=...a.processes.keventd=function()while true do local b={a.computer:getMachineEvent()}if b[1]then if b[1]=="key"or b[1]=="keyPressed"or b[1]=="keyReleased"then a.devfs.keyboard.push(b)end end end end

View File

@@ -1,17 +1 @@
local kernel=...
for i,v in ipairs(string.split(kernel.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)
if id~="$" then
kernel.vfs.mount(id,path)
end
::endline::
end
end
local a=...for b,c in ipairs(string.split(a.fstab,"\n"))do if c:sub(1,1)=="U"then local d=""for b=3,#c do if c:sub(b,b)==";"then if b==3 then a.log("Invalid fstab line... Skipping.","WARN")goto e end;d=c:sub(3,b-1)end end;local f=c:sub(#d+4)if d~="$"then a.vfs.mount(d,f)end::e::end end

View File

@@ -1 +0,0 @@
local kernel = ...

View File

@@ -1,75 +1 @@
local kernel = ...
local ports = {}
local signals = {}
local ipc = {}
function ipc.open(port)
if not ports[port] then
local handle = kernel.newUUID()
ports[port] = {owner = kernel.currentProcess.pid, handle = handle, messages = {}}
return ports[port].handle
end
error("Port already opened")
end
function ipc.close(port)
if ports[port] then
if ports[port].owner == kernel.currentProcess.pid then
ports[port] = nil
return true
else
error("Cannot close port you do not own")
end
end
error("Port not opened")
end
function ipc.send(port, message)
if ports[port] then
table.insert(ports[port].messages, {from = kernel.currentProcess.pid, message = message})
if signals[ports[port].owner] then
signals[ports[port].owner](port, message)
end
return true
end
error("Port not opened")
end
function ipc.receive(port)
if ports[port] then
if #ports[port].messages > 0 then
return table.remove(ports[port].messages, 1)
else
return nil
end
end
error("Port not opened")
end
function ipc.setSignalHandler(pid, handler)
signals[pid] = handler
end
function ipc.clearSignalHandler(pid)
signals[pid] = nil
end
function ipc.sendSignal(pid, ...)
coroutine.resumeWithTimeout(coroutine.create(function(...)
if signals[pid] then
signals[pid](...)
return true
end
end), 100)
return false
end
kernel.ipc = ipc
kernel.syscalls["ipc_open"] = ipc.open
kernel.syscalls["ipc_close"] = ipc.close
kernel.syscalls["ipc_send"] = ipc.send
kernel.syscalls["ipc_receive"] = ipc.receive
kernel.syscalls["ipc_setSignalHandler"] = ipc.setSignalHandler
kernel.syscalls["ipc_clearSignalHandler"] = ipc.clearSignalHandler
kernel.syscalls["ipc_sendSignal"] = ipc.sendSignal
kernel.log("Loaded IPC module")
local a=...local b={}local c={}local d={}function d.open(e)if not b[e]then local f=a.newUUID()b[e]={owner=a.currentProcess.pid,handle=f,messages={}}return b[e].handle end;error("Port already opened")end;function d.close(e)if b[e]then if b[e].owner==a.currentProcess.pid then b[e]=nil;return true else error("Cannot close port you do not own")end end;error("Port not opened")end;function d.send(e,g)if b[e]then table.insert(b[e].messages,{from=a.currentProcess.pid,message=g})if c[b[e].owner]then c[b[e].owner](e,g)end;return true end;error("Port not opened")end;function d.receive(e)if b[e]then if#b[e].messages>0 then return table.remove(b[e].messages,1)else return nil end end;error("Port not opened")end;function d.setSignalHandler(h,i)c[h]=i end;function d.clearSignalHandler(h)c[h]=nil end;function d.sendSignal(h,...)coroutine.resumeWithTimeout(coroutine.create(function(...)if c[h]then c[h](...)return true end end),100)return false end;a.ipc=d;a.syscalls["ipc_open"]=d.open;a.syscalls["ipc_close"]=d.close;a.syscalls["ipc_send"]=d.send;a.syscalls["ipc_receive"]=d.receive;a.syscalls["ipc_setSignalHandler"]=d.setSignalHandler;a.syscalls["ipc_clearSignalHandler"]=d.clearSignalHandler;a.syscalls["ipc_sendSignal"]=d.sendSignal;a.log("Loaded IPC module")

View File

@@ -1,17 +1 @@
local args={...}
local kernel=args[1]
kernel._G=_G
kernel._U=setmetatable({},{
__index = kernel._G,
__newindex = function(t,k,v)
if kernel.config.allowGlobalOverwrites or kernel.allowGlobalOverwrites then
rawset(t,k,v)
return
end
error("Attempt to modify global variable '"..k.."'",2)
end,
__metatable = false
})
kernel.allowGlobalOverwrites=true
kernel._U._G=kernel._U
kernel.allowGlobalOverwrites=false
local a={...}local b=a[1]b._G=_G;b._U=setmetatable({},{__index=b._G,__newindex=function(c,d,e)if b.config.allowGlobalOverwrites or b.allowGlobalOverwrites then rawset(c,d,e)return end;error("Attempt to modify global variable '"..d.."'",2)end,__metatable=false})b.allowGlobalOverwrites=true;b._U._G=b._U;b.allowGlobalOverwrites=false

View File

@@ -1,65 +1 @@
local kernel = ...
local pam = {}
kernel.pam = pam
local loggedIn = {}
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 = require("crypto.blake2s")
if not blake2s then error("Failed to load blake2s") end
if not kernel.vfs.exists("/etc/pam.d/secret") then
local key = ""
for i=1, 256 do
key=key..string.char(math.random(1,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")
function pam.authenticate(username, password)
local fpasswd = getFile("/etc/passwd")
local fshadow = getFile("/etc/shadow")
local passwdLines = string.split(fpasswd, "\n")
local shadowLines = string.split(fshadow, "\n")
local passwd = {}
local shadow = {}
for _, line in ipairs(passwdLines) do
local fields = string.split(line, ":")
passwd[fields[1]] = fields
end
for _, line in ipairs(shadowLines) do
local fields = string.split(line, ":")
shadow[fields[1]] = fields
end
for user, fields in pairs(passwd) do
if user == username then
local shadowPasswd = string.split(shadow[user][2], "$")
local salt = shadowPasswd[2]
local hashedPassword = blake2s(password .. salt, pepper)
if hashedPassword == shadowPasswd[3] then
loggedIn[username] = kernel.newUUID()
return loggedIn[username]
else
return false
end
end
end
end
function pam.authToken(username, token)
return loggedIn[username] == token
end
local a=...local b={}a.pam=b;local c={}local function d(e)local f=a.vfs.open(e,"r")if not f then error("Failed to open file: "..e)end;local g=a.vfs.read(f,1024000)a.vfs.close(f)return g end;local h=require("crypto.blake2s")if not h then error("Failed to load blake2s")end;if not a.vfs.exists("/etc/pam.d/secret")then local i=""for j=1,256 do i=i..string.char(math.random(1,255))end;local k=a.vfs.open("/etc/pam.d/secret","w")a.vfs.write(k,i)a.vfs.close(k)end;local l=d("/etc/pam.d/secret")function b.authenticate(m,n)local o=d("/etc/passwd")local p=d("/etc/shadow")local q=string.split(o,"\n")local r=string.split(p,"\n")local s={}local t={}for u,v in ipairs(q)do local w=string.split(v,":")s[w[1]]=w end;for u,v in ipairs(r)do local w=string.split(v,":")t[w[1]]=w end;for x,w in pairs(s)do if x==m then local y=string.split(t[x][2],"$")local z=y[2]local A=h(n..z,l)if A==y[3]then c[m]=a.newUUID()return c[m]else return false end end end end;function b.authToken(m,B)return c[m]==B end

View File

@@ -1,211 +1 @@
local kernel = ...
local tasks = {}
local sys = {}
local nextpid = 2
kernel.exitMain=false
function sys.spawn(func, name, envars, args, tgid, fshandles)
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
tasks[tostring(id)].status="Z"
tasks[tostring(id)].exit=tostring(err)
else
tasks[tostring(id)].status="Z"
tasks[tostring(id)].exit=err
end
end),
name=name or "task"..tostring(id),
envars=envars or {},
args=args or {},
status="R",
pid=id,
tgid=tgid or kernel.currentTask.tgid,
user=kernel.user,
uid=kernel.uid,
fd=fshandles or {},
exit="",
sleep=0,
ivs=0,
vs=0,
children={},
parent=kernel.currentTask,
siblings=kernel.currentTask.children,
syscallReturn={},
cwd=kernel.currentTask.cwd,
term=kernel.currentTask.term,
timeSlice=0,
lastTime=0,
totalTime=0,
numRuns=0
}
table.insert(kernel.currentTask.children, tasks[tostring(id)])
end
function sys.sleep(ms)
kernel.currentTask.status="S"
kernel.currentTask.sleep=kernel.computer:time()+ms
coroutine.yield()
end
kernel.syscalls["HPV_spawn"]=sys.spawn
kernel.syscalls["HPV_sleep"]=sys.sleep
kernel._G.sleep=function(...)coroutine.yield("HPV_sleep",...)end
local function reapDeadTasks()
for pid, task in pairs(tasks) do
if task.status == "Z" and not task.reapTime then
task.coro = nil
task.ivs = nil
task.vs = nil
task.args = nil
task.envars = nil
task.cwd = nil
task.term = nil
task.numRuns = nil
task.totalTime = nil
task.lastTime = nil
task.timeSlice = nil
task.syscallReturn = nil
task.sleep = nil
for k,v in pairs(task.fd) do
kernel.vfs.close(v)
end
task.fd = nil
task.reapTime = kernel.computer:time() + 30000
elseif task.reapTime and kernel.computer:time() > task.reapTime 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.vfs.cwd = task.cwd
kernel.user = task.user
kernel.uid = task.uid
N = N + 1
-- assign adaptive time slice
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
-- 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" then
kernel.log("processHandlerException: "..ret[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" 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])
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]))
else
kernel.log("Task "..task.pid.." syscall "..ret[3].." completed returning "..tostring(#sysret-1).." values")
for i=2,#sysret do
kernel.log(" retval["..tostring(i-1).."] = "..tostring(sysret[i]))
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
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
local a=...local b={}local c={}local d=2;a.exitMain=false;function c.spawn(e,f,g,h,i,j)local k=d;d=d+1;b[tostring(k)]={coro=coroutine.create(function()local l,m=xpcall(e,debug.traceback,table.unpack(h or{}))if not l then b[tostring(k)].status="Z"b[tostring(k)].exit=tostring(m)else b[tostring(k)].status="Z"b[tostring(k)].exit=m end end),name=f or"task"..tostring(k),envars=g or{},args=h or{},status="R",pid=k,tgid=i or a.currentTask.tgid,user=a.user,uid=a.uid,fd=j or{},exit="",sleep=0,ivs=0,vs=0,children={},parent=a.currentTask,siblings=a.currentTask.children,syscallReturn={},cwd=a.currentTask.cwd,term=a.currentTask.term,timeSlice=0,lastTime=0,totalTime=0,numRuns=0}table.insert(a.currentTask.children,b[tostring(k)])end;function c.sleep(n)a.currentTask.status="S"a.currentTask.sleep=a.computer:time()+n;coroutine.yield()end;a.syscalls["HPV_spawn"]=c.spawn;a.syscalls["HPV_sleep"]=c.sleep;a._G.sleep=function(...)coroutine.yield("syscall","HPV_sleep",...)end;local function o()for p,q in pairs(b)do if q.status=="Z"and not q.reapTime then q.coro=nil;q.ivs=nil;q.vs=nil;q.args=nil;q.envars=nil;q.cwd=nil;q.term=nil;q.numRuns=nil;q.totalTime=nil;q.lastTime=nil;q.timeSlice=nil;q.syscallReturn=nil;q.sleep=nil;for r,s in pairs(q.fd)do a.vfs.close(s)end;q.fd=nil;q.reapTime=a.computer:time()+30000 elseif q.reapTime and a.computer:time()>q.reapTime then for t,u in ipairs(q.children)do u.parent=b["1"]u.siblings=b["1"].children;table.insert(b["1"].children,u)end;for v,w in ipairs(q.siblings)do if w.pid==q.pid then table.remove(q.siblings,v)break end end;b[p]=nil end end end;local x=0.85;local y=0.01;local z=0.0005;local A=0.5;local B=0.08;local C=0.03;local D=0.02;local E=0.5;local F=0.5;local G=0.01;function a.main()while not a.exitMain do local H=0;local I=0;local J=0;local K=0;local L={}for p,q in pairs(b)do if q.status=="S"then if a.computer:time()>=q.sleep then q.status="R"q.sleep=0 end end;if q.status=="R"then a.currentTask=q;a.vfs.cwd=q.cwd;a.user=q.user;a.uid=q.uid;H=H+1;q.timeSlice=math.min(A,math.max(z,G/H^x))local M=a.computer:time()local N;if a.config.preempt then N={coroutine.resumeWithTimeout(q.coro,q.timeSlice,table.unpack(q.syscallReturn))}else N={coroutine.resume(q.coro,table.unpack(q.syscallReturn))}end;local O=a.computer:time()-M;q.lastTime=O;q.totalTime=(q.totalTime or 0)+O;q.numRuns=(q.numRuns or 0)+1;L[#L+1]=O;K=K+O;if O<=z then I=I+1 end;if O>=A then J=J+1 end;if N[1]=="error"then a.log("processHandlerException: "..N[2])q.status="Z"q.exit="processHandlerException: "..N[2]elseif N[1]=="timeout"then q.ivs=q.ivs+1;q.syscallReturn={}elseif N[1]=="success"then q.vs=q.vs+1;if N[2]=="syscall"then if a.syscalls[N[3]]then if a.config.debugSyscalls then a.log("Task "..q.pid.." invoking syscall: "..N[3],"DBUG")end;local P={xpcall(a.syscalls[N[3]],debug.traceback,table.unpack(N,4))}if a.config.debugSyscalls then if not P[1]then a.log("Task "..q.pid.." syscall "..N[3].." failed: "..tostring(P[2]))else a.log("Task "..q.pid.." syscall "..N[3].." completed returning "..tostring(#P-1).." values","DBUG")for v=2,#P do a.log(" retval["..tostring(v-1).."] = "..tostring(P[v]),"DBUG")end end end;if not P[1]then q.syscallReturn={false,P[2]}else q.syscallReturn={true,table.unpack(P,2)}end else q.syscallReturn={false,"Unknown syscall: "..tostring(N[3])}end end end end end;local Q=H>0 and K/H or 0;local R=0;for t,S in ipairs(L)do R=R+(S-Q)^2 end;if H>0 then R=R/H end;if H>0 then local T=E*I/H-F*J/H;local U=y*H^(x-1)/math.max(Q,1e-8)G=G+B*(U-G)+C*T-D*R end;o()end end;a.tasks=b;a.hpv=c

View File

@@ -1,6 +1 @@
local kernel=...
local debug=debug
kernel._G.debug={
getinfo=debug.getinfo,
traceback=debug.traceback
}
local a=...local debug=debug;a._G.debug={getinfo=debug.getinfo,traceback=debug.traceback}

View File

@@ -1,125 +1 @@
local kernel=...
kernel.tty={}
function kernel.tty.register(tty, ttyo)
kernel.tty[tty]=ttyo
end
function kernel.tty.print(text)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
kernel.tty[term].print(text)
end
end
function kernel.tty.printInline(text)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
kernel.tty[term].printInline(text)
end
end
function kernel.tty.size()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].size()
end
end
function kernel.tty.setCursorPos(x,y)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setCursorPos(x,y)
end
end
function kernel.tty.getCursorPos()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].getCursorPos()
end
end
function kernel.tty.clear()
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].clear()
end
end
function kernel.tty.setTextColor(color)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setTextColor(color)
end
end
function kernel.tty.setBackgroundColor(color)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].setBackgroundColor(color)
end
end
function kernel.tty.scroll(n)
local term=kernel.currentTask.term
if term and kernel.tty[term] then
return kernel.tty[term].scroll(n)
end
end
function kernel.tty.getTextColor()
local term=kernel.currentTask.term
if term and kernel.tty[term] and kernel.tty[term].getTextColor then
return kernel.tty[term].getTextColor()
end
end
function kernel.tty.getBackgroundColor()
local term=kernel.currentTask.term
if term and kernel.tty[term] and kernel.tty[term].getBackgroundColor then
return kernel.tty[term].getBackgroundColor()
end
end
function kernel.tty.bind(ttyid)
if not ttyid then
return false, "No TTY ID specified"
end
if not kernel.tty[ttyid] then
return false, "TTY "..tostring(ttyid).." not registered"
end
kernel.currentTask.term=ttyid
return true
end
function kernel.tty.unbind()
kernel.currentTask.term=false
end
function kernel.tty.isBound()
return kernel.currentTask.term ~= nil
end
function kernel.tty.getBoundTTY()
return kernel.currentTask.term
end
kernel.syscalls["TTY_print"]=kernel.tty.print
kernel.syscalls["TTY_printInline"]=kernel.tty.printInline
kernel.syscalls["TTY_size"]=kernel.tty.size
kernel.syscalls["TTY_setCursorPos"]=kernel.tty.setCursorPos
kernel.syscalls["TTY_getCursorPos"]=kernel.tty.getCursorPos
kernel.syscalls["TTY_clear"]=kernel.tty.clear
kernel.syscalls["TTY_setTextColor"]=kernel.tty.setTextColor
kernel.syscalls["TTY_setBackgroundColor"]=kernel.tty.setBackgroundColor
kernel.syscalls["TTY_scroll"]=kernel.tty.scroll
kernel.syscalls["TTY_getTextColor"]=kernel.tty.getTextColor
kernel.syscalls["TTY_getBackgroundColor"]=kernel.tty.getBackgroundColor
kernel.syscalls["TTY_bind"]=kernel.tty.bind
kernel.syscalls["TTY_unbind"]=kernel.tty.unbind
kernel.syscalls["TTY_isBound"]=kernel.tty.isBound
kernel.syscalls["TTY_getBoundTTY"]=kernel.tty.getBoundTTY
kernel.log("TTY module loaded attempting to register console tty")
kernel.status="init"
local a=...a.tty={}function a.tty.register(b,c)a.tty[b]=c end;function a.tty.print(d)local e=a.currentTask.term;if e and a.tty[e]then a.tty[e].print(d)end end;function a.tty.printInline(d)local e=a.currentTask.term;if e and a.tty[e]then a.tty[e].printInline(d)end end;function a.tty.size()local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].size()end end;function a.tty.setCursorPos(f,g)local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].setCursorPos(f,g)end end;function a.tty.getCursorPos()local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].getCursorPos()end end;function a.tty.clear()local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].clear()end end;function a.tty.setTextColor(h)local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].setTextColor(h)end end;function a.tty.setBackgroundColor(h)local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].setBackgroundColor(h)end end;function a.tty.scroll(i)local e=a.currentTask.term;if e and a.tty[e]then return a.tty[e].scroll(i)end end;function a.tty.getTextColor()local e=a.currentTask.term;if e and a.tty[e]and a.tty[e].getTextColor then return a.tty[e].getTextColor()end end;function a.tty.getBackgroundColor()local e=a.currentTask.term;if e and a.tty[e]and a.tty[e].getBackgroundColor then return a.tty[e].getBackgroundColor()end end;function a.tty.bind(j)if not j then return false,"No TTY ID specified"end;if not a.tty[j]then return false,"TTY "..tostring(j).." not registered"end;a.currentTask.term=j;return true end;function a.tty.unbind()a.currentTask.term=false end;function a.tty.isBound()return a.currentTask.term~=nil end;function a.tty.getBoundTTY()return a.currentTask.term end;a.syscalls["TTY_print"]=a.tty.print;a.syscalls["TTY_printInline"]=a.tty.printInline;a.syscalls["TTY_size"]=a.tty.size;a.syscalls["TTY_setCursorPos"]=a.tty.setCursorPos;a.syscalls["TTY_getCursorPos"]=a.tty.getCursorPos;a.syscalls["TTY_clear"]=a.tty.clear;a.syscalls["TTY_setTextColor"]=a.tty.setTextColor;a.syscalls["TTY_setBackgroundColor"]=a.tty.setBackgroundColor;a.syscalls["TTY_scroll"]=a.tty.scroll;a.syscalls["TTY_getTextColor"]=a.tty.getTextColor;a.syscalls["TTY_getBackgroundColor"]=a.tty.getBackgroundColor;a.syscalls["TTY_bind"]=a.tty.bind;a.syscalls["TTY_unbind"]=a.tty.unbind;a.syscalls["TTY_isBound"]=a.tty.isBound;a.syscalls["TTY_getBoundTTY"]=a.tty.getBoundTTY;a.log("TTY module loaded attempting to register console tty")a.status="init"

View File

@@ -1,2 +1 @@
local kernel=...
kernel.tty.bind("tty0")
local a=...a.tty.bind("tty0")

View File

@@ -1,28 +1 @@
local kernel=...
function print(...)
coroutine.yield()
local args={...}
local output=""
for i=1,#args do
output=output..tostring(args[i]).."\t"
end
output=output:sub(1,-2)
kernel.tty.print(output)
end
function printf(fmt, ...)
coroutine.yield()
local output=string.format(fmt,...)
kernel.tty.print(output)
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)
kernel.tty.printInline(output)
end
local a=...function print(...)coroutine.yield()local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)a.tty.print(c)end;function printf(e,...)coroutine.yield()local c=string.format(e,...)a.tty.print(c)end;function printInline(...)coroutine.yield()local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)a.tty.printInline(c)end

View File

@@ -1,44 +1 @@
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")
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,
user="root",
uid=0,
fd={},
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...")
local a=...a.log("Loading init system...")a.log("InitPath: "..a.config.initPath)local b=a.vfs.open(a.config.initPath,"r")local c=a.vfs.read(b,1024*1024*4)a.vfs.close(b)local d,e=load(c,"@sysinit")if not d then error("Failed to load init system: "..e)end;a.tasks["1"]={coro=coroutine.create(function()local f,e=xpcall(d,debug.traceback,a)if not f then a.panic("Init system crashed: "..tostring(e))else a.panic("Init system exited: "..tostring(e))end end),name="sysinit",status="R",pid=1,tgid=1,user="root",uid=0,fd={},exit="",sleep=0,ivs=0,vs=0,parent=a.kernelTask,siblings=a.kernelTask.children,children={},syscallReturn={},cwd="/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}a.log("created init task with PID 1")a.log("Initializing init system...")

View File

@@ -76,7 +76,7 @@ local function serialize(table, seen)
end
while true do
kernel.log(serialize(kernel.tasks))
--kernel.log(serialize(kernel.tasks))
kernel.saveLog()
sleep(1000)
end

View File

@@ -1,10 +1,10 @@
{
"Name": "Hyperion bash",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "basic bash shell",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.tar"
{
"Name": "Hyperion bash",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "basic bash shell",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.tar"
}

View File

@@ -1,24 +1,24 @@
local args={...}
local args={...}
<<<<<<< HEAD
local sys = require("sys")
local sys = require("sys")
=======
local os=require("os")
local io=require("io")
local text=""
local blockKeyEvents=false
io.link(io.focas)
os.hookSignal("keyTyped", function(_, screen, key)
if blockKeyEvents then return end
if key == "\n" then
blockKeyEvents=true
elseif key == "\b" then
text=text:sub(1,#text-1)
io.stdout.printInline("\b")
else
text=text..key
io.stdout.printInline(key)
end
end)
local os=require("os")
local io=require("io")
local text=""
local blockKeyEvents=false
io.link(io.focas)
os.hookSignal("keyTyped", function(_, screen, key)
if blockKeyEvents then return end
if key == "\n" then
blockKeyEvents=true
elseif key == "\b" then
text=text:sub(1,#text-1)
io.stdout.printInline("\b")
else
text=text..key
io.stdout.printInline(key)
end
end)
>>>>>>> 9b268810a7ea44e586d5faf6e2717f1d02497c03

View File

@@ -1,10 +1,10 @@
{
"Name": "Hyperion core",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "Core system files and librarys for HyperionOS",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.tar"
{
"Name": "Hyperion core",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "Core system files and librarys for HyperionOS",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.tar"
}

View File

@@ -1,11 +1,11 @@
{
"Name": "Hyperion CCT Firmware",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The ComputerCraftTweaked firmware package for HyperionOS.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-cct-v1.0.0.tar",
"BuildCommand": "sudo cp boot/cct/eeprom /dev/eeprom"
{
"Name": "Hyperion CCT Firmware",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The ComputerCraftTweaked firmware package for HyperionOS.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-cct-v1.0.0.tar",
"BuildCommand": "sudo cp boot/cct/eeprom /dev/eeprom"
}

View File

@@ -1,311 +1,311 @@
local BOOT_DRIVE_PATH="/$"
local term = term
local os = os
-- Function to write text to the terminal with special character handling
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
-- Handle wrapping if we go past right edge
if x > w then
x = 1
y = y + 1
end
-- Handle scrolling if we go past bottom
if y-1 > h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
-- Function to display critical errors and halt the system
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
-- Wrap all in xpcall to catch errors
local ok, err = xpcall(function()
local apis={}
-- List of standard Lua globals
local lua = {
coroutine = true,
debug = true,
_HOST = 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
}
-- Move all non-Lua standard library globals into the apis table
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
function sleep(time)
local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end
end
-- Set up terminal default colors
apis.term.setPaletteColor(0x1, 0x000000) -- #000000
apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0xFF0000) -- #FF0000
apis.term.setPaletteColor(0x8, 0x00FF00) -- #00FF00
apis.term.setPaletteColor(0x10, 0x0000FF) -- #0000FF
apis.term.setPaletteColor(0x20, 0x00FFFF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFF00FF) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFFFF00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0xFF6D00) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x6DFF55) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x24FFFF) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x924900) -- #924900
apis.term.setPaletteColor(0x1000, 0x6D6D55) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0xDBDBAA) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0x6D00FF) -- #6D00FF
apis.term.setPaletteColor(0x8000, 0xB6FF00) -- #B6FF00
-- Wrapper to read files
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
-- Load kernel first if it fails, we can't continue so we display an error
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
-- Set up event queue
local eventQueue = {}
local lkeys={}
lkeys[apis.keys.enter]="\n"
lkeys[apis.keys.backspace]="\b"
lkeys[apis.keys.tab]="\t"
-- Function to queue events
local function queueEvent(event, ...)
table.insert(eventQueue, {event, ...})
end
-- Set up computer api
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
}
-- Set up terminal colors
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local colors={
[0]=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(0x1)
apis.term.setTextColor(0x1000)
apis.term.clear()
apis.term.setCursorPos(1, 1)
-- Make the kernel coroutine so we can hook its execution
local kernelCoro = coroutine.create(function()
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)
-- Diffine a coroutine.resumeWithTimeout function to avoid hanging the system, 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")
-- Main loop to run the kernel coroutine
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] == "char" then
queueEvent("keyTyped", 1, event[2])
elseif event[1] == "key" then
queueEvent("keyPressed", 1, event[2])
if lkeys[event[2]] then
queueEvent("keyTyped", 1, lkeys[event[2]])
end
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
local BOOT_DRIVE_PATH="/$"
local term = term
local os = os
-- Function to write text to the terminal with special character handling
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
-- Handle wrapping if we go past right edge
if x > w then
x = 1
y = y + 1
end
-- Handle scrolling if we go past bottom
if y-1 > h then
term.scroll(1)
y = h
term.setCursorPos(x, y)
end
end
term.setCursorPos(x, y)
end
-- Function to display critical errors and halt the system
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
-- Wrap all in xpcall to catch errors
local ok, err = xpcall(function()
local apis={}
-- List of standard Lua globals
local lua = {
coroutine = true,
debug = true,
_HOST = 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
}
-- Move all non-Lua standard library globals into the apis table
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
function sleep(time)
local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end
end
-- Set up terminal default colors
apis.term.setPaletteColor(0x1, 0x000000) -- #000000
apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0xFF0000) -- #FF0000
apis.term.setPaletteColor(0x8, 0x00FF00) -- #00FF00
apis.term.setPaletteColor(0x10, 0x0000FF) -- #0000FF
apis.term.setPaletteColor(0x20, 0x00FFFF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFF00FF) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFFFF00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0xFF6D00) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x6DFF55) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x24FFFF) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x924900) -- #924900
apis.term.setPaletteColor(0x1000, 0x6D6D55) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0xDBDBAA) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0x6D00FF) -- #6D00FF
apis.term.setPaletteColor(0x8000, 0xB6FF00) -- #B6FF00
-- Wrapper to read files
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
-- Load kernel first if it fails, we can't continue so we display an error
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
-- Set up event queue
local eventQueue = {}
local lkeys={}
lkeys[apis.keys.enter]="\n"
lkeys[apis.keys.backspace]="\b"
lkeys[apis.keys.tab]="\t"
-- Function to queue events
local function queueEvent(event, ...)
table.insert(eventQueue, {event, ...})
end
-- Set up computer api
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
}
-- Set up terminal colors
local icolors={
[0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF
[0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00
}
local colors={
[0]=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(0x1)
apis.term.setTextColor(0x1000)
apis.term.clear()
apis.term.setCursorPos(1, 1)
-- Make the kernel coroutine so we can hook its execution
local kernelCoro = coroutine.create(function()
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)
-- Diffine a coroutine.resumeWithTimeout function to avoid hanging the system, 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")
-- Main loop to run the kernel coroutine
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] == "char" then
queueEvent("keyTyped", 1, event[2])
elseif event[1] == "key" then
queueEvent("keyPressed", 1, event[2])
if lkeys[event[2]] then
queueEvent("keyTyped", 1, lkeys[event[2]])
end
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

View File

@@ -1,121 +1,121 @@
sleep(1)
local BOOT_DRIVE_PATH="/$"
-- 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
-- Here's a list of things that are irreversibly changed:
-- * both `bit` and `bit32` are kept for compatibility
-- * string metatable blocking (on old versions of CC)
-- In addition, if `debug` is not available these things are also irreversibly changed:
-- * old Lua 5.1 `load` function (for loading from a function)
-- * `loadstring` prefixing (before CC:T 1.96.0)
-- * `http.request`
-- * `os.shutdown` and `os.reboot`
-- * `peripheral`
-- * `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
for _,k in ipairs(t) do _G[k] = nil end
local native = _G.term.native()
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
_G.term = native
if _G.http then
_G.http.checkURL = _G.http.checkURLAsync
_G.http.websocket = _G.http.websocketAsync
end
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
-- empty placeholder to let it continue and return without throwing. This results
-- in the `pcall` returning successfully, preventing the error-displaying code
-- from running - essentially making it so that `os.shutdown` is called immediately
-- after the new BIOS exits.
--
-- From there, the setup code is placed in `term.native` since it's the first
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
-- allow it to be the last function called in the original BIOS, and returns.
-- From there execution continues, calling the `term.redirect` dummy, skipping
-- over the error-handling code (since `pcall` returned ok), and calling
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
-- called, which effectively makes it run as the main chunk.
local olderror = error
_G.error = function() end
_G.term.redirect = function() end
function _G.term.native()
_G.term.native = nil
_G.term.redirect = nil
_G.error = olderror
term.setBackgroundColor(32768)
term.setTextColor(1)
term.setCursorPos(1, 1)
term.setCursorBlink(true)
term.clear()
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/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(), "@bootloader")
file.close()
if fn == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write(err)
term.setCursorPos(1, 3)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
setfenv(fn, _G)
local oldshutdown = os.shutdown
os.shutdown = function()
os.shutdown = oldshutdown
return fn(table.unpack(args))
end
end
if debug then
-- Restore functions that were overwritten in the BIOS
-- Apparently this has to be done *after* redefining term.native
local function restoreValue(tab, idx, name, hint)
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
while key ~= name and key ~= nil do
key, value = debug.getupvalue(tab[idx], i)
i=i+1
end
tab[idx] = value or tab[idx]
end
restoreValue(_G, "loadstring", "nativeloadstring", 1)
restoreValue(_G, "load", "nativeload", 5)
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
restoreValue(os, "shutdown", "nativeShutdown", 1)
restoreValue(os, "reboot", "nativeReboot", 1)
if turtle then
restoreValue(turtle, "equipLeft", "v", 1)
restoreValue(turtle, "equipRight", "v", 1)
end
do
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
while key ~= "native" and key ~= nil do
key, value = debug.getupvalue(peripheral.isPresent, i)
i=i+1
end
_G.peripheral = value or peripheral
end
sleep(1)
local BOOT_DRIVE_PATH="/$"
-- 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
-- Here's a list of things that are irreversibly changed:
-- * both `bit` and `bit32` are kept for compatibility
-- * string metatable blocking (on old versions of CC)
-- In addition, if `debug` is not available these things are also irreversibly changed:
-- * old Lua 5.1 `load` function (for loading from a function)
-- * `loadstring` prefixing (before CC:T 1.96.0)
-- * `http.request`
-- * `os.shutdown` and `os.reboot`
-- * `peripheral`
-- * `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
for _,k in ipairs(t) do _G[k] = nil end
local native = _G.term.native()
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
_G.term = native
if _G.http then
_G.http.checkURL = _G.http.checkURLAsync
_G.http.websocket = _G.http.websocketAsync
end
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
-- empty placeholder to let it continue and return without throwing. This results
-- in the `pcall` returning successfully, preventing the error-displaying code
-- from running - essentially making it so that `os.shutdown` is called immediately
-- after the new BIOS exits.
--
-- From there, the setup code is placed in `term.native` since it's the first
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
-- allow it to be the last function called in the original BIOS, and returns.
-- From there execution continues, calling the `term.redirect` dummy, skipping
-- over the error-handling code (since `pcall` returned ok), and calling
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
-- called, which effectively makes it run as the main chunk.
local olderror = error
_G.error = function() end
_G.term.redirect = function() end
function _G.term.native()
_G.term.native = nil
_G.term.redirect = nil
_G.error = olderror
term.setBackgroundColor(32768)
term.setTextColor(1)
term.setCursorPos(1, 1)
term.setCursorBlink(true)
term.clear()
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/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(), "@bootloader")
file.close()
if fn == nil then
term.setCursorBlink(false)
term.setTextColor(16384)
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2)
term.write(err)
term.setCursorPos(1, 3)
term.write("Press any key to continue")
coroutine.yield("key")
os.shutdown()
end
setfenv(fn, _G)
local oldshutdown = os.shutdown
os.shutdown = function()
os.shutdown = oldshutdown
return fn(table.unpack(args))
end
end
if debug then
-- Restore functions that were overwritten in the BIOS
-- Apparently this has to be done *after* redefining term.native
local function restoreValue(tab, idx, name, hint)
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
while key ~= name and key ~= nil do
key, value = debug.getupvalue(tab[idx], i)
i=i+1
end
tab[idx] = value or tab[idx]
end
restoreValue(_G, "loadstring", "nativeloadstring", 1)
restoreValue(_G, "load", "nativeload", 5)
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
restoreValue(os, "shutdown", "nativeShutdown", 1)
restoreValue(os, "reboot", "nativeReboot", 1)
if turtle then
restoreValue(turtle, "equipLeft", "v", 1)
restoreValue(turtle, "equipRight", "v", 1)
end
do
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
while key ~= "native" and key ~= nil do
key, value = debug.getupvalue(peripheral.isPresent, i)
i=i+1
end
_G.peripheral = value or peripheral
end
end

View File

@@ -1,191 +1,191 @@
local apis = ({...})[1]
local BOOT_DRIVE_PATH="/$"
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
---------------------------------------------------------
-- STORAGE
---------------------------------------------------------
local disks = {} -- real disks
local internal = {} -- "$" disk
---------------------------------------------------------
-- HELPERS
---------------------------------------------------------
local function norm(path)
if not path or path == "" then return "/" end
return fs.combine("/", path)
end
--- Creates a disk object given a base path
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 DISK "$" (mapped to "/")
---------------------------------------------------------
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")
local label = h.readAll()
h.close()
return label
end
})
---------------------------------------------------------
-- SCAN REAL DISK PERIPHERALS
---------------------------------------------------------
local function refresh()
-- remove disks that no longer exist
for id, _ in pairs(disks) do
if not peripheral.getType(id) then
disks[id] = nil
end
end
-- detect new disks
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
---------------------------------------------------------
-- ITERATOR
---------------------------------------------------------
local function iter()
refresh()
-- first internal
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
---------------------------------------------------------
-- MODULE RETURN
---------------------------------------------------------
return {
refresh = refresh,
list = iter
}
local apis = ({...})[1]
local BOOT_DRIVE_PATH="/$"
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
---------------------------------------------------------
-- STORAGE
---------------------------------------------------------
local disks = {} -- real disks
local internal = {} -- "$" disk
---------------------------------------------------------
-- HELPERS
---------------------------------------------------------
local function norm(path)
if not path or path == "" then return "/" end
return fs.combine("/", path)
end
--- Creates a disk object given a base path
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 DISK "$" (mapped to "/")
---------------------------------------------------------
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")
local label = h.readAll()
h.close()
return label
end
})
---------------------------------------------------------
-- SCAN REAL DISK PERIPHERALS
---------------------------------------------------------
local function refresh()
-- remove disks that no longer exist
for id, _ in pairs(disks) do
if not peripheral.getType(id) then
disks[id] = nil
end
end
-- detect new disks
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
---------------------------------------------------------
-- ITERATOR
---------------------------------------------------------
local function iter()
refresh()
-- first internal
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
---------------------------------------------------------
-- MODULE RETURN
---------------------------------------------------------
return {
refresh = refresh,
list = iter
}

View File

@@ -1,11 +1,11 @@
{
"Name": "Hyperion OC Firmware",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The OpenComputers firmware package for HyperionOS.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-oc-v1.0.0.tar",
"BuildCommand": "cp boot/oc/eeprom /dev/eeprom"
{
"Name": "Hyperion OC Firmware",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The OpenComputers firmware package for HyperionOS.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg"
],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-oc-v1.0.0.tar",
"BuildCommand": "cp boot/oc/eeprom /dev/eeprom"
}

View File

@@ -1,40 +1,40 @@
local lua = {
coroutine = true,
debug = true,
_HOST = 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
}
for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then
apis[i]=v
_G[i]=nil
end
local lua = {
coroutine = true,
debug = true,
_HOST = 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
}
for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then
apis[i]=v
_G[i]=nil
end
end

View File

@@ -1,18 +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
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

View File

@@ -1,8 +1,8 @@
{
"Name": "Hyperion Kernel",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The kernel package for HyperionOS.",
"Dependencies": [],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.tar"
}
{
"Name": "Hyperion Kernel",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The kernel package for HyperionOS.",
"Dependencies": [],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.tar"
}

View File

@@ -1,77 +1,78 @@
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
--: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

View File

@@ -1,250 +1,243 @@
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 LOG_Text = ""
local kernel = {}
kernel.process = "Kernel"
kernel.user = "root"
kernel.group = "root"
kernel.groups = {0}
kernel.uid = 0
kernel.gid = 0
kernel.status = "start"
kernel.key = {}
kernel.cache = {}
kernel.cache.preload = {}
kernel._G=_G
kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil
local windowsExp = false
function kernel.log(msg, level)
LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
if kernel.status == "start" then
screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
elseif kernel.status == "init" then
kernel.standbyTask=kernel.currentTask
kernel.currentTask=kernel.kernelTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
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(0)
screen:clear()
screen:setCursorPos(1,1)
screen:print(LOG_Text)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
screen:print("Press any key to continue...")
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")
ifs.writeAllText("/boot/boot.cfg",[[
-- 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.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}
]])
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
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", LOG_Text)
end
ifs.remove("/tmp")
ifs.makeDir("/tmp")
function kernel.newFifo()
local fifo = {}
fifo.push=function(data)
table.insert(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,
user="root",
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
kernel.log("Running modules")
for _,p in ipairs(modules) do
for _,v in ipairs(p) do
local code=ifs.readAllText(v)
if not code then
kernel.log("ModuReadErr: "..v, "WARN")
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
::skip::
end
end
kernel.log("Kernel initialized successfully.")
kernel.main()
--: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 LOG_Text = ""
local kernel = {}
kernel.process = "Kernel"
kernel.user = "root"
kernel.group = "root"
kernel.groups = {0}
kernel.uid = 0
kernel.gid = 0
kernel.status = "start"
kernel.key = {}
kernel.cache = {}
kernel.cache.preload = {}
kernel._G=_G
kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil
local windowsExp = false
function kernel.log(msg, level)
LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
if kernel.status == "start" then
screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
elseif kernel.status == "init" then
kernel.standbyTask=kernel.currentTask
kernel.currentTask=kernel.kernelTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
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(0)
screen:clear()
screen:setCursorPos(1,1)
screen:print(LOG_Text)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
screen:print("Press any key to continue...")
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")
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
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", LOG_Text)
end
ifs.remove("/tmp")
ifs.makeDir("/tmp")
function kernel.newFifo()
local fifo = {}
fifo.push=function(data)
table.insert(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,
user="root",
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
kernel.syscalls["OS_time"]=function() return kernel.computer:time() end
kernel.syscalls["OS_log"]=kernel.log
kernel.log("Running modules")
for _,p in ipairs(modules) do
for _,v in ipairs(p) do
local code=ifs.readAllText(v)
if not code then
kernel.log("ModuReadErr: "..v, "WARN")
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
::skip::
end
end
kernel.log("Kernel initialized successfully.")
kernel.status="running"
kernel.main()
kernel.PANIC("Execution complete")

View 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.
-- RECOVERY BOOT CONFIGURATION FILE
return {
initPath = "/sbin/init.lua",
maxOpenFiles = 128,
maxFilesPerTask = 16,
preempt=true
}

View File

@@ -1,284 +1,285 @@
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 string.replace(str, search, replacement)
local rv = ""
local consumedLen = 1
local i = 1
while i<#str do
if string.sub(str, i, i+#search-1) == search then
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
i=i+#search
consumedLen = i
end
i=i+1
end
return rv .. string.sub(str, consumedLen)
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 true
end
end
return false
end
function table.hasVal(tabl, query)
for i,v in pairs(tabl) do
if v==query then
return true
end
end
return false
end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify table proxy", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(table)
local output = "{"
for i,v in pairs(table) do
local coma=true
if type(i) == "string" then
output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end
if type(v) == "table" then
if v == table then
output=string.sub(output,1,#output-(#i+1))
coma=false
else
output=output..serialize(v)
end
elseif type(v) == "string" then
output=output.."[=["..v.."]=]"
elseif type(v) == "number" then
output=output..tostring(v)
elseif type(v) == "boolean" then
if v == true then
output=output.."true"
else
output=output.."false"
end
elseif type(v) == "function" then
output=output..tostring(v)
else
error("serialization of type \""..type(v).."\" is not supported")
end
if coma then
output=output..","
end
end
if #table>0 or string.sub(output,#output,#output) == "," then
output=string.sub(output,1,#output-1)
end
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)
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
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
})
--: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 string.replace(str, search, replacement)
local rv = ""
local consumedLen = 1
local i = 1
while i<#str do
if string.sub(str, i, i+#search-1) == search then
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
i=i+#search
consumedLen = i
end
i=i+1
end
return rv .. string.sub(str, consumedLen)
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 true
end
end
return false
end
function table.hasVal(tabl, query)
for i,v in pairs(tabl) do
if v==query then
return true
end
end
return false
end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify table proxy", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(table)
local output = "{"
for i,v in pairs(table) do
local coma=true
if type(i) == "string" then
output=output.."[\""..i.."\"]="
elseif type(i) == "number" then
output=output.."["..tostring(i).."]="
end
if type(v) == "table" then
if v == table then
output=string.sub(output,1,#output-(#i+1))
coma=false
else
output=output..serialize(v)
end
elseif type(v) == "string" then
output=output.."[=["..v.."]=]"
elseif type(v) == "number" then
output=output..tostring(v)
elseif type(v) == "boolean" then
if v == true then
output=output.."true"
else
output=output.."false"
end
elseif type(v) == "function" then
output=output..tostring(v)
else
error("serialization of type \""..type(v).."\" is not supported")
end
if coma then
output=output..","
end
end
if #table>0 or string.sub(output,#output,#output) == "," then
output=string.sub(output,1,#output-1)
end
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)
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
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

View File

@@ -1,277 +1,278 @@
local kernel = ...
local vfs = {}
vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks
-- Path handling
local function normalizePath(path)
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, "/") .. (path:sub(-1) == "/" and "/" or "")
end
local function resolvePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path
end
path = normalizePath(path)
local mountPoint = "/"
local mountId = "$"
for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then
mountPoint = v
mountId = k
end
end
local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath
end
-- File object creation
local function newFileObject(disk, handle, mode, path)
return {
disk = disk,
handle = handle,
mode = mode,
path = path,
refcount = 1
}
end
local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function allocFD(task)
-- enforce per-task limit
local count = 0
for _ in pairs(task.fd) do count = count + 1 end
if count >= kernel.config.maxFilesPerTask then
error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function checkSystemLimit()
-- enforce system-wide limit
local total = 0
for _, task in pairs(kernel.tasks or {}) do
for _ in pairs(task.fd) do total = total + 1 end
end
if total >= kernel.config.maxOpenFiles then
error("ENFILE") -- Too many open files in the system
end
end
-- VFS syscalls
function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
end
local handle = disk:open(diskPath, mode)
if not handle then return nil end
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
return fd
end
function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1
if file.refcount == 0 then
file.handle.close()
end
return true
end
function vfs.read(fd, count)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("r") then error("File not open for reading") end
return file.handle.read(count)
end
function vfs.write(fd, data)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("w") then error("File not open for writing") end
return file.handle.write(data)
end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
return file.path
end
-- Filesystem operations
function vfs.mkdir(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:makeDirectory(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:remove(diskPath)
end
function vfs.attributes(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:attributes(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
if not disk then return false end
return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:type(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:type(diskPath)
end
-- CWD
function vfs.getcwd()
return kernel.currentTask.cwd
end
function vfs.setcwd(path)
if path:sub(-1) ~= "/" then path = path .. "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path)
if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
if path:sub(-1) ~= "/" then path = path .. "/" end
for _,v in pairs(vfs.mounts) do
if v == path then error("Mount point already used") end
end
vfs.mounts[diskId] = path
end
function vfs.unmount(path)
if kernel.uid ~= 0 then error("Permission denied") end
for k,v in pairs(vfs.mounts) do
if v == path then
vfs.mounts[k] = nil
return true
end
end
return false
end
function vfs.getMounts()
return vfs.mounts
end
function vfs.virtdisk(obj)
kernel.disks[obj.address] = obj
kernel.log("Registered virtual disk at "..obj.address)
end
-- Redirect file operations to VFS
function vfs.dup(oldfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file
file.refcount = file.refcount + 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 oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
-- Syscall registration
kernel.vfs = vfs
kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded")
--:Minify:--
local kernel = ...
local vfs = {}
vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks
-- Path handling
local function normalizePath(path)
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, "/") .. (path:sub(-1) == "/" and "/" or "")
end
local function resolvePath(path)
local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path
end
path = normalizePath(path)
local mountPoint = "/"
local mountId = "$"
for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then
mountPoint = v
mountId = k
end
end
local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath
end
-- File object creation
local function newFileObject(disk, handle, mode, path)
return {
disk = disk,
handle = handle,
mode = mode,
path = path,
refcount = 1
}
end
local function allocFD(task)
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function allocFD(task)
-- enforce per-task limit
local count = 0
for _ in pairs(task.fd) do count = count + 1 end
if count >= kernel.config.maxFilesPerTask then
error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0
while task.fd[fd] do fd = fd + 1 end
return fd
end
local function checkSystemLimit()
-- enforce system-wide limit
local total = 0
for _, task in pairs(kernel.tasks or {}) do
for _ in pairs(task.fd) do total = total + 1 end
end
if total >= kernel.config.maxOpenFiles then
error("ENFILE") -- Too many open files in the system
end
end
-- VFS syscalls
function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then
error("No disk mounted for path '"..path.."'")
end
local handle = disk:open(diskPath, mode)
if not handle then return nil end
local file = newFileObject(disk.address, handle, mode, path)
local fd = allocFD(task)
task.fd[fd] = file
return fd
end
function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1
if file.refcount == 0 then
file.handle.close()
end
return true
end
function vfs.read(fd, count)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("r") then error("File not open for reading") end
return file.handle.read(count)
end
function vfs.write(fd, data)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
if not file.mode:find("w") then error("File not open for writing") end
return file.handle.write(data)
end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd]
if not file then error("EBADF") end
return file.path
end
-- Filesystem operations
function vfs.mkdir(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:makeDirectory(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:remove(diskPath)
end
function vfs.attributes(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:attributes(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path)
if not disk then return false end
return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
if type(path) == "number" then
local file = kernel.currentTask.fd[path]
if not file then error("EBADF") end
return disks[file.disk]:type(file.path)
end
local disk, diskPath = resolvePath(path)
if not disk then error("No disk mounted") end
return disk:type(diskPath)
end
-- CWD
function vfs.getcwd()
return kernel.currentTask.cwd
end
function vfs.setcwd(path)
if path:sub(-1) ~= "/" then path = path .. "/" end
if path:sub(1,1) ~= "/" then path = "/" .. path end
kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path)
if kernel.uid ~= 0 then error("Permission denied") end
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end
if path:sub(-1) ~= "/" then path = path .. "/" end
for _,v in pairs(vfs.mounts) do
if v == path then error("Mount point already used") end
end
vfs.mounts[diskId] = path
end
function vfs.unmount(path)
if kernel.uid ~= 0 then error("Permission denied") end
for k,v in pairs(vfs.mounts) do
if v == path then
vfs.mounts[k] = nil
return true
end
end
return false
end
function vfs.getMounts()
return vfs.mounts
end
function vfs.virtdisk(obj)
kernel.disks[obj.address] = obj
kernel.log("Registered virtual disk at "..obj.address)
end
-- Redirect file operations to VFS
function vfs.dup(oldfd)
local task = kernel.currentTask
local file = task.fd[oldfd]
if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file
file.refcount = file.refcount + 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 oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1
return newfd
end
-- Syscall registration
kernel.vfs = vfs
kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded")

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
local cache = {}
local searchpaths = {

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
kernel.processes.keventd = function()

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel=...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
local ports = {}
local signals = {}

View File

@@ -1,3 +1,4 @@
--:Minify:--
local args={...}
local kernel=args[1]
kernel._G=_G

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
local pam = {}
kernel.pam = pam

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
local tasks = {}
local sys = {}

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel=...
local debug=debug
kernel._G.debug={

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel=...
function print(...)
coroutine.yield()

View File

@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ...
kernel.log("Loading init system...")
kernel.log("InitPath: "..kernel.config.initPath)

View File

@@ -1,15 +1,15 @@
{
"Name": "HyperionOS",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The install package for HyperionOS project.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-ui-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-network-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-security-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-filesystem-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.pkg"
]
{
"Name": "HyperionOS",
"Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"],
"Description": "The install package for HyperionOS project.",
"Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-ui-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-network-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-security-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-filesystem-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.pkg"
]
}

View File

@@ -1,177 +0,0 @@
-- Minimal ISO9660 parser
-- Provides: ISO.open(path) -> iso object
-- Methods: :close(), :readPVD(), :listRoot(), :readFile(path)
local M = {}
local SECTOR_SIZE = 2048
local function readBytes(f, pos, len)
f:seek("set", pos)
return f:read(len)
end
local function u8(s, i)
return string.byte(s, i)
end
local function u16le(s, i)
local b1 = string.byte(s, i)
local b2 = string.byte(s, i+1)
return b1 + b2 * 256
end
local function u32le(s, i)
local b1 = string.byte(s, i)
local b2 = string.byte(s, i+1)
local b3 = string.byte(s, i+2)
local b4 = string.byte(s, i+3)
return b1 + b2*256 + b3*65536 + b4*16777216
end
local function trimVersion(name)
-- remove ;1 version and trailing dots
local n = name:gsub(";1$", "")
n = n:gsub("%.$", "")
return n
end
local ISO = {}
ISO.__index = ISO
function M.open(path)
local f, err = io.open(path, "rb")
if not f then return nil, err end
local self = setmetatable({ f = f, path = path }, ISO)
return self
end
function ISO:close()
if self.f then self.f:close(); self.f = nil end
end
function ISO:readSector(n)
local pos = n * SECTOR_SIZE
return readBytes(self.f, pos, SECTOR_SIZE)
end
function ISO:readPVD()
-- Primary Volume Descriptor at sector 16 (index 16)
local pvd = self:readSector(16)
if not pvd or #pvd < SECTOR_SIZE then return nil, "cannot read PVD" end
local typecode = u8(pvd,1)
local id = pvd:sub(2,6)
if typecode ~= 1 or id ~= "CD001" then return nil, "no primary volume descriptor" end
local volumeIdentifier = pvd:sub(41,72):gsub('%z+$','')
-- root directory record starts at offset 157 (1-based index)
local rdOffset = 157
local rdLen = u8(pvd, rdOffset)
local extent = u32le(pvd, rdOffset + 2)
local dataLen = u32le(pvd, rdOffset + 10)
self.pvd = {
volumeIdentifier = volumeIdentifier,
root = { extent = extent, size = dataLen }
}
return self.pvd
end
local function parseDirRecords(buffer, bytesToRead)
local records = {}
local offset = 1
local total = bytesToRead or #buffer
while offset <= total do
local len = string.byte(buffer, offset)
if not len or len == 0 then
-- padding to sector boundary, move to next byte
offset = offset + 1
else
local rec = {}
rec.len = len
rec.extAttrLen = string.byte(buffer, offset+1)
rec.extent = u32le(buffer, offset+2)
rec.size = u32le(buffer, offset+10)
rec.recordingDate = buffer:sub(offset+18, offset+24)
rec.flags = string.byte(buffer, offset+25)
rec.fileUnitSize = string.byte(buffer, offset+26)
rec.interleaveGapSize = string.byte(buffer, offset+27)
rec.volumeSeq = u16le(buffer, offset+29)
local fiLen = string.byte(buffer, offset+32)
local idStart = offset + 33
local idEnd = idStart + fiLen - 1
local fileId = buffer:sub(idStart, idEnd)
-- strip trailing ;1 and dots
rec.fileIdentifier = fileId
rec.fileName = trimVersion(fileId)
rec.isDirectory = (rec.flags & 0x02) ~= 0
table.insert(records, rec)
offset = offset + len
end
end
return records
end
function ISO:listRoot()
if not self.pvd then self:readPVD() end
local root = self.pvd.root
local extent = root.extent
local size = root.size
local pos = extent * SECTOR_SIZE
local buffer = readBytes(self.f, pos, size)
local records = parseDirRecords(buffer, size)
-- filter out '.' and '..' and entries with empty name
local out = {}
for _, r in ipairs(records) do
local name = r.fileName
if name and name ~= "" and name ~= "\0" and name ~= "\1" and name ~= "." and name ~= ".." then
table.insert(out, { name = name, isDirectory = r.isDirectory, extent = r.extent, size = r.size })
end
end
return out
end
local function splitPath(path)
local parts = {}
for part in path:gmatch('[^/\\]+') do parts[#parts+1]=part end
return parts
end
function ISO:findEntryByPath(path)
if not self.pvd then self:readPVD() end
local parts = splitPath(path)
local curExtent = self.pvd.root.extent
local curSize = self.pvd.root.size
for i, part in ipairs(parts) do
-- read directory entries for curExtent
local buffer = readBytes(self.f, curExtent * SECTOR_SIZE, curSize)
local records = parseDirRecords(buffer, curSize)
local found = nil
for _, r in ipairs(records) do
local name = trimVersion(r.fileIdentifier)
if name:lower() == part:lower() then
found = r; break
end
end
if not found then return nil, "path not found: " .. part end
if i < #parts then
if not found.isDirectory then return nil, "not a directory: "..part end
curExtent = found.extent
curSize = found.size
else
return found
end
end
return nil, "empty path"
end
function ISO:readFile(path)
local rec, err = self:findEntryByPath(path)
if not rec then return nil, err end
if rec.isDirectory then return nil, "path is a directory" end
local pos = rec.extent * SECTOR_SIZE
return readBytes(self.f, pos, rec.size)
end
-- return module
return M

View File

@@ -1 +0,0 @@
local kernel = ...

44
tools/build.ps1 Normal file
View 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."

57
tools/buildMini.ps1 Normal file
View 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."

108
tools/buildMiniTest.ps1 Normal file
View 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."

83
tools/buildTest.ps1 Normal file
View 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."

View File

View File

@@ -1,47 +0,0 @@
-- tar_list.lua
-- List all paths stored in a TAR file (no extraction)
local function octal_to_number(str)
str = str:gsub("%z", ""):match("^%s*(.-)%s*$")
return tonumber(str, 8) or 0
end
local file = ({...})[1]
if not file then
print("Usage: tar_list <tarfile>")
return
end
local f = fs.open(file, "r")
local tar = f.readAll()
f.close()
local i = 1
local len = #tar
while i + 512 <= len do
local header = tar:sub(i, i + 511)
if header:match("^\0+$") then break end
-- Extract raw name & prefix
local name = header:sub(1, 100):gsub("%z.*","")
local prefix = header:sub(346, 500):gsub("%z.*","")
local size = octal_to_number(header:sub(125, 136))
i = i + 512
-- Skip file contents
local pad = (512 - (size % 512)) % 512
i = i + size + pad
local full
if prefix ~= "" then
full = prefix .. "/" .. name
else
full = name
end
-- Print exactly what Windows Explorer stored
print(full)
end