update to start working on SysInit
This commit is contained in:
46
.vscode/tasks.json
vendored
Executable file
46
.vscode/tasks.json
vendored
Executable file
@@ -0,0 +1,46 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"label": "Build",
|
||||||
|
"type": "shell",
|
||||||
|
|
||||||
|
"windows": {
|
||||||
|
"command": "powershell",
|
||||||
|
"args": [
|
||||||
|
"-NoProfile",
|
||||||
|
"-ExecutionPolicy",
|
||||||
|
"Bypass",
|
||||||
|
"-Command",
|
||||||
|
"if (Test-Path '${workspaceFolder}\\Build') { Remove-Item -LiteralPath '${workspaceFolder}\\Build' -Recurse -Force -ErrorAction SilentlyContinue }; New-Item -ItemType Directory -Path '${workspaceFolder}\\Build' | Out-Null; Get-ChildItem -Path '${workspaceFolder}\\Test' -Directory | ForEach-Object { $base = $_.FullName; Get-ChildItem -Path $base -File -Recurse | ForEach-Object { $rel = $_.FullName.Substring($base.Length).TrimStart(\"\\\"); $destPath = Join-Path '${workspaceFolder}\\Build' $rel; $destDir = Split-Path $destPath; if (-not (Test-Path $destDir)) { New-Item -ItemType Directory -Path $destDir | Out-Null }; Copy-Item -LiteralPath $_.FullName -Destination $destPath -Force } }"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"linux": {
|
||||||
|
"command": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c",
|
||||||
|
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"osx": {
|
||||||
|
"command": "bash",
|
||||||
|
"args": [
|
||||||
|
"-c",
|
||||||
|
"[ -d \"${workspaceFolder}/Build\" ] && rm -rf \"${workspaceFolder}/Build\"; mkdir -p \"${workspaceFolder}/Build\"; for d in \"${workspaceFolder}/Test\"/*; do if [ -d \"$d\" ]; then find \"$d\" -type f | while read f; do rel=\"${f#$d/}\"; mkdir -p \"${workspaceFolder}/Build/$(dirname \"$rel\")\"; cp \"$f\" \"${workspaceFolder}/Build/$rel\"; done; fi; done"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
"presentation": {
|
||||||
|
"reveal": "always",
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": [],
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -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
src/disks/1h/bin/BASIC → Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/13_procfs.kmod
Normal file → Executable file
0
src/disks/1h/bin/BASIC → Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/13_procfs.kmod
Normal file → 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
|
||||||
0
src/disks/1h/bin/hex.lua → Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/50_mutiUserAuth.kmod
Normal file → Executable file
0
src/disks/1h/bin/hex.lua → Test/Hyperion-kernel-v0.1.0/lib/modules/Hyperion/50_mutiUserAuth.kmod
Normal file → Executable file
@@ -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)
|
||||||
|
|||||||
@@ -1,188 +0,0 @@
|
|||||||
local computer = component.getFirst("computer")
|
|
||||||
local screen=component.getFirst("screen")
|
|
||||||
if not screen then
|
|
||||||
local function e(...)end
|
|
||||||
screen = {
|
|
||||||
print=e,
|
|
||||||
printInline=e,
|
|
||||||
clear=e
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok,err = xpcall(function()
|
|
||||||
-- Init components
|
|
||||||
_G._DEVELOPMENT=true
|
|
||||||
_G.component=component
|
|
||||||
|
|
||||||
local printed=""
|
|
||||||
local print=function(text)
|
|
||||||
printed=printed..text.."\n"
|
|
||||||
screen.print(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get CFG
|
|
||||||
local biosCfg = {}
|
|
||||||
local i=1
|
|
||||||
while i<=256 do
|
|
||||||
biosCfg[i]=computer.getData(i) or ""
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
|
|
||||||
local function deepcopy(orig, copies)
|
|
||||||
copies = copies or {}
|
|
||||||
|
|
||||||
if type(orig) ~= 'table' then
|
|
||||||
return orig
|
|
||||||
elseif copies[orig] then
|
|
||||||
return copies[orig]
|
|
||||||
end
|
|
||||||
|
|
||||||
local copy = {}
|
|
||||||
copies[orig] = copy
|
|
||||||
|
|
||||||
for k, v in next, orig, nil do
|
|
||||||
local copied_key = deepcopy(k, copies)
|
|
||||||
local copied_val = deepcopy(v, copies)
|
|
||||||
copy[copied_key] = copied_val
|
|
||||||
end
|
|
||||||
|
|
||||||
return copy
|
|
||||||
end
|
|
||||||
|
|
||||||
local function save(table)
|
|
||||||
while i<=256 do
|
|
||||||
computer.setData(i, table[i] or nil)
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function hasKey(tabl, query)
|
|
||||||
for i,v in pairs(tabl) do
|
|
||||||
if i==query then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Start boot seq
|
|
||||||
local disks={}
|
|
||||||
for i,v in component.list() do
|
|
||||||
if i=="disk" then
|
|
||||||
disks[v.id]=v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local idx = 1
|
|
||||||
local bootOption=1
|
|
||||||
while true do
|
|
||||||
if biosCfg[idx]=="$EOF" then break end
|
|
||||||
print("Atempting boot option "..tostring(bootOption).." labled \""..biosCfg[idx].."\".")
|
|
||||||
bootOption=bootOption+1
|
|
||||||
local drive={}
|
|
||||||
idx=idx+1
|
|
||||||
if not hasKey(disks,biosCfg[idx]) then
|
|
||||||
print("└─ Drive not found.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+3
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
drive=disks[biosCfg[idx]]
|
|
||||||
print("├─ Drive found with id of \""..drive.id.."\"")
|
|
||||||
end
|
|
||||||
idx=idx+1
|
|
||||||
local path
|
|
||||||
local code
|
|
||||||
if drive.type=="udd" then
|
|
||||||
print("├─ Drive is Unmanaged, looking for MBR...")
|
|
||||||
sleep(0.02)
|
|
||||||
print("├─ Reading MBR...")
|
|
||||||
local tmp = drive.readBytes(0,512)
|
|
||||||
print("├─ MBR found, compiling bootloader...")
|
|
||||||
code = table.concat(tmp)
|
|
||||||
else
|
|
||||||
if not drive:fileExists(biosCfg[idx]) then
|
|
||||||
print("└─ Path not found.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+2
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
print("├─ Kernel exists at path \""..biosCfg[idx].."\"")
|
|
||||||
path=biosCfg[idx]
|
|
||||||
end
|
|
||||||
code = drive:open(path).read()
|
|
||||||
end
|
|
||||||
idx=idx+1
|
|
||||||
_VG=deepcopy(_G)
|
|
||||||
print("├─ Created virtual ENV.")
|
|
||||||
local _,func = pcall(load,code,drive.id.." | "..path,nil,_G)
|
|
||||||
if not func then
|
|
||||||
print("└─ Compilation failure.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+1
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
print("├─ Executing.")
|
|
||||||
end
|
|
||||||
local cmd=biosCfg[idx] or ""
|
|
||||||
idx=idx+1
|
|
||||||
local biosData = {}
|
|
||||||
biosData.bootDrive=drive
|
|
||||||
biosData.term=screen
|
|
||||||
screen.clear()
|
|
||||||
local ok, err = xpcall(func, debug.traceback, biosData, cmd)
|
|
||||||
screen.clear()
|
|
||||||
screen.print(printed)
|
|
||||||
if not ok then
|
|
||||||
print("└─ OS exited with error: "..err)
|
|
||||||
print(" ")
|
|
||||||
else
|
|
||||||
print("└─ OS exited.")
|
|
||||||
print(" ")
|
|
||||||
end
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
::invalid_boot::
|
|
||||||
end
|
|
||||||
computer.beep(400,0.4)
|
|
||||||
print("No boot options available")
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
end, debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
screen.clear()
|
|
||||||
screen.print("BIOS PANIC: "..err)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"disks":[1,2,3,56]
|
|
||||||
}
|
|
||||||
@@ -1,254 +0,0 @@
|
|||||||
HyperionOS
|
|
||||||
disk_1
|
|
||||||
/boot/ac/boot.ac
|
|
||||||
|
|
||||||
HyperionOS Dev
|
|
||||||
disk_2
|
|
||||||
/boot/Hyprkrnl.sys
|
|
||||||
|
|
||||||
$EOF
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
local computer = component.getFirst("computer")
|
|
||||||
local screen=component.getFirst("screen")
|
|
||||||
if not screen then
|
|
||||||
computer.beep(400,0.2)
|
|
||||||
sleep(0.2)
|
|
||||||
computer.beep(400,0.2)
|
|
||||||
while true do
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local idx = 1
|
|
||||||
local ok, err = xpcall(function()
|
|
||||||
for t, a in component.list() do
|
|
||||||
if t == "disk" then
|
|
||||||
if a:fileExists("boot.lua") then
|
|
||||||
screen.print("Bootable file found on "..a.id.." - reading...")
|
|
||||||
local code = a:open("boot.lua").read()
|
|
||||||
screen.print("Compiling boot.lua...")
|
|
||||||
local f = load(code)
|
|
||||||
if not f then error("bios boot compilation failed") end
|
|
||||||
screen.print("Booting...")
|
|
||||||
---@diagnostic disable-next-line: need-check-nil
|
|
||||||
local ok, err = xpcall(f, debug.traceback)
|
|
||||||
if not ok then screen.print(err); sleep(3) end
|
|
||||||
break
|
|
||||||
else
|
|
||||||
idx = idx+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end, debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
screen.print("BIOS error: "..err)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
osleep(0.02)
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
computer.beep(400,0.4)
|
|
||||||
screen.print("No bootable filesystem found!")
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"disks":[3,4,8]
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,189 +0,0 @@
|
|||||||
local computer = component.getFirst("computer")
|
|
||||||
local screen=component.getFirst("screen")
|
|
||||||
if not screen then
|
|
||||||
local function e(...)end
|
|
||||||
screen = {
|
|
||||||
print=e,
|
|
||||||
printInline=e,
|
|
||||||
clear=e
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok,err = xpcall(function()
|
|
||||||
-- Init components
|
|
||||||
_G._DEVELOPMENT=true
|
|
||||||
_G.component=component
|
|
||||||
|
|
||||||
local printed=""
|
|
||||||
local print=function(text)
|
|
||||||
printed=printed..text.."\n"
|
|
||||||
screen.print(text)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Get CFG
|
|
||||||
local biosCfg = {}
|
|
||||||
local i=1
|
|
||||||
while i<=256 do
|
|
||||||
biosCfg[i]=computer.getData(i) or ""
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
-- Difine functions
|
|
||||||
local function copy(tabl)
|
|
||||||
local out = {}
|
|
||||||
for i,v in pairs(tabl) do
|
|
||||||
local t=type(v)
|
|
||||||
if t=="table" then
|
|
||||||
if i == "_G" then
|
|
||||||
out._G=out
|
|
||||||
else
|
|
||||||
out[i]=copy(v)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
out[i]=v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return out
|
|
||||||
end
|
|
||||||
|
|
||||||
local function save(table)
|
|
||||||
while i<=256 do
|
|
||||||
computer.setData(i, table[i] or nil)
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function hasKey(tabl, query)
|
|
||||||
for i,v in pairs(tabl) do
|
|
||||||
if i==query then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Start boot seq
|
|
||||||
local disks={}
|
|
||||||
for i,v in component.list() do
|
|
||||||
if i=="disk" then
|
|
||||||
disks[v.id]=v
|
|
||||||
if v.type=="udd" then
|
|
||||||
v:writeBytes(0, "HDS") -- "HDS"
|
|
||||||
local tmp = v:readBytes(0,512) -- Just to make sure it writes the data
|
|
||||||
print(tmp)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local idx = 1
|
|
||||||
local bootOption=1
|
|
||||||
while true do
|
|
||||||
if biosCfg[idx]=="$EOF" then break end
|
|
||||||
print("Atempting boot option "..tostring(bootOption).." labled \""..biosCfg[idx].."\".")
|
|
||||||
bootOption=bootOption+1
|
|
||||||
local drive={}
|
|
||||||
idx=idx+1
|
|
||||||
if not hasKey(disks,biosCfg[idx]) then
|
|
||||||
print("└─ Drive not found.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+3
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
drive=disks[biosCfg[idx]]
|
|
||||||
print("├─ Drive found with id of \""..drive.id.."\"")
|
|
||||||
end
|
|
||||||
idx=idx+1
|
|
||||||
local path
|
|
||||||
local code
|
|
||||||
if drive.type=="udd" then
|
|
||||||
print("├─ Drive is Unmanaged, looking for MBR...")
|
|
||||||
sleep(0.02)
|
|
||||||
print("├─ Reading MBR...")
|
|
||||||
local tmp = drive.readBytes(0,512)
|
|
||||||
print("├─ MBR found, compiling bootloader...")
|
|
||||||
code = table.concat(tmp)
|
|
||||||
else
|
|
||||||
if not drive:fileExists(biosCfg[idx]) then
|
|
||||||
print("└─ Path not found.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+2
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
print("├─ Kernel exists at path \""..biosCfg[idx].."\"")
|
|
||||||
path=biosCfg[idx]
|
|
||||||
end
|
|
||||||
code = drive:open(path).read()
|
|
||||||
end
|
|
||||||
idx=idx+1
|
|
||||||
local _VG=copy(_G)
|
|
||||||
print("├─ Created virtual ENV.")
|
|
||||||
local _,func = pcall(load,code,drive.id.." | "..path,nil,_VG)
|
|
||||||
if not func then
|
|
||||||
print("└─ Compilation failure.")
|
|
||||||
print(" ")
|
|
||||||
idx=idx+1
|
|
||||||
goto invalid_boot
|
|
||||||
else
|
|
||||||
print("├─ Executing.")
|
|
||||||
end
|
|
||||||
local cmd=biosCfg[idx] or ""
|
|
||||||
idx=idx+1
|
|
||||||
local biosData = {}
|
|
||||||
biosData.bootDrive=drive
|
|
||||||
biosData.term=screen
|
|
||||||
screen.clear()
|
|
||||||
local ok, err = xpcall(func, debug.traceback, biosData, cmd)
|
|
||||||
screen.clear()
|
|
||||||
screen.print(printed)
|
|
||||||
if not ok then
|
|
||||||
print("└─ OS exited with error: "..err)
|
|
||||||
print(" ")
|
|
||||||
else
|
|
||||||
print("└─ OS exited.")
|
|
||||||
print(" ")
|
|
||||||
end
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
::invalid_boot::
|
|
||||||
end
|
|
||||||
computer.beep(400,0.4)
|
|
||||||
print("No boot options available")
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
end, debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
screen.clear()
|
|
||||||
screen.print("BIOS PANIC: "..err)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
computer.beep(800,0.2)
|
|
||||||
sleep(0.02)
|
|
||||||
screen.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
computer.shutdown()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
sleep(0.02)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"disks":[1,2,3,4,8]
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
HyperionOS
|
|
||||||
disk_3
|
|
||||||
/boot/ac/boot.ac
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,46 +0,0 @@
|
|||||||
local driverutil={}
|
|
||||||
function driverutil.getFirst(type)
|
|
||||||
if drivers[type] then
|
|
||||||
if drivers[type][1] then
|
|
||||||
return drivers[type][1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driverutil.list(type)
|
|
||||||
if not type then
|
|
||||||
local tmp={}
|
|
||||||
for i,v in ipairs(drivers.raw) do
|
|
||||||
tmp[#tmp+1] = {type=v.type, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp[i].type, tmp[i].obj
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local tmp={}
|
|
||||||
for i,v in ipairs(drivers[type]) do
|
|
||||||
tmp[#tmp+1] = {type=v.type, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp[i].type, tmp[i].obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function runAsKernel(path, ...)
|
|
||||||
local func, err = load("return {'e'}", path, "t", _G)
|
|
||||||
if not func then return false, "\t"..err end
|
|
||||||
local ret = {xpcall(func, debug.traceback, ...)}
|
|
||||||
if not ret[1] then
|
|
||||||
return false, ret[2]
|
|
||||||
end
|
|
||||||
return true, table.unpack(ret, 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
runAsKernel(e, driverutil)
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"disks":[1,2,3,4,8]
|
|
||||||
}
|
|
||||||
@@ -1,249 +0,0 @@
|
|||||||
HyperionOS
|
|
||||||
disk_3
|
|
||||||
/boot/ac/boot.ac
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
if #args>0 then
|
|
||||||
load(args[1])(table.unpack(args, 2))
|
|
||||||
else
|
|
||||||
local sys = require("system")
|
|
||||||
local evhook = sys.addEventHook("keyTyped", function()
|
|
||||||
|
|
||||||
end)
|
|
||||||
local term = sys.getParentTermObject()
|
|
||||||
end
|
|
||||||
@@ -1,783 +0,0 @@
|
|||||||
-- SPDX-FileCopyrightText: 2017 Daniel Ratcliffe
|
|
||||||
--
|
|
||||||
-- SPDX-License-Identifier: LicenseRef-CCPL
|
|
||||||
|
|
||||||
--[[- The shell API provides access to CraftOS's command line interface.
|
|
||||||
It allows you to @{run|start programs}, @{setCompletionFunction|add completion
|
|
||||||
for a program}, and much more.
|
|
||||||
@{shell} is not a "true" API. Instead, it is a standard program, which injects
|
|
||||||
its API into the programs that it launches. This allows for multiple shells to
|
|
||||||
run at the same time, but means that the API is not available in the global
|
|
||||||
environment, and so is unavailable to other @{os.loadAPI|APIs}.
|
|
||||||
## Programs and the program path
|
|
||||||
When you run a command with the shell, either from the prompt or
|
|
||||||
@{shell.run|from Lua code}, the shell API performs several steps to work out
|
|
||||||
which program to run:
|
|
||||||
1. Firstly, the shell attempts to resolve @{shell.aliases|aliases}. This allows
|
|
||||||
us to use multiple names for a single command. For example, the `list`
|
|
||||||
program has two aliases: `ls` and `dir`. When you write `ls /rom`, that's
|
|
||||||
expanded to `list /rom`.
|
|
||||||
2. Next, the shell attempts to find where the program actually is. For this, it
|
|
||||||
uses the @{shell.path|program path}. This is a colon separated list of
|
|
||||||
directories, each of which is checked to see if it contains the program.
|
|
||||||
`list` or `list.lua` doesn't exist in `.` (the current directory), so she
|
|
||||||
shell now looks in `/rom/programs`, where `list.lua` can be found!
|
|
||||||
3. Finally, the shell reads the file and checks if the file starts with a
|
|
||||||
`#!`. This is a [hashbang][], which says that this file shouldn't be treated
|
|
||||||
as Lua, but instead passed to _another_ program, the name of which should
|
|
||||||
follow the `#!`.
|
|
||||||
[hashbang]: https://en.wikipedia.org/wiki/Shebang_(Unix)
|
|
||||||
@module[module] shell
|
|
||||||
]]
|
|
||||||
local make_package = dofile("rom/modules/main/cc/require.lua").make
|
|
||||||
|
|
||||||
local multishell = multishell
|
|
||||||
local parentShell = shell
|
|
||||||
local parentTerm = term.current()
|
|
||||||
|
|
||||||
if multishell then
|
|
||||||
multishell.setTitle(multishell.getCurrent(), "shell")
|
|
||||||
end
|
|
||||||
|
|
||||||
local bExit = false
|
|
||||||
local sDir = parentShell and parentShell.dir() or ""
|
|
||||||
local sPath = parentShell and parentShell.path() or ".:/rom/programs"
|
|
||||||
local tAliases = parentShell and parentShell.aliases() or {}
|
|
||||||
local tCompletionInfo = parentShell and parentShell.getCompletionInfo() or {}
|
|
||||||
local tProgramStack = {}
|
|
||||||
|
|
||||||
local shell = {} --- @export
|
|
||||||
local function createShellEnv(dir)
|
|
||||||
local env = { shell = shell, multishell = multishell }
|
|
||||||
env.require, env.package = make_package(env, dir)
|
|
||||||
return env
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Set up a dummy require based on the current shell, for loading some of our internal dependencies.
|
|
||||||
local require
|
|
||||||
do
|
|
||||||
local env = setmetatable(createShellEnv("/rom/programs"), { __index = _ENV })
|
|
||||||
require = env.require
|
|
||||||
end
|
|
||||||
local expect = require("cc.expect").expect
|
|
||||||
local exception = require "cc.internal.exception"
|
|
||||||
|
|
||||||
-- Colours
|
|
||||||
local promptColour, textColour, bgColour
|
|
||||||
if term.isColour() then
|
|
||||||
promptColour = colours.yellow
|
|
||||||
textColour = colours.white
|
|
||||||
bgColour = colours.black
|
|
||||||
else
|
|
||||||
promptColour = colours.white
|
|
||||||
textColour = colours.white
|
|
||||||
bgColour = colours.black
|
|
||||||
end
|
|
||||||
|
|
||||||
local function tokenise(...)
|
|
||||||
local sLine = table.concat({ ... }, " ")
|
|
||||||
local tWords = {}
|
|
||||||
local bQuoted = false
|
|
||||||
for match in string.gmatch(sLine .. "\"", "(.-)\"") do
|
|
||||||
if bQuoted then
|
|
||||||
table.insert(tWords, match)
|
|
||||||
else
|
|
||||||
for m in string.gmatch(match, "[^ \t]+") do
|
|
||||||
table.insert(tWords, m)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
bQuoted = not bQuoted
|
|
||||||
end
|
|
||||||
return tWords
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Execute a program using os.run, unless a shebang is present.
|
|
||||||
-- In that case, execute the program using the interpreter specified in the hashbang.
|
|
||||||
-- This may occur recursively, up to the maximum number of times specified by remainingRecursion
|
|
||||||
-- Returns the same type as os.run, which is a boolean indicating whether the program exited successfully.
|
|
||||||
local function executeProgram(remainingRecursion, path, args)
|
|
||||||
local file, err = fs.open(path, "r")
|
|
||||||
if not file then
|
|
||||||
printError(err)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- First check if the file begins with a #!
|
|
||||||
local contents = file.readLine() or ""
|
|
||||||
|
|
||||||
if contents:sub(1, 2) == "#!" then
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
remainingRecursion = remainingRecursion - 1
|
|
||||||
if remainingRecursion == 0 then
|
|
||||||
printError("Hashbang recursion depth limit reached when loading file: " .. path)
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Load the specified hashbang program instead
|
|
||||||
local hashbangArgs = tokenise(contents:sub(3))
|
|
||||||
local originalHashbangPath = table.remove(hashbangArgs, 1)
|
|
||||||
local resolvedHashbangProgram = shell.resolveProgram(originalHashbangPath)
|
|
||||||
if not resolvedHashbangProgram then
|
|
||||||
printError("Hashbang program not found: " .. originalHashbangPath)
|
|
||||||
return false
|
|
||||||
elseif resolvedHashbangProgram == "rom/programs/shell.lua" and #hashbangArgs == 0 then
|
|
||||||
-- If we try to launch the shell then our shebang expands to "shell <program>", which just does a
|
|
||||||
-- shell.run("<program>") again, resulting in an infinite loop. This may still happen (if the user
|
|
||||||
-- has a custom shell), but this reduces the risk.
|
|
||||||
-- It's a little ugly special-casing this, but it's probably worth warning about.
|
|
||||||
printError("Cannot use the shell as a hashbang program")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add the path and any arguments to the interpreter's arguments
|
|
||||||
table.insert(hashbangArgs, path)
|
|
||||||
for _, v in ipairs(args) do
|
|
||||||
table.insert(hashbangArgs, v)
|
|
||||||
end
|
|
||||||
|
|
||||||
hashbangArgs[0] = originalHashbangPath
|
|
||||||
return executeProgram(remainingRecursion, resolvedHashbangProgram, hashbangArgs)
|
|
||||||
end
|
|
||||||
|
|
||||||
contents = contents .. "\n" .. (file.readAll() or "")
|
|
||||||
file.close()
|
|
||||||
|
|
||||||
local dir = fs.getDir(path)
|
|
||||||
local env = setmetatable(createShellEnv(dir), { __index = _G })
|
|
||||||
env.arg = args
|
|
||||||
|
|
||||||
local func, err = load(contents, "@/" .. fs.combine(path), nil, env)
|
|
||||||
if not func then
|
|
||||||
-- We had a syntax error. Attempt to run it through our own parser if
|
|
||||||
-- the file is "small enough", otherwise report the original error.
|
|
||||||
if #contents < 1024 * 128 then
|
|
||||||
local parser = require "cc.internal.syntax"
|
|
||||||
if parser.parse_program(contents) then printError(err) end
|
|
||||||
else
|
|
||||||
printError(err)
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
if settings.get("bios.strict_globals", false) then
|
|
||||||
getmetatable(env).__newindex = function(_, name)
|
|
||||||
error("Attempt to create global " .. tostring(name), 2)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local ok, err, co = exception.try(func, table.unpack(args, 1, args.n))
|
|
||||||
|
|
||||||
if ok then return true end
|
|
||||||
|
|
||||||
if err and err ~= "" then
|
|
||||||
printError(err)
|
|
||||||
exception.report(err, co)
|
|
||||||
end
|
|
||||||
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Run a program with the supplied arguments.
|
|
||||||
--
|
|
||||||
-- Unlike @{shell.run}, each argument is passed to the program verbatim. While
|
|
||||||
-- `shell.run("echo", "b c")` runs `echo` with `b` and `c`,
|
|
||||||
-- `shell.execute("echo", "b c")` runs `echo` with a single argument `b c`.
|
|
||||||
--
|
|
||||||
-- @tparam string command The program to execute.
|
|
||||||
-- @tparam string ... Arguments to this program.
|
|
||||||
-- @treturn boolean Whether the program exited successfully.
|
|
||||||
-- @since 1.88.0
|
|
||||||
-- @usage Run `paint my-image` from within your program:
|
|
||||||
--
|
|
||||||
-- shell.execute("paint", "my-image")
|
|
||||||
function shell.execute(command, ...)
|
|
||||||
expect(1, command, "string")
|
|
||||||
for i = 1, select('#', ...) do
|
|
||||||
expect(i + 1, select(i, ...), "string")
|
|
||||||
end
|
|
||||||
|
|
||||||
local sPath = shell.resolveProgram(command)
|
|
||||||
if sPath ~= nil then
|
|
||||||
tProgramStack[#tProgramStack + 1] = sPath
|
|
||||||
if multishell then
|
|
||||||
local sTitle = fs.getName(sPath)
|
|
||||||
if sTitle:sub(-4) == ".lua" then
|
|
||||||
sTitle = sTitle:sub(1, -5)
|
|
||||||
end
|
|
||||||
multishell.setTitle(multishell.getCurrent(), sTitle)
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = executeProgram(100, sPath, { [0] = command, ... })
|
|
||||||
|
|
||||||
tProgramStack[#tProgramStack] = nil
|
|
||||||
if multishell then
|
|
||||||
if #tProgramStack > 0 then
|
|
||||||
local sTitle = fs.getName(tProgramStack[#tProgramStack])
|
|
||||||
if sTitle:sub(-4) == ".lua" then
|
|
||||||
sTitle = sTitle:sub(1, -5)
|
|
||||||
end
|
|
||||||
multishell.setTitle(multishell.getCurrent(), sTitle)
|
|
||||||
else
|
|
||||||
multishell.setTitle(multishell.getCurrent(), "shell")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
else
|
|
||||||
printError("No such program")
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Install shell API
|
|
||||||
|
|
||||||
--- Run a program with the supplied arguments.
|
|
||||||
--
|
|
||||||
-- All arguments are concatenated together and then parsed as a command line. As
|
|
||||||
-- a result, `shell.run("program a b")` is the same as `shell.run("program",
|
|
||||||
-- "a", "b")`.
|
|
||||||
--
|
|
||||||
-- @tparam string ... The program to run and its arguments.
|
|
||||||
-- @treturn boolean Whether the program exited successfully.
|
|
||||||
-- @usage Run `paint my-image` from within your program:
|
|
||||||
--
|
|
||||||
-- shell.run("paint", "my-image")
|
|
||||||
-- @see shell.execute Run a program directly without parsing the arguments.
|
|
||||||
-- @changed 1.80pr1 Programs now get their own environment instead of sharing the same one.
|
|
||||||
-- @changed 1.83.0 `arg` is now added to the environment.
|
|
||||||
function shell.run(...)
|
|
||||||
local tWords = tokenise(...)
|
|
||||||
local sCommand = tWords[1]
|
|
||||||
if sCommand then
|
|
||||||
return shell.execute(sCommand, table.unpack(tWords, 2))
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Exit the current shell.
|
|
||||||
--
|
|
||||||
-- This does _not_ terminate your program, it simply makes the shell terminate
|
|
||||||
-- after your program has finished. If this is the toplevel shell, then the
|
|
||||||
-- computer will be shutdown.
|
|
||||||
function shell.exit()
|
|
||||||
bExit = true
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Return the current working directory. This is what is displayed before the
|
|
||||||
-- `> ` of the shell prompt, and is used by @{shell.resolve} to handle relative
|
|
||||||
-- paths.
|
|
||||||
--
|
|
||||||
-- @treturn string The current working directory.
|
|
||||||
-- @see setDir To change the working directory.
|
|
||||||
function shell.dir()
|
|
||||||
return sDir
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the current working directory.
|
|
||||||
--
|
|
||||||
-- @tparam string dir The new working directory.
|
|
||||||
-- @throws If the path does not exist or is not a directory.
|
|
||||||
-- @usage Set the working directory to "rom"
|
|
||||||
--
|
|
||||||
-- shell.setDir("rom")
|
|
||||||
function shell.setDir(dir)
|
|
||||||
expect(1, dir, "string")
|
|
||||||
if not fs.isDir(dir) then
|
|
||||||
error("Not a directory", 2)
|
|
||||||
end
|
|
||||||
sDir = fs.combine(dir, "")
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the path where programs are located.
|
|
||||||
--
|
|
||||||
-- The path is composed of a list of directory names in a string, each separated
|
|
||||||
-- by a colon (`:`). On normal turtles will look in the current directory (`.`),
|
|
||||||
-- `/rom/programs` and `/rom/programs/turtle` folder, making the path
|
|
||||||
-- `.:/rom/programs:/rom/programs/turtle`.
|
|
||||||
--
|
|
||||||
-- @treturn string The current shell's path.
|
|
||||||
-- @see setPath To change the current path.
|
|
||||||
function shell.path()
|
|
||||||
return sPath
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the @{path|current program path}.
|
|
||||||
--
|
|
||||||
-- Be careful to prefix directories with a `/`. Otherwise they will be searched
|
|
||||||
-- for from the @{shell.dir|current directory}, rather than the computer's root.
|
|
||||||
--
|
|
||||||
-- @tparam string path The new program path.
|
|
||||||
-- @since 1.2
|
|
||||||
function shell.setPath(path)
|
|
||||||
expect(1, path, "string")
|
|
||||||
sPath = path
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Resolve a relative path to an absolute path.
|
|
||||||
--
|
|
||||||
-- The @{fs} and @{io} APIs work using absolute paths, and so we must convert
|
|
||||||
-- any paths relative to the @{dir|current directory} to absolute ones. This
|
|
||||||
-- does nothing when the path starts with `/`.
|
|
||||||
--
|
|
||||||
-- @tparam string path The path to resolve.
|
|
||||||
-- @usage Resolve `startup.lua` when in the `rom` folder.
|
|
||||||
--
|
|
||||||
-- shell.setDir("rom")
|
|
||||||
-- print(shell.resolve("startup.lua"))
|
|
||||||
-- -- => rom/startup.lua
|
|
||||||
function shell.resolve(path)
|
|
||||||
expect(1, path, "string")
|
|
||||||
local sStartChar = string.sub(path, 1, 1)
|
|
||||||
if sStartChar == "/" or sStartChar == "\\" then
|
|
||||||
return fs.combine("", path)
|
|
||||||
else
|
|
||||||
return fs.combine(sDir, path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function pathWithExtension(_sPath, _sExt)
|
|
||||||
local nLen = #sPath
|
|
||||||
local sEndChar = string.sub(_sPath, nLen, nLen)
|
|
||||||
-- Remove any trailing slashes so we can add an extension to the path safely
|
|
||||||
if sEndChar == "/" or sEndChar == "\\" then
|
|
||||||
_sPath = string.sub(_sPath, 1, nLen - 1)
|
|
||||||
end
|
|
||||||
return _sPath .. "." .. _sExt
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Resolve a program, using the @{path|program path} and list of @{aliases|aliases}.
|
|
||||||
--
|
|
||||||
-- @tparam string command The name of the program
|
|
||||||
-- @treturn string|nil The absolute path to the program, or @{nil} if it could
|
|
||||||
-- not be found.
|
|
||||||
-- @since 1.2
|
|
||||||
-- @usage Locate the `hello` program.
|
|
||||||
--
|
|
||||||
-- shell.resolveProgram("hello")
|
|
||||||
-- -- => rom/programs/fun/hello.lua
|
|
||||||
function shell.resolveProgram(command)
|
|
||||||
expect(1, command, "string")
|
|
||||||
-- Substitute aliases firsts
|
|
||||||
if tAliases[command] ~= nil then
|
|
||||||
command = tAliases[command]
|
|
||||||
end
|
|
||||||
|
|
||||||
-- If the path is a global path, use it directly
|
|
||||||
if command:find("/") or command:find("\\") then
|
|
||||||
local sPath = shell.resolve(command)
|
|
||||||
if fs.exists(sPath) and not fs.isDir(sPath) then
|
|
||||||
return sPath
|
|
||||||
else
|
|
||||||
local sPathLua = pathWithExtension(sPath, "lua")
|
|
||||||
if fs.exists(sPathLua) and not fs.isDir(sPathLua) then
|
|
||||||
return sPathLua
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Otherwise, look on the path variable
|
|
||||||
for sPath in string.gmatch(sPath, "[^:]+") do
|
|
||||||
sPath = fs.combine(shell.resolve(sPath), command)
|
|
||||||
if fs.exists(sPath) and not fs.isDir(sPath) then
|
|
||||||
return sPath
|
|
||||||
else
|
|
||||||
local sPathLua = pathWithExtension(sPath, "lua")
|
|
||||||
if fs.exists(sPathLua) and not fs.isDir(sPathLua) then
|
|
||||||
return sPathLua
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Not found
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Return a list of all programs on the @{shell.path|path}.
|
|
||||||
--
|
|
||||||
-- @tparam[opt] boolean include_hidden Include hidden files. Namely, any which
|
|
||||||
-- start with `.`.
|
|
||||||
-- @treturn { string } A list of available programs.
|
|
||||||
-- @usage textutils.tabulate(shell.programs())
|
|
||||||
-- @since 1.2
|
|
||||||
function shell.programs(include_hidden)
|
|
||||||
expect(1, include_hidden, "boolean", "nil")
|
|
||||||
|
|
||||||
local tItems = {}
|
|
||||||
|
|
||||||
-- Add programs from the path
|
|
||||||
for sPath in string.gmatch(sPath, "[^:]+") do
|
|
||||||
sPath = shell.resolve(sPath)
|
|
||||||
if fs.isDir(sPath) then
|
|
||||||
local tList = fs.list(sPath)
|
|
||||||
for n = 1, #tList do
|
|
||||||
local sFile = tList[n]
|
|
||||||
if not fs.isDir(fs.combine(sPath, sFile)) and
|
|
||||||
(include_hidden or string.sub(sFile, 1, 1) ~= ".") then
|
|
||||||
if #sFile > 4 and sFile:sub(-4) == ".lua" then
|
|
||||||
sFile = sFile:sub(1, -5)
|
|
||||||
end
|
|
||||||
tItems[sFile] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Sort and return
|
|
||||||
local tItemList = {}
|
|
||||||
for sItem in pairs(tItems) do
|
|
||||||
table.insert(tItemList, sItem)
|
|
||||||
end
|
|
||||||
table.sort(tItemList)
|
|
||||||
return tItemList
|
|
||||||
end
|
|
||||||
|
|
||||||
local function completeProgram(sLine)
|
|
||||||
local bIncludeHidden = settings.get("shell.autocomplete_hidden")
|
|
||||||
if #sLine > 0 and (sLine:find("/") or sLine:find("\\")) then
|
|
||||||
-- Add programs from the root
|
|
||||||
return fs.complete(sLine, sDir, {
|
|
||||||
include_files = true,
|
|
||||||
include_dirs = false,
|
|
||||||
include_hidden = bIncludeHidden,
|
|
||||||
})
|
|
||||||
|
|
||||||
else
|
|
||||||
local tResults = {}
|
|
||||||
local tSeen = {}
|
|
||||||
|
|
||||||
-- Add aliases
|
|
||||||
for sAlias in pairs(tAliases) do
|
|
||||||
if #sAlias > #sLine and string.sub(sAlias, 1, #sLine) == sLine then
|
|
||||||
local sResult = string.sub(sAlias, #sLine + 1)
|
|
||||||
if not tSeen[sResult] then
|
|
||||||
table.insert(tResults, sResult)
|
|
||||||
tSeen[sResult] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add all subdirectories. We don't include files as they will be added in the block below
|
|
||||||
local tDirs = fs.complete(sLine, sDir, {
|
|
||||||
include_files = false,
|
|
||||||
include_dirs = false,
|
|
||||||
include_hidden = bIncludeHidden,
|
|
||||||
})
|
|
||||||
for i = 1, #tDirs do
|
|
||||||
local sResult = tDirs[i]
|
|
||||||
if not tSeen[sResult] then
|
|
||||||
table.insert (tResults, sResult)
|
|
||||||
tSeen [sResult] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Add programs from the path
|
|
||||||
local tPrograms = shell.programs()
|
|
||||||
for n = 1, #tPrograms do
|
|
||||||
local sProgram = tPrograms[n]
|
|
||||||
if #sProgram > #sLine and string.sub(sProgram, 1, #sLine) == sLine then
|
|
||||||
local sResult = string.sub(sProgram, #sLine + 1)
|
|
||||||
if not tSeen[sResult] then
|
|
||||||
table.insert(tResults, sResult)
|
|
||||||
tSeen[sResult] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Sort and return
|
|
||||||
table.sort(tResults)
|
|
||||||
return tResults
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function completeProgramArgument(sProgram, nArgument, sPart, tPreviousParts)
|
|
||||||
local tInfo = tCompletionInfo[sProgram]
|
|
||||||
if tInfo then
|
|
||||||
return tInfo.fnComplete(shell, nArgument, sPart, tPreviousParts)
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Complete a shell command line.
|
|
||||||
--
|
|
||||||
-- This accepts an incomplete command, and completes the program name or
|
|
||||||
-- arguments. For instance, `l` will be completed to `ls`, and `ls ro` will be
|
|
||||||
-- completed to `ls rom/`.
|
|
||||||
--
|
|
||||||
-- Completion handlers for your program may be registered with
|
|
||||||
-- @{shell.setCompletionFunction}.
|
|
||||||
--
|
|
||||||
-- @tparam string sLine The input to complete.
|
|
||||||
-- @treturn { string }|nil The list of possible completions.
|
|
||||||
-- @see _G.read For more information about completion.
|
|
||||||
-- @see shell.completeProgram
|
|
||||||
-- @see shell.setCompletionFunction
|
|
||||||
-- @see shell.getCompletionInfo
|
|
||||||
-- @since 1.74
|
|
||||||
function shell.complete(sLine)
|
|
||||||
expect(1, sLine, "string")
|
|
||||||
if #sLine > 0 then
|
|
||||||
local tWords = tokenise(sLine)
|
|
||||||
local nIndex = #tWords
|
|
||||||
if string.sub(sLine, #sLine, #sLine) == " " then
|
|
||||||
nIndex = nIndex + 1
|
|
||||||
end
|
|
||||||
if nIndex == 1 then
|
|
||||||
local sBit = tWords[1] or ""
|
|
||||||
local sPath = shell.resolveProgram(sBit)
|
|
||||||
if tCompletionInfo[sPath] then
|
|
||||||
return { " " }
|
|
||||||
else
|
|
||||||
local tResults = completeProgram(sBit)
|
|
||||||
for n = 1, #tResults do
|
|
||||||
local sResult = tResults[n]
|
|
||||||
local sPath = shell.resolveProgram(sBit .. sResult)
|
|
||||||
if tCompletionInfo[sPath] then
|
|
||||||
tResults[n] = sResult .. " "
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return tResults
|
|
||||||
end
|
|
||||||
|
|
||||||
elseif nIndex > 1 then
|
|
||||||
local sPath = shell.resolveProgram(tWords[1])
|
|
||||||
local sPart = tWords[nIndex] or ""
|
|
||||||
local tPreviousParts = tWords
|
|
||||||
tPreviousParts[nIndex] = nil
|
|
||||||
return completeProgramArgument(sPath , nIndex - 1, sPart, tPreviousParts)
|
|
||||||
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Complete the name of a program.
|
|
||||||
--
|
|
||||||
-- @tparam string program The name of a program to complete.
|
|
||||||
-- @treturn { string } A list of possible completions.
|
|
||||||
-- @see cc.shell.completion.program
|
|
||||||
function shell.completeProgram(program)
|
|
||||||
expect(1, program, "string")
|
|
||||||
return completeProgram(program)
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Set the completion function for a program. When the program is entered on
|
|
||||||
-- the command line, this program will be called to provide auto-complete
|
|
||||||
-- information.
|
|
||||||
--
|
|
||||||
-- The completion function accepts four arguments:
|
|
||||||
--
|
|
||||||
-- 1. The current shell. As completion functions are inherited, this is not
|
|
||||||
-- guaranteed to be the shell you registered this function in.
|
|
||||||
-- 2. The index of the argument currently being completed.
|
|
||||||
-- 3. The current argument. This may be the empty string.
|
|
||||||
-- 4. A list of the previous arguments.
|
|
||||||
--
|
|
||||||
-- For instance, when completing `pastebin put rom/st` our pastebin completion
|
|
||||||
-- function will receive the shell API, an index of 2, `rom/st` as the current
|
|
||||||
-- argument, and a "previous" table of `{ "put" }`. This function may then wish
|
|
||||||
-- to return a table containing `artup.lua`, indicating the entire command
|
|
||||||
-- should be completed to `pastebin put rom/startup.lua`.
|
|
||||||
--
|
|
||||||
-- You completion entries may also be followed by a space, if you wish to
|
|
||||||
-- indicate another argument is expected.
|
|
||||||
--
|
|
||||||
-- @tparam string program The path to the program. This should be an absolute path
|
|
||||||
-- _without_ the leading `/`.
|
|
||||||
-- @tparam function(shell: table, index: number, argument: string, previous: { string }):({ string }|nil) complete
|
|
||||||
-- The completion function.
|
|
||||||
-- @see cc.shell.completion Various utilities to help with writing completion functions.
|
|
||||||
-- @see shell.complete
|
|
||||||
-- @see _G.read For more information about completion.
|
|
||||||
-- @since 1.74
|
|
||||||
function shell.setCompletionFunction(program, complete)
|
|
||||||
expect(1, program, "string")
|
|
||||||
expect(2, complete, "function")
|
|
||||||
tCompletionInfo[program] = {
|
|
||||||
fnComplete = complete,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get a table containing all completion functions.
|
|
||||||
--
|
|
||||||
-- This should only be needed when building custom shells. Use
|
|
||||||
-- @{setCompletionFunction} to add a completion function.
|
|
||||||
--
|
|
||||||
-- @treturn { [string] = { fnComplete = function } } A table mapping the
|
|
||||||
-- absolute path of programs, to their completion functions.
|
|
||||||
function shell.getCompletionInfo()
|
|
||||||
return tCompletionInfo
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Returns the path to the currently running program.
|
|
||||||
--
|
|
||||||
-- @treturn string The absolute path to the running program.
|
|
||||||
-- @since 1.3
|
|
||||||
function shell.getRunningProgram()
|
|
||||||
if #tProgramStack > 0 then
|
|
||||||
return tProgramStack[#tProgramStack]
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Add an alias for a program.
|
|
||||||
--
|
|
||||||
-- @tparam string command The name of the alias to add.
|
|
||||||
-- @tparam string program The name or path to the program.
|
|
||||||
-- @since 1.2
|
|
||||||
-- @usage Alias `vim` to the `edit` program
|
|
||||||
--
|
|
||||||
-- shell.setAlias("vim", "edit")
|
|
||||||
function shell.setAlias(command, program)
|
|
||||||
expect(1, command, "string")
|
|
||||||
expect(2, program, "string")
|
|
||||||
tAliases[command] = program
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Remove an alias.
|
|
||||||
--
|
|
||||||
-- @tparam string command The alias name to remove.
|
|
||||||
function shell.clearAlias(command)
|
|
||||||
expect(1, command, "string")
|
|
||||||
tAliases[command] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Get the current aliases for this shell.
|
|
||||||
--
|
|
||||||
-- Aliases are used to allow multiple commands to refer to a single program. For
|
|
||||||
-- instance, the `list` program is aliased to `dir` or `ls`. Running `ls`, `dir`
|
|
||||||
-- or `list` in the shell will all run the `list` program.
|
|
||||||
--
|
|
||||||
-- @treturn { [string] = string } A table, where the keys are the names of
|
|
||||||
-- aliases, and the values are the path to the program.
|
|
||||||
-- @see shell.setAlias
|
|
||||||
-- @see shell.resolveProgram This uses aliases when resolving a program name to
|
|
||||||
-- an absolute path.
|
|
||||||
function shell.aliases()
|
|
||||||
-- Copy aliases
|
|
||||||
local tCopy = {}
|
|
||||||
for sAlias, sCommand in pairs(tAliases) do
|
|
||||||
tCopy[sAlias] = sCommand
|
|
||||||
end
|
|
||||||
return tCopy
|
|
||||||
end
|
|
||||||
|
|
||||||
if multishell then
|
|
||||||
--- Open a new @{multishell} tab running a command.
|
|
||||||
--
|
|
||||||
-- This behaves similarly to @{shell.run}, but instead returns the process
|
|
||||||
-- index.
|
|
||||||
--
|
|
||||||
-- This function is only available if the @{multishell} API is.
|
|
||||||
--
|
|
||||||
-- @tparam string ... The command line to run.
|
|
||||||
-- @see shell.run
|
|
||||||
-- @see multishell.launch
|
|
||||||
-- @since 1.6
|
|
||||||
-- @usage Launch the Lua interpreter and switch to it.
|
|
||||||
--
|
|
||||||
-- local id = shell.openTab("lua")
|
|
||||||
-- shell.switchTab(id)
|
|
||||||
function shell.openTab(...)
|
|
||||||
local tWords = tokenise(...)
|
|
||||||
local sCommand = tWords[1]
|
|
||||||
if sCommand then
|
|
||||||
local sPath = shell.resolveProgram(sCommand)
|
|
||||||
if sPath == "rom/programs/shell.lua" then
|
|
||||||
return multishell.launch(createShellEnv("rom/programs"), sPath, table.unpack(tWords, 2))
|
|
||||||
elseif sPath ~= nil then
|
|
||||||
return multishell.launch(createShellEnv("rom/programs"), "rom/programs/shell.lua", sCommand, table.unpack(tWords, 2))
|
|
||||||
else
|
|
||||||
printError("No such program")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
--- Switch to the @{multishell} tab with the given index.
|
|
||||||
--
|
|
||||||
-- @tparam number id The tab to switch to.
|
|
||||||
-- @see multishell.setFocus
|
|
||||||
-- @since 1.6
|
|
||||||
function shell.switchTab(id)
|
|
||||||
expect(1, id, "number")
|
|
||||||
multishell.setFocus(id)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local tArgs = { ... }
|
|
||||||
if #tArgs > 0 then
|
|
||||||
-- "shell x y z"
|
|
||||||
-- Run the program specified on the commandline
|
|
||||||
shell.run(...)
|
|
||||||
|
|
||||||
else
|
|
||||||
local function show_prompt()
|
|
||||||
term.setBackgroundColor(bgColour)
|
|
||||||
term.setTextColour(promptColour)
|
|
||||||
write(shell.dir() .. "> ")
|
|
||||||
term.setTextColour(textColour)
|
|
||||||
end
|
|
||||||
|
|
||||||
-- "shell"
|
|
||||||
-- Print the header
|
|
||||||
term.setBackgroundColor(bgColour)
|
|
||||||
term.setTextColour(promptColour)
|
|
||||||
print(os.version())
|
|
||||||
term.setTextColour(textColour)
|
|
||||||
|
|
||||||
-- Run the startup program
|
|
||||||
if parentShell == nil then
|
|
||||||
shell.run("/rom/startup.lua")
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Read commands and execute them
|
|
||||||
local tCommandHistory = {}
|
|
||||||
while not bExit do
|
|
||||||
term.redirect(parentTerm)
|
|
||||||
if term.setGraphicsMode then term.setGraphicsMode(0) end
|
|
||||||
show_prompt()
|
|
||||||
|
|
||||||
|
|
||||||
local complete
|
|
||||||
if settings.get("shell.autocomplete") then complete = shell.complete end
|
|
||||||
|
|
||||||
local ok, result
|
|
||||||
local co = coroutine.create(read)
|
|
||||||
assert(coroutine.resume(co, nil, tCommandHistory, complete))
|
|
||||||
|
|
||||||
while coroutine.status(co) ~= "dead" do
|
|
||||||
local event = table.pack(os.pullEvent())
|
|
||||||
if event[1] == "file_transfer" then
|
|
||||||
-- Abandon the current prompt
|
|
||||||
local _, h = term.getSize()
|
|
||||||
local _, y = term.getCursorPos()
|
|
||||||
if y == h then
|
|
||||||
term.scroll(1)
|
|
||||||
term.setCursorPos(1, y)
|
|
||||||
else
|
|
||||||
term.setCursorPos(1, y + 1)
|
|
||||||
end
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
|
|
||||||
-- Run the import script with the provided files
|
|
||||||
local ok, err = require("cc.internal.import")(event[2].getFiles())
|
|
||||||
if not ok and err then printError(err) end
|
|
||||||
|
|
||||||
-- And attempt to restore the prompt.
|
|
||||||
show_prompt()
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
event = { "term_resize", n = 1 } -- Nasty hack to force read() to redraw.
|
|
||||||
end
|
|
||||||
|
|
||||||
if result == nil or event[1] == result or event[1] == "terminate" then
|
|
||||||
ok, result = coroutine.resume(co, table.unpack(event, 1, event.n))
|
|
||||||
if not ok then error(result, 0) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if result:match("%S") and tCommandHistory[#tCommandHistory] ~= result then
|
|
||||||
table.insert(tCommandHistory, result)
|
|
||||||
end
|
|
||||||
shell.run(result)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,98 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
local apis = args[2]
|
|
||||||
local term = args[4]
|
|
||||||
local getfile = args[5]
|
|
||||||
local computer = args[7]
|
|
||||||
local timeout = computer.time() + 5000
|
|
||||||
|
|
||||||
term.print("HBoot V1.0.0 //\n")
|
|
||||||
local w, h = term.getSize()
|
|
||||||
|
|
||||||
local kernel = load(getfile("/boot/Hyprkrnl.sys").readAllText())
|
|
||||||
local recovery = load(getfile("/boot/util/shell").readAllText())
|
|
||||||
|
|
||||||
-- Predeclare dbg so entries can reference it
|
|
||||||
local dbg = {}
|
|
||||||
local entries = {
|
|
||||||
{"HyperionOS", function() kernel(args, nil, "/sbin/init") end},
|
|
||||||
{"HyperionOS (Debug options)", dbg}
|
|
||||||
}
|
|
||||||
|
|
||||||
dbg[1] = {"Back", "BACK"}
|
|
||||||
dbg[2] = {"Boot HyperionOS in debug mode", function() kernel(args, true) end}
|
|
||||||
dbg[3] = {"Boot as shell", function() kernel(args, true, "/bin/bash") end}
|
|
||||||
dbg[4] = {"Boot in recovery", function() recovery(args) end}
|
|
||||||
|
|
||||||
local function render(tbl, selected)
|
|
||||||
term.clear()
|
|
||||||
term.print("HBoot V1.0.0 //\n\n")
|
|
||||||
for i, v in ipairs(tbl) do
|
|
||||||
if selected == i then
|
|
||||||
term.print("> " .. v[1] .. "\n")
|
|
||||||
else
|
|
||||||
term.print(" " .. v[1] .. "\n")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Initial render
|
|
||||||
render(entries, 1)
|
|
||||||
|
|
||||||
-- Wait for keypress or timeout
|
|
||||||
local exit = false
|
|
||||||
while not exit do
|
|
||||||
local ret = {computer.getMachineEvent()}
|
|
||||||
if ret[1] == "keyPressed" then
|
|
||||||
timeout = math.huge
|
|
||||||
break
|
|
||||||
end
|
|
||||||
if timeout <= computer.time() then
|
|
||||||
exit = true
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Menu handling
|
|
||||||
if not exit then
|
|
||||||
local menuStack = {}
|
|
||||||
local currentMenu = entries
|
|
||||||
local selected = 1
|
|
||||||
render(currentMenu, selected)
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local ret = {computer.getMachineEvent()}
|
|
||||||
if ret[1] == "keyTyped" then
|
|
||||||
if ret[3] == "\n" then
|
|
||||||
local entry = currentMenu[selected]
|
|
||||||
if entry then
|
|
||||||
if type(entry[2]) == "function" then
|
|
||||||
entry[2]()
|
|
||||||
elseif type(entry[2]) == "table" then
|
|
||||||
table.insert(menuStack, {currentMenu, selected})
|
|
||||||
currentMenu = entry[2]
|
|
||||||
selected = 1
|
|
||||||
render(currentMenu, selected)
|
|
||||||
elseif entry[2] == "BACK" then
|
|
||||||
if #menuStack > 0 then
|
|
||||||
local prev = table.remove(menuStack)
|
|
||||||
currentMenu, selected = prev[1], prev[2]
|
|
||||||
render(currentMenu, selected)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif ret[3] == "\x1b[A" then -- Up arrow
|
|
||||||
if selected > 1 then
|
|
||||||
selected = selected - 1
|
|
||||||
render(currentMenu, selected)
|
|
||||||
end
|
|
||||||
elseif ret[3] == "\x1b[B" then -- Down arrow
|
|
||||||
if selected < #currentMenu then
|
|
||||||
selected = selected + 1
|
|
||||||
render(currentMenu, selected)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
kernel(args)
|
|
||||||
end
|
|
||||||
@@ -1,230 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local bootLoader=args[1]
|
|
||||||
local MODE=bootLoader[1]
|
|
||||||
local apis=bootLoader[2]
|
|
||||||
local bootDisk=bootLoader[3]
|
|
||||||
local term=bootLoader[4]
|
|
||||||
local getFile=bootLoader[5]
|
|
||||||
local bootData
|
|
||||||
do
|
|
||||||
local tmp=load("return "..(getFile("/var/log/kernel/bootData").readAllText() or "{}"))
|
|
||||||
if not tmp then error("Bootdata failed to load") end
|
|
||||||
bootData=tmp()
|
|
||||||
end
|
|
||||||
local list=bootLoader[6]
|
|
||||||
local computer=bootLoader[7]
|
|
||||||
local startup=true
|
|
||||||
local osleep=sleep
|
|
||||||
_G._SYSDEBUG=args[2]
|
|
||||||
bootData.debug=args[2]
|
|
||||||
local drivers={}
|
|
||||||
local eventCache={}
|
|
||||||
|
|
||||||
while true do
|
|
||||||
local event={computer.getMachineEvent()}
|
|
||||||
if event[1]==nil then break end
|
|
||||||
eventCache[#eventCache+1] = event
|
|
||||||
end
|
|
||||||
|
|
||||||
term.clear()
|
|
||||||
term.print("Welcome to Hyperion OS")
|
|
||||||
term.print("Creating logger")
|
|
||||||
osleep(1)
|
|
||||||
local log=load(getFile("/sys/util/logger.lua").readAllText())(computer)
|
|
||||||
term.clear()
|
|
||||||
local logHook=log.setHook(term.print)
|
|
||||||
log.api.log("Created logger")
|
|
||||||
local function saveLog()
|
|
||||||
local logNum=bootData.logNum
|
|
||||||
getFile("/var/log/kernel/"..tostring(logNum)..".log").writeAllText(log.api.get())
|
|
||||||
getFile("/var/log/kernel/latest.log").writeAllText(log.api.get())
|
|
||||||
if bootData.logNum==10 then
|
|
||||||
bootData.logNum=0
|
|
||||||
else
|
|
||||||
bootData.logNum=bootData.logNum+1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if bootData.debug then _G.saveLog=saveLog end
|
|
||||||
|
|
||||||
local function t2t(table)
|
|
||||||
local output = "{"
|
|
||||||
for i,v in pairs(table) do
|
|
||||||
local coma=true
|
|
||||||
if type(i) == "string" then
|
|
||||||
output=output.."[\""..i.."\"]="
|
|
||||||
end
|
|
||||||
if type(v) == "table" then
|
|
||||||
if v == table then
|
|
||||||
output=string.sub(output,1,#output-(#i+1))
|
|
||||||
coma=false
|
|
||||||
else
|
|
||||||
output=output..t2t(v)
|
|
||||||
end
|
|
||||||
elseif type(v) == "string" then
|
|
||||||
output=output.."[=["..v.."]=]"
|
|
||||||
elseif type(v) == "number" then
|
|
||||||
output=output..tostring(v)
|
|
||||||
elseif type(v) == "boolean" then
|
|
||||||
if v == true then
|
|
||||||
output=output.."true"
|
|
||||||
else
|
|
||||||
output=output.."false"
|
|
||||||
end
|
|
||||||
elseif type(v) == "function" then
|
|
||||||
output=output.."function()"
|
|
||||||
else
|
|
||||||
error("serialization of type \""..type(v).."\" is not supported")
|
|
||||||
end
|
|
||||||
if coma then
|
|
||||||
output=output..","
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #table>0 or string.sub(output,#output,#output) == "," then
|
|
||||||
output=string.sub(output,1,#output-1)
|
|
||||||
end
|
|
||||||
output=output.."}"
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Make PANIC
|
|
||||||
local function PANIC(err)
|
|
||||||
term.clear()
|
|
||||||
term.print(log.api.get())
|
|
||||||
saveLog()
|
|
||||||
if err==bootData.prevError then
|
|
||||||
bootData.errorCount=bootData.errorCount+1
|
|
||||||
else
|
|
||||||
bootData.prevError=err
|
|
||||||
bootData.errorCount=0
|
|
||||||
end
|
|
||||||
getFile("/var/log/kernel/bootData").writeAllText(t2t(bootData))
|
|
||||||
term.print("KERNEL PANIC: "..err)
|
|
||||||
term.print("Log saved to /var/log/kernel/"..tostring(bootData.logNum)..".log\n")
|
|
||||||
term.print("Press enter to continue...")
|
|
||||||
while true do
|
|
||||||
local event = {computer.getMachineEvent()}
|
|
||||||
if event[1]~=nil then
|
|
||||||
term.print(table.concat(event, " "))
|
|
||||||
end
|
|
||||||
if event[1] == "keyTyped" then
|
|
||||||
if event[3] == "\n" then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
computer.reboot()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function runAsKernel(path, ...)
|
|
||||||
local func, err = load(getFile(path).readAllText(), path, "t", _G)
|
|
||||||
if not func then return false, "\t"..err end
|
|
||||||
local ret = {xpcall(func, debug.traceback, ...)}
|
|
||||||
if not ret[1] then
|
|
||||||
return false, ret[2]
|
|
||||||
end
|
|
||||||
return true, table.unpack(ret, 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
log.api.log("Loading globals...")
|
|
||||||
for i,v in ipairs(list("/sys/api/")) do
|
|
||||||
if bootData.debug then log.api.debug("Loading "..v) end
|
|
||||||
local ok, err = runAsKernel("/sys/api/"..v, getFile, log)
|
|
||||||
if not ok then log.api.warn(err) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local driverutil={}
|
|
||||||
function driverutil.getFirst(type)
|
|
||||||
if drivers[type] then
|
|
||||||
if drivers[type][1] then
|
|
||||||
return drivers[type][1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driverutil.list(type)
|
|
||||||
if not type then
|
|
||||||
local tmp={}
|
|
||||||
for i,v in ipairs(drivers.raw) do
|
|
||||||
tmp[#tmp+1] = {type=v.type, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp[i].type, tmp[i].obj
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local tmp={}
|
|
||||||
for i,v in ipairs(drivers[type]) do
|
|
||||||
tmp[#tmp+1] = {type=v.type, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp[i].type, tmp[i].obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
log.api.log("Loading drivers...")
|
|
||||||
for i,v in ipairs(list("/sys/modules/")) do
|
|
||||||
if bootData.debug then log.api.debug("Loading module "..v) end
|
|
||||||
local ok, err = runAsKernel("/sys/modules/"..v, apis, drivers, log, driverutil)
|
|
||||||
if not ok then log.api.warn("["..v.."] exited with ERR:\n"..err) end
|
|
||||||
end
|
|
||||||
|
|
||||||
log.api.log("Unloading non \""..MODE.."\" specific drivers...")
|
|
||||||
do
|
|
||||||
local tmp={}
|
|
||||||
for i,v in ipairs(drivers) do
|
|
||||||
if type(v.arch)=="table" then
|
|
||||||
for i2,v2 in ipairs(v.arch) do
|
|
||||||
if v2==MODE or v2=="ANY" then
|
|
||||||
tmp[#tmp+1] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if v.arch==MODE or v.arch=="ANY" then
|
|
||||||
tmp[#tmp+1] = v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
drivers={}
|
|
||||||
drivers.raw=tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
if bootData.debug then log.api.debug("Sorting drivers...") end
|
|
||||||
for i,v in ipairs(drivers.raw) do
|
|
||||||
if not drivers[v.type] then drivers[v.type]={} end
|
|
||||||
drivers[v.type][#drivers[v.type]+1] = v
|
|
||||||
end
|
|
||||||
|
|
||||||
if bootData.debug then log.api.debug("Initializing drivers...") end
|
|
||||||
for i,v in ipairs(drivers.raw) do
|
|
||||||
if v.init then
|
|
||||||
local ok, err = xpcall(v.init, debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
log.api.warn("["..v.name.."]: Init function ERR:\n"..err)
|
|
||||||
if bootData.debug then log.api.debug("Removing driver ["..v.name.."]") end
|
|
||||||
table.remove(drivers.raw, i)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
log.api.log("Loaded "..tostring(#drivers.raw).." drivers")
|
|
||||||
|
|
||||||
log.api.log("Loading filesystem...")
|
|
||||||
local ok, fs = runAsKernel("/sys/fs/init", drivers, log, bootDisk, driverutil)
|
|
||||||
if not ok then PANIC(fs) end
|
|
||||||
if not fs then PANIC("filesystem failed to load") end
|
|
||||||
fs.delete("/tmp")
|
|
||||||
fs.mkDir("/tmp")
|
|
||||||
|
|
||||||
log.api.log("Loading system...")
|
|
||||||
local ok, err = runAsKernel("/sys/Hyperion.sys", drivers, log)
|
|
||||||
if not ok then PANIC(err) end
|
|
||||||
local hyperion = err
|
|
||||||
if type(hyperion)~="function" then PANIC("Hyperion failed to load:\nHyperion was: "..tostring(hyperion)) end
|
|
||||||
hyperion(fs, log, drivers, PANIC, driverutil)
|
|
||||||
|
|
||||||
PANIC("OS EXITED MAIN()")
|
|
||||||
@@ -1,135 +0,0 @@
|
|||||||
local biosData = ({...})[1]
|
|
||||||
local apis = {}
|
|
||||||
|
|
||||||
local lua = {
|
|
||||||
coroutine = true,
|
|
||||||
debug = true,
|
|
||||||
_HOST = true,
|
|
||||||
_VERSION = true,
|
|
||||||
assert = true,
|
|
||||||
collectgarbage = true,
|
|
||||||
error = true,
|
|
||||||
gcinfo = true,
|
|
||||||
getfenv = true,
|
|
||||||
getmetatable = true,
|
|
||||||
ipairs = true,
|
|
||||||
__inext = true,
|
|
||||||
load = true,
|
|
||||||
math = true,
|
|
||||||
next = true,
|
|
||||||
pairs = true,
|
|
||||||
pcall = true,
|
|
||||||
rawequal = true,
|
|
||||||
rawget = true,
|
|
||||||
rawlen = true,
|
|
||||||
rawset = true,
|
|
||||||
select = true,
|
|
||||||
setfenv = true,
|
|
||||||
setmetatable = true,
|
|
||||||
string = true,
|
|
||||||
table = true,
|
|
||||||
tonumber = true,
|
|
||||||
tostring = true,
|
|
||||||
type = true,
|
|
||||||
xpcall = true,
|
|
||||||
_G = true
|
|
||||||
}
|
|
||||||
|
|
||||||
local print=component.getFirst("screen").print
|
|
||||||
local comp=component
|
|
||||||
-- Sandbox globals
|
|
||||||
local _REAL_G = _G
|
|
||||||
local _PAIRS = pairs
|
|
||||||
|
|
||||||
if type(_REAL_G) ~= "table" then
|
|
||||||
error("Global environment (_G) is not a table")
|
|
||||||
end
|
|
||||||
|
|
||||||
for i, v in _PAIRS(_REAL_G) do
|
|
||||||
if not lua[i] then
|
|
||||||
apis[i] = v
|
|
||||||
_REAL_G[i] = nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
apis.component=comp
|
|
||||||
|
|
||||||
-- File abstraction compatible with open() -> {read,write,append}
|
|
||||||
local function getFile(path)
|
|
||||||
return {
|
|
||||||
readAllText = function()
|
|
||||||
local handle = biosData.bootDrive:open(path)
|
|
||||||
if not handle or type(handle.read) ~= "function" then
|
|
||||||
error("Cannot open file for reading: " .. tostring(path))
|
|
||||||
end
|
|
||||||
return handle.read() or ""
|
|
||||||
end,
|
|
||||||
writeAllText = function(text)
|
|
||||||
if not biosData.bootDrive:fileExists(path) then
|
|
||||||
biosData.bootDrive:createFile(path)
|
|
||||||
end
|
|
||||||
local handle = biosData.bootDrive:open(path)
|
|
||||||
if not handle or type(handle.write) ~= "function" then
|
|
||||||
error("Cannot open file for writing: " .. tostring(path))
|
|
||||||
end
|
|
||||||
handle.write(text)
|
|
||||||
end,
|
|
||||||
appendText = function(text)
|
|
||||||
local handle = biosData.bootDrive:open(path)
|
|
||||||
if not handle or type(handle.append) ~= "function" then
|
|
||||||
error("Cannot open file for appending: " .. tostring(path))
|
|
||||||
end
|
|
||||||
handle.append(text)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function list(path)
|
|
||||||
return biosData.bootDrive:list(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function coroutine.resumeWithTimeout(CORO, LINES, ...)
|
|
||||||
local ret = { coroutine.resume(CORO, ...) }
|
|
||||||
if math.random(0, 1) == 0 then
|
|
||||||
return false, table.unpack(ret)
|
|
||||||
else
|
|
||||||
return true, table.unpack(ret)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Safety: verify APIs exist
|
|
||||||
if not apis.component then
|
|
||||||
error("Component API missing in environment")
|
|
||||||
end
|
|
||||||
if not biosData.bootDrive then
|
|
||||||
error("bootDrive missing from biosData")
|
|
||||||
end
|
|
||||||
|
|
||||||
local computer = apis.component.getFirst("computer")
|
|
||||||
|
|
||||||
-- Read kernel file correctly
|
|
||||||
local kernelSource = getFile("/boot/Hyprkrnl.sys").readAllText()
|
|
||||||
if not kernelSource or kernelSource == "" then
|
|
||||||
error("Kernel file empty or unreadable")
|
|
||||||
end
|
|
||||||
|
|
||||||
local kernel, err = load(kernelSource, "@kernel", "t", _G)
|
|
||||||
if not kernel then
|
|
||||||
error("Failed to load kernel: " .. tostring(err))
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Run kernel safely
|
|
||||||
local ok, perr = xpcall(function()
|
|
||||||
kernel(
|
|
||||||
"ac",
|
|
||||||
apis,
|
|
||||||
biosData.bootDrive.id,
|
|
||||||
apis.component.getFirst("screen"),
|
|
||||||
getFile,
|
|
||||||
list,
|
|
||||||
apis.component.getFirst("computer")
|
|
||||||
)
|
|
||||||
end, debug.traceback)
|
|
||||||
|
|
||||||
if not ok then
|
|
||||||
error("Kernel execution failed: " .. tostring(perr))
|
|
||||||
end
|
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
-- UnBIOS by JackMacWindows
|
|
||||||
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
|
|
||||||
-- To use, just place a `bios.lua` in the root of the drive, and run this program
|
|
||||||
-- Here's a list of things that are irreversibly changed:
|
|
||||||
-- * both `bit` and `bit32` are kept for compatibility
|
|
||||||
-- * string metatable blocking (on old versions of CC)
|
|
||||||
-- In addition, if `debug` is not available these things are also irreversibly changed:
|
|
||||||
-- * old Lua 5.1 `load` function (for loading from a function)
|
|
||||||
-- * `loadstring` prefixing (before CC:T 1.96.0)
|
|
||||||
-- * `http.request`
|
|
||||||
-- * `os.shutdown` and `os.reboot`
|
|
||||||
-- * `peripheral`
|
|
||||||
-- * `turtle.equip[Left|Right]`
|
|
||||||
-- Licensed under the MIT license
|
|
||||||
local args = {...}
|
|
||||||
if _HOST:find("UnBIOS") then return end
|
|
||||||
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
|
|
||||||
local t = {}
|
|
||||||
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
|
|
||||||
for _,k in ipairs(t) do _G[k] = nil end
|
|
||||||
local native = _G.term.native()
|
|
||||||
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
|
|
||||||
_G.term = native
|
|
||||||
if _G.http then
|
|
||||||
_G.http.checkURL = _G.http.checkURLAsync
|
|
||||||
_G.http.websocket = _G.http.websocketAsync
|
|
||||||
end
|
|
||||||
if _G.commands then _G.commands = _G.commands.native end
|
|
||||||
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
|
|
||||||
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
|
|
||||||
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
|
|
||||||
_G._HOST = _G._HOST .. " (UnBIOS)"
|
|
||||||
-- Set up TLCO
|
|
||||||
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
|
|
||||||
-- this would cause `parallel` to throw an error, but we replace `error` with an
|
|
||||||
-- empty placeholder to let it continue and return without throwing. This results
|
|
||||||
-- in the `pcall` returning successfully, preventing the error-displaying code
|
|
||||||
-- from running - essentially making it so that `os.shutdown` is called immediately
|
|
||||||
-- after the new BIOS exits.
|
|
||||||
--
|
|
||||||
-- From there, the setup code is placed in `term.native` since it's the first
|
|
||||||
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
|
|
||||||
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
|
|
||||||
-- allow it to be the last function called in the original BIOS, and returns.
|
|
||||||
-- From there execution continues, calling the `term.redirect` dummy, skipping
|
|
||||||
-- over the error-handling code (since `pcall` returned ok), and calling
|
|
||||||
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
|
|
||||||
-- called, which effectively makes it run as the main chunk.
|
|
||||||
local olderror = error
|
|
||||||
_G.error = function() end
|
|
||||||
_G.term.redirect = function() end
|
|
||||||
function _G.term.native()
|
|
||||||
_G.term.native = nil
|
|
||||||
_G.term.redirect = nil
|
|
||||||
_G.error = olderror
|
|
||||||
term.setBackgroundColor(32768)
|
|
||||||
term.setTextColor(1)
|
|
||||||
term.setCursorPos(1, 1)
|
|
||||||
term.setCursorBlink(true)
|
|
||||||
term.clear()
|
|
||||||
local file = fs.open("/disk/boot/cc/preboot.cc", "r")
|
|
||||||
if file == nil then
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
term.setTextColor(16384)
|
|
||||||
term.write("Could not find /boot/cc/bootloader.cc. UnBIOS cannot continue.")
|
|
||||||
term.setCursorPos(1, 2)
|
|
||||||
term.write("Press any key to continue")
|
|
||||||
coroutine.yield("key")
|
|
||||||
os.shutdown()
|
|
||||||
end
|
|
||||||
local fn, err = loadstring(file.readAll(), "@preboot.cc")
|
|
||||||
file.close()
|
|
||||||
if fn == nil then
|
|
||||||
term.setCursorBlink(false)
|
|
||||||
term.setTextColor(16384)
|
|
||||||
term.write("Could not load /boot/cc/bootloader.cc. UnBIOS cannot continue.")
|
|
||||||
term.setCursorPos(1, 2)
|
|
||||||
term.write(err)
|
|
||||||
term.setCursorPos(1, 3)
|
|
||||||
term.write("Press any key to continue")
|
|
||||||
coroutine.yield("key")
|
|
||||||
os.shutdown()
|
|
||||||
end
|
|
||||||
setfenv(fn, _G)
|
|
||||||
local oldshutdown = os.shutdown
|
|
||||||
os.shutdown = function()
|
|
||||||
os.shutdown = oldshutdown
|
|
||||||
return fn(table.unpack(args))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if debug then
|
|
||||||
-- Restore functions that were overwritten in the BIOS
|
|
||||||
-- Apparently this has to be done *after* redefining term.native
|
|
||||||
local function restoreValue(tab, idx, name, hint)
|
|
||||||
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
|
|
||||||
while key ~= name and key ~= nil do
|
|
||||||
key, value = debug.getupvalue(tab[idx], i)
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
tab[idx] = value or tab[idx]
|
|
||||||
end
|
|
||||||
restoreValue(_G, "loadstring", "nativeloadstring", 1)
|
|
||||||
restoreValue(_G, "load", "nativeload", 5)
|
|
||||||
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
|
|
||||||
restoreValue(os, "shutdown", "nativeShutdown", 1)
|
|
||||||
restoreValue(os, "reboot", "nativeReboot", 1)
|
|
||||||
if turtle then
|
|
||||||
restoreValue(turtle, "equipLeft", "v", 1)
|
|
||||||
restoreValue(turtle, "equipRight", "v", 1)
|
|
||||||
end
|
|
||||||
do
|
|
||||||
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
|
|
||||||
while key ~= "native" and key ~= nil do
|
|
||||||
key, value = debug.getupvalue(peripheral.isPresent, i)
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
_G.peripheral = value or peripheral
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
local apis={}
|
|
||||||
|
|
||||||
local lua = {
|
|
||||||
coroutine = true,
|
|
||||||
debug = true,
|
|
||||||
_HOST = true,
|
|
||||||
_VERSION = true,
|
|
||||||
assert = true,
|
|
||||||
collectgarbage = true,
|
|
||||||
error = true,
|
|
||||||
gcinfo = true,
|
|
||||||
getfenv = true,
|
|
||||||
getmetatable = true,
|
|
||||||
ipairs = true,
|
|
||||||
__inext = true,
|
|
||||||
load = true,
|
|
||||||
math = true,
|
|
||||||
next = true,
|
|
||||||
pairs = true,
|
|
||||||
pcall = true,
|
|
||||||
rawequal = true,
|
|
||||||
rawget = true,
|
|
||||||
rawlen = true,
|
|
||||||
rawset = true,
|
|
||||||
select = true,
|
|
||||||
setfenv = true,
|
|
||||||
setmetatable = true,
|
|
||||||
string = true,
|
|
||||||
table = true,
|
|
||||||
tonumber = true,
|
|
||||||
tostring = true,
|
|
||||||
type = true,
|
|
||||||
xpcall = true,
|
|
||||||
_G=true
|
|
||||||
}
|
|
||||||
|
|
||||||
for i,v in pairs(_G) do
|
|
||||||
if not lua[i] or lua[i]==nil then
|
|
||||||
apis[i]=v
|
|
||||||
_G[i]=nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function sleep(time)
|
|
||||||
coroutine.yield("CC_TIMER", time)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function catErr(text)
|
|
||||||
apis.term.setCursorPos(1,1)
|
|
||||||
apis.term.write(text)
|
|
||||||
while true do
|
|
||||||
coroutine.yield()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getFile(path)
|
|
||||||
if path:sub(1,1) ~= "/" then
|
|
||||||
path="/"..path
|
|
||||||
end
|
|
||||||
path="/disk"..path
|
|
||||||
if not apis.fs.exists(path) then error("File does not exist") end
|
|
||||||
if apis.fs.isDir(path) then error("Cannot open a directory") end
|
|
||||||
return {
|
|
||||||
readAllText=function()
|
|
||||||
local file = apis.fs.open(path, "r")
|
|
||||||
local text = file.readAll()
|
|
||||||
file.close()
|
|
||||||
return text
|
|
||||||
end,
|
|
||||||
writeAllText=function(text)
|
|
||||||
local file = apis.fs.open(path, "w")
|
|
||||||
file.write(text)
|
|
||||||
file.close()
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Prints text handling \n, \t, and \b with scrolling (no wrapping)
|
|
||||||
local function write(text)
|
|
||||||
local x, y = apis.term.getCursorPos()
|
|
||||||
local w, h = apis.term.getSize()
|
|
||||||
|
|
||||||
for i = 1, #text do
|
|
||||||
local c = text:sub(i, i)
|
|
||||||
|
|
||||||
if c == "\n" then
|
|
||||||
y = y + 1
|
|
||||||
x = 1
|
|
||||||
elseif c == "\t" then
|
|
||||||
local tabSize = 4
|
|
||||||
local spaces = tabSize - ((x - 1) % tabSize)
|
|
||||||
apis.term.write(string.rep(" ", spaces))
|
|
||||||
x = x + spaces
|
|
||||||
elseif c == "\b" then
|
|
||||||
if x > 1 then
|
|
||||||
x = x - 1
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
apis.term.write(" ")
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if x <= w and y <= h then
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
apis.term.write(c)
|
|
||||||
x = x + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle scrolling if we go past bottom
|
|
||||||
if y > h then
|
|
||||||
apis.term.scroll(1)
|
|
||||||
y = h
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
local event_queue = {}
|
|
||||||
local function addEventRaw(...)
|
|
||||||
event_queue[#event_queue+1] = {...}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getEvent()
|
|
||||||
local event = event_queue[1]
|
|
||||||
event_queue = {table.unpack(event_queue, 2)}
|
|
||||||
return table.unpack(event or {})
|
|
||||||
end
|
|
||||||
|
|
||||||
local lkeys={}
|
|
||||||
lkeys[apis.keys.enter]="\n"
|
|
||||||
lkeys[apis.keys.backspace]="\b"
|
|
||||||
lkeys[apis.keys.tab]="\t"
|
|
||||||
lkeys[apis.keys.up]="\x1b[A"
|
|
||||||
lkeys[apis.keys.down]="\x1b[B"
|
|
||||||
lkeys[apis.keys.right]="\x1b[C"
|
|
||||||
lkeys[apis.keys.left]="\x1b[D"
|
|
||||||
|
|
||||||
local computer={}
|
|
||||||
computer.beep=function() end
|
|
||||||
computer.shutdown=apis.os.shutdown
|
|
||||||
computer.reboot=apis.os.reboot
|
|
||||||
computer.time=function()
|
|
||||||
return apis.os.epoch("utc")
|
|
||||||
end
|
|
||||||
computer.getMachineEvent=getEvent
|
|
||||||
computer.date=apis.os.date
|
|
||||||
|
|
||||||
local function list(path)
|
|
||||||
if path:sub(1,1) ~= "/" then
|
|
||||||
path="/"..path
|
|
||||||
end
|
|
||||||
path="/disk"..path
|
|
||||||
if not apis.fs.isDir(path) then return {} end
|
|
||||||
return apis.fs.list(path)
|
|
||||||
end
|
|
||||||
|
|
||||||
function coroutine.resumeWithTimeout(CORO, LINES, ...)
|
|
||||||
local yeildKey = {}
|
|
||||||
debug.sethook(CORO, function()
|
|
||||||
coroutine.yield(yeildKey)
|
|
||||||
end, "l", LINES)
|
|
||||||
local ret = {coroutine.resume(CORO, ...)}
|
|
||||||
debug.sethook(CORO)
|
|
||||||
if ret[2]==yeildKey then return false else return true, table.unpack(ret, 2) end
|
|
||||||
end
|
|
||||||
|
|
||||||
local kernel = load(getFile("/boot/HBoot.sys").readAllText(), "@kernel", "t", _G)
|
|
||||||
if not kernel then
|
|
||||||
catErr("BOOT COMPILE ERR")
|
|
||||||
end
|
|
||||||
local kernel_coro = coroutine.create(function()
|
|
||||||
local ok,err = pcall(function()
|
|
||||||
local ok, err=xpcall(kernel, debug.traceback, "cc", apis, "disk", {
|
|
||||||
print=function(text)
|
|
||||||
write(text.."\n")
|
|
||||||
end,
|
|
||||||
printInline=function(text)
|
|
||||||
write(text)
|
|
||||||
end,
|
|
||||||
clear=function()
|
|
||||||
apis.term.clear()
|
|
||||||
apis.term.setCursorPos(1,1)
|
|
||||||
end,
|
|
||||||
getSize=function ()
|
|
||||||
return apis.term.getSize()
|
|
||||||
end
|
|
||||||
}, getFile, list, computer)
|
|
||||||
if not ok then
|
|
||||||
write(err)
|
|
||||||
while true do
|
|
||||||
coroutine.yield()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
if not ok then
|
|
||||||
catErr(err)
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
apis.term.setCursorBlink(false)
|
|
||||||
while true do
|
|
||||||
local ret = {coroutine.resumeWithTimeout(kernel_coro, 200)}
|
|
||||||
if coroutine.status(kernel_coro) == "dead" then
|
|
||||||
catErr("KERNEL EXITED")
|
|
||||||
end
|
|
||||||
if ret[1] then
|
|
||||||
if ret[2]=="CC_TIMER" and ret[3]~=nil and type(ret[3])=="number" then
|
|
||||||
local timer = apis.os.startTimer(ret[3])
|
|
||||||
repeat
|
|
||||||
local _, param = coroutine.yield("timer")
|
|
||||||
until param == timer
|
|
||||||
end
|
|
||||||
end
|
|
||||||
apis.os.queueEvent("nosleep")
|
|
||||||
local exit = false
|
|
||||||
repeat
|
|
||||||
local event = {coroutine.yield()}
|
|
||||||
if event[1] == "nosleep" then
|
|
||||||
exit=true
|
|
||||||
elseif event[1]==nil then
|
|
||||||
elseif event[1]=="key" then
|
|
||||||
addEventRaw("keyPressed", 1, event[2])
|
|
||||||
if lkeys[event[2]] then
|
|
||||||
addEventRaw("keyTyped", 1, lkeys[event[2]])
|
|
||||||
end
|
|
||||||
elseif event[1]=="char" then
|
|
||||||
addEventRaw("keyTyped", 1, event[2])
|
|
||||||
elseif event[1]=="key_up" then
|
|
||||||
addEventRaw("keyReleased", 1, event[2])
|
|
||||||
elseif event[1]=="disk" then
|
|
||||||
addEventRaw("componentAdded", "disk")
|
|
||||||
elseif event[1]=="disk_eject" then
|
|
||||||
addEventRaw("componentRemoved", "disk")
|
|
||||||
end
|
|
||||||
until exit
|
|
||||||
end
|
|
||||||
apis.os.reboot()
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,10 +0,0 @@
|
|||||||
local lib = {}
|
|
||||||
|
|
||||||
function lib.create()
|
|
||||||
local array = {}
|
|
||||||
return setmetatable(array,{
|
|
||||||
__add=function(t1, t2)
|
|
||||||
|
|
||||||
end
|
|
||||||
})
|
|
||||||
end
|
|
||||||
@@ -1,27 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local fs=args[1]
|
|
||||||
local log=args[2]
|
|
||||||
local drivers=args[3]
|
|
||||||
local PANIC=args[4]
|
|
||||||
local driverutil=args[5]
|
|
||||||
local sys={}
|
|
||||||
local task={}
|
|
||||||
|
|
||||||
sys._VERSION = "HyperionOS V1.0.4"
|
|
||||||
|
|
||||||
local function run(file, args)
|
|
||||||
local func, err=fs.loadAsFunc(file)
|
|
||||||
if not file then return 8, err end
|
|
||||||
local ret={xpcall(func, debug.traceback, table.unpack(args))}
|
|
||||||
if not ret[1] then return 1, ret[2] end
|
|
||||||
return 0, table.unpack(ret, 2)
|
|
||||||
end
|
|
||||||
|
|
||||||
local exitcode, req=run("/sys/system/require", {sys})
|
|
||||||
if exitcode~=0 then PANIC(req) end
|
|
||||||
_G.require=req
|
|
||||||
|
|
||||||
local exitcode, hypervisor=run("/sys/system/hypervisor/init", {sys})
|
|
||||||
if exitcode~=0 then PANIC(hypervisor) end
|
|
||||||
_G.require=hypervisor
|
|
||||||
|
|
||||||
@@ -1,57 +0,0 @@
|
|||||||
-- Copyright (C) 2025 ASTRONAND
|
|
||||||
function string.hasSuffix(str, suffix)
|
|
||||||
return string.sub(str, #suffix+1) == suffix
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.hasPrefix(str, prefix)
|
|
||||||
return string.sub(str, 1, #prefix) == prefix
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.getSuffix(str, prefix)
|
|
||||||
return string.sub(str, #prefix+1)
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.getPrefix(str, suffix)
|
|
||||||
return string.sub(str, 1, #suffix)
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.join(str, ...)
|
|
||||||
return table.concat(table.pack(str, ...))
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.delim(str, ...)
|
|
||||||
return table.concat(table.pack(...), str)
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.split(str, delim, maxResultCountOrNil)
|
|
||||||
assert(#delim == 1, "only delim len 1 supported for now")
|
|
||||||
maxResultCountOrNil = (maxResultCountOrNil or 0)-1
|
|
||||||
local rv = {}
|
|
||||||
local buf = ""
|
|
||||||
for i = 1, #str do
|
|
||||||
local c = string.sub(str,i,i)
|
|
||||||
if #rv ~= maxResultCountOrNil and c == delim then
|
|
||||||
table.insert(rv, buf)
|
|
||||||
buf = ""
|
|
||||||
else
|
|
||||||
buf = buf..c
|
|
||||||
end
|
|
||||||
end
|
|
||||||
table.insert(rv, buf)
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
function string.replace(str, search, replacement)
|
|
||||||
local rv = ""
|
|
||||||
local consumedLen = 1
|
|
||||||
local i = 1
|
|
||||||
while i<#str do
|
|
||||||
if string.sub(str, i, i+#search-1) == search then
|
|
||||||
rv = rv .. string.sub(str, consumedLen, i-1) .. replacement
|
|
||||||
i=i+#search
|
|
||||||
consumedLen = i
|
|
||||||
end
|
|
||||||
i=i+1
|
|
||||||
end
|
|
||||||
return rv .. string.sub(str, consumedLen)
|
|
||||||
end
|
|
||||||
@@ -1,81 +0,0 @@
|
|||||||
-- Copyright (C) 2025 ASTRONAND
|
|
||||||
function table.deepcopy(orig, copies)
|
|
||||||
copies = copies or {}
|
|
||||||
|
|
||||||
if type(orig) ~= 'table' then
|
|
||||||
return orig
|
|
||||||
elseif copies[orig] then
|
|
||||||
return copies[orig]
|
|
||||||
end
|
|
||||||
|
|
||||||
local copy = {}
|
|
||||||
copies[orig] = copy
|
|
||||||
|
|
||||||
for k, v in next, orig, nil do
|
|
||||||
local copied_key = table.deepcopy(k, copies)
|
|
||||||
local copied_val = table.deepcopy(v, copies)
|
|
||||||
copy[copied_key] = copied_val
|
|
||||||
end
|
|
||||||
|
|
||||||
return copy
|
|
||||||
end
|
|
||||||
|
|
||||||
function table.hasKey(tabl, query)
|
|
||||||
for i,v in pairs(tabl) do
|
|
||||||
if i==query then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function table.hasVal(tabl, query)
|
|
||||||
for i,v in pairs(tabl) do
|
|
||||||
if v==query then
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
local function serialize(table)
|
|
||||||
local output = "{"
|
|
||||||
for i,v in pairs(table) do
|
|
||||||
local coma=true
|
|
||||||
if type(i) == "string" then
|
|
||||||
output=output.."[\""..i.."\"]="
|
|
||||||
end
|
|
||||||
if type(v) == "table" then
|
|
||||||
if v == table then
|
|
||||||
output=string.sub(output,1,#output-(#i+1))
|
|
||||||
coma=false
|
|
||||||
else
|
|
||||||
output=output..serialize(v)
|
|
||||||
end
|
|
||||||
elseif type(v) == "string" then
|
|
||||||
output=output.."[=["..v.."]=]"
|
|
||||||
elseif type(v) == "number" then
|
|
||||||
output=output..tostring(v)
|
|
||||||
elseif type(v) == "boolean" then
|
|
||||||
if v == true then
|
|
||||||
output=output.."true"
|
|
||||||
else
|
|
||||||
output=output.."false"
|
|
||||||
end
|
|
||||||
elseif type(v) == "function" then
|
|
||||||
output=output.."function() end"
|
|
||||||
else
|
|
||||||
error("serialization of type \""..type(v).."\" is not supported")
|
|
||||||
end
|
|
||||||
if coma then
|
|
||||||
output=output..","
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if #table>0 or string.sub(output,#output,#output) == "," then
|
|
||||||
output=string.sub(output,1,#output-1)
|
|
||||||
end
|
|
||||||
output=output.."}"
|
|
||||||
return output
|
|
||||||
end
|
|
||||||
|
|
||||||
table.serialize=serialize
|
|
||||||
@@ -1,124 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local drivers=args[1]
|
|
||||||
local log=args[2]
|
|
||||||
local bootDisk=args[3]
|
|
||||||
local driverutil=args[4]
|
|
||||||
local wd="/"
|
|
||||||
log.api.log("Bootdrive is "..bootDisk)
|
|
||||||
if not drivers.disk then
|
|
||||||
error("WTF") -- ???
|
|
||||||
end
|
|
||||||
|
|
||||||
local disks={}
|
|
||||||
local mounts={
|
|
||||||
["/"]=bootDisk
|
|
||||||
}
|
|
||||||
local meta={}
|
|
||||||
|
|
||||||
local function refreshDisks()
|
|
||||||
local diskstmp={}
|
|
||||||
local tmp={}
|
|
||||||
for i,v in driverutil.list("disk") do
|
|
||||||
tmp[#tmp+1] = v
|
|
||||||
end
|
|
||||||
for _,d in ipairs(tmp) do
|
|
||||||
for i,v in d.api.list() do
|
|
||||||
if diskstmp[i]==nil then
|
|
||||||
diskstmp[i]=v
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
disks=diskstmp
|
|
||||||
end
|
|
||||||
refreshDisks()
|
|
||||||
--[[
|
|
||||||
meta=load("return "..(disks[bootDisk].readAllText("/sys/fs/meta.ltn") or "{}"), "meta")()
|
|
||||||
if not meta then error("Meta failed to load") end
|
|
||||||
]]
|
|
||||||
local function resolve(path)
|
|
||||||
if path:sub(1,1)~="/" then path=wd..path end
|
|
||||||
local currmatch="/"
|
|
||||||
for i,_ in pairs(mounts) do
|
|
||||||
if string.hasPrefix(path, i) then
|
|
||||||
if #i>#currmatch then
|
|
||||||
currmatch=i
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
local drive=disks[mounts[currmatch]]
|
|
||||||
local newPath=string.getSuffix(path, currmatch)
|
|
||||||
return drive, newPath
|
|
||||||
end
|
|
||||||
|
|
||||||
local fs={}
|
|
||||||
|
|
||||||
function fs.list(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.list(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.readAllText(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.readAllText(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.writeAllText(path, content)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.writeAllText(newPath, content)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.delete(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.delete(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.exists(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return (drive.fileExists(newPath) or drive.directoryExists(newPath))
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.fileExists(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.fileExists(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.directoryExists(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.directoryExists(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.createFile(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.makeFile(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.createDirectory(path)
|
|
||||||
local drive, newPath = resolve(path)
|
|
||||||
return drive.makeDirectory(newPath)
|
|
||||||
end
|
|
||||||
|
|
||||||
fs.mkDir=fs.createDirectory
|
|
||||||
fs.mkFile=fs.createFile
|
|
||||||
fs.isDir=fs.directoryExists
|
|
||||||
fs.isFile=fs.fileExists
|
|
||||||
|
|
||||||
function fs.getWorkingDir()
|
|
||||||
return wd
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.setWorkingDir(dir)
|
|
||||||
if type(dir)~="string" then error("Invailid path") end
|
|
||||||
if dir:sub(1,1)~="/" then dir=wd..dir end
|
|
||||||
if dir:sub(#dir,#dir)~="/" then dir=dir.."/" end
|
|
||||||
if not fs.isDir(dir) then error("Invailid path") end
|
|
||||||
end
|
|
||||||
|
|
||||||
function fs.loadAsFunc(path)
|
|
||||||
local file = fs.readAllText(path)
|
|
||||||
return load(file, path, "t", setmetatable({},{
|
|
||||||
__index=_G,
|
|
||||||
__metatable=false
|
|
||||||
}))
|
|
||||||
end
|
|
||||||
|
|
||||||
return fs
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
{["/sys/util/logger.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/bin/hex.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules/cc.component.kd"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt/astronand/ZDelta/init"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/api"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/10.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/7.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/1.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/bin/BASIC"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/cc/preboot.cc"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/ac"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/fs/init"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/api/table.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/5.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr/share/doc"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/3.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt/astronand/ZDelta"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/hypervisor/init.sys"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr/share"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/6.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/hypervisor"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/4.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib/array/math"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/util/conhost.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/Hyprkrnl.sys"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/bin"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules/ac.disks.kd"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib/array/x"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules/cc.disks.kd"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt/astronand/dbg"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr/share/doc/kernel/drivers"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/util"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/8.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/9.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/latest.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib/array"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/cc/boot.cc"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/home"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr/share/doc/kernel/drivers/disk.md"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib/LibDeflate"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/fs/meta.ltn"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/0.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/bootData"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/api/string.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/bin/shell.hex"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt/astronand/dbg/init"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/bootloader.sys"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/lib/array/2d"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/cc"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot/ac/boot.ac"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/log/kernel/2.log"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules/ccpc.disk.kd"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/api/require.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/bin/lua.lua"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/usr/share/doc/kernel"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/boot"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/fs"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/var/system"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/sys/modules/cc.terminal.kd"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
,["/opt/astronand"]={["p"]=21,["o"]=0,["g"]=0}
|
|
||||||
}
|
|
||||||
@@ -1,75 +0,0 @@
|
|||||||
local kernelArgs={...}
|
|
||||||
local apis=kernelArgs[1]
|
|
||||||
local drivers=kernelArgs[2]
|
|
||||||
local log=kernelArgs[3]
|
|
||||||
local driver={}
|
|
||||||
local disks = {}
|
|
||||||
|
|
||||||
driver.type = "disk"
|
|
||||||
driver.name = "AC:Disk"
|
|
||||||
driver.version = "1.0.0"
|
|
||||||
driver.apiVersion = 1
|
|
||||||
driver.description = "Driver for AC disks"
|
|
||||||
driver.arch = "ac"
|
|
||||||
driver.api = {}
|
|
||||||
|
|
||||||
local function refreshDisks()
|
|
||||||
local tmp={}
|
|
||||||
for i,v in apis.component.list() do
|
|
||||||
if i=="disk" then
|
|
||||||
tmp[v.id]={
|
|
||||||
readAllText=function(path)
|
|
||||||
return v:open(path).read()
|
|
||||||
end,
|
|
||||||
writeAllText=function(path, content)
|
|
||||||
return v:open(path).write(content)
|
|
||||||
end,
|
|
||||||
list=function(path)
|
|
||||||
return v:list(path)
|
|
||||||
end,
|
|
||||||
delete=function(path)
|
|
||||||
return v:delete(path)
|
|
||||||
end,
|
|
||||||
makeDirectory=function(path)
|
|
||||||
return v:makeDirectory(path)
|
|
||||||
end,
|
|
||||||
makeFile=function(path)
|
|
||||||
return v:makeFile(path)
|
|
||||||
end,
|
|
||||||
directoryExists=function(path)
|
|
||||||
return v:directoryExists(path)
|
|
||||||
end,
|
|
||||||
fileExists=function(path)
|
|
||||||
return v:fileExists(path)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
disks=tmp
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.init()
|
|
||||||
refreshDisks()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.list()
|
|
||||||
local tmp={}
|
|
||||||
for i,v in pairs(disks) do
|
|
||||||
tmp[#tmp+1]={id=i, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp.id, tmp.obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.main()
|
|
||||||
while true do
|
|
||||||
refreshDisks()
|
|
||||||
sleep(5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
drivers[#drivers+1]=driver
|
|
||||||
@@ -1,100 +0,0 @@
|
|||||||
local kernelArgs={...}
|
|
||||||
local apis=kernelArgs[1]
|
|
||||||
local drivers=kernelArgs[2]
|
|
||||||
local log=kernelArgs[3]
|
|
||||||
local driver={}
|
|
||||||
local disks={}
|
|
||||||
local driverutil=kernelArgs[4]
|
|
||||||
|
|
||||||
driver.type = "disk"
|
|
||||||
driver.name = "CC:Disks"
|
|
||||||
driver.version = "1.0.0"
|
|
||||||
driver.apiVersion = 1
|
|
||||||
driver.description = "Driver for CC:Tweaked disks"
|
|
||||||
driver.arch = "cc"
|
|
||||||
driver.api = {}
|
|
||||||
|
|
||||||
local function abs(path)
|
|
||||||
if path:sub(1,1)~="/" then path="/"..path end
|
|
||||||
return path
|
|
||||||
end
|
|
||||||
|
|
||||||
local function newDisk(root)
|
|
||||||
root="/"..root
|
|
||||||
return {
|
|
||||||
readAllText=function(path)
|
|
||||||
local file=apis.fs.open(root..abs(path),"r")
|
|
||||||
local text=file.readAll()
|
|
||||||
file.close()
|
|
||||||
return text
|
|
||||||
end,
|
|
||||||
writeAllText=function(path, content)
|
|
||||||
local file=apis.fs.open(root..abs(path),"w")
|
|
||||||
file.write(content)
|
|
||||||
file.close()
|
|
||||||
end,
|
|
||||||
list=function(path)
|
|
||||||
return apis.fs.list(root..abs(path))
|
|
||||||
end,
|
|
||||||
delete=function(path)
|
|
||||||
return apis.fs.delete(root..abs(path))
|
|
||||||
end,
|
|
||||||
makeDirectory=function(path)
|
|
||||||
return apis.fs.makeDir(root..abs(path))
|
|
||||||
end,
|
|
||||||
makeFile=function(path)
|
|
||||||
local file=apis.fs.open(root..abs(path),"w")
|
|
||||||
file.close()
|
|
||||||
end,
|
|
||||||
directoryExists=function(path)
|
|
||||||
return apis.fs.exists(root..abs(path)) and apis.fs.isDir(root..abs(path))
|
|
||||||
end,
|
|
||||||
fileExists=function(path)
|
|
||||||
return apis.fs.exists(root..abs(path)) and not apis.fs.isDir(root..abs(path))
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function refreshDisks(peripheral)
|
|
||||||
local tmp2={}
|
|
||||||
tmp2["disk"]=newDisk("disk")
|
|
||||||
for i,v in ipairs(peripheral.api.getNames()) do
|
|
||||||
if peripheral.api.isType(v, "drive") then
|
|
||||||
local p=peripheral.api.wrap(v)
|
|
||||||
if p.isDiskPresent() then
|
|
||||||
if p.getMountPath()~="disk" then
|
|
||||||
tmp2["disk_"..p.getID()] = newDisk(p.getMountPath())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
disks=tmp2
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.init()
|
|
||||||
local peripheral=driverutil.getFirst("component")
|
|
||||||
refreshDisks(peripheral)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.list()
|
|
||||||
local tmp={}
|
|
||||||
for i,v in pairs(disks) do
|
|
||||||
tmp[#tmp+1]={id=i, obj=v}
|
|
||||||
end
|
|
||||||
local i=0
|
|
||||||
return function()
|
|
||||||
i=i+1
|
|
||||||
if tmp[i]==nil then return end
|
|
||||||
return tmp[i].id, tmp[i].obj
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.main()
|
|
||||||
while true do
|
|
||||||
refreshDisks()
|
|
||||||
sleep(5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
drivers[#drivers+1] = driver
|
|
||||||
@@ -1,129 +0,0 @@
|
|||||||
local kernelArgs={...}
|
|
||||||
local apis=kernelArgs[1]
|
|
||||||
local drivers=kernelArgs[2]
|
|
||||||
local log=kernelArgs[3]
|
|
||||||
local driver={}
|
|
||||||
|
|
||||||
driver.type = "component"
|
|
||||||
driver.name = "CC:Periph"
|
|
||||||
driver.version = "1.0.0"
|
|
||||||
driver.apiVersion = 1
|
|
||||||
driver.description = "Driver for CC:Tweaked peripherals"
|
|
||||||
driver.arch = "cc"
|
|
||||||
driver.api = {}
|
|
||||||
|
|
||||||
local native,sides
|
|
||||||
if apis.peripheral then
|
|
||||||
native = apis.peripheral
|
|
||||||
sides = apis.rs.getSides()
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getNames()
|
|
||||||
local results = {}
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.isPresent(side) then
|
|
||||||
table.insert(results, side)
|
|
||||||
if native.hasType(side, "peripheral_hub") then
|
|
||||||
local remote = native.call(side, "getNamesRemote")
|
|
||||||
for _, name in ipairs(remote) do
|
|
||||||
table.insert(results, name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return results
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getType(peripheral)
|
|
||||||
if type(peripheral) == "string" then -- Peripheral name passed
|
|
||||||
if native.isPresent(peripheral) then
|
|
||||||
return native.getType(peripheral)
|
|
||||||
end
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
|
||||||
return native.call(side, "getTypeRemote", peripheral)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
local mt = getmetatable(peripheral)
|
|
||||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
|
||||||
error("bad argument #1 (table is not a peripheral)", 2)
|
|
||||||
end
|
|
||||||
return table.unpack(mt.types)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.isType(peripheral, peripheral_type)
|
|
||||||
if type(peripheral) == "string" then -- Peripheral name passed
|
|
||||||
if native.isPresent(peripheral) then
|
|
||||||
return native.hasType(peripheral, peripheral_type)
|
|
||||||
end
|
|
||||||
for n = 1, #sides do
|
|
||||||
local side = sides[n]
|
|
||||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", peripheral) then
|
|
||||||
return native.call(side, "hasTypeRemote", peripheral, peripheral_type)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
else
|
|
||||||
local mt = getmetatable(peripheral)
|
|
||||||
if not mt or mt.__name ~= "peripheral" or type(mt.types) ~= "table" then
|
|
||||||
error("bad argument #1 (table is not a peripheral)", 2)
|
|
||||||
end
|
|
||||||
return mt.types[peripheral_type] ~= nil
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.getMethods(name)
|
|
||||||
if native.isPresent(name) then
|
|
||||||
return native.getMethods(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, "getMethodsRemote", name)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.call(name, method, ...)
|
|
||||||
if native.isPresent(name) then
|
|
||||||
return native.call(name, method, ...)
|
|
||||||
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, "callRemote", name, method, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.wrap(name)
|
|
||||||
local methods = driver.api.getMethods(name)
|
|
||||||
if not methods then
|
|
||||||
return nil
|
|
||||||
end
|
|
||||||
|
|
||||||
local types = { driver.api.getType(name) }
|
|
||||||
for i = 1, #types do types[types[i]] = true end
|
|
||||||
local result = setmetatable({}, {
|
|
||||||
__name = "peripheral",
|
|
||||||
name = name,
|
|
||||||
type = types[1],
|
|
||||||
types = types,
|
|
||||||
})
|
|
||||||
for _, method in ipairs(methods) do
|
|
||||||
result[method] = function(...)
|
|
||||||
return driver.api.call(name, method, ...)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return result
|
|
||||||
end
|
|
||||||
|
|
||||||
drivers[#drivers+1] = driver
|
|
||||||
@@ -1,74 +0,0 @@
|
|||||||
local kernelArgs={...}
|
|
||||||
local apis=kernelArgs[1]
|
|
||||||
local drivers=kernelArgs[2]
|
|
||||||
local log=kernelArgs[3]
|
|
||||||
local driver={}
|
|
||||||
|
|
||||||
driver.type = "terminal"
|
|
||||||
driver.name = "CC:Term"
|
|
||||||
driver.version = "1.0.0"
|
|
||||||
driver.apiVersion = 1
|
|
||||||
driver.description = "Driver for CC:Tweaked screens"
|
|
||||||
driver.arch = "cc"
|
|
||||||
driver.api = {}
|
|
||||||
|
|
||||||
-- Prints text handling \n, \t, and \b with scrolling (no wrapping)
|
|
||||||
local function write(text)
|
|
||||||
local x, y = apis.term.getCursorPos()
|
|
||||||
local w, h = apis.term.getSize()
|
|
||||||
|
|
||||||
for i = 1, #text do
|
|
||||||
local c = text:sub(i, i)
|
|
||||||
|
|
||||||
if c == "\n" then
|
|
||||||
y = y + 1
|
|
||||||
x = 1
|
|
||||||
elseif c == "\t" then
|
|
||||||
local tabSize = 4
|
|
||||||
local spaces = tabSize - ((x - 1) % tabSize)
|
|
||||||
apis.term.write(string.rep(" ", spaces))
|
|
||||||
x = x + spaces
|
|
||||||
elseif c == "\b" then
|
|
||||||
if x > 1 then
|
|
||||||
x = x - 1
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
apis.term.write(" ")
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if x <= w and y <= h then
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
apis.term.write(c)
|
|
||||||
x = x + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- Handle scrolling if we go past bottom
|
|
||||||
if y > h then
|
|
||||||
apis.term.scroll(1)
|
|
||||||
y = h
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
apis.term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.print(text)
|
|
||||||
write(text.."\n")
|
|
||||||
end
|
|
||||||
|
|
||||||
function driver.api.printInline(text)
|
|
||||||
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
|
|
||||||
|
|
||||||
drivers[#drivers+1] = driver
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
|
|
||||||
-- <!ARCH>
|
|
||||||
-- @ICON$101003000000000000092492492490080000000010082000000010080400000010080080000010080400000010082002492010080000000010092492492490000000000000092492492490080000000010080000000010092492492490000000000000
|
|
||||||
@@ -1,70 +0,0 @@
|
|||||||
local args={...}
|
|
||||||
local computer=args[1]
|
|
||||||
local logs={["nil"]=""}
|
|
||||||
local hooks={["nil"]=function()end}
|
|
||||||
local log={api={}}
|
|
||||||
|
|
||||||
local function convert_epoch(epoch)
|
|
||||||
return computer.date("[%b %d %H:%M:%S]", epoch/1000)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.getProcess(func)
|
|
||||||
if type(func)=="function" then
|
|
||||||
log.getProcess=func
|
|
||||||
else
|
|
||||||
return "Hyprkrnl"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.log(text, logID)
|
|
||||||
local appendedText=convert_epoch(computer.time()).." "..log.getProcess()..":[IN] "..text
|
|
||||||
logs[tostring(logID)]=logs[tostring(logID)]..appendedText.."\n"
|
|
||||||
hooks[tostring(logID)](appendedText)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.warn(text, logID)
|
|
||||||
local appendedText=convert_epoch(computer.time()).." "..log.getProcess()..":[WN] "..text
|
|
||||||
logs[tostring(logID)]=logs[tostring(logID)]..appendedText.."\n"
|
|
||||||
hooks[tostring(logID)](appendedText)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.fail(text, logID)
|
|
||||||
local appendedText=convert_epoch(computer.time()).." "..log.getProcess()..":[FA] "..text
|
|
||||||
logs[tostring(logID)]=logs[tostring(logID)]..appendedText.."\n"
|
|
||||||
hooks[tostring(logID)](appendedText)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.debug(text, logID)
|
|
||||||
local appendedText=convert_epoch(computer.time()).." "..log.getProcess()..":[DE] "..text
|
|
||||||
logs[tostring(logID)]=logs[tostring(logID)]..appendedText.."\n"
|
|
||||||
hooks[tostring(logID)](appendedText)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.error(text, logID)
|
|
||||||
local appendedText=convert_epoch(computer.time()).." "..log.getProcess()..":[ER] "..text
|
|
||||||
logs[tostring(logID)]=logs[tostring(logID)]..appendedText.."\n"
|
|
||||||
hooks[tostring(logID)](appendedText)
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.api.get(logID)
|
|
||||||
return logs[tostring(logID)]
|
|
||||||
end
|
|
||||||
|
|
||||||
function log.setHook(func, logID)
|
|
||||||
hooks[tostring(logID)]=func
|
|
||||||
return {
|
|
||||||
removeHook=function()
|
|
||||||
hooks[tostring(logID)]=function()end
|
|
||||||
end
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local UUID = 0
|
|
||||||
function log.api.createLog(logID)
|
|
||||||
if logs[tostring(logID)]~=nil then error("cannot create duplicate log") end
|
|
||||||
if logID==nil then UUID=UUID+1; logID=UUID end
|
|
||||||
hooks[tostring(logID)]=function()end
|
|
||||||
logs[tostring(logID)]=""
|
|
||||||
end
|
|
||||||
|
|
||||||
return log
|
|
||||||
@@ -1,6 +0,0 @@
|
|||||||
### API:
|
|
||||||
---
|
|
||||||
```
|
|
||||||
getDisks():id, obj
|
|
||||||
|
|
||||||
```
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 31 18:33:08] Hyprkrnl:[IN] Loading system...
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Created logger
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Nov 12 22:17:07] Hyprkrnl:[IN] Loading system...
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 18:13:15] Hyprkrnl:[IN] Loading system...
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Created logger
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Nov 13 20:06:54] Hyprkrnl:[IN] Loading system...
|
|
||||||
@@ -1,17 +0,0 @@
|
|||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Created logger
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Nov 13 20:07:50] Hyprkrnl:[IN] Loading system...
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading require.lua
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] [REQUIRE]: Initialized FS
|
|
||||||
[Oct 30 17:41:54] Hyprkrnl:[IN] Loading hypervisor...
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading require.lua
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] [REQUIRE]: Initialized FS
|
|
||||||
[Oct 30 17:43:09] Hyprkrnl:[IN] Loading hypervisor...
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading require.lua
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] [REQUIRE]: Initialized FS
|
|
||||||
[Oct 30 17:44:55] Hyprkrnl:[IN] Loading hypervisor...
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading require.lua
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] [REQUIRE]: Initialized FS
|
|
||||||
[Oct 30 17:45:15] Hyprkrnl:[IN] Loading hypervisor...
|
|
||||||
@@ -1,19 +0,0 @@
|
|||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Created logger
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Loading globals...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading require.lua
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading string.lua
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading table.lua
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Loading drivers...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading module ac.disks.kd
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading module cc.disks.kd
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading module cc.periph.kd
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading module cc.terminal.kd
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Loading module ccpc.disk.kd
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Unloading non "cc" specific drivers...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Sorting drivers...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[DE] Initializing drivers...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Loaded 3 drivers
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Loading filesystem...
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Bootdrive is disk
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] [REQUIRE]: Initialized FS
|
|
||||||
[Oct 30 18:02:54] Hyprkrnl:[IN] Loading hypervisor...
|
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user