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
+2
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):
```lua
kernel.PANIC("Test panic message")
OR
kernel.log("Test log message")
```
---
+11 -8
View File
@@ -10,6 +10,7 @@ local pid=syscall.getpid()
local proc=0
local fs=require("sys.fs")
local timeout=false
syscall.setEnviron("SHELL","simpleshell")
printInline("> ")
while true do
local event = {syscall.IO_pullEvent()}
@@ -29,10 +30,11 @@ while true do
stopInput=false
else
local path=nil
if fs.exists("/bin/"..str) then
path="/bin/"..str
elseif fs.exists("/bin/"..str..".lua") then
path="/bin/"..str..".lua"
local split=string.split(str, " ")
if fs.exists("/bin/"..split[1]) then
path="/bin/"..split[1]
elseif fs.exists("/bin/"..split[1]..".lua") then
path="/bin/"..split[1]..".lua"
end
if not path then
print("Program not found")
@@ -46,11 +48,13 @@ while true do
printInline("> ")
end
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)
end
str=""
end
elseif event[1]=="keyTyped" and event[3]=="^d" then
syscall.exit(0)
else
str=str..event[3]
printInline(event[3])
@@ -64,7 +68,9 @@ while true do
if stopInput then
local exited, code = syscall.collect(proc)
if exited then
if code then
print("\nTask exited with code:\n"..tostring(code))
end
printInline("> ")
stopInput=false
else
@@ -74,9 +80,6 @@ while true do
print("Terminated")
printInline("> ")
stopInput=false
elseif event[1]=="keyTyped" and event[3]=="^d" then
syscall.kill(proc)
syscall.exit(0)
else
syscall.IO_pushEvent("bash:"..tostring(pid), table.unpack(event))
end
+8
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)
View File
+1
View File
@@ -0,0 +1 @@
syscall.TTY_clear()
+6 -2
View File
@@ -1,7 +1,11 @@
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
if fs.isDir(v) then
if fs.isDir(dir..v) then
print(v.."/")
else
print(v)
+1 -1
View File
@@ -21,7 +21,7 @@ while true do
if str == "" then
printInline("> ")
stopInput=false
elseif str == "exit" then
elseif str == "exit()" then
break
else
local func=load(str,"@Lua","t",luaEnv)
+1
View File
@@ -0,0 +1 @@
print(syscall.getcwd())
+32 -29
View File
@@ -128,7 +128,9 @@ local ok, err = xpcall(function()
local function getFile(path)
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()
file.close()
return content
@@ -138,18 +140,11 @@ local ok, err = xpcall(function()
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
local fs = load(getFile(BOOT_DRIVE_PATH .. "/boot/initfs"), "@InitFs")()
local key = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/keys.lua"),"@keyhelper")(apis)
if not Kernel then
displaySuperBadError("Could not load kernel.")
end
if not initFs then
displaySuperBadError("Could not load initdisks.")
end
if not fs then
displaySuperBadError("Could not load initfs.")
end
if not key then
displaySuperBadError("Could not load key helper.")
end
if not Kernel then displaySuperBadError("Could not load kernel.") end
if not initFs then displaySuperBadError("Could not load initdisks.") end
if not fs then displaySuperBadError("Could not load initfs.") end
if not key then displaySuperBadError("Could not load key helper.") end
local eventQueue = {}
@@ -169,9 +164,7 @@ local ok, err = xpcall(function()
return nil
end
end,
getEEPROM = function()
return getFile("/startup.lua")
end,
getEEPROM = function() return getFile("/startup.lua") end,
setEEPROM = function(_, text)
local h = apis.fs.open("/startup.lua", "w")
h.write(text)
@@ -224,21 +217,33 @@ local ok, err = xpcall(function()
local kernelCoro = coroutine.create(function()
---@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,
clear=function() apis.term.clear() apis.term.setCursorPos(1,1) end,
setCursorPos=function(_,x,y) apis.term.setCursorPos(x,y) end,
clear = function()
apis.term.clear()
apis.term.setCursorPos(1, 1)
end,
setCursorPos = function(_, x, y)
apis.term.setCursorPos(x, y)
end,
getCursorPos = function() return apis.term.getCursorPos() end,
getSize = function() return apis.term.getSize() end,
setBackgroundColor=function(_,color) apis.term.setBackgroundColor(colors[color]) end,
setTextColor=function(_,color) apis.term.setTextColor(colors[color]) end,
getBackgroundColor=function() return icolors[apis.term.getBackgroundColor()] end,
getTextColor=function() return icolors[apis.term.getTextColor()] end
}, computer, fs, "$")
if not ok then
displaySuperBadError(err)
setBackgroundColor = function(_, color)
apis.term.setBackgroundColor(colors[color])
end,
setTextColor = function(_, color)
apis.term.setTextColor(colors[color])
end,
getBackgroundColor = function()
return icolors[apis.term.getBackgroundColor()]
end,
getTextColor = function()
return icolors[apis.term.getTextColor()]
end
}, computer, fs, "$")
if not ok then displaySuperBadError(err) end
end)
-- time is in milliseconds
@@ -289,7 +294,5 @@ local ok, err = xpcall(function()
end
end, debug.traceback)
if not ok then
displaySuperBadError("Fatal error during boot: "..err)
end
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
while true do coroutine.yield() end
@@ -16,7 +16,6 @@ local BOOT_DRIVE_PATH=({...})[1] or "/$"
-- * `turtle.equip[Left|Right]`
-- Licensed under the MIT license
local args = {...}
if _HOST:find("UnBIOS") then return end
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
local t = {}
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
@@ -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
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
_G._HOST = _G._HOST .. " (UnBIOS)"
-- Set up TLCO
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
-- this would cause `parallel` to throw an error, but we replace `error` with an
+17 -54
View File
@@ -7,12 +7,11 @@ local peripheral = {}
local sides = {"top", "bottom", "left", "right", "front", "back"}
function peripheral.getType(name)
if native.isPresent(name) then
return native.getType(name)
end
if native.isPresent(name) then return native.getType(name) end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
if native.hasType(side, "peripheral_hub") and
native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
@@ -23,9 +22,7 @@ function peripheral.getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.isPresent(side) then table.insert(names, side) end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
@@ -36,21 +33,14 @@ function peripheral.getNames()
return names
end
---------------------------------------------------------
-- STORAGE
---------------------------------------------------------
local disks = {} -- real disks
local internal = {} -- "$" disk
local disks = {}
local internal = {}
---------------------------------------------------------
-- HELPERS
---------------------------------------------------------
local function norm(path)
if not path or path == "" then return "/" end
return fs.combine("/", path)
end
--- Creates a disk object given a base path
local function createDisk(id, basePath, readonly, periph)
basePath = norm(basePath)
@@ -60,13 +50,13 @@ local function createDisk(id, basePath, readonly, periph)
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
end
function disk:spaceTotal()
return fs.getCapacity(basePath)
end
function disk:spaceTotal() return fs.getCapacity(basePath) end
function disk:list(path)
local p = fs.combine(basePath, path)
if not fs.exists(p) or not fs.isDir(p) then return nil, "not directory" end
if not fs.exists(p) or not fs.isDir(p) then
return nil, "not directory"
end
return fs.list(p)
end
@@ -103,13 +93,9 @@ local function createDisk(id, basePath, readonly, periph)
return true
end
function disk:setLabel(label)
periph.setLabel(label)
end
function disk:setLabel(label) periph.setLabel(label) end
function disk:getLabel(label)
return periph.getLabel()
end
function disk:getLabel(label) return periph.getLabel() end
function disk:attributes(path)
local p = fs.combine(basePath, path)
@@ -124,9 +110,6 @@ local function createDisk(id, basePath, readonly, periph)
return disk
end
---------------------------------------------------------
-- INTERNAL DISK "$" (mapped to "/")
---------------------------------------------------------
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
setLabel = function(label)
local h = fs.open("/.label", "w")
@@ -135,24 +118,18 @@ internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
end,
getLabel = function()
local h = fs.open("/.label", "r")
if not h then return "$" end
local label = h.readAll()
h.close()
return label
end
})
---------------------------------------------------------
-- SCAN REAL DISK PERIPHERALS
---------------------------------------------------------
local function refresh()
-- remove disks that no longer exist
for id, _ in pairs(disks) do
if not peripheral.getType(id) then
disks[id] = nil
end
if not peripheral.getType(id) then disks[id] = nil end
end
-- detect new disks
for _, name in ipairs(peripheral.getNames()) do
if peripheral.getType(name) == "disk" then
if not disks[name] then
@@ -165,28 +142,14 @@ local function refresh()
end
end
---------------------------------------------------------
-- ITERATOR
---------------------------------------------------------
local function iter()
refresh()
-- first internal
local combined = {}
for id, obj in pairs(internal) do
combined[id] = obj
end
for id, obj in pairs(disks) do
combined[id] = obj
end
for id, obj in pairs(internal) do combined[id] = obj end
for id, obj in pairs(disks) do combined[id] = obj end
return pairs(combined)
end
---------------------------------------------------------
-- MODULE RETURN
---------------------------------------------------------
return {
refresh = refresh,
list = iter
}
return {refresh = refresh, list = iter}
+20 -12
View File
@@ -178,26 +178,34 @@ end
local function p()
local str = ""
if alt then
str=str.."\x1b"
end
if ctrl then
str=str.."^"
end
if alt then str = str .. "\x1b" end
if ctrl then str = str .. "^" end
return str
end
return function(event, q)
if event[1] == "key" then
if event[2]==keys.leftCtrl or event[2]==keys.rightCtrl then ctrl=true 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
if event[2] == keys.leftCtrl or event[2] == keys.rightCtrl then
ctrl = true
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
q("keyTyped", 1, p() .. s(tKeys[event[2]]))
elseif event[1] == "key_up" then
if event[2]==keys.leftCtrl or event[2]==keys.rightCtrl then ctrl=false 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
if event[2] == keys.leftCtrl or event[2] == keys.rightCtrl then
ctrl = false
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
@@ -6,12 +6,11 @@ local native=apis.peripheral
local sides = {"top", "bottom", "left", "right", "front", "back"}
local function getType(name)
if native.isPresent(name) then
return native.getType(name)
end
if native.isPresent(name) then return native.getType(name) end
for n = 1, #sides do
local side = sides[n]
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
if native.hasType(side, "peripheral_hub") and
native.call(side, "isPresentRemote", name) then
return native.call(side, "getTypeRemote", name)
end
end
@@ -22,9 +21,7 @@ local function getNames()
local names = {}
for n = 1, #sides do
local side = sides[n]
if native.isPresent(side) then
table.insert(names, side)
end
if native.isPresent(side) then table.insert(names, side) end
if native.hasType(side, "peripheral_hub") then
local hubSides = native.call(side, "getConnectedSides")
for _, hubSide in ipairs(hubSides) do
@@ -36,12 +33,11 @@ local function getNames()
end
local function wrapPeripheral(name)
if native.isPresent(name) then
return wrapPeripheral(name)
end
if native.isPresent(name) then return wrapPeripheral(name) end
for n = 1, #sides do
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)
end
end
@@ -133,37 +129,23 @@ end
local function newTTY(term)
local ret = {}
function ret.print(text)
write(text.."\n", term)
end
function ret.printInline(text)
write(text, term)
end
function ret.print(text) write(text .. "\n", term) end
function ret.printInline(text) write(text, term) end
function ret.clear()
term.clear()
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
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)
term.setBackgroundColor(colors[color])
end
function ret.setTextColor(color)
term.setTextColor(colors[color])
end
function ret.setTextColor(color) term.setTextColor(colors[color]) end
function ret.getBackgroundColor()
return icolors[term.getBackgroundColor()]
end
function ret.getTextColor()
return icolors[term.getTextColor()]
end
function ret.getTextColor() return icolors[term.getTextColor()] end
return ret
end
+2
View File
@@ -1 +1,3 @@
U $;/
U devfs0000;/dev/
U tmpfs0000;/tmp/
+13 -7
View File
@@ -15,39 +15,42 @@ local function resolve(path)
local newPath = path:sub(#mountPoint + 1)
return disks[mounts[mountPoint]], newPath
end
---------------------------------------------------------
function fs.update(initdisks)
disks = {}
for k, v in initdisks.list() do
disks[k] = v
end
for k, v in initdisks.list() do disks[k] = v end
end
function fs.exists(path)
local disk, newPath = resolve(path)
return disk:directoryExists(newPath) or disk:fileExists(newPath)
end
function fs.isFile(path)
local disk, newPath = resolve(path)
return disk:fileExists(newPath)
end
function fs.isDir(path)
local disk, newPath = resolve(path)
return disk:directoryExists(newPath)
end
function fs.list(path)
local disk, newPath = resolve(path)
return disk:list(newPath)
end
function fs.makeDir(path)
local disk, newPath = resolve(path)
return disk:makeDirectory(newPath)
end
function fs.remove(path)
local disk, newPath = resolve(path)
return disk:remove(newPath)
end
function fs.readAllText(path)
local disk, newPath = resolve(path)
local handle = disk:open(newPath, "r")
@@ -56,23 +59,26 @@ function fs.readAllText(path)
handle.close()
return content
end
function fs.writeAllText(path, text)
local disk, newPath = resolve(path)
local handle = disk:open(newPath, "w")
handle.write(text)
handle.close()
end
function fs.appendAllText(path, text)
local disk, newPath = resolve(path)
local handle = disk:open(newPath, "a")
handle.write(text)
handle.close()
end
function fs.load(path)
return load(fs.readAllText(path), path)
end
function fs.load(path) return load(fs.readAllText(path), path) end
function fs.mount(disk, mountPoint)
if not disks[disk] then return end
mounts[mountPoint] = disk
end
return fs
+2 -4
View File
@@ -12,7 +12,7 @@ kernel.version="HyperionOS V1.0.0"
kernel.process = "Kernel"
kernel.username = "root"
kernel.hostname = "hyperion"
kernel.groups = {0}
kernel.groups = {}
kernel.uid = 0
kernel.gid = 0
kernel.status = "start"
@@ -149,9 +149,6 @@ function kernel.saveLog()
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
end
ifs.remove("/tmp")
ifs.makeDir("/tmp")
function kernel.newFifo()
local fifo = {}
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["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["arch"]=function() return arch end
kernel.syscalls["test"]=function() return true end
kernel.log("Running modules")
@@ -7,21 +7,13 @@ function string.hasPrefix(str, prefix)
return string.sub(str, 1, #prefix) == prefix
end
function string.getSuffix(str, prefix)
return string.sub(str, #prefix+1)
end
function string.getSuffix(str, prefix) return string.sub(str, #prefix + 1) end
function string.getPrefix(str, suffix)
return string.sub(str, 1, #suffix)
end
function string.getPrefix(str, suffix) return string.sub(str, 1, #suffix) end
function string.join(str, ...)
return table.concat(table.pack(str, ...))
end
function string.join(str, ...) return table.concat(table.pack(str, ...)) end
function string.delim(str, ...)
return table.concat(table.pack(...), str)
end
function string.delim(str, ...) return table.concat(table.pack(...), str) end
function string.split(str, delim, maxResultCountOrNil)
assert(#delim == 1, "only delim len 1 supported for now")
@@ -41,21 +33,6 @@ function string.split(str, delim, maxResultCountOrNil)
return rv
end
function string.replace(str, search, replacement)
local rv = ""
local consumedLen = 1
local i = 1
while i<#str do
if string.sub(str, i, i+#search-1) == search then
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
i=i+#search
consumedLen = i
end
i=i+1
end
return rv .. string.sub(str, consumedLen)
end
function table.deepcopy(orig, copies)
copies = copies or {}
@@ -78,86 +55,20 @@ function table.deepcopy(orig, copies)
end
function table.hasKey(tabl, query)
for i,v in pairs(tabl) do
if i==query then
return v
end
end
for i, v in pairs(tabl) do if i == query then return v end end
return false
end
function table.hasVal(tabl, query)
for i,v in pairs(tabl) do
if v==query then
return i
end
end
for i, v in pairs(tabl) do if v == query then return i end end
return false
end
function table.proxy(tbl)
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
local function createProxy(t)
if type(t) ~= "table" then return t end
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
local proxy = {}
proxies[t] = proxy
local mt
mt = {
__index = function(_, k)
local value = t[k]
if type(value) == "table" then
return createProxy(value) -- recursively proxy subtables
else
return value
end
end,
__newindex = function()
error("Attempt to modify table proxy", 2)
end,
__pairs = function()
return function(_, k)
local nextKey, nextValue = next(t, k)
if type(nextValue) == "table" then
nextValue = createProxy(nextValue)
end
return nextKey, nextValue
end, nil, nil
end,
__ipairs = function()
local i = 0
local n = #t
return function()
i = i + 1
if i <= n then
local v = t[i]
if type(v) == "table" then
v = createProxy(v)
end
return i, v
end
end
end,
__metatable = false
}
setmetatable(proxy, mt)
return proxy
end
return createProxy(tbl)
end
local function serialize(tbl, seen)
seen = seen or {}
-- If we've seen this table before, return a placeholder to prevent infinite loops
if seen[tbl] then
return '"[Circular Reference]"'
end
if seen[tbl] then return '"[Circular Reference]"' end
-- Mark this table as seen
seen[tbl] = true
@@ -167,9 +78,7 @@ local function serialize(tbl, seen)
for i, v in pairs(tbl) do
-- Handle comma placement more cleanly
if not first then
output = output .. ","
end
if not first then output = output .. "," end
first = false
-- Serialize Key
@@ -205,9 +114,7 @@ end
local oldtype = type
local oldgetmetatable = getmetatable
function type(object, trueType)
if trueType then
return oldtype(object)
end
if trueType then return oldtype(object) end
if oldtype(object) ~= "table" then
return oldtype(object)
else
@@ -240,21 +147,13 @@ end
function isEqualToAny(a, ...)
local args = {...}
for i=0, #args do
if a==args[i] then
return true
end
end
for i = 0, #args do if a == args[i] then return true end end
return false
end
function isEqualToAll(a, ...)
local args = {...}
for i=0, #args do
if a~=args[i] then
return false
end
end
for i = 0, #args do if a ~= args[i] then return false end end
return true
end
@@ -271,14 +170,41 @@ function table.values(t)
end
function table.indexOf(t, value)
for i,v in ipairs(t) do
if v==value then
return i
end
end
for i, v in ipairs(t) do if v == value then return i end end
return -1
end
function string.replace(s, target, repl)
local result = {}
local i = 1
local n = #s
local t_len = #target
while i <= n do
local match = true
if i + t_len - 1 <= n then
for j = 1, t_len do
if s:sub(i + j - 1, i + j - 1) ~= target:sub(j, j) then
match = false
break
end
end
else
match = false
end
if match then
table.insert(result, repl)
i = i + t_len
else
table.insert(result, s:sub(i, i))
i = i + 1
end
end
return table.concat(result)
end
syscall = setmetatable({}, {
__index = function(self, name)
return function(...)
@@ -6,9 +6,7 @@ io.eventq={}
function io.pushEvent(queue, ...)
queue = tostring(queue)
if not io.eventq[queue] then
io.eventq[queue]={}
end
if not io.eventq[queue] then io.eventq[queue] = {} end
io.eventq[queue][#io.eventq[queue] + 1] = {...}
end
@@ -24,15 +22,16 @@ function io.pullEvent()
io.eventq[kernel.currentTask.eventq] = nil
return table.unpack(event)
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
return table.unpack(event)
end
end
function io.getBoundQueue()
return kernel.currentTask.eventq
end
function io.getBoundQueue() return kernel.currentTask.eventq end
kernel.syscalls["IO_pushEvent"] = io.pushEvent
kernel.syscalls["IO_pullEvent"] = io.pullEvent
@@ -21,21 +21,42 @@ local function normalizePath(path)
return "/" .. table.concat(parts, "/")
end
function vfs.splitPath(path)
local rv=string.split(path,"/")
while table.indexOf(rv, "") ~= -1 do
table.remove(rv, table.indexOf(rv, ""))
end
return rv
end
-- Resolve mount and disk path
local function resolvePath(path)
path = normalizePath(path)
local mountPoint = "/"
local mountId = "$"
for k,v in pairs(vfs.mounts) do
if path:sub(1,#v) == v and #v > #mountPoint then
mountPoint = v
mountId = k
local mountPoint = nil
local mountId = nil
for id, mp in pairs(vfs.mounts) do
if path == mp or (mp == "/" and path:sub(1, 1) == "/") or path:sub(1, #mp + 1) == mp .. "/" then
if not mountPoint or #mp > #mountPoint then
mountPoint = mp
mountId = id
end
end
end
local diskPath = path:sub(#mountPoint)
if diskPath == "" then diskPath = "/" end
if not mountId then
error("ENODEV")
end
local diskPath = path:sub(#mountPoint + 1)
if diskPath == "" then
diskPath = "/"
end
if kernel.config.logPathResolution then
kernel.log("Path '"..path.."' resolved to disk '"..mountId.."' and path '"..diskPath.."'")
end
return vfs.disks[mountId], diskPath
end
@@ -55,25 +76,26 @@ local function checkSystemLimit()
end
-- File object constructor
local function newFileObj(handle, mode, path, meta)
local function newFileObj(handle, mode, path, meta, type)
return {
handle = handle,
mode = mode,
path = path,
meta = meta
meta = meta,
type = type
}
end
-- Validate mode
local function ismode(mode)
if not (mode == "r" or mode == "w" or mode == "a") then error("EINVAL") end
function vfs.newfd(fdobj)
checkSystemLimit()
total=total+1
local fd = allocFD(kernel.currentTask)
kernel.currentTask.fd[fd]=fdobj
end
-- Parse metafile
local function parseMetafile(file)
if not file or file == "" then
return {}
end
if not file or file == "" then return {} end
local ret = {}
local pointer = 1
@@ -99,12 +121,7 @@ local function parseMetafile(file)
pointer = pointer + cmetalen
end
ret[name] = {
owner = owner,
group = group,
perms = perms,
cmeta = cmeta
}
ret[name] = {owner = owner, group = group, perms = perms, cmeta = cmeta}
end
return ret
@@ -129,12 +146,10 @@ local function getFileMeta(path)
fullPath = normalizePath(fullPath)
local parts = {}
for p in fullPath:gmatch("[^/]+") do
table.insert(parts, p)
end
for p in fullPath:gmatch("[^/]+") do table.insert(parts, p) end
-- 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
for i = #parts, 1, -1 do
@@ -142,9 +157,7 @@ local function getFileMeta(path)
if parent ~= "/" then parent = parent .. "/" end
local target = parts[i]
if target == ".meta" then
error("Cannot open metafile")
end
if target == ".meta" then error("Cannot open metafile") end
local metaPath = parent .. ".meta"
if disk:fileExists(metaPath) then
@@ -153,9 +166,7 @@ local function getFileMeta(path)
f.close()
local parsed = parseMetafile(text)
if parsed[target] then
return parsed[target]
end
if parsed[target] then return parsed[target] end
end
end
@@ -173,13 +184,9 @@ local function ensureParentMeta(path)
name = fullPath:gsub("^/", "")
end
if name == ".meta" then
error("Cannot open metafile")
end
if name == ".meta" then error("Cannot open metafile") end
if parent ~= "/" and parent:sub(-1) ~= "/" then
parent = parent .. "/"
end
if parent ~= "/" and parent:sub(-1) ~= "/" then parent = parent .. "/" end
local metaPath = parent .. ".meta"
@@ -192,7 +199,6 @@ local function ensureParentMeta(path)
return metaPath, name
end
-- Permission checking
local function checkperms(meta, mode)
local modes = {
@@ -207,12 +213,18 @@ local function checkperms(meta, mode)
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
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
if bit_is_set(bits, modes[mode].everyone) then return true end
error("EACCES")
end
@@ -220,39 +232,55 @@ end
-- mounts
local function normalizeMountPoint(path)
path = normalizePath(path)
if path ~= "/" and path:sub(-1) == "/" then
path = path:sub(1, -2)
end
if path ~= "/" and path:sub(-1) == "/" then path = path:sub(1, -2) end
return path
end
local required = {
"open",
"type",
"list",
"attributes",
"fileExists",
"makeDirectory",
"remove"
}
local function check(disk)
for _, name in ipairs(required) do
if type(disk[name]) ~= "function" then
error("Invalid disk: missing method '" .. name .. "'")
end
end
end
function vfs.mount(target, diskOrId)
if kernel.uid ~= 0 then error("EPERM") end
if not target then error("EINVAL") end
target = normalizeMountPoint(target)
if not vfs.exists(target) then vfs.mkdir(target) end
if vfs.type(target) ~= "directory" then error("EINVAL") end
local disk
local id
if type(diskOrId) == "string" then
disk = kernel.disks[diskOrId]
id = diskOrId
if not disk then error("ENODEV") end
check(disk)
id = diskOrId
elseif type(diskOrId) == "table" then
check(disk)
disk = diskOrId
id = tostring(disk)
id = disk.address
vfs.disks[id] = disk
else
error("EINVAL")
end
-- Prevent shadowing an existing mount
for _, mp in pairs(vfs.mounts) do
if mp == target then
error("EBUSY")
end
end
for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
vfs.mounts[id] = target
return true
@@ -277,7 +305,6 @@ end
-- Open file
function vfs.open(path, mode)
ismode(mode)
checkSystemLimit()
local task = kernel.currentTask
local fd = allocFD(task)
@@ -287,8 +314,13 @@ function vfs.open(path, mode)
local meta = getFileMeta(path)
checkperms(meta, mode)
local handle = disk:open(diskPath, mode)
task.fd[fd] = newFileObj(handle, mode, path, meta)
local handle
if disk:type(diskPath)~="directory" then
handle = disk:open(diskPath, mode)
if type(handle)~="table" then error("ENFILE") end
end
task.fd[fd] = newFileObj(handle, mode, path, meta, disk:type(diskPath))
total = total + 1
return fd
end
@@ -298,6 +330,7 @@ function vfs.read(fd, count)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.read then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end
return file.handle.read(count or 1)
end
@@ -307,6 +340,7 @@ function vfs.write(fd, content)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.write then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
return file.handle.write(content)
end
@@ -316,6 +350,8 @@ function vfs.pread(fd, count, offset)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.read then error("EBADF") end
if not file.handle.seek then error("EBADF") end
if file.mode ~= "r" then error("EBADF") end
file.handle.seek("set", offset)
return file.handle.read(count or 1)
@@ -325,6 +361,8 @@ function vfs.pwrite(fd, content, offset)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.write then error("EBADF") end
if not file.handle.seek then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.seek("set", offset)
return file.handle.write(content)
@@ -335,6 +373,7 @@ function vfs.lseek(fd, offset, whence)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.seek then error("EBADF") end
return file.handle.seek(whence or "set", offset)
end
@@ -343,6 +382,7 @@ function vfs.fsync(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if not file.handle.flush then error("EBADF") end
if file.mode ~= "w" and file.mode ~= "a" then error("EBADF") end
file.handle.flush()
end
@@ -352,7 +392,9 @@ function vfs.close(fd)
local task = kernel.currentTask
local file = task.fd[fd]
if not file then error("EBADF") end
if file.handle.close then
file.handle.close()
end
task.fd[fd] = nil
total = total - 1
end
@@ -364,8 +406,11 @@ function vfs.sendfile(outfd, infd, count)
local outFile = task.fd[outfd]
if not inFile or not outFile 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 not outFile.handle.write then error("EBADF") end
local data = inFile.handle.read(count or 1024)
if not data or data == "" then return end
return outFile.handle.write(data)
end
@@ -403,7 +448,7 @@ end
-- Directory operations
function vfs.listdir(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)
checkperms(meta, "r")
local list = disk:list(diskPath)
@@ -431,8 +476,8 @@ end
function vfs.chmod(path, perms)
local disk, diskPath = resolvePath(path)
local meta = getFileMeta(path)
checkperms(meta, "w")
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
meta.perms = perms
local mpath, target = ensureParentMeta(path)
@@ -449,7 +494,6 @@ function vfs.chmod(path, perms)
f.close()
end
function vfs.fchmod(fd, perms)
local task = kernel.currentTask
local file = task.fd[fd]
@@ -460,8 +504,8 @@ end
function vfs.chown(path, uid, gid)
local disk, diskPath = resolvePath(path)
local meta = getFileMeta(path)
checkperms(meta, "w")
if meta.owner ~= kernel.currentTask.uid then error("EACCES") end
meta.owner = uid
meta.group = gid
@@ -479,7 +523,6 @@ function vfs.chown(path, uid, gid)
f.close()
end
function vfs.fchown(fd, uid, gid)
local task = kernel.currentTask
local file = task.fd[fd]
@@ -501,13 +544,9 @@ function vfs.type(path)
return disk:type(diskPath)
end
function vfs.getcwd()
return kernel.currentTask.cwd
end
function vfs.getcwd() return kernel.currentTask.cwd end
function vfs.chdir(path)
kernel.currentTask.cwd=path
end
function vfs.chdir(path) kernel.currentTask.cwd = path end
-- Export syscalls
local sys = kernel.syscalls
@@ -2,36 +2,32 @@
local kernel = ...
local cache = {}
kernel.searchpaths = {
"/lib/?.lua",
"/lib/?",
"/usr/lib/?.lua",
"/usr/lib/?",
"/usr/local/lib/?.lua",
"/usr/local/lib/?",
"?.lua",
"?"
"/lib/?.lua", "/lib/?", "/usr/lib/?.lua", "/usr/lib/?",
"/usr/local/lib/?.lua", "/usr/local/lib/?", "?.lua", "?"
}
function require(module, ...)
if cache[module] then
return cache[module]
end
if cache[module] then return cache[module] end
local modpath = module:gsub("%.", "/")
local failed = {}
for _, path in ipairs(kernel.searchpaths) do
local full_path = string.gsub(path, "%?", modpath)
local full_path = string.replace(path, "?", modpath)
if full_path:sub(1, 1) ~= "/" then
full_path = kernel.currentTask.cwd .. full_path
end
if kernel.vfs.exists(full_path) then
if kernel.vfs.type(full_path) == "directory" then
full_path = full_path .. "/init"
end
if kernel.vfs.exists(full_path) then
local handle = kernel.vfs.open(full_path, "r")
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.vfs.close(handle)
return assert(load(file_content, full_path, "t", kernel._U))(...)
return
assert(load(file_content, full_path, "t", kernel._U))(...)
else
table.insert(failed, full_path)
end
@@ -39,5 +35,6 @@ function require(module,...)
table.insert(failed, full_path)
end
end
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
end
@@ -1,173 +1,143 @@
--:Minify:--
--local kernel = ...
--
--local proxy = {}
--local data = {}
--
--proxy.address = "devfs0000"
--proxy.isReadOnly = false
--proxy.spaceUsed = function() return 0 end
--proxy.spaceTotal = function() return 0 end
--proxy.makeDirectory = function() error("Permission denied") end
--proxy.remove = function() error("Permission denied") end
--proxy.setLabel = function() error("Permission denied") end
--proxy.getLabel = function() return "devfs" end
--proxy.attributes = function(path) return {
-- type = proxy.type(path),
-- isReadOnly = false,
-- size = 0,
-- lastModified = 0,
-- created = 0,
-- Permissions = "666",
-- owner = "root",
-- group = "root"
--} end
--
--local function getNode(path)
-- local parts = string.split(path, "/")
-- if parts[1] == "" then
-- table.remove(parts, 1)
-- end
--
-- local node = data
-- for _, part in ipairs(parts) do
-- if node[part] then
-- node = node[part]
-- else
-- return nil
-- end
-- end
--
-- return node
--end
--
--proxy.type = function(path)
-- local node = getNode(path)
-- if node then
-- return node.type
-- else
-- return nil
-- end
--end
--
--proxy.list = function(path)
-- local node = getNode(path)
-- if node and node.type == "directory" then
-- local content = table.keys(node)
-- table.remove(content, table.indexOf(content, "type"))
-- return content
-- else
-- error("Not a directory")
-- end
--end
--
--proxy.open = function(path, mode)
-- local node = getNode(path)
-- if node and (node.type == "file" or node.type == "character device") then
-- if mode == "r" then
-- return {
-- read = node.read,
-- close = function() end
-- }
-- elseif mode == "w" then
-- return {
-- write = node.write,
-- close = function() end
-- }
-- else
-- error("Invalid mode")
-- end
-- else
-- error("Not a file"..type(node))
-- end
--end
--
--local function newStringFile(content)
-- return {
-- type = "file",
-- read = function() return content end,
-- write = function(newContent) content = newContent end
-- }
--end
--
--local function newDirectory()
-- return {
-- type = "directory"
-- }
--end
--
--data["random"] = {
-- type = "character device",
-- read = function(amount)
-- local result = ""
-- for _ = 1, amount do
-- result = result .. string.char(math.random(0, 255))
-- end
-- return result
-- end,
-- write = function() error("Permission denied") end
--}
--
--data["null"] = {
-- type = "character device",
-- read = function() return "" end,
-- write = function() end
--}
--
--data["zero"] = {
-- type = "character device",
-- read = function(amount)
-- return string.rep("\0", amount)
-- end,
-- write = function() error("Permission denied") end
--}
--
--data["rtc"] = {
-- type = "character device",
-- read = function() return kernel.computer:time() end,
-- write = function() error("Permission denied") end
--}
--
--data["rtc0"] = {
-- type = "character device",
-- read = function() return kernel.computer:time() end,
-- write = function() error("Permission denied") end
--}
--
--data["eeprom"] = {
-- type = "character device",
-- read = function() return kernel.computer:getEEPROM() end,
-- write = function(data)
-- if kernel.uid ~= 0 then
-- error("Permission denied")
-- end
-- kernel.computer:setEEPROM(data)
-- end
--}
--
--local keyboard = kernel.newFifo()
--local mouse = kernel.newFifo()
--data["input"] = newDirectory()
--data["input"]["keyboard"] = {
-- type = "pipe",
-- read = function(amount)
-- return keyboard.pop()
-- end,
-- write = function() error("Permission denied") end
--}
--data["input"]["mouse"] = {
-- type = "pipe",
-- read = function(amount)
-- return mouse.pop()
-- end,
-- write = function() error("Permission denied") end
--}
--
--data["pts"] = newDirectory()
--
--kernel.devfs = {}
--kernel.devfs.keyboard = keyboard
--kernel.devfs.mouse = mouse
--kernel.devfs.proxy = proxy
--kernel.devfs.data = data
--kernel.vfs.virtdisk(proxy)
local kernel = ...
local proxy = {}
local data = {}
proxy.address = "devfs0000"
proxy.isReadOnly = function() return false end
proxy.spaceUsed = function() return 0 end
proxy.spaceTotal = function() return 0 end
proxy.makeDirectory = function() error("EACCES") end
proxy.remove = function() error("EACCES") end
proxy.setLabel = function() error("EACCES") end
proxy.getLabel = function() return "devfs" end
proxy.attributes = function(path) return {
size = 0,
modified = 0,
created = 0,
} end
function proxy:open(path, mode)
local steps = kernel.vfs.splitPath(path)
local step = data
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENFILE") end
step=dat
end
if type(step[steps[#steps]]) == "function" then
return step[steps[#steps]]("open", mode)
end
error("ENFILE")
end
function proxy:type(path, mode)
local steps = kernel.vfs.splitPath(path)
local step = data
if #steps == 0 then
return "directory"
end
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENFILE") end
step=dat
end
if type(step[steps[#steps]]) == "function" then
return step[steps[#steps]]("type", mode)
end
if type(step[steps[#steps]]) == "table" then
return "directory"
end
error("ENOENT")
end
function proxy:list(path)
local steps = kernel.vfs.splitPath(path)
local step = data
if #steps == 0 then
return table.keys(data)
end
for i=1, #steps-1 do
local dat = step[steps[i]]
if type(dat) ~= "table" then error("ENOENT") end
step=dat
end
if type(step[steps[#steps]]) == "table" then
return table.keys(step[steps[#steps]])
end
error("ENOENT")
end
function proxy:fileExists(path)
local ok = pcall(function()
return self:type(path)
end)
return ok
end
function data.random(op, mode)
if op=="type" then
return "character device"
elseif op=="open" then
if mode=="r" then
return {
read=function(amount)
local str = ""
for i=1, amount or 1 do
str=str..string.char(math.random(0, 255))
end
return str
end
}
elseif mode=="w" or mode=="a" then
return {
write=function() end
}
else error("EACCES")
end
end
end
function data.null(op, mode)
if op=="type" then
return "character device"
elseif op=="open" then
if mode=="r" then
return {
read=function(amount) end
}
elseif mode=="w" or mode=="a" then
return {
write=function() end
}
else error("EACCES")
end
end
end
function data.zero(op, mode)
if op=="type" then
return "character device"
elseif op=="open" then
if mode=="r" then
return {
read=function(amount)
local str = ""
for i=1, amount or 1 do
str=str..string.char(0)
end
return str
end
}
elseif mode=="w" or mode=="a" then
return {
write=function() end
}
else error("EACCES")
end
end
end
data["disk"]={}
kernel.disks["devfs0000"]=proxy
@@ -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
@@ -18,8 +18,6 @@ kernel.processes.keventd = function()
else
timeout = true
end
if timeout then
sleep(.05)
end
if timeout then sleep(.05) end
end
end
@@ -1,18 +1,34 @@
--:Minify:--
local kernel = ...
for i,v in ipairs(string.split(kernel.fstab,"\n")) do
if v:sub(1,1)=="U" then
local id=""
for i=3,#v do
if v:sub(i,i)==";" then
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 8) goto endline end
id=v:sub(3,i-1)
local function trim(str)
local s, e = 1, #str
while s <= e and (str:sub(s,s) == " " or str:sub(s,s) == "\t") do s = s + 1 end
while e >= s and (str:sub(e,e) == " " or str:sub(e,e) == "\t" or str:sub(e,e) == "\n" or str:sub(e,e) == "\r") do e = e - 1 end
if s > e then return "" end
return str:sub(s,e)
end
for _, line in ipairs(string.split(kernel.fstab, "\n")) do
line = trim(line)
if line ~= "" and line:sub(1,1) == "U" then
local semicolon_pos
for i = 3, #line do
if line:sub(i,i) == ";" then
semicolon_pos = i
break
end
end
local path=v:sub(#id+4)
if not semicolon_pos or semicolon_pos == 3 then
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 8)
else
local id = line:sub(3, semicolon_pos - 1)
local path = trim(line:sub(semicolon_pos + 1))
kernel.log("Mounted "..id.." to "..path)
if id ~= "$" then
kernel.vfs.mount(path, id)
end
::endline::
end
end
end
@@ -6,5 +6,15 @@ function socket.socket()
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.log("Loaded socket module")
@@ -7,14 +7,13 @@ local function readonly(tbl)
return setmetatable({}, {
__index = function(_, key)
local value = tbl[key]
if type(value) == "table" then
return readonly(value)
end
if type(value) == "table" then return readonly(value) end
return value
end,
__newindex = function(t, k, v)
if kernel.config.allowGlobalOverwrites or kernel.allowGlobalOverwrites then
if kernel.config.allowGlobalOverwrites or
kernel.allowGlobalOverwrites then
rawset(tbl, k, v)
return
end
@@ -45,11 +44,9 @@ local function readonly(tbl)
end
end,
__len = function()
return #tbl
end,
__len = function() return #tbl end,
__metatable = false,
__metatable = false
})
end
@@ -8,12 +8,16 @@ kernel.exitMain=false
function sys.spawn(func, name, envars, args, tgid)
local id = nextpid
nextpid = nextpid + 1
tasks[tostring(id)] = {
coro = coroutine.create(function()
local ok, err = xpcall(func, debug.traceback, table.unpack(args or {}))
local ok, err = xpcall(func, debug.traceback,
table.unpack(args or {}))
if not ok then
if kernel.config.logTaskExit then
kernel.log("Task "..tostring(id).." exited with err: "..tostring(err), "ERROR", 2)
kernel.log(
"Task " .. tostring(id) .. " exited with err: " ..
tostring(err), "ERROR", 2)
end
tasks[tostring(id)].status = "Z"
if type(err) == "number" then
@@ -22,9 +26,12 @@ function sys.spawn(func, name, envars, args, tgid)
else
if kernel.config.logTaskExit 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
kernel.log("Task "..tostring(id).." exited without code", "INFO")
kernel.log("Task " .. tostring(id) ..
" exited without code", "INFO")
end
end
tasks[tostring(id)].status = "Z"
@@ -41,8 +48,11 @@ function sys.spawn(func, name, envars, args, tgid)
tgid = tgid or kernel.currentTask.tgid,
username = kernel.username,
uid = kernel.uid,
fd={},
exit="",
fd = {
[0]=kernel.currentTask.fd[0],
[1]=kernel.currentTask.fd[1],
[2]=kernel.currentTask.fd[2]
},
sleep = 0,
ivs = 0,
vs = 0,
@@ -51,7 +61,6 @@ function sys.spawn(func, name, envars, args, tgid)
siblings = kernel.currentTask.children,
syscallReturn = {},
cwd = kernel.currentTask.cwd,
term=kernel.currentTask.term,
timeSlice = 0,
lastTime = 0,
totalTime = 0,
@@ -60,6 +69,7 @@ function sys.spawn(func, name, envars, args, tgid)
debugger = false,
eventq = kernel.currentTask.eventq
}
table.insert(kernel.currentTask.children, tasks[tostring(id)])
return id
end
@@ -75,12 +85,10 @@ function sys.getTask(pid)
local task = tasks[tostring(pid)]
local children = {}
local siblings = {}
for i,v in ipairs(task.children) do
children[i]=v.pid
end
for i,v in ipairs(task.siblings) do
siblings[i]=v.pid
end
for i, v in ipairs(task.children) do children[i] = v.pid end
for i, v in ipairs(task.siblings) do siblings[i] = v.pid end
return {
name = task.name,
status = task.status,
@@ -103,15 +111,17 @@ end
function sys.collect(pid)
local children = {}
for i,v in ipairs(kernel.currentTask.children) do
children[i]=v.pid
end
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
if not tasks[tostring(pid)] then
return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) then
return false, "You do not own this task"
elseif tasks[tostring(pid)].status ~= "Z" then
return false, "Task must exit to collect status"
else
tasks[tostring(pid)].reapTime = 0
return true, tasks[tostring(pid)].exit
@@ -120,15 +130,18 @@ end
function sys.kill(pid)
local children = {}
for i,v in ipairs(kernel.currentTask.children) do
children[i]=v.pid
end
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
if not tasks[tostring(pid)] then
return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task"
elseif tasks[tostring(pid)].status == "Z" then
return false, "Task is already dead"
else
tasks[tostring(pid)].status = "Z"
return true
@@ -137,15 +150,18 @@ end
function sys.stop(pid)
local children = {}
for i,v in ipairs(kernel.currentTask.children) do
children[i]=v.pid
end
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
if not tasks[tostring(pid)] then
return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task"
elseif tasks[tostring(pid)].status ~= "R" then
return false, "Cannot stop non running task"
else
tasks[tostring(pid)].status = "T"
return true
@@ -154,44 +170,36 @@ end
function sys.continue(pid)
local children = {}
for i,v in ipairs(kernel.currentTask.children) do
children[i]=v.pid
end
for i, v in ipairs(kernel.currentTask.children) do children[i] = v.pid end
if not tasks[tostring(pid)] then
return false, "Task does not exist"
elseif not isEqualToAny(tasks[tostring(pid)].pid,table.unpack(children)) and kernel.uid~=0 then
elseif not isEqualToAny(tasks[tostring(pid)].pid, table.unpack(children)) and
kernel.uid ~= 0 then
return false, "You do not own this task"
elseif tasks[tostring(pid)].status ~= "T" then
return false, "Task is not stopped"
else
tasks[tostring(pid)].status = "R"
return true
end
end
function sys.getpid()
return kernel.currentTask.pid
end
function sys.getpid() return kernel.currentTask.pid end
function sys.getppid()
return kernel.currentTask.parent.pid
end
function sys.getppid() return kernel.currentTask.parent.pid end
function sys.getTasks()
local ret = {}
for i,v in pairs(tasks) do
ret[#ret+1]=v.pid
end
for i, v in pairs(tasks) do ret[#ret + 1] = v.pid end
return ret
end
function sys.getEnviron(key)
return kernel.currentTask.envars[key]
end
function sys.getEnviron(key) return kernel.currentTask.envars[key] end
function sys.setEnviron(key, value)
kernel.currentTask.envars[key]=value
end
function sys.setEnviron(key, value) kernel.currentTask.envars[key] = value end
function sys.exit(code)
if kernel.config.logTaskExit then
@@ -201,6 +209,7 @@ function sys.exit(code)
kernel.log("Task " .. tostring(kernel.currentTask.pid) .. " exited without code", "INFO")
end
end
tasks[tostring(kernel.currentTask.pid)].status = "Z"
if type(code) == "number" then
tasks[tostring(kernel.currentTask.pid)].exit = code
@@ -212,9 +221,7 @@ function sys.setuid(uid)
kernel.currentTask.uid = uid
end
function sys.getuid()
return kernel.currentTask.uid
end
function sys.getuid() return kernel.currentTask.uid end
local sysc = kernel.syscalls
sysc["spawn"] = sys.spawn
@@ -243,32 +250,33 @@ local function reapDeadTasks()
task.args = nil
task.envars = nil
task.cwd = nil
task.term = nil
task.numRuns = nil
task.totalTime = nil
task.lastTime = nil
task.timeSlice = nil
task.syscallReturn = nil
task.sleep = nil
for v,_ in ipairs(task.fd) do
kernel.vfs.close(v)
end
for v, _ in ipairs(task.fd) do kernel.vfs.close(v) end
task.fd = nil
task.debugger = nil
task.privacy = nil
task.reapTime = kernel.computer:time() + 30000
elseif task.reapTime and kernel.computer:time() > task.reapTime and task.status=="Z" then
elseif task.reapTime and kernel.computer:time() > task.reapTime and
task.status == "Z" then
for _, child in ipairs(task.children) do
child.parent = tasks["1"]
child.siblings = tasks["1"].children
table.insert(tasks["1"].children, child)
end
for i, sibling in ipairs(task.siblings) do
if sibling.pid == task.pid then
table.remove(task.siblings, i)
break
end
end
tasks[pid] = nil
end
end
@@ -314,9 +322,20 @@ function kernel.main()
local startTime = kernel.computer:time()
local ret
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
ret = {coroutine.resume(task.coro, table.unpack(task.syscallReturn))}
ret = {
coroutine.resume(
task.coro,
table.unpack(task.syscallReturn)
)
}
end
local elapsed = kernel.computer:time() - startTime
@@ -335,41 +354,66 @@ function kernel.main()
kernel.log("processHandlerException: " .. ret[2], "ERROR", 2)
task.status = "Z"
task.exit = "processHandlerException: " .. ret[2]
elseif ret[1] == "timeout" then
task.ivs = task.ivs + 1
task.syscallReturn = {}
elseif ret[1] == "success" or ret[1] == true then
task.vs = task.vs + 1
if ret[2] == "syscall" then
if kernel.syscalls[ret[3]] then
if kernel.config.debugSyscalls then
kernel.log("Task " .. task.pid .. " invoking syscall: " .. ret[3], "DBUG", 5)
for i = 4, #ret do
kernel.log(" inval[" .. tostring(i - 3) .. "] = " .. tostring(ret[i]), "DBUG", 5)
end
end
local sysret = {xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))}
local sysret = {
xpcall(kernel.syscalls[ret[3]], debug.traceback, table.unpack(ret, 4))
}
if kernel.config.debugSyscalls then
if not sysret[1] then
kernel.log("Task "..task.pid.." syscall "..ret[3].." failed: "..tostring(sysret[2]), "ERROR", 2)
kernel.log(
"Task " .. task.pid .. " syscall " .. ret[3] .. " failed: " .. tostring(sysret[2]), "ERROR", 2
)
else
kernel.log("Task "..task.pid.." syscall "..ret[3].." completed returning "..tostring(#sysret-1).." values", "DBUG", 5)
kernel.log(
"Task " .. task.pid .. " syscall " .. ret[3] .. " completed returning " .. tostring(#sysret - 1) .. " values", "DBUG", 5
)
for i = 2, #sysret do
if type(sysret[i]) == "table" then
kernel.log(" retval["..tostring(i-1).."] = "..table.serialize(sysret[i]), "DBUG", 5)
kernel.log(
" retval[" .. tostring(i - 1) .. "] = " .. table.serialize(sysret[i]),"DBUG", 5
)
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
if not sysret[1] then
task.syscallReturn = {false, sysret[2]}
else
task.syscallReturn={true, table.unpack(sysret,2)}
task.syscallReturn = {
true, table.unpack(sysret, 2)
}
end
else
task.syscallReturn={false, "Unknown syscall: "..tostring(ret[3])}
task.syscallReturn = {
false, "Unknown syscall: " .. tostring(ret[3])
}
end
end
end
@@ -378,6 +422,7 @@ function kernel.main()
local T_prev_avg = (N > 0) and (totalTaskTime / N) or 0
local T_prev_var = 0
for _, t in ipairs(taskTimes) do
T_prev_var = T_prev_var + (t - T_prev_avg) ^ 2
end
@@ -385,10 +430,10 @@ function kernel.main()
if N > 0 then
local f_clamp = k_min * (Tmin_hit / N) - k_max * (Tmax_hit / N)
local B_budget = (C_target * (N^(alpha-1))) / math.max(T_prev_avg, 1e-8)
B = B + lambda_budget * (B_budget - B)
+ lambda_clamp * f_clamp
- lambda_var * T_prev_var
local B_budget = (C_target * (N ^ (alpha - 1))) /
math.max(T_prev_avg, 1e-8)
B = B + lambda_budget * (B_budget - B) + lambda_clamp * f_clamp -
lambda_var * T_prev_var
end
-- clean up dead tasks
@@ -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
@@ -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"
@@ -3,9 +3,7 @@ local kernel=...
function print(...)
local args = {...}
local output = ""
for i=1,#args do
output=output..tostring(args[i]).."\t"
end
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
output = output:sub(1, -2)
syscall.TTY_print(output)
end
@@ -20,9 +18,7 @@ function printInline(...)
coroutine.yield()
local args = {...}
local output = ""
for i=1,#args do
output=output..tostring(args[i]).."\t"
end
for i = 1, #args do output = output .. tostring(args[i]) .. "\t" end
output = output:sub(1, -2)
syscall.TTY_printInline(output)
end
@@ -8,9 +8,7 @@ local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
kernel.vfs.close(handle)
local initFunc, err = load(data, "@sysinit", "t", kernel._U)
if not initFunc then
error("Failed to load init system: "..err)
end
if not initFunc then error("Failed to load init system: " .. err) end
kernel.tasks["1"] = {
coro = coroutine.create(function()
@@ -21,6 +19,7 @@ kernel.tasks["1"] = {
kernel.panic("Init system exited: " .. tostring(err))
end
end),
name = "sysinit",
status = "R",
pid = 1,
@@ -44,5 +43,6 @@ kernel.tasks["1"] = {
totalTime = 0,
numRuns = 0
}
kernel.log("created init task with PID 1")
kernel.log("Initializing init system...")