Merge branch 'main' of https://git.astronand.dev/Hyperion/HyperionOS
This commit is contained in:
@@ -14,22 +14,26 @@ kernel.group = "root"
|
|||||||
kernel.groups = {0}
|
kernel.groups = {0}
|
||||||
kernel.uid = 0
|
kernel.uid = 0
|
||||||
kernel.gid = 0
|
kernel.gid = 0
|
||||||
kernel.stage = "start"
|
kernel.status = "start"
|
||||||
kernel.key = {}
|
kernel.key = {}
|
||||||
kernel.chache = {}
|
kernel.cache = {}
|
||||||
kernel.chache.preload = {}
|
kernel.cache.preload = {}
|
||||||
|
kernel._G=_G
|
||||||
local windowsExp = false
|
local windowsExp = false
|
||||||
|
|
||||||
function kernel.log(msg, level)
|
function kernel.log(msg, level)
|
||||||
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||||
if kernel.stage == "start" then
|
if kernel.status == "start" then
|
||||||
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.PANIC(msg)
|
function kernel.PANIC(msg)
|
||||||
|
if kernel.status~="Panic" then
|
||||||
kernel.log("PANIC: "..msg, "PANIC")
|
kernel.log("PANIC: "..msg, "PANIC")
|
||||||
pcall(kernel["saveLog"])
|
pcall(kernel["saveLog"])
|
||||||
|
kernel.status="Panic"
|
||||||
|
kernel.reason=msg
|
||||||
screen:setTextColor(2)
|
screen:setTextColor(2)
|
||||||
screen:setBackgroundColor(0)
|
screen:setBackgroundColor(0)
|
||||||
screen:clear()
|
screen:clear()
|
||||||
@@ -37,6 +41,7 @@ function kernel.PANIC(msg)
|
|||||||
screen:print(LOG_Text)
|
screen:print(LOG_Text)
|
||||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||||
screen:print("Press any key to continue...")
|
screen:print("Press any key to continue...")
|
||||||
|
end
|
||||||
while true do
|
while true do
|
||||||
local event={computer:getMachineEvent()}
|
local event={computer:getMachineEvent()}
|
||||||
if event[1]=="keyPressed" then
|
if event[1]=="keyPressed" then
|
||||||
@@ -65,16 +70,12 @@ if windowsExp then
|
|||||||
while true do end
|
while true do end
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("Kernel loaded.", "INFO")
|
kernel.log("Kernel loaded.")
|
||||||
kernel.log("Mounting disks...", "INFO")
|
kernel.log("Mounting init disks...")
|
||||||
disks.refresh()
|
disks.refresh()
|
||||||
ifs.update(disks)
|
ifs.update(disks)
|
||||||
ifs.mount("$", "/")
|
ifs.mount("$", "/")
|
||||||
|
|
||||||
function kernel.saveLog()
|
|
||||||
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
|
|
||||||
end
|
|
||||||
|
|
||||||
local fstab=ifs.readAllText("/etc/fstab")
|
local fstab=ifs.readAllText("/etc/fstab")
|
||||||
local split = function(str, delim, maxResultCountOrNil)
|
local split = function(str, delim, maxResultCountOrNil)
|
||||||
assert(#delim == 1, "only delim len 1 supported for now")
|
assert(#delim == 1, "only delim len 1 supported for now")
|
||||||
@@ -104,11 +105,15 @@ for i,v in ipairs(split(fstab,"\n")) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local path=v:sub(#id+4)
|
local path=v:sub(#id+4)
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
|
||||||
ifs.mount(id,path)
|
ifs.mount(id,path)
|
||||||
::endline::
|
::endline::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Disks initialized")
|
||||||
|
|
||||||
|
function kernel.saveLog()
|
||||||
|
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
|
||||||
|
end
|
||||||
|
|
||||||
ifs.remove("/tmp")
|
ifs.remove("/tmp")
|
||||||
ifs.makeDir("/tmp")
|
ifs.makeDir("/tmp")
|
||||||
@@ -116,29 +121,24 @@ ifs.makeDir("/tmp")
|
|||||||
local drivers={}
|
local drivers={}
|
||||||
drivers.raw={}
|
drivers.raw={}
|
||||||
drivers.processes={}
|
drivers.processes={}
|
||||||
drivers.prior={}
|
|
||||||
drivers.type={}
|
drivers.type={}
|
||||||
for i=0, 99 do
|
|
||||||
drivers.prior[i]={}
|
|
||||||
end
|
|
||||||
|
|
||||||
function drivers.register(prior,object)
|
function drivers.register(object)
|
||||||
drivers.raw[#drivers.raw+1]=object
|
drivers.raw[#drivers.raw+1]=object
|
||||||
if object.main then drivers.processes[#drivers.processes+1]=object.main end
|
if object.main then drivers.processes[#drivers.processes+1]=object.main end
|
||||||
if drivers.prior[prior]==nil then drivers.prior[prior]={} end
|
|
||||||
drivers.prior[prior][#drivers.prior[prior]+1]=object
|
|
||||||
if drivers.type[object.type]==nil then drivers.type[object.type]={} end
|
if drivers.type[object.type]==nil then drivers.type[object.type]={} end
|
||||||
drivers.type[object.type][#drivers.type[object.type]+1]=object
|
drivers.type[object.type][#drivers.type[object.type]+1]=object
|
||||||
end
|
end
|
||||||
|
|
||||||
local modules={}
|
local modules={[0]={}}
|
||||||
for i=0, 99 do
|
for i=0, 100 do
|
||||||
modules[i]={}
|
modules[i]={}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.log("Gathering modules")
|
||||||
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
|
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
|
||||||
local prior=tonumber(v:sub(1,2))
|
local prior=tonumber(v:sub(1,2))
|
||||||
modules[prior][#modules[prior]+1]="/lib/modules/Hyperion/"..v
|
modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.drivers=drivers
|
kernel.drivers=drivers
|
||||||
@@ -147,19 +147,17 @@ kernel.apis=apis
|
|||||||
kernel.computer=computer
|
kernel.computer=computer
|
||||||
kernel.initPath=initPath
|
kernel.initPath=initPath
|
||||||
kernel.arch=arch
|
kernel.arch=arch
|
||||||
kernel.initdisks=initdisks
|
kernel.initdisks=disks
|
||||||
kernel.screen=screen
|
kernel.screen=screen
|
||||||
|
|
||||||
|
kernel.log("Running modules")
|
||||||
for _,p in ipairs(modules) do
|
for _,p in ipairs(modules) do
|
||||||
for _,v in ipairs(p) do
|
for _,v in ipairs(p) do
|
||||||
local code=ifs.readAllText(v)
|
local code=ifs.readAllText(v)
|
||||||
local func,err=load(code,"@"..v)
|
local func,err=load(code,"@"..v)
|
||||||
if not func then kernel.log("ModuLoadErr: "..tostring(err)) goto skip end
|
if not func then kernel.log("ModuLoadErr: "..tostring(err), "WARN") goto skip end
|
||||||
local status, err = xpcall(func,debug.traceback,kernel)
|
local status, err = xpcall(func,debug.traceback, kernel)
|
||||||
if not status then goto skip end
|
if not status then kernel.log("ModuRunErr: "..tostring(err), "WARN") end
|
||||||
if not err then goto skip end
|
|
||||||
if not err.init then goto skip end
|
|
||||||
local ok, err = xpcall(status.main,debug.traceback)
|
|
||||||
if not ok then kernel.log("ModuInitErr: "..tostring(err)) end
|
|
||||||
::skip::
|
::skip::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
U $;/
|
U $;/
|
||||||
U devfs0000;/dev/
|
U devfs0000;/dev/
|
||||||
|
U sysfs0000;/sys/
|
||||||
26
Build/lib/modules/CC-Tweaked/redstone.kmod
Executable file
26
Build/lib/modules/CC-Tweaked/redstone.kmod
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
local driver={}
|
||||||
|
|
||||||
|
driver.name="CCT Term Module"
|
||||||
|
driver.version="0.1.0"
|
||||||
|
driver.type="gpio"
|
||||||
|
driver.description="CCT redstone Module Kernel Module"
|
||||||
|
driver.arch="cct"
|
||||||
|
driver.author="HyperionOS Dev Team"
|
||||||
|
driver.license="MIT"
|
||||||
|
driver.api={}
|
||||||
|
|
||||||
|
function driver.load()
|
||||||
|
-- will
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.unload()
|
||||||
|
-- Nothing to unload
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.main()
|
||||||
|
-- Nothing to run
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.drivers.register(driver)
|
||||||
105
Build/lib/modules/CC-Tweaked/tty.kmod
Executable file
105
Build/lib/modules/CC-Tweaked/tty.kmod
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
local apis=kernel.apis
|
||||||
|
local native=apis.peripheral
|
||||||
|
local driver={}
|
||||||
|
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||||
|
|
||||||
|
local function getType(name)
|
||||||
|
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
|
||||||
|
return native.call(side, "getTypeRemote", name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
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.hasType(side, "peripheral_hub") then
|
||||||
|
local hubSides = native.call(side, "getConnectedSides")
|
||||||
|
for _, hubSide in ipairs(hubSides) do
|
||||||
|
table.insert(names, hubSide)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return names
|
||||||
|
end
|
||||||
|
|
||||||
|
driver.name="CCT TTY Module"
|
||||||
|
driver.version="0.1.0"
|
||||||
|
driver.type="tty"
|
||||||
|
driver.description="CCT TTY Module Kernel Module"
|
||||||
|
driver.arch="cct"
|
||||||
|
driver.author="HyperionOS Dev Team"
|
||||||
|
driver.license="MIT"
|
||||||
|
driver.api={}
|
||||||
|
|
||||||
|
local colors={
|
||||||
|
[0]=0x000000, -- #000000
|
||||||
|
0xFFFFFF, -- #FFFFFF
|
||||||
|
0xFF0000, -- #FF0000
|
||||||
|
0x00FF00, -- #00FF00
|
||||||
|
0x0000FF, -- #0000FF
|
||||||
|
0x00FFFF, -- #00FFFF
|
||||||
|
0xFF00FF, -- #FF00FF
|
||||||
|
0xFFFF00, -- #FFFF00
|
||||||
|
0xFF6D00, -- #FF6D00
|
||||||
|
0x6DFF55, -- #6DFF55
|
||||||
|
0x24FFFF, -- #24FFFF
|
||||||
|
0x924900, -- #924900
|
||||||
|
0x6D6D55, -- #6D6D55
|
||||||
|
0xDBDBAA, -- #DBDBAA
|
||||||
|
0x6D00FF, -- #6D00FF
|
||||||
|
0xB6FF00 -- #B6FF00
|
||||||
|
}
|
||||||
|
|
||||||
|
local icolors={
|
||||||
|
[0x1] =0, -- #000000
|
||||||
|
[0x2] =1, -- #FFFFFF
|
||||||
|
[0x4] =2, -- #FF0000
|
||||||
|
[0x8] =3, -- #00FF00
|
||||||
|
[0x10] =4, -- #0000FF
|
||||||
|
[0x20] =5, -- #00FFFF
|
||||||
|
[0x40] =6, -- #FF00FF
|
||||||
|
[0x80] =7, -- #FFFF00
|
||||||
|
[0x100] =8, -- #FF6D00
|
||||||
|
[0x200] =9, -- #6DFF55
|
||||||
|
[0x400] =10, -- #24FFFF
|
||||||
|
[0x800] =11, -- #924900
|
||||||
|
[0x1000] =12, -- #6D6D55
|
||||||
|
[0x2000] =13, -- #DBDBAA
|
||||||
|
[0x4000] =14, -- #6D00FF
|
||||||
|
[0x8000] =15 -- #B6FF00
|
||||||
|
}
|
||||||
|
|
||||||
|
local function getAllScreens()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wrapScreens()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.load()
|
||||||
|
-- Nothing to load
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.unload()
|
||||||
|
-- Nothing to unload
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.main()
|
||||||
|
-- Nothing to run
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.drivers.register(driver)
|
||||||
@@ -1,3 +1,5 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
function string.hasSuffix(str, suffix)
|
function string.hasSuffix(str, suffix)
|
||||||
return string.sub(str, #suffix+1) == suffix
|
return string.sub(str, #suffix+1) == suffix
|
||||||
end
|
end
|
||||||
@@ -94,6 +96,62 @@ function table.hasVal(tabl, query)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.proxy(tbl)
|
||||||
|
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
|
||||||
|
|
||||||
|
local function createProxy(t)
|
||||||
|
if type(t) ~= "table" then return t end
|
||||||
|
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
|
||||||
|
|
||||||
|
local proxy = {}
|
||||||
|
proxies[t] = proxy
|
||||||
|
|
||||||
|
local mt
|
||||||
|
mt = {
|
||||||
|
__index = function(_, k)
|
||||||
|
local value = t[k]
|
||||||
|
if type(value) == "table" then
|
||||||
|
return createProxy(value) -- recursively proxy subtables
|
||||||
|
else
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__newindex = function()
|
||||||
|
error("Attempt to modify read-only table", 2)
|
||||||
|
end,
|
||||||
|
__pairs = function()
|
||||||
|
return function(_, k)
|
||||||
|
local nextKey, nextValue = next(t, k)
|
||||||
|
if type(nextValue) == "table" then
|
||||||
|
nextValue = createProxy(nextValue)
|
||||||
|
end
|
||||||
|
return nextKey, nextValue
|
||||||
|
end, nil, nil
|
||||||
|
end,
|
||||||
|
__ipairs = function()
|
||||||
|
local i = 0
|
||||||
|
local n = #t
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
if i <= n then
|
||||||
|
local v = t[i]
|
||||||
|
if type(v) == "table" then
|
||||||
|
v = createProxy(v)
|
||||||
|
end
|
||||||
|
return i, v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__metatable = false
|
||||||
|
}
|
||||||
|
|
||||||
|
setmetatable(proxy, mt)
|
||||||
|
return proxy
|
||||||
|
end
|
||||||
|
|
||||||
|
return createProxy(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
local function serialize(table)
|
local function serialize(table)
|
||||||
local output = "{"
|
local output = "{"
|
||||||
for i,v in pairs(table) do
|
for i,v in pairs(table) do
|
||||||
@@ -119,7 +177,7 @@ local function serialize(table)
|
|||||||
output=output.."false"
|
output=output.."false"
|
||||||
end
|
end
|
||||||
elseif type(v) == "function" then
|
elseif type(v) == "function" then
|
||||||
output=output.."function() end"
|
output=output..tostring(v)
|
||||||
else
|
else
|
||||||
error("serialization of type \""..type(v).."\" is not supported")
|
error("serialization of type \""..type(v).."\" is not supported")
|
||||||
end
|
end
|
||||||
@@ -135,3 +193,4 @@ local function serialize(table)
|
|||||||
end
|
end
|
||||||
|
|
||||||
table.serialize=serialize
|
table.serialize=serialize
|
||||||
|
kernel.log("Loaded stdlib")
|
||||||
3
Build/lib/modules/Hyperion/05_userspace.kmod
Executable file
3
Build/lib/modules/Hyperion/05_userspace.kmod
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
kernel._U=table.proxy(_G)
|
||||||
@@ -1,217 +1,321 @@
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
local fs = {}
|
local fs = {}
|
||||||
local disks = {}
|
|
||||||
local mounts = {["/"]="$"}
|
|
||||||
|
|
||||||
-- path normaliing
|
-- =====================================================================
|
||||||
local function normalizePath(path)
|
-- INTERNAL STATE
|
||||||
if not path or path == "" then return "/" end
|
-- =====================================================================
|
||||||
if path:sub(1,1) ~= "/" then path = "/" .. path end
|
|
||||||
local parts = {}
|
|
||||||
for part in path:gmatch("[^/]+") do
|
|
||||||
if part == ".." then
|
|
||||||
if #parts > 0 then table.remove(parts) end
|
|
||||||
elseif part ~= "." and part ~= "" then
|
|
||||||
parts[#parts+1] = part
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return "/" .. table.concat(parts, "/")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- disk resolution
|
local disks = {} -- address → disk object
|
||||||
local function resolvePath(path)
|
local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk)
|
||||||
local abs = normalizePath(path)
|
|
||||||
local best = "/"
|
|
||||||
for mount, diskAddr in pairs(mounts) do
|
|
||||||
if abs:sub(1, #mount) == mount and #mount > #best then
|
|
||||||
best = mount
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local newPath = abs:sub(#best + 1)
|
|
||||||
if newPath == "" then newPath = "/" end
|
|
||||||
return disks[mounts[best]], newPath
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Symlinks
|
|
||||||
-- Format: #!@SYMLINK[target]
|
|
||||||
local SYMLINK_PREFIX = "#!@SYMLINK["
|
local SYMLINK_PREFIX = "#!@SYMLINK["
|
||||||
local SYMLINK_SUFFIX = "]"
|
local SYMLINK_SUFFIX = "]"
|
||||||
local SYMLINK_MAX_DEPTH = 64
|
local SYMLINK_MAX_DEPTH = 64
|
||||||
|
|
||||||
local function isSymlink(disk, path)
|
|
||||||
if not disk:fileExists(path) then return false end
|
-- =====================================================================
|
||||||
local text = disk:readAllText(path)
|
-- PATH NORMALIZATION
|
||||||
if not text then return false end
|
-- =====================================================================
|
||||||
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
|
||||||
|
local function splitPath(p)
|
||||||
|
local t = {}
|
||||||
|
for part in p:gmatch("[^/]+") do t[#t+1] = part end
|
||||||
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
local function readSymlink(disk, path)
|
local function normalizePath(path)
|
||||||
local text = disk:readAllText(path)
|
if not path or path == "" then return "/" end
|
||||||
|
|
||||||
|
-- ensure absolute
|
||||||
|
if path:sub(1,1) ~= "/" then
|
||||||
|
path = "/" .. path
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = splitPath(path)
|
||||||
|
local out = {}
|
||||||
|
|
||||||
|
for _,part in ipairs(parts) do
|
||||||
|
if part == ".." then
|
||||||
|
if #out > 0 then table.remove(out) end
|
||||||
|
elseif part ~= "." and part ~= "" then
|
||||||
|
out[#out+1] = part
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return "/" .. table.concat(out, "/")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- DISK & MOUNT RESOLUTION
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- Finds which disk owns an absolute path
|
||||||
|
local function resolveMount(abs)
|
||||||
|
local best = "/"
|
||||||
|
|
||||||
|
for mount, addr in pairs(mounts) do
|
||||||
|
if abs:sub(1, #mount) == mount then
|
||||||
|
if #mount > #best then
|
||||||
|
best = mount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local disk = disks[mounts[best]]
|
||||||
|
if not disk then
|
||||||
|
error("No disk registered for mount: " .. best)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sub = abs:sub(#best + 1)
|
||||||
|
if sub == "" then sub = "/" end
|
||||||
|
return disk, sub
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- SYMLINK HANDLING
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
local function isSymlinkRaw(disk, p)
|
||||||
|
if not disk:fileExists(p) then return false end
|
||||||
|
local text = disk:readAllText(p)
|
||||||
|
return text and text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
||||||
|
end
|
||||||
|
|
||||||
|
local function readSymlinkRaw(disk, p)
|
||||||
|
local text = disk:readAllText(p)
|
||||||
if not text then return nil end
|
if not text then return nil end
|
||||||
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
||||||
local target = text:sub(#SYMLINK_PREFIX + 1)
|
|
||||||
if target:sub(-1) == SYMLINK_SUFFIX then
|
local t = text:sub(#SYMLINK_PREFIX + 1)
|
||||||
target = target:sub(1, -2)
|
if t:sub(-1) == SYMLINK_SUFFIX then
|
||||||
|
t = t:sub(1, -2)
|
||||||
end
|
end
|
||||||
return target
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Path resolution
|
-- =====================================================================
|
||||||
local function splitPath(p)
|
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS)
|
||||||
local parts = {}
|
-- =====================================================================
|
||||||
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end
|
|
||||||
return parts
|
|
||||||
end
|
|
||||||
|
|
||||||
local function resolveSymlink(path)
|
local function resolveSymlink(path)
|
||||||
path = normalizePath(path)
|
local abs = normalizePath(path)
|
||||||
local symlinkDepth = 0
|
local parts = splitPath(abs)
|
||||||
local parts = splitPath(path)
|
local out = {}
|
||||||
local resolved = {}
|
|
||||||
local i = 1
|
local depth = 0
|
||||||
|
local idx = 1
|
||||||
|
|
||||||
|
while idx <= #parts do
|
||||||
|
local comp = parts[idx]
|
||||||
|
|
||||||
while i <= #parts do
|
|
||||||
local comp = parts[i]
|
|
||||||
if comp == "." then
|
if comp == "." then
|
||||||
|
-- nothing
|
||||||
elseif comp == ".." then
|
elseif comp == ".." then
|
||||||
if #resolved > 0 then table.remove(resolved) end
|
if #out > 0 then table.remove(out) end
|
||||||
else
|
else
|
||||||
local currentPath = "/" .. table.concat(resolved, "/")
|
local curAbs = "/" .. table.concat(out, "/")
|
||||||
local disk, p = resolvePath(currentPath .. "/" .. comp)
|
if curAbs ~= "/" then curAbs = curAbs .. "/" end
|
||||||
if isSymlink(disk, p) then
|
curAbs = curAbs .. comp
|
||||||
symlinkDepth = symlinkDepth + 1
|
|
||||||
if symlinkDepth > SYMLINK_MAX_DEPTH then
|
local disk, dpath = resolveMount(curAbs)
|
||||||
error("Too many levels of symbolic links: " .. path)
|
|
||||||
|
if isSymlinkRaw(disk, dpath) then
|
||||||
|
depth = depth + 1
|
||||||
|
if depth > SYMLINK_MAX_DEPTH then
|
||||||
|
error("Too many symlink levels: " .. path)
|
||||||
end
|
end
|
||||||
local target = readSymlink(disk, p)
|
|
||||||
if not target then
|
local target = readSymlinkRaw(disk, dpath)
|
||||||
resolved[#resolved+1] = comp
|
if target then
|
||||||
else
|
local newAbs
|
||||||
|
|
||||||
if target:sub(1,1) == "/" then
|
if target:sub(1,1) == "/" then
|
||||||
resolved = splitPath(normalizePath(target))
|
-- absolute target
|
||||||
|
newAbs = normalizePath(target)
|
||||||
else
|
else
|
||||||
local base = resolved
|
-- relative to current out[]
|
||||||
resolved = {}
|
local tmp = "/" .. table.concat(out, "/")
|
||||||
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end
|
if tmp ~= "/" then tmp = tmp .. "/" end
|
||||||
for seg in target:gmatch("[^/]+") do
|
tmp = tmp .. target
|
||||||
if seg == ".." then
|
newAbs = normalizePath(tmp)
|
||||||
if #resolved>0 then table.remove(resolved) end
|
|
||||||
elseif seg ~= "." then
|
|
||||||
resolved[#resolved+1]=seg
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- rebuild remaining parts
|
||||||
local remaining = {}
|
local remaining = {}
|
||||||
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
|
for j = idx + 1, #parts do
|
||||||
parts = remaining
|
remaining[#remaining+1] = parts[j]
|
||||||
i = 0
|
end
|
||||||
|
|
||||||
|
-- restart symlink resolution with new path
|
||||||
|
abs = newAbs
|
||||||
|
parts = splitPath(abs)
|
||||||
|
|
||||||
|
-- append remaining
|
||||||
|
for _,x in ipairs(remaining) do parts[#parts+1] = x end
|
||||||
|
|
||||||
|
out = {}
|
||||||
|
idx = 0
|
||||||
|
else
|
||||||
|
out[#out+1] = comp
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
resolved[#resolved+1]=comp
|
out[#out+1] = comp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
|
|
||||||
local finalPath="/"..table.concat(resolved,"/")
|
idx = idx + 1
|
||||||
local disk,diskPath=resolvePath(finalPath)
|
end
|
||||||
return disk,diskPath
|
|
||||||
|
local finalAbs = "/" .. table.concat(out, "/")
|
||||||
|
return resolveMount(finalAbs)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PUBLIC API: MOUNTING
|
|
||||||
function fs.mount(disk, mountPoint)
|
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
-- =====================================================================
|
||||||
mounts[mountPoint]=disk
|
-- PUBLIC API
|
||||||
end
|
-- =====================================================================
|
||||||
function fs.unmount(mountPoint)
|
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
-- MOUNT OPERATIONS -----------------------------------------------------
|
||||||
mounts[mountPoint]=nil
|
|
||||||
end
|
|
||||||
function fs.virtDisk(diskObj)
|
function fs.virtDisk(diskObj)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
if disks[diskObj.address] then error("Disk exists") end
|
if disks[diskObj.address] then
|
||||||
disks[diskObj.address]=diskObj
|
error("Disk exists: " .. diskObj.address)
|
||||||
|
end
|
||||||
|
disks[diskObj.address] = diskObj
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function fs.mount(disk, mountPoint)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
mountPoint = normalizePath(mountPoint)
|
||||||
|
|
||||||
|
local drive, path = resolveMount(normalizePath(mountPoint))
|
||||||
|
if not drive:directoryExists(path) then error("Must mount on folder") end
|
||||||
|
|
||||||
|
if mountPoint ~= "/" and mounts[mountPoint] then
|
||||||
|
error("Already mounted: " .. mountPoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
mounts[mountPoint] = disk
|
||||||
|
end
|
||||||
|
|
||||||
|
function fs.unmount(mountPoint)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
mountPoint = normalizePath(mountPoint)
|
||||||
|
|
||||||
|
if mountPoint == "/" then error("Cannot unmount root") end
|
||||||
|
mounts[mountPoint] = nil
|
||||||
|
end
|
||||||
|
|
||||||
function fs.eject(addr)
|
function fs.eject(addr)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
disks[addr]=nil
|
disks[addr] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SYMLINK API
|
function fs.isMount(path)
|
||||||
|
if mounts[normalizePath(path)] then return true, mounts[normalizePath(path)] end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SYMLINK API ----------------------------------------------------------
|
||||||
|
|
||||||
function fs.symlink(target, linkPath)
|
function fs.symlink(target, linkPath)
|
||||||
local disk, p = resolvePath(linkPath)
|
kernel.log("WARNING: Symlinks are a untested feature if you find any bugs please report them to https://git.astronand.dev/Hyperion/HyperionOS","WARN")
|
||||||
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX)
|
local disk, p = resolveMount(normalizePath(linkPath))
|
||||||
|
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isLink(path)
|
function fs.isLink(path)
|
||||||
local disk, p = resolvePath(path)
|
local disk, p = resolveMount(normalizePath(path))
|
||||||
return isSymlink(disk,p)
|
return isSymlinkRaw(disk, p)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.readLink(path)
|
function fs.readLink(path)
|
||||||
local disk, p = resolvePath(path)
|
local disk, p = resolveMount(normalizePath(path))
|
||||||
return readSymlink(disk,p)
|
return readSymlinkRaw(disk, p)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FILE OPERATIONS
|
|
||||||
function fs.exists(path)
|
-- FILE OPERATIONS ------------------------------------------------------
|
||||||
|
|
||||||
|
function fs.exists(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:fileExists(p) or disk:directoryExists(p)
|
return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isFile(path)
|
function fs.isFile(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
if isSymlink(disk, p) then return false end
|
return disk:fileExists(p, ...)
|
||||||
return disk:fileExists(p)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isDir(path)
|
function fs.isDir(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
if isSymlink(disk, p) then return false end
|
return disk:directoryExists(p, ...)
|
||||||
return disk:directoryExists(p)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.list(path)
|
function fs.list(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:list(p)
|
return disk:list(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.makeDir(path)
|
function fs.makeDir(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:makeDirectory(p)
|
return disk:makeDirectory(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.remove(path)
|
-- remove does NOT follow symlinks (UNIX semantics)
|
||||||
local disk, p = resolvePath(path)
|
function fs.remove(path, ...)
|
||||||
if isSymlink(disk, p) then
|
if fs.isMount(path) then return "Cannot delete mounted folder" end
|
||||||
return disk:remove(p)
|
local abs = normalizePath(path)
|
||||||
end
|
local disk, p = resolveMount(abs)
|
||||||
local d2, p2 = resolveSymlink(path)
|
return disk:remove(p, ...)
|
||||||
return d2:remove(p2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.readAllText(path)
|
function fs.readAllText(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:readAllText(p)
|
return disk:readAllText(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.writeAllText(path, text)
|
function fs.writeAllText(path, text, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:writeAllText(p, text)
|
return disk:writeAllText(p, text, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.appendAllText(path, text)
|
function fs.appendAllText(path, text, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:appendAllText(p, text)
|
return disk:appendAllText(p, text, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.getSize(path)
|
function fs.load(path, name, ...)
|
||||||
|
return load(fs.readAllText(path, ...), name or path, nil, kernel._U)
|
||||||
|
end
|
||||||
|
|
||||||
|
function fs.getSize(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:getSize(p)
|
return disk:getSize(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
-- INIT
|
-- INIT
|
||||||
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end
|
-- =====================================================================
|
||||||
kernel.fs=fs
|
|
||||||
kernel.chache.preload.fs=fs
|
kernel.log("Loading disks for vfs")
|
||||||
kernel.chache.preload.filesystem=fs
|
local ok,err = xpcall(function()
|
||||||
|
for _,v in kernel.initdisks.list() do
|
||||||
|
fs.virtDisk(v)
|
||||||
|
end
|
||||||
|
end, debug.traceback)
|
||||||
|
if not ok then kernel.panic(err) end
|
||||||
|
|
||||||
|
kernel.disks=disks
|
||||||
|
kernel.mounts=mounts
|
||||||
|
kernel.fs = fs
|
||||||
|
kernel.cache.preload.fs = table.proxy(kernel.fs)
|
||||||
|
kernel.cache.preload.filesystem = kernel.cache.preload.fs
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
|
|
||||||
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
local disk = {}
|
local disk = {}
|
||||||
@@ -55,34 +54,36 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
-- File IO (supports string or file-object with read/write funcs)
|
-- File IO (supports string or file-object with read/write funcs)
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
local function fileRead(node)
|
local function fileRead(node, ...)
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
return node
|
return node
|
||||||
elseif type(node) == "table" and node.__file and node.read then
|
elseif type(node) == "table" and node.__file and node.read then
|
||||||
return node.read()
|
return node.read(...)
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fileWrite(parent, name, text)
|
local function fileWrite(parent, name, text, ...)
|
||||||
local node = parent[name]
|
local node = parent[name]
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
elseif type(node) == "table" and node.__file and node.write then
|
elseif type(node) == "table" and node.__file and node.write then
|
||||||
return node.write(text)
|
return node.write(text, ...)
|
||||||
end
|
end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fileAppend(parent, name, text)
|
local function fileAppend(parent, name, text, ...)
|
||||||
local node = parent[name]
|
local node = parent[name]
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||||
parent[name] = node .. text
|
parent[name] = node .. text
|
||||||
return true
|
return true
|
||||||
elseif type(node) == "table" and node.__file and node.write then
|
elseif type(node) == "table" and node.__file and node.write then
|
||||||
return node.write((node.read() or "") .. text)
|
return node.write((node.read() or "") .. text, ...)
|
||||||
end
|
end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
@@ -96,26 +97,22 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
function disk:spaceUsed() return 0 end
|
function disk:spaceUsed() return 0 end
|
||||||
function disk:spaceTotal() return 0 end
|
function disk:spaceTotal() return 0 end
|
||||||
|
|
||||||
function disk:readAllText(path)
|
function disk:readAllText(path, ...)
|
||||||
local node = getNode(path)
|
local node = getNode(path)
|
||||||
if not node then return nil, "file not found" end
|
if not node then return nil, "file not found" end
|
||||||
return fileRead(node)
|
return fileRead(node, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:writeAllText(path, text)
|
function disk:writeAllText(path, text, ...)
|
||||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
||||||
|
|
||||||
local parent, name = getParent(path)
|
local parent, name = getParent(path)
|
||||||
if not parent or not parent.__dir then return false, "invalid directory" end
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
||||||
return fileWrite(parent, name, tostring(text))
|
return fileWrite(parent, name, tostring(text), ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:appendAllText(path, text)
|
function disk:appendAllText(path, text, ...)
|
||||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
||||||
|
|
||||||
local parent, name = getParent(path)
|
local parent, name = getParent(path)
|
||||||
if not parent or not parent.__dir then return false, "invalid directory" end
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
||||||
return fileAppend(parent, name, tostring(text))
|
return fileAppend(parent, name, tostring(text), ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:list(path)
|
function disk:list(path)
|
||||||
@@ -161,11 +158,11 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
return label
|
return label
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:size(path)
|
function disk:size(path, ...)
|
||||||
local node = getNode(path)
|
local node = getNode(path)
|
||||||
if type(node) == "string" then return #node end
|
if type(node) == "string" then return #node end
|
||||||
if type(node) == "table" and node.__file and node.read then
|
if type(node) == "table" and node.__file and node.read then
|
||||||
local v = node.read()
|
local v = node.read(...)
|
||||||
return v and #v or 0
|
return v and #v or 0
|
||||||
end
|
end
|
||||||
return 0
|
return 0
|
||||||
@@ -174,7 +171,7 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
-- Auto-register with kernel and return backend
|
-- Auto-register with kernel and return backend
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
if kernel and kernel.fs and kernel.fs.virtDisk and autoRegister then
|
if autoRegister then
|
||||||
kernel.fs.virtDisk(disk)
|
kernel.fs.virtDisk(disk)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
|
|
||||||
-- List of search paths
|
-- List of search paths
|
||||||
local paths = {
|
local paths = {
|
||||||
"/lib/?",
|
"/lib/?",
|
||||||
@@ -11,7 +10,7 @@ local paths = {
|
|||||||
-- Custom require implementation
|
-- Custom require implementation
|
||||||
function require(module)
|
function require(module)
|
||||||
-- Return cached module if it already exists
|
-- Return cached module if it already exists
|
||||||
if kernel.cache.preload[module] then
|
if kernel.cache.preload[module]~=nil then
|
||||||
return kernel.cache.preload[module]
|
return kernel.cache.preload[module]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,3 +53,4 @@ function require(module)
|
|||||||
-- If nothing worked, raise an error with all reasons
|
-- If nothing worked, raise an error with all reasons
|
||||||
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
|
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
|
||||||
end
|
end
|
||||||
|
kernel.log("Created require")
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
|
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true)
|
||||||
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", false)
|
if not kernel.fs.isDir("/dev") then kernel.fs.makeDir("/dev") end
|
||||||
|
kernel.devfs={}
|
||||||
|
kernel.devfs.data=data
|
||||||
|
|
||||||
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
||||||
data["/"]["eeprom"]={
|
data["/"]["eeprom"]={
|
||||||
@@ -14,4 +16,42 @@ data["/"]["eeprom"]={
|
|||||||
kernel.computer:setEEPROM(text)
|
kernel.computer:setEEPROM(text)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
data["/"]["null"]={
|
||||||
|
__file=true,
|
||||||
|
read=function() end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["random"]={
|
||||||
|
__file=true,
|
||||||
|
read=function(amount)
|
||||||
|
local s = ""
|
||||||
|
for i = 1, amount do
|
||||||
|
s = s .. string.char(math.random(0, 255))
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["zero"]={
|
||||||
|
__file=true,
|
||||||
|
read=function(amount)
|
||||||
|
return ("\0"):rep(amount)
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["rtc0"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:time()
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["rtc"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:time()
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel.log("Created devfs")
|
||||||
18
Build/lib/modules/Hyperion/12_sysfs.kmod
Executable file
18
Build/lib/modules/Hyperion/12_sysfs.kmod
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
local args = {...}
|
||||||
|
local kernel = args[1]
|
||||||
|
local data = kernel.fs.mkvirtfs("sysfs0000", true, "sysfs", true)
|
||||||
|
if not kernel.fs.isDir("/sys") then kernel.fs.makeDir("/sys") end
|
||||||
|
|
||||||
|
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
||||||
|
data["/"]["eeprom"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:getEEPROM()
|
||||||
|
end,
|
||||||
|
write=function(text)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
kernel.computer:setEEPROM(text)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel.log("Created sysfs")
|
||||||
@@ -1,11 +1,11 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
local ifs=kernel.ifs
|
local ifs=kernel.ifs
|
||||||
local initdisks=kernel.initdisks
|
|
||||||
|
|
||||||
|
kernel.log("Mounting fstab")
|
||||||
local fstab=ifs.readAllText("/etc/fstab")
|
local fstab=ifs.readAllText("/etc/fstab")
|
||||||
kernel.fs.update(initdisks)
|
local entrys = string.split(fstab,"\n")
|
||||||
for i,v in ipairs(string.split(fstab,"\n")) do
|
for i,v in ipairs(entrys) do
|
||||||
if v:sub(1,1)=="U" then
|
if v:sub(1,1)=="U" then
|
||||||
local id=""
|
local id=""
|
||||||
for i=3,#v do
|
for i=3,#v do
|
||||||
@@ -14,9 +14,13 @@ for i,v in ipairs(string.split(fstab,"\n")) do
|
|||||||
id=v:sub(3,i-1)
|
id=v:sub(3,i-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local path=v:sub(#id+4)
|
local path=v:sub(#id+4,#v)
|
||||||
|
if i~=#entrys then
|
||||||
|
path=path:sub(1,#path-1)
|
||||||
|
end
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
kernel.log("Mounted "..id.." to "..path)
|
||||||
kernel.fs.mount(id,path)
|
kernel.fs.mount(id,path)
|
||||||
::endline::
|
::endline::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Mounted all disks")
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
||||||
while true do
|
while true do
|
||||||
local event={kernel.computer:getMachineEvent()}
|
local event={kernel.computer:getMachineEvent()}
|
||||||
@@ -10,3 +10,4 @@ kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
|||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Created keventd daemon")
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[2]
|
local kernel = args[1]
|
||||||
|
kernel.log("Loading third party drivers")
|
||||||
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
|
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
|
||||||
|
if kernel.fs.isDir("/lib/modules/"..subf) then
|
||||||
if subf~="Hyperion" then
|
if subf~="Hyperion" then
|
||||||
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
|
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
|
||||||
|
kernel.log("Compiling driver \""..subf..":"..driver.."\"")
|
||||||
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
|
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
|
||||||
local func, err = load(code, "@"..driver)
|
local func, err = load(code, "@"..driver)
|
||||||
if not func then
|
if not func then
|
||||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
|
||||||
else
|
else
|
||||||
local ok, err = xpcall(func, debug.traceback)
|
local ok, err = xpcall(func, debug.traceback, table.unpack(args))
|
||||||
if not ok then
|
if not ok then
|
||||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
kernel.log("DriverExecErr: "..tostring(err), "ERROR")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
|
kernel.log("initializing third party drivers")
|
||||||
for _,l in ipairs(kernel.drivers.prior) do
|
for _,v in ipairs(kernel.drivers.raw) do
|
||||||
for _,d in ipairs(l) do
|
if v.arch==kernel.arch then
|
||||||
if d.init then
|
if v.load then
|
||||||
local ok,err = xpcall(d.init, debug.traceback)
|
kernel.log("Loading "..v.name)
|
||||||
if not ok then kernel.log("DriverInitErr: "..tostring(err)) end
|
local ok,err = xpcall(v.load, debug.traceback)
|
||||||
|
if not ok then
|
||||||
|
kernel.log("DriverLoadErr: "..tostring(err))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,17 +1,25 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
local tasks={}
|
local tasks={}
|
||||||
local currentTask={}
|
local currentTask={}
|
||||||
local signals={}
|
local signals={}
|
||||||
local tid=1
|
local tid=2
|
||||||
local gid=1
|
local gid=2
|
||||||
|
local hookuuid=0
|
||||||
local sys={}
|
local sys={}
|
||||||
|
|
||||||
function sys.hookSig(sig, func)
|
function sys.hookSig(sig, func)
|
||||||
if not signals[tostring(currentTask.pid)][sig] then
|
if not currentTask.signal[sig] then
|
||||||
signals[tostring(currentTask.pid)][sig]={}
|
currentTask.signal[sig]={}
|
||||||
end
|
end
|
||||||
signals[tostring(currentTask.pid)][sig][#signals[tostring(currentTask.pid)][sig]+1]=func
|
hookuuid=hookuuid+1
|
||||||
|
currentTask.signal[sig][tostring(hookuuid)]=func
|
||||||
|
callbackid=tostring(hookuuid)
|
||||||
|
return {
|
||||||
|
remove=function()
|
||||||
|
currentTask.signal[sig][callbackid]=nil
|
||||||
|
end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.clearSigHooks(typ)
|
function sys.clearSigHooks(typ)
|
||||||
@@ -27,7 +35,7 @@ end
|
|||||||
|
|
||||||
function sys.sendSig(pid, signal, ...)
|
function sys.sendSig(pid, signal, ...)
|
||||||
if pid=="all" then
|
if pid=="all" then
|
||||||
for i,v in pairs(tasks) do
|
for i,v in pairs(tasks) do+
|
||||||
v.sigQ[#v.sigQ+1]={signal, ...}
|
v.sigQ[#v.sigQ+1]={signal, ...}
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
@@ -38,31 +46,35 @@ function sys.sendSig(pid, signal, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function sys.flushSigs()
|
function sys.flushSigs()
|
||||||
local ret = {}
|
local sigs = {}
|
||||||
for i=1, #currentTask.sigQ do
|
for i,v in ipairs(currentTask.sigQ) do
|
||||||
if currentTask.signal[currentTask.sigQ[i][1]] then
|
sigs[i]=v
|
||||||
for _,v in ipairs(currentTask.signal[currentTask.sigQ[1][1]]) do
|
|
||||||
coroutine.resumeWithTimeout(coroutine.create(function()
|
|
||||||
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1)))
|
|
||||||
if not ok then
|
|
||||||
table.insert(ret, err)
|
|
||||||
end
|
end
|
||||||
end), 10)
|
for i=1, #sigs do
|
||||||
|
local sig = sigs[i]
|
||||||
|
if currentTask.signal[sig[1]] then
|
||||||
|
for k,v in pairs(currentTask.signal[sig[1]]) do
|
||||||
|
coroutine.resumeWithTimeout(coroutine.create(function()
|
||||||
|
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
|
||||||
|
if not ok and sig[1]~="callbackErr" then
|
||||||
|
sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
|
||||||
|
end
|
||||||
|
end),10)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,v in ipairs(currentTask.signal["unhandledEvent"]) do
|
for k,v in pairs(currentTask.signal["unhandledSignal"]) do
|
||||||
coroutine.resumeWithTimeout(coroutine.create(function()
|
coroutine.resumeWithTimeout(coroutine.create(function()
|
||||||
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1)))
|
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
|
||||||
if not ok then
|
if not ok and sig[1]~="callbackErr" then
|
||||||
table.insert(ret, err)
|
sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
|
||||||
end
|
end
|
||||||
end), 10)
|
end),10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.spawn(func, name, evars, args)
|
function sys.spawn(func, name, evars, args, stdin, stdout, stderr)
|
||||||
local id=tid
|
local id=tid
|
||||||
tid=tid+1
|
tid=tid+1
|
||||||
name=name or tostring(id)
|
name=name or tostring(id)
|
||||||
@@ -89,6 +101,7 @@ function sys.spawn(func, name, evars, args)
|
|||||||
vy=0,
|
vy=0,
|
||||||
ivy=0,
|
ivy=0,
|
||||||
status="R",
|
status="R",
|
||||||
|
sleep=0,
|
||||||
signal=signals[tostring(id)],
|
signal=signals[tostring(id)],
|
||||||
parent=currentTask,
|
parent=currentTask,
|
||||||
children={},
|
children={},
|
||||||
@@ -97,6 +110,12 @@ function sys.spawn(func, name, evars, args)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sys.exit(...)
|
||||||
|
sys.sendSig(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
|
||||||
|
currentTask.status="Z"
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
local function collectZombieProc()
|
local function collectZombieProc()
|
||||||
local ret = {}
|
local ret = {}
|
||||||
for _,v in pairs(tasks) do
|
for _,v in pairs(tasks) do
|
||||||
@@ -116,13 +135,23 @@ local function collectZombieProc()
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.log("initPath is: " .. tostring(kernel.initPath))
|
||||||
signals["1"]={}
|
signals["1"]={}
|
||||||
tasks["1"]={
|
tasks["1"]={
|
||||||
coro=coroutine.create(function()
|
coro=coroutine.create(function()
|
||||||
local ret = {xpcall(kernel.fs.load(kernel.initPath), debug.traceback)}
|
local ok, code_or_err = xpcall(function() return kernel.fs.readAllText(kernel.initPath) end, debug.traceback)
|
||||||
|
if not ok then currentTask.status="Z"; kernel.panic(code_or_err) end
|
||||||
|
local code = code_or_err
|
||||||
|
|
||||||
|
local func, err = load(code, "@SysInit", nil, kernel._U)
|
||||||
|
if not func then currentTask.status="Z"; kernel.panic(err) end
|
||||||
|
|
||||||
|
local ok, err = xpcall(func, debug.traceback, kernel)
|
||||||
if not ok then
|
if not ok then
|
||||||
|
currentTask.status="Z"
|
||||||
kernel.panic(err)
|
kernel.panic(err)
|
||||||
else
|
else
|
||||||
|
currentTask.status="Z"
|
||||||
kernel.panic("Attempted to kill init!")
|
kernel.panic("Attempted to kill init!")
|
||||||
end
|
end
|
||||||
end),
|
end),
|
||||||
@@ -130,27 +159,38 @@ tasks["1"]={
|
|||||||
pid=1,
|
pid=1,
|
||||||
ppid=0,
|
ppid=0,
|
||||||
tgid=1,
|
tgid=1,
|
||||||
user=kernel.user,
|
user="root",
|
||||||
uid=kernel.uid,
|
uid=0,
|
||||||
evars={},
|
evars={},
|
||||||
args={kernel},
|
args={kernel},
|
||||||
vy=0,
|
vy=0,
|
||||||
ivy=0,
|
ivy=0,
|
||||||
status="R",
|
status="R",
|
||||||
|
sleep=0,
|
||||||
signal=signals["1"],
|
signal=signals["1"],
|
||||||
parent={name="Hyprkrnl",pid=0},
|
parent={name="Hyprkrnl",pid=0},
|
||||||
children={},
|
children={},
|
||||||
sibling={},
|
sibling={},
|
||||||
sigQ={}
|
sigQ={}
|
||||||
}
|
}
|
||||||
kernel.chache.preload.sys=sys
|
tasks["1"].sibling={tasks["1"]}
|
||||||
kernel.chache.preload.system=sys
|
|
||||||
|
kernel.log("Created pid 1")
|
||||||
|
kernel.cache.preload.sys=table.proxy(sys)
|
||||||
|
kernel.cache.preload.system=kernel.cache.preload.sys
|
||||||
|
kernel.cache.preload.os=kernel.cache.preload.sys
|
||||||
kernel.hpv=sys
|
kernel.hpv=sys
|
||||||
|
kernel.tasks=tasks
|
||||||
|
kernel.signals=signals
|
||||||
|
kernel.currentTask=currentTask
|
||||||
|
|
||||||
kernel.saveLog()
|
kernel.saveLog()
|
||||||
while true do
|
kernel.status="running"
|
||||||
for _,v in pairs(tasks) do
|
while kernel.status~="Panic" do
|
||||||
|
for k,v in pairs(tasks) do
|
||||||
currentTask=v
|
currentTask=v
|
||||||
|
kernel.currentTask=v
|
||||||
|
kernel.process=currentTask.name
|
||||||
kernel.user=currentTask.user
|
kernel.user=currentTask.user
|
||||||
kernel.uid=currentTask.uid
|
kernel.uid=currentTask.uid
|
||||||
sys.flushSigs()
|
sys.flushSigs()
|
||||||
@@ -164,4 +204,7 @@ while true do
|
|||||||
collectZombieProc()
|
collectZombieProc()
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.panic("Exited pid 0")
|
kernel.process="Kernel"
|
||||||
|
kernel.user="root"
|
||||||
|
kernel.uid=0
|
||||||
|
kernel.panic(kernel.reason or "Exited pid 0")
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local apis=args[1]
|
|
||||||
local drivers=args[2]
|
|
||||||
local driver={}
|
|
||||||
|
|
||||||
driver.name="CCT TTO Module"
|
|
||||||
driver.version="0.1.0"
|
|
||||||
driver.description="CCT TTO Module Kernel Module"
|
|
||||||
driver.arch="cct"
|
|
||||||
driver.author="HyperionOS Dev Team"
|
|
||||||
driver.license="MIT"
|
|
||||||
driver.api={}
|
|
||||||
|
|
||||||
colors={
|
|
||||||
0x000000, -- #000000
|
|
||||||
0xFFFFFF, -- #FFFFFF
|
|
||||||
0xFF0000, -- #FF0000
|
|
||||||
0x00FF00, -- #00FF00
|
|
||||||
0x0000FF, -- #0000FF
|
|
||||||
0x00FFFF, -- #00FFFF
|
|
||||||
0xFF00FF, -- #FF00FF
|
|
||||||
0xFFFF00, -- #FFFF00
|
|
||||||
0xFF6D00, -- #FF6D00
|
|
||||||
0x6DFF55, -- #6DFF55
|
|
||||||
0x24FFFF, -- #24FFFF
|
|
||||||
0x924900, -- #924900
|
|
||||||
0x6D6D55, -- #6D6D55
|
|
||||||
0xDBDBAA, -- #DBDBAA
|
|
||||||
0x6D00FF, -- #6D00FF
|
|
||||||
0xB6FF00 -- #B6FF00
|
|
||||||
}
|
|
||||||
|
|
||||||
icolors={
|
|
||||||
[0x1] =0, -- #000000
|
|
||||||
[0x2] =1, -- #FFFFFF
|
|
||||||
[0x4] =2, -- #FF0000
|
|
||||||
[0x8] =3, -- #00FF00
|
|
||||||
[0x10] =4, -- #0000FF
|
|
||||||
[0x20] =5, -- #00FFFF
|
|
||||||
[0x40] =6, -- #FF00FF
|
|
||||||
[0x80] =7, -- #FFFF00
|
|
||||||
[0x100] =8, -- #FF6D00
|
|
||||||
[0x200] =9, -- #6DFF55
|
|
||||||
[0x400] =10, -- #24FFFF
|
|
||||||
[0x800] =11, -- #924900
|
|
||||||
[0x1000] =12, -- #6D6D55
|
|
||||||
[0x2000] =13, -- #DBDBAA
|
|
||||||
[0x4000] =14, -- #6D00FF
|
|
||||||
[0x8000] =15 -- #B6FF00
|
|
||||||
}
|
|
||||||
|
|
||||||
function driver.load()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.unload()
|
|
||||||
-- Nothing to unload
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.reload()
|
|
||||||
-- Nothing to reload
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.main()
|
|
||||||
-- Nothing to run
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.print(text)
|
|
||||||
apis.term.write(text.."\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.printInline(text)
|
|
||||||
apis.term.write(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.clear()
|
|
||||||
apis.term.clear()
|
|
||||||
apis.term.setCursorPos(1,1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getSize()
|
|
||||||
return apis.term.getSize()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setBackgroundColor(index)
|
|
||||||
apis.term.setBackgroundColor(colors[index] or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setForegroundColor(index)
|
|
||||||
apis.term.setTextColor(colors[index] or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setCursorPos(x, y)
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getCursorPos()
|
|
||||||
return apis.term.getCursorPos()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getBackgroundColor()
|
|
||||||
return icolors[apis.term.getBackgroundColor()]
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getForegroundColor()
|
|
||||||
return icolors[apis.term.getTextColor()]
|
|
||||||
end
|
|
||||||
|
|
||||||
drivers.register(driver)
|
|
||||||
@@ -1,8 +1,3 @@
|
|||||||
local args={...}
|
local args={...}
|
||||||
local kernel=args[1]
|
local kernel=args[1]
|
||||||
|
kernel.fs.load("/bin/bash")()
|
||||||
kernel.panic("text")
|
|
||||||
|
|
||||||
for i,v in ipairs(kernel.fs.list("/dev")) do
|
|
||||||
kernl.log(v)
|
|
||||||
end
|
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
U $;/
|
U $;/
|
||||||
U devfs0000;/dev/
|
U devfs0000;/dev/
|
||||||
|
U sysfs0000;/sys/
|
||||||
@@ -1,8 +1,3 @@
|
|||||||
local args={...}
|
local args={...}
|
||||||
local kernel=args[1]
|
local kernel=args[1]
|
||||||
|
kernel.fs.load("/bin/bash")()
|
||||||
kernel.panic("text")
|
|
||||||
|
|
||||||
for i,v in ipairs(kernel.fs.list("/dev")) do
|
|
||||||
kernl.log(v)
|
|
||||||
end
|
|
||||||
26
Test/Hyperion-firmware-cct-v0.1.0/lib/modules/CC-Tweaked/redstone.kmod
Executable file
26
Test/Hyperion-firmware-cct-v0.1.0/lib/modules/CC-Tweaked/redstone.kmod
Executable file
@@ -0,0 +1,26 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
local driver={}
|
||||||
|
|
||||||
|
driver.name="CCT Term Module"
|
||||||
|
driver.version="0.1.0"
|
||||||
|
driver.type="gpio"
|
||||||
|
driver.description="CCT redstone Module Kernel Module"
|
||||||
|
driver.arch="cct"
|
||||||
|
driver.author="HyperionOS Dev Team"
|
||||||
|
driver.license="MIT"
|
||||||
|
driver.api={}
|
||||||
|
|
||||||
|
function driver.load()
|
||||||
|
-- will
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.unload()
|
||||||
|
-- Nothing to unload
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.main()
|
||||||
|
-- Nothing to run
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.drivers.register(driver)
|
||||||
105
Test/Hyperion-firmware-cct-v0.1.0/lib/modules/CC-Tweaked/tty.kmod
Executable file
105
Test/Hyperion-firmware-cct-v0.1.0/lib/modules/CC-Tweaked/tty.kmod
Executable file
@@ -0,0 +1,105 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
local apis=kernel.apis
|
||||||
|
local native=apis.peripheral
|
||||||
|
local driver={}
|
||||||
|
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||||
|
|
||||||
|
local function getType(name)
|
||||||
|
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
|
||||||
|
return native.call(side, "getTypeRemote", name)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
|
||||||
|
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.hasType(side, "peripheral_hub") then
|
||||||
|
local hubSides = native.call(side, "getConnectedSides")
|
||||||
|
for _, hubSide in ipairs(hubSides) do
|
||||||
|
table.insert(names, hubSide)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return names
|
||||||
|
end
|
||||||
|
|
||||||
|
driver.name="CCT TTY Module"
|
||||||
|
driver.version="0.1.0"
|
||||||
|
driver.type="tty"
|
||||||
|
driver.description="CCT TTY Module Kernel Module"
|
||||||
|
driver.arch="cct"
|
||||||
|
driver.author="HyperionOS Dev Team"
|
||||||
|
driver.license="MIT"
|
||||||
|
driver.api={}
|
||||||
|
|
||||||
|
local colors={
|
||||||
|
[0]=0x000000, -- #000000
|
||||||
|
0xFFFFFF, -- #FFFFFF
|
||||||
|
0xFF0000, -- #FF0000
|
||||||
|
0x00FF00, -- #00FF00
|
||||||
|
0x0000FF, -- #0000FF
|
||||||
|
0x00FFFF, -- #00FFFF
|
||||||
|
0xFF00FF, -- #FF00FF
|
||||||
|
0xFFFF00, -- #FFFF00
|
||||||
|
0xFF6D00, -- #FF6D00
|
||||||
|
0x6DFF55, -- #6DFF55
|
||||||
|
0x24FFFF, -- #24FFFF
|
||||||
|
0x924900, -- #924900
|
||||||
|
0x6D6D55, -- #6D6D55
|
||||||
|
0xDBDBAA, -- #DBDBAA
|
||||||
|
0x6D00FF, -- #6D00FF
|
||||||
|
0xB6FF00 -- #B6FF00
|
||||||
|
}
|
||||||
|
|
||||||
|
local icolors={
|
||||||
|
[0x1] =0, -- #000000
|
||||||
|
[0x2] =1, -- #FFFFFF
|
||||||
|
[0x4] =2, -- #FF0000
|
||||||
|
[0x8] =3, -- #00FF00
|
||||||
|
[0x10] =4, -- #0000FF
|
||||||
|
[0x20] =5, -- #00FFFF
|
||||||
|
[0x40] =6, -- #FF00FF
|
||||||
|
[0x80] =7, -- #FFFF00
|
||||||
|
[0x100] =8, -- #FF6D00
|
||||||
|
[0x200] =9, -- #6DFF55
|
||||||
|
[0x400] =10, -- #24FFFF
|
||||||
|
[0x800] =11, -- #924900
|
||||||
|
[0x1000] =12, -- #6D6D55
|
||||||
|
[0x2000] =13, -- #DBDBAA
|
||||||
|
[0x4000] =14, -- #6D00FF
|
||||||
|
[0x8000] =15 -- #B6FF00
|
||||||
|
}
|
||||||
|
|
||||||
|
local function getAllScreens()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
local function wrapScreens()
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.load()
|
||||||
|
-- Nothing to load
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.unload()
|
||||||
|
-- Nothing to unload
|
||||||
|
end
|
||||||
|
|
||||||
|
function driver.main()
|
||||||
|
-- Nothing to run
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.drivers.register(driver)
|
||||||
@@ -1,109 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local apis=args[1]
|
|
||||||
local drivers=args[2]
|
|
||||||
local driver={}
|
|
||||||
|
|
||||||
driver.name="CCT TTO Module"
|
|
||||||
driver.version="0.1.0"
|
|
||||||
driver.description="CCT TTO Module Kernel Module"
|
|
||||||
driver.arch="cct"
|
|
||||||
driver.author="HyperionOS Dev Team"
|
|
||||||
driver.license="MIT"
|
|
||||||
driver.api={}
|
|
||||||
|
|
||||||
colors={
|
|
||||||
0x000000, -- #000000
|
|
||||||
0xFFFFFF, -- #FFFFFF
|
|
||||||
0xFF0000, -- #FF0000
|
|
||||||
0x00FF00, -- #00FF00
|
|
||||||
0x0000FF, -- #0000FF
|
|
||||||
0x00FFFF, -- #00FFFF
|
|
||||||
0xFF00FF, -- #FF00FF
|
|
||||||
0xFFFF00, -- #FFFF00
|
|
||||||
0xFF6D00, -- #FF6D00
|
|
||||||
0x6DFF55, -- #6DFF55
|
|
||||||
0x24FFFF, -- #24FFFF
|
|
||||||
0x924900, -- #924900
|
|
||||||
0x6D6D55, -- #6D6D55
|
|
||||||
0xDBDBAA, -- #DBDBAA
|
|
||||||
0x6D00FF, -- #6D00FF
|
|
||||||
0xB6FF00 -- #B6FF00
|
|
||||||
}
|
|
||||||
|
|
||||||
icolors={
|
|
||||||
[0x1] =0, -- #000000
|
|
||||||
[0x2] =1, -- #FFFFFF
|
|
||||||
[0x4] =2, -- #FF0000
|
|
||||||
[0x8] =3, -- #00FF00
|
|
||||||
[0x10] =4, -- #0000FF
|
|
||||||
[0x20] =5, -- #00FFFF
|
|
||||||
[0x40] =6, -- #FF00FF
|
|
||||||
[0x80] =7, -- #FFFF00
|
|
||||||
[0x100] =8, -- #FF6D00
|
|
||||||
[0x200] =9, -- #6DFF55
|
|
||||||
[0x400] =10, -- #24FFFF
|
|
||||||
[0x800] =11, -- #924900
|
|
||||||
[0x1000] =12, -- #6D6D55
|
|
||||||
[0x2000] =13, -- #DBDBAA
|
|
||||||
[0x4000] =14, -- #6D00FF
|
|
||||||
[0x8000] =15 -- #B6FF00
|
|
||||||
}
|
|
||||||
|
|
||||||
function driver.load()
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.unload()
|
|
||||||
-- Nothing to unload
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.reload()
|
|
||||||
-- Nothing to reload
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.main()
|
|
||||||
-- Nothing to run
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.print(text)
|
|
||||||
apis.term.write(text.."\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.printInline(text)
|
|
||||||
apis.term.write(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.clear()
|
|
||||||
apis.term.clear()
|
|
||||||
apis.term.setCursorPos(1,1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getSize()
|
|
||||||
return apis.term.getSize()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setBackgroundColor(index)
|
|
||||||
apis.term.setBackgroundColor(colors[index] or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setForegroundColor(index)
|
|
||||||
apis.term.setTextColor(colors[index] or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.setCursorPos(x, y)
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getCursorPos()
|
|
||||||
return apis.term.getCursorPos()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getBackgroundColor()
|
|
||||||
return icolors[apis.term.getBackgroundColor()]
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getForegroundColor()
|
|
||||||
return icolors[apis.term.getTextColor()]
|
|
||||||
end
|
|
||||||
|
|
||||||
drivers.register(driver)
|
|
||||||
@@ -14,22 +14,26 @@ kernel.group = "root"
|
|||||||
kernel.groups = {0}
|
kernel.groups = {0}
|
||||||
kernel.uid = 0
|
kernel.uid = 0
|
||||||
kernel.gid = 0
|
kernel.gid = 0
|
||||||
kernel.stage = "start"
|
kernel.status = "start"
|
||||||
kernel.key = {}
|
kernel.key = {}
|
||||||
kernel.chache = {}
|
kernel.cache = {}
|
||||||
kernel.chache.preload = {}
|
kernel.cache.preload = {}
|
||||||
|
kernel._G=_G
|
||||||
local windowsExp = false
|
local windowsExp = false
|
||||||
|
|
||||||
function kernel.log(msg, level)
|
function kernel.log(msg, level)
|
||||||
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
LOG_Text = LOG_Text..tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||||
if kernel.stage == "start" then
|
if kernel.status == "start" then
|
||||||
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
screen:print(tostring(computer.time()).." "..kernel.user.." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.PANIC(msg)
|
function kernel.PANIC(msg)
|
||||||
|
if kernel.status~="Panic" then
|
||||||
kernel.log("PANIC: "..msg, "PANIC")
|
kernel.log("PANIC: "..msg, "PANIC")
|
||||||
pcall(kernel["saveLog"])
|
pcall(kernel["saveLog"])
|
||||||
|
kernel.status="Panic"
|
||||||
|
kernel.reason=msg
|
||||||
screen:setTextColor(2)
|
screen:setTextColor(2)
|
||||||
screen:setBackgroundColor(0)
|
screen:setBackgroundColor(0)
|
||||||
screen:clear()
|
screen:clear()
|
||||||
@@ -37,6 +41,7 @@ function kernel.PANIC(msg)
|
|||||||
screen:print(LOG_Text)
|
screen:print(LOG_Text)
|
||||||
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
screen:print("KERNEL PANIC!\n"..msg.."\nSystem halted.")
|
||||||
screen:print("Press any key to continue...")
|
screen:print("Press any key to continue...")
|
||||||
|
end
|
||||||
while true do
|
while true do
|
||||||
local event={computer:getMachineEvent()}
|
local event={computer:getMachineEvent()}
|
||||||
if event[1]=="keyPressed" then
|
if event[1]=="keyPressed" then
|
||||||
@@ -65,16 +70,12 @@ if windowsExp then
|
|||||||
while true do end
|
while true do end
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("Kernel loaded.", "INFO")
|
kernel.log("Kernel loaded.")
|
||||||
kernel.log("Mounting disks...", "INFO")
|
kernel.log("Mounting init disks...")
|
||||||
disks.refresh()
|
disks.refresh()
|
||||||
ifs.update(disks)
|
ifs.update(disks)
|
||||||
ifs.mount("$", "/")
|
ifs.mount("$", "/")
|
||||||
|
|
||||||
function kernel.saveLog()
|
|
||||||
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
|
|
||||||
end
|
|
||||||
|
|
||||||
local fstab=ifs.readAllText("/etc/fstab")
|
local fstab=ifs.readAllText("/etc/fstab")
|
||||||
local split = function(str, delim, maxResultCountOrNil)
|
local split = function(str, delim, maxResultCountOrNil)
|
||||||
assert(#delim == 1, "only delim len 1 supported for now")
|
assert(#delim == 1, "only delim len 1 supported for now")
|
||||||
@@ -104,11 +105,15 @@ for i,v in ipairs(split(fstab,"\n")) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
local path=v:sub(#id+4)
|
local path=v:sub(#id+4)
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
|
||||||
ifs.mount(id,path)
|
ifs.mount(id,path)
|
||||||
::endline::
|
::endline::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Disks initialized")
|
||||||
|
|
||||||
|
function kernel.saveLog()
|
||||||
|
ifs.writeAllText("/var/log/syslog.log", LOG_Text)
|
||||||
|
end
|
||||||
|
|
||||||
ifs.remove("/tmp")
|
ifs.remove("/tmp")
|
||||||
ifs.makeDir("/tmp")
|
ifs.makeDir("/tmp")
|
||||||
@@ -116,29 +121,24 @@ ifs.makeDir("/tmp")
|
|||||||
local drivers={}
|
local drivers={}
|
||||||
drivers.raw={}
|
drivers.raw={}
|
||||||
drivers.processes={}
|
drivers.processes={}
|
||||||
drivers.prior={}
|
|
||||||
drivers.type={}
|
drivers.type={}
|
||||||
for i=0, 99 do
|
|
||||||
drivers.prior[i]={}
|
|
||||||
end
|
|
||||||
|
|
||||||
function drivers.register(prior,object)
|
function drivers.register(object)
|
||||||
drivers.raw[#drivers.raw+1]=object
|
drivers.raw[#drivers.raw+1]=object
|
||||||
if object.main then drivers.processes[#drivers.processes+1]=object.main end
|
if object.main then drivers.processes[#drivers.processes+1]=object.main end
|
||||||
if drivers.prior[prior]==nil then drivers.prior[prior]={} end
|
|
||||||
drivers.prior[prior][#drivers.prior[prior]+1]=object
|
|
||||||
if drivers.type[object.type]==nil then drivers.type[object.type]={} end
|
if drivers.type[object.type]==nil then drivers.type[object.type]={} end
|
||||||
drivers.type[object.type][#drivers.type[object.type]+1]=object
|
drivers.type[object.type][#drivers.type[object.type]+1]=object
|
||||||
end
|
end
|
||||||
|
|
||||||
local modules={}
|
local modules={[0]={}}
|
||||||
for i=0, 99 do
|
for i=0, 100 do
|
||||||
modules[i]={}
|
modules[i]={}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.log("Gathering modules")
|
||||||
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
|
for i,v in ipairs(ifs.list("/lib/modules/Hyperion/")) do
|
||||||
local prior=tonumber(v:sub(1,2))
|
local prior=tonumber(v:sub(1,2))
|
||||||
modules[prior][#modules[prior]+1]="/lib/modules/Hyperion/"..v
|
modules[prior+1][#modules[prior+1]+1]="/lib/modules/Hyperion/"..v
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.drivers=drivers
|
kernel.drivers=drivers
|
||||||
@@ -147,19 +147,17 @@ kernel.apis=apis
|
|||||||
kernel.computer=computer
|
kernel.computer=computer
|
||||||
kernel.initPath=initPath
|
kernel.initPath=initPath
|
||||||
kernel.arch=arch
|
kernel.arch=arch
|
||||||
kernel.initdisks=initdisks
|
kernel.initdisks=disks
|
||||||
kernel.screen=screen
|
kernel.screen=screen
|
||||||
|
|
||||||
|
kernel.log("Running modules")
|
||||||
for _,p in ipairs(modules) do
|
for _,p in ipairs(modules) do
|
||||||
for _,v in ipairs(p) do
|
for _,v in ipairs(p) do
|
||||||
local code=ifs.readAllText(v)
|
local code=ifs.readAllText(v)
|
||||||
local func,err=load(code,"@"..v)
|
local func,err=load(code,"@"..v)
|
||||||
if not func then kernel.log("ModuLoadErr: "..tostring(err)) goto skip end
|
if not func then kernel.log("ModuLoadErr: "..tostring(err), "WARN") goto skip end
|
||||||
local status, err = xpcall(func,debug.traceback,kernel)
|
local status, err = xpcall(func,debug.traceback, kernel)
|
||||||
if not status then goto skip end
|
if not status then kernel.log("ModuRunErr: "..tostring(err), "WARN") end
|
||||||
if not err then goto skip end
|
|
||||||
if not err.init then goto skip end
|
|
||||||
local ok, err = xpcall(status.main,debug.traceback)
|
|
||||||
if not ok then kernel.log("ModuInitErr: "..tostring(err)) end
|
|
||||||
::skip::
|
::skip::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,5 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
function string.hasSuffix(str, suffix)
|
function string.hasSuffix(str, suffix)
|
||||||
return string.sub(str, #suffix+1) == suffix
|
return string.sub(str, #suffix+1) == suffix
|
||||||
end
|
end
|
||||||
@@ -94,6 +96,62 @@ function table.hasVal(tabl, query)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.proxy(tbl)
|
||||||
|
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
|
||||||
|
|
||||||
|
local function createProxy(t)
|
||||||
|
if type(t) ~= "table" then return t end
|
||||||
|
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
|
||||||
|
|
||||||
|
local proxy = {}
|
||||||
|
proxies[t] = proxy
|
||||||
|
|
||||||
|
local mt
|
||||||
|
mt = {
|
||||||
|
__index = function(_, k)
|
||||||
|
local value = t[k]
|
||||||
|
if type(value) == "table" then
|
||||||
|
return createProxy(value) -- recursively proxy subtables
|
||||||
|
else
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__newindex = function()
|
||||||
|
error("Attempt to modify read-only table", 2)
|
||||||
|
end,
|
||||||
|
__pairs = function()
|
||||||
|
return function(_, k)
|
||||||
|
local nextKey, nextValue = next(t, k)
|
||||||
|
if type(nextValue) == "table" then
|
||||||
|
nextValue = createProxy(nextValue)
|
||||||
|
end
|
||||||
|
return nextKey, nextValue
|
||||||
|
end, nil, nil
|
||||||
|
end,
|
||||||
|
__ipairs = function()
|
||||||
|
local i = 0
|
||||||
|
local n = #t
|
||||||
|
return function()
|
||||||
|
i = i + 1
|
||||||
|
if i <= n then
|
||||||
|
local v = t[i]
|
||||||
|
if type(v) == "table" then
|
||||||
|
v = createProxy(v)
|
||||||
|
end
|
||||||
|
return i, v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
__metatable = false
|
||||||
|
}
|
||||||
|
|
||||||
|
setmetatable(proxy, mt)
|
||||||
|
return proxy
|
||||||
|
end
|
||||||
|
|
||||||
|
return createProxy(tbl)
|
||||||
|
end
|
||||||
|
|
||||||
local function serialize(table)
|
local function serialize(table)
|
||||||
local output = "{"
|
local output = "{"
|
||||||
for i,v in pairs(table) do
|
for i,v in pairs(table) do
|
||||||
@@ -119,7 +177,7 @@ local function serialize(table)
|
|||||||
output=output.."false"
|
output=output.."false"
|
||||||
end
|
end
|
||||||
elseif type(v) == "function" then
|
elseif type(v) == "function" then
|
||||||
output=output.."function() end"
|
output=output..tostring(v)
|
||||||
else
|
else
|
||||||
error("serialization of type \""..type(v).."\" is not supported")
|
error("serialization of type \""..type(v).."\" is not supported")
|
||||||
end
|
end
|
||||||
@@ -135,3 +193,4 @@ local function serialize(table)
|
|||||||
end
|
end
|
||||||
|
|
||||||
table.serialize=serialize
|
table.serialize=serialize
|
||||||
|
kernel.log("Loaded stdlib")
|
||||||
3
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/05_userspace.kmod
Executable file
3
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/05_userspace.kmod
Executable file
@@ -0,0 +1,3 @@
|
|||||||
|
local args={...}
|
||||||
|
local kernel=args[1]
|
||||||
|
kernel._U=table.proxy(_G)
|
||||||
@@ -1,217 +1,321 @@
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
local fs = {}
|
local fs = {}
|
||||||
local disks = {}
|
|
||||||
local mounts = {["/"]="$"}
|
|
||||||
|
|
||||||
-- path normaliing
|
-- =====================================================================
|
||||||
local function normalizePath(path)
|
-- INTERNAL STATE
|
||||||
if not path or path == "" then return "/" end
|
-- =====================================================================
|
||||||
if path:sub(1,1) ~= "/" then path = "/" .. path end
|
|
||||||
local parts = {}
|
|
||||||
for part in path:gmatch("[^/]+") do
|
|
||||||
if part == ".." then
|
|
||||||
if #parts > 0 then table.remove(parts) end
|
|
||||||
elseif part ~= "." and part ~= "" then
|
|
||||||
parts[#parts+1] = part
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return "/" .. table.concat(parts, "/")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- disk resolution
|
local disks = {} -- address → disk object
|
||||||
local function resolvePath(path)
|
local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk)
|
||||||
local abs = normalizePath(path)
|
|
||||||
local best = "/"
|
|
||||||
for mount, diskAddr in pairs(mounts) do
|
|
||||||
if abs:sub(1, #mount) == mount and #mount > #best then
|
|
||||||
best = mount
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local newPath = abs:sub(#best + 1)
|
|
||||||
if newPath == "" then newPath = "/" end
|
|
||||||
return disks[mounts[best]], newPath
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Symlinks
|
|
||||||
-- Format: #!@SYMLINK[target]
|
|
||||||
local SYMLINK_PREFIX = "#!@SYMLINK["
|
local SYMLINK_PREFIX = "#!@SYMLINK["
|
||||||
local SYMLINK_SUFFIX = "]"
|
local SYMLINK_SUFFIX = "]"
|
||||||
local SYMLINK_MAX_DEPTH = 64
|
local SYMLINK_MAX_DEPTH = 64
|
||||||
|
|
||||||
local function isSymlink(disk, path)
|
|
||||||
if not disk:fileExists(path) then return false end
|
-- =====================================================================
|
||||||
local text = disk:readAllText(path)
|
-- PATH NORMALIZATION
|
||||||
if not text then return false end
|
-- =====================================================================
|
||||||
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
|
||||||
|
local function splitPath(p)
|
||||||
|
local t = {}
|
||||||
|
for part in p:gmatch("[^/]+") do t[#t+1] = part end
|
||||||
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
local function readSymlink(disk, path)
|
local function normalizePath(path)
|
||||||
local text = disk:readAllText(path)
|
if not path or path == "" then return "/" end
|
||||||
|
|
||||||
|
-- ensure absolute
|
||||||
|
if path:sub(1,1) ~= "/" then
|
||||||
|
path = "/" .. path
|
||||||
|
end
|
||||||
|
|
||||||
|
local parts = splitPath(path)
|
||||||
|
local out = {}
|
||||||
|
|
||||||
|
for _,part in ipairs(parts) do
|
||||||
|
if part == ".." then
|
||||||
|
if #out > 0 then table.remove(out) end
|
||||||
|
elseif part ~= "." and part ~= "" then
|
||||||
|
out[#out+1] = part
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return "/" .. table.concat(out, "/")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- DISK & MOUNT RESOLUTION
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- Finds which disk owns an absolute path
|
||||||
|
local function resolveMount(abs)
|
||||||
|
local best = "/"
|
||||||
|
|
||||||
|
for mount, addr in pairs(mounts) do
|
||||||
|
if abs:sub(1, #mount) == mount then
|
||||||
|
if #mount > #best then
|
||||||
|
best = mount
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local disk = disks[mounts[best]]
|
||||||
|
if not disk then
|
||||||
|
error("No disk registered for mount: " .. best)
|
||||||
|
end
|
||||||
|
|
||||||
|
local sub = abs:sub(#best + 1)
|
||||||
|
if sub == "" then sub = "/" end
|
||||||
|
return disk, sub
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- SYMLINK HANDLING
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
local function isSymlinkRaw(disk, p)
|
||||||
|
if not disk:fileExists(p) then return false end
|
||||||
|
local text = disk:readAllText(p)
|
||||||
|
return text and text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
||||||
|
end
|
||||||
|
|
||||||
|
local function readSymlinkRaw(disk, p)
|
||||||
|
local text = disk:readAllText(p)
|
||||||
if not text then return nil end
|
if not text then return nil end
|
||||||
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
||||||
local target = text:sub(#SYMLINK_PREFIX + 1)
|
|
||||||
if target:sub(-1) == SYMLINK_SUFFIX then
|
local t = text:sub(#SYMLINK_PREFIX + 1)
|
||||||
target = target:sub(1, -2)
|
if t:sub(-1) == SYMLINK_SUFFIX then
|
||||||
|
t = t:sub(1, -2)
|
||||||
end
|
end
|
||||||
return target
|
return t
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
-- Path resolution
|
-- =====================================================================
|
||||||
local function splitPath(p)
|
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS)
|
||||||
local parts = {}
|
-- =====================================================================
|
||||||
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end
|
|
||||||
return parts
|
|
||||||
end
|
|
||||||
|
|
||||||
local function resolveSymlink(path)
|
local function resolveSymlink(path)
|
||||||
path = normalizePath(path)
|
local abs = normalizePath(path)
|
||||||
local symlinkDepth = 0
|
local parts = splitPath(abs)
|
||||||
local parts = splitPath(path)
|
local out = {}
|
||||||
local resolved = {}
|
|
||||||
local i = 1
|
local depth = 0
|
||||||
|
local idx = 1
|
||||||
|
|
||||||
|
while idx <= #parts do
|
||||||
|
local comp = parts[idx]
|
||||||
|
|
||||||
while i <= #parts do
|
|
||||||
local comp = parts[i]
|
|
||||||
if comp == "." then
|
if comp == "." then
|
||||||
|
-- nothing
|
||||||
elseif comp == ".." then
|
elseif comp == ".." then
|
||||||
if #resolved > 0 then table.remove(resolved) end
|
if #out > 0 then table.remove(out) end
|
||||||
else
|
else
|
||||||
local currentPath = "/" .. table.concat(resolved, "/")
|
local curAbs = "/" .. table.concat(out, "/")
|
||||||
local disk, p = resolvePath(currentPath .. "/" .. comp)
|
if curAbs ~= "/" then curAbs = curAbs .. "/" end
|
||||||
if isSymlink(disk, p) then
|
curAbs = curAbs .. comp
|
||||||
symlinkDepth = symlinkDepth + 1
|
|
||||||
if symlinkDepth > SYMLINK_MAX_DEPTH then
|
local disk, dpath = resolveMount(curAbs)
|
||||||
error("Too many levels of symbolic links: " .. path)
|
|
||||||
|
if isSymlinkRaw(disk, dpath) then
|
||||||
|
depth = depth + 1
|
||||||
|
if depth > SYMLINK_MAX_DEPTH then
|
||||||
|
error("Too many symlink levels: " .. path)
|
||||||
end
|
end
|
||||||
local target = readSymlink(disk, p)
|
|
||||||
if not target then
|
local target = readSymlinkRaw(disk, dpath)
|
||||||
resolved[#resolved+1] = comp
|
if target then
|
||||||
else
|
local newAbs
|
||||||
|
|
||||||
if target:sub(1,1) == "/" then
|
if target:sub(1,1) == "/" then
|
||||||
resolved = splitPath(normalizePath(target))
|
-- absolute target
|
||||||
|
newAbs = normalizePath(target)
|
||||||
else
|
else
|
||||||
local base = resolved
|
-- relative to current out[]
|
||||||
resolved = {}
|
local tmp = "/" .. table.concat(out, "/")
|
||||||
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end
|
if tmp ~= "/" then tmp = tmp .. "/" end
|
||||||
for seg in target:gmatch("[^/]+") do
|
tmp = tmp .. target
|
||||||
if seg == ".." then
|
newAbs = normalizePath(tmp)
|
||||||
if #resolved>0 then table.remove(resolved) end
|
|
||||||
elseif seg ~= "." then
|
|
||||||
resolved[#resolved+1]=seg
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- rebuild remaining parts
|
||||||
local remaining = {}
|
local remaining = {}
|
||||||
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
|
for j = idx + 1, #parts do
|
||||||
parts = remaining
|
remaining[#remaining+1] = parts[j]
|
||||||
i = 0
|
end
|
||||||
|
|
||||||
|
-- restart symlink resolution with new path
|
||||||
|
abs = newAbs
|
||||||
|
parts = splitPath(abs)
|
||||||
|
|
||||||
|
-- append remaining
|
||||||
|
for _,x in ipairs(remaining) do parts[#parts+1] = x end
|
||||||
|
|
||||||
|
out = {}
|
||||||
|
idx = 0
|
||||||
|
else
|
||||||
|
out[#out+1] = comp
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
resolved[#resolved+1]=comp
|
out[#out+1] = comp
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
|
|
||||||
local finalPath="/"..table.concat(resolved,"/")
|
idx = idx + 1
|
||||||
local disk,diskPath=resolvePath(finalPath)
|
end
|
||||||
return disk,diskPath
|
|
||||||
|
local finalAbs = "/" .. table.concat(out, "/")
|
||||||
|
return resolveMount(finalAbs)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- PUBLIC API: MOUNTING
|
|
||||||
function fs.mount(disk, mountPoint)
|
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
-- =====================================================================
|
||||||
mounts[mountPoint]=disk
|
-- PUBLIC API
|
||||||
end
|
-- =====================================================================
|
||||||
function fs.unmount(mountPoint)
|
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
-- MOUNT OPERATIONS -----------------------------------------------------
|
||||||
mounts[mountPoint]=nil
|
|
||||||
end
|
|
||||||
function fs.virtDisk(diskObj)
|
function fs.virtDisk(diskObj)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
if disks[diskObj.address] then error("Disk exists") end
|
if disks[diskObj.address] then
|
||||||
disks[diskObj.address]=diskObj
|
error("Disk exists: " .. diskObj.address)
|
||||||
|
end
|
||||||
|
disks[diskObj.address] = diskObj
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function fs.mount(disk, mountPoint)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
mountPoint = normalizePath(mountPoint)
|
||||||
|
|
||||||
|
local drive, path = resolveMount(normalizePath(mountPoint))
|
||||||
|
if not drive:directoryExists(path) then error("Must mount on folder") end
|
||||||
|
|
||||||
|
if mountPoint ~= "/" and mounts[mountPoint] then
|
||||||
|
error("Already mounted: " .. mountPoint)
|
||||||
|
end
|
||||||
|
|
||||||
|
mounts[mountPoint] = disk
|
||||||
|
end
|
||||||
|
|
||||||
|
function fs.unmount(mountPoint)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
mountPoint = normalizePath(mountPoint)
|
||||||
|
|
||||||
|
if mountPoint == "/" then error("Cannot unmount root") end
|
||||||
|
mounts[mountPoint] = nil
|
||||||
|
end
|
||||||
|
|
||||||
function fs.eject(addr)
|
function fs.eject(addr)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
disks[addr]=nil
|
disks[addr] = nil
|
||||||
end
|
end
|
||||||
|
|
||||||
-- SYMLINK API
|
function fs.isMount(path)
|
||||||
|
if mounts[normalizePath(path)] then return true, mounts[normalizePath(path)] end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- SYMLINK API ----------------------------------------------------------
|
||||||
|
|
||||||
function fs.symlink(target, linkPath)
|
function fs.symlink(target, linkPath)
|
||||||
local disk, p = resolvePath(linkPath)
|
kernel.log("WARNING: Symlinks are a untested feature if you find any bugs please report them to https://git.astronand.dev/Hyperion/HyperionOS","WARN")
|
||||||
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX)
|
local disk, p = resolveMount(normalizePath(linkPath))
|
||||||
|
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isLink(path)
|
function fs.isLink(path)
|
||||||
local disk, p = resolvePath(path)
|
local disk, p = resolveMount(normalizePath(path))
|
||||||
return isSymlink(disk,p)
|
return isSymlinkRaw(disk, p)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.readLink(path)
|
function fs.readLink(path)
|
||||||
local disk, p = resolvePath(path)
|
local disk, p = resolveMount(normalizePath(path))
|
||||||
return readSymlink(disk,p)
|
return readSymlinkRaw(disk, p)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- FILE OPERATIONS
|
|
||||||
function fs.exists(path)
|
-- FILE OPERATIONS ------------------------------------------------------
|
||||||
|
|
||||||
|
function fs.exists(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:fileExists(p) or disk:directoryExists(p)
|
return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isFile(path)
|
function fs.isFile(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
if isSymlink(disk, p) then return false end
|
return disk:fileExists(p, ...)
|
||||||
return disk:fileExists(p)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.isDir(path)
|
function fs.isDir(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
if isSymlink(disk, p) then return false end
|
return disk:directoryExists(p, ...)
|
||||||
return disk:directoryExists(p)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.list(path)
|
function fs.list(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:list(p)
|
return disk:list(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.makeDir(path)
|
function fs.makeDir(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:makeDirectory(p)
|
return disk:makeDirectory(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.remove(path)
|
-- remove does NOT follow symlinks (UNIX semantics)
|
||||||
local disk, p = resolvePath(path)
|
function fs.remove(path, ...)
|
||||||
if isSymlink(disk, p) then
|
if fs.isMount(path) then return "Cannot delete mounted folder" end
|
||||||
return disk:remove(p)
|
local abs = normalizePath(path)
|
||||||
end
|
local disk, p = resolveMount(abs)
|
||||||
local d2, p2 = resolveSymlink(path)
|
return disk:remove(p, ...)
|
||||||
return d2:remove(p2)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.readAllText(path)
|
function fs.readAllText(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:readAllText(p)
|
return disk:readAllText(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.writeAllText(path, text)
|
function fs.writeAllText(path, text, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:writeAllText(p, text)
|
return disk:writeAllText(p, text, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.appendAllText(path, text)
|
function fs.appendAllText(path, text, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:appendAllText(p, text)
|
return disk:appendAllText(p, text, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function fs.getSize(path)
|
function fs.load(path, name, ...)
|
||||||
|
return load(fs.readAllText(path, ...), name or path, nil, kernel._U)
|
||||||
|
end
|
||||||
|
|
||||||
|
function fs.getSize(path, ...)
|
||||||
local disk, p = resolveSymlink(path)
|
local disk, p = resolveSymlink(path)
|
||||||
return disk:getSize(p)
|
return disk:getSize(p, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
-- INIT
|
-- INIT
|
||||||
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end
|
-- =====================================================================
|
||||||
kernel.fs=fs
|
|
||||||
kernel.chache.preload.fs=fs
|
kernel.log("Loading disks for vfs")
|
||||||
kernel.chache.preload.filesystem=fs
|
local ok,err = xpcall(function()
|
||||||
|
for _,v in kernel.initdisks.list() do
|
||||||
|
fs.virtDisk(v)
|
||||||
|
end
|
||||||
|
end, debug.traceback)
|
||||||
|
if not ok then kernel.panic(err) end
|
||||||
|
|
||||||
|
kernel.disks=disks
|
||||||
|
kernel.mounts=mounts
|
||||||
|
kernel.fs = fs
|
||||||
|
kernel.cache.preload.fs = table.proxy(kernel.fs)
|
||||||
|
kernel.cache.preload.filesystem = kernel.cache.preload.fs
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
|
|
||||||
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
local disk = {}
|
local disk = {}
|
||||||
@@ -55,34 +54,36 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
-- File IO (supports string or file-object with read/write funcs)
|
-- File IO (supports string or file-object with read/write funcs)
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
|
|
||||||
local function fileRead(node)
|
local function fileRead(node, ...)
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
return node
|
return node
|
||||||
elseif type(node) == "table" and node.__file and node.read then
|
elseif type(node) == "table" and node.__file and node.read then
|
||||||
return node.read()
|
return node.read(...)
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fileWrite(parent, name, text)
|
local function fileWrite(parent, name, text, ...)
|
||||||
local node = parent[name]
|
local node = parent[name]
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
elseif type(node) == "table" and node.__file and node.write then
|
elseif type(node) == "table" and node.__file and node.write then
|
||||||
return node.write(text)
|
return node.write(text, ...)
|
||||||
end
|
end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
local function fileAppend(parent, name, text)
|
local function fileAppend(parent, name, text, ...)
|
||||||
local node = parent[name]
|
local node = parent[name]
|
||||||
if type(node) == "string" then
|
if type(node) == "string" then
|
||||||
|
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||||
parent[name] = node .. text
|
parent[name] = node .. text
|
||||||
return true
|
return true
|
||||||
elseif type(node) == "table" and node.__file and node.write then
|
elseif type(node) == "table" and node.__file and node.write then
|
||||||
return node.write((node.read() or "") .. text)
|
return node.write((node.read() or "") .. text, ...)
|
||||||
end
|
end
|
||||||
parent[name] = text
|
parent[name] = text
|
||||||
return true
|
return true
|
||||||
@@ -96,26 +97,22 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
function disk:spaceUsed() return 0 end
|
function disk:spaceUsed() return 0 end
|
||||||
function disk:spaceTotal() return 0 end
|
function disk:spaceTotal() return 0 end
|
||||||
|
|
||||||
function disk:readAllText(path)
|
function disk:readAllText(path, ...)
|
||||||
local node = getNode(path)
|
local node = getNode(path)
|
||||||
if not node then return nil, "file not found" end
|
if not node then return nil, "file not found" end
|
||||||
return fileRead(node)
|
return fileRead(node, ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:writeAllText(path, text)
|
function disk:writeAllText(path, text, ...)
|
||||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
||||||
|
|
||||||
local parent, name = getParent(path)
|
local parent, name = getParent(path)
|
||||||
if not parent or not parent.__dir then return false, "invalid directory" end
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
||||||
return fileWrite(parent, name, tostring(text))
|
return fileWrite(parent, name, tostring(text), ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:appendAllText(path, text)
|
function disk:appendAllText(path, text, ...)
|
||||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
|
||||||
|
|
||||||
local parent, name = getParent(path)
|
local parent, name = getParent(path)
|
||||||
if not parent or not parent.__dir then return false, "invalid directory" end
|
if not parent or not parent.__dir then return false, "invalid directory" end
|
||||||
return fileAppend(parent, name, tostring(text))
|
return fileAppend(parent, name, tostring(text), ...)
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:list(path)
|
function disk:list(path)
|
||||||
@@ -161,11 +158,11 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
return label
|
return label
|
||||||
end
|
end
|
||||||
|
|
||||||
function disk:size(path)
|
function disk:size(path, ...)
|
||||||
local node = getNode(path)
|
local node = getNode(path)
|
||||||
if type(node) == "string" then return #node end
|
if type(node) == "string" then return #node end
|
||||||
if type(node) == "table" and node.__file and node.read then
|
if type(node) == "table" and node.__file and node.read then
|
||||||
local v = node.read()
|
local v = node.read(...)
|
||||||
return v and #v or 0
|
return v and #v or 0
|
||||||
end
|
end
|
||||||
return 0
|
return 0
|
||||||
@@ -174,7 +171,7 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
|||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
-- Auto-register with kernel and return backend
|
-- Auto-register with kernel and return backend
|
||||||
-----------------------------------------------------------------
|
-----------------------------------------------------------------
|
||||||
if kernel and kernel.fs and kernel.fs.virtDisk and autoRegister then
|
if autoRegister then
|
||||||
kernel.fs.virtDisk(disk)
|
kernel.fs.virtDisk(disk)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
local args = {...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
|
|
||||||
-- List of search paths
|
-- List of search paths
|
||||||
local paths = {
|
local paths = {
|
||||||
"/lib/?",
|
"/lib/?",
|
||||||
@@ -11,7 +10,7 @@ local paths = {
|
|||||||
-- Custom require implementation
|
-- Custom require implementation
|
||||||
function require(module)
|
function require(module)
|
||||||
-- Return cached module if it already exists
|
-- Return cached module if it already exists
|
||||||
if kernel.cache.preload[module] then
|
if kernel.cache.preload[module]~=nil then
|
||||||
return kernel.cache.preload[module]
|
return kernel.cache.preload[module]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -54,3 +53,4 @@ function require(module)
|
|||||||
-- If nothing worked, raise an error with all reasons
|
-- If nothing worked, raise an error with all reasons
|
||||||
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
|
error("Unable to require module '" .. module .. "':\n" .. table.concat(err, "\n"))
|
||||||
end
|
end
|
||||||
|
kernel.log("Created require")
|
||||||
@@ -1,7 +1,9 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
|
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true)
|
||||||
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", false)
|
if not kernel.fs.isDir("/dev") then kernel.fs.makeDir("/dev") end
|
||||||
|
kernel.devfs={}
|
||||||
|
kernel.devfs.data=data
|
||||||
|
|
||||||
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
||||||
data["/"]["eeprom"]={
|
data["/"]["eeprom"]={
|
||||||
@@ -14,4 +16,42 @@ data["/"]["eeprom"]={
|
|||||||
kernel.computer:setEEPROM(text)
|
kernel.computer:setEEPROM(text)
|
||||||
end
|
end
|
||||||
}
|
}
|
||||||
|
data["/"]["null"]={
|
||||||
|
__file=true,
|
||||||
|
read=function() end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["random"]={
|
||||||
|
__file=true,
|
||||||
|
read=function(amount)
|
||||||
|
local s = ""
|
||||||
|
for i = 1, amount do
|
||||||
|
s = s .. string.char(math.random(0, 255))
|
||||||
|
end
|
||||||
|
return s
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["zero"]={
|
||||||
|
__file=true,
|
||||||
|
read=function(amount)
|
||||||
|
return ("\0"):rep(amount)
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["rtc0"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:time()
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
data["/"]["rtc"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:time()
|
||||||
|
end,
|
||||||
|
write=function() end
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel.log("Created devfs")
|
||||||
18
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/12_sysfs.kmod
Executable file
18
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/12_sysfs.kmod
Executable file
@@ -0,0 +1,18 @@
|
|||||||
|
local args = {...}
|
||||||
|
local kernel = args[1]
|
||||||
|
local data = kernel.fs.mkvirtfs("sysfs0000", true, "sysfs", true)
|
||||||
|
if not kernel.fs.isDir("/sys") then kernel.fs.makeDir("/sys") end
|
||||||
|
|
||||||
|
data["/"]["OSVERSION"]="Hyperion 1.0.0"
|
||||||
|
data["/"]["eeprom"]={
|
||||||
|
__file=true,
|
||||||
|
read=function()
|
||||||
|
return kernel.computer:getEEPROM()
|
||||||
|
end,
|
||||||
|
write=function(text)
|
||||||
|
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||||
|
kernel.computer:setEEPROM(text)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
|
kernel.log("Created sysfs")
|
||||||
0
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/13_procfs.kmod
Executable file
0
Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/13_procfs.kmod
Executable file
@@ -1,11 +1,11 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
local ifs=kernel.ifs
|
local ifs=kernel.ifs
|
||||||
local initdisks=kernel.initdisks
|
|
||||||
|
|
||||||
|
kernel.log("Mounting fstab")
|
||||||
local fstab=ifs.readAllText("/etc/fstab")
|
local fstab=ifs.readAllText("/etc/fstab")
|
||||||
kernel.fs.update(initdisks)
|
local entrys = string.split(fstab,"\n")
|
||||||
for i,v in ipairs(string.split(fstab,"\n")) do
|
for i,v in ipairs(entrys) do
|
||||||
if v:sub(1,1)=="U" then
|
if v:sub(1,1)=="U" then
|
||||||
local id=""
|
local id=""
|
||||||
for i=3,#v do
|
for i=3,#v do
|
||||||
@@ -14,9 +14,13 @@ for i,v in ipairs(string.split(fstab,"\n")) do
|
|||||||
id=v:sub(3,i-1)
|
id=v:sub(3,i-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local path=v:sub(#id+4)
|
local path=v:sub(#id+4,#v)
|
||||||
|
if i~=#entrys then
|
||||||
|
path=path:sub(1,#path-1)
|
||||||
|
end
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
kernel.log("Mounted "..id.." to "..path)
|
||||||
kernel.fs.mount(id,path)
|
kernel.fs.mount(id,path)
|
||||||
::endline::
|
::endline::
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Mounted all disks")
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
||||||
while true do
|
while true do
|
||||||
local event={kernel.computer:getMachineEvent()}
|
local event={kernel.computer:getMachineEvent()}
|
||||||
@@ -10,3 +10,4 @@ kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
|||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.log("Created keventd daemon")
|
||||||
@@ -1,17 +1,20 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[2]
|
local kernel = args[1]
|
||||||
|
kernel.log("Loading third party drivers")
|
||||||
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
|
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
|
||||||
|
if kernel.fs.isDir("/lib/modules/"..subf) then
|
||||||
if subf~="Hyperion" then
|
if subf~="Hyperion" then
|
||||||
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
|
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
|
||||||
|
kernel.log("Compiling driver \""..subf..":"..driver.."\"")
|
||||||
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
|
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
|
||||||
local func, err = load(code, "@"..driver)
|
local func, err = load(code, "@"..driver)
|
||||||
if not func then
|
if not func then
|
||||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
|
||||||
else
|
else
|
||||||
local ok, err = xpcall(func, debug.traceback)
|
local ok, err = xpcall(func, debug.traceback, table.unpack(args))
|
||||||
if not ok then
|
if not ok then
|
||||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
kernel.log("DriverExecErr: "..tostring(err), "ERROR")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,11 +1,14 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel=args[1]
|
local kernel = args[1]
|
||||||
|
kernel.log("initializing third party drivers")
|
||||||
for _,l in ipairs(kernel.drivers.prior) do
|
for _,v in ipairs(kernel.drivers.raw) do
|
||||||
for _,d in ipairs(l) do
|
if v.arch==kernel.arch then
|
||||||
if d.init then
|
if v.load then
|
||||||
local ok,err = xpcall(d.init, debug.traceback)
|
kernel.log("Loading "..v.name)
|
||||||
if not ok then kernel.log("DriverInitErr: "..tostring(err)) end
|
local ok,err = xpcall(v.load, debug.traceback)
|
||||||
|
if not ok then
|
||||||
|
kernel.log("DriverLoadErr: "..tostring(err))
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,17 +1,25 @@
|
|||||||
local args={...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
local tasks={}
|
local tasks={}
|
||||||
local currentTask={}
|
local currentTask={}
|
||||||
local signals={}
|
local signals={}
|
||||||
local tid=1
|
local tid=2
|
||||||
local gid=1
|
local gid=2
|
||||||
|
local hookuuid=0
|
||||||
local sys={}
|
local sys={}
|
||||||
|
|
||||||
function sys.hookSig(sig, func)
|
function sys.hookSig(sig, func)
|
||||||
if not signals[tostring(currentTask.pid)][sig] then
|
if not currentTask.signal[sig] then
|
||||||
signals[tostring(currentTask.pid)][sig]={}
|
currentTask.signal[sig]={}
|
||||||
end
|
end
|
||||||
signals[tostring(currentTask.pid)][sig][#signals[tostring(currentTask.pid)][sig]+1]=func
|
hookuuid=hookuuid+1
|
||||||
|
currentTask.signal[sig][tostring(hookuuid)]=func
|
||||||
|
callbackid=tostring(hookuuid)
|
||||||
|
return {
|
||||||
|
remove=function()
|
||||||
|
currentTask.signal[sig][callbackid]=nil
|
||||||
|
end
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.clearSigHooks(typ)
|
function sys.clearSigHooks(typ)
|
||||||
@@ -27,7 +35,7 @@ end
|
|||||||
|
|
||||||
function sys.sendSig(pid, signal, ...)
|
function sys.sendSig(pid, signal, ...)
|
||||||
if pid=="all" then
|
if pid=="all" then
|
||||||
for i,v in pairs(tasks) do
|
for i,v in pairs(tasks) do+
|
||||||
v.sigQ[#v.sigQ+1]={signal, ...}
|
v.sigQ[#v.sigQ+1]={signal, ...}
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
@@ -38,31 +46,35 @@ function sys.sendSig(pid, signal, ...)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function sys.flushSigs()
|
function sys.flushSigs()
|
||||||
local ret = {}
|
local sigs = {}
|
||||||
for i=1, #currentTask.sigQ do
|
for i,v in ipairs(currentTask.sigQ) do
|
||||||
if currentTask.signal[currentTask.sigQ[i][1]] then
|
sigs[i]=v
|
||||||
for _,v in ipairs(currentTask.signal[currentTask.sigQ[1][1]]) do
|
|
||||||
coroutine.resumeWithTimeout(coroutine.create(function()
|
|
||||||
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1)))
|
|
||||||
if not ok then
|
|
||||||
table.insert(ret, err)
|
|
||||||
end
|
end
|
||||||
end), 10)
|
for i=1, #sigs do
|
||||||
|
local sig = sigs[i]
|
||||||
|
if currentTask.signal[sig[1]] then
|
||||||
|
for k,v in pairs(currentTask.signal[sig[1]]) do
|
||||||
|
coroutine.resumeWithTimeout(coroutine.create(function()
|
||||||
|
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
|
||||||
|
if not ok and sig[1]~="callbackErr" then
|
||||||
|
sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
|
||||||
|
end
|
||||||
|
end),10)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
for _,v in ipairs(currentTask.signal["unhandledEvent"]) do
|
for k,v in pairs(currentTask.signal["unhandledSignal"]) do
|
||||||
coroutine.resumeWithTimeout(coroutine.create(function()
|
coroutine.resumeWithTimeout(coroutine.create(function()
|
||||||
local ok, err = xpcall(v, debug.traceback, table.unpack(table.remove(currentTask.sigQ, 1)))
|
local ok,err = xpcall(v,debug.traceback,table.unpack(sig))
|
||||||
if not ok then
|
if not ok and sig[1]~="callbackErr" then
|
||||||
table.insert(ret, err)
|
sys.sendSig(currentTask.pid, "callbackErr", sig[1], k, err)
|
||||||
end
|
end
|
||||||
end), 10)
|
end),10)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function sys.spawn(func, name, evars, args)
|
function sys.spawn(func, name, evars, args, stdin, stdout, stderr)
|
||||||
local id=tid
|
local id=tid
|
||||||
tid=tid+1
|
tid=tid+1
|
||||||
name=name or tostring(id)
|
name=name or tostring(id)
|
||||||
@@ -89,6 +101,7 @@ function sys.spawn(func, name, evars, args)
|
|||||||
vy=0,
|
vy=0,
|
||||||
ivy=0,
|
ivy=0,
|
||||||
status="R",
|
status="R",
|
||||||
|
sleep=0,
|
||||||
signal=signals[tostring(id)],
|
signal=signals[tostring(id)],
|
||||||
parent=currentTask,
|
parent=currentTask,
|
||||||
children={},
|
children={},
|
||||||
@@ -97,6 +110,12 @@ function sys.spawn(func, name, evars, args)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function sys.exit(...)
|
||||||
|
sys.sendSig(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
|
||||||
|
currentTask.status="Z"
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
local function collectZombieProc()
|
local function collectZombieProc()
|
||||||
local ret = {}
|
local ret = {}
|
||||||
for _,v in pairs(tasks) do
|
for _,v in pairs(tasks) do
|
||||||
@@ -116,13 +135,23 @@ local function collectZombieProc()
|
|||||||
return ret
|
return ret
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.log("initPath is: " .. tostring(kernel.initPath))
|
||||||
signals["1"]={}
|
signals["1"]={}
|
||||||
tasks["1"]={
|
tasks["1"]={
|
||||||
coro=coroutine.create(function()
|
coro=coroutine.create(function()
|
||||||
local ret = {xpcall(kernel.fs.load(kernel.initPath), debug.traceback)}
|
local ok, code_or_err = xpcall(function() return kernel.fs.readAllText(kernel.initPath) end, debug.traceback)
|
||||||
|
if not ok then currentTask.status="Z"; kernel.panic(code_or_err) end
|
||||||
|
local code = code_or_err
|
||||||
|
|
||||||
|
local func, err = load(code, "@SysInit", nil, kernel._U)
|
||||||
|
if not func then currentTask.status="Z"; kernel.panic(err) end
|
||||||
|
|
||||||
|
local ok, err = xpcall(func, debug.traceback, kernel)
|
||||||
if not ok then
|
if not ok then
|
||||||
|
currentTask.status="Z"
|
||||||
kernel.panic(err)
|
kernel.panic(err)
|
||||||
else
|
else
|
||||||
|
currentTask.status="Z"
|
||||||
kernel.panic("Attempted to kill init!")
|
kernel.panic("Attempted to kill init!")
|
||||||
end
|
end
|
||||||
end),
|
end),
|
||||||
@@ -130,27 +159,38 @@ tasks["1"]={
|
|||||||
pid=1,
|
pid=1,
|
||||||
ppid=0,
|
ppid=0,
|
||||||
tgid=1,
|
tgid=1,
|
||||||
user=kernel.user,
|
user="root",
|
||||||
uid=kernel.uid,
|
uid=0,
|
||||||
evars={},
|
evars={},
|
||||||
args={kernel},
|
args={kernel},
|
||||||
vy=0,
|
vy=0,
|
||||||
ivy=0,
|
ivy=0,
|
||||||
status="R",
|
status="R",
|
||||||
|
sleep=0,
|
||||||
signal=signals["1"],
|
signal=signals["1"],
|
||||||
parent={name="Hyprkrnl",pid=0},
|
parent={name="Hyprkrnl",pid=0},
|
||||||
children={},
|
children={},
|
||||||
sibling={},
|
sibling={},
|
||||||
sigQ={}
|
sigQ={}
|
||||||
}
|
}
|
||||||
kernel.chache.preload.sys=sys
|
tasks["1"].sibling={tasks["1"]}
|
||||||
kernel.chache.preload.system=sys
|
|
||||||
|
kernel.log("Created pid 1")
|
||||||
|
kernel.cache.preload.sys=table.proxy(sys)
|
||||||
|
kernel.cache.preload.system=kernel.cache.preload.sys
|
||||||
|
kernel.cache.preload.os=kernel.cache.preload.sys
|
||||||
kernel.hpv=sys
|
kernel.hpv=sys
|
||||||
|
kernel.tasks=tasks
|
||||||
|
kernel.signals=signals
|
||||||
|
kernel.currentTask=currentTask
|
||||||
|
|
||||||
kernel.saveLog()
|
kernel.saveLog()
|
||||||
while true do
|
kernel.status="running"
|
||||||
for _,v in pairs(tasks) do
|
while kernel.status~="Panic" do
|
||||||
|
for k,v in pairs(tasks) do
|
||||||
currentTask=v
|
currentTask=v
|
||||||
|
kernel.currentTask=v
|
||||||
|
kernel.process=currentTask.name
|
||||||
kernel.user=currentTask.user
|
kernel.user=currentTask.user
|
||||||
kernel.uid=currentTask.uid
|
kernel.uid=currentTask.uid
|
||||||
sys.flushSigs()
|
sys.flushSigs()
|
||||||
@@ -164,4 +204,7 @@ while true do
|
|||||||
collectZombieProc()
|
collectZombieProc()
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.panic("Exited pid 0")
|
kernel.process="Kernel"
|
||||||
|
kernel.user="root"
|
||||||
|
kernel.uid=0
|
||||||
|
kernel.panic(kernel.reason or "Exited pid 0")
|
||||||
@@ -4,22 +4,24 @@
|
|||||||
Hyperion OS supports many driver types to allow it to run on any hardware
|
Hyperion OS supports many driver types to allow it to run on any hardware
|
||||||
```
|
```
|
||||||
Driver types
|
Driver types
|
||||||
tto - Supports basic text terminal output
|
tty - Supports basic teletype devices
|
||||||
gpio - Supports things like redstone
|
gpio - Supports things like redstone
|
||||||
runner - Kernel level programs (no api)
|
runner - Kernel level programs (no api)
|
||||||
timer - Timers and time related
|
timer - Timers and time related
|
||||||
periph - Basic peripheral info
|
periph - Basic peripheral info
|
||||||
gfx - PixelScreens
|
gfx - PixelScreens
|
||||||
|
modem - networking
|
||||||
```
|
```
|
||||||
Hyperion also has a base driver api
|
Hyperion also has a base driver api
|
||||||
```
|
```
|
||||||
Driver API
|
Driver API
|
||||||
name - Name of driver+
|
name - Name of driver
|
||||||
type - Type of driver
|
type - Type of driver
|
||||||
init - Ran before init
|
load - loading code
|
||||||
|
unload - unloading code
|
||||||
main - Ran as a process and has normal behavior (used for checking network like things)
|
main - Ran as a process and has normal behavior (used for checking network like things)
|
||||||
api - api difined by type
|
api - api difined by type
|
||||||
arch - architecture difined in bootloader (EX: cct, oc, ac, cc, ccpc)
|
arch - architecture difined in bootloader (EX: cct, oc, ac, cc, ccpc, or all)
|
||||||
description - discription
|
description - discription
|
||||||
author - author of driver
|
author - author of driver
|
||||||
prior - priority (low first)
|
prior - priority (low first)
|
||||||
|
|||||||
Reference in New Issue
Block a user