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
+86 -43
View File
@@ -1,46 +1,89 @@
{ {
"version": "2.0.0", "version": "2.0.0",
"tasks": [ "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", "label": "Test (Minfiyed)",
"type": "shell", "type": "shell",
"command": "powershell",
"windows": { "args": [
"command": "powershell", "-NoProfile",
"args": [ "-ExecutionPolicy",
"-NoProfile", "Bypass",
"-ExecutionPolicy", "-File",
"Bypass", "${workspaceFolder}\\tools\\buildMiniTest.ps1"
"-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 } }" "group": {
] "kind": "test",
}, "isDefault": true
},
"linux": { "presentation": {
"command": "bash", "reveal": "always",
"args": [ "panel": "shared"
"-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" "problemMatcher": []
] },
}, {
"label": "Test (Source)",
"osx": { "type": "shell",
"command": "bash", "command": "powershell",
"args": [ "args": [
"-c", "-NoProfile",
"[ -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" "-ExecutionPolicy",
] "Bypass",
}, "-File",
"${workspaceFolder}\\tools\\buildTest.ps1"
"presentation": { ],
"reveal": "always", "group": {
"panel": "shared" "kind": "test",
}, "isDefault": true
"problemMatcher": [], },
"group": { "presentation": {
"kind": "build", "reveal": "always",
"isDefault": true "panel": "shared"
} },
} "problemMatcher": []
] }
]
} }
+24
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
+1 -77
View File
@@ -1,77 +1 @@
local 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
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
+1 -250
View File
@@ -1,250 +1 @@
local args = {...} 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")
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")
+11
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
}
+1 -1
View File
@@ -36,7 +36,7 @@ end
local function wrapPeripheral(name) local function wrapPeripheral(name)
if native.isPresent(name) then if native.isPresent(name) then
return native.wrap(name) return wrapPeripheral(name)
end end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
+1 -284
View File
@@ -1,284 +1 @@
function string.hasSuffix(str, suffix) 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
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
+1 -277
View File
@@ -1,277 +1 @@
local kernel = ... 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")
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")
+1 -42
View File
@@ -1,42 +1 @@
local kernel = ... 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
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
+1 -172
View File
@@ -1,172 +1 @@
local kernel = ... 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)
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)
+1 -12
View File
@@ -1,12 +1 @@
local kernel = ... 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
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
+1 -17
View File
@@ -1,17 +1 @@
local kernel=... 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
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
@@ -1 +0,0 @@
local kernel = ...
+1 -75
View File
@@ -1,75 +1 @@
local kernel = ... 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")
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")
+1 -17
View File
@@ -1,17 +1 @@
local args={...} 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
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
+1 -65
View File
@@ -1,65 +1 @@
local kernel = ... 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
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
+1 -211
View File
@@ -1,211 +1 @@
local kernel = ... 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
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
+1 -6
View File
@@ -1,6 +1 @@
local kernel=... local a=...local debug=debug;a._G.debug={getinfo=debug.getinfo,traceback=debug.traceback}
local debug=debug
kernel._G.debug={
getinfo=debug.getinfo,
traceback=debug.traceback
}
+1 -125
View File
@@ -1,125 +1 @@
local kernel=... 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"
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"
@@ -1,2 +1 @@
local kernel=... local a=...a.tty.bind("tty0")
kernel.tty.bind("tty0")
+1 -28
View File
@@ -1,28 +1 @@
local kernel=... 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
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
+1 -44
View File
@@ -1,44 +1 @@
local kernel = ... 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...")
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...")
+1 -1
View File
@@ -76,7 +76,7 @@ local function serialize(table, seen)
end end
while true do while true do
kernel.log(serialize(kernel.tasks)) --kernel.log(serialize(kernel.tasks))
kernel.saveLog() kernel.saveLog()
sleep(1000) sleep(1000)
end end
@@ -1,10 +1,10 @@
{ {
"Name": "Hyperion bash", "Name": "Hyperion bash",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "basic bash shell", "Description": "basic bash shell",
"Dependencies": [ "Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg" "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" "Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.tar"
} }
@@ -1,24 +1,24 @@
local args={...} local args={...}
<<<<<<< HEAD <<<<<<< HEAD
local sys = require("sys") local sys = require("sys")
======= =======
local os=require("os") local os=require("os")
local io=require("io") local io=require("io")
local text="" local text=""
local blockKeyEvents=false local blockKeyEvents=false
io.link(io.focas) io.link(io.focas)
os.hookSignal("keyTyped", function(_, screen, key) os.hookSignal("keyTyped", function(_, screen, key)
if blockKeyEvents then return end if blockKeyEvents then return end
if key == "\n" then if key == "\n" then
blockKeyEvents=true blockKeyEvents=true
elseif key == "\b" then elseif key == "\b" then
text=text:sub(1,#text-1) text=text:sub(1,#text-1)
io.stdout.printInline("\b") io.stdout.printInline("\b")
else else
text=text..key text=text..key
io.stdout.printInline(key) io.stdout.printInline(key)
end end
end) end)
>>>>>>> 9b268810a7ea44e586d5faf6e2717f1d02497c03 >>>>>>> 9b268810a7ea44e586d5faf6e2717f1d02497c03
@@ -1,10 +1,10 @@
{ {
"Name": "Hyperion core", "Name": "Hyperion core",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "Core system files and librarys for HyperionOS", "Description": "Core system files and librarys for HyperionOS",
"Dependencies": [ "Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg" "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" "Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.tar"
} }
@@ -1,11 +1,11 @@
{ {
"Name": "Hyperion CCT Firmware", "Name": "Hyperion CCT Firmware",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "The ComputerCraftTweaked firmware package for HyperionOS.", "Description": "The ComputerCraftTweaked firmware package for HyperionOS.",
"Dependencies": [ "Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg" "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", "Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-cct-v1.0.0.tar",
"BuildCommand": "sudo cp boot/cct/eeprom /dev/eeprom" "BuildCommand": "sudo cp boot/cct/eeprom /dev/eeprom"
} }
@@ -1,311 +1,311 @@
local BOOT_DRIVE_PATH="/$" local BOOT_DRIVE_PATH="/$"
local term = term local term = term
local os = os local os = os
-- Function to write text to the terminal with special character handling -- Function to write text to the terminal with special character handling
local function write(text) local function write(text)
local x, y = term.getCursorPos() local x, y = term.getCursorPos()
local w, h = term.getSize() local w, h = term.getSize()
for i = 1, #text do for i = 1, #text do
local c = text:sub(i, i) local c = text:sub(i, i)
if c == "\n" then if c == "\n" then
y = y + 1 y = y + 1
x = 1 x = 1
elseif c == "\t" then elseif c == "\t" then
local tabSize = 4 local tabSize = 4
local spaces = tabSize - ((x - 1) % tabSize) local spaces = tabSize - ((x - 1) % tabSize)
term.write(string.rep(" ", spaces)) term.write(string.rep(" ", spaces))
x = x + spaces x = x + spaces
elseif c == "\b" then elseif c == "\b" then
if x > 1 then if x > 1 then
x = x - 1 x = x - 1
term.setCursorPos(x, y) term.setCursorPos(x, y)
term.write(" ") term.write(" ")
term.setCursorPos(x, y) term.setCursorPos(x, y)
end end
else else
if x <= w and y <= h then if x <= w and y <= h then
term.setCursorPos(x, y) term.setCursorPos(x, y)
term.write(c) term.write(c)
x = x + 1 x = x + 1
end end
end end
-- Handle wrapping if we go past right edge -- Handle wrapping if we go past right edge
if x > w then if x > w then
x = 1 x = 1
y = y + 1 y = y + 1
end end
-- Handle scrolling if we go past bottom -- Handle scrolling if we go past bottom
if y-1 > h then if y-1 > h then
term.scroll(1) term.scroll(1)
y = h y = h
term.setCursorPos(x, y) term.setCursorPos(x, y)
end end
end end
term.setCursorPos(x, y) term.setCursorPos(x, y)
end end
-- Function to display critical errors and halt the system -- Function to display critical errors and halt the system
local function displaySuperBadError(err) local function displaySuperBadError(err)
term.setBackgroundColor(0x1) term.setBackgroundColor(0x1)
term.setTextColor(0x4) term.setTextColor(0x4)
term.clear() term.clear()
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
term.write("A critical error occurred while loading the system:") term.write("A critical error occurred while loading the system:")
term.setCursorPos(1, 3) term.setCursorPos(1, 3)
write(err) write(err)
while true do end while true do end
end end
-- Wrap all in xpcall to catch errors -- Wrap all in xpcall to catch errors
local ok, err = xpcall(function() local ok, err = xpcall(function()
local apis={} local apis={}
-- List of standard Lua globals -- List of standard Lua globals
local lua = { local lua = {
coroutine = true, coroutine = true,
debug = true, debug = true,
_HOST = true, _HOST = true,
_VERSION = true, _VERSION = true,
assert = true, assert = true,
collectgarbage = true, collectgarbage = true,
error = true, error = true,
gcinfo = true, gcinfo = true,
getfenv = true, getfenv = true,
getmetatable = true, getmetatable = true,
ipairs = true, ipairs = true,
__inext = true, __inext = true,
load = true, load = true,
math = true, math = true,
next = true, next = true,
pairs = true, pairs = true,
pcall = true, pcall = true,
rawequal = true, rawequal = true,
rawget = true, rawget = true,
rawlen = true, rawlen = true,
rawset = true, rawset = true,
select = true, select = true,
setfenv = true, setfenv = true,
setmetatable = true, setmetatable = true,
string = true, string = true,
table = true, table = true,
tonumber = true, tonumber = true,
tostring = true, tostring = true,
type = true, type = true,
xpcall = true, xpcall = true,
_G=true _G=true
} }
-- Move all non-Lua standard library globals into the apis table -- Move all non-Lua standard library globals into the apis table
local debug = debug local debug = debug
for i,v in pairs(_G) do for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then if not lua[i] or lua[i]==nil then
apis[i]=v apis[i]=v
_G[i]=nil _G[i]=nil
end end
end end
function sleep(time) function sleep(time)
local stoptime = apis.os.clock() + (time) local stoptime = apis.os.clock() + (time)
while stoptime > apis.os.clock() do end while stoptime > apis.os.clock() do end
end end
-- Set up terminal default colors -- Set up terminal default colors
apis.term.setPaletteColor(0x1, 0x000000) -- #000000 apis.term.setPaletteColor(0x1, 0x000000) -- #000000
apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF apis.term.setPaletteColor(0x2, 0xFFFFFF) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0xFF0000) -- #FF0000 apis.term.setPaletteColor(0x4, 0xFF0000) -- #FF0000
apis.term.setPaletteColor(0x8, 0x00FF00) -- #00FF00 apis.term.setPaletteColor(0x8, 0x00FF00) -- #00FF00
apis.term.setPaletteColor(0x10, 0x0000FF) -- #0000FF apis.term.setPaletteColor(0x10, 0x0000FF) -- #0000FF
apis.term.setPaletteColor(0x20, 0x00FFFF) -- #00FFFF apis.term.setPaletteColor(0x20, 0x00FFFF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFF00FF) -- #FF00FF apis.term.setPaletteColor(0x40, 0xFF00FF) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFFFF00) -- #FFFF00 apis.term.setPaletteColor(0x80, 0xFFFF00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0xFF6D00) -- #FF6D00 apis.term.setPaletteColor(0x100, 0xFF6D00) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x6DFF55) -- #6DFF55 apis.term.setPaletteColor(0x200, 0x6DFF55) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x24FFFF) -- #24FFFF apis.term.setPaletteColor(0x400, 0x24FFFF) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x924900) -- #924900 apis.term.setPaletteColor(0x800, 0x924900) -- #924900
apis.term.setPaletteColor(0x1000, 0x6D6D55) -- #6D6D55 apis.term.setPaletteColor(0x1000, 0x6D6D55) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0xDBDBAA) -- #DBDBAA apis.term.setPaletteColor(0x2000, 0xDBDBAA) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0x6D00FF) -- #6D00FF apis.term.setPaletteColor(0x4000, 0x6D00FF) -- #6D00FF
apis.term.setPaletteColor(0x8000, 0xB6FF00) -- #B6FF00 apis.term.setPaletteColor(0x8000, 0xB6FF00) -- #B6FF00
-- Wrapper to read files -- Wrapper to read files
local function getFile(path) local function getFile(path)
local file = apis.fs.open(path, "r") local file = apis.fs.open(path, "r")
if not file then displaySuperBadError("Could not open file: "..path) end if not file then displaySuperBadError("Could not open file: "..path) end
local content = file.readAll() local content = file.readAll()
file.close() file.close()
return content return content
end end
-- Load kernel first if it fails, we can't continue so we display an error -- 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 Kernel = load(getFile(BOOT_DRIVE_PATH.."/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/initdisks","@Init_disks"))(apis) local initFs = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/initdisks","@Init_disks"))(apis)
local fs = load(getFile(BOOT_DRIVE_PATH.."/boot/initfs"),"@InitFs")() local fs = load(getFile(BOOT_DRIVE_PATH.."/boot/initfs"),"@InitFs")()
if not Kernel then if not Kernel then
displaySuperBadError("Could not load kernel.") displaySuperBadError("Could not load kernel.")
end end
if not initFs then if not initFs then
displaySuperBadError("Could not load initdisks.") displaySuperBadError("Could not load initdisks.")
end end
if not fs then if not fs then
displaySuperBadError("Could not load initfs.") displaySuperBadError("Could not load initfs.")
end end
-- Set up event queue -- Set up event queue
local eventQueue = {} local eventQueue = {}
local lkeys={} local lkeys={}
lkeys[apis.keys.enter]="\n" lkeys[apis.keys.enter]="\n"
lkeys[apis.keys.backspace]="\b" lkeys[apis.keys.backspace]="\b"
lkeys[apis.keys.tab]="\t" lkeys[apis.keys.tab]="\t"
-- Function to queue events -- Function to queue events
local function queueEvent(event, ...) local function queueEvent(event, ...)
table.insert(eventQueue, {event, ...}) table.insert(eventQueue, {event, ...})
end end
-- Set up computer api -- Set up computer api
local computer = { local computer = {
time = function() return apis.os.epoch("utc") end, time = function() return apis.os.epoch("utc") end,
clock = function() return apis.os.clock()/1000 end, clock = function() return apis.os.clock()/1000 end,
shutdown = apis.os.shutdown, shutdown = apis.os.shutdown,
reboot = apis.os.reboot, reboot = apis.os.reboot,
getMachineEvent = function() getMachineEvent = function()
if #eventQueue > 0 then if #eventQueue > 0 then
return table.unpack(table.remove(eventQueue, 1)) return table.unpack(table.remove(eventQueue, 1))
else else
return nil return nil
end end
end, end,
getEEPROM = function() getEEPROM = function()
return getFile("/startup.lua") return getFile("/startup.lua")
end, end,
setEEPROM = function(_,text) setEEPROM = function(_,text)
local h = apis.fs.open("/startup.lua", "w") local h = apis.fs.open("/startup.lua", "w")
h.write(text) h.write(text)
h.close() h.close()
end end
} }
-- Set up terminal colors -- Set up terminal colors
local icolors={ local icolors={
[0x1] =0, -- #000000 [0x1] =0, -- #000000
[0x2] =1, -- #FFFFFF [0x2] =1, -- #FFFFFF
[0x4] =2, -- #FF0000 [0x4] =2, -- #FF0000
[0x8] =3, -- #00FF00 [0x8] =3, -- #00FF00
[0x10] =4, -- #0000FF [0x10] =4, -- #0000FF
[0x20] =5, -- #00FFFF [0x20] =5, -- #00FFFF
[0x40] =6, -- #FF00FF [0x40] =6, -- #FF00FF
[0x80] =7, -- #FFFF00 [0x80] =7, -- #FFFF00
[0x100] =8, -- #FF6D00 [0x100] =8, -- #FF6D00
[0x200] =9, -- #6DFF55 [0x200] =9, -- #6DFF55
[0x400] =10, -- #24FFFF [0x400] =10, -- #24FFFF
[0x800] =11, -- #924900 [0x800] =11, -- #924900
[0x1000] =12, -- #6D6D55 [0x1000] =12, -- #6D6D55
[0x2000] =13, -- #DBDBAA [0x2000] =13, -- #DBDBAA
[0x4000] =14, -- #6D00FF [0x4000] =14, -- #6D00FF
[0x8000] =15 -- #B6FF00 [0x8000] =15 -- #B6FF00
} }
local colors={ local colors={
[0]=0x0001, -- #000000 [0]=0x0001, -- #000000
0x0002, -- #FFFFFF 0x0002, -- #FFFFFF
0x0004, -- #FF0000 0x0004, -- #FF0000
0x0008, -- #00FF00 0x0008, -- #00FF00
0x0010, -- #0000FF 0x0010, -- #0000FF
0x0020, -- #00FFFF 0x0020, -- #00FFFF
0x0040, -- #FF00FF 0x0040, -- #FF00FF
0x0080, -- #FFFF00 0x0080, -- #FFFF00
0x0100, -- #FF6D00 0x0100, -- #FF6D00
0x0200, -- #6DFF55 0x0200, -- #6DFF55
0x0400, -- #24FFFF 0x0400, -- #24FFFF
0x0800, -- #924900 0x0800, -- #924900
0x1000, -- #6D6D55 0x1000, -- #6D6D55
0x2000, -- #DBDBAA 0x2000, -- #DBDBAA
0x4000, -- #6D00FF 0x4000, -- #6D00FF
0x8000 -- #B6FF00 0x8000 -- #B6FF00
} }
apis.term.setBackgroundColor(0x1) apis.term.setBackgroundColor(0x1)
apis.term.setTextColor(0x1000) apis.term.setTextColor(0x1000)
apis.term.clear() apis.term.clear()
apis.term.setCursorPos(1, 1) apis.term.setCursorPos(1, 1)
-- Make the kernel coroutine so we can hook its execution -- Make the kernel coroutine so we can hook its execution
local kernelCoro = coroutine.create(function() local kernelCoro = coroutine.create(function()
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init", { local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init", {
print=function(_,text) write(text.."\n") end, print=function(_,text) write(text.."\n") end,
printInline=function(_,text) write(text) end, printInline=function(_,text) write(text) end,
clear=function() apis.term.clear() apis.term.setCursorPos(1,1) end, clear=function() apis.term.clear() apis.term.setCursorPos(1,1) end,
setCursorPos=function(_,x,y) apis.term.setCursorPos(x,y) end, setCursorPos=function(_,x,y) apis.term.setCursorPos(x,y) end,
getCursorPos=function() return apis.term.getCursorPos() end, getCursorPos=function() return apis.term.getCursorPos() end,
getSize=function() return apis.term.getSize() end, getSize=function() return apis.term.getSize() end,
setBackgroundColor=function(_,color) apis.term.setBackgroundColor(colors[color]) end, setBackgroundColor=function(_,color) apis.term.setBackgroundColor(colors[color]) end,
setTextColor=function(_,color) apis.term.setTextColor(colors[color]) end, setTextColor=function(_,color) apis.term.setTextColor(colors[color]) end,
getBackgroundColor=function() return icolors[apis.term.getBackgroundColor()] end, getBackgroundColor=function() return icolors[apis.term.getBackgroundColor()] end,
getTextColor=function() return icolors[apis.term.getTextColor()] end getTextColor=function() return icolors[apis.term.getTextColor()] end
}, computer, fs, "$") }, computer, fs, "$")
if not ok then if not ok then
displaySuperBadError(err) displaySuperBadError(err)
end end
end) end)
-- Diffine a coroutine.resumeWithTimeout function to avoid hanging the system, time is in milliseconds -- Diffine a coroutine.resumeWithTimeout function to avoid hanging the system, time is in milliseconds
function coroutine.resumeWithTimeout(co, timeout, ...) function coroutine.resumeWithTimeout(co, timeout, ...)
local startTime = computer.time() local startTime = computer.time()
debug.sethook(co, function() debug.sethook(co, function()
if computer.time() > startTime + timeout then if computer.time() > startTime + timeout then
return coroutine.yield("timeout") return coroutine.yield("timeout")
end end
end, "", 1000) end, "", 1000)
local ret = {coroutine.resume(co, ...)} local ret = {coroutine.resume(co, ...)}
if ret[1] and ret[2]=="timeout" then if ret[1] and ret[2]=="timeout" then
return "timeout" return "timeout"
elseif ret[1]==false then elseif ret[1]==false then
return "error", ret[2] return "error", ret[2]
else else
debug.sethook(co) debug.sethook(co)
return "success", table.unpack(ret, 2) return "success", table.unpack(ret, 2)
end end
end end
write("Loaded in "..tostring(apis.os.clock()).." seconds.\n") write("Loaded in "..tostring(apis.os.clock()).." seconds.\n")
-- Main loop to run the kernel coroutine -- Main loop to run the kernel coroutine
while true do while true do
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50) local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
apis.os.queueEvent("NoSleep") apis.os.queueEvent("NoSleep")
local exit = false local exit = false
while not exit do while not exit do
local event = {coroutine.yield()} local event = {coroutine.yield()}
if event[1] == "char" then if event[1] == "char" then
queueEvent("keyTyped", 1, event[2]) queueEvent("keyTyped", 1, event[2])
elseif event[1] == "key" then elseif event[1] == "key" then
queueEvent("keyPressed", 1, event[2]) queueEvent("keyPressed", 1, event[2])
if lkeys[event[2]] then if lkeys[event[2]] then
queueEvent("keyTyped", 1, lkeys[event[2]]) queueEvent("keyTyped", 1, lkeys[event[2]])
end end
elseif event[1] == "key_up" then elseif event[1] == "key_up" then
queueEvent("keyReleased", 1, event[2]) queueEvent("keyReleased", 1, event[2])
elseif event[1] == "disk" then elseif event[1] == "disk" then
queueEvent("componentAdded", "disk") queueEvent("componentAdded", "disk")
elseif event[1] == "disk_eject" then elseif event[1] == "disk_eject" then
queueEvent("componentRemoved", "disk") queueEvent("componentRemoved", "disk")
elseif event[1] == "NoSleep" then elseif event[1] == "NoSleep" then
exit=true exit=true
end end
end end
if status == "error" or coroutine.status(kernelCoro)=="dead" then if status == "error" or coroutine.status(kernelCoro)=="dead" then
displaySuperBadError("Kernel error: "..tostring(err)) displaySuperBadError("Kernel error: "..tostring(err))
coroutine.yield("key") coroutine.yield("key")
end end
end end
end, debug.traceback) end, debug.traceback)
if not ok then if not ok then
displaySuperBadError("Fatal error during boot: "..err) displaySuperBadError("Fatal error during boot: "..err)
end end
while true do coroutine.yield() end while true do coroutine.yield() end
@@ -1,121 +1,121 @@
sleep(1) sleep(1)
local BOOT_DRIVE_PATH="/$" local BOOT_DRIVE_PATH="/$"
-- UnBIOS by JackMacWindows -- 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 -- 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 -- 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: -- Here's a list of things that are irreversibly changed:
-- * both `bit` and `bit32` are kept for compatibility -- * both `bit` and `bit32` are kept for compatibility
-- * string metatable blocking (on old versions of CC) -- * string metatable blocking (on old versions of CC)
-- In addition, if `debug` is not available these things are also irreversibly changed: -- In addition, if `debug` is not available these things are also irreversibly changed:
-- * old Lua 5.1 `load` function (for loading from a function) -- * old Lua 5.1 `load` function (for loading from a function)
-- * `loadstring` prefixing (before CC:T 1.96.0) -- * `loadstring` prefixing (before CC:T 1.96.0)
-- * `http.request` -- * `http.request`
-- * `os.shutdown` and `os.reboot` -- * `os.shutdown` and `os.reboot`
-- * `peripheral` -- * `peripheral`
-- * `turtle.equip[Left|Right]` -- * `turtle.equip[Left|Right]`
-- Licensed under the MIT license -- Licensed under the MIT license
local args = {...} local args = {...}
if _HOST:find("UnBIOS") then return end 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 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 = {} local t = {}
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end 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 for _,k in ipairs(t) do _G[k] = nil end
local native = _G.term.native() local native = _G.term.native()
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
_G.term = native _G.term = native
if _G.http then if _G.http then
_G.http.checkURL = _G.http.checkURLAsync _G.http.checkURL = _G.http.checkURLAsync
_G.http.websocket = _G.http.websocketAsync _G.http.websocket = _G.http.websocketAsync
end end
if _G.commands then _G.commands = _G.commands.native end if _G.commands then _G.commands = _G.commands.native end
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil 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"}} 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 for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
_G._HOST = _G._HOST .. " (UnBIOS)" _G._HOST = _G._HOST .. " (UnBIOS)"
-- Set up TLCO -- Set up TLCO
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally -- 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 -- 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 -- empty placeholder to let it continue and return without throwing. This results
-- in the `pcall` returning successfully, preventing the error-displaying code -- in the `pcall` returning successfully, preventing the error-displaying code
-- from running - essentially making it so that `os.shutdown` is called immediately -- from running - essentially making it so that `os.shutdown` is called immediately
-- after the new BIOS exits. -- after the new BIOS exits.
-- --
-- From there, the setup code is placed in `term.native` since it's the first -- 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 -- 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 -- 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. -- allow it to be the last function called in the original BIOS, and returns.
-- From there execution continues, calling the `term.redirect` dummy, skipping -- From there execution continues, calling the `term.redirect` dummy, skipping
-- over the error-handling code (since `pcall` returned ok), and calling -- 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 -- `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. -- called, which effectively makes it run as the main chunk.
local olderror = error local olderror = error
_G.error = function() end _G.error = function() end
_G.term.redirect = function() end _G.term.redirect = function() end
function _G.term.native() function _G.term.native()
_G.term.native = nil _G.term.native = nil
_G.term.redirect = nil _G.term.redirect = nil
_G.error = olderror _G.error = olderror
term.setBackgroundColor(32768) term.setBackgroundColor(32768)
term.setTextColor(1) term.setTextColor(1)
term.setCursorPos(1, 1) term.setCursorPos(1, 1)
term.setCursorBlink(true) term.setCursorBlink(true)
term.clear() term.clear()
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r") local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
if file == nil then if file == nil then
term.setCursorBlink(false) term.setCursorBlink(false)
term.setTextColor(16384) term.setTextColor(16384)
term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.") term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2) term.setCursorPos(1, 2)
term.write("Press any key to continue") term.write("Press any key to continue")
coroutine.yield("key") coroutine.yield("key")
os.shutdown() os.shutdown()
end end
local fn, err = loadstring(file.readAll(), "@bootloader") local fn, err = loadstring(file.readAll(), "@bootloader")
file.close() file.close()
if fn == nil then if fn == nil then
term.setCursorBlink(false) term.setCursorBlink(false)
term.setTextColor(16384) term.setTextColor(16384)
term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.") term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")
term.setCursorPos(1, 2) term.setCursorPos(1, 2)
term.write(err) term.write(err)
term.setCursorPos(1, 3) term.setCursorPos(1, 3)
term.write("Press any key to continue") term.write("Press any key to continue")
coroutine.yield("key") coroutine.yield("key")
os.shutdown() os.shutdown()
end end
setfenv(fn, _G) setfenv(fn, _G)
local oldshutdown = os.shutdown local oldshutdown = os.shutdown
os.shutdown = function() os.shutdown = function()
os.shutdown = oldshutdown os.shutdown = oldshutdown
return fn(table.unpack(args)) return fn(table.unpack(args))
end end
end end
if debug then if debug then
-- Restore functions that were overwritten in the BIOS -- Restore functions that were overwritten in the BIOS
-- Apparently this has to be done *after* redefining term.native -- Apparently this has to be done *after* redefining term.native
local function restoreValue(tab, idx, name, hint) local function restoreValue(tab, idx, name, hint)
local i, key, value = 1, debug.getupvalue(tab[idx], hint) local i, key, value = 1, debug.getupvalue(tab[idx], hint)
while key ~= name and key ~= nil do while key ~= name and key ~= nil do
key, value = debug.getupvalue(tab[idx], i) key, value = debug.getupvalue(tab[idx], i)
i=i+1 i=i+1
end end
tab[idx] = value or tab[idx] tab[idx] = value or tab[idx]
end end
restoreValue(_G, "loadstring", "nativeloadstring", 1) restoreValue(_G, "loadstring", "nativeloadstring", 1)
restoreValue(_G, "load", "nativeload", 5) restoreValue(_G, "load", "nativeload", 5)
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
restoreValue(os, "shutdown", "nativeShutdown", 1) restoreValue(os, "shutdown", "nativeShutdown", 1)
restoreValue(os, "reboot", "nativeReboot", 1) restoreValue(os, "reboot", "nativeReboot", 1)
if turtle then if turtle then
restoreValue(turtle, "equipLeft", "v", 1) restoreValue(turtle, "equipLeft", "v", 1)
restoreValue(turtle, "equipRight", "v", 1) restoreValue(turtle, "equipRight", "v", 1)
end end
do do
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2) local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
while key ~= "native" and key ~= nil do while key ~= "native" and key ~= nil do
key, value = debug.getupvalue(peripheral.isPresent, i) key, value = debug.getupvalue(peripheral.isPresent, i)
i=i+1 i=i+1
end end
_G.peripheral = value or peripheral _G.peripheral = value or peripheral
end end
end end
@@ -1,191 +1,191 @@
local apis = ({...})[1] local apis = ({...})[1]
local BOOT_DRIVE_PATH="/$" local BOOT_DRIVE_PATH="/$"
local fs = apis.fs local fs = apis.fs
local native = apis.peripheral local native = apis.peripheral
local peripheral = {} local peripheral = {}
local sides = {"top", "bottom", "left", "right", "front", "back"} local sides = {"top", "bottom", "left", "right", "front", "back"}
function peripheral.getType(name) function peripheral.getType(name)
if native.isPresent(name) then if native.isPresent(name) then
return native.getType(name) return native.getType(name)
end end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name) return native.call(side, "getTypeRemote", name)
end end
end end
return nil return nil
end end
function peripheral.getNames() function peripheral.getNames()
local names = {} local names = {}
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.isPresent(side) then if native.isPresent(side) then
table.insert(names, side) table.insert(names, side)
end end
if native.hasType(side, "peripheral_hub") then if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides") local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do for _, hubSide in ipairs(hubSides) do
table.insert(names, hubSide) table.insert(names, hubSide)
end end
end end
end end
return names return names
end end
--------------------------------------------------------- ---------------------------------------------------------
-- STORAGE -- STORAGE
--------------------------------------------------------- ---------------------------------------------------------
local disks = {} -- real disks local disks = {} -- real disks
local internal = {} -- "$" disk local internal = {} -- "$" disk
--------------------------------------------------------- ---------------------------------------------------------
-- HELPERS -- HELPERS
--------------------------------------------------------- ---------------------------------------------------------
local function norm(path) local function norm(path)
if not path or path == "" then return "/" end if not path or path == "" then return "/" end
return fs.combine("/", path) return fs.combine("/", path)
end end
--- Creates a disk object given a base path --- Creates a disk object given a base path
local function createDisk(id, basePath, readonly, periph) local function createDisk(id, basePath, readonly, periph)
basePath = norm(basePath) basePath = norm(basePath)
local disk = {address=id,isReadOnly=function() return readonly end} local disk = {address=id,isReadOnly=function() return readonly end}
function disk:spaceUsed() function disk:spaceUsed()
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath) return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
end end
function disk:spaceTotal() function disk:spaceTotal()
return fs.getCapacity(basePath) return fs.getCapacity(basePath)
end end
function disk:list(path) function disk:list(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end
return fs.list(p) return fs.list(p)
end end
function disk:fileExists(path) function disk:fileExists(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.exists(p) and not fs.isDir(p) return fs.exists(p) and not fs.isDir(p)
end end
function disk:directoryExists(path) function disk:directoryExists(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.exists(p) and fs.isDir(p) return fs.exists(p) and fs.isDir(p)
end end
function disk:type(path) function disk:type(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
if not fs.exists(p) then if not fs.exists(p) then
return nil return nil
elseif fs.isDir(p) then elseif fs.isDir(p) then
return "directory" return "directory"
else else
return "file" return "file"
end end
end end
function disk:makeDirectory(path) function disk:makeDirectory(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
fs.makeDir(p) fs.makeDir(p)
return true return true
end end
function disk:remove(path) function disk:remove(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
if fs.exists(p) then fs.delete(p) end if fs.exists(p) then fs.delete(p) end
return true return true
end end
function disk:setLabel(label) function disk:setLabel(label)
periph.setLabel(label) periph.setLabel(label)
end end
function disk:getLabel(label) function disk:getLabel(label)
return periph.getLabel() return periph.getLabel()
end end
function disk:attributes(path) function disk:attributes(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.attributes(p) return fs.attributes(p)
end end
function disk:open(path, mode) function disk:open(path, mode)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.open(p, mode) return fs.open(p, mode)
end end
return disk return disk
end end
--------------------------------------------------------- ---------------------------------------------------------
-- INTERNAL DISK "$" (mapped to "/") -- INTERNAL DISK "$" (mapped to "/")
--------------------------------------------------------- ---------------------------------------------------------
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, { internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel=function(label) setLabel=function(label)
local h = fs.open("/.label", "w") local h = fs.open("/.label", "w")
h.write(label) h.write(label)
h.close() h.close()
end, end,
getLabel=function() getLabel=function()
local h = fs.open("/.label", "r") local h = fs.open("/.label", "r")
local label = h.readAll() local label = h.readAll()
h.close() h.close()
return label return label
end end
}) })
--------------------------------------------------------- ---------------------------------------------------------
-- SCAN REAL DISK PERIPHERALS -- SCAN REAL DISK PERIPHERALS
--------------------------------------------------------- ---------------------------------------------------------
local function refresh() local function refresh()
-- remove disks that no longer exist -- remove disks that no longer exist
for id, _ in pairs(disks) do for id, _ in pairs(disks) do
if not peripheral.getType(id) then if not peripheral.getType(id) then
disks[id] = nil disks[id] = nil
end end
end end
-- detect new disks -- detect new disks
for _, name in ipairs(peripheral.getNames()) do for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == "disk" then if peripheral.getType(name) == "disk" then
if not disks[name] then if not disks[name] then
local mount = disk.getMountPath(name) local mount = disk.getMountPath(name)
if mount then if mount then
disks[name] = createDisk(name, mount, false, disk) disks[name] = createDisk(name, mount, false, disk)
end end
end end
end end
end end
end end
--------------------------------------------------------- ---------------------------------------------------------
-- ITERATOR -- ITERATOR
--------------------------------------------------------- ---------------------------------------------------------
local function iter() local function iter()
refresh() refresh()
-- first internal -- first internal
local combined = {} local combined = {}
for id, obj in pairs(internal) do for id, obj in pairs(internal) do
combined[id] = obj combined[id] = obj
end end
for id, obj in pairs(disks) do for id, obj in pairs(disks) do
combined[id] = obj combined[id] = obj
end end
return pairs(combined) return pairs(combined)
end end
--------------------------------------------------------- ---------------------------------------------------------
-- MODULE RETURN -- MODULE RETURN
--------------------------------------------------------- ---------------------------------------------------------
return { return {
refresh = refresh, refresh = refresh,
list = iter list = iter
} }
@@ -1,11 +1,11 @@
{ {
"Name": "Hyperion OC Firmware", "Name": "Hyperion OC Firmware",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "The OpenComputers firmware package for HyperionOS.", "Description": "The OpenComputers firmware package for HyperionOS.",
"Dependencies": [ "Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.pkg" "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", "Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-firmware-oc-v1.0.0.tar",
"BuildCommand": "cp boot/oc/eeprom /dev/eeprom" "BuildCommand": "cp boot/oc/eeprom /dev/eeprom"
} }
@@ -1,40 +1,40 @@
local lua = { local lua = {
coroutine = true, coroutine = true,
debug = true, debug = true,
_HOST = true, _HOST = true,
_VERSION = true, _VERSION = true,
assert = true, assert = true,
collectgarbage = true, collectgarbage = true,
error = true, error = true,
gcinfo = true, gcinfo = true,
getfenv = true, getfenv = true,
getmetatable = true, getmetatable = true,
ipairs = true, ipairs = true,
__inext = true, __inext = true,
load = true, load = true,
math = true, math = true,
next = true, next = true,
pairs = true, pairs = true,
pcall = true, pcall = true,
rawequal = true, rawequal = true,
rawget = true, rawget = true,
rawlen = true, rawlen = true,
rawset = true, rawset = true,
select = true, select = true,
setfenv = true, setfenv = true,
setmetatable = true, setmetatable = true,
string = true, string = true,
table = true, table = true,
tonumber = true, tonumber = true,
tostring = true, tostring = true,
type = true, type = true,
xpcall = true, xpcall = true,
_G=true _G=true
} }
for i,v in pairs(_G) do for i,v in pairs(_G) do
if not lua[i] or lua[i]==nil then if not lua[i] or lua[i]==nil then
apis[i]=v apis[i]=v
_G[i]=nil _G[i]=nil
end end
end end
@@ -1,18 +1,18 @@
checkArg=nil checkArg=nil
local oldcomputer=computer local oldcomputer=computer
_G.computer=nil _G.computer=nil
local os=os local os=os
_G.os=nil _G.os=nil
function component.wrap(address) function component.wrap(address)
local methods=oldcomponent.methods(address) local methods=oldcomponent.methods(address)
local object={} local object={}
for _,method in ipairs(methods) do for _,method in ipairs(methods) do
object[method]=function(_,...) object[method]=function(_,...)
return oldcomponent.invoke(address,method,...) return oldcomponent.invoke(address,method,...)
end end
end end
return object return object
end end
local local
@@ -1,8 +1,8 @@
{ {
"Name": "Hyperion Kernel", "Name": "Hyperion Kernel",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "The kernel package for HyperionOS.", "Description": "The kernel package for HyperionOS.",
"Dependencies": [], "Dependencies": [],
"Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.tar" "Tar": "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-kernel-v1.0.0.tar"
} }
@@ -1,77 +1,78 @@
local fs = {} --:Minify:--
local disks = {} local fs = {}
local mounts = {} local disks = {}
local mounts = {}
local function resolve(path)
local mountPoint = "/" local function resolve(path)
for mount, disk in pairs(mounts) do local mountPoint = "/"
if path:sub(1, #mount) == mount then for mount, disk in pairs(mounts) do
if not mountPoint or #mount > #mountPoint then if path:sub(1, #mount) == mount then
mountPoint = mount if not mountPoint or #mount > #mountPoint then
end mountPoint = mount
end end
end end
local newPath = path:sub(#mountPoint + 1) end
return disks[mounts[mountPoint]], newPath local newPath = path:sub(#mountPoint + 1)
end return disks[mounts[mountPoint]], newPath
--------------------------------------------------------- end
---------------------------------------------------------
function fs.update(initdisks)
disks = {} function fs.update(initdisks)
for k, v in initdisks.list() do disks = {}
disks[k] = v for k, v in initdisks.list() do
end disks[k] = v
end end
end
function fs.exists(path)
local disk, newPath = resolve(path) function fs.exists(path)
return disk:directoryExists(newPath) or disk:fileExists(newPath) local disk, newPath = resolve(path)
end return disk:directoryExists(newPath) or disk:fileExists(newPath)
function fs.isFile(path) end
local disk, newPath = resolve(path) function fs.isFile(path)
return disk:fileExists(newPath) local disk, newPath = resolve(path)
end return disk:fileExists(newPath)
function fs.isDir(path) end
local disk, newPath = resolve(path) function fs.isDir(path)
return disk:directoryExists(newPath) local disk, newPath = resolve(path)
end return disk:directoryExists(newPath)
function fs.list(path) end
local disk, newPath = resolve(path) function fs.list(path)
return disk:list(newPath) local disk, newPath = resolve(path)
end return disk:list(newPath)
function fs.makeDir(path) end
local disk, newPath = resolve(path) function fs.makeDir(path)
return disk:makeDirectory(newPath) local disk, newPath = resolve(path)
end return disk:makeDirectory(newPath)
function fs.remove(path) end
local disk, newPath = resolve(path) function fs.remove(path)
return disk:remove(newPath) local disk, newPath = resolve(path)
end return disk:remove(newPath)
function fs.readAllText(path) end
local disk, newPath = resolve(path) function fs.readAllText(path)
local handle = disk:open(newPath, "r") local disk, newPath = resolve(path)
if not handle then return nil end local handle = disk:open(newPath, "r")
local content = handle.readAll() if not handle then return nil end
handle.close() local content = handle.readAll()
return content handle.close()
end return content
function fs.writeAllText(path, text) end
local disk, newPath = resolve(path) function fs.writeAllText(path, text)
local handle = disk:open(newPath, "w") local disk, newPath = resolve(path)
handle.write(text) local handle = disk:open(newPath, "w")
handle.close() handle.write(text)
end handle.close()
function fs.appendAllText(path, text) end
local disk, newPath = resolve(path) function fs.appendAllText(path, text)
local handle = disk:open(newPath, "a") local disk, newPath = resolve(path)
handle.write(text) local handle = disk:open(newPath, "a")
handle.close() handle.write(text)
end handle.close()
function fs.load(path) end
return load(fs.readAllText(path), path) function fs.load(path)
end return load(fs.readAllText(path), path)
function fs.mount(disk, mountPoint) end
if not disks[disk] then return end function fs.mount(disk, mountPoint)
mounts[mountPoint] = disk if not disks[disk] then return end
end mounts[mountPoint] = disk
end
return fs return fs
@@ -1,250 +1,243 @@
local args = {...} --:Minify:--
local apis = args[1] local args = {...}
local disks = args[2] local apis = args[1]
local arch = args[3] local disks = args[2]
local screen = args[5] local arch = args[3]
local computer = args[6] local screen = args[5]
local ifs = args[7] local computer = args[6]
local LOG_Text = "" local ifs = args[7]
local kernel = {} local LOG_Text = ""
kernel.process = "Kernel" local kernel = {}
kernel.user = "root" kernel.process = "Kernel"
kernel.group = "root" kernel.user = "root"
kernel.groups = {0} kernel.group = "root"
kernel.uid = 0 kernel.groups = {0}
kernel.gid = 0 kernel.uid = 0
kernel.status = "start" kernel.gid = 0
kernel.key = {} kernel.status = "start"
kernel.cache = {} kernel.key = {}
kernel.cache.preload = {} kernel.cache = {}
kernel._G=_G kernel.cache.preload = {}
kernel.sleep=sleep kernel._G=_G
kernel.debug=true kernel.sleep=sleep
kernel.debug=true
_G.sleep=nil
local windowsExp = false _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" function kernel.log(msg, level)
if kernel.status == "start" then LOG_Text = LOG_Text..tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg) if kernel.status == "start" then
elseif kernel.status == "init" then screen:print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
kernel.standbyTask=kernel.currentTask elseif kernel.status == "init" then
kernel.currentTask=kernel.kernelTask kernel.standbyTask=kernel.currentTask
kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg) kernel.currentTask=kernel.kernelTask
kernel.currentTask=kernel.standbyTask kernel.tty.print(tostring(computer:time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
end kernel.currentTask=kernel.standbyTask
end end
end
function kernel.PANIC(msg)
if kernel.status~="Panic" then function kernel.PANIC(msg)
kernel.log("PANIC: "..msg, "PANIC") if kernel.status~="Panic" then
pcall(kernel["saveLog"]) kernel.log("PANIC: "..msg, "PANIC")
kernel.status="Panic" pcall(kernel["saveLog"])
kernel.reason=msg kernel.status="Panic"
screen:setTextColor(2) kernel.reason=msg
screen:setBackgroundColor(0) screen:setTextColor(2)
screen:clear() screen:setBackgroundColor(0)
screen:setCursorPos(1,1) screen:clear()
screen:print(LOG_Text) screen:setCursorPos(1,1)
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.") screen:print(LOG_Text)
screen:print("Press any key to continue...") screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
end screen:print("Press any key to continue...")
while true do end
local event={computer:getMachineEvent()} while true do
if event[1]=="keyPressed" then local event={computer:getMachineEvent()}
break if event[1]=="keyPressed" then
end break
end end
computer:reboot() end
end computer:reboot()
kernel.panic=kernel.PANIC end
kernel.panic=kernel.PANIC
if windowsExp then
screen:setTextColor(1) if windowsExp then
screen:setBackgroundColor(4) screen:setTextColor(1)
screen:clear() screen:setBackgroundColor(4)
local w,h = screen:getSize() screen:clear()
screen:setCursorPos(3,5) local w,h = screen:getSize()
screen:print(":(") screen:setCursorPos(3,5)
screen:setCursorPos(3,7) screen:print(":(")
screen:print("Your PC ran into a problem and needs to restart. We're just collecting some error") screen:setCursorPos(3,7)
screen:setCursorPos(3,8) screen:print("Your PC ran into a problem and needs to restart. We're just collecting some error")
screen:print("info, and then we'll restart for you.\n") screen:setCursorPos(3,8)
screen:setCursorPos(3,h-5) screen:print("info, and then we'll restart for you.\n")
screen:print("Stop code: average windows experience") screen:setCursorPos(3,h-5)
screen:setCursorPos(1,h) screen:print("Stop code: average windows experience")
screen:print("Press any key to continue... jk reboot it yourself lazy") screen:setCursorPos(1,h)
while true do end screen:print("Press any key to continue... jk reboot it yourself lazy")
end while true do end
end
kernel.log("Kernel loaded.")
kernel.log("Mounting init disks...") kernel.log("Kernel loaded.")
disks.refresh() kernel.log("Mounting init disks...")
ifs.update(disks) disks.refresh()
kernel.disks={} ifs.update(disks)
for _,v in disks.list() do kernel.disks={}
kernel.disks[v.address] = v for _,v in disks.list() do
end kernel.disks[v.address] = v
ifs.mount("$", "/") end
ifs.mount("$", "/")
local fstab=ifs.readAllText("/boot/fstab")
local split = function(str, delim, maxResultCountOrNil) local fstab=ifs.readAllText("/boot/fstab")
assert(#delim == 1, "only delim len 1 supported for now") local split = function(str, delim, maxResultCountOrNil)
maxResultCountOrNil = (maxResultCountOrNil or 0)-1 assert(#delim == 1, "only delim len 1 supported for now")
local rv = {} maxResultCountOrNil = (maxResultCountOrNil or 0)-1
local buf = "" local rv = {}
for i = 1, #str do local buf = ""
local c = string.sub(str,i,i) for i = 1, #str do
if #rv ~= maxResultCountOrNil and c == delim then local c = string.sub(str,i,i)
table.insert(rv, buf) if #rv ~= maxResultCountOrNil and c == delim then
buf = "" table.insert(rv, buf)
else buf = ""
buf = buf..c else
end buf = buf..c
end end
table.insert(rv, buf) end
return rv table.insert(rv, buf)
end 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") if not ifs.isFile("/boot/boot.cfg") then
ifs.writeAllText("/boot/boot.cfg",[[ kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR")
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING! ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE! end
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
-- This file is auto-generated during the build process. if not initCfgFunc then
-- RECOVERY BOOT CONFIGURATION FILE kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err))
return { end
initPath = "/sbin/init.lua",
maxOpenFiles = 128, local initCfgStatus, config = pcall(initCfgFunc)
maxFilesPerTask = 16, if not initCfgStatus then
preempt=true kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config))
} end
]]) kernel.config = config
end
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg") for i,v in ipairs(split(fstab,"\n")) do
if not initCfgFunc then if v:sub(1,1)=="U" then
kernel.PANIC("Failed to load /boot/boot.cfg: "..tostring(err)) local id=""
end for i=3,#v do
if v:sub(i,i)==";" then
local initCfgStatus, config = pcall(initCfgFunc) if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
if not initCfgStatus then id=v:sub(3,i-1)
kernel.PANIC("Error in /boot/boot.cfg: "..tostring(config)) end
end end
kernel.config = config local path=v:sub(#id+4)
ifs.mount(id,path)
for i,v in ipairs(split(fstab,"\n")) do ::endline::
if v:sub(1,1)=="U" then end
local id="" end
for i=3,#v do kernel.log("Disks initialized")
if v:sub(i,i)==";" then
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end function kernel.saveLog()
id=v:sub(3,i-1) ifs.writeAllText("/var/log/syslog.log", LOG_Text)
end end
end
local path=v:sub(#id+4) ifs.remove("/tmp")
ifs.mount(id,path) ifs.makeDir("/tmp")
::endline::
end function kernel.newFifo()
end local fifo = {}
kernel.log("Disks initialized") fifo.push=function(data)
table.insert(data)
function kernel.saveLog() end
ifs.writeAllText("/var/log/syslog.log", LOG_Text) fifo.pop=function()
end return table.remove(fifo,1)
end
ifs.remove("/tmp") return fifo
ifs.makeDir("/tmp") end
function kernel.newFifo() function kernel.newUUID()
local fifo = {} local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx"
fifo.push=function(data) local uuid = ""
table.insert(data) for i = 1, #template do
end local c = template:sub(i,i)
fifo.pop=function() if c == "x" then
return table.remove(fifo,1) uuid = uuid .. string.format("%x", math.random(0, 15))
end elseif c == "y" then
return fifo uuid = uuid .. string.format("%x", math.random(8, 11))
end else
uuid = uuid .. c
function kernel.newUUID() end
local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" end
local uuid = "" return uuid
for i = 1, #template do end
local c = template:sub(i,i)
if c == "x" then kernel.syscalls={}
uuid = uuid .. string.format("%x", math.random(0, 15)) local modules={[0]={}}
elseif c == "y" then for i=0, 100 do
uuid = uuid .. string.format("%x", math.random(8, 11)) modules[i]={}
else end
uuid = uuid .. c
end kernel.log("Gathering modules")
end for _, i in ipairs(ifs.list("/lib/modules")) do
return uuid for _,v in ipairs(ifs.list("/lib/modules/"..i)) do
end local prior=tonumber(v:sub(1,2))
modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v
kernel.syscalls={} end
local modules={[0]={}} end
for i=0, 100 do
modules[i]={} kernel.ifs=ifs
end kernel.apis=apis
kernel.computer=computer
kernel.log("Gathering modules") kernel.arch=arch
for _, i in ipairs(ifs.list("/lib/modules")) do kernel.initdisks=disks
for _,v in ipairs(ifs.list("/lib/modules/"..i)) do kernel.screen=screen
local prior=tonumber(v:sub(1,2)) kernel.processes={}
modules[prior+1][#modules[prior+1]+1]="/lib/modules/"..i.."/"..v kernel.fstab=fstab
end
end kernel.kernelTask = {
name="kernel",
kernel.ifs=ifs status="R",
kernel.apis=apis pid=0,
kernel.computer=computer tgid=0,
kernel.arch=arch user="root",
kernel.initdisks=disks uid=0,
kernel.screen=screen fd={},
kernel.processes={} exit="",
kernel.fstab=fstab sleep=0,
ivs=0,
kernel.kernelTask = { vs=0,
name="kernel", children={},
status="R", syscallReturn={},
pid=0, cwd="/",
tgid=0, timeSlice=0,
user="root", lastTime=0,
uid=0, totalTime=0,
fd={}, numRuns=0
exit="", }
sleep=0, kernel.currentTask = kernel.kernelTask
ivs=0,
vs=0, kernel.syscalls["OS_time"]=function() return kernel.computer:time() end
children={}, kernel.syscalls["OS_log"]=kernel.log
syscallReturn={},
cwd="/", kernel.log("Running modules")
timeSlice=0, for _,p in ipairs(modules) do
lastTime=0, for _,v in ipairs(p) do
totalTime=0, local code=ifs.readAllText(v)
numRuns=0 if not code then
} kernel.log("ModuReadErr: "..v, "WARN")
kernel.currentTask = kernel.kernelTask goto skip
end
kernel.log("Running modules") local func,err=load(code,"@"..v)
for _,p in ipairs(modules) do if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
for _,v in ipairs(p) do local status, err = xpcall(func,debug.traceback, kernel)
local code=ifs.readAllText(v) if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
if not code then ::skip::
kernel.log("ModuReadErr: "..v, "WARN") end
goto skip end
end
local func,err=load(code,"@"..v) kernel.log("Kernel initialized successfully.")
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end kernel.status="running"
local status, err = xpcall(func,debug.traceback, kernel) kernel.main()
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
::skip::
end
end
kernel.log("Kernel initialized successfully.")
kernel.main()
kernel.PANIC("Execution complete") kernel.PANIC("Execution complete")
@@ -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
}
@@ -1,284 +1,285 @@
function string.hasSuffix(str, suffix) --:Minify:--
return string.sub(str, #suffix+1) == suffix function string.hasSuffix(str, suffix)
end return string.sub(str, #suffix+1) == suffix
end
function string.hasPrefix(str, prefix)
return string.sub(str, 1, #prefix) == prefix function string.hasPrefix(str, prefix)
end return string.sub(str, 1, #prefix) == prefix
end
function string.getSuffix(str, prefix)
return string.sub(str, #prefix+1) function string.getSuffix(str, prefix)
end return string.sub(str, #prefix+1)
end
function string.getPrefix(str, suffix)
return string.sub(str, 1, #suffix) function string.getPrefix(str, suffix)
end return string.sub(str, 1, #suffix)
end
function string.join(str, ...)
return table.concat(table.pack(str, ...)) function string.join(str, ...)
end return table.concat(table.pack(str, ...))
end
function string.delim(str, ...)
return table.concat(table.pack(...), str) function string.delim(str, ...)
end return table.concat(table.pack(...), str)
end
function string.split(str, delim, maxResultCountOrNil)
assert(#delim == 1, "only delim len 1 supported for now") function string.split(str, delim, maxResultCountOrNil)
maxResultCountOrNil = (maxResultCountOrNil or 0)-1 assert(#delim == 1, "only delim len 1 supported for now")
local rv = {} maxResultCountOrNil = (maxResultCountOrNil or 0)-1
local buf = "" local rv = {}
for i = 1, #str do local buf = ""
local c = string.sub(str,i,i) for i = 1, #str do
if #rv ~= maxResultCountOrNil and c == delim then local c = string.sub(str,i,i)
table.insert(rv, buf) if #rv ~= maxResultCountOrNil and c == delim then
buf = "" table.insert(rv, buf)
else buf = ""
buf = buf..c else
end buf = buf..c
end end
table.insert(rv, buf) end
return rv table.insert(rv, buf)
end return rv
end
function string.replace(str, search, replacement)
local rv = "" function string.replace(str, search, replacement)
local consumedLen = 1 local rv = ""
local i = 1 local consumedLen = 1
while i<#str do local i = 1
if string.sub(str, i, i+#search-1) == search then while i<#str do
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement if string.sub(str, i, i+#search-1) == search then
i=i+#search rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
consumedLen = i i=i+#search
end consumedLen = i
i=i+1 end
end i=i+1
return rv .. string.sub(str, consumedLen) end
end return rv .. string.sub(str, consumedLen)
end
function table.deepcopy(orig, copies)
copies = copies or {} function table.deepcopy(orig, copies)
copies = copies or {}
if type(orig) ~= 'table' then
return orig if type(orig) ~= 'table' then
elseif copies[orig] then return orig
return copies[orig] elseif copies[orig] then
end return copies[orig]
end
local copy = {}
copies[orig] = copy local copy = {}
copies[orig] = copy
for k, v in next, orig, nil do
local copied_key = table.deepcopy(k, copies) for k, v in next, orig, nil do
local copied_val = table.deepcopy(v, copies) local copied_key = table.deepcopy(k, copies)
copy[copied_key] = copied_val local copied_val = table.deepcopy(v, copies)
end copy[copied_key] = copied_val
end
return copy
end return copy
end
function table.hasKey(tabl, query)
for i,v in pairs(tabl) do function table.hasKey(tabl, query)
if i==query then for i,v in pairs(tabl) do
return true if i==query then
end return true
end end
return false end
end return false
end
function table.hasVal(tabl, query)
for i,v in pairs(tabl) do function table.hasVal(tabl, query)
if v==query then for i,v in pairs(tabl) do
return true if v==query then
end return true
end end
return false end
end return false
end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles 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 local function createProxy(t)
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles) 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 proxy = {}
proxies[t] = proxy
local mt
mt = { local mt
__index = function(_, k) mt = {
local value = t[k] __index = function(_, k)
if type(value) == "table" then local value = t[k]
return createProxy(value) -- recursively proxy subtables if type(value) == "table" then
else return createProxy(value) -- recursively proxy subtables
return value else
end return value
end, end
__newindex = function() end,
error("Attempt to modify table proxy", 2) __newindex = function()
end, error("Attempt to modify table proxy", 2)
__pairs = function() end,
return function(_, k) __pairs = function()
local nextKey, nextValue = next(t, k) return function(_, k)
if type(nextValue) == "table" then local nextKey, nextValue = next(t, k)
nextValue = createProxy(nextValue) if type(nextValue) == "table" then
end nextValue = createProxy(nextValue)
return nextKey, nextValue end
end, nil, nil return nextKey, nextValue
end, end, nil, nil
__ipairs = function() end,
local i = 0 __ipairs = function()
local n = #t local i = 0
return function() local n = #t
i = i + 1 return function()
if i <= n then i = i + 1
local v = t[i] if i <= n then
if type(v) == "table" then local v = t[i]
v = createProxy(v) if type(v) == "table" then
end v = createProxy(v)
return i, v end
end return i, v
end end
end, end
__metatable = false end,
} __metatable = false
}
setmetatable(proxy, mt)
return proxy setmetatable(proxy, mt)
end return proxy
end
return createProxy(tbl)
end return createProxy(tbl)
end
local function serialize(table)
local output = "{" local function serialize(table)
for i,v in pairs(table) do local output = "{"
local coma=true for i,v in pairs(table) do
if type(i) == "string" then local coma=true
output=output.."[\""..i.."\"]=" if type(i) == "string" then
elseif type(i) == "number" then output=output.."[\""..i.."\"]="
output=output.."["..tostring(i).."]=" elseif type(i) == "number" then
end output=output.."["..tostring(i).."]="
if type(v) == "table" then end
if v == table then if type(v) == "table" then
output=string.sub(output,1,#output-(#i+1)) if v == table then
coma=false output=string.sub(output,1,#output-(#i+1))
else coma=false
output=output..serialize(v) else
end output=output..serialize(v)
elseif type(v) == "string" then end
output=output.."[=["..v.."]=]" elseif type(v) == "string" then
elseif type(v) == "number" then output=output.."[=["..v.."]=]"
output=output..tostring(v) elseif type(v) == "number" then
elseif type(v) == "boolean" then output=output..tostring(v)
if v == true then elseif type(v) == "boolean" then
output=output.."true" if v == true then
else output=output.."true"
output=output.."false" else
end output=output.."false"
elseif type(v) == "function" then end
output=output..tostring(v) elseif type(v) == "function" then
else output=output..tostring(v)
error("serialization of type \""..type(v).."\" is not supported") else
end error("serialization of type \""..type(v).."\" is not supported")
if coma then end
output=output.."," if coma then
end output=output..","
end end
if #table>0 or string.sub(output,#output,#output) == "," then end
output=string.sub(output,1,#output-1) if #table>0 or string.sub(output,#output,#output) == "," then
end output=string.sub(output,1,#output-1)
output=output.."}" end
return output output=output.."}"
end return output
end
local oldtype=type
local oldgetmetatable=getmetatable local oldtype=type
function type(object, trueType) local oldgetmetatable=getmetatable
if trueType then function type(object, trueType)
return oldtype(object) if trueType then
end return oldtype(object)
if oldtype(object)~="table" then end
return oldtype(object) if oldtype(object)~="table" then
else return oldtype(object)
if oldtype(oldgetmetatable(object))=="table" then else
local metatable = oldgetmetatable(object) if oldtype(oldgetmetatable(object))=="table" then
if metatable.__type then return metatable.__type end local metatable = oldgetmetatable(object)
else if metatable.__type then return metatable.__type end
return "table" else
end return "table"
end end
end end
end
function getmetatable(object)
if oldtype(object)~="table" then return end function getmetatable(object)
if oldtype(oldgetmetatable(object))=="table" then if oldtype(object)~="table" then return end
if oldgetmetatable(object).__isuserdata then if oldtype(oldgetmetatable(object))=="table" then
if oldtype(oldgetmetatable(object).__usermeta)=="function" then if oldgetmetatable(object).__isuserdata then
return oldgetmetatable(object).__usermeta() if oldtype(oldgetmetatable(object).__usermeta)=="function" then
else return oldgetmetatable(object).__usermeta()
return oldgetmetatable(object).__usermeta else
end return oldgetmetatable(object).__usermeta
else end
return oldgetmetatable(object) else
end return oldgetmetatable(object)
else end
return oldgetmetatable(object) else
end return oldgetmetatable(object)
end end
end
function isEqualToAny(a, ...)
local args={...} function isEqualToAny(a, ...)
for i=0, #args do local args={...}
if a==args[i] then for i=0, #args do
return true if a==args[i] then
end return true
end end
return false end
end return false
end
function isEqualToAll(a, ...)
local args={...} function isEqualToAll(a, ...)
for i=0, #args do local args={...}
if a~=args[i] then for i=0, #args do
return false if a~=args[i] then
end return false
end end
return true end
end return true
end
function table.keys(t)
local a = {} function table.keys(t)
for n in pairs(t) do table.insert(a, n) end local a = {}
return a for n in pairs(t) do table.insert(a, n) end
end return a
end
function table.values(t)
local a = {} function table.values(t)
for _, n in pairs(t) do table.insert(a, n) end local a = {}
return a for _, n in pairs(t) do table.insert(a, n) end
end return a
end
function table.indexOf(t, value)
for i,v in ipairs(t) do function table.indexOf(t, value)
if v==value then for i,v in ipairs(t) do
return i if v==value then
end return i
end end
return -1 end
end return -1
end
syscall = setmetatable({}, {
__index = function(self, name) syscall = setmetatable({}, {
return function(...) __index = function(self, name)
local res = table.pack(coroutine.yield("syscall", name, ...)) return function(...)
if res[1] then local res = table.pack(coroutine.yield("syscall", name, ...))
return table.unpack(res, 2, res.n) if res[1] then
else return table.unpack(res, 2, res.n)
error(res[2], 2) else
end error(res[2], 2)
end end
end end
}) end
})
table.serialize=serialize table.serialize=serialize
@@ -1,277 +1,278 @@
local kernel = ... --:Minify:--
local vfs = {} local kernel = ...
vfs.mounts = { ["$"] = "/" } local vfs = {}
local disks = kernel.disks vfs.mounts = { ["$"] = "/" }
local disks = kernel.disks
-- Path handling
local function normalizePath(path) -- Path handling
local parts = {} local function normalizePath(path)
for part in path:gmatch("[^/]+") do local parts = {}
if part == ".." then for part in path:gmatch("[^/]+") do
if #parts > 0 then table.remove(parts) end if part == ".." then
elseif part ~= "." and part ~= "" then if #parts > 0 then table.remove(parts) end
table.insert(parts, part) elseif part ~= "." and part ~= "" then
end table.insert(parts, part)
end end
return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "") end
end return "/" .. table.concat(parts, "/") .. (path:sub(-1) == "/" and "/" or "")
end
local function resolvePath(path)
local task = kernel.currentTask local function resolvePath(path)
local cwd = task.cwd or "/" local task = kernel.currentTask
local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then
path = cwd .. path if path:sub(1,1) ~= "/" then
end path = cwd .. path
end
path = normalizePath(path)
path = normalizePath(path)
local mountPoint = "/"
local mountId = "$" local mountPoint = "/"
for k,v in pairs(vfs.mounts) do local mountId = "$"
if path:sub(1,#v) == v and #v > #mountPoint then for k,v in pairs(vfs.mounts) do
mountPoint = v if path:sub(1,#v) == v and #v > #mountPoint then
mountId = k mountPoint = v
end mountId = k
end end
end
local diskPath = path:sub(#mountPoint + 1)
return disks[mountId], diskPath local diskPath = path:sub(#mountPoint + 1)
end return disks[mountId], diskPath
end
-- File object creation
local function newFileObject(disk, handle, mode, path) -- File object creation
return { local function newFileObject(disk, handle, mode, path)
disk = disk, return {
handle = handle, disk = disk,
mode = mode, handle = handle,
path = path, mode = mode,
refcount = 1 path = path,
} refcount = 1
end }
end
local function allocFD(task)
local fd = 0 local function allocFD(task)
while task.fd[fd] do fd = fd + 1 end local fd = 0
return fd while task.fd[fd] do fd = fd + 1 end
end return fd
end
local function allocFD(task)
-- enforce per-task limit local function allocFD(task)
local count = 0 -- enforce per-task limit
for _ in pairs(task.fd) do count = count + 1 end local count = 0
if count >= kernel.config.maxFilesPerTask then for _ in pairs(task.fd) do count = count + 1 end
error("EMFILE") -- Too many open files in this task if count >= kernel.config.maxFilesPerTask then
end error("EMFILE") -- Too many open files in this task
end
-- find first free FD
local fd = 0 -- find first free FD
while task.fd[fd] do fd = fd + 1 end local fd = 0
return fd while task.fd[fd] do fd = fd + 1 end
end return fd
end
local function checkSystemLimit()
-- enforce system-wide limit local function checkSystemLimit()
local total = 0 -- enforce system-wide limit
for _, task in pairs(kernel.tasks or {}) do local total = 0
for _ in pairs(task.fd) do total = total + 1 end for _, task in pairs(kernel.tasks or {}) do
end for _ in pairs(task.fd) do total = total + 1 end
if total >= kernel.config.maxOpenFiles then end
error("ENFILE") -- Too many open files in the system if total >= kernel.config.maxOpenFiles then
end error("ENFILE") -- Too many open files in the system
end end
end
-- VFS syscalls
function vfs.open(path, mode) -- VFS syscalls
local task = kernel.currentTask function vfs.open(path, mode)
local task = kernel.currentTask
-- check limits
checkSystemLimit() -- check limits
checkSystemLimit()
local disk, diskPath = resolvePath(path)
if not disk then local disk, diskPath = resolvePath(path)
error("No disk mounted for path '"..path.."'") if not disk then
end error("No disk mounted for path '"..path.."'")
end
local handle = disk:open(diskPath, mode)
if not handle then return nil 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) local file = newFileObject(disk.address, handle, mode, path)
task.fd[fd] = file local fd = allocFD(task)
task.fd[fd] = file
return fd
end return fd
end
function vfs.close(fd)
local task = kernel.currentTask function vfs.close(fd)
local file = task.fd[fd] local task = kernel.currentTask
if not file then error("EBADF") end local file = task.fd[fd]
if not file then error("EBADF") end
task.fd[fd] = nil
file.refcount = file.refcount - 1 task.fd[fd] = nil
if file.refcount == 0 then file.refcount = file.refcount - 1
file.handle.close() if file.refcount == 0 then
end file.handle.close()
return true end
end return true
end
function vfs.read(fd, count)
local file = kernel.currentTask.fd[fd] function vfs.read(fd, count)
if not file then error("EBADF") end local file = kernel.currentTask.fd[fd]
if not file.mode:find("r") then error("File not open for reading") end if not file then error("EBADF") end
return file.handle.read(count) if not file.mode:find("r") then error("File not open for reading") end
end return file.handle.read(count)
end
function vfs.write(fd, data)
local file = kernel.currentTask.fd[fd] function vfs.write(fd, data)
if not file then error("EBADF") end local file = kernel.currentTask.fd[fd]
if not file.mode:find("w") then error("File not open for writing") end if not file then error("EBADF") end
return file.handle.write(data) if not file.mode:find("w") then error("File not open for writing") end
end return file.handle.write(data)
end
function vfs.whereis(fd)
local file = kernel.currentTask.fd[fd] function vfs.whereis(fd)
if not file then error("EBADF") end local file = kernel.currentTask.fd[fd]
return file.path if not file then error("EBADF") end
end return file.path
end
-- Filesystem operations
function vfs.mkdir(path) -- Filesystem operations
local disk, diskPath = resolvePath(path) function vfs.mkdir(path)
if not disk then error("No disk mounted") end local disk, diskPath = resolvePath(path)
return disk:makeDirectory(diskPath) if not disk then error("No disk mounted") end
end return disk:makeDirectory(diskPath)
end
function vfs.remove(path)
local disk, diskPath = resolvePath(path) function vfs.remove(path)
if not disk then error("No disk mounted") end local disk, diskPath = resolvePath(path)
return disk:remove(diskPath) if not disk then error("No disk mounted") end
end return disk:remove(diskPath)
end
function vfs.attributes(path)
if type(path) == "number" then function vfs.attributes(path)
local file = kernel.currentTask.fd[path] if type(path) == "number" then
if not file then error("EBADF") end local file = kernel.currentTask.fd[path]
return disks[file.disk]:attributes(file.path) if not file then error("EBADF") end
end return disks[file.disk]:attributes(file.path)
local disk, diskPath = resolvePath(path) end
if not disk then error("No disk mounted") end local disk, diskPath = resolvePath(path)
return disk:attributes(diskPath) if not disk then error("No disk mounted") end
end return disk:attributes(diskPath)
end
function vfs.list(path)
local disk, diskPath = resolvePath(path) function vfs.list(path)
if not disk then error("No disk mounted") end local disk, diskPath = resolvePath(path)
return disk:list(diskPath) if not disk then error("No disk mounted") end
end return disk:list(diskPath)
end
function vfs.exists(path)
local disk, diskPath = resolvePath(path) function vfs.exists(path)
if not disk then return false end local disk, diskPath = resolvePath(path)
return disk:directoryExists(diskPath) or disk:fileExists(diskPath) if not disk then return false end
end return disk:directoryExists(diskPath) or disk:fileExists(diskPath)
end
function vfs.type(path)
if type(path) == "number" then function vfs.type(path)
local file = kernel.currentTask.fd[path] if type(path) == "number" then
if not file then error("EBADF") end local file = kernel.currentTask.fd[path]
return disks[file.disk]:type(file.path) if not file then error("EBADF") end
end return disks[file.disk]:type(file.path)
local disk, diskPath = resolvePath(path) end
if not disk then error("No disk mounted") end local disk, diskPath = resolvePath(path)
return disk:type(diskPath) if not disk then error("No disk mounted") end
end return disk:type(diskPath)
end
-- CWD
function vfs.getcwd() -- CWD
return kernel.currentTask.cwd function vfs.getcwd()
end return kernel.currentTask.cwd
end
function vfs.setcwd(path)
if path:sub(-1) ~= "/" then path = path .. "/" end function vfs.setcwd(path)
if path:sub(1,1) ~= "/" then path = "/" .. path end if path:sub(-1) ~= "/" then path = path .. "/" end
kernel.currentTask.cwd = normalizePath(path) if path:sub(1,1) ~= "/" then path = "/" .. path end
end kernel.currentTask.cwd = normalizePath(path)
end
-- Mounting
function vfs.mount(diskId, path) -- Mounting
if kernel.uid ~= 0 then error("Permission denied") end function vfs.mount(diskId, path)
if not disks[diskId] then error("Unknown disk '"..diskId.."'") end if kernel.uid ~= 0 then error("Permission denied") end
if path:sub(-1) ~= "/" then path = path .. "/" 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 for _,v in pairs(vfs.mounts) do
end if v == path then error("Mount point already used") end
vfs.mounts[diskId] = path end
end vfs.mounts[diskId] = path
end
function vfs.unmount(path)
if kernel.uid ~= 0 then error("Permission denied") end function vfs.unmount(path)
for k,v in pairs(vfs.mounts) do if kernel.uid ~= 0 then error("Permission denied") end
if v == path then for k,v in pairs(vfs.mounts) do
vfs.mounts[k] = nil if v == path then
return true vfs.mounts[k] = nil
end return true
end end
return false end
end return false
end
function vfs.getMounts()
return vfs.mounts function vfs.getMounts()
end return vfs.mounts
end
function vfs.virtdisk(obj)
kernel.disks[obj.address] = obj function vfs.virtdisk(obj)
kernel.log("Registered virtual disk at "..obj.address) kernel.disks[obj.address] = obj
end kernel.log("Registered virtual disk at "..obj.address)
end
-- Redirect file operations to VFS
function vfs.dup(oldfd) -- Redirect file operations to VFS
local task = kernel.currentTask function vfs.dup(oldfd)
local file = task.fd[oldfd] local task = kernel.currentTask
if not file then error("EBADF") end local file = task.fd[oldfd]
if not file then error("EBADF") end
local newfd = allocFD(task)
task.fd[newfd] = file local newfd = allocFD(task)
file.refcount = file.refcount + 1 task.fd[newfd] = file
return newfd file.refcount = file.refcount + 1
end return newfd
end
function vfs.dup2(oldfd, newfd)
local task = kernel.currentTask function vfs.dup2(oldfd, newfd)
local file = task.fd[oldfd] local task = kernel.currentTask
if not file then error("EBADF") end local file = task.fd[oldfd]
if not file then error("EBADF") end
if oldfd == newfd then return newfd end
if oldfd == newfd then return newfd end
if task.fd[newfd] then
vfs.close(newfd) if task.fd[newfd] then
end vfs.close(newfd)
end
task.fd[newfd] = file
file.refcount = file.refcount + 1 task.fd[newfd] = file
return newfd file.refcount = file.refcount + 1
end return newfd
end
-- Syscall registration
kernel.vfs = vfs -- Syscall registration
kernel.syscalls["VFS_open"] = vfs.open kernel.vfs = vfs
kernel.syscalls["VFS_read"] = vfs.read kernel.syscalls["VFS_open"] = vfs.open
kernel.syscalls["VFS_write"] = vfs.write kernel.syscalls["VFS_read"] = vfs.read
kernel.syscalls["VFS_close"] = vfs.close kernel.syscalls["VFS_write"] = vfs.write
kernel.syscalls["VFS_list"] = vfs.list kernel.syscalls["VFS_close"] = vfs.close
kernel.syscalls["VFS_type"] = vfs.type kernel.syscalls["VFS_list"] = vfs.list
kernel.syscalls["VFS_attributes"] = vfs.attributes kernel.syscalls["VFS_type"] = vfs.type
kernel.syscalls["VFS_mkdir"] = vfs.mkdir kernel.syscalls["VFS_attributes"] = vfs.attributes
kernel.syscalls["VFS_remove"] = vfs.remove kernel.syscalls["VFS_mkdir"] = vfs.mkdir
kernel.syscalls["VFS_exists"] = vfs.exists kernel.syscalls["VFS_remove"] = vfs.remove
kernel.syscalls["VFS_mount"] = vfs.mount kernel.syscalls["VFS_exists"] = vfs.exists
kernel.syscalls["VFS_unmount"] = vfs.unmount kernel.syscalls["VFS_mount"] = vfs.mount
kernel.syscalls["VFS_getcwd"] = vfs.getcwd kernel.syscalls["VFS_unmount"] = vfs.unmount
kernel.syscalls["VFS_setcwd"] = vfs.setcwd kernel.syscalls["VFS_getcwd"] = vfs.getcwd
kernel.syscalls["VFS_whereis"] = vfs.whereis kernel.syscalls["VFS_setcwd"] = vfs.setcwd
kernel.syscalls["VFS_dup"] = vfs.dup kernel.syscalls["VFS_whereis"] = vfs.whereis
kernel.syscalls["VFS_dup2"] = vfs.dup2 kernel.syscalls["VFS_dup"] = vfs.dup
kernel.syscalls["VFS_dup2"] = vfs.dup2
kernel.log("VFS module loaded")
kernel.log("VFS module loaded")
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
local cache = {} local cache = {}
local searchpaths = { local searchpaths = {
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
local proxy = {} local proxy = {}
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
kernel.processes.keventd = function() kernel.processes.keventd = function()
@@ -1,3 +1,4 @@
--:Minify:--
local kernel=... local kernel=...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then if v:sub(1,1)=="U" then
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
local ports = {} local ports = {}
local signals = {} local signals = {}
@@ -1,3 +1,4 @@
--:Minify:--
local args={...} local args={...}
local kernel=args[1] local kernel=args[1]
kernel._G=_G kernel._G=_G
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
local pam = {} local pam = {}
kernel.pam = pam kernel.pam = pam
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
local tasks = {} local tasks = {}
local sys = {} local sys = {}
@@ -1,3 +1,4 @@
--:Minify:--
local kernel=... local kernel=...
local debug=debug local debug=debug
kernel._G.debug={ kernel._G.debug={
@@ -1,3 +1,4 @@
--:Minify:--
local kernel=... local kernel=...
kernel.tty={} kernel.tty={}
@@ -1,2 +1,3 @@
--:Minify:--
local kernel=... local kernel=...
kernel.tty.bind("tty0") kernel.tty.bind("tty0")
@@ -1,3 +1,4 @@
--:Minify:--
local kernel=... local kernel=...
function print(...) function print(...)
coroutine.yield() coroutine.yield()
@@ -1,3 +1,4 @@
--:Minify:--
local kernel = ... local kernel = ...
kernel.log("Loading init system...") kernel.log("Loading init system...")
kernel.log("InitPath: "..kernel.config.initPath) kernel.log("InitPath: "..kernel.config.initPath)
@@ -1,15 +1,15 @@
{ {
"Name": "HyperionOS", "Name": "HyperionOS",
"Version": "1.0.0", "Version": "1.0.0",
"Publishers": ["HyperionOS Dev Team"], "Publishers": ["HyperionOS Dev Team"],
"Description": "The install package for HyperionOS project.", "Description": "The install package for HyperionOS project.",
"Dependencies": [ "Dependencies": [
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-core-v1.0.0.pkg", "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-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-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-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-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-filesystem-v1.0.0.pkg",
"https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.pkg" "https://git.astronand.dev/Hyperion/HyperionOS/archive/Hyperion-bash-v1.0.0.pkg"
] ]
} }
-177
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
@@ -1 +0,0 @@
local kernel = ...
+44
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
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
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
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
-47
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