finished vfs for a while

This commit is contained in:
2026-02-12 11:43:41 -05:00
parent 1c4f48bd65
commit 33cd291c21
31 changed files with 1083 additions and 1097 deletions

View File

@@ -29,6 +29,8 @@ You can also view real-time loading logs during boot if `showModLoad` in boot.cf
To trigger a panic (for testing): To trigger a panic (for testing):
```lua ```lua
kernel.PANIC("Test panic message") kernel.PANIC("Test panic message")
OR
kernel.log("Test log message")
``` ```
--- ---

View File

@@ -10,6 +10,7 @@ local pid=syscall.getpid()
local proc=0 local proc=0
local fs=require("sys.fs") local fs=require("sys.fs")
local timeout=false local timeout=false
syscall.setEnviron("SHELL","simpleshell")
printInline("> ") printInline("> ")
while true do while true do
local event = {syscall.IO_pullEvent()} local event = {syscall.IO_pullEvent()}
@@ -29,10 +30,11 @@ while true do
stopInput=false stopInput=false
else else
local path=nil local path=nil
if fs.exists("/bin/"..str) then local split=string.split(str, " ")
path="/bin/"..str if fs.exists("/bin/"..split[1]) then
elseif fs.exists("/bin/"..str..".lua") then path="/bin/"..split[1]
path="/bin/"..str..".lua" elseif fs.exists("/bin/"..split[1]..".lua") then
path="/bin/"..split[1]..".lua"
end end
if not path then if not path then
print("Program not found") print("Program not found")
@@ -46,11 +48,13 @@ while true do
printInline("> ") printInline("> ")
end end
syscall.IO_bind("bash:"..tostring(pid)) syscall.IO_bind("bash:"..tostring(pid))
proc = syscall.spawn(program, path) proc = syscall.spawn(program, path, nil, {table.unpack(split, 2)})
syscall.IO_bind(inputIO) syscall.IO_bind(inputIO)
end end
str="" str=""
end end
elseif event[1]=="keyTyped" and event[3]=="^d" then
syscall.exit(0)
else else
str=str..event[3] str=str..event[3]
printInline(event[3]) printInline(event[3])
@@ -64,7 +68,9 @@ while true do
if stopInput then if stopInput then
local exited, code = syscall.collect(proc) local exited, code = syscall.collect(proc)
if exited then if exited then
print("\nTask exited with code:\n"..tostring(code)) if code then
print("\nTask exited with code:\n"..tostring(code))
end
printInline("> ") printInline("> ")
stopInput=false stopInput=false
else else
@@ -74,9 +80,6 @@ while true do
print("Terminated") print("Terminated")
printInline("> ") printInline("> ")
stopInput=false stopInput=false
elseif event[1]=="keyTyped" and event[3]=="^d" then
syscall.kill(proc)
syscall.exit(0)
else else
syscall.IO_pushEvent("bash:"..tostring(pid), table.unpack(event)) syscall.IO_pushEvent("bash:"..tostring(pid), table.unpack(event))
end end

View File

@@ -0,0 +1,8 @@
local args = {...}
local file = syscall.open(args[1], "r")
local content=""
while content~=nil do
content=syscall.read(file, 1024)
syscall.TTY_printInline(content)
end
syscall.close(file)

0
Src/Hyperion-bash/bin/cd Normal file
View File

View File

@@ -0,0 +1 @@
syscall.TTY_clear()

View File

@@ -1,7 +1,11 @@
local fs = require("sys.fs") local fs = require("sys.fs")
local stuff = fs.list(syscall.getcwd()) local dir = (({...})[1] or "")
if dir~="" and dir:sub(#dir,#dir)~="/" then
dir=dir.."/"
end
local stuff = fs.list(dir)
for i,v in ipairs(stuff) do for i,v in ipairs(stuff) do
if fs.isDir(v) then if fs.isDir(dir..v) then
print(v.."/") print(v.."/")
else else
print(v) print(v)

View File

@@ -21,7 +21,7 @@ while true do
if str == "" then if str == "" then
printInline("> ") printInline("> ")
stopInput=false stopInput=false
elseif str == "exit" then elseif str == "exit()" then
break break
else else
local func=load(str,"@Lua","t",luaEnv) local func=load(str,"@Lua","t",luaEnv)

View File

@@ -0,0 +1 @@
print(syscall.getcwd())

View File

@@ -1,5 +1,5 @@
--:Minify:-- -- :Minify:--
local BOOT_DRIVE_PATH=({...})[1] or "/$" local BOOT_DRIVE_PATH = ({...})[1] or "/$"
---@diagnostic disable-next-line: undefined-global ---@diagnostic disable-next-line: undefined-global
local term = term local term = term
local os = os local os = os
@@ -38,7 +38,7 @@ local function write(text)
y = y + 1 y = y + 1
end end
if y-1 >= h then if y - 1 >= h then
term.scroll(1) term.scroll(1)
y = h y = h
term.setCursorPos(x, y) term.setCursorPos(x, y)
@@ -61,7 +61,7 @@ end
term.setCursorBlink(false) term.setCursorBlink(false)
local ok, err = xpcall(function() local ok, err = xpcall(function()
local apis={BOOT_DRIVE_PATH=BOOT_DRIVE_PATH} local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
local lua = { local lua = {
coroutine = true, coroutine = true,
@@ -93,14 +93,14 @@ local ok, err = xpcall(function()
tostring = true, tostring = true,
type = true, type = true,
xpcall = true, xpcall = true,
_G=true _G = true
} }
local debug = debug local debug = debug
for i,v in pairs(_G) do for i, v in pairs(_G) do
if not lua[i] or lua[i]==nil then if not lua[i] or lua[i] == nil then
apis[i]=v apis[i] = v
_G[i]=nil _G[i] = nil
end end
end end
@@ -109,18 +109,18 @@ local ok, err = xpcall(function()
while stoptime > apis.os.clock() do end while stoptime > apis.os.clock() do end
end end
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000 apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000 apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00 apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00 apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00 apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55 apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900 apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55 apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
@@ -128,28 +128,23 @@ local ok, err = xpcall(function()
local function getFile(path) local function getFile(path)
local file = apis.fs.open(path, "r") local file = apis.fs.open(path, "r")
if not file then displaySuperBadError("Could not open file: "..path) end if not file then
displaySuperBadError("Could not open file: " .. path)
end
local content = file.readAll() local content = file.readAll()
file.close() file.close()
return content return content
end end
local Kernel = load(getFile(BOOT_DRIVE_PATH.."/boot/kernel.lua"),"@Kernel") local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
local initFs = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/initdisks"),"@Init_disks")(apis) local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
local fs = load(getFile(BOOT_DRIVE_PATH.."/boot/initfs"),"@InitFs")() local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
local key = load(getFile(BOOT_DRIVE_PATH.."/boot/cct/keys.lua"),"@keyhelper")(apis) local key = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/keys.lua"),"@keyhelper")(apis)
if not Kernel then
displaySuperBadError("Could not load kernel.") if not Kernel then displaySuperBadError("Could not load kernel.") end
end if not initFs then displaySuperBadError("Could not load initdisks.") end
if not initFs then if not fs then displaySuperBadError("Could not load initfs.") end
displaySuperBadError("Could not load initdisks.") if not key then displaySuperBadError("Could not load key helper.") end
end
if not fs then
displaySuperBadError("Could not load initfs.")
end
if not key then
displaySuperBadError("Could not load key helper.")
end
local eventQueue = {} local eventQueue = {}
@@ -159,7 +154,7 @@ local ok, err = xpcall(function()
local computer = { local computer = {
time = function() return apis.os.epoch("utc") end, time = function() return apis.os.epoch("utc") end,
clock = function() return apis.os.clock()*1000 end, clock = function() return apis.os.clock() * 1000 end,
shutdown = apis.os.shutdown, shutdown = apis.os.shutdown,
reboot = apis.os.reboot, reboot = apis.os.reboot,
getMachineEvent = function() getMachineEvent = function()
@@ -169,36 +164,34 @@ local ok, err = xpcall(function()
return nil return nil
end end
end, end,
getEEPROM = function() getEEPROM = function() return getFile("/startup.lua") end,
return getFile("/startup.lua") setEEPROM = function(_, text)
end,
setEEPROM = function(_,text)
local h = apis.fs.open("/startup.lua", "w") local h = apis.fs.open("/startup.lua", "w")
h.write(text) h.write(text)
h.close() h.close()
end end
} }
local icolors={ local icolors = {
[0x1] =1, -- #000000 [0x1] = 1, -- #000000
[0x2] =2, -- #FFFFFF [0x2] = 2, -- #FFFFFF
[0x4] =3, -- #FF0000 [0x4] = 3, -- #FF0000
[0x8] =4, -- #00FF00 [0x8] = 4, -- #00FF00
[0x10] =5, -- #0000FF [0x10] = 5, -- #0000FF
[0x20] =6, -- #00FFFF [0x20] = 6, -- #00FFFF
[0x40] =7, -- #FF00FF [0x40] = 7, -- #FF00FF
[0x80] =8, -- #FFFF00 [0x80] = 8, -- #FFFF00
[0x100] =9, -- #FF6D00 [0x100] = 9, -- #FF6D00
[0x200] =10, -- #6DFF55 [0x200] = 10, -- #6DFF55
[0x400] =11, -- #24FFFF [0x400] = 11, -- #24FFFF
[0x800] =12, -- #924900 [0x800] = 12, -- #924900
[0x1000] =13, -- #6D6D55 [0x1000] = 13, -- #6D6D55
[0x2000] =14, -- #DBDBAA [0x2000] = 14, -- #DBDBAA
[0x4000] =15, -- #6D00FF [0x4000] = 15, -- #6D00FF
[0x8000] =16 -- #B6FF00 [0x8000] = 16 -- #B6FF00
} }
local colors={ local colors = {
0x0001, -- #000000 0x0001, -- #000000
0x0002, -- #FFFFFF 0x0002, -- #FFFFFF
0x0004, -- #FF0000 0x0004, -- #FF0000
@@ -214,7 +207,7 @@ local ok, err = xpcall(function()
0x1000, -- #6D6D55 0x1000, -- #6D6D55
0x2000, -- #DBDBAA 0x2000, -- #DBDBAA
0x4000, -- #6D00FF 0x4000, -- #6D00FF
0x8000 -- #B6FF00 0x8000 -- #B6FF00
} }
apis.term.setBackgroundColor(0x8000) apis.term.setBackgroundColor(0x8000)
@@ -224,21 +217,33 @@ local ok, err = xpcall(function()
local kernelCoro = coroutine.create(function() local kernelCoro = coroutine.create(function()
---@diagnostic disable-next-line: param-type-mismatch ---@diagnostic disable-next-line: param-type-mismatch
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init", { local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
print=function(_,text) write(text.."\n") end, {
printInline=function(_,text) write(text) end, print = function(_, text) write(text .. "\n") end,
clear=function() apis.term.clear() apis.term.setCursorPos(1,1) end, printInline = function(_, text) write(text) end,
setCursorPos=function(_,x,y) apis.term.setCursorPos(x,y) end, clear = function()
getCursorPos=function() return apis.term.getCursorPos() end, apis.term.clear()
getSize=function() return apis.term.getSize() end, apis.term.setCursorPos(1, 1)
setBackgroundColor=function(_,color) apis.term.setBackgroundColor(colors[color]) end, end,
setTextColor=function(_,color) apis.term.setTextColor(colors[color]) end, setCursorPos = function(_, x, y)
getBackgroundColor=function() return icolors[apis.term.getBackgroundColor()] end, apis.term.setCursorPos(x, y)
getTextColor=function() return icolors[apis.term.getTextColor()] end end,
getCursorPos = function() return apis.term.getCursorPos() end,
getSize = function() return apis.term.getSize() end,
setBackgroundColor = function(_, color)
apis.term.setBackgroundColor(colors[color])
end,
setTextColor = function(_, color)
apis.term.setTextColor(colors[color])
end,
getBackgroundColor = function()
return icolors[apis.term.getBackgroundColor()]
end,
getTextColor = function()
return icolors[apis.term.getTextColor()]
end
}, computer, fs, "$") }, computer, fs, "$")
if not ok then if not ok then displaySuperBadError(err) end
displaySuperBadError(err)
end
end) end)
-- time is in milliseconds -- time is in milliseconds
@@ -250,9 +255,9 @@ local ok, err = xpcall(function()
end end
end, "", 1000) end, "", 1000)
local ret = {coroutine.resume(co, ...)} local ret = {coroutine.resume(co, ...)}
if ret[1] and ret[2]=="timeout" then if ret[1] and ret[2] == "timeout" then
return "timeout" return "timeout"
elseif ret[1]==false then elseif ret[1] == false then
return "error", ret[2] return "error", ret[2]
else else
debug.sethook(co) debug.sethook(co)
@@ -260,7 +265,7 @@ local ok, err = xpcall(function()
end end
end end
write("Loaded in "..tostring(apis.os.clock()).." seconds.\n") write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
while true do while true do
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50) local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
@@ -279,17 +284,15 @@ local ok, err = xpcall(function()
elseif event[1] == "disk_eject" then elseif event[1] == "disk_eject" then
queueEvent("componentRemoved", "disk") queueEvent("componentRemoved", "disk")
elseif event[1] == "NoSleep" then elseif event[1] == "NoSleep" then
exit=true exit = true
end end
end end
if status == "error" or coroutine.status(kernelCoro)=="dead" then if status == "error" or coroutine.status(kernelCoro) == "dead" then
displaySuperBadError("Kernel error: "..tostring(err)) displaySuperBadError("Kernel error: " .. tostring(err))
coroutine.yield("key") coroutine.yield("key")
end end
end end
end, debug.traceback) end, debug.traceback)
if not ok then if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
displaySuperBadError("Fatal error during boot: "..err) while true do coroutine.yield() end
end
while true do coroutine.yield() end

View File

@@ -16,7 +16,6 @@ local BOOT_DRIVE_PATH=({...})[1] or "/$"
-- * `turtle.equip[Left|Right]` -- * `turtle.equip[Left|Right]`
-- Licensed under the MIT license -- Licensed under the MIT license
local args = {...} local args = {...}
if _HOST:find("UnBIOS") then return end
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true} local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
local t = {} local t = {}
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
@@ -32,7 +31,6 @@ if _G.commands then _G.commands = _G.commands.native end
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}} local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
_G._HOST = _G._HOST .. " (UnBIOS)"
-- Set up TLCO -- Set up TLCO
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally -- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
-- this would cause `parallel` to throw an error, but we replace `error` with an -- this would cause `parallel` to throw an error, but we replace `error` with an

View File

@@ -1,18 +1,17 @@
--:Minify:-- -- :Minify:--
local apis = ({...})[1] local apis = ({...})[1]
local BOOT_DRIVE_PATH=apis.BOOT_DRIVE_PATH or "/$" local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
local fs = apis.fs local fs = apis.fs
local native = apis.peripheral local native = apis.peripheral
local peripheral = {} local peripheral = {}
local sides = {"top", "bottom", "left", "right", "front", "back"} local sides = {"top", "bottom", "left", "right", "front", "back"}
function peripheral.getType(name) function peripheral.getType(name)
if native.isPresent(name) then if native.isPresent(name) then return native.getType(name) end
return native.getType(name)
end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then if native.hasType(side, "peripheral_hub") and
native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name) return native.call(side, "getTypeRemote", name)
end end
end end
@@ -23,9 +22,7 @@ function peripheral.getNames()
local names = {} local names = {}
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.isPresent(side) then if native.isPresent(side) then table.insert(names, side) end
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides") local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do for _, hubSide in ipairs(hubSides) do
@@ -36,37 +33,30 @@ function peripheral.getNames()
return names return names
end end
--------------------------------------------------------- local disks = {}
-- STORAGE local internal = {}
---------------------------------------------------------
local disks = {} -- real disks
local internal = {} -- "$" disk
---------------------------------------------------------
-- HELPERS
---------------------------------------------------------
local function norm(path) local function norm(path)
if not path or path == "" then return "/" end if not path or path == "" then return "/" end
return fs.combine("/", path) return fs.combine("/", path)
end end
--- Creates a disk object given a base path
local function createDisk(id, basePath, readonly, periph) local function createDisk(id, basePath, readonly, periph)
basePath = norm(basePath) basePath = norm(basePath)
local disk = {address=id,isReadOnly=function() return readonly end} local disk = {address = id, isReadOnly = function() return readonly end}
function disk:spaceUsed() function disk:spaceUsed()
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath) return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
end end
function disk:spaceTotal() function disk:spaceTotal() return fs.getCapacity(basePath) end
return fs.getCapacity(basePath)
end
function disk:list(path) function disk:list(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end if not fs.exists(p) or not fs.isDir(p) then
return nil, "not directory"
end
return fs.list(p) return fs.list(p)
end end
@@ -103,13 +93,9 @@ local function createDisk(id, basePath, readonly, periph)
return true return true
end end
function disk:setLabel(label) function disk:setLabel(label) periph.setLabel(label) end
periph.setLabel(label)
end
function disk:getLabel(label) function disk:getLabel(label) return periph.getLabel() end
return periph.getLabel()
end
function disk:attributes(path) function disk:attributes(path)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
@@ -120,39 +106,30 @@ local function createDisk(id, basePath, readonly, periph)
local p = fs.combine(basePath, path) local p = fs.combine(basePath, path)
return fs.open(p, mode) return fs.open(p, mode)
end end
return disk return disk
end end
---------------------------------------------------------
-- INTERNAL DISK "$" (mapped to "/")
---------------------------------------------------------
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, { internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel=function(label) setLabel = function(label)
local h = fs.open("/.label", "w") local h = fs.open("/.label", "w")
h.write(label) h.write(label)
h.close() h.close()
end, end,
getLabel=function() getLabel = function()
local h = fs.open("/.label", "r") local h = fs.open("/.label", "r")
if not h then return "$" end
local label = h.readAll() local label = h.readAll()
h.close() h.close()
return label return label
end end
}) })
---------------------------------------------------------
-- SCAN REAL DISK PERIPHERALS
---------------------------------------------------------
local function refresh() local function refresh()
-- remove disks that no longer exist
for id, _ in pairs(disks) do for id, _ in pairs(disks) do
if not peripheral.getType(id) then if not peripheral.getType(id) then disks[id] = nil end
disks[id] = nil
end
end end
-- detect new disks
for _, name in ipairs(peripheral.getNames()) do for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == "disk" then if peripheral.getType(name) == "disk" then
if not disks[name] then if not disks[name] then
@@ -165,28 +142,14 @@ local function refresh()
end end
end end
---------------------------------------------------------
-- ITERATOR
---------------------------------------------------------
local function iter() local function iter()
refresh() refresh()
-- first internal
local combined = {} local combined = {}
for id, obj in pairs(internal) do for id, obj in pairs(internal) do combined[id] = obj end
combined[id] = obj for id, obj in pairs(disks) do combined[id] = obj end
end
for id, obj in pairs(disks) do
combined[id] = obj
end
return pairs(combined) return pairs(combined)
end end
--------------------------------------------------------- return {refresh = refresh, list = iter}
-- MODULE RETURN
---------------------------------------------------------
return {
refresh = refresh,
list = iter
}

View File

@@ -1,6 +1,6 @@
--:Minify:-- -- :Minify:--
local apis=... local apis = ...
local keys=apis.keys local keys = apis.keys
local tKeys = {} local tKeys = {}
tKeys[keys.space] = ' ' tKeys[keys.space] = ' '
tKeys[keys.grave] = '`' tKeys[keys.grave] = '`'
@@ -63,13 +63,13 @@ tKeys[keys.pageUp] = '\x1b[5~'
tKeys[keys.pageDown] = '\x1b[6~' tKeys[keys.pageDown] = '\x1b[6~'
tKeys[keys.home] = '\x1b[1~' tKeys[keys.home] = '\x1b[1~'
tKeys[keys["end"]] = '\x1b[4~' tKeys[keys["end"]] = '\x1b[4~'
--tKeys[keys.capsLock] = '\x1b[capsLock' -- tKeys[keys.capsLock] = '\x1b[capsLock'
--tKeys[keys.scrollLock] = '\x1b[scrollLock' -- tKeys[keys.scrollLock] = '\x1b[scrollLock'
--tKeys[keys.numLock] = '\x1b[numLock' -- tKeys[keys.numLock] = '\x1b[numLock'
--if keys.printScreen then -- if keys.printScreen then
-- tKeys[keys.printScreen] = '\x1b[printScreen' -- tKeys[keys.printScreen] = '\x1b[printScreen'
--end -- end
--tKeys[keys.pause] = '\x1b[pause' -- tKeys[keys.pause] = '\x1b[pause'
tKeys[keys.f1] = '\x1b[11~' tKeys[keys.f1] = '\x1b[11~'
tKeys[keys.f2] = '\x1b[12~' tKeys[keys.f2] = '\x1b[12~'
tKeys[keys.f3] = '\x1b[13~' tKeys[keys.f3] = '\x1b[13~'
@@ -82,19 +82,19 @@ tKeys[keys.f9] = '\x1b[20~'
tKeys[keys.f10] = '\x1b[21~' tKeys[keys.f10] = '\x1b[21~'
tKeys[keys.f11] = '\x1b[23~' tKeys[keys.f11] = '\x1b[23~'
tKeys[keys.f12] = '\x1b[24~' tKeys[keys.f12] = '\x1b[24~'
--tKeys[keys.f13] = '\x1b[25~' -- tKeys[keys.f13] = '\x1b[25~'
--tKeys[keys.f14] = '\x1b[26~' -- tKeys[keys.f14] = '\x1b[26~'
--tKeys[keys.f15] = '\x1b[28~' -- tKeys[keys.f15] = '\x1b[28~'
--tKeys[keys.f16] = '\x1b[29~' -- tKeys[keys.f16] = '\x1b[29~'
--tKeys[keys.f17] = '\x1b[31~' -- tKeys[keys.f17] = '\x1b[31~'
--tKeys[keys.f18] = '\x1b[32~' -- tKeys[keys.f18] = '\x1b[32~'
--tKeys[keys.f19] = '\x1b[33~' -- tKeys[keys.f19] = '\x1b[33~'
--tKeys[keys.f20] = '\x1b[34~' -- tKeys[keys.f20] = '\x1b[34~'
--tKeys[keys.f21] = '\x1b[42~' -- tKeys[keys.f21] = '\x1b[42~'
--tKeys[keys.f22] = '\x1b[43~' -- tKeys[keys.f22] = '\x1b[43~'
--tKeys[keys.f23] = '\x1b[44~' -- tKeys[keys.f23] = '\x1b[44~'
--tKeys[keys.f24] = '\x1b[45~' -- tKeys[keys.f24] = '\x1b[45~'
--tKeys[keys.f25] = '\x1b[46~' -- tKeys[keys.f25] = '\x1b[46~'
-- Numpad -- Numpad
tKeys[keys.numPad0] = '0' tKeys[keys.numPad0] = '0'
@@ -108,15 +108,15 @@ tKeys[keys.numPad7] = '7'
tKeys[keys.numPad8] = '8' tKeys[keys.numPad8] = '8'
tKeys[keys.numPad9] = '9' tKeys[keys.numPad9] = '9'
--tKeys[340] = 'leftShift' -- tKeys[340] = 'leftShift'
--tKeys[341] = 'leftCtrl' -- tKeys[341] = 'leftCtrl'
--tKeys[342] = 'leftAlt' -- tKeys[342] = 'leftAlt'
--tKeys[343] = 'leftSuper' -- tKeys[343] = 'leftSuper'
--tKeys[344] = 'rightShift' -- tKeys[344] = 'rightShift'
--tKeys[345] = 'rightCtrl' -- tKeys[345] = 'rightCtrl'
--tKeys[346] = 'rightAlt' -- tKeys[346] = 'rightAlt'
--tKeys[347] = 'rightSuper' -- tKeys[347] = 'rightSuper'
--tKeys[348] = 'menu' -- tKeys[348] = 'menu'
local shift = false local shift = false
local ctrl = false local ctrl = false
@@ -178,26 +178,34 @@ end
local function p() local function p()
local str = "" local str = ""
if alt then if alt then str = str .. "\x1b" end
str=str.."\x1b" if ctrl then str = str .. "^" end
end
if ctrl then
str=str.."^"
end
return str return str
end end
return function(event, q) return function(event, q)
if event[1] == "key" then if event[1] == "key" then
if event[2]==keys.leftCtrl or event[2]==keys.rightCtrl then ctrl=true return if event[2] == keys.leftCtrl or event[2] == keys.rightCtrl then
elseif event[2]==keys.leftAlt or event[2]==keys.rightAlt then alt=true return ctrl = true
elseif event[2]==keys.leftShift or event[2]==keys.rightCtrl then shift=true return return
elseif event[2] == keys.leftAlt or event[2] == keys.rightAlt then
alt = true
return
elseif event[2] == keys.leftShift or event[2] == keys.rightCtrl then
shift = true
return
end end
q("keyTyped", 1, p()..s(tKeys[event[2]])) q("keyTyped", 1, p() .. s(tKeys[event[2]]))
elseif event[1] == "key_up" then elseif event[1] == "key_up" then
if event[2]==keys.leftCtrl or event[2]==keys.rightCtrl then ctrl=false return if event[2] == keys.leftCtrl or event[2] == keys.rightCtrl then
elseif event[2]==keys.leftAlt or event[2]==keys.rightAlt then alt=false return ctrl = false
elseif event[2]==keys.leftShift or event[2]==keys.rightCtrl then shift=false return return
elseif event[2] == keys.leftAlt or event[2] == keys.rightAlt then
alt = false
return
elseif event[2] == keys.leftShift or event[2] == keys.rightCtrl then
shift = false
return
end end
end end
end end

View File

@@ -1,17 +1,16 @@
--:Minify:-- -- :Minify:--
local kernel=... local kernel = ...
local apis=kernel.apis local apis = kernel.apis
local main=apis.term local main = apis.term
local native=apis.peripheral local native = apis.peripheral
local sides = {"top", "bottom", "left", "right", "front", "back"} local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name) local function getType(name)
if native.isPresent(name) then if native.isPresent(name) then return native.getType(name) end
return native.getType(name)
end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then if native.hasType(side, "peripheral_hub") and
native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name) return native.call(side, "getTypeRemote", name)
end end
end end
@@ -22,9 +21,7 @@ local function getNames()
local names = {} local names = {}
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.isPresent(side) then if native.isPresent(side) then table.insert(names, side) end
table.insert(names, side)
end
if native.hasType(side, "peripheral_hub") then if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides") local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do for _, hubSide in ipairs(hubSides) do
@@ -36,38 +33,37 @@ local function getNames()
end end
local function wrapPeripheral(name) local function wrapPeripheral(name)
if native.isPresent(name) then if native.isPresent(name) then return wrapPeripheral(name) end
return wrapPeripheral(name)
end
for n = 1, #sides do for n = 1, #sides do
local side = sides[n] local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then if native.hasType(side, "peripheral_hub") and
native.call(side, "isPresentRemote", name) then
return native.call(side, "wrapRemote", name) return native.call(side, "wrapRemote", name)
end end
end end
return nil return nil
end end
local icolors={ local icolors = {
[0x1] =1, -- #000000 [0x1] = 1, -- #000000
[0x2] =2, -- #FFFFFF [0x2] = 2, -- #FFFFFF
[0x4] =3, -- #FF0000 [0x4] = 3, -- #FF0000
[0x8] =4, -- #00FF00 [0x8] = 4, -- #00FF00
[0x10] =5, -- #0000FF [0x10] = 5, -- #0000FF
[0x20] =6, -- #00FFFF [0x20] = 6, -- #00FFFF
[0x40] =7, -- #FF00FF [0x40] = 7, -- #FF00FF
[0x80] =8, -- #FFFF00 [0x80] = 8, -- #FFFF00
[0x100] =9, -- #FF6D00 [0x100] = 9, -- #FF6D00
[0x200] =10, -- #6DFF55 [0x200] = 10, -- #6DFF55
[0x400] =11, -- #24FFFF [0x400] = 11, -- #24FFFF
[0x800] =12, -- #924900 [0x800] = 12, -- #924900
[0x1000] =13, -- #6D6D55 [0x1000] = 13, -- #6D6D55
[0x2000] =14, -- #DBDBAA [0x2000] = 14, -- #DBDBAA
[0x4000] =15, -- #6D00FF [0x4000] = 15, -- #6D00FF
[0x8000] =16 -- #B6FF00 [0x8000] = 16 -- #B6FF00
} }
local colors={ local colors = {
0x0001, -- #000000 0x0001, -- #000000
0x0002, -- #FFFFFF 0x0002, -- #FFFFFF
0x0004, -- #FF0000 0x0004, -- #FF0000
@@ -83,7 +79,7 @@ local colors={
0x1000, -- #6D6D55 0x1000, -- #6D6D55
0x2000, -- #DBDBAA 0x2000, -- #DBDBAA
0x4000, -- #6D00FF 0x4000, -- #6D00FF
0x8000 -- #B6FF00 0x8000 -- #B6FF00
} }
local function write(text, term) local function write(text, term)
@@ -121,7 +117,7 @@ local function write(text, term)
y = y + 1 y = y + 1
end end
if y-1 >= h then if y - 1 >= h then
term.scroll(1) term.scroll(1)
y = h y = h
term.setCursorPos(x, y) term.setCursorPos(x, y)
@@ -132,38 +128,24 @@ local function write(text, term)
end end
local function newTTY(term) local function newTTY(term)
local ret={} local ret = {}
function ret.print(text) function ret.print(text) write(text .. "\n", term) end
write(text.."\n", term) function ret.printInline(text) write(text, term) end
end
function ret.printInline(text)
write(text, term)
end
function ret.clear() function ret.clear()
term.clear() term.clear()
term.setCursorPos(1,1) term.setCursorPos(1, 1)
end
function ret.setCursorPos(x,y)
term.setCursorPos(x,y)
end
function ret.getCursorPos()
return term.getCursorPos()
end
function ret.getSize()
return term.getSize()
end end
function ret.setCursorPos(x, y) term.setCursorPos(x, y) end
function ret.getCursorPos() return term.getCursorPos() end
function ret.getSize() return term.getSize() end
function ret.setBackgroundColor(color) function ret.setBackgroundColor(color)
term.setBackgroundColor(colors[color]) term.setBackgroundColor(colors[color])
end end
function ret.setTextColor(color) function ret.setTextColor(color) term.setTextColor(colors[color]) end
term.setTextColor(colors[color])
end
function ret.getBackgroundColor() function ret.getBackgroundColor()
return icolors[term.getBackgroundColor()] return icolors[term.getBackgroundColor()]
end end
function ret.getTextColor() function ret.getTextColor() return icolors[term.getTextColor()] end
return icolors[term.getTextColor()]
end
return ret return ret
end end

View File

@@ -1 +1,3 @@
U $;/ U $;/
U devfs0000;/dev/
U tmpfs0000;/tmp/

View File

@@ -1,4 +1,4 @@
--:Minify:-- -- :Minify:--
local fs = {} local fs = {}
local disks = {} local disks = {}
local mounts = {} local mounts = {}
@@ -15,39 +15,42 @@ local function resolve(path)
local newPath = path:sub(#mountPoint + 1) local newPath = path:sub(#mountPoint + 1)
return disks[mounts[mountPoint]], newPath return disks[mounts[mountPoint]], newPath
end end
---------------------------------------------------------
function fs.update(initdisks) function fs.update(initdisks)
disks = {} disks = {}
for k, v in initdisks.list() do for k, v in initdisks.list() do disks[k] = v end
disks[k] = v
end
end end
function fs.exists(path) function fs.exists(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:directoryExists(newPath) or disk:fileExists(newPath) return disk:directoryExists(newPath) or disk:fileExists(newPath)
end end
function fs.isFile(path) function fs.isFile(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:fileExists(newPath) return disk:fileExists(newPath)
end end
function fs.isDir(path) function fs.isDir(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:directoryExists(newPath) return disk:directoryExists(newPath)
end end
function fs.list(path) function fs.list(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:list(newPath) return disk:list(newPath)
end end
function fs.makeDir(path) function fs.makeDir(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:makeDirectory(newPath) return disk:makeDirectory(newPath)
end end
function fs.remove(path) function fs.remove(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
return disk:remove(newPath) return disk:remove(newPath)
end end
function fs.readAllText(path) function fs.readAllText(path)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
local handle = disk:open(newPath, "r") local handle = disk:open(newPath, "r")
@@ -56,23 +59,26 @@ function fs.readAllText(path)
handle.close() handle.close()
return content return content
end end
function fs.writeAllText(path, text) function fs.writeAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
local handle = disk:open(newPath, "w") local handle = disk:open(newPath, "w")
handle.write(text) handle.write(text)
handle.close() handle.close()
end end
function fs.appendAllText(path, text) function fs.appendAllText(path, text)
local disk, newPath = resolve(path) local disk, newPath = resolve(path)
local handle = disk:open(newPath, "a") local handle = disk:open(newPath, "a")
handle.write(text) handle.write(text)
handle.close() handle.close()
end end
function fs.load(path)
return load(fs.readAllText(path), path) function fs.load(path) return load(fs.readAllText(path), path) end
end
function fs.mount(disk, mountPoint) function fs.mount(disk, mountPoint)
if not disks[disk] then return end if not disks[disk] then return end
mounts[mountPoint] = disk mounts[mountPoint] = disk
end end
return fs
return fs

View File

@@ -12,7 +12,7 @@ kernel.version="HyperionOS V1.0.0"
kernel.process = "Kernel" kernel.process = "Kernel"
kernel.username = "root" kernel.username = "root"
kernel.hostname = "hyperion" kernel.hostname = "hyperion"
kernel.groups = {0} kernel.groups = {}
kernel.uid = 0 kernel.uid = 0
kernel.gid = 0 kernel.gid = 0
kernel.status = "start" kernel.status = "start"
@@ -149,9 +149,6 @@ function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text) ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
end end
ifs.remove("/tmp")
ifs.makeDir("/tmp")
function kernel.newFifo() function kernel.newFifo()
local fifo = {} local fifo = {}
fifo.push=function(data) fifo.push=function(data)
@@ -241,6 +238,7 @@ kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
kernel.syscalls["version"]=function() return kernel.version end kernel.syscalls["version"]=function() return kernel.version end
kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end kernel.syscalls["setHostname"]=function(name) if kernel.uid~=0 then error("Permission denied") end kernel.hostname=name end
kernel.syscalls["setUsername"]=function(user) if kernel.uid~=0 then error("Permission denied") end kernel.currentTask.username=user end kernel.syscalls["setUsername"]=function(user) if kernel.uid~=0 then error("Permission denied") end kernel.currentTask.username=user end
kernel.syscalls["arch"]=function() return arch end
kernel.syscalls["test"]=function() return true end kernel.syscalls["test"]=function() return true end
kernel.log("Running modules") kernel.log("Running modules")

View File

@@ -1,61 +1,38 @@
--:Minify:-- -- :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
function string.hasPrefix(str, prefix) function string.hasPrefix(str, prefix)
return string.sub(str, 1, #prefix) == prefix return string.sub(str, 1, #prefix) == prefix
end end
function string.getSuffix(str, prefix) function string.getSuffix(str, prefix) return string.sub(str, #prefix + 1) end
return string.sub(str, #prefix+1)
end
function string.getPrefix(str, suffix) function string.getPrefix(str, suffix) return string.sub(str, 1, #suffix) end
return string.sub(str, 1, #suffix)
end
function string.join(str, ...) function string.join(str, ...) return table.concat(table.pack(str, ...)) end
return table.concat(table.pack(str, ...))
end
function string.delim(str, ...) function string.delim(str, ...) return table.concat(table.pack(...), str) end
return table.concat(table.pack(...), str)
end
function string.split(str, delim, maxResultCountOrNil) function string.split(str, delim, maxResultCountOrNil)
assert(#delim == 1, "only delim len 1 supported for now") assert(#delim == 1, "only delim len 1 supported for now")
maxResultCountOrNil = (maxResultCountOrNil or 0)-1 maxResultCountOrNil = (maxResultCountOrNil or 0) - 1
local rv = {} local rv = {}
local buf = "" local buf = ""
for i = 1, #str do for i = 1, #str do
local c = string.sub(str,i,i) local c = string.sub(str, i, i)
if #rv ~= maxResultCountOrNil and c == delim then if #rv ~= maxResultCountOrNil and c == delim then
table.insert(rv, buf) table.insert(rv, buf)
buf = "" buf = ""
else else
buf = buf..c buf = buf .. c
end end
end end
table.insert(rv, buf) table.insert(rv, buf)
return rv return rv
end 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) function table.deepcopy(orig, copies)
copies = copies or {} copies = copies or {}
@@ -78,98 +55,30 @@ function table.deepcopy(orig, copies)
end end
function table.hasKey(tabl, query) function table.hasKey(tabl, query)
for i,v in pairs(tabl) do for i, v in pairs(tabl) do if i == query then return v end end
if i==query then
return v
end
end
return false return false
end end
function table.hasVal(tabl, query) function table.hasVal(tabl, query)
for i,v in pairs(tabl) do for i, v in pairs(tabl) do if v == query then return i end end
if v==query then
return i
end
end
return false return false
end 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(tbl, seen) local function serialize(tbl, seen)
seen = seen or {} seen = seen or {}
-- If we've seen this table before, return a placeholder to prevent infinite loops -- If we've seen this table before, return a placeholder to prevent infinite loops
if seen[tbl] then if seen[tbl] then return '"[Circular Reference]"' end
return '"[Circular Reference]"'
end
-- Mark this table as seen -- Mark this table as seen
seen[tbl] = true seen[tbl] = true
local output = "{" local output = "{"
local first = true local first = true
for i, v in pairs(tbl) do for i, v in pairs(tbl) do
-- Handle comma placement more cleanly -- Handle comma placement more cleanly
if not first then if not first then output = output .. "," end
output = output .. ","
end
first = false first = false
-- Serialize Key -- Serialize Key
@@ -197,21 +106,19 @@ local function serialize(tbl, seen)
end end
seen[tbl] = nil seen[tbl] = nil
output = output .. "}" output = output .. "}"
return output return output
end end
local oldtype=type local oldtype = type
local oldgetmetatable=getmetatable local oldgetmetatable = getmetatable
function type(object, trueType) function type(object, trueType)
if trueType then if trueType then return oldtype(object) end
return oldtype(object) if oldtype(object) ~= "table" then
end
if oldtype(object)~="table" then
return oldtype(object) return oldtype(object)
else else
if oldtype(oldgetmetatable(object))=="table" then if oldtype(oldgetmetatable(object)) == "table" then
local metatable = oldgetmetatable(object) local metatable = oldgetmetatable(object)
---@diagnostic disable-next-line: need-check-nil ---@diagnostic disable-next-line: need-check-nil
if metatable.__type then return metatable.__type end if metatable.__type then return metatable.__type end
@@ -222,10 +129,10 @@ function type(object, trueType)
end end
function getmetatable(object) function getmetatable(object)
if oldtype(object)~="table" then return end if oldtype(object) ~= "table" then return end
if oldtype(oldgetmetatable(object))=="table" then if oldtype(oldgetmetatable(object)) == "table" then
if oldgetmetatable(object).__isuserdata then if oldgetmetatable(object).__isuserdata then
if oldtype(oldgetmetatable(object).__usermeta)=="function" then if oldtype(oldgetmetatable(object).__usermeta) == "function" then
return oldgetmetatable(object).__usermeta() return oldgetmetatable(object).__usermeta()
else else
return oldgetmetatable(object).__usermeta return oldgetmetatable(object).__usermeta
@@ -239,22 +146,14 @@ function getmetatable(object)
end end
function isEqualToAny(a, ...) function isEqualToAny(a, ...)
local args={...} local args = {...}
for i=0, #args do for i = 0, #args do if a == args[i] then return true end end
if a==args[i] then
return true
end
end
return false return false
end end
function isEqualToAll(a, ...) function isEqualToAll(a, ...)
local args={...} local args = {...}
for i=0, #args do for i = 0, #args do if a ~= args[i] then return false end end
if a~=args[i] then
return false
end
end
return true return true
end end
@@ -271,12 +170,39 @@ function table.values(t)
end end
function table.indexOf(t, value) function table.indexOf(t, value)
for i,v in ipairs(t) do for i, v in ipairs(t) do if v == value then return i end end
if v==value then return -1
return i end
function string.replace(s, target, repl)
local result = {}
local i = 1
local n = #s
local t_len = #target
while i <= n do
local match = true
if i + t_len - 1 <= n then
for j = 1, t_len do
if s:sub(i + j - 1, i + j - 1) ~= target:sub(j, j) then
match = false
break
end
end
else
match = false
end
if match then
table.insert(result, repl)
i = i + t_len
else
table.insert(result, s:sub(i, i))
i = i + 1
end end
end end
return -1
return table.concat(result)
end end
syscall = setmetatable({}, { syscall = setmetatable({}, {
@@ -292,4 +218,4 @@ syscall = setmetatable({}, {
end end
}) })
table.serialize=serialize table.serialize = serialize

View File

@@ -1,42 +1,41 @@
--:Minify:-- -- :Minify:--
local kernel=... local kernel = ...
local io = {} local io = {}
kernel.io=io kernel.io = io
io.eventq={} io.eventq = {}
function io.pushEvent(queue, ...) function io.pushEvent(queue, ...)
queue=tostring(queue) queue = tostring(queue)
if not io.eventq[queue] then if not io.eventq[queue] then io.eventq[queue] = {} end
io.eventq[queue]={} io.eventq[queue][#io.eventq[queue] + 1] = {...}
end
io.eventq[queue][#io.eventq[queue]+1]={...}
end end
function io.bind(queue) function io.bind(queue)
queue=tostring(queue) queue = tostring(queue)
kernel.currentTask.eventq=queue kernel.currentTask.eventq = queue
end end
function io.pullEvent() function io.pullEvent()
if io.eventq[kernel.currentTask.eventq] then if io.eventq[kernel.currentTask.eventq] then
if #io.eventq[kernel.currentTask.eventq]==1 then if #io.eventq[kernel.currentTask.eventq] == 1 then
local event = table.remove(io.eventq[kernel.currentTask.eventq] or {}, 1) local event = table.remove(io.eventq[kernel.currentTask.eventq] or {}, 1)
io.eventq[kernel.currentTask.eventq]=nil io.eventq[kernel.currentTask.eventq] = nil
return table.unpack(event) return table.unpack(event)
end end
local event = table.remove(io.eventq[kernel.currentTask.eventq] or {}, 1)
local event =
table.remove(io.eventq[kernel.currentTask.eventq] or {}, 1)
if not event then return end if not event then return end
return table.unpack(event) return table.unpack(event)
end end
end end
function io.getBoundQueue() function io.getBoundQueue() return kernel.currentTask.eventq end
return kernel.currentTask.eventq
end
kernel.syscalls["IO_pushEvent"]=io.pushEvent kernel.syscalls["IO_pushEvent"] = io.pushEvent
kernel.syscalls["IO_pullEvent"]=io.pullEvent kernel.syscalls["IO_pullEvent"] = io.pullEvent
kernel.syscalls["IO_bind"]=io.bind kernel.syscalls["IO_bind"] = io.bind
kernel.syscalls["IO_getBoundQueue"]=io.getBoundQueue kernel.syscalls["IO_getBoundQueue"] = io.getBoundQueue
kernel.log("IO pipeline initialized") kernel.log("IO pipeline initialized")

View File

@@ -1,15 +1,15 @@
--:Minify:-- -- :Minify:--
local kernel = ... local kernel = ...
local vfs = {} local vfs = {}
kernel.vfs=vfs kernel.vfs = vfs
vfs.mounts = { ["$"] = "/" } vfs.mounts = {["$"] = "/"}
vfs.disks = kernel.disks vfs.disks = kernel.disks
-- Path normalization -- Path normalization
local function normalizePath(path) local function normalizePath(path)
local task = kernel.currentTask local task = kernel.currentTask
local cwd = task.cwd or "/" local cwd = task.cwd or "/"
if path:sub(1,1) ~= "/" then path = cwd .. "/" .. path end if path:sub(1, 1) ~= "/" then path = cwd .. "/" .. path end
local parts = {} local parts = {}
for part in path:gmatch("[^/]+") do for part in path:gmatch("[^/]+") do
if part == ".." then if part == ".." then
@@ -21,22 +21,43 @@ local function normalizePath(path)
return "/" .. table.concat(parts, "/") return "/" .. table.concat(parts, "/")
end end
function vfs.splitPath(path)
local rv=string.split(path,"/")
while table.indexOf(rv, "") ~= -1 do
table.remove(rv, table.indexOf(rv, ""))
end
return rv
end
-- Resolve mount and disk path -- Resolve mount and disk path
local function resolvePath(path) local function resolvePath(path)
path = normalizePath(path) path = normalizePath(path)
local mountPoint = "/" local mountPoint = nil
local mountId = "$" local mountId = nil
for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then for id, mp in pairs(vfs.mounts) do
mountPoint = v if path == mp or (mp == "/" and path:sub(1, 1) == "/") or path:sub(1, #mp + 1) == mp .. "/" then
mountId = k if not mountPoint or #mp > #mountPoint then
mountPoint = mp
mountId = id
end
end end
end end
local diskPath = path:sub(#mountPoint) if not mountId then
if diskPath == "" then diskPath = "/" end error("ENODEV")
end
local diskPath = path:sub(#mountPoint + 1)
if diskPath == "" then
diskPath = "/"
end
if kernel.config.logPathResolution then
kernel.log("Path '"..path.."' resolved to disk '"..mountId.."' and path '"..diskPath.."'")
end
return vfs.disks[mountId], diskPath return vfs.disks[mountId], diskPath
end end
@@ -55,25 +76,26 @@ local function checkSystemLimit()
end end
-- File object constructor -- File object constructor
local function newFileObj(handle, mode, path, meta) local function newFileObj(handle, mode, path, meta, type)
return { return {
handle = handle, handle = handle,
mode = mode, mode = mode,
path = path, path = path,
meta = meta meta = meta,
type = type
} }
end end
-- Validate mode function vfs.newfd(fdobj)
local function ismode(mode) checkSystemLimit()
if not (mode == "r" or mode == "w" or mode == "a") then error("EINVAL") end total=total+1
local fd = allocFD(kernel.currentTask)
kernel.currentTask.fd[fd]=fdobj
end end
-- Parse metafile -- Parse metafile
local function parseMetafile(file) local function parseMetafile(file)
if not file or file == "" then if not file or file == "" then return {} end
return {}
end
local ret = {} local ret = {}
local pointer = 1 local pointer = 1
@@ -99,12 +121,7 @@ local function parseMetafile(file)
pointer = pointer + cmetalen pointer = pointer + cmetalen
end end
ret[name] = { ret[name] = {owner = owner, group = group, perms = perms, cmeta = cmeta}
owner = owner,
group = group,
perms = perms,
cmeta = cmeta
}
end end
return ret return ret
@@ -112,7 +129,7 @@ end
-- Build metafile -- Build metafile
local function makeMetafile(meta) local function makeMetafile(meta)
local file="" local file = ""
for name, m in pairs(meta) do for name, m in pairs(meta) do
local entry = "" local entry = ""
entry = entry .. string.char(#name) .. name entry = entry .. string.char(#name) .. name
@@ -129,22 +146,18 @@ local function getFileMeta(path)
fullPath = normalizePath(fullPath) fullPath = normalizePath(fullPath)
local parts = {} local parts = {}
for p in fullPath:gmatch("[^/]+") do for p in fullPath:gmatch("[^/]+") do table.insert(parts, p) end
table.insert(parts, p)
end
-- default fallback -- default fallback
local default = { owner=0, group=0, perms=62, cmeta="" } local default = {owner = 0, group = 0, perms = 63, cmeta = ""}
-- walk from deepest parent upward -- walk from deepest parent upward
for i = #parts, 1, -1 do for i = #parts, 1, -1 do
local parent = "/" .. table.concat(parts, "/", 1, i-1) local parent = "/" .. table.concat(parts, "/", 1, i - 1)
if parent ~= "/" then parent = parent .. "/" end if parent ~= "/" then parent = parent .. "/" end
local target = parts[i] local target = parts[i]
if target == ".meta" then if target == ".meta" then error("Cannot open metafile") end
error("Cannot open metafile")
end
local metaPath = parent .. ".meta" local metaPath = parent .. ".meta"
if disk:fileExists(metaPath) then if disk:fileExists(metaPath) then
@@ -153,9 +166,7 @@ local function getFileMeta(path)
f.close() f.close()
local parsed = parseMetafile(text) local parsed = parseMetafile(text)
if parsed[target] then if parsed[target] then return parsed[target] end
return parsed[target]
end
end end
end end
@@ -173,13 +184,9 @@ local function ensureParentMeta(path)
name = fullPath:gsub("^/", "") name = fullPath:gsub("^/", "")
end end
if name == ".meta" then if name == ".meta" then error("Cannot open metafile") end
error("Cannot open metafile")
end
if parent ~= "/" and parent:sub(-1) ~= "/" then if parent ~= "/" and parent:sub(-1) ~= "/" then parent = parent .. "/" end
parent = parent .. "/"
end
local metaPath = parent .. ".meta" local metaPath = parent .. ".meta"
@@ -192,27 +199,32 @@ local function ensureParentMeta(path)
return metaPath, name return metaPath, name
end end
-- Permission checking -- Permission checking
local function checkperms(meta, mode) local function checkperms(meta, mode)
local modes = { local modes = {
r = {owner=5, group=3, everyone=1}, r = {owner = 5, group = 3, everyone = 1},
w = {owner=4, group=2, everyone=0}, w = {owner = 4, group = 2, everyone = 0},
a = {owner=4, group=2, everyone=0} a = {owner = 4, group = 2, everyone = 0}
} }
local bits = meta.perms local bits = meta.perms
local function bit_is_set(num, bit) local function bit_is_set(num, bit)
return math.floor(num / (2^bit)) % 2 == 1 return math.floor(num / (2 ^ bit)) % 2 == 1
end end
if kernel.uid == 0 then return true end if kernel.uid == 0 then return true end
if kernel.uid == meta.owner and bit_is_set(bits, modes[mode].owner) then return true end if kernel.uid == meta.owner and bit_is_set(bits, modes[mode].owner) then
return true
end
if meta.group and kernel.groups then if meta.group and kernel.groups then
for _, gid in ipairs(kernel.groups) do for _, gid in ipairs(kernel.groups) do
if gid == meta.group and bit_is_set(bits, modes[mode].group) then return true end if gid == meta.group and bit_is_set(bits, modes[mode].group) then
return true
end
end end
end end
if bit_is_set(bits, modes[mode].everyone) then return true end if bit_is_set(bits, modes[mode].everyone) then return true end
error("EACCES") error("EACCES")
end end
@@ -220,39 +232,55 @@ end
-- mounts -- mounts
local function normalizeMountPoint(path) local function normalizeMountPoint(path)
path = normalizePath(path) path = normalizePath(path)
if path ~= "/" and path:sub(-1) == "/" then if path ~= "/" and path:sub(-1) == "/" then path = path:sub(1, -2) end
path = path:sub(1, -2)
end
return path return path
end end
local required = {
"open",
"type",
"list",
"attributes",
"fileExists",
"makeDirectory",
"remove"
}
local function check(disk)
for _, name in ipairs(required) do
if type(disk[name]) ~= "function" then
error("Invalid disk: missing method '" .. name .. "'")
end
end
end
function vfs.mount(target, diskOrId) function vfs.mount(target, diskOrId)
if kernel.uid ~= 0 then error("EPERM") end if kernel.uid ~= 0 then error("EPERM") end
if not target then error("EINVAL") end if not target then error("EINVAL") end
target = normalizeMountPoint(target) target = normalizeMountPoint(target)
if not vfs.exists(target) then vfs.mkdir(target) end
if vfs.type(target) ~= "directory" then error("EINVAL") end
local disk local disk
local id local id
if type(diskOrId) == "string" then if type(diskOrId) == "string" then
disk = kernel.disks[diskOrId] disk = kernel.disks[diskOrId]
id = diskOrId
if not disk then error("ENODEV") end if not disk then error("ENODEV") end
check(disk)
id = diskOrId
elseif type(diskOrId) == "table" then elseif type(diskOrId) == "table" then
check(disk)
disk = diskOrId disk = diskOrId
id = tostring(disk) id = disk.address
vfs.disks[id] = disk vfs.disks[id] = disk
else else
error("EINVAL") error("EINVAL")
end end
-- Prevent shadowing an existing mount -- Prevent shadowing an existing mount
for _, mp in pairs(vfs.mounts) do for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
if mp == target then
error("EBUSY")
end
end
vfs.mounts[id] = target vfs.mounts[id] = target
return true return true
@@ -277,7 +305,6 @@ end
-- Open file -- Open file
function vfs.open(path, mode) function vfs.open(path, mode)
ismode(mode)
checkSystemLimit() checkSystemLimit()
local task = kernel.currentTask local task = kernel.currentTask
local fd = allocFD(task) local fd = allocFD(task)
@@ -287,8 +314,13 @@ function vfs.open(path, mode)
local meta = getFileMeta(path) local meta = getFileMeta(path)
checkperms(meta, mode) checkperms(meta, mode)
local handle = disk:open(diskPath, mode) local handle
task.fd[fd] = newFileObj(handle, mode, path, meta) if disk:type(diskPath)~="directory" then
handle = disk:open(diskPath, mode)
if type(handle)~="table" then error("ENFILE") end
end
task.fd[fd] = newFileObj(handle, mode, path, meta, disk:type(diskPath))
total = total + 1 total = total + 1
return fd return fd
end end
@@ -298,6 +330,7 @@ function vfs.read(fd, count)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.read then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end if file.mode ~= "r" then error("EBADF") end
return file.handle.read(count or 1) return file.handle.read(count or 1)
end end
@@ -307,6 +340,7 @@ function vfs.write(fd, content)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.write then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
return file.handle.write(content) return file.handle.write(content)
end end
@@ -316,6 +350,8 @@ function vfs.pread(fd, count, offset)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.read then error("EBADF") end
if not file.handle.seek then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end if file.mode ~= "r" then error("EBADF") end
file.handle.seek("set", offset) file.handle.seek("set", offset)
return file.handle.read(count or 1) return file.handle.read(count or 1)
@@ -325,6 +361,8 @@ function vfs.pwrite(fd, content, offset)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.write then error("EBADF") end
if not file.handle.seek then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.seek("set", offset) file.handle.seek("set", offset)
return file.handle.write(content) return file.handle.write(content)
@@ -335,6 +373,7 @@ function vfs.lseek(fd, offset, whence)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.seek then error("EBADF") end
return file.handle.seek(whence or "set", offset) return file.handle.seek(whence or "set", offset)
end end
@@ -343,6 +382,7 @@ function vfs.fsync(fd)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
if not file.handle.flush then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.flush() file.handle.flush()
end end
@@ -352,7 +392,9 @@ function vfs.close(fd)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
if not file then error("EBADF") end if not file then error("EBADF") end
file.handle.close() if file.handle.close then
file.handle.close()
end
task.fd[fd] = nil task.fd[fd] = nil
total = total - 1 total = total - 1
end end
@@ -364,8 +406,11 @@ function vfs.sendfile(outfd, infd, count)
local outFile = task.fd[outfd] local outFile = task.fd[outfd]
if not inFile or not outFile then error("EBADF") end if not inFile or not outFile then error("EBADF") end
if inFile.mode ~= "r" then error("EBADF") end if inFile.mode ~= "r" then error("EBADF") end
if not inFile.handle.read then error("EBADF") end
if outFile.mode ~= "w" and outFile.mode ~= "a" then error("EBADF") end if outFile.mode ~= "w" and outFile.mode ~= "a" then error("EBADF") end
if not outFile.handle.write then error("EBADF") end
local data = inFile.handle.read(count or 1024) local data = inFile.handle.read(count or 1024)
if not data or data == "" then return end
return outFile.handle.write(data) return outFile.handle.write(data)
end end
@@ -403,12 +448,12 @@ end
-- Directory operations -- Directory operations
function vfs.listdir(path) function vfs.listdir(path)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
if disk:type(diskPath) ~= "directory" then error("ENOTDIR") end if disk:type(diskPath) ~= "directory" then error("ENOENT") end
local meta = getFileMeta(path) local meta = getFileMeta(path)
checkperms(meta, "r") checkperms(meta, "r")
local list = disk:list(diskPath) local list = disk:list(diskPath)
if table.indexOf(list,".meta")~=-1 then if table.indexOf(list, ".meta") ~= -1 then
table.remove(list,table.indexOf(list,".meta")) table.remove(list, table.indexOf(list, ".meta"))
end end
return list return list
end end
@@ -431,8 +476,8 @@ end
function vfs.chmod(path, perms) function vfs.chmod(path, perms)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
local meta = getFileMeta(path) local meta = getFileMeta(path)
checkperms(meta, "w")
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
meta.perms = perms meta.perms = perms
local mpath, target = ensureParentMeta(path) local mpath, target = ensureParentMeta(path)
@@ -449,7 +494,6 @@ function vfs.chmod(path, perms)
f.close() f.close()
end end
function vfs.fchmod(fd, perms) function vfs.fchmod(fd, perms)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
@@ -460,8 +504,8 @@ end
function vfs.chown(path, uid, gid) function vfs.chown(path, uid, gid)
local disk, diskPath = resolvePath(path) local disk, diskPath = resolvePath(path)
local meta = getFileMeta(path) local meta = getFileMeta(path)
checkperms(meta, "w")
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
meta.owner = uid meta.owner = uid
meta.group = gid meta.group = gid
@@ -479,7 +523,6 @@ function vfs.chown(path, uid, gid)
f.close() f.close()
end end
function vfs.fchown(fd, uid, gid) function vfs.fchown(fd, uid, gid)
local task = kernel.currentTask local task = kernel.currentTask
local file = task.fd[fd] local file = task.fd[fd]
@@ -501,13 +544,9 @@ function vfs.type(path)
return disk:type(diskPath) return disk:type(diskPath)
end end
function vfs.getcwd() function vfs.getcwd() return kernel.currentTask.cwd end
return kernel.currentTask.cwd
end
function vfs.chdir(path) function vfs.chdir(path) kernel.currentTask.cwd = path end
kernel.currentTask.cwd=path
end
-- Export syscalls -- Export syscalls
local sys = kernel.syscalls local sys = kernel.syscalls
@@ -531,9 +570,9 @@ sys["chown"] = vfs.chown
sys["fchown"] = vfs.fchown sys["fchown"] = vfs.fchown
sys["exists"] = vfs.exists sys["exists"] = vfs.exists
sys["type"] = vfs.type sys["type"] = vfs.type
sys["mount"] = vfs.mount sys["mount"] = vfs.mount
sys["umount"] = vfs.umount sys["umount"] = vfs.umount
sys["getcwd"] = vfs.getcwd sys["getcwd"] = vfs.getcwd
sys["chdir"] = vfs.chdir sys["chdir"] = vfs.chdir
kernel.log("VFS module loaded") kernel.log("VFS module loaded")

View File

@@ -1,37 +1,33 @@
--:Minify:-- -- :Minify:--
local kernel = ... local kernel = ...
local cache = {} local cache = {}
kernel.searchpaths = { kernel.searchpaths = {
"/lib/?.lua", "/lib/?.lua", "/lib/?", "/usr/lib/?.lua", "/usr/lib/?",
"/lib/?", "/usr/local/lib/?.lua", "/usr/local/lib/?", "?.lua", "?"
"/usr/lib/?.lua",
"/usr/lib/?",
"/usr/local/lib/?.lua",
"/usr/local/lib/?",
"?.lua",
"?"
} }
function require(module,...) function require(module, ...)
if cache[module] then if cache[module] then return cache[module] end
return cache[module]
end
local modpath = module:gsub("%.", "/") local modpath = module:gsub("%.", "/")
local failed = {} local failed = {}
for _, path in ipairs(kernel.searchpaths) do for _, path in ipairs(kernel.searchpaths) do
local full_path = string.gsub(path, "%?", modpath) local full_path = string.replace(path, "?", modpath)
if full_path:sub(1,1)~="/" then if full_path:sub(1, 1) ~= "/" then
full_path=kernel.currentTask.cwd..full_path full_path = kernel.currentTask.cwd .. full_path
end end
if kernel.vfs.exists(full_path) then if kernel.vfs.exists(full_path) then
if kernel.vfs.type(full_path)=="directory" then if kernel.vfs.type(full_path) == "directory" then
full_path = full_path .. "/init" full_path = full_path .. "/init"
end end
if kernel.vfs.exists(full_path) then if kernel.vfs.exists(full_path) then
local handle = kernel.vfs.open(full_path, "r") local handle = kernel.vfs.open(full_path, "r")
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4) local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.vfs.close(handle) kernel.vfs.close(handle)
return assert(load(file_content, full_path, "t", kernel._U))(...)
return
assert(load(file_content, full_path, "t", kernel._U))(...)
else else
table.insert(failed, full_path) table.insert(failed, full_path)
end end
@@ -39,5 +35,6 @@ function require(module,...)
table.insert(failed, full_path) table.insert(failed, full_path)
end end
end end
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")") error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
end end

View File

@@ -1,173 +1,143 @@
--:Minify:-- --:Minify:--
--local kernel = ... local kernel = ...
--
--local proxy = {} local proxy = {}
--local data = {} local data = {}
--
--proxy.address = "devfs0000" proxy.address = "devfs0000"
--proxy.isReadOnly = false proxy.isReadOnly = function() return false end
--proxy.spaceUsed = function() return 0 end proxy.spaceUsed = function() return 0 end
--proxy.spaceTotal = function() return 0 end proxy.spaceTotal = function() return 0 end
--proxy.makeDirectory = function() error("Permission denied") end proxy.makeDirectory = function() error("EACCES") end
--proxy.remove = function() error("Permission denied") end proxy.remove = function() error("EACCES") end
--proxy.setLabel = function() error("Permission denied") end proxy.setLabel = function() error("EACCES") end
--proxy.getLabel = function() return "devfs" end proxy.getLabel = function() return "devfs" end
--proxy.attributes = function(path) return { proxy.attributes = function(path) return {
-- type = proxy.type(path), size = 0,
-- isReadOnly = false, modified = 0,
-- size = 0, created = 0,
-- lastModified = 0, } end
-- created = 0,
-- Permissions = "666", function proxy:open(path, mode)
-- owner = "root", local steps = kernel.vfs.splitPath(path)
-- group = "root" local step = data
--} end for i=1, #steps-1 do
-- local dat = step[steps[i]]
--local function getNode(path) if type(dat) ~= "table" then error("ENFILE") end
-- local parts = string.split(path, "/") step=dat
-- if parts[1] == "" then end
-- table.remove(parts, 1) if type(step[steps[#steps]]) == "function" then
-- end return step[steps[#steps]]("open", mode)
-- end
-- local node = data error("ENFILE")
-- for _, part in ipairs(parts) do end
-- if node[part] then
-- node = node[part] function proxy:type(path, mode)
-- else local steps = kernel.vfs.splitPath(path)
-- return nil local step = data
-- end if #steps == 0 then
-- end return "directory"
-- end
-- return node for i=1, #steps-1 do
--end local dat = step[steps[i]]
-- if type(dat) ~= "table" then error("ENFILE") end
--proxy.type = function(path) step=dat
-- local node = getNode(path) end
-- if node then if type(step[steps[#steps]]) == "function" then
-- return node.type return step[steps[#steps]]("type", mode)
-- else end
-- return nil if type(step[steps[#steps]]) == "table" then
-- end return "directory"
--end end
-- error("ENOENT")
--proxy.list = function(path) end
-- local node = getNode(path)
-- if node and node.type == "directory" then function proxy:list(path)
-- local content = table.keys(node) local steps = kernel.vfs.splitPath(path)
-- table.remove(content, table.indexOf(content, "type")) local step = data
-- return content if #steps == 0 then
-- else return table.keys(data)
-- error("Not a directory") end
-- end for i=1, #steps-1 do
--end local dat = step[steps[i]]
-- if type(dat) ~= "table" then error("ENOENT") end
--proxy.open = function(path, mode) step=dat
-- local node = getNode(path) end
-- if node and (node.type == "file" or node.type == "character device") then if type(step[steps[#steps]]) == "table" then
-- if mode == "r" then return table.keys(step[steps[#steps]])
-- return { end
-- read = node.read, error("ENOENT")
-- close = function() end end
-- }
-- elseif mode == "w" then function proxy:fileExists(path)
-- return { local ok = pcall(function()
-- write = node.write, return self:type(path)
-- close = function() end end)
-- } return ok
-- else end
-- error("Invalid mode")
-- end function data.random(op, mode)
-- else if op=="type" then
-- error("Not a file"..type(node)) return "character device"
-- end elseif op=="open" then
--end if mode=="r" then
-- return {
--local function newStringFile(content) read=function(amount)
-- return { local str = ""
-- type = "file", for i=1, amount or 1 do
-- read = function() return content end, str=str..string.char(math.random(0, 255))
-- write = function(newContent) content = newContent end end
-- } return str
--end end
-- }
--local function newDirectory() elseif mode=="w" or mode=="a" then
-- return { return {
-- type = "directory" write=function() end
-- } }
--end else error("EACCES")
-- end
--data["random"] = { end
-- type = "character device", end
-- read = function(amount)
-- local result = "" function data.null(op, mode)
-- for _ = 1, amount do if op=="type" then
-- result = result .. string.char(math.random(0, 255)) return "character device"
-- end elseif op=="open" then
-- return result if mode=="r" then
-- end, return {
-- write = function() error("Permission denied") end read=function(amount) end
--} }
-- elseif mode=="w" or mode=="a" then
--data["null"] = { return {
-- type = "character device", write=function() end
-- read = function() return "" end, }
-- write = function() end else error("EACCES")
--} end
-- end
--data["zero"] = { end
-- type = "character device",
-- read = function(amount) function data.zero(op, mode)
-- return string.rep("\0", amount) if op=="type" then
-- end, return "character device"
-- write = function() error("Permission denied") end elseif op=="open" then
--} if mode=="r" then
-- return {
--data["rtc"] = { read=function(amount)
-- type = "character device", local str = ""
-- read = function() return kernel.computer:time() end, for i=1, amount or 1 do
-- write = function() error("Permission denied") end str=str..string.char(0)
--} end
-- return str
--data["rtc0"] = { end
-- type = "character device", }
-- read = function() return kernel.computer:time() end, elseif mode=="w" or mode=="a" then
-- write = function() error("Permission denied") end return {
--} write=function() end
-- }
--data["eeprom"] = { else error("EACCES")
-- type = "character device", end
-- read = function() return kernel.computer:getEEPROM() end, end
-- write = function(data) end
-- if kernel.uid ~= 0 then
-- error("Permission denied") data["disk"]={}
-- end kernel.disks["devfs0000"]=proxy
-- 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)

View File

@@ -0,0 +1,128 @@
local kernel = ...
local proxy = {}
local data = {}
proxy.address = "tmpfs0000"
proxy.isReadOnly = function() return false end
-- Space functions (just placeholders)
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
-- Writable operations
proxy.makeDirectory = function(_, path)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1,#steps do
if not step[steps[i]] then
step[steps[i]] = {}
elseif type(step[steps[i]]) ~= "table" then
error("ENOTDIR")
end
step = step[steps[i]]
end
end
proxy.remove = function(_, path)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1,#steps-1 do
step = step[steps[i]]
if not step then error("ENOENT") end
end
step[steps[#steps]] = nil
end
proxy.setLabel = function(_, label) end
proxy.getLabel = function() return "tmpfs" end
proxy.attributes = function(_, path)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1,#steps do
step = step[steps[i]]
if not step then error("ENOENT") end
end
return {
size = type(step) == "string" and #step or 0,
modified = 0,
created = 0,
}
end
-- Open files
function proxy:open(path, mode)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1,#steps-1 do
if not step[steps[i]] then
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
elseif type(step[steps[i]]) ~= "table" then
error("ENOTDIR")
end
step = step[steps[i]]
end
local filename = steps[#steps]
if mode == "r" then
if type(step[filename]) ~= "string" then error("ENOENT") end
local content = step[filename]
local pos = 1
return {
read = function(amount)
amount = amount or #content
local chunk = content:sub(pos, pos+amount-1)
pos = pos + #chunk
return chunk
end
}
elseif mode == "w" then
step[filename] = ""
return {
write = function(str)
step[filename] = str
end
}
elseif mode == "a" then
if type(step[filename]) ~= "string" then step[filename] = "" end
return {
write = function(str)
step[filename] = step[filename] .. str
end
}
else
error("EACCES")
end
end
function proxy:type(path)
local steps = kernel.vfs.splitPath(path)
local step = data
if #steps == 0 then return "directory" end
for i=1,#steps do
step = step[steps[i]]
if not step then error("ENOENT") end
end
if type(step) == "table" then return "directory" end
if type(step) == "string" then return "file" end
end
function proxy:list(path)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1,#steps do
step = step[steps[i]]
if not step then error("ENOENT") end
end
if type(step) ~= "table" then error("ENOTDIR") end
local keys = {}
for k,_ in pairs(step) do table.insert(keys, k) end
return keys
end
function proxy:fileExists(path)
return pcall(function() return self:type(path) end)
end
kernel.disks["tmpfs0000"] = proxy

View File

@@ -1,25 +1,23 @@
--:Minify:-- -- :Minify:--
local kernel = ... local kernel = ...
local timeout=false local timeout = false
kernel.processes.keventd = function() kernel.processes.keventd = function()
while true do while true do
local event = {kernel.computer:getMachineEvent()} local event = {kernel.computer:getMachineEvent()}
if event[1] then if event[1] then
if event[1]=="keyTyped" then if event[1] == "keyTyped" then
if event[3]=="\x1b^s" then if event[3] == "\x1b^s" then
kernel.shutdown() kernel.shutdown()
elseif event[3]=="\x1b^r" then elseif event[3] == "\x1b^r" then
kernel.reboot() kernel.reboot()
end end
end end
kernel.io.pushEvent("raw", table.unpack(event)) kernel.io.pushEvent("raw", table.unpack(event))
timeout=false timeout = false
else else
timeout=true timeout = true
end
if timeout then
sleep(.05)
end end
if timeout then sleep(.05) end
end end
end end

View File

@@ -1,18 +1,34 @@
--:Minify:-- --:Minify:--
local kernel=... local kernel = ...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then local function trim(str)
local id="" local s, e = 1, #str
for i=3,#v do while s <= e and (str:sub(s,s) == " " or str:sub(s,s) == "\t") do s = s + 1 end
if v:sub(i,i)==";" then while e >= s and (str:sub(e,e) == " " or str:sub(e,e) == "\t" or str:sub(e,e) == "\n" or str:sub(e,e) == "\r") do e = e - 1 end
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 8) goto endline end if s > e then return "" end
id=v:sub(3,i-1) return str:sub(s,e)
end
for _, line in ipairs(string.split(kernel.fstab, "\n")) do
line = trim(line)
if line ~= "" and line:sub(1,1) == "U" then
local semicolon_pos
for i = 3, #line do
if line:sub(i,i) == ";" then
semicolon_pos = i
break
end end
end end
local path=v:sub(#id+4)
if id~="$" then if not semicolon_pos or semicolon_pos == 3 then
kernel.vfs.mount(path, id) kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 8)
else
local id = line:sub(3, semicolon_pos - 1)
local path = trim(line:sub(semicolon_pos + 1))
kernel.log("Mounted "..id.." to "..path)
if id ~= "$" then
kernel.vfs.mount(path, id)
end
end end
::endline::
end end
end end

View File

@@ -6,5 +6,15 @@ function socket.socket()
end end
function socket.bind()
end
kernel.syscalls["ioctl"]=function(fd, method, ...)
if not kernel.currentTask.fd[fd] then error("EBADF") end
if not kernel.currentTask.fd[fd][method] then error("EINVAL") end
end
kernel.socket=socket kernel.socket=socket
kernel.log("Loaded socket module") kernel.log("Loaded socket module")

View File

@@ -1,24 +1,23 @@
--:Minify:-- -- :Minify:--
local args={...} local args = {...}
local kernel=args[1] local kernel = args[1]
kernel._G=_G kernel._G = _G
local function readonly(tbl) local function readonly(tbl)
return setmetatable({}, { return setmetatable({}, {
__index = function(_, key) __index = function(_, key)
local value = tbl[key] local value = tbl[key]
if type(value) == "table" then if type(value) == "table" then return readonly(value) end
return readonly(value)
end
return value return value
end, end,
__newindex = function(t,k,v) __newindex = function(t, k, v)
if kernel.config.allowGlobalOverwrites or kernel.allowGlobalOverwrites then if kernel.config.allowGlobalOverwrites or
rawset(tbl,k,v) kernel.allowGlobalOverwrites then
rawset(tbl, k, v)
return return
end end
error("Attempt to modify global variable '"..k.."'",2) error("Attempt to modify global variable '" .. k .. "'", 2)
end, end,
__pairs = function() __pairs = function()
@@ -45,15 +44,13 @@ local function readonly(tbl)
end end
end, end,
__len = function() __len = function() return #tbl end,
return #tbl
end,
__metatable = false, __metatable = false
}) })
end end
kernel._U=readonly(kernel._G) kernel._U = readonly(kernel._G)
kernel.allowGlobalOverwrites=true kernel.allowGlobalOverwrites = true
kernel._U._G=kernel._U kernel._U._G = kernel._U
kernel.allowGlobalOverwrites=false kernel.allowGlobalOverwrites = false

View File

@@ -1,72 +1,82 @@
--:Minify:-- -- :Minify:--
local kernel = ... local kernel = ...
local tasks = {} local tasks = {}
local sys = {} local sys = {}
local nextpid = 2 local nextpid = 2
kernel.exitMain=false kernel.exitMain = false
function sys.spawn(func, name, envars, args, tgid) function sys.spawn(func, name, envars, args, tgid)
local id = nextpid local id = nextpid
nextpid = nextpid + 1 nextpid = nextpid + 1
tasks[tostring(id)] = { tasks[tostring(id)] = {
coro=coroutine.create(function() coro = coroutine.create(function()
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {})) local ok, err = xpcall(func, debug.traceback,
table.unpack(args or {}))
if not ok then if not ok then
if kernel.config.logTaskExit then if kernel.config.logTaskExit then
kernel.log("Task "..tostring(id).." exited with err: "..tostring(err), "ERROR", 2) kernel.log(
"Task " .. tostring(id) .. " exited with err: " ..
tostring(err), "ERROR", 2)
end end
tasks[tostring(id)].status="Z" tasks[tostring(id)].status = "Z"
if type(err)=="number" then if type(err) == "number" then
tasks[tostring(id)].exit=err tasks[tostring(id)].exit = err
end end
else else
if kernel.config.logTaskExit then if kernel.config.logTaskExit then
if err then if err then
kernel.log("Task "..tostring(id).." exited with code: "..tostring(err), "INFO") kernel.log("Task " .. tostring(id) ..
" exited with code: " .. tostring(err),
"INFO")
else else
kernel.log("Task "..tostring(id).." exited without code", "INFO") kernel.log("Task " .. tostring(id) ..
" exited without code", "INFO")
end end
end end
tasks[tostring(id)].status="Z" tasks[tostring(id)].status = "Z"
if type(err)=="number" then if type(err) == "number" then
tasks[tostring(id)].exit=err tasks[tostring(id)].exit = err
end end
end end
end), end),
name=name or ("task"..tostring(id)), name = name or ("task" .. tostring(id)),
envars=envars or kernel.currentTask.envars, envars = envars or kernel.currentTask.envars,
args=args or {}, args = args or {},
status="R", status = "R",
pid=id, pid = id,
tgid=tgid or kernel.currentTask.tgid, tgid = tgid or kernel.currentTask.tgid,
username=kernel.username, username = kernel.username,
uid=kernel.uid, uid = kernel.uid,
fd={}, fd = {
exit="", [0]=kernel.currentTask.fd[0],
sleep=0, [1]=kernel.currentTask.fd[1],
ivs=0, [2]=kernel.currentTask.fd[2]
vs=0, },
children={}, sleep = 0,
parent=kernel.currentTask, ivs = 0,
siblings=kernel.currentTask.children, vs = 0,
syscallReturn={}, children = {},
cwd=kernel.currentTask.cwd, parent = kernel.currentTask,
term=kernel.currentTask.term, siblings = kernel.currentTask.children,
timeSlice=0, syscallReturn = {},
lastTime=0, cwd = kernel.currentTask.cwd,
totalTime=0, timeSlice = 0,
numRuns=0, lastTime = 0,
privacy=0, totalTime = 0,
debugger=false, numRuns = 0,
eventq=kernel.currentTask.eventq privacy = 0,
debugger = false,
eventq = kernel.currentTask.eventq
} }
table.insert(kernel.currentTask.children, tasks[tostring(id)]) table.insert(kernel.currentTask.children, tasks[tostring(id)])
return id return id
end end
function sys.sleep(s) function sys.sleep(s)
kernel.currentTask.status="S" kernel.currentTask.status = "S"
kernel.currentTask.sleep=kernel.computer:time()+s*1000 kernel.currentTask.sleep = kernel.computer:time() + s * 1000
coroutine.yield() coroutine.yield()
end end
@@ -75,164 +85,161 @@ function sys.getTask(pid)
local task = tasks[tostring(pid)] local task = tasks[tostring(pid)]
local children = {} local children = {}
local siblings = {} local siblings = {}
for i,v in ipairs(task.children) do
children[i]=v.pid for i, v in ipairs(task.children) do children[i] = v.pid end
end for i, v in ipairs(task.siblings) do siblings[i] = v.pid end
for i,v in ipairs(task.siblings) do
siblings[i]=v.pid
end
return { return {
name=task.name, name = task.name,
status=task.status, status = task.status,
pid=task.pid, pid = task.pid,
tgid=task.tgid, tgid = task.tgid,
username=task.username, username = task.username,
uid=task.uid, uid = task.uid,
exit=task.exit, exit = task.exit,
sleep=task.sleep, sleep = task.sleep,
ivs=task.ivs, ivs = task.ivs,
vs=task.vs, vs = task.vs,
children=children, children = children,
siblings=siblings, siblings = siblings,
parent=task.parent.pid, parent = task.parent.pid,
cwd=task.cwd, cwd = task.cwd,
term=task.term term = task.term
} }
end end
end end
function sys.collect(pid) function sys.collect(pid)
local children={} local children = {}
for i,v in ipairs(kernel.currentTask.children) do for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
children[i]=v.pid
end
if not tasks[tostring(pid)] then if not tasks[tostring(pid)] then
return false, "Task does not exist" return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) then
return false, "You do not own this task" return false, "You do not own this task"
elseif tasks[tostring(pid)].status~="Z" then
elseif tasks[tostring(pid)].status ~= "Z" then
return false, "Task must exit to collect status" return false, "Task must exit to collect status"
else else
tasks[tostring(pid)].reapTime=0 tasks[tostring(pid)].reapTime = 0
return true, tasks[tostring(pid)].exit return true, tasks[tostring(pid)].exit
end end
end end
function sys.kill(pid) function sys.kill(pid)
local children={} local children = {}
for i,v in ipairs(kernel.currentTask.children) do for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
children[i]=v.pid
end
if not tasks[tostring(pid)] then if not tasks[tostring(pid)] then
return false, "Task does not exist" return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task" return false, "You do not own this task"
elseif tasks[tostring(pid)].status=="Z" then
elseif tasks[tostring(pid)].status == "Z" then
return false, "Task is already dead" return false, "Task is already dead"
else else
tasks[tostring(pid)].status="Z" tasks[tostring(pid)].status = "Z"
return true return true
end end
end end
function sys.stop(pid) function sys.stop(pid)
local children={} local children = {}
for i,v in ipairs(kernel.currentTask.children) do for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
children[i]=v.pid
end
if not tasks[tostring(pid)] then if not tasks[tostring(pid)] then
return false, "Task does not exist" return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task" return false, "You do not own this task"
elseif tasks[tostring(pid)].status~="R" then
elseif tasks[tostring(pid)].status ~= "R" then
return false, "Cannot stop non running task" return false, "Cannot stop non running task"
else else
tasks[tostring(pid)].status="T" tasks[tostring(pid)].status = "T"
return true return true
end end
end end
function sys.continue(pid) function sys.continue(pid)
local children={} local children = {}
for i,v in ipairs(kernel.currentTask.children) do for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
children[i]=v.pid
end
if not tasks[tostring(pid)] then if not tasks[tostring(pid)] then
return false, "Task does not exist" return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task" return false, "You do not own this task"
elseif tasks[tostring(pid)].status~="T" then
elseif tasks[tostring(pid)].status ~= "T" then
return false, "Task is not stopped" return false, "Task is not stopped"
else else
tasks[tostring(pid)].status="R" tasks[tostring(pid)].status = "R"
return true return true
end end
end end
function sys.getpid() function sys.getpid() return kernel.currentTask.pid end
return kernel.currentTask.pid
end
function sys.getppid() function sys.getppid() return kernel.currentTask.parent.pid end
return kernel.currentTask.parent.pid
end
function sys.getTasks() function sys.getTasks()
local ret={} local ret = {}
for i,v in pairs(tasks) do for i, v in pairs(tasks) do ret[#ret + 1] = v.pid end
ret[#ret+1]=v.pid
end
return ret return ret
end end
function sys.getEnviron(key) function sys.getEnviron(key) return kernel.currentTask.envars[key] end
return kernel.currentTask.envars[key]
end
function sys.setEnviron(key, value) function sys.setEnviron(key, value) kernel.currentTask.envars[key] = value end
kernel.currentTask.envars[key]=value
end
function sys.exit(code) function sys.exit(code)
if kernel.config.logTaskExit then if kernel.config.logTaskExit then
if code then if code then
kernel.log("Task "..tostring(kernel.currentTask.pid).." exited with code: "..tostring(code), "INFO") kernel.log("Task " .. tostring(kernel.currentTask.pid) .. " exited with code: " .. tostring(code), "INFO")
else else
kernel.log("Task "..tostring(kernel.currentTask.pid).." exited without code", "INFO") kernel.log("Task " .. tostring(kernel.currentTask.pid) .. " exited without code", "INFO")
end end
end end
tasks[tostring(kernel.currentTask.pid)].status="Z"
if type(code)=="number" then tasks[tostring(kernel.currentTask.pid)].status = "Z"
tasks[tostring(kernel.currentTask.pid)].exit=code if type(code) == "number" then
tasks[tostring(kernel.currentTask.pid)].exit = code
end end
end end
function sys.setuid(uid) function sys.setuid(uid)
if kernel.uid~=0 then error("EACCES") end if kernel.uid ~= 0 then error("EACCES") end
kernel.currentTask.uid=uid kernel.currentTask.uid = uid
end end
function sys.getuid() function sys.getuid() return kernel.currentTask.uid end
return kernel.currentTask.uid
end
local sysc=kernel.syscalls local sysc = kernel.syscalls
sysc["spawn"]=sys.spawn sysc["spawn"] = sys.spawn
sysc["sleep"]=sys.sleep sysc["sleep"] = sys.sleep
sysc["getTask"]=sys.getTask sysc["getTask"] = sys.getTask
sysc["collect"]=sys.collect sysc["collect"] = sys.collect
sysc["kill"]=sys.kill sysc["kill"] = sys.kill
sysc["stop"]=sys.stop sysc["stop"] = sys.stop
sysc["continue"]=sys.continue sysc["continue"] = sys.continue
sysc["getpid"]=sys.getpid sysc["getpid"] = sys.getpid
sysc["getppid"]=sys.getppid sysc["getppid"] = sys.getppid
sysc["getTasks"]=sys.getTasks sysc["getTasks"] = sys.getTasks
sysc["setEnviron"]=sys.setEnviron sysc["setEnviron"] = sys.setEnviron
sysc["getEnviron"]=sys.getEnviron sysc["getEnviron"] = sys.getEnviron
sysc["exit"]=sys.exit sysc["exit"] = sys.exit
sysc["setuid"]=sys.setuid sysc["setuid"] = sys.setuid
sysc["getuid"]=sys.getuid sysc["getuid"] = sys.getuid
kernel._G.sleep=function(...)coroutine.yield("syscall","sleep",...)end kernel._G.sleep = function(...) coroutine.yield("syscall", "sleep", ...) end
local function reapDeadTasks() local function reapDeadTasks()
for pid, task in pairs(tasks) do for pid, task in pairs(tasks) do
@@ -243,32 +250,33 @@ local function reapDeadTasks()
task.args = nil task.args = nil
task.envars = nil task.envars = nil
task.cwd = nil task.cwd = nil
task.term = nil
task.numRuns = nil task.numRuns = nil
task.totalTime = nil task.totalTime = nil
task.lastTime = nil task.lastTime = nil
task.timeSlice = nil task.timeSlice = nil
task.syscallReturn = nil task.syscallReturn = nil
task.sleep = nil task.sleep = nil
for v,_ in ipairs(task.fd) do for v, _ in ipairs(task.fd) do kernel.vfs.close(v) end
kernel.vfs.close(v)
end
task.fd = nil task.fd = nil
task.debugger=nil task.debugger = nil
task.privacy=nil task.privacy = nil
task.reapTime = kernel.computer:time() + 30000 task.reapTime = kernel.computer:time() + 30000
elseif task.reapTime and kernel.computer:time() > task.reapTime and task.status=="Z" then
for _,child in ipairs(task.children) do elseif task.reapTime and kernel.computer:time() > task.reapTime and
task.status == "Z" then
for _, child in ipairs(task.children) do
child.parent = tasks["1"] child.parent = tasks["1"]
child.siblings = tasks["1"].children child.siblings = tasks["1"].children
table.insert(tasks["1"].children, child) table.insert(tasks["1"].children, child)
end end
for i, sibling in ipairs(task.siblings) do for i, sibling in ipairs(task.siblings) do
if sibling.pid == task.pid then if sibling.pid == task.pid then
table.remove(task.siblings, i) table.remove(task.siblings, i)
break break
end end
end end
tasks[pid] = nil tasks[pid] = nil
end end
end end
@@ -296,8 +304,8 @@ function kernel.main()
for pid, task in pairs(tasks) do for pid, task in pairs(tasks) do
if task.status == "S" then if task.status == "S" then
if kernel.computer:time() >= task.sleep then if kernel.computer:time() >= task.sleep then
task.status="R" task.status = "R"
task.sleep=0 task.sleep = 0
end end
end end
if task.status == "R" then if task.status == "R" then
@@ -314,9 +322,20 @@ function kernel.main()
local startTime = kernel.computer:time() local startTime = kernel.computer:time()
local ret local ret
if kernel.config.preempt then if kernel.config.preempt then
ret = {coroutine.resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn))} ret = {
coroutine.resumeWithTimeout(
task.coro,
task.timeSlice,
table.unpack(task.syscallReturn)
)
}
else else
ret = {coroutine.resume(task.coro, table.unpack(task.syscallReturn))} ret = {
coroutine.resume(
task.coro,
table.unpack(task.syscallReturn)
)
}
end end
local elapsed = kernel.computer:time() - startTime local elapsed = kernel.computer:time() - startTime
@@ -331,45 +350,70 @@ function kernel.main()
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
-- handle task results -- handle task results
if ret[1] == "error" or ret[1]==false then if ret[1] == "error" or ret[1] == false then
kernel.log("processHandlerException: "..ret[2], "ERROR", 2) kernel.log("processHandlerException: " .. ret[2], "ERROR", 2)
task.status = "Z" task.status = "Z"
task.exit = "processHandlerException: "..ret[2] task.exit = "processHandlerException: " .. ret[2]
elseif ret[1] == "timeout" then elseif ret[1] == "timeout" then
task.ivs=task.ivs+1 task.ivs = task.ivs + 1
task.syscallReturn = {} task.syscallReturn = {}
elseif ret[1] == "success" or ret[1] == true then elseif ret[1] == "success" or ret[1] == true then
task.vs=task.vs+1 task.vs = task.vs + 1
if ret[2]=="syscall" then
if ret[2] == "syscall" then
if kernel.syscalls[ret[3]] then if kernel.syscalls[ret[3]] then
if kernel.config.debugSyscalls then if kernel.config.debugSyscalls then
kernel.log("Task "..task.pid.." invoking syscall: "..ret[3], "DBUG", 5) kernel.log("Task " .. task.pid .. " invoking syscall: " .. ret[3], "DBUG", 5)
for i=4,#ret do
kernel.log(" inval["..tostring(i-3).."] = "..tostring(ret[i]), "DBUG", 5) for i = 4, #ret do
kernel.log(" inval[" .. tostring(i - 3) .. "] = " .. tostring(ret[i]), "DBUG", 5)
end end
end end
local sysret = {xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))}
local sysret = {
xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))
}
if kernel.config.debugSyscalls then if kernel.config.debugSyscalls then
if not sysret[1] then if not sysret[1] then
kernel.log("Task "..task.pid.." syscall "..ret[3].." failed: "..tostring(sysret[2]), "ERROR", 2) kernel.log(
"Task " .. task.pid .. " syscall " .. ret[3] .. " failed: " .. tostring(sysret[2]), "ERROR", 2
)
else else
kernel.log("Task "..task.pid.." syscall "..ret[3].." completed returning "..tostring(#sysret-1).." values", "DBUG", 5) kernel.log(
for i=2,#sysret do "Task " .. task.pid .. " syscall " .. ret[3] .. " completed returning " .. tostring(#sysret - 1) .. " values", "DBUG", 5
if type(sysret[i])=="table" then )
kernel.log(" retval["..tostring(i-1).."] = "..table.serialize(sysret[i]), "DBUG", 5)
for i = 2, #sysret do
if type(sysret[i]) == "table" then
kernel.log(
" retval[" .. tostring(i - 1) .. "] = " .. table.serialize(sysret[i]),"DBUG", 5
)
else else
kernel.log(" retval["..tostring(i-1).."] = "..tostring(sysret[i]), "DBUG", 5) kernel.log(
" retval[" .. tostring(i - 1) .. "] = " .. tostring(sysret[i]), "DBUG", 5
)
end end
end end
end end
end end
if not sysret[1] then if not sysret[1] then
task.syscallReturn={false, sysret[2]} task.syscallReturn = {false, sysret[2]}
else else
task.syscallReturn={true, table.unpack(sysret,2)} task.syscallReturn = {
true, table.unpack(sysret, 2)
}
end end
else else
task.syscallReturn={false, "Unknown syscall: "..tostring(ret[3])} task.syscallReturn = {
false, "Unknown syscall: " .. tostring(ret[3])
}
end end
end end
end end
@@ -378,17 +422,18 @@ function kernel.main()
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0 local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
local T_prev_var = 0 local T_prev_var = 0
for _, t in ipairs(taskTimes) do for _, t in ipairs(taskTimes) do
T_prev_var = T_prev_var + (t - T_prev_avg)^2 T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
end end
if N > 0 then T_prev_var = T_prev_var / N end if N > 0 then T_prev_var = T_prev_var / N end
if N > 0 then if N > 0 then
local f_clamp = k_min*(Tmin_hit/N) - k_max*(Tmax_hit/N) 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) local B_budget = (C_target * (N ^ (alpha - 1))) /
B = B + lambda_budget * (B_budget - B) math.max(T_prev_avg, 1e-8)
+ lambda_clamp * f_clamp B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp -
- lambda_var * T_prev_var lambda_var * T_prev_var
end end
-- clean up dead tasks -- clean up dead tasks
@@ -396,5 +441,5 @@ function kernel.main()
end end
end end
kernel.tasks=tasks kernel.tasks = tasks
kernel.hpv=sys kernel.hpv = sys

View File

@@ -0,0 +1,15 @@
local kernel=...
local sysc=kernel.syscalls
kernel.gpio={}
sysc["gpio_write"]=function(pin, data)
if kernel.gpio[pin] then
return kernel.gpio[pin]("w", data)
end
end
sysc["gpio_read"]=function(pin)
if kernel.gpio[pin] then
return kernel.gpio[pin]("r")
end
end

View File

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

View File

@@ -1,28 +1,24 @@
--:Minify:-- -- :Minify:--
local kernel=... local kernel = ...
function print(...) function print(...)
local args={...} local args = {...}
local output="" local output = ""
for i=1,#args do for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
output=output..tostring(args[i]).."\t" output = output:sub(1, -2)
end
output=output:sub(1,-2)
syscall.TTY_print(output) syscall.TTY_print(output)
end end
function printf(fmt, ...) function printf(fmt, ...)
coroutine.yield() coroutine.yield()
local output=string.format(fmt,...) local output = string.format(fmt, ...)
syscall.TTY_print(output) syscall.TTY_print(output)
end end
function printInline(...) function printInline(...)
coroutine.yield() coroutine.yield()
local args={...} local args = {...}
local output="" local output = ""
for i=1,#args do for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
output=output..tostring(args[i]).."\t" output = output:sub(1, -2)
end
output=output:sub(1,-2)
syscall.TTY_printInline(output) syscall.TTY_printInline(output)
end end

View File

@@ -1,48 +1,48 @@
--:Minify:-- -- :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)
local handle = kernel.vfs.open(kernel.config.initPath, "r") local handle = kernel.vfs.open(kernel.config.initPath, "r")
local data = kernel.vfs.read(handle, 1024 * 1024 * 4) local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.vfs.close(handle) kernel.vfs.close(handle)
local initFunc, err = load(data, "@sysinit", "t", kernel._U) local initFunc, err = load(data, "@sysinit", "t", kernel._U)
if not initFunc then if not initFunc then error("Failed to load init system: " .. err) end
error("Failed to load init system: "..err)
end
kernel.tasks["1"] = { kernel.tasks["1"] = {
coro=coroutine.create(function() coro = coroutine.create(function()
local ok, err = xpcall(initFunc, debug.traceback, kernel) local ok, err = xpcall(initFunc, debug.traceback, kernel)
if not ok then if not ok then
kernel.panic("Init system crashed: "..tostring(err)) kernel.panic("Init system crashed: " .. tostring(err))
else else
kernel.panic("Init system exited: "..tostring(err)) kernel.panic("Init system exited: " .. tostring(err))
end end
end), end),
name="sysinit",
status="R", name = "sysinit",
pid=1, status = "R",
tgid=1, pid = 1,
username="root", tgid = 1,
uid=0, username = "root",
fd={}, uid = 0,
envars={}, fd = {},
args={}, envars = {},
exit="", args = {},
sleep=0, exit = "",
ivs=0, sleep = 0,
vs=0, ivs = 0,
parent=kernel.kernelTask, vs = 0,
siblings=kernel.kernelTask.children, parent = kernel.kernelTask,
children={}, siblings = kernel.kernelTask.children,
syscallReturn={}, children = {},
cwd="/", syscallReturn = {},
timeSlice=0, cwd = "/",
lastTime=0, timeSlice = 0,
totalTime=0, lastTime = 0,
numRuns=0 totalTime = 0,
numRuns = 0
} }
kernel.log("created init task with PID 1") kernel.log("created init task with PID 1")
kernel.log("Initializing init system...") kernel.log("Initializing init system...")