finished vfs for a while
This commit is contained in:
@@ -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")
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,0 +1 @@
|
||||
syscall.TTY_clear()
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
print(syscall.getcwd())
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -1 +1,3 @@
|
||||
U $;/
|
||||
U devfs0000;/dev/
|
||||
U tmpfs0000;/tmp/
|
||||
@@ -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
|
||||
@@ -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
|
||||
+1
-3
@@ -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...")
|
||||
Reference in New Issue
Block a user