forked from Hyperion/HyperionOS
update to start working on SysInit
This commit is contained in:
@@ -1,3 +1,5 @@
|
||||
local args={...}
|
||||
local kernel=args[1]
|
||||
function string.hasSuffix(str, suffix)
|
||||
return string.sub(str, #suffix+1) == suffix
|
||||
end
|
||||
@@ -94,6 +96,62 @@ function table.hasVal(tabl, query)
|
||||
return false
|
||||
end
|
||||
|
||||
function table.proxy(tbl)
|
||||
local proxies = setmetatable({}, {__mode = "k"}) -- Weak table to avoid cycles
|
||||
|
||||
local function createProxy(t)
|
||||
if type(t) ~= "table" then return t end
|
||||
if proxies[t] then return proxies[t] end -- reuse proxy for the same table (handle cycles)
|
||||
|
||||
local proxy = {}
|
||||
proxies[t] = proxy
|
||||
|
||||
local mt
|
||||
mt = {
|
||||
__index = function(_, k)
|
||||
local value = t[k]
|
||||
if type(value) == "table" then
|
||||
return createProxy(value) -- recursively proxy subtables
|
||||
else
|
||||
return value
|
||||
end
|
||||
end,
|
||||
__newindex = function()
|
||||
error("Attempt to modify 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 output = "{"
|
||||
for i,v in pairs(table) do
|
||||
@@ -119,7 +177,7 @@ local function serialize(table)
|
||||
output=output.."false"
|
||||
end
|
||||
elseif type(v) == "function" then
|
||||
output=output.."function() end"
|
||||
output=output..tostring(v)
|
||||
else
|
||||
error("serialization of type \""..type(v).."\" is not supported")
|
||||
end
|
||||
@@ -134,4 +192,5 @@ local function serialize(table)
|
||||
return output
|
||||
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 kernel = args[1]
|
||||
local fs = {}
|
||||
local disks = {}
|
||||
local mounts = {["/"]="$"}
|
||||
|
||||
-- path normaliing
|
||||
local function normalizePath(path)
|
||||
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
|
||||
-- =====================================================================
|
||||
-- INTERNAL STATE
|
||||
-- =====================================================================
|
||||
|
||||
-- disk resolution
|
||||
local function resolvePath(path)
|
||||
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
|
||||
local disks = {} -- address → disk object
|
||||
local mounts = {["/"] = "$"} -- mountpoint → disk address (root = boot disk)
|
||||
|
||||
-- Symlinks
|
||||
-- Format: #!@SYMLINK[target]
|
||||
local SYMLINK_PREFIX = "#!@SYMLINK["
|
||||
local SYMLINK_SUFFIX = "]"
|
||||
local SYMLINK_MAX_DEPTH = 64
|
||||
|
||||
local function isSymlink(disk, path)
|
||||
if not disk:fileExists(path) then return false end
|
||||
local text = disk:readAllText(path)
|
||||
if not text then return false end
|
||||
return text:sub(1, #SYMLINK_PREFIX) == SYMLINK_PREFIX
|
||||
end
|
||||
|
||||
local function readSymlink(disk, path)
|
||||
local text = disk:readAllText(path)
|
||||
if not text 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
|
||||
target = target:sub(1, -2)
|
||||
end
|
||||
return target
|
||||
end
|
||||
-- =====================================================================
|
||||
-- PATH NORMALIZATION
|
||||
-- =====================================================================
|
||||
|
||||
|
||||
-- Path resolution
|
||||
local function splitPath(p)
|
||||
local parts = {}
|
||||
for part in p:gmatch("[^/]+") do parts[#parts+1] = part end
|
||||
return parts
|
||||
local t = {}
|
||||
for part in p:gmatch("[^/]+") do t[#t+1] = part end
|
||||
return t
|
||||
end
|
||||
|
||||
local function resolveSymlink(path)
|
||||
path = normalizePath(path)
|
||||
local symlinkDepth = 0
|
||||
local parts = splitPath(path)
|
||||
local resolved = {}
|
||||
local i = 1
|
||||
local function normalizePath(path)
|
||||
if not path or path == "" then return "/" end
|
||||
|
||||
while i <= #parts do
|
||||
local comp = parts[i]
|
||||
if comp == "." then
|
||||
elseif comp == ".." then
|
||||
if #resolved > 0 then table.remove(resolved) end
|
||||
else
|
||||
local currentPath = "/" .. table.concat(resolved, "/")
|
||||
local disk, p = resolvePath(currentPath .. "/" .. comp)
|
||||
if isSymlink(disk, p) then
|
||||
symlinkDepth = symlinkDepth + 1
|
||||
if symlinkDepth > SYMLINK_MAX_DEPTH then
|
||||
error("Too many levels of symbolic links: " .. path)
|
||||
end
|
||||
local target = readSymlink(disk, p)
|
||||
if not target then
|
||||
resolved[#resolved+1] = comp
|
||||
else
|
||||
if target:sub(1,1) == "/" then
|
||||
resolved = splitPath(normalizePath(target))
|
||||
else
|
||||
local base = resolved
|
||||
resolved = {}
|
||||
for _, seg in ipairs(base) do resolved[#resolved+1]=seg end
|
||||
for seg in target:gmatch("[^/]+") do
|
||||
if seg == ".." then
|
||||
if #resolved>0 then table.remove(resolved) end
|
||||
elseif seg ~= "." then
|
||||
resolved[#resolved+1]=seg
|
||||
end
|
||||
end
|
||||
end
|
||||
local remaining = {}
|
||||
for j=i+1,#parts do remaining[#remaining+1]=parts[j] end
|
||||
parts = remaining
|
||||
i = 0
|
||||
end
|
||||
else
|
||||
resolved[#resolved+1]=comp
|
||||
-- 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
|
||||
i=i+1
|
||||
end
|
||||
|
||||
local finalPath="/"..table.concat(resolved,"/")
|
||||
local disk,diskPath=resolvePath(finalPath)
|
||||
return disk,diskPath
|
||||
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
|
||||
|
||||
-- PUBLIC API: MOUNTING
|
||||
function fs.mount(disk, mountPoint)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
mounts[mountPoint]=disk
|
||||
|
||||
|
||||
-- =====================================================================
|
||||
-- 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
|
||||
function fs.unmount(mountPoint)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
mounts[mountPoint]=nil
|
||||
|
||||
local function readSymlinkRaw(disk, p)
|
||||
local text = disk:readAllText(p)
|
||||
if not text then return nil end
|
||||
if text:sub(1, #SYMLINK_PREFIX) ~= SYMLINK_PREFIX then return nil end
|
||||
|
||||
local t = text:sub(#SYMLINK_PREFIX + 1)
|
||||
if t:sub(-1) == SYMLINK_SUFFIX then
|
||||
t = t:sub(1, -2)
|
||||
end
|
||||
return t
|
||||
end
|
||||
|
||||
|
||||
-- =====================================================================
|
||||
-- FULL PATH RESOLUTION (FOLLOWS SYMLINKS)
|
||||
-- =====================================================================
|
||||
|
||||
local function resolveSymlink(path)
|
||||
local abs = normalizePath(path)
|
||||
local parts = splitPath(abs)
|
||||
local out = {}
|
||||
|
||||
local depth = 0
|
||||
local idx = 1
|
||||
|
||||
while idx <= #parts do
|
||||
local comp = parts[idx]
|
||||
|
||||
if comp == "." then
|
||||
-- nothing
|
||||
elseif comp == ".." then
|
||||
if #out > 0 then table.remove(out) end
|
||||
else
|
||||
local curAbs = "/" .. table.concat(out, "/")
|
||||
if curAbs ~= "/" then curAbs = curAbs .. "/" end
|
||||
curAbs = curAbs .. comp
|
||||
|
||||
local disk, dpath = resolveMount(curAbs)
|
||||
|
||||
if isSymlinkRaw(disk, dpath) then
|
||||
depth = depth + 1
|
||||
if depth > SYMLINK_MAX_DEPTH then
|
||||
error("Too many symlink levels: " .. path)
|
||||
end
|
||||
|
||||
local target = readSymlinkRaw(disk, dpath)
|
||||
if target then
|
||||
local newAbs
|
||||
|
||||
if target:sub(1,1) == "/" then
|
||||
-- absolute target
|
||||
newAbs = normalizePath(target)
|
||||
else
|
||||
-- relative to current out[]
|
||||
local tmp = "/" .. table.concat(out, "/")
|
||||
if tmp ~= "/" then tmp = tmp .. "/" end
|
||||
tmp = tmp .. target
|
||||
newAbs = normalizePath(tmp)
|
||||
end
|
||||
|
||||
-- rebuild remaining parts
|
||||
local remaining = {}
|
||||
for j = idx + 1, #parts do
|
||||
remaining[#remaining+1] = parts[j]
|
||||
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
|
||||
else
|
||||
out[#out+1] = comp
|
||||
end
|
||||
end
|
||||
|
||||
idx = idx + 1
|
||||
end
|
||||
|
||||
local finalAbs = "/" .. table.concat(out, "/")
|
||||
return resolveMount(finalAbs)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- =====================================================================
|
||||
-- PUBLIC API
|
||||
-- =====================================================================
|
||||
|
||||
-- MOUNT OPERATIONS -----------------------------------------------------
|
||||
|
||||
function fs.virtDisk(diskObj)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
if disks[diskObj.address] then error("Disk exists") end
|
||||
disks[diskObj.address]=diskObj
|
||||
if disks[diskObj.address] then
|
||||
error("Disk exists: " .. diskObj.address)
|
||||
end
|
||||
disks[diskObj.address] = diskObj
|
||||
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)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
disks[addr]=nil
|
||||
disks[addr] = nil
|
||||
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)
|
||||
local disk, p = resolvePath(linkPath)
|
||||
return disk:writeAllText(p, SYMLINK_PREFIX..target..SYMLINK_SUFFIX)
|
||||
kernel.log("WARNING: Symlinks are a untested feature if you find any bugs please report them to https://git.astronand.dev/Hyperion/HyperionOS","WARN")
|
||||
local disk, p = resolveMount(normalizePath(linkPath))
|
||||
return disk:writeAllText(p, SYMLINK_PREFIX .. target .. SYMLINK_SUFFIX)
|
||||
end
|
||||
|
||||
function fs.isLink(path)
|
||||
local disk, p = resolvePath(path)
|
||||
return isSymlink(disk,p)
|
||||
local disk, p = resolveMount(normalizePath(path))
|
||||
return isSymlinkRaw(disk, p)
|
||||
end
|
||||
|
||||
function fs.readLink(path)
|
||||
local disk, p = resolvePath(path)
|
||||
return readSymlink(disk,p)
|
||||
local disk, p = resolveMount(normalizePath(path))
|
||||
return readSymlinkRaw(disk, p)
|
||||
end
|
||||
|
||||
-- FILE OPERATIONS
|
||||
function fs.exists(path)
|
||||
|
||||
-- FILE OPERATIONS ------------------------------------------------------
|
||||
|
||||
function fs.exists(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:fileExists(p) or disk:directoryExists(p)
|
||||
return disk:fileExists(p, ...) or disk:directoryExists(p, ...)
|
||||
end
|
||||
|
||||
function fs.isFile(path)
|
||||
function fs.isFile(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
if isSymlink(disk, p) then return false end
|
||||
return disk:fileExists(p)
|
||||
return disk:fileExists(p, ...)
|
||||
end
|
||||
|
||||
function fs.isDir(path)
|
||||
function fs.isDir(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
if isSymlink(disk, p) then return false end
|
||||
return disk:directoryExists(p)
|
||||
return disk:directoryExists(p, ...)
|
||||
end
|
||||
|
||||
function fs.list(path)
|
||||
function fs.list(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:list(p)
|
||||
return disk:list(p, ...)
|
||||
end
|
||||
|
||||
function fs.makeDir(path)
|
||||
function fs.makeDir(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:makeDirectory(p)
|
||||
return disk:makeDirectory(p, ...)
|
||||
end
|
||||
|
||||
function fs.remove(path)
|
||||
local disk, p = resolvePath(path)
|
||||
if isSymlink(disk, p) then
|
||||
return disk:remove(p)
|
||||
end
|
||||
local d2, p2 = resolveSymlink(path)
|
||||
return d2:remove(p2)
|
||||
-- remove does NOT follow symlinks (UNIX semantics)
|
||||
function fs.remove(path, ...)
|
||||
if fs.isMount(path) then return "Cannot delete mounted folder" end
|
||||
local abs = normalizePath(path)
|
||||
local disk, p = resolveMount(abs)
|
||||
return disk:remove(p, ...)
|
||||
end
|
||||
|
||||
function fs.readAllText(path)
|
||||
function fs.readAllText(path, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:readAllText(p)
|
||||
return disk:readAllText(p, ...)
|
||||
end
|
||||
|
||||
function fs.writeAllText(path, text)
|
||||
function fs.writeAllText(path, text, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:writeAllText(p, text)
|
||||
return disk:writeAllText(p, text, ...)
|
||||
end
|
||||
|
||||
function fs.appendAllText(path, text)
|
||||
function fs.appendAllText(path, text, ...)
|
||||
local disk, p = resolveSymlink(path)
|
||||
return disk:appendAllText(p, text)
|
||||
return disk:appendAllText(p, text, ...)
|
||||
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)
|
||||
return disk:getSize(p)
|
||||
return disk:getSize(p, ...)
|
||||
end
|
||||
|
||||
|
||||
|
||||
-- =====================================================================
|
||||
-- INIT
|
||||
for _,v in kernel.initdisks.list() do fs.virtDisk(v) end
|
||||
kernel.fs=fs
|
||||
kernel.chache.preload.fs=fs
|
||||
kernel.chache.preload.filesystem=fs
|
||||
-- =====================================================================
|
||||
|
||||
kernel.log("Loading disks for vfs")
|
||||
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 kernel=args[1]
|
||||
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||
if kernel.uid ~= 0 then error("Permission Denied") end
|
||||
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)
|
||||
-----------------------------------------------------------------
|
||||
|
||||
local function fileRead(node)
|
||||
local function fileRead(node, ...)
|
||||
if type(node) == "string" then
|
||||
return node
|
||||
elseif type(node) == "table" and node.__file and node.read then
|
||||
return node.read()
|
||||
return node.read(...)
|
||||
end
|
||||
return nil
|
||||
end
|
||||
|
||||
local function fileWrite(parent, name, text)
|
||||
local function fileWrite(parent, name, text, ...)
|
||||
local node = parent[name]
|
||||
if type(node) == "string" then
|
||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||
parent[name] = text
|
||||
return true
|
||||
elseif type(node) == "table" and node.__file and node.write then
|
||||
return node.write(text)
|
||||
return node.write(text, ...)
|
||||
end
|
||||
parent[name] = text
|
||||
return true
|
||||
end
|
||||
|
||||
local function fileAppend(parent, name, text)
|
||||
local function fileAppend(parent, name, text, ...)
|
||||
local node = parent[name]
|
||||
if type(node) == "string" then
|
||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||
parent[name] = node .. text
|
||||
return true
|
||||
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
|
||||
parent[name] = text
|
||||
return true
|
||||
@@ -96,26 +97,22 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||
function disk:spaceUsed() return 0 end
|
||||
function disk:spaceTotal() return 0 end
|
||||
|
||||
function disk:readAllText(path)
|
||||
function disk:readAllText(path, ...)
|
||||
local node = getNode(path)
|
||||
if not node then return nil, "file not found" end
|
||||
return fileRead(node)
|
||||
return fileRead(node, ...)
|
||||
end
|
||||
|
||||
function disk:writeAllText(path, text)
|
||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||
|
||||
function disk:writeAllText(path, text, ...)
|
||||
local parent, name = getParent(path)
|
||||
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
|
||||
|
||||
function disk:appendAllText(path, text)
|
||||
local ok, err = ensureWrite(); if not ok then return false, err end
|
||||
|
||||
function disk:appendAllText(path, text, ...)
|
||||
local parent, name = getParent(path)
|
||||
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
|
||||
|
||||
function disk:list(path)
|
||||
@@ -161,11 +158,11 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||
return label
|
||||
end
|
||||
|
||||
function disk:size(path)
|
||||
function disk:size(path, ...)
|
||||
local node = getNode(path)
|
||||
if type(node) == "string" then return #node end
|
||||
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
|
||||
end
|
||||
return 0
|
||||
@@ -174,7 +171,7 @@ function kernel.fs.mkvirtfs(address, readOnly, label, autoRegister)
|
||||
-----------------------------------------------------------------
|
||||
-- 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)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
|
||||
-- List of search paths
|
||||
local paths = {
|
||||
"/lib/?",
|
||||
@@ -11,7 +10,7 @@ local paths = {
|
||||
-- Custom require implementation
|
||||
function require(module)
|
||||
-- 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]
|
||||
end
|
||||
|
||||
@@ -53,4 +52,5 @@ function require(module)
|
||||
|
||||
-- If nothing worked, raise an error with all reasons
|
||||
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 data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", false)
|
||||
local data = kernel.fs.mkvirtfs("devfs0000", true, "devfs", true)
|
||||
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["/"]["eeprom"]={
|
||||
@@ -14,4 +16,42 @@ data["/"]["eeprom"]={
|
||||
kernel.computer:setEEPROM(text)
|
||||
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 kernel=args[1]
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
local ifs=kernel.ifs
|
||||
local initdisks=kernel.initdisks
|
||||
|
||||
kernel.log("Mounting fstab")
|
||||
local fstab=ifs.readAllText("/etc/fstab")
|
||||
kernel.fs.update(initdisks)
|
||||
for i,v in ipairs(string.split(fstab,"\n")) do
|
||||
local entrys = string.split(fstab,"\n")
|
||||
for i,v in ipairs(entrys) do
|
||||
if v:sub(1,1)=="U" then
|
||||
local id=""
|
||||
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)
|
||||
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.fs.mount(id,path)
|
||||
::endline::
|
||||
end
|
||||
end
|
||||
end
|
||||
kernel.log("Mounted all disks")
|
||||
@@ -1,5 +1,5 @@
|
||||
local args={...}
|
||||
local kernel=args[1]
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
||||
while true do
|
||||
local event={kernel.computer:getMachineEvent()}
|
||||
@@ -9,4 +9,5 @@ kernel.drivers.processes[#kernel.drivers.processes+1]=function()
|
||||
end
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
end
|
||||
kernel.log("Created keventd daemon")
|
||||
@@ -1,17 +1,20 @@
|
||||
local args={...}
|
||||
local kernel=args[2]
|
||||
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
kernel.log("Loading third party drivers")
|
||||
for _,subf in ipairs(kernel.fs.list("/lib/modules/")) do
|
||||
if subf~="Hyperion" then
|
||||
for _,driver in ipairs(kernel.fs.list("/lib/modules/"..subf)) do
|
||||
local code = kernel.fs.readAllText("/lib/modules/"..subf.."/"..driver)
|
||||
local func, err = load(code, "@"..driver)
|
||||
if not func then
|
||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
||||
else
|
||||
local ok, err = xpcall(func, debug.traceback)
|
||||
if not ok then
|
||||
kernel.log("DriverLoadErr: "..tostring(err), "ERROR")
|
||||
if kernel.fs.isDir("/lib/modules/"..subf) then
|
||||
if subf~="Hyperion" then
|
||||
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 func, err = load(code, "@"..driver)
|
||||
if not func then
|
||||
kernel.log("DriverCompileErr: "..tostring(err), "ERROR")
|
||||
else
|
||||
local ok, err = xpcall(func, debug.traceback, table.unpack(args))
|
||||
if not ok then
|
||||
kernel.log("DriverExecErr: "..tostring(err), "ERROR")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,11 +1,14 @@
|
||||
local args={...}
|
||||
local kernel=args[1]
|
||||
|
||||
for _,l in ipairs(kernel.drivers.prior) do
|
||||
for _,d in ipairs(l) do
|
||||
if d.init then
|
||||
local ok,err = xpcall(d.init, debug.traceback)
|
||||
if not ok then kernel.log("DriverInitErr: "..tostring(err)) end
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
kernel.log("initializing third party drivers")
|
||||
for _,v in ipairs(kernel.drivers.raw) do
|
||||
if v.arch==kernel.arch then
|
||||
if v.load then
|
||||
kernel.log("Loading "..v.name)
|
||||
local ok,err = xpcall(v.load, debug.traceback)
|
||||
if not ok then
|
||||
kernel.log("DriverLoadErr: "..tostring(err))
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,17 +1,25 @@
|
||||
local args={...}
|
||||
local args = {...}
|
||||
local kernel = args[1]
|
||||
local tasks={}
|
||||
local currentTask={}
|
||||
local signals={}
|
||||
local tid=1
|
||||
local gid=1
|
||||
local tid=2
|
||||
local gid=2
|
||||
local hookuuid=0
|
||||
local sys={}
|
||||
|
||||
function sys.hookSig(sig, func)
|
||||
if not signals[tostring(currentTask.pid)][sig] then
|
||||
signals[tostring(currentTask.pid)][sig]={}
|
||||
if not currentTask.signal[sig] then
|
||||
currentTask.signal[sig]={}
|
||||
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
|
||||
|
||||
function sys.clearSigHooks(typ)
|
||||
@@ -27,7 +35,7 @@ end
|
||||
|
||||
function sys.sendSig(pid, signal, ...)
|
||||
if pid=="all" then
|
||||
for i,v in pairs(tasks) do
|
||||
for i,v in pairs(tasks) do+
|
||||
v.sigQ[#v.sigQ+1]={signal, ...}
|
||||
end
|
||||
return
|
||||
@@ -38,31 +46,35 @@ function sys.sendSig(pid, signal, ...)
|
||||
end
|
||||
|
||||
function sys.flushSigs()
|
||||
local ret = {}
|
||||
for i=1, #currentTask.sigQ do
|
||||
if currentTask.signal[currentTask.sigQ[i][1]] then
|
||||
for _,v in ipairs(currentTask.signal[currentTask.sigQ[1][1]]) do
|
||||
local sigs = {}
|
||||
for i,v in ipairs(currentTask.sigQ) do
|
||||
sigs[i]=v
|
||||
end
|
||||
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(table.remove(currentTask.sigQ, 1)))
|
||||
if not ok then
|
||||
table.insert(ret, err)
|
||||
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),10)
|
||||
end
|
||||
else
|
||||
for _,v in ipairs(currentTask.signal["unhandledEvent"]) do
|
||||
for k,v in pairs(currentTask.signal["unhandledSignal"]) 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)
|
||||
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),10)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function sys.spawn(func, name, evars, args)
|
||||
function sys.spawn(func, name, evars, args, stdin, stdout, stderr)
|
||||
local id=tid
|
||||
tid=tid+1
|
||||
name=name or tostring(id)
|
||||
@@ -89,6 +101,7 @@ function sys.spawn(func, name, evars, args)
|
||||
vy=0,
|
||||
ivy=0,
|
||||
status="R",
|
||||
sleep=0,
|
||||
signal=signals[tostring(id)],
|
||||
parent=currentTask,
|
||||
children={},
|
||||
@@ -97,6 +110,12 @@ function sys.spawn(func, name, evars, args)
|
||||
}
|
||||
end
|
||||
|
||||
function sys.exit(...)
|
||||
sys.sendSig(currentTask.ppid, "ChildTaskExit", currentTask.pid, ...)
|
||||
currentTask.status="Z"
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
local function collectZombieProc()
|
||||
local ret = {}
|
||||
for _,v in pairs(tasks) do
|
||||
@@ -116,13 +135,23 @@ local function collectZombieProc()
|
||||
return ret
|
||||
end
|
||||
|
||||
kernel.log("initPath is: " .. tostring(kernel.initPath))
|
||||
signals["1"]={}
|
||||
tasks["1"]={
|
||||
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
|
||||
currentTask.status="Z"
|
||||
kernel.panic(err)
|
||||
else
|
||||
currentTask.status="Z"
|
||||
kernel.panic("Attempted to kill init!")
|
||||
end
|
||||
end),
|
||||
@@ -130,27 +159,38 @@ tasks["1"]={
|
||||
pid=1,
|
||||
ppid=0,
|
||||
tgid=1,
|
||||
user=kernel.user,
|
||||
uid=kernel.uid,
|
||||
user="root",
|
||||
uid=0,
|
||||
evars={},
|
||||
args={kernel},
|
||||
vy=0,
|
||||
ivy=0,
|
||||
status="R",
|
||||
sleep=0,
|
||||
signal=signals["1"],
|
||||
parent={name="Hyprkrnl",pid=0},
|
||||
children={},
|
||||
sibling={},
|
||||
sigQ={}
|
||||
}
|
||||
kernel.chache.preload.sys=sys
|
||||
kernel.chache.preload.system=sys
|
||||
tasks["1"].sibling={tasks["1"]}
|
||||
|
||||
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.tasks=tasks
|
||||
kernel.signals=signals
|
||||
kernel.currentTask=currentTask
|
||||
|
||||
kernel.saveLog()
|
||||
while true do
|
||||
for _,v in pairs(tasks) do
|
||||
kernel.status="running"
|
||||
while kernel.status~="Panic" do
|
||||
for k,v in pairs(tasks) do
|
||||
currentTask=v
|
||||
kernel.currentTask=v
|
||||
kernel.process=currentTask.name
|
||||
kernel.user=currentTask.user
|
||||
kernel.uid=currentTask.uid
|
||||
sys.flushSigs()
|
||||
@@ -164,4 +204,7 @@ while true do
|
||||
collectZombieProc()
|
||||
end
|
||||
|
||||
kernel.panic("Exited pid 0")
|
||||
kernel.process="Kernel"
|
||||
kernel.user="root"
|
||||
kernel.uid=0
|
||||
kernel.panic(kernel.reason or "Exited pid 0")
|
||||
Reference in New Issue
Block a user