moved stuff to src/ from test/ and made better build scripts
This commit is contained in:
93
.vscode/tasks.json
vendored
93
.vscode/tasks.json
vendored
@@ -2,45 +2,88 @@
|
|||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"tasks": [
|
"tasks": [
|
||||||
{
|
{
|
||||||
"label": "Build",
|
"label": "Build (Minfiyed)",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
|
|
||||||
"windows": {
|
|
||||||
"command": "powershell",
|
"command": "powershell",
|
||||||
"args": [
|
"args": [
|
||||||
"-NoProfile",
|
"-NoProfile",
|
||||||
"-ExecutionPolicy",
|
"-ExecutionPolicy",
|
||||||
"Bypass",
|
"Bypass",
|
||||||
"-Command",
|
"-File",
|
||||||
"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 } }"
|
"${workspaceFolder}\\tools\\buildMini.ps1"
|
||||||
]
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
},
|
},
|
||||||
|
|
||||||
"linux": {
|
|
||||||
"command": "bash",
|
|
||||||
"args": [
|
|
||||||
"-c",
|
|
||||||
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"osx": {
|
|
||||||
"command": "bash",
|
|
||||||
"args": [
|
|
||||||
"-c",
|
|
||||||
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
|
|
||||||
]
|
|
||||||
},
|
|
||||||
|
|
||||||
"presentation": {
|
"presentation": {
|
||||||
"reveal": "always",
|
"reveal": "always",
|
||||||
"panel": "shared"
|
"panel": "shared"
|
||||||
},
|
},
|
||||||
"problemMatcher": [],
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Build (Source)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "powershell",
|
||||||
|
"args": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy",
|
||||||
|
"Bypass",
|
||||||
|
"-File",
|
||||||
|
"${workspaceFolder}\\tools\\build.ps1"
|
||||||
|
],
|
||||||
"group": {
|
"group": {
|
||||||
"kind": "build",
|
"kind": "build",
|
||||||
"isDefault": true
|
"isDefault": true
|
||||||
}
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test (Minfiyed)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "powershell",
|
||||||
|
"args": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy",
|
||||||
|
"Bypass",
|
||||||
|
"-File",
|
||||||
|
"${workspaceFolder}\\tools\\buildMiniTest.ps1"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"label": "Test (Source)",
|
||||||
|
"type": "shell",
|
||||||
|
"command": "powershell",
|
||||||
|
"args": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy",
|
||||||
|
"Bypass",
|
||||||
|
"-File",
|
||||||
|
"${workspaceFolder}\\tools\\buildTest.ps1"
|
||||||
|
],
|
||||||
|
"group": {
|
||||||
|
"kind": "test",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": []
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 +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 +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
Build/boot/safeboot.cfg
Normal file
11
Build/boot/safeboot.cfg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||||
|
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
|
||||||
|
|
||||||
|
-- This file is auto-generated during the build process.
|
||||||
|
-- RECOVERY BOOT CONFIGURATION FILE
|
||||||
|
return {
|
||||||
|
initPath = "/sbin/init.lua",
|
||||||
|
maxOpenFiles = 128,
|
||||||
|
maxFilesPerTask = 16,
|
||||||
|
preempt=true
|
||||||
|
}
|
||||||
@@ -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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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 +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...")
|
|
||||||
@@ -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,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local fs = {}
|
local fs = {}
|
||||||
local disks = {}
|
local disks = {}
|
||||||
local mounts = {}
|
local mounts = {}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local apis = args[1]
|
local apis = args[1]
|
||||||
local disks = args[2]
|
local disks = args[2]
|
||||||
@@ -109,19 +110,7 @@ end
|
|||||||
|
|
||||||
if not ifs.isFile("/boot/boot.cfg") then
|
if not ifs.isFile("/boot/boot.cfg") then
|
||||||
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR")
|
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR")
|
||||||
ifs.writeAllText("/boot/boot.cfg",[[
|
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.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
|
end
|
||||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||||
if not initCfgFunc then
|
if not initCfgFunc then
|
||||||
@@ -229,6 +218,9 @@ kernel.kernelTask = {
|
|||||||
}
|
}
|
||||||
kernel.currentTask = kernel.kernelTask
|
kernel.currentTask = kernel.kernelTask
|
||||||
|
|
||||||
|
kernel.syscalls["OS_time"]=function() return kernel.computer:time() end
|
||||||
|
kernel.syscalls["OS_log"]=kernel.log
|
||||||
|
|
||||||
kernel.log("Running modules")
|
kernel.log("Running modules")
|
||||||
for _,p in ipairs(modules) do
|
for _,p in ipairs(modules) do
|
||||||
for _,v in ipairs(p) do
|
for _,v in ipairs(p) do
|
||||||
@@ -246,5 +238,6 @@ for _,p in ipairs(modules) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("Kernel initialized successfully.")
|
kernel.log("Kernel initialized successfully.")
|
||||||
|
kernel.status="running"
|
||||||
kernel.main()
|
kernel.main()
|
||||||
kernel.PANIC("Execution complete")
|
kernel.PANIC("Execution complete")
|
||||||
11
Src/Hyperion-kernel-v1.0.0/boot/safeboot.cfg
Normal file
11
Src/Hyperion-kernel-v1.0.0/boot/safeboot.cfg
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||||
|
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
|
||||||
|
|
||||||
|
-- This file is auto-generated during the build process.
|
||||||
|
-- RECOVERY BOOT CONFIGURATION FILE
|
||||||
|
return {
|
||||||
|
initPath = "/sbin/init.lua",
|
||||||
|
maxOpenFiles = 128,
|
||||||
|
maxFilesPerTask = 16,
|
||||||
|
preempt=true
|
||||||
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
function string.hasSuffix(str, suffix)
|
function string.hasSuffix(str, suffix)
|
||||||
return string.sub(str, #suffix+1) == suffix
|
return string.sub(str, #suffix+1) == suffix
|
||||||
end
|
end
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
local vfs = {}
|
local vfs = {}
|
||||||
vfs.mounts = { ["$"] = "/" }
|
vfs.mounts = { ["$"] = "/" }
|
||||||
@@ -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)
|
||||||
177
Src/iso.lua
177
Src/iso.lua
@@ -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
tools/build.ps1
Normal file
44
tools/build.ps1
Normal file
@@ -0,0 +1,44 @@
|
|||||||
|
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
# Clean Build folder
|
||||||
|
if (Test-Path $buildRoot) {
|
||||||
|
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
57
tools/buildMini.ps1
Normal file
57
tools/buildMini.ps1
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
# Clean Build folder
|
||||||
|
if (Test-Path $buildRoot) {
|
||||||
|
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
|
||||||
|
# Read first 3 lines
|
||||||
|
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($header -match "--:Minify:--") {
|
||||||
|
Write-Host " > Minifying"
|
||||||
|
$content = luamin -f "$src"
|
||||||
|
|
||||||
|
# UTF8 encoding without BOM because it breaks lua
|
||||||
|
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||||
|
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
108
tools/buildMiniTest.ps1
Normal file
108
tools/buildMiniTest.ps1
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
# Clean Build folder
|
||||||
|
if (Test-Path $buildRoot) {
|
||||||
|
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
|
||||||
|
# Read first 3 lines
|
||||||
|
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($header -match "--:Minify:--") {
|
||||||
|
Write-Host " > Minifying"
|
||||||
|
$content = luamin -f "$src"
|
||||||
|
|
||||||
|
# UTF8 encoding without BOM because it breaks lua
|
||||||
|
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||||
|
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
|
|
||||||
|
$testRoot = Join-Path $PSScriptRoot "..\test"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
|
||||||
|
# Read first 3 lines
|
||||||
|
$header = Get-Content $src -TotalCount 3 -ErrorAction SilentlyContinue
|
||||||
|
|
||||||
|
if ($header -match "--:Minify:--") {
|
||||||
|
Write-Host " > Minifying"
|
||||||
|
$content = luamin -f "$src"
|
||||||
|
|
||||||
|
# UTF8 encoding without BOM because it breaks lua
|
||||||
|
$utf8NoBOM = New-Object System.Text.UTF8Encoding($false)
|
||||||
|
[System.IO.File]::WriteAllText($dst, $content, $utf8NoBOM)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
83
tools/buildTest.ps1
Normal file
83
tools/buildTest.ps1
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
$testRoot = Join-Path $PSScriptRoot "..\src"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
# Clean Build folder
|
||||||
|
if (Test-Path $buildRoot) {
|
||||||
|
Remove-Item -LiteralPath $buildRoot -Recurse -Force -ErrorAction SilentlyContinue
|
||||||
|
}
|
||||||
|
|
||||||
|
New-Item -ItemType Directory -Path $buildRoot | Out-Null
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
|
|
||||||
|
|
||||||
|
$testRoot = Join-Path $PSScriptRoot "..\test"
|
||||||
|
$buildRoot = Join-Path $PSScriptRoot "..\Build"
|
||||||
|
|
||||||
|
$testRoot = Resolve-Path $testRoot
|
||||||
|
|
||||||
|
Write-Host "Building from $testRoot"
|
||||||
|
Write-Host "Output to $buildRoot"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Each top-level folder in test/
|
||||||
|
Get-ChildItem -Path $testRoot -Directory | ForEach-Object {
|
||||||
|
|
||||||
|
$folderRoot = $_.FullName
|
||||||
|
Write-Host "== Package: $($_.Name) =="
|
||||||
|
|
||||||
|
# Walk files inside this folder
|
||||||
|
Get-ChildItem -Path $folderRoot -File -Recurse | ForEach-Object {
|
||||||
|
|
||||||
|
$src = $_.FullName
|
||||||
|
$rel = $src.Substring($folderRoot.Length).TrimStart("\")
|
||||||
|
$dst = Join-Path $buildRoot $rel
|
||||||
|
$dstDir = Split-Path $dst
|
||||||
|
|
||||||
|
if (-not (Test-Path $dstDir)) {
|
||||||
|
New-Item -ItemType Directory -Path $dstDir -Force | Out-Null
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Processing: $rel"
|
||||||
|
|
||||||
|
Write-Host " > Copying"
|
||||||
|
Copy-Item -LiteralPath $src -Destination $dst -Force
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "Build complete."
|
||||||
@@ -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
|
|
||||||
Reference in New Issue
Block a user