Compare commits
19 Commits
1.2.4-dev
...
1.2.4-dev_
| Author | SHA1 | Date | |
|---|---|---|---|
| 22b5021e9d | |||
| 462c74686a | |||
| 0072547beb | |||
| 7deefc83ca | |||
| df62414229 | |||
| 055dd4e606 | |||
| 5755dd9cbe | |||
| 8e11faf9ec | |||
| 0ea42f9454 | |||
| d0f26a937f | |||
| 9b338328f0 | |||
| 4f9eebade2 | |||
| d08935b68a | |||
| 45b46cf3c4 | |||
| aeea68bc9b | |||
| f983b13d56 | |||
| 03c5b106c4 | |||
| 08323e00ff | |||
| 5e3cdbe40c |
18
Src/Hyperion-core/lib/colors
Normal file
18
Src/Hyperion-core/lib/colors
Normal file
@@ -0,0 +1,18 @@
|
||||
--:Minify:--
|
||||
return {
|
||||
white=0xFFFFFF,
|
||||
red=0xFF0000,
|
||||
green=0x00FF00,
|
||||
blue=0x0000FF,
|
||||
cyan=0x00FFFF,
|
||||
yellow=0xFFFF00,
|
||||
purple=0xFF00FF,
|
||||
black=0x000000,
|
||||
gray=0x888888,
|
||||
lightgrey=0xBBBBBB,
|
||||
darkgrey=0x444444,
|
||||
orange=0xFF8800,
|
||||
mint=0x00FF88,
|
||||
brown=0xa52a2a,
|
||||
chocolate=0xd2691e
|
||||
}
|
||||
344
Src/Hyperion-firmware-ac/boot/ac/boot.lua
Normal file
344
Src/Hyperion-firmware-ac/boot/ac/boot.lua
Normal file
@@ -0,0 +1,344 @@
|
||||
--:Minify:--
|
||||
local args={...}
|
||||
local bootdrive=args[1]
|
||||
local gpu=components:getFirst("gpu")
|
||||
local screenTextBuffer=nil
|
||||
local cursorX,cursorY=0,0
|
||||
local screenSizeX,screenSizeY=128,25
|
||||
|
||||
|
||||
if gpu then
|
||||
screenTextBuffer=gpu:newBuffer(screenSizeX,screenSizeY)
|
||||
for t,v in components:list() do
|
||||
if t == "screen" then
|
||||
gpu:assignBuffer(screenTextBuffer, v)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function write(text)
|
||||
cursorX, cursorY = screenTextBuffer:pasteText(cursorX, cursorY, "SCROLL_SPILL_CLEAR", text)
|
||||
cursorY = cursorY + 1
|
||||
cursorX = 0
|
||||
if cursorY >= screenSizeY then
|
||||
cursorY = screenSizeY-1
|
||||
screenTextBuffer:newline()
|
||||
end
|
||||
end
|
||||
|
||||
local function displaySuperBadError(err)
|
||||
gpu:freeAllBuffers()
|
||||
screenTextBuffer=gpu:newBuffer(screenSizeX,screenSizeY)
|
||||
for t,v in components:list() do
|
||||
if t == "screen" then
|
||||
gpu:assignBuffer(screenTextBuffer, v)
|
||||
end
|
||||
end
|
||||
term.setBackgroundColor(0x1)
|
||||
term.setTextColor(0x4)
|
||||
term.clear()
|
||||
term.setCursorPos(1, 1)
|
||||
term.write("A critical error occurred while loading the system:")
|
||||
term.setCursorPos(1, 3)
|
||||
write(err)
|
||||
while true do end
|
||||
end
|
||||
|
||||
local ok, err = xpcall(function()
|
||||
local apis = {}
|
||||
|
||||
local lua = {
|
||||
coroutine = true,
|
||||
debug = true,
|
||||
_VERSION = true,
|
||||
assert = true,
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
gcinfo = 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,
|
||||
setmetatable = true,
|
||||
string = true,
|
||||
table = true,
|
||||
tonumber = true,
|
||||
tostring = true,
|
||||
type = true,
|
||||
xpcall = true,
|
||||
_G = true
|
||||
}
|
||||
|
||||
local debug = debug
|
||||
for i, v in pairs(_G) do
|
||||
if not lua[i] or lua[i] == nil then
|
||||
apis[i] = v
|
||||
_G[i] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function string_file(file)
|
||||
local str = file:read()
|
||||
local buf = {str or ""}
|
||||
local pos = 1
|
||||
local closed = false
|
||||
|
||||
local function content()
|
||||
return table.concat(buf)
|
||||
end
|
||||
|
||||
local function set_content(s)
|
||||
buf = {s}
|
||||
end
|
||||
|
||||
local function flush()
|
||||
file.write(content())
|
||||
end
|
||||
|
||||
local file = {}
|
||||
|
||||
function file:read(n)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
if not n then
|
||||
local out = s:sub(pos)
|
||||
pos = len + 1
|
||||
return out
|
||||
end
|
||||
|
||||
local out = s:sub(pos, pos + n - 1)
|
||||
pos = pos + #out
|
||||
return out
|
||||
end
|
||||
|
||||
function file:write(data)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local before = s:sub(1, pos - 1)
|
||||
local after = s:sub(pos + #data)
|
||||
|
||||
set_content(before .. data .. after)
|
||||
pos = pos + #data
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function file:seek(whence, offset)
|
||||
assert(not closed, "file is closed")
|
||||
|
||||
local s = content()
|
||||
local len = #s
|
||||
|
||||
whence = whence or "cur"
|
||||
offset = offset or 0
|
||||
|
||||
if whence == "set" then
|
||||
pos = offset + 1
|
||||
elseif whence == "cur" then
|
||||
pos = pos + offset
|
||||
elseif whence == "end" then
|
||||
pos = len + offset + 1
|
||||
else
|
||||
error("invalid whence")
|
||||
end
|
||||
|
||||
if pos < 1 then pos = 1 end
|
||||
if pos > len + 1 then pos = len + 1 end
|
||||
|
||||
return pos - 1
|
||||
end
|
||||
|
||||
function file:close()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
closed = true
|
||||
end
|
||||
|
||||
function file:flush()
|
||||
assert(not closed, "file is closed")
|
||||
flush()
|
||||
end
|
||||
|
||||
return file
|
||||
end
|
||||
|
||||
local function getFile(path)
|
||||
local file = bootdrive:open(path, "r")
|
||||
if not file then
|
||||
displaySuperBadError("Could not open file: " .. path)
|
||||
end
|
||||
local content = file:read()
|
||||
return content
|
||||
end
|
||||
|
||||
local Kernel = load(getFile("/boot/kernel.lua"),"@Kernel")
|
||||
local initFs = load(getFile("/boot/ac/initdisks"),"@Init_disks")(apis)
|
||||
local fs = load(getFile("/boot/initfs"), "@InitFs")()
|
||||
|
||||
if not Kernel then displaySuperBadError("Could not load kernel.") end
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
local computercomp=apis.components:getFirst("computer")
|
||||
local uefi=apis.components:getFirst("uefi")
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
getMachineEvent = function()
|
||||
return computercomp:getMachineEvent()
|
||||
end,
|
||||
getEEPROM = function() return uefi.data end,
|
||||
setEEPROM = function(_, text)
|
||||
uefi.data=text
|
||||
end
|
||||
}
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
|
||||
{
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
clear = function()
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
end,
|
||||
setCursorPos = function(_, x, y)
|
||||
apis.term.setCursorPos(x, y)
|
||||
end,
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(colors[color])
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(colors[color])
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return icolors[apis.term.getBackgroundColor()]
|
||||
end,
|
||||
getTextColor = function()
|
||||
return icolors[apis.term.getTextColor()]
|
||||
end
|
||||
}, computer, fs, "$")
|
||||
if not ok then displaySuperBadError(err) end
|
||||
end)
|
||||
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = computer.time()
|
||||
debug.sethook(co, function()
|
||||
if computer.time() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
local ret = {coroutine.resume(co, ...)}
|
||||
if ret[1] and ret[2] == "timeout" then
|
||||
return "timeout"
|
||||
elseif ret[1] == false then
|
||||
return "error", ret[2]
|
||||
else
|
||||
debug.sethook(co)
|
||||
return "success", table.unpack(ret, 2)
|
||||
end
|
||||
end
|
||||
|
||||
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
|
||||
while true do
|
||||
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||
apis.os.queueEvent("NoSleep")
|
||||
local exit = false
|
||||
while not exit do
|
||||
local event = {coroutine.yield()}
|
||||
if event[1] == "key" then
|
||||
queueEvent("keyPressed", 1, event[2])
|
||||
if acekeys[event[2]] then
|
||||
queueEvent("keyTyped", 1, acekeys[event[2]])
|
||||
end
|
||||
elseif event[1] == "char" then
|
||||
queueEvent("keyTyped", 1, event[2])
|
||||
elseif event[1] == "key_up" then
|
||||
queueEvent("keyReleased", 1, event[2])
|
||||
elseif event[1] == "disk" then
|
||||
queueEvent("componentAdded", "disk")
|
||||
elseif event[1] == "disk_eject" then
|
||||
queueEvent("componentRemoved", "disk")
|
||||
elseif event[1] == "modem_message" then
|
||||
queueEvent("modem_message", table.unpack(event, 2))
|
||||
elseif event[1] == "rednet_message" then
|
||||
queueEvent("rednet_message", table.unpack(event, 2))
|
||||
elseif event[1] == "http_success" then
|
||||
queueEvent("http_success", table.unpack(event, 2))
|
||||
elseif event[1] == "http_failure" then
|
||||
queueEvent("http_failure", table.unpack(event, 2))
|
||||
elseif event[1] == "NoSleep" then
|
||||
exit = true
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield() end
|
||||
@@ -1,4 +1,4 @@
|
||||
-- :Minify:--
|
||||
--:Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
@@ -71,7 +71,6 @@ local ok, err = xpcall(function()
|
||||
collectgarbage = true,
|
||||
error = true,
|
||||
gcinfo = true,
|
||||
getfenv = true,
|
||||
getmetatable = true,
|
||||
ipairs = true,
|
||||
__inext = true,
|
||||
@@ -85,7 +84,6 @@ local ok, err = xpcall(function()
|
||||
rawlen = true,
|
||||
rawset = true,
|
||||
select = true,
|
||||
setfenv = true,
|
||||
setmetatable = true,
|
||||
string = true,
|
||||
table = true,
|
||||
@@ -154,17 +152,106 @@ local ok, err = xpcall(function()
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
if not apis.fs.exists("/nvram.dat") then
|
||||
local file = apis.fs.open("/nvram.dat", "w")
|
||||
file.write("Hello, World!")
|
||||
file.close()
|
||||
end
|
||||
|
||||
local eeprom
|
||||
if apis.fs.exists("/startup.lua") then
|
||||
eeprom="/startup.lua"
|
||||
elseif apis.fs.exists("/eeprom") then
|
||||
eeprom="/eeprom"
|
||||
end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
local colors = {
|
||||
[0x000000]=0x0001,
|
||||
[0xFFFFFF]=0x0002,
|
||||
[0xFF0000]=0x0004,
|
||||
[0x00FF00]=0x0008,
|
||||
[0x0000FF]=0x0010,
|
||||
[0x00FFFF]=0x0020,
|
||||
[0xFF00FF]=0x0040,
|
||||
[0xFFFF00]=0x0080,
|
||||
[0xFF6D00]=0x0100,
|
||||
[0x6DFF55]=0x0200,
|
||||
[0x24FFFF]=0x0400,
|
||||
[0x924900]=0x0800,
|
||||
[0x6D6D55]=0x1000,
|
||||
[0xDBDBAA]=0x2000,
|
||||
[0x6D00FF]=0x4000,
|
||||
[0xB6FF00]=0x8000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local EFI = {
|
||||
getEpochMs = function() return apis.os.epoch("utc") end,
|
||||
getUptime = function() return apis.os.clock() * 1000 end,
|
||||
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
@@ -172,61 +259,15 @@ local ok, err = xpcall(function()
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
getEEPROM = function() return getFile("/startup.lua") end,
|
||||
getEEPROM = function() return getFile(eeprom) end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open("/startup.lua", "w")
|
||||
local h = apis.fs.open(eeprom, "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end
|
||||
}
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
|
||||
{
|
||||
end,
|
||||
initfs=fs,
|
||||
disks=initFs,
|
||||
screenCtl={
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
clear = function()
|
||||
@@ -239,25 +280,51 @@ local ok, err = xpcall(function()
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(colors[color])
|
||||
apis.term.setBackgroundColor(aprox(color))
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(colors[color])
|
||||
apis.term.setTextColor(aprox(color))
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return icolors[apis.term.getBackgroundColor()]
|
||||
return bg
|
||||
end,
|
||||
getTextColor = function()
|
||||
return icolors[apis.term.getTextColor()]
|
||||
end
|
||||
}, computer, fs, "$")
|
||||
if not ok then displaySuperBadError(err) end
|
||||
return fg
|
||||
end,
|
||||
enable=function() end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
getNvram = function() return getFile("/nvram.dat") end,
|
||||
setNvram = function(_, text)
|
||||
local h = apis.fs.open("/nvram.dat", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end,
|
||||
firmware=apis,
|
||||
reboot=false
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
||||
if not ok and not EFI.reboot then displaySuperBadError(err) end
|
||||
if err then
|
||||
apis.os.reboot()
|
||||
else
|
||||
apis.os.shutdown()
|
||||
end
|
||||
end)
|
||||
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = computer.time()
|
||||
local startTime = EFI.getEpochMs()
|
||||
debug.sethook(co, function()
|
||||
if computer.time() > startTime + timeout then
|
||||
if EFI.getEpochMs() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
@@ -306,11 +373,15 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
if EFI.reboot then
|
||||
apis.os.reboot()
|
||||
end
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
initFs:refresh()
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield() end
|
||||
while true do coroutine.yield("key") end
|
||||
272
Src/Hyperion-firmware-ccpc/boot/ccpc/initdisks
Normal file
272
Src/Hyperion-firmware-ccpc/boot/ccpc/initdisks
Normal file
@@ -0,0 +1,272 @@
|
||||
--:Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.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 peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.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 peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.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 peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.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 peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local disks = {}
|
||||
local internal = {}
|
||||
|
||||
local function norm(path)
|
||||
if not path or path == "" then return "/" end
|
||||
return fs.combine("/", path)
|
||||
end
|
||||
|
||||
local function createDisk(id, basePath, readonly, periph)
|
||||
basePath = norm(basePath)
|
||||
|
||||
local disk = {address = id, isReadOnly = function() return readonly end}
|
||||
|
||||
function disk:spaceUsed()
|
||||
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
|
||||
end
|
||||
|
||||
function disk:spaceTotal() return fs.getCapacity(basePath) end
|
||||
|
||||
function disk:list(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) or not fs.isDir(p) then
|
||||
return nil, "not directory"
|
||||
end
|
||||
return fs.list(p)
|
||||
end
|
||||
|
||||
function disk:fileExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and not fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:directoryExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:type(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) then
|
||||
return nil
|
||||
elseif fs.isDir(p) then
|
||||
return "directory"
|
||||
else
|
||||
return "file"
|
||||
end
|
||||
end
|
||||
|
||||
function disk:makeDirectory(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
fs.makeDir(p)
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:remove(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if fs.exists(p) then fs.delete(p) end
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:setLabel(label) periph.setLabel(label) end
|
||||
|
||||
function disk:getLabel(label) return periph.getLabel() end
|
||||
|
||||
function disk:attributes(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.attributes(p)
|
||||
end
|
||||
|
||||
function disk:open(path, mode)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.open(p, mode)
|
||||
end
|
||||
|
||||
return disk
|
||||
end
|
||||
|
||||
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
setLabel = function(label)
|
||||
local h = fs.open("/.label", "w")
|
||||
h.write(label)
|
||||
h.close()
|
||||
end,
|
||||
getLabel = function()
|
||||
local h = fs.open("/.label", "r")
|
||||
if not h then return "$" end
|
||||
local label = h.readAll()
|
||||
h.close()
|
||||
return label
|
||||
end
|
||||
})
|
||||
|
||||
internal["rom"] = createDisk("rom", "/rom", true, {
|
||||
setLabel = function(label)
|
||||
error("Device is read-only")
|
||||
end,
|
||||
getLabel = function()
|
||||
return "cctrom"
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
disks={}
|
||||
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||
if disk.isDiskPresent() then
|
||||
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function iter()
|
||||
refresh()
|
||||
local combined = {}
|
||||
|
||||
for id, obj in pairs(internal) do combined[id] = obj end
|
||||
for id, obj in pairs(disks) do combined[id] = obj end
|
||||
|
||||
return pairs(combined)
|
||||
end
|
||||
|
||||
return {refresh = refresh, list = iter}
|
||||
@@ -1,155 +0,0 @@
|
||||
-- :Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.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
|
||||
|
||||
function peripheral.getNames()
|
||||
local names = {}
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.isPresent(side) then table.insert(names, side) end
|
||||
if native.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
|
||||
|
||||
local disks = {}
|
||||
local internal = {}
|
||||
|
||||
local function norm(path)
|
||||
if not path or path == "" then return "/" end
|
||||
return fs.combine("/", path)
|
||||
end
|
||||
|
||||
local function createDisk(id, basePath, readonly, periph)
|
||||
basePath = norm(basePath)
|
||||
|
||||
local disk = {address = id, isReadOnly = function() return readonly end}
|
||||
|
||||
function disk:spaceUsed()
|
||||
return fs.getCapacity(basePath) - fs.getFreeSpace(basePath)
|
||||
end
|
||||
|
||||
function disk:spaceTotal() return fs.getCapacity(basePath) end
|
||||
|
||||
function disk:list(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) or not fs.isDir(p) then
|
||||
return nil, "not directory"
|
||||
end
|
||||
return fs.list(p)
|
||||
end
|
||||
|
||||
function disk:fileExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and not fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:directoryExists(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.exists(p) and fs.isDir(p)
|
||||
end
|
||||
|
||||
function disk:type(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if not fs.exists(p) then
|
||||
return nil
|
||||
elseif fs.isDir(p) then
|
||||
return "directory"
|
||||
else
|
||||
return "file"
|
||||
end
|
||||
end
|
||||
|
||||
function disk:makeDirectory(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
fs.makeDir(p)
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:remove(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
if fs.exists(p) then fs.delete(p) end
|
||||
return true
|
||||
end
|
||||
|
||||
function disk:setLabel(label) periph.setLabel(label) end
|
||||
|
||||
function disk:getLabel(label) return periph.getLabel() end
|
||||
|
||||
function disk:attributes(path)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.attributes(p)
|
||||
end
|
||||
|
||||
function disk:open(path, mode)
|
||||
local p = fs.combine(basePath, path)
|
||||
return fs.open(p, mode)
|
||||
end
|
||||
|
||||
return disk
|
||||
end
|
||||
|
||||
internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
setLabel = function(label)
|
||||
local h = fs.open("/.label", "w")
|
||||
h.write(label)
|
||||
h.close()
|
||||
end,
|
||||
getLabel = function()
|
||||
local h = fs.open("/.label", "r")
|
||||
if not h then return "$" end
|
||||
local label = h.readAll()
|
||||
h.close()
|
||||
return label
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
for id, _ in pairs(disks) do
|
||||
if not peripheral.getType(id) then disks[id] = nil end
|
||||
end
|
||||
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.getType(name) == "disk" then
|
||||
if not disks[name] then
|
||||
local mount = disk.getMountPath(name)
|
||||
if mount then
|
||||
disks[name] = createDisk(name, mount, false, disk)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function iter()
|
||||
refresh()
|
||||
local combined = {}
|
||||
|
||||
for id, obj in pairs(internal) do combined[id] = obj end
|
||||
for id, obj in pairs(disks) do combined[id] = obj end
|
||||
|
||||
return pairs(combined)
|
||||
end
|
||||
|
||||
return {refresh = refresh, list = iter}
|
||||
@@ -311,7 +311,7 @@ local fifo = kernel.newFifo()
|
||||
kernel.processes.cctmond = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.computer:getMachineEvent()}
|
||||
local event = {kernel.EFI:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
-- :Minify:--
|
||||
--:Minify:--
|
||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||
---@diagnostic disable-next-line: undefined-global
|
||||
local term = term
|
||||
@@ -152,17 +152,262 @@ local ok, err = xpcall(function()
|
||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||
if not fs then displaySuperBadError("Could not load initfs.") end
|
||||
|
||||
if not apis.fs.exists("/nvram.dat") then
|
||||
local file = apis.fs.open("/nvram.dat", "w")
|
||||
file.write("Hello, World!")
|
||||
file.close()
|
||||
end
|
||||
|
||||
local eeprom
|
||||
if apis.fs.exists("/startup.lua") then
|
||||
eeprom="/startup.lua"
|
||||
elseif apis.fs.exists("/eeprom") then
|
||||
eeprom="/eeprom"
|
||||
end
|
||||
|
||||
local eventQueue = {}
|
||||
|
||||
local function queueEvent(event, ...)
|
||||
table.insert(eventQueue, {event, ...})
|
||||
end
|
||||
|
||||
local computer = {
|
||||
time = function() return apis.os.epoch("utc") end,
|
||||
clock = function() return apis.os.clock() * 1000 end,
|
||||
shutdown = apis.os.shutdown,
|
||||
reboot = apis.os.reboot,
|
||||
local colors = {
|
||||
[0x000000]=0x0001,
|
||||
[0xFFFFFF]=0x0002,
|
||||
[0xFF0000]=0x0004,
|
||||
[0x00FF00]=0x0008,
|
||||
[0x0000FF]=0x0010,
|
||||
[0x00FFFF]=0x0020,
|
||||
[0xFF00FF]=0x0040,
|
||||
[0xFFFF00]=0x0080,
|
||||
[0xFF6D00]=0x0100,
|
||||
[0x6DFF55]=0x0200,
|
||||
[0x24FFFF]=0x0400,
|
||||
[0x924900]=0x0800,
|
||||
[0x6D6D55]=0x1000,
|
||||
[0xDBDBAA]=0x2000,
|
||||
[0x6D00FF]=0x4000,
|
||||
[0xB6FF00]=0x8000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
if k==target then return k end
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local peripheral={}
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.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 peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.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 peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.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 peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.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 peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local allscreens = {peripheral.find("monitor")}
|
||||
for i=1, #allscreens do
|
||||
allscreens[i].setTextScale(.5)
|
||||
allscreens[i].clear()
|
||||
allscreens[i].setCursorPos(1,1)
|
||||
allscreens[i].write("Initializing...")
|
||||
end
|
||||
|
||||
local EFI = {
|
||||
getEpochMs = function() return apis.os.epoch("utc") end,
|
||||
getUptime = function() return apis.os.clock() * 1000 end,
|
||||
date = function() return apis.os.date("!%Y-%m-%dT%H:%M:%SZ", apis.os.epoch("utc") / 1000) end,
|
||||
getMachineEvent = function()
|
||||
if #eventQueue > 0 then
|
||||
return table.unpack(table.remove(eventQueue, 1))
|
||||
@@ -170,61 +415,15 @@ local ok, err = xpcall(function()
|
||||
return nil
|
||||
end
|
||||
end,
|
||||
getEEPROM = function() return getFile("/startup.lua") end,
|
||||
getEEPROM = function() return getFile(eeprom) end,
|
||||
setEEPROM = function(_, text)
|
||||
local h = apis.fs.open("/startup.lua", "w")
|
||||
local h = apis.fs.open(eeprom, "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end
|
||||
}
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, apis, initFs, "cct", "/sbin/init",
|
||||
{
|
||||
end,
|
||||
initfs=fs,
|
||||
disks=initFs,
|
||||
screenCtl={
|
||||
print = function(_, text) write(text .. "\n") end,
|
||||
printInline = function(_, text) write(text) end,
|
||||
clear = function()
|
||||
@@ -237,25 +436,52 @@ local ok, err = xpcall(function()
|
||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||
getSize = function() return apis.term.getSize() end,
|
||||
setBackgroundColor = function(_, color)
|
||||
apis.term.setBackgroundColor(colors[color])
|
||||
apis.term.setBackgroundColor(aprox(color))
|
||||
end,
|
||||
setTextColor = function(_, color)
|
||||
apis.term.setTextColor(colors[color])
|
||||
apis.term.setTextColor(aprox(color))
|
||||
end,
|
||||
getBackgroundColor = function()
|
||||
return icolors[apis.term.getBackgroundColor()]
|
||||
return bg
|
||||
end,
|
||||
getTextColor = function()
|
||||
return icolors[apis.term.getTextColor()]
|
||||
end
|
||||
}, computer, fs, "$")
|
||||
if not ok then displaySuperBadError(err) end
|
||||
return fg
|
||||
end,
|
||||
enable=function() end,
|
||||
disable=function() end
|
||||
},
|
||||
architecture="cct",
|
||||
getNvram = function() return getFile("/nvram.dat") end,
|
||||
setNvram = function(_, text)
|
||||
local h = apis.fs.open("/nvram.dat", "w")
|
||||
h.write(text)
|
||||
h.close()
|
||||
end,
|
||||
firmware=apis,
|
||||
reboot=false,
|
||||
beep=function() end
|
||||
}
|
||||
|
||||
apis.term.setBackgroundColor(0x8000)
|
||||
apis.term.setTextColor(0x1000)
|
||||
apis.term.clear()
|
||||
apis.term.setCursorPos(1, 1)
|
||||
|
||||
local kernelCoro = coroutine.create(function()
|
||||
---@diagnostic disable-next-line: param-type-mismatch
|
||||
local ok, err = xpcall(Kernel, debug.traceback, EFI)
|
||||
if not ok and not EFI.reboot then displaySuperBadError(err) end
|
||||
if err then
|
||||
apis.os.reboot()
|
||||
else
|
||||
apis.os.shutdown()
|
||||
end
|
||||
end)
|
||||
|
||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||
local startTime = computer.time()
|
||||
local startTime = EFI.getEpochMs()
|
||||
debug.sethook(co, function()
|
||||
if computer.time() > startTime + timeout then
|
||||
if EFI.getEpochMs() > startTime + timeout then
|
||||
return coroutine.yield("timeout")
|
||||
end
|
||||
end, "", 1000)
|
||||
@@ -270,7 +496,7 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
|
||||
write("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
EFI.screenCtl:print("Loaded in " .. tostring(apis.os.clock()) .. " seconds.\n")
|
||||
|
||||
while true do
|
||||
local status, err = coroutine.resumeWithTimeout(kernelCoro, 50)
|
||||
@@ -304,11 +530,15 @@ local ok, err = xpcall(function()
|
||||
end
|
||||
end
|
||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||
if EFI.reboot then
|
||||
apis.os.reboot()
|
||||
end
|
||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||
coroutine.yield("key")
|
||||
end
|
||||
initFs:refresh()
|
||||
end
|
||||
end, debug.traceback)
|
||||
|
||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||
while true do coroutine.yield() end
|
||||
while true do coroutine.yield("key") end
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
-- :Minify:--
|
||||
--:Minify:--
|
||||
local apis = ({...})[1]
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH or "/$"
|
||||
local BOOT_DRIVE_PATH = apis.BOOT_DRIVE_PATH
|
||||
local fs = apis.fs
|
||||
local native = apis.peripheral
|
||||
local peripheral = {}
|
||||
@@ -241,11 +241,17 @@ internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
for id, _ in pairs(disks) do
|
||||
if not peripheral.getType(id) then disks[id] = nil end
|
||||
internal["rom"] = createDisk("rom", "/rom", true, {
|
||||
setLabel = function(label)
|
||||
error("Device is read-only")
|
||||
end,
|
||||
getLabel = function()
|
||||
return "cctrom"
|
||||
end
|
||||
})
|
||||
|
||||
local function refresh()
|
||||
disks={}
|
||||
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||
if disk.isDiskPresent() then
|
||||
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
|
||||
|
||||
152
Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod
Normal file
152
Src/Hyperion-firmware-cct/lib/modules/cc-tweaked/01_periph.kmod
Normal file
@@ -0,0 +1,152 @@
|
||||
--:Minify:--
|
||||
-- CCT driver peripheral helper
|
||||
local kernel=...
|
||||
kernel.cct={}
|
||||
kernel.cct.peripheral={}
|
||||
local peripheral=kernel.cct.peripheral
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
|
||||
function peripheral.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 peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.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 peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.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 peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.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 peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
@@ -1,192 +1,104 @@
|
||||
--:Minify:--
|
||||
|
||||
local kernel = ...
|
||||
local apis = kernel.apis
|
||||
local native = apis.peripheral
|
||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||
local peripheral={}
|
||||
|
||||
function peripheral.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 peripheral.isPresent(name)
|
||||
if native.isPresent(name) then
|
||||
return true
|
||||
end
|
||||
|
||||
for n = 1, #sides do
|
||||
local side = sides[n]
|
||||
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function peripheral.getType(peripheral)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.hasType(peripheral, peripheral_type)
|
||||
if type(peripheral) == "string" then
|
||||
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 peripheral.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 peripheral.getName(peripheral)
|
||||
local mt = getmetatable(peripheral)
|
||||
if not mt or mt.__name ~= "peripheral" or type(mt.name) ~= "string" then
|
||||
error("bad argument #1 (table is not a peripheral)", 2)
|
||||
end
|
||||
return mt.name
|
||||
end
|
||||
|
||||
function peripheral.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 peripheral.wrap(name)
|
||||
local methods = peripheral.getMethods(name)
|
||||
if not methods then
|
||||
return nil
|
||||
end
|
||||
|
||||
local types = { peripheral.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 peripheral.call(name, method, ...)
|
||||
end
|
||||
end
|
||||
return result
|
||||
end
|
||||
|
||||
function peripheral.find(ty, filter)
|
||||
local results = {}
|
||||
for _, name in ipairs(peripheral.getNames()) do
|
||||
if peripheral.hasType(name, ty) then
|
||||
local wrapped = peripheral.wrap(name)
|
||||
if filter == nil or filter(name, wrapped) then
|
||||
table.insert(results, wrapped)
|
||||
end
|
||||
end
|
||||
end
|
||||
return table.unpack(results)
|
||||
end
|
||||
|
||||
local icolors = {
|
||||
[0x1] = 1, -- #000000
|
||||
[0x2] = 2, -- #FFFFFF
|
||||
[0x4] = 3, -- #FF0000
|
||||
[0x8] = 4, -- #00FF00
|
||||
[0x10] = 5, -- #0000FF
|
||||
[0x20] = 6, -- #00FFFF
|
||||
[0x40] = 7, -- #FF00FF
|
||||
[0x80] = 8, -- #FFFF00
|
||||
[0x100] = 9, -- #FF6D00
|
||||
[0x200] = 10, -- #6DFF55
|
||||
[0x400] = 11, -- #24FFFF
|
||||
[0x800] = 12, -- #924900
|
||||
[0x1000] = 13, -- #6D6D55
|
||||
[0x2000] = 14, -- #DBDBAA
|
||||
[0x4000] = 15, -- #6D00FF
|
||||
[0x8000] = 16 -- #B6FF00
|
||||
}
|
||||
local peripheral=kernel.cct.peripheral
|
||||
|
||||
local colors = {
|
||||
0x0001, -- #000000
|
||||
0x0002, -- #FFFFFF
|
||||
0x0004, -- #FF0000
|
||||
0x0008, -- #00FF00
|
||||
0x0010, -- #0000FF
|
||||
0x0020, -- #00FFFF
|
||||
0x0040, -- #FF00FF
|
||||
0x0080, -- #FFFF00
|
||||
0x0100, -- #FF6D00
|
||||
0x0200, -- #6DFF55
|
||||
0x0400, -- #24FFFF
|
||||
0x0800, -- #924900
|
||||
0x1000, -- #6D6D55
|
||||
0x2000, -- #DBDBAA
|
||||
0x4000, -- #6D00FF
|
||||
0x8000 -- #B6FF00
|
||||
[0xFFFFFF]=0x0001,
|
||||
[0xFF0000]=0x0002,
|
||||
[0x00FF00]=0x0004,
|
||||
[0x0000FF]=0x0008,
|
||||
[0x00FFFF]=0x0010,
|
||||
[0xFF00FF]=0x0020,
|
||||
[0xFFFF00]=0x0040,
|
||||
[0xFF6D00]=0x0080,
|
||||
[0x6DFF55]=0x0100,
|
||||
[0x24FFFF]=0x0200,
|
||||
[0x924900]=0x0400,
|
||||
[0x6D6D55]=0x0800,
|
||||
[0xDBDBAA]=0x1000,
|
||||
[0x6D00FF]=0x2000,
|
||||
[0xB6FF00]=0x4000,
|
||||
[0x000000]=0x8000
|
||||
}
|
||||
|
||||
local plt = {
|
||||
0xFFFFFF,
|
||||
0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0x00FFFF,
|
||||
0xFF00FF,
|
||||
0xFFFF00,
|
||||
0xFF6D00,
|
||||
0x6DFF55,
|
||||
0x24FFFF,
|
||||
0x924900,
|
||||
0x6D6D55,
|
||||
0xDBDBAA,
|
||||
0x6D00FF,
|
||||
0xB6FF00,
|
||||
0x000000
|
||||
}
|
||||
|
||||
local fg,bg=0x6D6D55,0x000000
|
||||
local l1f,l1d,l2,ops={},{},{},0
|
||||
|
||||
local function findClosest(tbl, target)
|
||||
local closest = nil
|
||||
local smallestDiff = math.huge
|
||||
|
||||
for k, _ in pairs(tbl) do
|
||||
if k==target then return k end
|
||||
local diff = math.abs(k - target)
|
||||
if diff < smallestDiff then
|
||||
smallestDiff = diff
|
||||
closest = k
|
||||
end
|
||||
end
|
||||
|
||||
return closest
|
||||
end
|
||||
|
||||
local function aprox(c24)
|
||||
ops = ops + 1
|
||||
|
||||
if ops % 1024 == 0 then
|
||||
l1d = {}
|
||||
l1f = {}
|
||||
end
|
||||
|
||||
if ops % 8192 == 0 then
|
||||
l2 = {}
|
||||
end
|
||||
|
||||
if l2[c24] ~= nil then
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
if l1d[c24] ~= nil then
|
||||
l1f[c24] = l1f[c24] + 1
|
||||
|
||||
if l1f[c24] >= 16 then
|
||||
l2[c24] = l1d[c24]
|
||||
l1d[c24] = nil
|
||||
l1f[c24] = nil
|
||||
return l2[c24]
|
||||
end
|
||||
|
||||
return l1d[c24]
|
||||
end
|
||||
|
||||
local closestKey = findClosest(colors, c24)
|
||||
if not closestKey then return nil end
|
||||
|
||||
local value = colors[closestKey]
|
||||
|
||||
l1d[c24] = value
|
||||
l1f[c24] = 1
|
||||
|
||||
return value
|
||||
end
|
||||
|
||||
local function write(text, term)
|
||||
local x, y = term.getCursorPos()
|
||||
local w, h = term.getSize()
|
||||
@@ -233,7 +145,7 @@ local function write(text, term)
|
||||
end
|
||||
|
||||
kernel.devfs.data.tty={}
|
||||
local ctrl,alt = false, false
|
||||
kernel.cct.ctrl,kernel.cct.alt = false, false
|
||||
|
||||
local function serializeBool(bool)
|
||||
if bool then
|
||||
@@ -244,25 +156,25 @@ local function serializeBool(bool)
|
||||
end
|
||||
|
||||
local function newtty(obj, id, ev)
|
||||
obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
obj.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
obj.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
obj.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
obj.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
obj.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
obj.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
obj.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
obj.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
obj.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
obj.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||
obj.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||
obj.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||
obj.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||
obj.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||
obj.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||
obj.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||
obj.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||
obj.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||
obj.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||
obj.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||
obj.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||
obj.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||
obj.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||
obj.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||
obj.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
return "Terminal"
|
||||
elseif op=="open" then
|
||||
local h = {
|
||||
read=function(amount)
|
||||
@@ -295,19 +207,24 @@ local function newtty(obj, id, ev)
|
||||
return obj.setCursorPos(x,y)
|
||||
end,
|
||||
sfgc=function(c)
|
||||
return obj.setTextColor(colors[c])
|
||||
fg=c
|
||||
return obj.setTextColor(aprox(c))
|
||||
end,
|
||||
sbgc=function(c)
|
||||
return obj.setBackgroundColor(colors[c])
|
||||
bg=c
|
||||
return obj.setBackgroundColor(aprox(c))
|
||||
end,
|
||||
gfgc=function()
|
||||
return icolors[obj.getTextColor()]
|
||||
return fg
|
||||
end,
|
||||
gbgc=function()
|
||||
return icolors[obj.getBackgroundColor()]
|
||||
return bg
|
||||
end,
|
||||
gctrl=function()
|
||||
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||
end,
|
||||
gplt=function()
|
||||
return plt
|
||||
end
|
||||
}
|
||||
if mode=="rw" then
|
||||
@@ -324,85 +241,9 @@ local function newtty(obj, id, ev)
|
||||
end
|
||||
|
||||
local fifo = kernel.newFifo()
|
||||
kernel.cct.fifo=fifo
|
||||
|
||||
kernel.processes.cctmond = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.computer:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
local ctrlKeyMap = {
|
||||
[apis.keys.a]=1, [apis.keys.b]=2, [apis.keys.c]=3,
|
||||
[apis.keys.d]=4, [apis.keys.e]=5, [apis.keys.f]=6,
|
||||
[apis.keys.g]=7, [apis.keys.h]=8, [apis.keys.i]=9,
|
||||
[apis.keys.j]=10, [apis.keys.k]=11, [apis.keys.l]=12,
|
||||
[apis.keys.m]=13, [apis.keys.n]=14, [apis.keys.o]=15,
|
||||
[apis.keys.p]=16, [apis.keys.q]=17, [apis.keys.r]=18,
|
||||
[apis.keys.s]=19, [apis.keys.t]=20, [apis.keys.u]=21,
|
||||
[apis.keys.v]=22, [apis.keys.w]=23, [apis.keys.x]=24,
|
||||
[apis.keys.y]=25, [apis.keys.z]=26,
|
||||
}
|
||||
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = true
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = true
|
||||
end
|
||||
|
||||
if ctrl then
|
||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||
if ctrlByte then
|
||||
if ctrlByte == 3 then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1)
|
||||
end
|
||||
else
|
||||
fifo.push(string.char(ctrlByte))
|
||||
end
|
||||
end
|
||||
else
|
||||
local specialKeyMap = {
|
||||
[apis.keys.up] = "[A",
|
||||
[apis.keys.down] = "[B",
|
||||
[apis.keys.right] = "[C",
|
||||
[apis.keys.left] = "[D",
|
||||
[apis.keys.home] = "[H",
|
||||
[apis.keys["end"]] = "[F",
|
||||
[apis.keys.pageUp] = "[5~",
|
||||
[apis.keys.pageDown] = "[6~",
|
||||
[apis.keys.delete] = "[3~",
|
||||
}
|
||||
local special = specialKeyMap[charOrKey]
|
||||
if special then fifo.push(special) end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||
ctrl = false
|
||||
elseif charOrKey == apis.keys.leftAlt or charOrKey == apis.keys.rightAlt then
|
||||
alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then fifo.push(charOrKey) end
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newtty(apis.term, "1", fifo.pop)
|
||||
newtty(kernel.apis.term, "1", fifo.pop)
|
||||
|
||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||
v.setTextScale(.5)
|
||||
|
||||
@@ -0,0 +1,86 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local keys=kernel.apis.keys
|
||||
|
||||
kernel.processes.cctdeamon = function()
|
||||
local timeout = false
|
||||
while true do
|
||||
local event = {kernel.EFI:getMachineEvent()}
|
||||
|
||||
if event[1] then
|
||||
local eventType = event[1]
|
||||
local charOrKey = event[3]
|
||||
|
||||
local ctrlKeyMap = {
|
||||
[keys.a]=1, [keys.b]=2, [keys.c]=3,
|
||||
[keys.d]=4, [keys.e]=5, [keys.f]=6,
|
||||
[keys.g]=7, [keys.h]=8, [keys.i]=9,
|
||||
[keys.j]=10, [keys.k]=11, [keys.l]=12,
|
||||
[keys.m]=13, [keys.n]=14, [keys.o]=15,
|
||||
[keys.p]=16, [keys.q]=17, [keys.r]=18,
|
||||
[keys.s]=19, [keys.t]=20, [keys.u]=21,
|
||||
[keys.v]=22, [keys.w]=23, [keys.x]=24,
|
||||
[keys.y]=25, [keys.z]=26,
|
||||
}
|
||||
|
||||
if eventType == "keyPressed" then
|
||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||
kernel.cct.ctrl = true
|
||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||
kernel.cct.alt = true
|
||||
end
|
||||
|
||||
if kernel.cct.ctrl then
|
||||
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||
if ctrlByte then
|
||||
if ctrlByte == 3 then
|
||||
for _, task in ipairs(syscall.getTasks()) do
|
||||
syscall.sigsend(task, 1)
|
||||
end
|
||||
else
|
||||
kernel.cct.fifo.push(string.char(ctrlByte))
|
||||
end
|
||||
end
|
||||
else
|
||||
local specialKeyMap = {
|
||||
[keys.up] = "[A",
|
||||
[keys.down] = "[B",
|
||||
[keys.right] = "[C",
|
||||
[keys.left] = "[D",
|
||||
[keys.home] = "[H",
|
||||
[keys["end"]] = "[F",
|
||||
[keys.pageUp] = "[5~",
|
||||
[keys.pageDown] = "[6~",
|
||||
[keys.delete] = "[3~",
|
||||
}
|
||||
local special = specialKeyMap[charOrKey]
|
||||
if special then kernel.cct.fifo.push(special) end
|
||||
end
|
||||
|
||||
elseif eventType == "keyReleased" then
|
||||
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||
kernel.cct.ctrl = false
|
||||
elseif charOrKey == keys.leftAlt or charOrKey == keys.rightAlt then
|
||||
kernel.cct.alt = false
|
||||
end
|
||||
|
||||
elseif eventType == "keyTyped" then
|
||||
if charOrKey then kernel.cct.fifo.push(charOrKey) end
|
||||
elseif eventType == "http_success" then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httpresponse[event[2]]=event[3]
|
||||
elseif eventType == "http_failure" then
|
||||
kernel.cct.httpqueue[event[2]]=nil
|
||||
kernel.cct.httperror[event[2]]=event[3]
|
||||
end
|
||||
|
||||
timeout = false
|
||||
else
|
||||
timeout = true
|
||||
end
|
||||
|
||||
if timeout then
|
||||
sleep(0.05)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,26 +0,0 @@
|
||||
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)
|
||||
@@ -0,0 +1,25 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local rs=kernel.apis.rs
|
||||
local sides = {top=1, bottom=2, left=3, right=4, front=5, back=6}
|
||||
local function newGPIO(side)
|
||||
return function(mode, data)
|
||||
if mode=="w" then
|
||||
if type(data)~="boolean" then error("data: expected bool") end
|
||||
rs.setOutput(side, data)
|
||||
elseif mode=="wa" then
|
||||
if type(data)~="number" then error("data: expected bool") end
|
||||
rs.setAnalogOutput(side, data)
|
||||
elseif mode=="r" then
|
||||
return rs.getInput(side)
|
||||
elseif mode=="ra" then
|
||||
return rs.getAnalogInput(side)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
for side, alt in pairs(sides) do
|
||||
local func=newGPIO(side)
|
||||
kernel.gpio[side]=func
|
||||
kernel.gpio[alt]=func
|
||||
end
|
||||
@@ -1,14 +1,13 @@
|
||||
--:Minify:--
|
||||
local args = {...}
|
||||
local apis = args[1]
|
||||
local disks = args[2]
|
||||
local arch = args[3]
|
||||
local screen = args[5]
|
||||
local computer = args[6]
|
||||
local ifs = args[7]
|
||||
local EFI=...
|
||||
EFI.beep(440, 500)
|
||||
local screen=EFI.screenCtl
|
||||
local ifs=EFI.initfs
|
||||
local disks=EFI.disks
|
||||
local arch=EFI.architecture
|
||||
local kernel = {}
|
||||
kernel.LOG_Text=""
|
||||
kernel.version="HyperionOS V1.2.3"
|
||||
kernel.version="HyperionOS V1.2.4"
|
||||
kernel.process = "Kernel"
|
||||
kernel.users={[0]="root",[1]="User"}
|
||||
kernel.hostname = "hyperion"
|
||||
@@ -26,28 +25,31 @@ _G.sleep=nil
|
||||
local windowsExp = false
|
||||
|
||||
function kernel.log(msg, level, c)
|
||||
c=c or 12
|
||||
kernel.LOG_Text = kernel.LOG_Text..string.format("%X",c-1).." "..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||
c=c or 0x6D6D6D
|
||||
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||
if kernel.status == "start" then
|
||||
screen:setTextColor(c)
|
||||
screen:print(tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||
elseif kernel.status == "term" then
|
||||
kernel.standbyTask=kernel.currentTask
|
||||
kernel.currentTask=kernel.kernelTask
|
||||
kernel.vfs.devctl(1,"sfgc",c)
|
||||
kernel.vfs.write(1,tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||
local file=kernel.vfs.open("/dev/console", "w")
|
||||
kernel.vfs.devctl(file,"sfgc",c)
|
||||
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||
kernel.vfs.close(file)
|
||||
kernel.currentTask=kernel.standbyTask
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.PANIC(msg)
|
||||
if kernel.status~="Panic" then
|
||||
kernel.log("PANIC: "..msg, "PANIC")
|
||||
kernel.log("PANIC: "..msg, "PANIC", 0xFF0000)
|
||||
pcall(kernel["saveLog"])
|
||||
kernel.status="Panic"
|
||||
kernel.reason=msg
|
||||
screen:setTextColor(2)
|
||||
screen:setBackgroundColor(16)
|
||||
screen:enable()
|
||||
screen:setTextColor(0xFF0000)
|
||||
screen:setBackgroundColor(0x000000)
|
||||
screen:clear()
|
||||
screen:setCursorPos(1,1)
|
||||
screen:print(kernel.LOG_Text)
|
||||
@@ -56,18 +58,19 @@ function kernel.PANIC(msg)
|
||||
kernel.exitMain = true
|
||||
end
|
||||
while true do
|
||||
local event={computer:getMachineEvent()}
|
||||
local event={EFI:getMachineEvent()}
|
||||
if event[1]=="keyPressed" then
|
||||
break
|
||||
end
|
||||
end
|
||||
computer:reboot()
|
||||
EFI.reboot=true
|
||||
error("KERNEL PANIC")
|
||||
end
|
||||
kernel.panic=kernel.PANIC
|
||||
|
||||
if windowsExp then
|
||||
screen:setTextColor(1)
|
||||
screen:setBackgroundColor(4)
|
||||
screen:setTextColor(0xFFFFFF)
|
||||
screen:setBackgroundColor(0x0000FF)
|
||||
screen:clear()
|
||||
local w,h = screen:getSize()
|
||||
screen:setCursorPos(3,5)
|
||||
@@ -113,7 +116,7 @@ local split = function(str, delim, maxResultCountOrNil)
|
||||
end
|
||||
|
||||
if not ifs.isFile("/boot/boot.cfg") then
|
||||
kernel.log("First boot detected writing boot.cfg", "INFO", 3)
|
||||
kernel.log("First boot detected writing boot.cfg", "INFO", 0x00FF00)
|
||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||
kernel.firstBoot=true
|
||||
end
|
||||
@@ -130,24 +133,34 @@ if not initCfgStatus then
|
||||
end
|
||||
kernel.config = config
|
||||
|
||||
local skip=false
|
||||
for i,v in ipairs(split(fstab,"\n")) do
|
||||
if v:sub(1,1)=="U" then
|
||||
local id=""
|
||||
for i=3,#v do
|
||||
if v:sub(i,i)==";" then
|
||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN") goto endline end
|
||||
if i==3 then kernel.log("Invalid fstab line... Skipping.","WARN", 0xFF8800) skip = true break end
|
||||
id=v:sub(3,i-1)
|
||||
end
|
||||
end
|
||||
local path=v:sub(#id+4)
|
||||
ifs.mount(id,path)
|
||||
::endline::
|
||||
if not skip then
|
||||
local path=v:sub(#id+4)
|
||||
ifs.mount(id,path)
|
||||
else
|
||||
skip=false
|
||||
end
|
||||
end
|
||||
end
|
||||
kernel.log("Disks initialized")
|
||||
|
||||
function kernel.saveLog()
|
||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||
if kernel.status=="running" then
|
||||
local file = kernel.vfs.open("/var/log/syslog.log", "w")
|
||||
kernel.vfs.write(file, kernel.LOG_Text)
|
||||
kernel.vfs.close(file)
|
||||
else
|
||||
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||
end
|
||||
end
|
||||
|
||||
function kernel.newFifo()
|
||||
@@ -187,7 +200,7 @@ kernel.log("Gathering modules")
|
||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
local modlist = ifs.list("/lib/modules/"..i)
|
||||
if not modlist then
|
||||
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 8)
|
||||
kernel.log("WARNING: could not list /lib/modules/"..i.." (skipping)", "WARN", 0xFF8800)
|
||||
else
|
||||
for _,v in ipairs(modlist) do
|
||||
local prior=tonumber(v:sub(1,2))
|
||||
@@ -199,8 +212,8 @@ for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||
end
|
||||
|
||||
kernel.ifs=ifs
|
||||
kernel.apis=apis
|
||||
kernel.computer=computer
|
||||
kernel.apis=EFI.firmware
|
||||
kernel.EFI=EFI
|
||||
kernel.arch=arch
|
||||
kernel.initdisks=disks
|
||||
kernel.screen=screen
|
||||
@@ -229,16 +242,19 @@ kernel.kernelTask = {
|
||||
kernel.currentTask = kernel.kernelTask
|
||||
|
||||
function kernel.shutdown()
|
||||
kernel.computer:shutdown()
|
||||
kernel.exitMain=true
|
||||
kernel.status="shutdown"
|
||||
end
|
||||
|
||||
function kernel.reboot()
|
||||
kernel.computer:reboot()
|
||||
kernel.exitMain=true
|
||||
kernel.status="reboot"
|
||||
end
|
||||
|
||||
kernel.syscalls["time"]=function() return kernel.computer:time() end
|
||||
kernel.syscalls["time"]=function() return kernel.EFI:getEpochMs() end
|
||||
kernel.syscalls["date"]=function() return kernel.EFI:date() end
|
||||
kernel.syscalls["log"]=kernel.log
|
||||
kernel.syscalls["getUptime"]=function() return kernel.computer:clock() end
|
||||
kernel.syscalls["getUptime"]=function() return kernel.EFI:getUptime() end
|
||||
kernel.syscalls["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||
@@ -252,36 +268,34 @@ kernel.syscalls["sysdump"]=function()
|
||||
end
|
||||
return rv
|
||||
end
|
||||
kernel.syscalls["reboot"]=function()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
kernel.syscalls["shutdown"]=function()
|
||||
kernel.computer:reboot()
|
||||
end
|
||||
kernel.syscalls["reboot"]=kernel.reboot
|
||||
kernel.syscalls["shutdown"]=kernel.shutdown
|
||||
|
||||
kernel.log("Running modules")
|
||||
for _,p in ipairs(modules) do
|
||||
for _,v in ipairs(p) do
|
||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 5) end
|
||||
if kernel.config.showModLoad then kernel.log("Loading module "..v, "DBUG", 0x00FFFF) end
|
||||
local code=ifs.readAllText(v)
|
||||
if not code then
|
||||
kernel.log("ModuReadErr: "..v, "WARN", 8)
|
||||
goto skip
|
||||
kernel.panic("Failed to read module "..v)
|
||||
end
|
||||
local func,err=load(code,"@"..v)
|
||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) goto skip end
|
||||
if not func then kernel.panic("ModuLoadErr: "..tostring(err)) end
|
||||
local status, err = xpcall(func,debug.traceback, kernel)
|
||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 5) end
|
||||
::skip::
|
||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Kernel initialized successfully.")
|
||||
kernel.saveLog()
|
||||
kernel.status="running"
|
||||
screen:disable()
|
||||
kernel.main()
|
||||
if kernel.status=="panic" then
|
||||
kernel.panic()
|
||||
kernel.panic(kernel.reason)
|
||||
end
|
||||
kernel.PANIC("Execution complete")
|
||||
if kernel.status=="reboot" then
|
||||
EFI.reboot=true
|
||||
return true
|
||||
end
|
||||
@@ -7,5 +7,6 @@ return {
|
||||
initPath = "/sbin/init",
|
||||
maxOpenFiles = 128,
|
||||
maxFilesPerTask = 16,
|
||||
preempt=true
|
||||
preempt=true,
|
||||
logTaskExit=true
|
||||
}
|
||||
@@ -499,7 +499,7 @@ local function checkperms(meta, mode)
|
||||
local bitmap = {
|
||||
r = {owner = 5, group = 3, everyone = 1},
|
||||
w = {owner = 4, group = 2, everyone = 0},
|
||||
a = {owner = 4, group = 2, everyone = 0},
|
||||
a = {owner = 4, group = 2, everyone = 0}
|
||||
}
|
||||
local m = bitmap[mode]
|
||||
if not m then error("EINVAL") end
|
||||
@@ -544,7 +544,6 @@ local function newFileObj(handle, mode, path, meta, ftype)
|
||||
end
|
||||
|
||||
function vfs.newfd(fdobj)
|
||||
checkSystemLimit(); total = total + 1
|
||||
local fd = allocFD(kernel.currentTask)
|
||||
kernel.currentTask.fd[fd] = fdobj
|
||||
return fd
|
||||
@@ -555,8 +554,9 @@ function vfs.mount(target, diskOrId)
|
||||
if _euid ~= 0 then error("EPERM") end
|
||||
if not target then error("EINVAL") end
|
||||
target = normalizeMountPoint(target)
|
||||
if not vfs.exists(target) then vfs.mkdir(target) end
|
||||
if vfs.type(target) ~= "directory" then error("EINVAL") end
|
||||
local drive, path = resolvePath(target)
|
||||
if not drive:directoryExists(path) then drive:makeDirectory(path) end
|
||||
if drive:type(target) ~= "directory" then error("EINVAL") end
|
||||
|
||||
local disk, id
|
||||
if type(diskOrId) == "string" then
|
||||
@@ -594,6 +594,21 @@ function vfs.open(path, mode)
|
||||
local fd = allocFD(task)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if not disk then error("NODISK") end
|
||||
if (mode=="w" or mode=="a") and disk:isReadOnly() then error("ERDONLY") end
|
||||
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
local meta = kernel.unixSockets[normalizePath(path)].meta
|
||||
if kernel.uid~=0 or kernel.uid~=meta.owner then
|
||||
local groups = (task and task.groups) or kernel.groups or {}
|
||||
local access=false
|
||||
for _, gid in ipairs(groups) do
|
||||
if gid == meta.group then access=true end
|
||||
end
|
||||
if not access then error("EACCES") end
|
||||
end
|
||||
task[fd]=kernel.unixSockets[normalizePath(path)]
|
||||
return fd
|
||||
end
|
||||
|
||||
local meta = getFileMeta(path)
|
||||
local isNew = (mode == "w" or mode == "a") and not disk:fileExists(diskPath)
|
||||
@@ -695,10 +710,18 @@ function vfs.sendfile(outfd, infd, count)
|
||||
end
|
||||
|
||||
function vfs.stat(path)
|
||||
local disk, diskPath = resolvePath(path)
|
||||
local meta = getFileMeta(path)
|
||||
local ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||
local attrs
|
||||
local meta
|
||||
if meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(path)
|
||||
meta = getFileMeta(path)
|
||||
local ok
|
||||
ok, attrs = pcall(disk.attributes, disk, diskPath)
|
||||
if not ok then attrs = { size=0, modified=0, created=0 } end
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -713,15 +736,15 @@ end
|
||||
|
||||
function vfs.lstat(path)
|
||||
local meta = getFileMeta(path, true)
|
||||
|
||||
local attrs
|
||||
if meta.etype == 0x01 then
|
||||
if meta.etype == 0x01 or meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(path, true)
|
||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -738,8 +761,15 @@ end
|
||||
function vfs.fstat(fd)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
local disk, diskPath = resolvePath(file.path)
|
||||
local attrs = disk:attributes(diskPath)
|
||||
local attrs
|
||||
if file.meta.etype == 0x02 then
|
||||
attrs = { size=0, modified=0, created=0 }
|
||||
else
|
||||
local disk, diskPath = resolvePath(file.path, true)
|
||||
local ok, a = pcall(disk.attributes, disk, diskPath)
|
||||
attrs = ok and a or { size=0, modified=0, created=0 }
|
||||
end
|
||||
|
||||
return {
|
||||
size = attrs.size,
|
||||
modified = attrs.modified,
|
||||
@@ -768,6 +798,14 @@ function vfs.listdir(path)
|
||||
end
|
||||
end
|
||||
|
||||
for k,v in pairs(kernel.unixSockets) do
|
||||
local p=normalizePath(path)
|
||||
if k:match("^(.*)/[^/]+$")==p then
|
||||
seen[v.name]=true
|
||||
table.insert(out, v.name)
|
||||
end
|
||||
end
|
||||
|
||||
local mp
|
||||
if diskPath == "/" then
|
||||
mp = ".meta"
|
||||
@@ -796,6 +834,7 @@ function vfs.mkdir(path)
|
||||
local parentMeta = getFileMeta(parent)
|
||||
checkperms(parentMeta, "w")
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
disk:makeDirectory(diskPath)
|
||||
local task = kernel.currentTask
|
||||
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||
@@ -817,8 +856,13 @@ function vfs.remove(path)
|
||||
|
||||
local meta = getFileMeta(path, true)
|
||||
|
||||
if kernel.unixSockets and kernel.unixSockets[path] then
|
||||
kernel.unixSockets[path] = nil
|
||||
if kernel.unixSockets and kernel.unixSockets[normalizePath(path)] then
|
||||
if kernel.uid ~= 0 then
|
||||
if kernel.unixSockets[normalizePath(path)].meta.owner~=kernel.uid then
|
||||
error("EACCES")
|
||||
end
|
||||
end
|
||||
kernel.unixSockets[normalizePath(path)] = nil
|
||||
end
|
||||
|
||||
if meta.etype == 0x01 then
|
||||
@@ -827,6 +871,7 @@ function vfs.remove(path)
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
local disk, parentDiskPath = resolveMount(parent)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local mp
|
||||
if parentDiskPath == "/" then mp = ".meta"
|
||||
else mp = parentDiskPath:gsub("^/+", "") .. "/.meta" end
|
||||
@@ -843,6 +888,7 @@ function vfs.remove(path)
|
||||
if f2.close then f2.close() end
|
||||
else
|
||||
local disk, diskPath = resolvePath(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
disk:remove(diskPath)
|
||||
end
|
||||
end
|
||||
@@ -851,6 +897,8 @@ function vfs.symlink(target, linkPath)
|
||||
if type(target) ~= "string" or type(linkPath) ~= "string" then error("EINVAL") end
|
||||
local norm = normalizePath(linkPath)
|
||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||
local disk = resolveMount(linkPath)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
if not name then error("EINVAL") end
|
||||
@@ -880,7 +928,13 @@ function vfs.readlink(path)
|
||||
end
|
||||
|
||||
function vfs.access(path, mode)
|
||||
local meta = getFileMeta(path)
|
||||
local meta
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
meta = kernel.unixSockets[normalizePath(path)].meta
|
||||
else
|
||||
meta = getFileMeta(path)
|
||||
end
|
||||
|
||||
for i = 1, #mode do
|
||||
checkperms(meta, mode:sub(i,i))
|
||||
end
|
||||
@@ -891,6 +945,8 @@ local function updateMeta(path, fn, noFollow)
|
||||
local real = namei(path, noFollow)
|
||||
local norm = real
|
||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
if parent == "" then parent = "/" end
|
||||
local name = norm:match("[^/]+$")
|
||||
if not name then error("EINVAL") end
|
||||
@@ -917,6 +973,9 @@ local function updateMeta(path, fn, noFollow)
|
||||
end
|
||||
|
||||
function vfs.chmod(path, perms)
|
||||
if kernel.unixSockets[normalizePath(path)] then error("EINVAL") end
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local meta = getFileMeta(path)
|
||||
local euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||
if euid ~= 0 and euid ~= meta.owner then error("EACCES") end
|
||||
@@ -926,10 +985,14 @@ end
|
||||
function vfs.fchmod(fd, perms)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.etype==0x02 then error("EINVAL") end
|
||||
vfs.chmod(file.path, perms)
|
||||
end
|
||||
|
||||
function vfs.chown(path, uid, gid)
|
||||
if kernel.unixSockets[normalizePath(path)] then error("EINVAL") end
|
||||
local disk = resolveMount(path)
|
||||
if disk:isReadOnly() then error("ERDONLY") end
|
||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||
if _euid ~= 0 then error("EPERM") end
|
||||
updateMeta(path, function(e) e.owner = uid; e.group = gid end)
|
||||
@@ -938,20 +1001,29 @@ end
|
||||
function vfs.fchown(fd, uid, gid)
|
||||
local file = kernel.currentTask.fd[fd]
|
||||
if not file then error("EBADF") end
|
||||
if file.etype==0x02 then error("EINVAL") end
|
||||
vfs.chown(file.path, uid, gid)
|
||||
end
|
||||
|
||||
function vfs.exists(path)
|
||||
if kernel.unixSockets[normalizePath(path)] then return true end
|
||||
local meta = getFileMeta(path, true)
|
||||
if meta.etype == 0x01 then return true end
|
||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||
if not ok then return false end
|
||||
return disk:fileExists(diskPath)
|
||||
if disk:type(diskPath) then
|
||||
return true
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
function vfs.type(path)
|
||||
local meta = getFileMeta(path, true)
|
||||
if meta.etype == 0x01 then return "symlink" end
|
||||
if kernel.unixSockets[normalizePath(path)] then
|
||||
return "socket"
|
||||
end
|
||||
local ok, disk, diskPath = pcall(resolvePath, path)
|
||||
if not ok then return nil end
|
||||
return disk:type(diskPath)
|
||||
|
||||
@@ -50,7 +50,7 @@ function proxy:type(path, mode)
|
||||
if type(step[steps[#steps]]) == "table" then
|
||||
return "directory"
|
||||
end
|
||||
error("ENOENT")
|
||||
error(type(step[steps[#steps]]))
|
||||
end
|
||||
|
||||
function proxy:list(path)
|
||||
@@ -140,6 +140,82 @@ function data.zero(op, mode)
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI:getEEPROM() then
|
||||
function data.eeprom(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
local ptr,eeprom=1,kernel.EFI:getEEPROM()
|
||||
return {
|
||||
read=function(amount)
|
||||
ptr=ptr+amount
|
||||
return eeprom:sub(ptr-amount, ptr)
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
if firstwrite then
|
||||
kernel.EFI:setEEPROM(data)
|
||||
else
|
||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||
end
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setEEPROM(kernel.EFI:getEEPROM()..data)
|
||||
end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.EFI:getNvram() then
|
||||
function data.nvram(op, mode)
|
||||
if op=="type" then
|
||||
return "character device"
|
||||
elseif op=="open" then
|
||||
if mode=="r" then
|
||||
local ptr,nvram=1,kernel.EFI:getNvram()
|
||||
return {
|
||||
read=function(amount)
|
||||
ptr=ptr+amount
|
||||
return nvram:sub(ptr-amount, ptr)
|
||||
end
|
||||
}
|
||||
elseif mode=="w" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
local firstwrite=true
|
||||
return {
|
||||
write=function(data)
|
||||
if firstwrite then
|
||||
kernel.EFI:setNvram(data)
|
||||
else
|
||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||
end
|
||||
end
|
||||
}
|
||||
elseif mode=="a" then
|
||||
if kernel.uid~=0 then error("EACCES") end
|
||||
return {
|
||||
write=function(data)
|
||||
kernel.EFI:setNvram(kernel.EFI:getNvram()..data)
|
||||
end
|
||||
}
|
||||
else error("EACCES")
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
data["disk"]={}
|
||||
kernel.devfs={}
|
||||
kernel.devfs.data=data
|
||||
|
||||
@@ -6,7 +6,7 @@ local data = {}
|
||||
|
||||
proxy.address = "procfs0000"
|
||||
proxy.isvirt = true
|
||||
proxy.isReadOnly = function() return false end
|
||||
proxy.isReadOnly = function() return true end
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("EACCES") end
|
||||
@@ -258,7 +258,7 @@ function proxy:fileExists(path)
|
||||
return ok
|
||||
end
|
||||
|
||||
data.uptime=simpleFile(function()return tostring(kernel.computer:getUptime())end,function()error("EACCES")end)
|
||||
data.uptime=simpleFile(function()return tostring(kernel.EFI:getUptime())end,function()error("EACCES")end)
|
||||
kernel.procfs={}
|
||||
kernel.procfs.data=data
|
||||
kernel.procfs.proxy=proxy
|
||||
|
||||
@@ -21,7 +21,7 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
||||
end
|
||||
|
||||
if not semicolon_pos or semicolon_pos == 3 then
|
||||
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 8)
|
||||
kernel.log("Invalid fstab line: "..line.." ... Skipping.", "WARN", 0xFF8800)
|
||||
else
|
||||
local id = line:sub(3, semicolon_pos - 1)
|
||||
local path = trim(line:sub(semicolon_pos + 1))
|
||||
|
||||
@@ -12,13 +12,24 @@ function signal.sigsend(pid, sig)
|
||||
end
|
||||
|
||||
function signal.sigcatch(handler)
|
||||
kernel.currentTask.sigh=handler
|
||||
if not kernel.currentTask.sigq then kernel.currentTask.sigq={} end
|
||||
local task=kernel.currentTask
|
||||
task.sigh=handler
|
||||
if not task.sigq then task.sigq={} end
|
||||
local handle={
|
||||
error="",
|
||||
active=true
|
||||
}
|
||||
if task.sigd then task.sigd.active=false; end
|
||||
task.sigd=handle
|
||||
return handle
|
||||
end
|
||||
|
||||
function signal.sigignore()
|
||||
kernel.currentTask.sigh=nil
|
||||
kernel.currentTask.sigq=nil
|
||||
local task=kernel.currentTask
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
if task.sigd then task.sigd.active=false end
|
||||
task.sigd=nil
|
||||
end
|
||||
|
||||
local s=kernel.syscalls
|
||||
|
||||
@@ -2,10 +2,7 @@
|
||||
-- Supports:
|
||||
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
||||
-- AF_INET - network sockets with three backends:
|
||||
-- rednet://0.0.B.C or rednet+PROTO://0.0.B.C -> CC rednet (computer B*256+C)
|
||||
-- modem://0.0.B.C -> raw CC modem frames
|
||||
-- http://host/path or https://... -> HTTP via CC http API
|
||||
-- A.B.C.D (dotted quad, non-zero A) -> HTTP
|
||||
-- Implemented by drivers but expect http:// and https://
|
||||
--
|
||||
-- Socket lifecycle:
|
||||
-- fd = syscall.socket(domain, socktype) -- "unix"/"inet", "stream"/"dgram"
|
||||
@@ -18,539 +15,44 @@
|
||||
-- syscall.sockshutdown(fd) -- half-close send side
|
||||
-- -- normal vfs.close(fd) closes the socket
|
||||
|
||||
local kernel = ...
|
||||
local kernel=...
|
||||
local socket={}
|
||||
socket.handlers={}
|
||||
kernel.socket=socket
|
||||
|
||||
local sockets = {}
|
||||
local unixSocks = {}
|
||||
local nextSockId = 1
|
||||
|
||||
local function allocSockId()
|
||||
local id = nextSockId
|
||||
nextSockId = nextSockId + 1
|
||||
return id
|
||||
function socket.registerProtocal(protocal, handler)
|
||||
socket.handlers[protocal] = handler
|
||||
end
|
||||
|
||||
local function parseAddress(addr)
|
||||
if not addr then error("EINVAL") end
|
||||
function socket.socket()
|
||||
local P=kernel.vfs.P
|
||||
local data=kernel.newFifo()
|
||||
local isClosed=false
|
||||
kernel.vfs.newfd({
|
||||
handle={
|
||||
read=function() if isClosed then error("ECCON") end return data.read() end,
|
||||
write=function() if isClosed then error("ECCON") end return data.write() end,
|
||||
close=function() isClosed = true end
|
||||
},
|
||||
type="socket",
|
||||
refcount=1,
|
||||
|
||||
if addr:sub(1,1) == "/" or addr:sub(1,5) == "unix:" then
|
||||
local path = addr:sub(1,5) == "unix:" and addr:sub(6) or addr
|
||||
return { backend="unix", path=path }
|
||||
end
|
||||
|
||||
local rproto, raddr = addr:match("^rednet%+?([^:/]*)://(.+)$")
|
||||
if raddr then
|
||||
local a,b,c,d = raddr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if not a then error("EINVAL: bad rednet address " .. raddr) end
|
||||
local compId = tonumber(c)*256 + tonumber(d)
|
||||
return { backend="rednet", compId=compId,
|
||||
protocol=(rproto ~= "" and rproto or "hyperion") }
|
||||
end
|
||||
|
||||
local maddr = addr:match("^modem://(.+)$")
|
||||
if maddr then
|
||||
local a,b,c,d = maddr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if not a then error("EINVAL: bad modem address " .. maddr) end
|
||||
local compId = tonumber(c)*256 + tonumber(d)
|
||||
local port = tonumber(maddr:match(":(%d+)$")) or 0
|
||||
return { backend="modem", compId=compId, port=port }
|
||||
end
|
||||
|
||||
local scheme, rest = addr:match("^(https?)://(.+)$")
|
||||
if scheme then
|
||||
return { backend=scheme, url=addr }
|
||||
end
|
||||
|
||||
local a,b,c,d = addr:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)")
|
||||
if a and tonumber(a) ~= 0 then
|
||||
return { backend="http", url="http://" .. addr }
|
||||
end
|
||||
|
||||
error("EINVAL: unrecognised address format: " .. tostring(addr))
|
||||
end
|
||||
|
||||
local rednetOpen = false
|
||||
local function ensureRednet()
|
||||
if rednetOpen then return end
|
||||
local rn = kernel.apis and kernel.apis.rednet
|
||||
if not rn then error("ENODEV: no rednet API available") end
|
||||
local peripheral = kernel.apis.peripheral
|
||||
if peripheral then
|
||||
for _, name in ipairs(peripheral.getNames and peripheral.getNames() or {}) do
|
||||
if peripheral.getType(name) == "modem" then
|
||||
pcall(rn.open, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
rednetOpen = true
|
||||
end
|
||||
|
||||
local function getModem()
|
||||
local peripheral = kernel.apis and kernel.apis.peripheral
|
||||
if not peripheral then error("ENODEV") end
|
||||
for _, name in ipairs(peripheral.getNames and peripheral.getNames() or {}) do
|
||||
if peripheral.getType(name) == "modem" then
|
||||
local m = peripheral.wrap(name)
|
||||
if m then return m, name end
|
||||
end
|
||||
end
|
||||
error("ENODEV: no modem peripheral found")
|
||||
end
|
||||
|
||||
local function pumpEvents()
|
||||
local ev = kernel.computer:getMachineEvent()
|
||||
while ev do
|
||||
if ev == "rednet_message" then
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "rednet" and sock.bound then
|
||||
if sock.address.protocol == tostring(select(4, table.unpack({ev}))) or
|
||||
sock.address.protocol == "hyperion" then
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
ev = kernel.computer:getMachineEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local function pollEvent()
|
||||
local results = table.pack(kernel.computer:getMachineEvent())
|
||||
if results.n == 0 or results[1] == nil then return nil end
|
||||
return results
|
||||
end
|
||||
|
||||
local function dispatchEvent(ev)
|
||||
if not ev then return end
|
||||
local evtype = ev[1]
|
||||
|
||||
if evtype == "rednet_message" then
|
||||
local senderId = ev[2]
|
||||
local message = ev[3]
|
||||
local protocol = ev[4] or "hyperion"
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "rednet" and (sock.listening or sock.connected) then
|
||||
if sock.address and sock.address.protocol == protocol then
|
||||
table.insert(sock.rxbuf, { from=senderId, data=message })
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "modem_message" then
|
||||
local channel = ev[3]
|
||||
local msg = ev[5]
|
||||
local fromCh = ev[4]
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "modem" and sock.modemChannel == channel then
|
||||
table.insert(sock.rxbuf, { from=fromCh, data=msg })
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "http_success" then
|
||||
local url = ev[2]
|
||||
local handle = ev[3]
|
||||
for _, sock in pairs(sockets) do
|
||||
if sock.backend == "http" or sock.backend == "https" then
|
||||
if sock.pendingUrl == url then
|
||||
local body = handle.readAll and handle.readAll() or ""
|
||||
handle.close()
|
||||
table.insert(sock.rxbuf, { data=body, done=true })
|
||||
sock.pendingUrl = nil
|
||||
sock.connected = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
elseif evtype == "http_failure" then
|
||||
local url = ev[2]
|
||||
local err = ev[3]
|
||||
for _, sock in pairs(sockets) do
|
||||
if (sock.backend == "http" or sock.backend == "https") and
|
||||
sock.pendingUrl == url then
|
||||
sock.error = err
|
||||
sock.pendingUrl = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function pumpAll()
|
||||
local ev = pollEvent()
|
||||
while ev do
|
||||
dispatchEvent(ev)
|
||||
ev = pollEvent()
|
||||
end
|
||||
end
|
||||
|
||||
local function newSocket(domain, socktype)
|
||||
local sock = {
|
||||
id = allocSockId(),
|
||||
domain = domain, -- "unix" | "inet"
|
||||
socktype = socktype, -- "stream" | "dgram"
|
||||
backend = nil,
|
||||
state = "idle", -- idle | bound | listening | connected | closed
|
||||
rxbuf = {},
|
||||
txbuf = {},
|
||||
backlog = {},
|
||||
address = nil,
|
||||
peer = nil,
|
||||
modemChannel = nil,
|
||||
modem = nil,
|
||||
pendingUrl = nil,
|
||||
bound = false,
|
||||
listening = false,
|
||||
connected = false,
|
||||
error = nil,
|
||||
}
|
||||
sockets[sock.id] = sock
|
||||
return sock
|
||||
end
|
||||
|
||||
local sockSend, sockClose
|
||||
|
||||
local function socketToFd(sock)
|
||||
return {
|
||||
isSocket = true,
|
||||
sockId = sock.id,
|
||||
mode = "rw",
|
||||
meta = { etype=0, owner=0, group=0, perms=0x1FF, cmeta="" },
|
||||
type = "socket",
|
||||
refcount = 1,
|
||||
handle = {
|
||||
read = function(count)
|
||||
pumpAll()
|
||||
if #sock.rxbuf == 0 then return "" end
|
||||
local item = table.remove(sock.rxbuf, 1)
|
||||
local data = type(item) == "table" and (item.data or "") or tostring(item)
|
||||
if count and #data > count then
|
||||
table.insert(sock.rxbuf, 1, { data=data:sub(count+1), from=item.from })
|
||||
data = data:sub(1, count)
|
||||
end
|
||||
return data
|
||||
end,
|
||||
write = function(data)
|
||||
if sock.state == "closed" then error("EBADF") end
|
||||
return sockSend(sock, data)
|
||||
end,
|
||||
close = function()
|
||||
sockClose(sock)
|
||||
end,
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
sockSend = function(sock, data)
|
||||
if sock.backend == "unix" then
|
||||
local peer = sock.peer
|
||||
if not peer then error("ENOTCONN") end
|
||||
table.insert(peer.rxbuf, { data=data })
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "rednet" then
|
||||
ensureRednet()
|
||||
local rn = kernel.apis.rednet
|
||||
rn.send(sock.address.compId, data, sock.address.protocol)
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "modem" then
|
||||
local modem = sock.modem
|
||||
if not modem then error("ENOTCONN") end
|
||||
modem.transmit(sock.address.port, sock.modemChannel or 0, data)
|
||||
return #data
|
||||
|
||||
elseif sock.backend == "http" or sock.backend == "https" then
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API") end
|
||||
local url = sock.address.url
|
||||
local ok, err = pcall(http.request, url, data, {
|
||||
["Content-Type"] = "application/octet-stream"
|
||||
})
|
||||
if not ok then error("ENETDOWN: " .. tostring(err)) end
|
||||
sock.pendingUrl = url
|
||||
return #data
|
||||
end
|
||||
error("EPROTONOSUPPORT")
|
||||
end
|
||||
|
||||
sockClose = function(sock)
|
||||
if sock.state == "closed" then return end
|
||||
sock.state = "closed"
|
||||
|
||||
if sock.backend == "unix" then
|
||||
if sock.peer then
|
||||
sock.peer.peer = nil
|
||||
sock.peer.state = "closed"
|
||||
end
|
||||
if sock.bound and sock.address and sock.address.path then
|
||||
unixSocks[sock.address.path] = nil
|
||||
end
|
||||
|
||||
elseif sock.backend == "modem" and sock.modem and sock.modemChannel then
|
||||
pcall(sock.modem.close, sock.modemChannel)
|
||||
|
||||
elseif sock.backend == "rednet" then
|
||||
end
|
||||
|
||||
sockets[sock.id] = nil
|
||||
end
|
||||
|
||||
kernel.syscalls["socket"] = function(domain, socktype)
|
||||
domain = domain or "inet"
|
||||
socktype = socktype or "stream"
|
||||
if domain ~= "unix" and domain ~= "inet" then error("EAFNOSUPPORT") end
|
||||
if socktype ~= "stream" and socktype ~= "dgram" then error("EPROTOTYPE") end
|
||||
|
||||
local sock = newSocket(domain, socktype)
|
||||
local fdobj = socketToFd(sock)
|
||||
local fd = kernel.vfs.newfd(fdobj)
|
||||
return fd
|
||||
end
|
||||
|
||||
kernel.syscalls["bind"] = function(fd, address)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if sock.bound then error("EINVAL") end
|
||||
|
||||
local parsed = parseAddress(address)
|
||||
|
||||
if parsed.backend == "unix" then
|
||||
local existing = unixSocks[parsed.path]
|
||||
if existing then
|
||||
if existing.state == "closed" then
|
||||
unixSocks[parsed.path] = nil
|
||||
else
|
||||
error("EADDRINUSE")
|
||||
end
|
||||
end
|
||||
sock.backend = "unix"
|
||||
sock.address = parsed
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
unixSocks[parsed.path] = sock
|
||||
|
||||
elseif parsed.backend == "rednet" then
|
||||
ensureRednet()
|
||||
sock.backend = "rednet"
|
||||
sock.address = parsed
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
|
||||
elseif parsed.backend == "modem" then
|
||||
local modem, side = getModem()
|
||||
sock.backend = "modem"
|
||||
sock.address = parsed
|
||||
sock.modem = modem
|
||||
sock.modemChannel = parsed.port
|
||||
sock.bound = true
|
||||
sock.state = "bound"
|
||||
modem.open(parsed.port)
|
||||
|
||||
else
|
||||
error("EOPNOTSUPP: cannot bind to " .. parsed.backend .. " address")
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["listen"] = function(fd, backlog)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if not sock.bound then error("EDESTADDRREQ") end
|
||||
sock.listening = true
|
||||
sock.state = "listening"
|
||||
sock.maxBacklog = backlog or 5
|
||||
end
|
||||
|
||||
kernel.syscalls["accept"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if not sock.listening then error("EINVAL") end
|
||||
|
||||
local deadline = kernel.computer:time() + 30000
|
||||
while #sock.backlog == 0 do
|
||||
pumpAll()
|
||||
if kernel.computer:time() > deadline then error("ETIMEDOUT") end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
local clientSock = table.remove(sock.backlog, 1)
|
||||
local cfdobj = socketToFd(clientSock)
|
||||
local newfd = kernel.vfs.newfd(cfdobj)
|
||||
return newfd
|
||||
end
|
||||
|
||||
kernel.syscalls["connect"] = function(fd, address)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
if sock.connected then error("EISCONN") end
|
||||
|
||||
local parsed = parseAddress(address)
|
||||
sock.address = parsed
|
||||
sock.backend = parsed.backend
|
||||
|
||||
if parsed.backend == "unix" then
|
||||
local server = unixSocks[parsed.path]
|
||||
if not server then error("ECONNREFUSED") end
|
||||
if not server.listening then error("ECONNREFUSED") end
|
||||
if #server.backlog >= (server.maxBacklog or 5) then error("ECONNREFUSED") end
|
||||
|
||||
local serverPeer = newSocket("unix", sock.socktype)
|
||||
serverPeer.backend = "unix"
|
||||
serverPeer.connected = true
|
||||
serverPeer.state = "connected"
|
||||
serverPeer.peer = sock
|
||||
|
||||
sock.peer = serverPeer
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
table.insert(server.backlog, serverPeer)
|
||||
|
||||
elseif parsed.backend == "rednet" then
|
||||
ensureRednet()
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
elseif parsed.backend == "modem" then
|
||||
local modem, side = getModem()
|
||||
local replyChannel = math.random(1024, 65534)
|
||||
sock.modem = modem
|
||||
sock.modemChannel = replyChannel
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
modem.open(replyChannel)
|
||||
|
||||
elseif parsed.backend == "http" or parsed.backend == "https" then
|
||||
sock.connected = true
|
||||
sock.state = "connected"
|
||||
|
||||
else
|
||||
error("EAFNOSUPPORT")
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["send"] = function(fd, data)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
return sockSend(sock, data)
|
||||
end
|
||||
|
||||
kernel.syscalls["recv"] = function(fd, maxlen, timeout_ms)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
|
||||
local deadline = kernel.computer:time() + (timeout_ms or 10000)
|
||||
while #sock.rxbuf == 0 do
|
||||
pumpAll()
|
||||
if #sock.rxbuf > 0 then break end
|
||||
if sock.state == "closed" or sock.error then
|
||||
if sock.error then error("ECONNRESET: " .. tostring(sock.error)) end
|
||||
return ""
|
||||
end
|
||||
if kernel.computer:time() > deadline then return "" end
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
local item = table.remove(sock.rxbuf, 1)
|
||||
local data = type(item) == "table" and (item.data or "") or tostring(item)
|
||||
if maxlen and #data > maxlen then
|
||||
table.insert(sock.rxbuf, 1, { data=data:sub(maxlen+1), from=item and item.from })
|
||||
data = data:sub(1, maxlen)
|
||||
end
|
||||
return data
|
||||
end
|
||||
|
||||
kernel.syscalls["sockshutdown"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if sock then sockClose(sock) end
|
||||
end
|
||||
|
||||
kernel.syscalls["getpeername"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock or not sock.connected then error("ENOTCONN") end
|
||||
if sock.address then return sock.address end
|
||||
return nil
|
||||
end
|
||||
|
||||
kernel.syscalls["getsockname"] = function(fd)
|
||||
local task = kernel.currentTask
|
||||
local fdobj = task.fd[fd]
|
||||
if not fdobj or not fdobj.isSocket then error("ENOTSOCK") end
|
||||
local sock = sockets[fdobj.sockId]
|
||||
if not sock then error("EBADF") end
|
||||
return sock.address
|
||||
end
|
||||
|
||||
kernel.syscalls["httpget"] = function(url, headers)
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API") end
|
||||
|
||||
local ok, err = pcall(http.request, url, nil, headers)
|
||||
if not ok then error("ENETDOWN: " .. tostring(err)) end
|
||||
|
||||
local deadline = kernel.computer:time() + 15000
|
||||
while true do
|
||||
local ev = pollEvent()
|
||||
if ev then
|
||||
if ev[1] == "http_success" and ev[2] == url then
|
||||
local handle = ev[3]
|
||||
local body = handle.readAll and handle.readAll() or ""
|
||||
handle.close()
|
||||
return body
|
||||
elseif ev[1] == "http_failure" and ev[2] == url then
|
||||
error("ECONNREFUSED: " .. tostring(ev[3]))
|
||||
else
|
||||
dispatchEvent(ev)
|
||||
end
|
||||
end
|
||||
if kernel.computer:time() > deadline then error("ETIMEDOUT") end
|
||||
coroutine.yield()
|
||||
end
|
||||
end
|
||||
|
||||
kernel.syscalls["resolve"] = function(hostname)
|
||||
if hostname:match("^%d+%.%d+%.%d+%.%d+$") then return hostname end
|
||||
|
||||
local a,b,c,d = hostname:match("^(%d+)%.(%d+)%.(%d+)%.(%d+)$")
|
||||
if a and tonumber(a) == 0 and tonumber(b) == 0 then
|
||||
return hostname
|
||||
end
|
||||
|
||||
local http = kernel.apis and kernel.apis.http
|
||||
if not http then error("ENODEV: no http API for DNS") end
|
||||
|
||||
local url = "https://cloudflare-dns.com/dns-query?name=" .. hostname .. "&type=A"
|
||||
local body = kernel.syscalls["httpget"](url, {
|
||||
["Accept"] = "application/dns-json"
|
||||
meta={
|
||||
owner=kernel.currentTask.uid,
|
||||
group=kernel.currentTask.uid,
|
||||
etype=2,
|
||||
perms=P.OWNER_R+P.OWNER_W+P.GROUP_R+P.GROUP_W
|
||||
},
|
||||
isvirt=true
|
||||
})
|
||||
|
||||
local ip = body:match('"type":1[^}]*"data":"([%d%.]+)"')
|
||||
if not ip then error("ENOENT: could not resolve " .. hostname) end
|
||||
return ip
|
||||
end
|
||||
|
||||
kernel.sockets = sockets
|
||||
kernel.unixSockets = unixSocks
|
||||
function socket.connect(fd, address)
|
||||
|
||||
end
|
||||
|
||||
function socket.listen(fd, backlog)
|
||||
|
||||
end
|
||||
|
||||
kernel.log("Loaded socket module")
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
kernel.unixSockets={}
|
||||
@@ -139,7 +139,7 @@ end
|
||||
if not blake2s then error("Failed to load blake2s") end
|
||||
|
||||
if not kernel.vfs.exists("/etc/pam.d/secret") then
|
||||
kernel.log("PAM SECRET REGENERATING PLEASE USE ROOT")
|
||||
kernel.log("PAM SECRET REGENERATING PLEASE USE ROOT", "WARN", 0xFF8800)
|
||||
local key = ""
|
||||
for i = 1, 256 do key = key .. string.char(math.random(0, 255)) end
|
||||
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
|
||||
@@ -150,16 +150,11 @@ end
|
||||
local pepper = getFile("/etc/pam.d/secret")
|
||||
|
||||
local function genSalt()
|
||||
local chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789./"
|
||||
local s = ""
|
||||
for i = 1, 16 do
|
||||
s = s .. chars:sub(math.random(1, #chars), math.random(1, #chars))
|
||||
end
|
||||
return s
|
||||
return toHex(math.random(0,2^32))
|
||||
end
|
||||
|
||||
local function hashPassword(password, salt)
|
||||
local key = (pepper .. salt):sub(1, 32)
|
||||
local key = (pepper .. salt)
|
||||
return blake2s(password, key)
|
||||
end
|
||||
|
||||
|
||||
@@ -41,11 +41,11 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid)
|
||||
|
||||
if kernel.config.logTaskExit then
|
||||
if not ok then
|
||||
kernel.log("Task " .. tostring(id) .. " exited with err: " .. tostring(err), "ERROR", 2)
|
||||
kernel.log("Task " .. tostring(id) .. " exited with err: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
elseif err then
|
||||
kernel.log("Task " .. tostring(id) .. " exited with code: " .. tostring(err), "INFO")
|
||||
kernel.log("Task " .. tostring(id) .. " exited with code: " .. tostring(err), "DBUG", 0x00FFFF)
|
||||
else
|
||||
kernel.log("Task " .. tostring(id) .. " exited without code", "INFO")
|
||||
kernel.log("Task " .. tostring(id) .. " exited without code", "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -110,7 +110,7 @@ function sys.execspawn(path, name, envars, args, tgid)
|
||||
kernel.log(
|
||||
"execspawn: suid exec '" .. path ..
|
||||
"' caller_uid=" .. tostring(real_uid) ..
|
||||
" -> euid=" .. tostring(euid), "INFO"
|
||||
" -> euid=" .. tostring(euid)
|
||||
)
|
||||
end
|
||||
|
||||
@@ -136,9 +136,9 @@ function sys.exec(path, args, envars)
|
||||
local ok, err = xpcall(func, debug.traceback, table.unpack(task.args))
|
||||
if kernel.config.logTaskExit then
|
||||
if not ok then
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' err: " .. tostring(err), "ERROR", 2)
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' err: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' exited: " .. tostring(err), "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exec '" .. path .. "' exited: " .. tostring(err), "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
if type(err) == "number" then tasks[tostring(task.pid)].exit = err end
|
||||
@@ -155,8 +155,7 @@ end
|
||||
|
||||
function sys.sleep(s)
|
||||
kernel.currentTask.status = "S"
|
||||
kernel.currentTask.sleep = kernel.computer:time() + s * 1000
|
||||
coroutine.yield()
|
||||
kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000
|
||||
end
|
||||
|
||||
function sys.getTask(pid)
|
||||
@@ -260,9 +259,9 @@ function sys.exit(code)
|
||||
local task = kernel.currentTask
|
||||
if kernel.config.logTaskExit then
|
||||
if code then
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited with code: " .. tostring(code), "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited with code: " .. tostring(code), "DBUG", 0x00FFFF)
|
||||
else
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "INFO")
|
||||
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
tasks[tostring(task.pid)].status = "Z"
|
||||
@@ -303,9 +302,9 @@ local function reapDeadTasks()
|
||||
task.syscallReturn = nil
|
||||
task.sleep = nil
|
||||
task.fd = nil
|
||||
task.reapTime = kernel.computer:time() + 30000
|
||||
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
||||
|
||||
elseif task.reapTime and kernel.computer:time() > task.reapTime
|
||||
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
||||
and task.status == "Z" then
|
||||
for _, child in ipairs(task.children) do
|
||||
child.parent = tasks["1"]
|
||||
@@ -343,55 +342,61 @@ function kernel.main()
|
||||
local taskTimes = {}
|
||||
|
||||
for pid, task in pairs(tasks) do
|
||||
if task.status == "S" and kernel.computer:time() >= task.sleep then
|
||||
kernel.currentTask = task
|
||||
kernel.uid = task.euid or task.uid
|
||||
kernel.process = task.name
|
||||
|
||||
if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||
task.status = "R"
|
||||
task.sleep = 0
|
||||
end
|
||||
|
||||
if task.status == "R" then
|
||||
kernel.currentTask = task
|
||||
if task.status == "D" then
|
||||
if task.ksh then
|
||||
coroutine.resume(task.ksh)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.uid = task.euid or task.uid
|
||||
kernel.process = task.name
|
||||
if task.status == "R" then
|
||||
N = N + 1
|
||||
|
||||
task.timeSlice = math.min(Tmax, math.max(Tmin, B / (N ^ alpha)))
|
||||
|
||||
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
||||
local coro = coroutine.create(task.sigh)
|
||||
local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) }
|
||||
while coroutine.status(coro) ~= "dead" do
|
||||
if sigret[1] == false then break end
|
||||
if sigret[2] == "syscall" then
|
||||
local scname = sigret[3]
|
||||
local sysret
|
||||
if kernel.syscalls[scname] then
|
||||
sysret = { xpcall(kernel.syscalls[scname], debug.traceback, table.unpack(sigret, 4)) }
|
||||
else
|
||||
sysret = { false, "Unknown syscall: " .. tostring(scname) }
|
||||
end
|
||||
if not sysret[1] then
|
||||
sigret = { coroutine.resume(coro, false, sysret[2]) }
|
||||
else
|
||||
sigret = { coroutine.resume(coro, true, table.unpack(sysret, 2)) }
|
||||
end
|
||||
else
|
||||
sigret = { coroutine.resume(coro) }
|
||||
local status,err=coroutine.resumeWithTimeout(coro, 100, table.remove(task.sigq, 1))
|
||||
if status=="error" then
|
||||
task.sigd.error=err
|
||||
task.sigd.active=false
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
task.sigd=nil
|
||||
elseif status=="success" then
|
||||
if err=="syscall" then
|
||||
task.sigd.error="Cannot execute syscalls from signals"
|
||||
task.sigd.active=false
|
||||
task.sigh=nil
|
||||
task.sigq=nil
|
||||
task.sigd=nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if task.status == "R" then
|
||||
local startTime = kernel.computer:time()
|
||||
local startTime = kernel.EFI:getEpochMs()
|
||||
local ret
|
||||
|
||||
if kernel.config.preempt then
|
||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||
if not task.debugger then
|
||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||
else
|
||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||
end
|
||||
else
|
||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||
end
|
||||
|
||||
local elapsed = kernel.computer:time() - startTime
|
||||
local elapsed = kernel.EFI:getEpochMs() - startTime
|
||||
task.lastTime = elapsed
|
||||
task.totalTime = (task.totalTime or 0) + elapsed
|
||||
task.numRuns = (task.numRuns or 0) + 1
|
||||
@@ -403,7 +408,7 @@ function kernel.main()
|
||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
||||
|
||||
if ret[1] == "error" or ret[1] == false then
|
||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 2)
|
||||
kernel.log("processHandlerException: " .. tostring(ret[2]), "ERROR", 0xFF0000)
|
||||
task.status = "Z"
|
||||
task.exit = "processHandlerException: " .. tostring(ret[2])
|
||||
|
||||
@@ -418,9 +423,9 @@ function kernel.main()
|
||||
local scname = ret[3]
|
||||
if kernel.syscalls[scname] then
|
||||
if kernel.config.debugSyscalls then
|
||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 5)
|
||||
kernel.log("Task " .. task.pid .. " syscall: " .. scname, "DBUG", 0x00FFFF)
|
||||
for i = 4, #ret do
|
||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 5)
|
||||
kernel.log(" inval[" .. (i-3) .. "] = " .. tostring(ret[i]), "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -428,12 +433,12 @@ function kernel.main()
|
||||
|
||||
if kernel.config.debugSyscalls then
|
||||
if not sysret[1] then
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 2)
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " failed: " .. tostring(sysret[2]), "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 5)
|
||||
kernel.log("Task " .. task.pid .. " syscall " .. scname .. " ok, " .. (#sysret-1) .. " retvals", "DBUG", 0x00FFFF)
|
||||
for i = 2, #sysret do
|
||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 5)
|
||||
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -9,8 +9,20 @@ sysc["gpio_write"]=function(pin, data)
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_writeAnalog"]=function(pin, data)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("wa", data)
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_read"]=function(pin)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("r")
|
||||
end
|
||||
end
|
||||
|
||||
sysc["gpio_readAnalog"]=function(pin)
|
||||
if kernel.gpio[pin] then
|
||||
return kernel.gpio[pin]("ra")
|
||||
end
|
||||
end
|
||||
@@ -9,11 +9,13 @@ if not initOk then
|
||||
end
|
||||
|
||||
local handle = kernel.vfs.open(kernel.config.initPath, "r")
|
||||
if not handle then kernel.panic("Failed to open "..kernel.config.initPath) end
|
||||
local data = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
||||
if not handle then kernel.panic("Failed to read "..kernel.config.initPath) end
|
||||
kernel.vfs.close(handle)
|
||||
|
||||
local initFunc, err = load(data, "@sysinit", "t", kernel._U)
|
||||
if not initFunc then error("Failed to load init system: " .. err) end
|
||||
if not initFunc then kernel.PANIC("Failed to load init system: " .. err) end
|
||||
|
||||
kernel.tasks["1"] = {
|
||||
coro = coroutine.create(function()
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
if not kernel.vfs.exists("/root") then kernel.vfs.mkdir("/root") end
|
||||
|
||||
kernel.processes.login = function()
|
||||
local ok, err = pcall(kernel.hpv.execspawn, "/bin/login", "login")
|
||||
if not ok then
|
||||
kernel.log("Failed to exec /bin/login: " .. tostring(err), "ERROR", 2)
|
||||
kernel.log("Failed to exec /bin/login: " .. tostring(err), "ERROR", 0xFF0000)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,88 +1,88 @@
|
||||
--:Minify:--
|
||||
local kernel = ...
|
||||
|
||||
local P = kernel.vfs.P
|
||||
local PERM = kernel.vfs.PERM
|
||||
|
||||
local RW_R_R = P.OWNER_R + P.OWNER_W + P.GROUP_R + P.WORLD_R
|
||||
local RWX_RX_RX = P.OWNER_R + P.OWNER_W + P.OWNER_X
|
||||
+ P.GROUP_R + P.GROUP_X
|
||||
+ P.WORLD_R + P.WORLD_X
|
||||
local RW_R__ = P.OWNER_R + P.OWNER_W + P.GROUP_R
|
||||
local RW____ = P.OWNER_R + P.OWNER_W
|
||||
local RWXRWXRWX = PERM.RWXRWXRWX
|
||||
local SUID_755 = PERM.SUID_755
|
||||
|
||||
local META_VERSION = 0x02
|
||||
local rootDisk = kernel.disks["$"]
|
||||
|
||||
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
||||
cmeta = cmeta or ""
|
||||
local plo = perms % 256
|
||||
local phi = math.floor(perms / 256) % 256
|
||||
local olo = (owner or 0) % 256
|
||||
local ohi = math.floor((owner or 0) / 256) % 256
|
||||
local glo = (group or 0) % 256
|
||||
local ghi = math.floor((group or 0) / 256) % 256
|
||||
return string.char(#name) .. name
|
||||
.. string.char(etype, olo, ohi, glo, ghi, plo, phi)
|
||||
.. string.char(#cmeta) .. cmeta
|
||||
end
|
||||
|
||||
local REG = 0x00
|
||||
|
||||
local function mergeMeta(dir, entries)
|
||||
local diskDir = dir
|
||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||
|
||||
local existing = {}
|
||||
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||
if rok and rf then
|
||||
local raw = rf.read(65535)
|
||||
if rf.close then rf.close() end
|
||||
existing = (kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw)) or {}
|
||||
end
|
||||
|
||||
for _, e in ipairs(entries) do
|
||||
local name = e[1]
|
||||
local etype = e[2] or REG
|
||||
local owner = e[3] or 0
|
||||
local group = e[4] or 0
|
||||
local perms = e[5] or RWX_RX_RX
|
||||
local cmeta = e[6] or ""
|
||||
existing[name] = {
|
||||
etype = etype,
|
||||
owner = owner,
|
||||
group = group,
|
||||
perms = perms,
|
||||
cmeta = cmeta,
|
||||
}
|
||||
end
|
||||
|
||||
local data = string.char(META_VERSION)
|
||||
for name, m in pairs(existing) do
|
||||
data = data .. makeEntry(
|
||||
name,
|
||||
m.etype or REG,
|
||||
m.owner or 0,
|
||||
m.group or 0,
|
||||
m.perms or RWX_RX_RX,
|
||||
m.cmeta or ""
|
||||
)
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
local f = rootDisk:open(metaPath, "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
end)
|
||||
if not ok then
|
||||
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 8)
|
||||
end
|
||||
end
|
||||
|
||||
if kernel.firstBoot then
|
||||
local P = kernel.vfs.P
|
||||
local PERM = kernel.vfs.PERM
|
||||
|
||||
local RW_R_R = P.OWNER_R + P.OWNER_W + P.GROUP_R + P.WORLD_R
|
||||
local RWX_RX_RX = P.OWNER_R + P.OWNER_W + P.OWNER_X
|
||||
+ P.GROUP_R + P.GROUP_X
|
||||
+ P.WORLD_R + P.WORLD_X
|
||||
local RW_R__ = P.OWNER_R + P.OWNER_W + P.GROUP_R
|
||||
local RW____ = P.OWNER_R + P.OWNER_W
|
||||
local RWXRWXRWX = PERM.RWXRWXRWX
|
||||
local SUID_755 = PERM.SUID_755
|
||||
|
||||
local META_VERSION = 0x02
|
||||
local rootDisk = kernel.disks["$"]
|
||||
|
||||
local function makeEntry(name, etype, owner, group, perms, cmeta)
|
||||
cmeta = cmeta or ""
|
||||
local plo = perms % 256
|
||||
local phi = math.floor(perms / 256) % 256
|
||||
local olo = (owner or 0) % 256
|
||||
local ohi = math.floor((owner or 0) / 256) % 256
|
||||
local glo = (group or 0) % 256
|
||||
local ghi = math.floor((group or 0) / 256) % 256
|
||||
return string.char(#name) .. name
|
||||
.. string.char(etype, olo, ohi, glo, ghi, plo, phi)
|
||||
.. string.char(#cmeta) .. cmeta
|
||||
end
|
||||
|
||||
local REG = 0x00
|
||||
|
||||
local function mergeMeta(dir, entries)
|
||||
local diskDir = dir
|
||||
if diskDir:sub(1,1) == "/" then diskDir = diskDir:sub(2) end
|
||||
local metaPath = (diskDir == "" and ".meta" or diskDir .. "/.meta")
|
||||
|
||||
local existing = {}
|
||||
local rok, rf = pcall(function() return rootDisk:open(metaPath, "r") end)
|
||||
if rok and rf then
|
||||
local raw = rf.read(65535)
|
||||
if rf.close then rf.close() end
|
||||
existing = (kernel.vfs._parseMetafile and kernel.vfs._parseMetafile(raw)) or {}
|
||||
end
|
||||
|
||||
for _, e in ipairs(entries) do
|
||||
local name = e[1]
|
||||
local etype = e[2] or REG
|
||||
local owner = e[3] or 0
|
||||
local group = e[4] or 0
|
||||
local perms = e[5] or RWX_RX_RX
|
||||
local cmeta = e[6] or ""
|
||||
existing[name] = {
|
||||
etype = etype,
|
||||
owner = owner,
|
||||
group = group,
|
||||
perms = perms,
|
||||
cmeta = cmeta,
|
||||
}
|
||||
end
|
||||
|
||||
local data = string.char(META_VERSION)
|
||||
for name, m in pairs(existing) do
|
||||
data = data .. makeEntry(
|
||||
name,
|
||||
m.etype or REG,
|
||||
m.owner or 0,
|
||||
m.group or 0,
|
||||
m.perms or RWX_RX_RX,
|
||||
m.cmeta or ""
|
||||
)
|
||||
end
|
||||
|
||||
local ok, err = pcall(function()
|
||||
local f = rootDisk:open(metaPath, "w")
|
||||
f.write(data)
|
||||
f.close()
|
||||
end)
|
||||
if not ok then
|
||||
kernel.log("permissions: failed to write " .. metaPath .. ": " .. tostring(err), "WARN", 0xFF8800)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.log("Seeding filesystem permissions...")
|
||||
|
||||
mergeMeta("/", {
|
||||
@@ -92,6 +92,7 @@ if kernel.firstBoot then
|
||||
{"etc", REG, 0, 0, RWX_RX_RX},
|
||||
{"home", REG, 0, 0, RWX_RX_RX},
|
||||
{"lib", REG, 0, 0, RWX_RX_RX},
|
||||
{"proc", REG, 0, 0, RWXRWXRWX},
|
||||
{"root", REG, 0, 0, RW____ },
|
||||
{"sbin", REG, 0, 0, RWX_RX_RX},
|
||||
{"tmp", REG, 0, 0, RWXRWXRWX},
|
||||
@@ -117,4 +118,4 @@ if kernel.firstBoot then
|
||||
})
|
||||
|
||||
kernel.log("Filesystem permissions seeded.")
|
||||
end
|
||||
end
|
||||
@@ -261,16 +261,16 @@ local function render()
|
||||
syscall.write(1, "\n")
|
||||
end
|
||||
end
|
||||
syscall.devctl(1, "sfgc", 16)
|
||||
syscall.devctl(1, "sbgc", 13)
|
||||
syscall.devctl(1, "sfgc", 0x000000)
|
||||
syscall.devctl(1, "sbgc", 0xDBDBDB)
|
||||
local pct = math.floor(math.min(100, (scroll + pageSize) / totalLines * 100))
|
||||
local status = string.format(" help -- line %d/%d (%d%%) [up/down: scroll q: quit] ",
|
||||
scroll + 1, totalLines, pct)
|
||||
if #status > screenW then status = status:sub(1, screenW) end
|
||||
syscall.devctl(1, "spos", 1, screenH)
|
||||
syscall.write(1, status .. string.rep(" ", screenW - #status))
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sbgc", 16)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
dirty = false
|
||||
end
|
||||
|
||||
@@ -281,7 +281,7 @@ if totalLines <= pageSize then
|
||||
syscall.devctl(1, "sfgc", line[2])
|
||||
syscall.write(1, line[1] .. "\n")
|
||||
end
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -305,5 +305,5 @@ end
|
||||
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sbgc", 16)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
|
||||
@@ -3,11 +3,11 @@
|
||||
-- 1=white, 2=red, 3=green, 4=blue, 5=cyan, 6=magenta, 7=yellow
|
||||
-- 8=orange, 9=lime, 10=lightcyan, 11=brown, 12=darkgrey, 13=lightgrey, 14=purple, 15=chartreuse, 16=black
|
||||
|
||||
local C_LOGO = 5 -- cyan
|
||||
local C_WHITE = 1 -- white
|
||||
local C_LABEL = 13 -- light grey (key names)
|
||||
local C_SEP = 12 -- dark grey (---- separator)
|
||||
local C_USER = 3 -- green (user@host)
|
||||
local C_LOGO = 0x00FFFF -- cyan
|
||||
local C_WHITE = 0xFFFFFF -- white
|
||||
local C_LABEL = 0xDBDBDB -- light grey (key names)
|
||||
local C_SEP = 0x6D6D6D -- dark grey (---- separator)
|
||||
local C_USER = 0x00FF00 -- green (user@host)
|
||||
|
||||
local function c(col) syscall.devctl(1, "sfgc", col) end
|
||||
|
||||
|
||||
@@ -8,7 +8,7 @@ local success, errorMsg = xpcall(function()
|
||||
local fs = require("fs")
|
||||
|
||||
syscall.devctl(1,"clear")
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
syscall.devctl(1,"spos",1,1)
|
||||
print("HyperionOS hysh Shell")
|
||||
|
||||
@@ -26,8 +26,27 @@ else
|
||||
end
|
||||
local oldWD = ""
|
||||
|
||||
local colors = {
|
||||
0xFFFFFF,
|
||||
0xFF0000,
|
||||
0x00FF00,
|
||||
0x0000FF,
|
||||
0x00FFFF,
|
||||
0xFF00FF,
|
||||
0xFFFF00,
|
||||
0xFF6D00,
|
||||
0x6DFF55,
|
||||
0x24FFFF,
|
||||
0x924900,
|
||||
0x6D6D55,
|
||||
0xDBDBAA,
|
||||
0x6D00FF,
|
||||
0xB6FF00,
|
||||
0x000000
|
||||
}
|
||||
|
||||
for i = 1, 16 do
|
||||
syscall.devctl(1,"sbgc",i); printInline(" ")
|
||||
syscall.devctl(1,"sbgc",colors[i]); printInline(" ")
|
||||
end
|
||||
print("\n")
|
||||
|
||||
@@ -221,7 +240,7 @@ end
|
||||
|
||||
builtinCmds.clear = function()
|
||||
syscall.devctl(1,"clear")
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
syscall.devctl(1,"spos",1,1)
|
||||
end
|
||||
|
||||
@@ -429,7 +448,7 @@ builtinCmds.head = function(...)
|
||||
local multi = #files > 1
|
||||
local function dohead(text, label)
|
||||
if multi then
|
||||
syscall.devctl(1,"sfgc",4); print("==> "..label.." <=="); syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0x0000FF); print("==> "..label.." <=="); syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
end
|
||||
local count = 0
|
||||
for line in (text.."\n"):gmatch("([^\n]*)\n") do
|
||||
@@ -468,7 +487,7 @@ builtinCmds.tail = function(...)
|
||||
local multi = #files > 1
|
||||
local function dotail(text, label)
|
||||
if multi then
|
||||
syscall.devctl(1,"sfgc",4); print("==> "..label.." <=="); syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0x0000FF); print("==> "..label.." <=="); syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
end
|
||||
local lines = splitlines(text)
|
||||
local start = math.max(1, #lines - n + 1)
|
||||
@@ -963,13 +982,13 @@ local function doTabComplete(input, cursorPos)
|
||||
end
|
||||
|
||||
local function getUserInput()
|
||||
syscall.devctl(1,"sfgc",3)
|
||||
syscall.devctl(1,"sfgc",0x00FF00)
|
||||
syscall.write(1, userhost)
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
syscall.write(1, ":")
|
||||
syscall.devctl(1,"sfgc",10)
|
||||
syscall.devctl(1,"sfgc",0x24FFFF)
|
||||
syscall.write(1, syscall.getcwd())
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
syscall.write(1, "$ ")
|
||||
local curOffsetStr = syscall.devctl(1, "gpos")
|
||||
local curOffsetX = tonumber(curOffsetStr:sub(1, curOffsetStr:find(";")-1))
|
||||
@@ -1020,21 +1039,21 @@ local function getUserInput()
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
syscall.write(1, string.sub(input, 1, cursorPos-1))
|
||||
if blinkState then
|
||||
syscall.devctl(1,"sfgc",16); syscall.devctl(1,"sbgc",1)
|
||||
syscall.devctl(1,"sfgc",0x000000); syscall.devctl(1,"sbgc",0xFFFFFF)
|
||||
end
|
||||
if cursorPos > #input then
|
||||
syscall.write(1, " ")
|
||||
else
|
||||
syscall.write(1, string.sub(input, cursorPos, cursorPos))
|
||||
end
|
||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.devctl(1,"sbgc",0x000000)
|
||||
local after = string.sub(input, cursorPos+1)
|
||||
syscall.write(1, after)
|
||||
local ghost = getGhostSuffix()
|
||||
if #ghost > 0 then
|
||||
syscall.devctl(1,"sfgc",14)
|
||||
syscall.devctl(1,"sfgc",0x6D00FF)
|
||||
syscall.write(1, ghost)
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
syscall.write(1, " ")
|
||||
else
|
||||
syscall.write(1, " ")
|
||||
@@ -1082,10 +1101,10 @@ local function getUserInput()
|
||||
syscall.write(1, string.rep(" ", tw))
|
||||
syscall.devctl(1,"spos",1,py)
|
||||
end
|
||||
syscall.devctl(1,"sfgc",3); syscall.write(1, userhost)
|
||||
syscall.devctl(1,"sfgc",1); syscall.write(1, ":")
|
||||
syscall.devctl(1,"sfgc",10); syscall.write(1, syscall.getcwd())
|
||||
syscall.devctl(1,"sfgc",1); syscall.write(1, "$ ")
|
||||
syscall.devctl(1,"sfgc",0x00FF00); syscall.write(1, userhost)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.write(1, ":")
|
||||
syscall.devctl(1,"sfgc",0x00FFFF); syscall.write(1, syscall.getcwd())
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.write(1, "$ ")
|
||||
posStr = syscall.devctl(1, "gpos")
|
||||
sep = posStr:find(";")
|
||||
curOffsetX = tonumber(posStr:sub(1, sep-1))
|
||||
@@ -1098,7 +1117,7 @@ local function getUserInput()
|
||||
cursorPos=cursorPos-1;dirty=true
|
||||
end
|
||||
elseif key=="\n" then
|
||||
syscall.devctl(1,"sfgc",1);syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF);syscall.devctl(1,"sbgc",0x000000)
|
||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||
syscall.write(1, input.." \n")
|
||||
return input
|
||||
@@ -1114,7 +1133,7 @@ local function getUserInput()
|
||||
end
|
||||
|
||||
local function printError(progName, msg)
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
syscall.devctl(1,"sfgc",0xFF0000)
|
||||
local s = tostring(msg)
|
||||
local line, rest = s:match("%]:(%d+): (.+)$")
|
||||
if not line then line, rest = s:match(":(%d+): (.+)$") end
|
||||
@@ -1123,7 +1142,7 @@ local function printError(progName, msg)
|
||||
else
|
||||
print(progName..": "..s)
|
||||
end
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
end
|
||||
|
||||
local function runCommand(command)
|
||||
@@ -1171,7 +1190,7 @@ local function runCommand(command)
|
||||
|
||||
local xok, xerr = pcall(syscall.access, cmdPath, "x")
|
||||
if not xok then
|
||||
syscall.devctl(1,"sfgc",2); print(progName..": Permission denied"); syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFF0000); print(progName..": Permission denied"); syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -1195,8 +1214,8 @@ local function runCommand(command)
|
||||
if terminate then
|
||||
local ok2 = syscall.kill(proc)
|
||||
if ok2 then
|
||||
syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",2)
|
||||
print("\nProgram Terminated."); syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",0xFF0000)
|
||||
print("\nProgram Terminated."); syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
end
|
||||
terminate = false; break
|
||||
end
|
||||
@@ -1218,8 +1237,8 @@ end, debug.traceback)
|
||||
|
||||
if not success then
|
||||
syscall.log("Error running shell: "..errorMsg, "ERROR")
|
||||
syscall.devctl(1,"sfgc",2)
|
||||
syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",0xFF0000)
|
||||
syscall.devctl(1,"sbgc",0x000000)
|
||||
print()
|
||||
print("Error running shell: ")
|
||||
print(errorMsg)
|
||||
|
||||
@@ -37,9 +37,9 @@ local function firstBoot()
|
||||
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "HyperionOS First Boot Setup\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "No root password is set. Please create one now.\n\n")
|
||||
|
||||
while true do
|
||||
@@ -49,25 +49,25 @@ local function firstBoot()
|
||||
local pw2 = readLine("*")
|
||||
|
||||
if pw1 ~= pw2 then
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Passwords do not match. Try again.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
elseif #pw1 < 6 then
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Password too short (minimum 6 characters).\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
else
|
||||
local ok, err = syscall.setpassword(0, pw1)
|
||||
if ok then
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "Root password set.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.5)
|
||||
break
|
||||
else
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -112,8 +112,8 @@ end
|
||||
|
||||
local function doLogin()
|
||||
syscall.devctl(1, "clear")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sbgc", 16)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.devctl(1, "sbgc", 0x000000)
|
||||
syscall.devctl(1, "spos", 1, 1)
|
||||
|
||||
local hostname = syscall.getHostname() or "hyperion"
|
||||
@@ -122,45 +122,44 @@ local function doLogin()
|
||||
|
||||
local attempts = 0
|
||||
while attempts < MAX_ATTEMPTS do
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
syscall.write(1, "Username: ")
|
||||
local username = readLine(nil)
|
||||
|
||||
if username == "" then goto continue end
|
||||
if username ~= "" then
|
||||
|
||||
syscall.write(1, "Password: ")
|
||||
local password = readLine("*")
|
||||
local uid = syscall.getuidbyname(username)
|
||||
|
||||
local ok, err = syscall.login(uid, password)
|
||||
if ok then
|
||||
local uid = syscall.getuid()
|
||||
local pwent = syscall.getpasswd(uid)
|
||||
syscall.write(1, "Password: ")
|
||||
local password = readLine("*")
|
||||
local uid = syscall.getuidbyname(username)
|
||||
|
||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
local ok, err = syscall.login(uid, password)
|
||||
if ok then
|
||||
local uid = syscall.getuid()
|
||||
local pwent = syscall.getpasswd(uid)
|
||||
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
sleep(0.3)
|
||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||
local homedir = (pwent and pwent.homedir) or "/"
|
||||
|
||||
spawnShell(username, uid, shell, homedir)
|
||||
return -- back to login prompt
|
||||
else
|
||||
attempts = attempts + 1
|
||||
sleep(1)
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(0.3)
|
||||
|
||||
spawnShell(username, uid, shell, homedir)
|
||||
return -- back to login prompt
|
||||
else
|
||||
attempts = attempts + 1
|
||||
sleep(1)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Login incorrect.\n\n")
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 2)
|
||||
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||
syscall.write(1, "Maximum login attempts exceeded.\n")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
sleep(5)
|
||||
end
|
||||
|
||||
|
||||
@@ -110,9 +110,9 @@ if opts.x then
|
||||
pcall(syscall.umount, tmpMnt)
|
||||
pcall(syscall.lodetach, loopId)
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": extracted "..count.." file(s) to "..destPath)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -150,8 +150,8 @@ local lineCount = 0
|
||||
for _ in imgStr:gmatch("\n") do lineCount = lineCount + 1 end
|
||||
local byteCount = #imgStr
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": image written to "..imgPath)
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||
print(string.format(" %d records, %d bytes", lineCount - 1, byteCount))
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
|
||||
@@ -60,18 +60,18 @@ if opts.l then
|
||||
local info = devs[id]
|
||||
local mode = (type(info) == "table" and info.mode) or "bind"
|
||||
local path = (type(info) == "table" and info.path) or tostring(info)
|
||||
local colour = mode == "image" and 5 or 4
|
||||
syscall.devctl(1, "sfgc", 3)
|
||||
local colour = mode == "image" and 0x00FFFF or 0x0000FF
|
||||
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||
printInline(string.format("%-10s", id))
|
||||
syscall.devctl(1, "sfgc", colour)
|
||||
printInline(string.format("%-7s", "["..mode.."]"))
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
print(" "..path)
|
||||
end
|
||||
if not any then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||
print(name..": no loop devices attached")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
return
|
||||
end
|
||||
@@ -92,9 +92,9 @@ if opts.d then
|
||||
end
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": detached "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -110,10 +110,12 @@ if cloptions.l then
|
||||
local stat = syscall.lstat and syscall.lstat(fullPath) or syscall.stat(fullPath)
|
||||
local isDir = fs.isDir(fullPath)
|
||||
local isSym = stat and stat.etype == 0x01
|
||||
local isSock = stat and stat.etype == 0x02
|
||||
|
||||
local typeChar
|
||||
if isSym then typeChar = "l"
|
||||
if isSym then typeChar = "l"
|
||||
elseif isDir then typeChar = "d"
|
||||
elseif isSock then typeChar = "s"
|
||||
else typeChar = "-" end
|
||||
|
||||
local pstr
|
||||
@@ -136,26 +138,30 @@ if cloptions.l then
|
||||
printInline(tostring(mtime) .. " ")
|
||||
|
||||
if isSym then
|
||||
syscall.devctl(1, "sfgc", 6)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
printInline(v)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
local ok, target = pcall(syscall.readlink, fullPath)
|
||||
if ok then
|
||||
printInline(" -> ")
|
||||
local targetExists = pcall(syscall.stat, fullPath)
|
||||
syscall.devctl(1, "sfgc", targetExists and 6 or 2)
|
||||
syscall.devctl(1, "sfgc", targetExists and 0x00FFFF or 0xFF0000)
|
||||
printInline(target)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
elseif isDir then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||
printInline(v)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
elseif isSock then
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
printInline(v)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
else
|
||||
local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1)
|
||||
syscall.devctl(1, "sfgc", isExec and 3 or 1)
|
||||
syscall.devctl(1, "sfgc", isExec and 0x00FF00 or 0xFFFFFF)
|
||||
printInline(v)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
print("")
|
||||
end
|
||||
@@ -175,16 +181,18 @@ for i, v in ipairs(list) do
|
||||
local isSym = stat and stat.etype == 0x01
|
||||
|
||||
if isSym then
|
||||
syscall.devctl(1, "sfgc", 6)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
elseif isDir then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||
elseif isSock then
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
else
|
||||
local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1)
|
||||
syscall.devctl(1, "sfgc", isExec and 3 or 1)
|
||||
syscall.devctl(1, "sfgc", isExec and 0x00FF00 or 0xFFFFFF)
|
||||
end
|
||||
|
||||
printInline(v)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
printInline((" "):rep(colWidth - #v))
|
||||
|
||||
if i % numCols == 0 then print("") end
|
||||
|
||||
@@ -5,15 +5,15 @@ if not users or #users == 0 then
|
||||
return
|
||||
end
|
||||
|
||||
syscall.devctl(1,"sfgc",13)
|
||||
syscall.devctl(1,"sfgc",0xDBDBDB)
|
||||
print(string.format("%-6s %-6s %-16s %-20s %s", "UID", "GID", "Username", "Home", "Shell"))
|
||||
print(string.rep("-", 65))
|
||||
syscall.devctl(1,"sfgc",1)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||
|
||||
for _, u in ipairs(users) do
|
||||
local lock_marker = u.locked and " [locked]" or ""
|
||||
if u.locked then syscall.devctl(1,"sfgc",2) end
|
||||
if u.locked then syscall.devctl(1,"sfgc",0xFF0000) end
|
||||
print(string.format("%-6d %-6d %-16s %-20s %s%s",
|
||||
u.uid, u.gid, u.username, u.homedir, u.shell, lock_marker))
|
||||
if u.locked then syscall.devctl(1,"sfgc",1) end
|
||||
if u.locked then syscall.devctl(1,"sfgc",0xFFFFFF) end
|
||||
end
|
||||
|
||||
@@ -69,17 +69,17 @@ if #args == 0 and not opts.o then
|
||||
end
|
||||
|
||||
if next(loDevs) == nil then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
print("(no loop devices attached)")
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
for id, info in pairs(loDevs) do
|
||||
local colour = info.mode == "image" and 5 or 4
|
||||
local colour = info.mode == "image" and 0x00FFFF or 0x0000FF
|
||||
syscall.devctl(1, "sfgc", colour)
|
||||
printInline(info.mode.." "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
print(" on "..info.path)
|
||||
end
|
||||
return
|
||||
@@ -119,9 +119,9 @@ if opts.o and opts.o:lower() == "loop" then
|
||||
print(name..": mount: "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": "..loopId.." mounted at "..dest)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -141,9 +141,9 @@ if #args == 2 then
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": "..loopId.." mounted at "..dest)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
--:Minify:--
|
||||
local targetUser = ({ ... })[1]
|
||||
local currentUid = syscall.getuid()
|
||||
if syscall.geteuid()~=0 then
|
||||
syscall.exec("/bin/su", {...})
|
||||
end
|
||||
local targetUid
|
||||
if targetUser then
|
||||
targetUid = syscall.getuidbyname(targetUser)
|
||||
|
||||
@@ -59,9 +59,9 @@ if opts.l then
|
||||
end
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": detached "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
return
|
||||
end
|
||||
|
||||
@@ -95,17 +95,17 @@ if not ok then
|
||||
print(name..": "..msg); syscall.exit(1); return
|
||||
end
|
||||
|
||||
syscall.devctl(1, "sfgc", 10)
|
||||
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||
print(name..": unmounted "..mpt)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
|
||||
if loopIdToDetach then
|
||||
for _, id in ipairs(loopIdToDetach) do
|
||||
local dok = pcall(syscall.lodetach, id)
|
||||
if dok then
|
||||
syscall.devctl(1, "sfgc", 14)
|
||||
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||
print(name..": auto-detached "..id)
|
||||
syscall.devctl(1, "sfgc", 1)
|
||||
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
--:Minify:--
|
||||
local ini = {}
|
||||
|
||||
function ini.parse(str)
|
||||
|
||||
8
Src/install.json
Normal file
8
Src/install.json
Normal file
@@ -0,0 +1,8 @@
|
||||
[
|
||||
"Hyperion-kernel",
|
||||
"Hyperion-core",
|
||||
"hysh",
|
||||
"lua",
|
||||
"micro",
|
||||
"sysinit"
|
||||
]
|
||||
@@ -1,14 +1,14 @@
|
||||
--:Minify:--
|
||||
local C_PROMPT = 7
|
||||
local C_CONT = 13
|
||||
local C_OUT = 5
|
||||
local C_ERR = 2
|
||||
local C_KEY = 3
|
||||
local C_STR = 9
|
||||
local C_NUM = 10
|
||||
local C_BOOL = 8
|
||||
local C_NIL = 12
|
||||
local C_TABLE = 13
|
||||
local C_PROMPT = 0xFFFF00
|
||||
local C_CONT = 0xDBDBDB
|
||||
local C_OUT = 0x00FFFF
|
||||
local C_ERR = 0xFF0000
|
||||
local C_KEY = 0x00FF00
|
||||
local C_STR = 0x00FF88
|
||||
local C_NUM = 0x24FFFF
|
||||
local C_BOOL = 0xFF6D00
|
||||
local C_NIL = 0x6D6D6D
|
||||
local C_TABLE = 0xDBDBDB
|
||||
|
||||
local function c(col) syscall.devctl(1, "sfgc", col) end
|
||||
local function w(s) syscall.write(1, tostring(s)) end
|
||||
@@ -250,9 +250,9 @@ local function getUserInput(prompt, history)
|
||||
local function redraw()
|
||||
syscall.devctl(1, "spos", ox, oy)
|
||||
w(input:sub(1, cursor-1))
|
||||
if blink then syscall.devctl(1,"sfgc",16); syscall.devctl(1,"sbgc",1) end
|
||||
if blink then syscall.devctl(1,"sfgc",0x000000); syscall.devctl(1,"sbgc",1) end
|
||||
w(cursor > #input and " " or input:sub(cursor, cursor))
|
||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.devctl(1,"sbgc",16)
|
||||
w(input:sub(cursor+1) .. " ")
|
||||
dirty = false
|
||||
end
|
||||
@@ -284,7 +284,7 @@ local function getUserInput(prompt, history)
|
||||
cursor = cursor - 1; dirty = true
|
||||
end
|
||||
elseif key == "\n" then
|
||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.devctl(1,"sbgc",16)
|
||||
syscall.devctl(1,"spos",ox,oy)
|
||||
w(input .. " \n")
|
||||
return input
|
||||
@@ -308,16 +308,16 @@ local history = {}
|
||||
|
||||
while true do
|
||||
local code = getUserInput("lua> ", history)
|
||||
if code == "" then goto continue end
|
||||
if code ~= "" then
|
||||
|
||||
while isIncomplete(code) do
|
||||
code = code .. "\n" .. getUserInput("... ", nil)
|
||||
while isIncomplete(code) do
|
||||
code = code .. "\n" .. getUserInput("... ", nil)
|
||||
end
|
||||
|
||||
if code ~= history[#history] then
|
||||
history[#history+1] = code
|
||||
end
|
||||
|
||||
runCode(code)
|
||||
end
|
||||
|
||||
if code ~= history[#history] then
|
||||
history[#history+1] = code
|
||||
end
|
||||
|
||||
runCode(code)
|
||||
::continue::
|
||||
end
|
||||
|
||||
@@ -135,16 +135,16 @@ local function pad(s, w)
|
||||
end
|
||||
|
||||
local function drawTop()
|
||||
tpos(1,1); tbg(4); tfg(16)
|
||||
tpos(1,1); tbg(0x0000FF); tfg(0x000000)
|
||||
local left = " edit" .. (fname and (" - "..fname) or "")
|
||||
if dirty then left = left .. " [+]" end
|
||||
local right = tostring(cy)..","..tostring(cx).." "
|
||||
twrite(pad(left..string.rep(" ", math.max(1, W-#left-#right))..right, W))
|
||||
tbg(16); tfg(1)
|
||||
tbg(0x000000); tfg(0xFFFFFF)
|
||||
end
|
||||
|
||||
local function drawBottom()
|
||||
tpos(1, H); tbg(4); tfg(16)
|
||||
tpos(1, H); tbg(0x0000FF); tfg(0x000000)
|
||||
if msg ~= "" then
|
||||
if msgErr then tbg(2) end
|
||||
twrite(pad(" "..msg, W))
|
||||
@@ -152,7 +152,7 @@ local function drawBottom()
|
||||
else
|
||||
twrite(pad(" ^W Save ^X Quit+Save ^P Quit ^K Cut ^U Paste ^F Find ^G Go", W))
|
||||
end
|
||||
tbg(16); tfg(1)
|
||||
tbg(0x000000); tfg(0xFFFFFF)
|
||||
end
|
||||
|
||||
local function drawLines(map)
|
||||
@@ -177,29 +177,29 @@ local function drawLines(map)
|
||||
local curCh = ci > #seg and " " or seg:sub(ci, ci)
|
||||
local after = seg:sub(ci+1)
|
||||
|
||||
tfg(1); tbg(16); twrite(before)
|
||||
if blinkState then tfg(16); tbg(1) else tfg(1); tbg(16) end
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(before)
|
||||
if blinkState then tfg(0x000000); tbg(0xFFFFFF) else tfg(0xFFFFFF); tbg(0x000000) end
|
||||
twrite(curCh)
|
||||
tfg(1); tbg(16); twrite(after)
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(after)
|
||||
local drawn = #before + 1 + #after
|
||||
if drawn < W then twrite(string.rep(" ", W - drawn)) end
|
||||
else
|
||||
if li == sLine and sPat ~= "" and entry[2] == 1 then
|
||||
local s, e = seg:find(sPat)
|
||||
if s then
|
||||
tfg(1); tbg(16); twrite(seg:sub(1,s-1))
|
||||
tfg(16); tbg(3); twrite(seg:sub(s,e))
|
||||
tfg(1); tbg(16); twrite(seg:sub(e+1))
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(seg:sub(1,s-1))
|
||||
tfg(0x000000); tbg(0x00FF00); twrite(seg:sub(s,e))
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(seg:sub(e+1))
|
||||
twrite(string.rep(" ", W - #seg))
|
||||
else
|
||||
tfg(1); tbg(16); twrite(pad(seg, W))
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(pad(seg, W))
|
||||
end
|
||||
else
|
||||
tfg(1); tbg(16); twrite(pad(seg, W))
|
||||
tfg(0xFFFFFF); tbg(0x000000); twrite(pad(seg, W))
|
||||
end
|
||||
end
|
||||
else
|
||||
tfg(13); tbg(16); twrite(pad("~", W)); tfg(1)
|
||||
tfg(0xDBDBDB); tbg(0x000000); twrite(pad("~", W)); tfg(0xFFFFFF)
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -212,15 +212,15 @@ local function redraw()
|
||||
drawLines(map)
|
||||
drawBottom()
|
||||
tpos(1, H)
|
||||
tbg(16); tfg(1)
|
||||
tbg(0x000000); tfg(0xFFFFFF)
|
||||
end
|
||||
|
||||
local function prompt(label, default)
|
||||
local inp = default or ""
|
||||
while true do
|
||||
tpos(1, H); tbg(3); tfg(16)
|
||||
tpos(1, H); tbg(0x00FF00); tfg(0x000000)
|
||||
twrite(pad(" "..label..inp.." ", W))
|
||||
tbg(16); tfg(1)
|
||||
tbg(0x000000); tfg(0xFFFFFF)
|
||||
local key = syscall.read(0)
|
||||
if not key or key == "" then sleep(0.02)
|
||||
elseif key == "" then return nil
|
||||
@@ -415,5 +415,5 @@ while running do
|
||||
end
|
||||
end
|
||||
|
||||
tclear(); tfg(1); tbg(16); tpos(1,1)
|
||||
tclear(); tfg(0xFFFFFF); tbg(0x000000); tpos(1,1)
|
||||
print("edit: exited"..(fname and (" - "..fname) or ""))
|
||||
|
||||
122
Src/sed/bin/sed
122
Src/sed/bin/sed
@@ -139,72 +139,68 @@ local function parseCommands(src)
|
||||
local c = src:sub(pos, pos)
|
||||
if c == "\n" or c == ";" then
|
||||
pos = pos + 1
|
||||
goto continue
|
||||
end
|
||||
if c == "#" then
|
||||
elseif c == "#" then
|
||||
while pos <= len and src:sub(pos,pos) ~= "\n" do pos = pos + 1 end
|
||||
goto continue
|
||||
end
|
||||
|
||||
local addr1, addr2
|
||||
addr1, pos = parseAddr(src, pos)
|
||||
skip()
|
||||
if addr1 and pos <= len and src:sub(pos,pos) == "," then
|
||||
pos = pos + 1
|
||||
skip()
|
||||
addr2, pos = parseAddr(src, pos)
|
||||
end
|
||||
skip()
|
||||
|
||||
if pos > len then break end
|
||||
local cmd = src:sub(pos, pos)
|
||||
pos = pos + 1
|
||||
|
||||
if cmd == "s" then
|
||||
local delim = src:sub(pos, pos); pos = pos + 1
|
||||
local pat, p1 = parseDelim(src, pos, delim); pos = p1
|
||||
local repl, p2 = parseDelim(src, pos, delim); pos = p2
|
||||
local flags = ""
|
||||
while pos <= len and src:sub(pos,pos):match("[giIp]") do
|
||||
flags = flags .. src:sub(pos,pos); pos = pos + 1
|
||||
end
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd="s",
|
||||
pat=pat, repl=repl, flags=flags })
|
||||
|
||||
elseif cmd == "y" then
|
||||
local delim = src:sub(pos, pos); pos = pos + 1
|
||||
local srcch, p1 = parseDelim(src, pos, delim); pos = p1
|
||||
local dstch, p2 = parseDelim(src, pos, delim); pos = p2
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd="y",
|
||||
src=srcch, dst=dstch })
|
||||
|
||||
elseif cmd == "d" or cmd == "p" or cmd == "q" or cmd == "=" then
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd=cmd })
|
||||
|
||||
elseif cmd == "{" then
|
||||
local depth = 1
|
||||
local start = pos
|
||||
while pos <= len and depth > 0 do
|
||||
local ch = src:sub(pos,pos)
|
||||
if ch == "{" then depth = depth + 1
|
||||
elseif ch == "}" then depth = depth - 1 end
|
||||
pos = pos + 1
|
||||
end
|
||||
local inner = src:sub(start, pos - 2)
|
||||
local innerCmds = parseCommands(inner)
|
||||
for _, ic in ipairs(innerCmds) do
|
||||
ic.addr1 = ic.addr1 or addr1
|
||||
ic.addr2 = ic.addr2 or addr2
|
||||
end
|
||||
for _, ic in ipairs(innerCmds) do
|
||||
table.insert(cmds, ic)
|
||||
end
|
||||
|
||||
elseif cmd == "\n" or cmd == ";" then
|
||||
else
|
||||
end
|
||||
|
||||
::continue::
|
||||
local addr1, addr2
|
||||
addr1, pos = parseAddr(src, pos)
|
||||
skip()
|
||||
if addr1 and pos <= len and src:sub(pos,pos) == "," then
|
||||
pos = pos + 1
|
||||
skip()
|
||||
addr2, pos = parseAddr(src, pos)
|
||||
end
|
||||
skip()
|
||||
|
||||
if pos > len then break end
|
||||
local cmd = src:sub(pos, pos)
|
||||
pos = pos + 1
|
||||
|
||||
if cmd == "s" then
|
||||
local delim = src:sub(pos, pos); pos = pos + 1
|
||||
local pat, p1 = parseDelim(src, pos, delim); pos = p1
|
||||
local repl, p2 = parseDelim(src, pos, delim); pos = p2
|
||||
local flags = ""
|
||||
while pos <= len and src:sub(pos,pos):match("[giIp]") do
|
||||
flags = flags .. src:sub(pos,pos); pos = pos + 1
|
||||
end
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd="s",
|
||||
pat=pat, repl=repl, flags=flags })
|
||||
|
||||
elseif cmd == "y" then
|
||||
local delim = src:sub(pos, pos); pos = pos + 1
|
||||
local srcch, p1 = parseDelim(src, pos, delim); pos = p1
|
||||
local dstch, p2 = parseDelim(src, pos, delim); pos = p2
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd="y",
|
||||
src=srcch, dst=dstch })
|
||||
|
||||
elseif cmd == "d" or cmd == "p" or cmd == "q" or cmd == "=" then
|
||||
table.insert(cmds, { addr1=addr1, addr2=addr2, cmd=cmd })
|
||||
|
||||
elseif cmd == "{" then
|
||||
local depth = 1
|
||||
local start = pos
|
||||
while pos <= len and depth > 0 do
|
||||
local ch = src:sub(pos,pos)
|
||||
if ch == "{" then depth = depth + 1
|
||||
elseif ch == "}" then depth = depth - 1 end
|
||||
pos = pos + 1
|
||||
end
|
||||
local inner = src:sub(start, pos - 2)
|
||||
local innerCmds = parseCommands(inner)
|
||||
for _, ic in ipairs(innerCmds) do
|
||||
ic.addr1 = ic.addr1 or addr1
|
||||
ic.addr2 = ic.addr2 or addr2
|
||||
end
|
||||
for _, ic in ipairs(innerCmds) do
|
||||
table.insert(cmds, ic)
|
||||
end
|
||||
|
||||
elseif cmd == "\n" or cmd == ";" then
|
||||
else
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return cmds
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
--:Minify:--
|
||||
local kernel=...
|
||||
local fs=require("fs")
|
||||
kernel.log("Sysinit started...")
|
||||
|
||||
for i,v in pairs(kernel.processes) do
|
||||
kernel.log("Spawning kernel task "..i)
|
||||
syscall.spawn(function()
|
||||
local status, err = pcall(v)
|
||||
if not status then
|
||||
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR")
|
||||
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Successfully executed kernel task: " .. i, "INFO")
|
||||
kernel.log("Successfully executed kernel task: " .. i)
|
||||
end
|
||||
end, i)
|
||||
end
|
||||
@@ -17,23 +18,24 @@ end
|
||||
if not fs.exists("/bin/startup") then
|
||||
fs.mkdir("/bin/startup")
|
||||
end
|
||||
|
||||
local files = fs.list("/bin/startup")
|
||||
if not files then error("Failed to list /bin/startup") end
|
||||
for i,v in ipairs(files) do
|
||||
if v:sub(-4) == ".lua" then
|
||||
local filepath = "/bin/startup/" .. v
|
||||
kernel.log("Executing startup script: " .. filepath, "INFO")
|
||||
kernel.log("Executing startup script: " .. filepath)
|
||||
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
|
||||
if not startupFunc then
|
||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR")
|
||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
syscall.spawn(function()
|
||||
syscall.setuid(1)
|
||||
local status, err = pcall(startupFunc)
|
||||
if not status then
|
||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR")
|
||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||
else
|
||||
kernel.log("Successfully executed startup script: " .. filepath, "INFO")
|
||||
kernel.log("Successfully executed startup script: " .. filepath)
|
||||
end
|
||||
end, "startup:" .. v)
|
||||
end
|
||||
|
||||
43
build.py
43
build.py
@@ -11,6 +11,8 @@ Targets:
|
||||
build-mini-test
|
||||
build-micro-test
|
||||
clean
|
||||
prod
|
||||
prod-mini
|
||||
|
||||
Arch flags:
|
||||
--arch cct
|
||||
@@ -32,6 +34,7 @@ PROJECT_ROOT = Path(__file__).resolve().parent
|
||||
SRC_ROOT = PROJECT_ROOT / "Src"
|
||||
TEST_ROOT = PROJECT_ROOT / "Test"
|
||||
BUILD_ROOT = PROJECT_ROOT / "Build"
|
||||
PROD_ROOT = PROJECT_ROOT / "prod"
|
||||
|
||||
ARCH_BOOT_DIR = {
|
||||
"cct": Path("boot") / "cct",
|
||||
@@ -46,6 +49,13 @@ def clean():
|
||||
else:
|
||||
print("Nothing to clean.")
|
||||
|
||||
def cleanprod():
|
||||
if PROD_ROOT.exists():
|
||||
print(f"Removing {PROD_ROOT} ...")
|
||||
shutil.rmtree(PROD_ROOT)
|
||||
else:
|
||||
print("Nothing to clean.")
|
||||
|
||||
|
||||
def has_minify_header(path: Path) -> bool:
|
||||
try:
|
||||
@@ -74,14 +84,19 @@ def compress_lz4(data: bytes) -> bytes:
|
||||
return lz4.frame.compress(data)
|
||||
|
||||
|
||||
def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool):
|
||||
def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool, arch:Union[str, None], prod:bool):
|
||||
print(f"Building from {src_root}")
|
||||
print(f"Output to {out_root}")
|
||||
print(f"Output to {out_root}")
|
||||
print()
|
||||
|
||||
for pkg_dir in sorted(src_root.iterdir()):
|
||||
if not pkg_dir.is_dir():
|
||||
continue
|
||||
|
||||
if pkg_dir.name[:18] == "Hyperion-firmware-":
|
||||
if pkg_dir.name != f"Hyperion-firmware-{arch}":
|
||||
if prod != True:
|
||||
continue
|
||||
|
||||
print(f"== Package: {pkg_dir.name} ==")
|
||||
|
||||
@@ -93,8 +108,11 @@ def process_root(src_root: Path, out_root: Path, minify: bool, micro: bool):
|
||||
|
||||
if rel.name=="$PKGCONFIG.ini":
|
||||
continue
|
||||
|
||||
|
||||
dst = out_root / rel
|
||||
if prod:
|
||||
dst = out_root / pkg_dir.name / rel
|
||||
|
||||
dst.parent.mkdir(parents=True, exist_ok=True)
|
||||
|
||||
print(f" Processing: {src.relative_to(src_root)}")
|
||||
@@ -128,13 +146,19 @@ def install_bootloader(arch: str, release: bool):
|
||||
shutil.copy2(eeprom, BUILD_ROOT / eeprom_dst_name)
|
||||
|
||||
|
||||
def run_build(minify: bool, micro: bool, include_test: bool, arch: Union[str, None], release: bool):
|
||||
def run_build(minify: bool, micro: bool, include_test: bool, arch: Union[str, None], release: bool, prod: bool):
|
||||
clean()
|
||||
BUILD_ROOT.mkdir()
|
||||
|
||||
if prod:
|
||||
cleanprod()
|
||||
PROD_ROOT.mkdir()
|
||||
|
||||
out_root = BUILD_ROOT / "$" if arch else BUILD_ROOT
|
||||
|
||||
process_root(SRC_ROOT, out_root, minify, micro)
|
||||
process_root(SRC_ROOT, out_root, minify, micro, arch, False)
|
||||
if prod:
|
||||
process_root(SRC_ROOT, PROD_ROOT, minify, micro, arch, True)
|
||||
|
||||
if include_test:
|
||||
process_root(TEST_ROOT, out_root, minify, micro)
|
||||
|
||||
@@ -196,9 +220,9 @@ def inject_makeusers(users, arch):
|
||||
|
||||
def main():
|
||||
parser = argparse.ArgumentParser(description="HyperionOS build script")
|
||||
parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean"])
|
||||
parser.add_argument("target", choices=["build", "build-mini", "build-micro", "build-test", "build-mini-test", "build-micro-test", "clean", "prod", "prod-mini"])
|
||||
parser.add_argument("--arch", choices=["cct", "oc"], default=None,
|
||||
help="Target architecture (cct or oc)")
|
||||
help="Target architecture")
|
||||
parser.add_argument("--release", dest="release", action="store_true", default=True,
|
||||
help="Release build: eeprom placed as startup.lua (default)")
|
||||
parser.add_argument("--dev", dest="release", action="store_false",
|
||||
@@ -222,6 +246,7 @@ def main():
|
||||
clean()
|
||||
return
|
||||
|
||||
prod = "prod" in args.target
|
||||
minify = "mini" in args.target or "micro" in args.target
|
||||
micro = "micro" in args.target
|
||||
include_test = "test" in args.target
|
||||
@@ -229,7 +254,7 @@ def main():
|
||||
if micro:
|
||||
import lz4.block
|
||||
|
||||
run_build(minify=minify, micro=micro, include_test=include_test, arch=args.arch, release=args.release)
|
||||
run_build(minify=minify, micro=micro, include_test=include_test, arch=args.arch, release=args.release, prod=prod)
|
||||
|
||||
if args.makeuser:
|
||||
print("Injecting first-boot user setup ...")
|
||||
|
||||
Binary file not shown.
@@ -1,157 +0,0 @@
|
||||
|
||||
local function octal_to_number(str)
|
||||
str = str:gsub("%z", ""):match("^%s*(.-)%s*$")
|
||||
return tonumber(str, 8) or 0
|
||||
end
|
||||
|
||||
local function dedupe_path(path)
|
||||
|
||||
local parts = {}
|
||||
for p in path:gmatch("[^/]+") do table.insert(parts, p) end
|
||||
|
||||
for prefix_len = 1, math.floor(#parts / 2) do
|
||||
local ok = true
|
||||
for i = 1, prefix_len do
|
||||
if parts[i] ~= parts[i + prefix_len] then
|
||||
ok = false
|
||||
break
|
||||
end
|
||||
end
|
||||
if ok then
|
||||
local cleaned = {}
|
||||
for i = 1, #parts - prefix_len do
|
||||
cleaned[#cleaned + 1] = parts[i + prefix_len]
|
||||
end
|
||||
return table.concat(cleaned, "/")
|
||||
end
|
||||
end
|
||||
|
||||
return path
|
||||
end
|
||||
|
||||
|
||||
local function make_dirs(root, path)
|
||||
local cur = root
|
||||
for part in path:gmatch("([^/]+)/") do
|
||||
if not cur[part] then
|
||||
cur[part] = { __type = "dir", __entries = {} }
|
||||
end
|
||||
cur = cur[part].__entries
|
||||
end
|
||||
return cur
|
||||
end
|
||||
|
||||
local function flatten(node, prefix)
|
||||
local out = {}
|
||||
prefix = prefix or ""
|
||||
|
||||
for name, obj in pairs(node) do
|
||||
local full = prefix .. name
|
||||
if obj.__type == "file" then
|
||||
out[#out+1] = {
|
||||
name = full,
|
||||
type = "file",
|
||||
contents = obj.__contents
|
||||
}
|
||||
elseif obj.__type == "dir" then
|
||||
out[#out+1] = {
|
||||
name = full .. "/",
|
||||
type = "dir",
|
||||
contents = flatten(obj.__entries, full .. "/")
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
return out
|
||||
end
|
||||
|
||||
local function unpack_tar(tarstr)
|
||||
local i = 1
|
||||
local len = #tarstr
|
||||
local root = {}
|
||||
|
||||
while i + 512 <= len do
|
||||
local header = tarstr:sub(i, i + 511)
|
||||
|
||||
if header:match("^\0+$") then break end
|
||||
|
||||
local name_raw = header:sub(1, 100):gsub("%z.*", "")
|
||||
local prefix_raw = header:sub(346, 500):gsub("%z.*", "")
|
||||
|
||||
local name
|
||||
if prefix_raw ~= "" then
|
||||
name = prefix_raw .. "/" .. name_raw
|
||||
else
|
||||
name = name_raw
|
||||
end
|
||||
|
||||
name = name:gsub("^%./", ""):gsub("/+", "/")
|
||||
|
||||
name = dedupe_path(name)
|
||||
|
||||
local size = octal_to_number(header:sub(125,136))
|
||||
local typeflag = header:sub(157,157)
|
||||
|
||||
i = i + 512
|
||||
|
||||
local contents = tarstr:sub(i, i + size - 1)
|
||||
local pad = (512 - (size % 512)) % 512
|
||||
i = i + size + pad
|
||||
|
||||
if name == "" then goto continue end
|
||||
|
||||
local is_dir = typeflag == "5" or name:sub(-1) == "/"
|
||||
|
||||
local clean_name = name:gsub("/$", "")
|
||||
if clean_name == "" then goto continue end
|
||||
|
||||
local parent_path = clean_name:match("(.+)/")
|
||||
local fname = clean_name:match("([^/]+)$")
|
||||
if not fname then goto continue end
|
||||
|
||||
local parent = root
|
||||
if parent_path then
|
||||
parent = make_dirs(root, parent_path .. "/")
|
||||
end
|
||||
|
||||
if is_dir then
|
||||
parent[fname] = parent[fname] or { __type = "dir", __entries = {} }
|
||||
else
|
||||
parent[fname] = { __type = "file", __contents = contents }
|
||||
end
|
||||
|
||||
::continue::
|
||||
end
|
||||
|
||||
return flatten(root)
|
||||
end
|
||||
|
||||
local function write_directory(prefix, items)
|
||||
for _, v in ipairs(items) do
|
||||
if v.type == "dir" then
|
||||
fs.makeDir(prefix..v.name)
|
||||
write_directory(prefix, v.contents)
|
||||
elseif v.type == "file" then
|
||||
local file = fs.open(prefix..v.name, "w")
|
||||
file.write(v.contents)
|
||||
file.close()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local in_tar = ({...})[1]
|
||||
local out_dir = ({...})[2]
|
||||
|
||||
if not in_tar or not out_dir then
|
||||
print("Usage: unpack_tar <tarfile> <output_dir>")
|
||||
return
|
||||
end
|
||||
|
||||
local f = fs.open(in_tar, "r")
|
||||
local tarstr = f.readAll()
|
||||
f.close()
|
||||
|
||||
local list = unpack_tar(tarstr)
|
||||
write_directory(out_dir, list)
|
||||
|
||||
print("TAR extracted into: " .. out_dir)
|
||||
@@ -1,27 +0,0 @@
|
||||
print("Hello, World!")
|
||||
sleep(1)
|
||||
term.clear()
|
||||
print("Do you want to install HyperionOS? [Y/n]")
|
||||
local input=read()
|
||||
if input=="y" or input=="Y" or input=="" then
|
||||
goto install
|
||||
else
|
||||
goto exit
|
||||
end
|
||||
|
||||
::install::
|
||||
print("Installing tar but bad...")
|
||||
shell.run("wget https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/1.2-dev/install/data/tarbad /tar.lua")
|
||||
print("Installing HyperionOS...")
|
||||
print("Installing precompiled tar")
|
||||
shell.run("wget https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/1.2-dev/install/data/Build.tar /Build.tar")
|
||||
shell.run("tar Build.tar /")
|
||||
print("Removing tar but bad...")
|
||||
shell.run("rm /tar.lua")
|
||||
shell.run("rm $")
|
||||
shell.run("cp Build $")
|
||||
shell.run("rm Build")
|
||||
shell.run("rm Build.tar")
|
||||
fs.copy("/$/boot/cct/eeprom","/startup.lua")
|
||||
dofile("startup.lua")
|
||||
::exit::
|
||||
229
installers/HyperionOS-install-cct.lua
Normal file
229
installers/HyperionOS-install-cct.lua
Normal file
@@ -0,0 +1,229 @@
|
||||
term.clear()
|
||||
term.setTextColor(colors.white)
|
||||
term.setCursorPos(1,1)
|
||||
print("HyperionOS CCT Installer //")
|
||||
local w,h = term.getSize()
|
||||
local exitall,releasename,packagelist=false,"",{}
|
||||
|
||||
local function printc(...)
|
||||
local args={...}
|
||||
for i=1, #args do
|
||||
if type(args[i]) == "number" then
|
||||
term.setTextColor(args[i])
|
||||
else
|
||||
term.write(args[i])
|
||||
end
|
||||
end
|
||||
print("")
|
||||
end
|
||||
|
||||
local function download(url)
|
||||
printc(colors.gray, "[ ", colors.green, " FETCH ", colors.gray, " ] ", colors.white, url)
|
||||
local data,err=http.get(url)
|
||||
if not data then error(err) end
|
||||
local text=data.readAll()
|
||||
data.close()
|
||||
return text
|
||||
end
|
||||
|
||||
local function writeFile(path, data)
|
||||
printc(colors.gray, "[ ", colors.green, "WRITING", colors.gray, " ] ", colors.white, path)
|
||||
local file=fs.open(path, "w")
|
||||
file.write(data)
|
||||
file.close()
|
||||
end
|
||||
|
||||
print("Installing JSON to /hyinstall/json...")
|
||||
writeFile("/hyinstall/json",download("https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/misc/json"))
|
||||
print("Loading JSON...")
|
||||
local json=loadfile("/hyinstall/json")()
|
||||
|
||||
local function printTitle()
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.white)
|
||||
print("HyperionOS CCT Installer //")
|
||||
print("Orange is prerelease...")
|
||||
term.setCursorPos(1,h-1)
|
||||
print("DESCLAIMER: This will wipe your system on install...")
|
||||
term.write("Bspc: Back | Enter: execute | Tab: description")
|
||||
end
|
||||
printTitle()
|
||||
|
||||
local function pc(text, y, c)
|
||||
local x=(w/2)-#text/2
|
||||
term.setTextColor(c)
|
||||
term.setCursorPos(x, y)
|
||||
term.write(text)
|
||||
end
|
||||
|
||||
local function drawMenu(menu, sel)
|
||||
local y=(h/2)-#menu/2
|
||||
for i,v in ipairs(menu) do
|
||||
if i==sel then
|
||||
pc("[ "..v.name.." ]", y+i, v.color)
|
||||
else
|
||||
pc(v.name, y+i, v.color)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function desc(description)
|
||||
term.clear()
|
||||
term.setTextColor(colors.white)
|
||||
term.setCursorPos(1,1)
|
||||
print("HyperionOS CCT Installer //\n")
|
||||
print(description)
|
||||
term.setCursorPos(1,h)
|
||||
term.write("Press enter to continue...")
|
||||
while not exitall do
|
||||
local _,key = os.pullEvent("key")
|
||||
if key==keys.enter then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function menu(m)
|
||||
local exit,sel=false,1
|
||||
while not exit and not exitall do
|
||||
printTitle()
|
||||
drawMenu(m, sel)
|
||||
local _,key = os.pullEvent("key")
|
||||
if key==keys.down then
|
||||
if sel<#m then
|
||||
sel=sel+1
|
||||
end
|
||||
elseif key==keys.up then
|
||||
if sel>1 then
|
||||
sel=sel-1
|
||||
end
|
||||
elseif key==keys.enter then
|
||||
m[sel].func()
|
||||
elseif key==keys.tab then
|
||||
desc(m[sel].desc)
|
||||
elseif key==keys.backspace then
|
||||
exit=true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local releases,page={},1
|
||||
while true do
|
||||
local handle=http.get("https://git.astronand.dev/api/v1/repos/Hyperion/HyperionOS/releases?page="..tostring(page).."&limit=1")
|
||||
local raw=handle.readAll()
|
||||
handle.close()
|
||||
if raw=="[]\n" then
|
||||
break
|
||||
end
|
||||
releases[page]=json.decode(raw)[1]
|
||||
page=page+1
|
||||
end
|
||||
|
||||
local function makePage(start, num)
|
||||
local m={}
|
||||
for i=start, num do
|
||||
if not releases[i] then break end
|
||||
local release=releases[i]
|
||||
m[#m+1]={
|
||||
name=release.name,
|
||||
desc=release.body,
|
||||
color=release.prerelease and colors.orange or colors.white,
|
||||
func=function()
|
||||
local data=download("https://git.astronand.dev/Hyperion/HyperionOS/raw/tag/"..release.tag_name.."/Src/install.json")
|
||||
if not data then
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
print("Unable to find package list for ver "..release.tag_name..":\n"..err)
|
||||
sleep(3)
|
||||
return
|
||||
end
|
||||
releasename=release.tag_name
|
||||
packagelist=json.decode(data)
|
||||
exitall=true
|
||||
end
|
||||
}
|
||||
end
|
||||
if #releases>start+num then
|
||||
m[#m+1]={
|
||||
name="Next",
|
||||
desc="Next menu",
|
||||
color=colors.cyan,
|
||||
func=function()
|
||||
local menudata=makePage(start+num, num)
|
||||
menu(menudata)
|
||||
end
|
||||
}
|
||||
end
|
||||
return m
|
||||
end
|
||||
|
||||
menu(makePage(1,5))
|
||||
term.clear()
|
||||
term.setCursorPos(1,1)
|
||||
term.setTextColor(colors.white)
|
||||
term.write("Formating disk in ")
|
||||
for i=5, 1, -1 do
|
||||
term.write(tostring(i))
|
||||
sleep(.25)
|
||||
for v=1, 3 do
|
||||
term.write(".")
|
||||
sleep(.25)
|
||||
end
|
||||
end
|
||||
print("")
|
||||
|
||||
local function delDir(dir)
|
||||
printc(colors.gray, "[ ", colors.green, " LSDIR ", colors.gray, " ] ", colors.white, dir)
|
||||
local list=fs.list(dir)
|
||||
printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir)
|
||||
for i=1, #list do
|
||||
if fs.isDir(dir..list[i]) then
|
||||
if dir..list[i] ~= "/rom" then
|
||||
delDir(dir..list[i].."/")
|
||||
fs.delete(dir..list[i])
|
||||
end
|
||||
else
|
||||
fs.delete(dir..list[i])
|
||||
printc(colors.gray, "[ ", colors.red, " DELET ", colors.gray, " ] ", colors.white, dir..list[i])
|
||||
end
|
||||
sleep(.1)
|
||||
end
|
||||
end
|
||||
|
||||
delDir("/")
|
||||
|
||||
print("")
|
||||
printc(colors.cyan, " \\\\Installing//")
|
||||
print("")
|
||||
printc(colors.white, "Getting package list...")
|
||||
|
||||
local function installdir(path, dir, pkg)
|
||||
local data=json.decode(download("https://git.astronand.dev/api/v1/repos/Hyperion/HyperionOS/contents/prod/"..pkg..dir.."?ref="..releasename))
|
||||
if not data then error("Uh Oh: JSON decode error...") end
|
||||
for i=1, #data do
|
||||
local entry=data[i]
|
||||
if entry.type == "dir" then
|
||||
installdir(path, dir..entry.name.."/", pkg)
|
||||
elseif entry.type == "file" then
|
||||
writeFile(path..dir..entry.name, download(entry.download_url))
|
||||
else
|
||||
error("Uh Oh: unknown entrytype "..entry.path)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function installpkg(pkg)
|
||||
installdir("/$", "/", pkg)
|
||||
end
|
||||
|
||||
for i=1, #packagelist do
|
||||
installpkg(packagelist[i])
|
||||
end
|
||||
|
||||
installpkg("Hyperion-firmware-cct")
|
||||
fs.copy("/$/boot/cct/eeprom", "/startup.lua")
|
||||
|
||||
printc(colors.white, "Rebooting...")
|
||||
sleep(1)
|
||||
os.reboot()
|
||||
15
manifest.lua
15
manifest.lua
@@ -144,9 +144,14 @@ syscall.dup=function(fd) end
|
||||
|
||||
--- Read GPIO pin
|
||||
--- @param pin integer
|
||||
--- @return number|nil
|
||||
--- @return boolean|nil
|
||||
syscall.gpio_read=function(pin) end
|
||||
|
||||
--- Read GPIO pin analog
|
||||
--- @param pin integer
|
||||
--- @return number|nil
|
||||
syscall.gpio_readAnalog=function(pin) end
|
||||
|
||||
--- Get SUID bit from fd
|
||||
--- @param fd integer
|
||||
--- @return boolean
|
||||
@@ -154,10 +159,14 @@ syscall.fget_suid=function(fd) end
|
||||
|
||||
--- Write GPIO pin
|
||||
--- @param pin integer
|
||||
--- @param data number
|
||||
--- @return boolean
|
||||
--- @param data boolean
|
||||
syscall.gpio_write=function(pin, data) end
|
||||
|
||||
--- Write GPIO pin analog
|
||||
--- @param pin integer
|
||||
--- @param data number
|
||||
syscall.gpio_writeAnalog=function(pin, data) end
|
||||
|
||||
--- Set password for user
|
||||
--- @param uid integer
|
||||
--- @param newPassword string
|
||||
|
||||
388
misc/json
Normal file
388
misc/json
Normal file
@@ -0,0 +1,388 @@
|
||||
--:Minify:--
|
||||
-- json.lua
|
||||
--
|
||||
-- Copyright (c) 2020 rxi
|
||||
--
|
||||
-- Permission is hereby granted, free of charge, to any person obtaining a copy of
|
||||
-- this software and associated documentation files (the "Software"), to deal in
|
||||
-- the Software without restriction, including without limitation the rights to
|
||||
-- use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
||||
-- of the Software, and to permit persons to whom the Software is furnished to do
|
||||
-- so, subject to the following conditions:
|
||||
--
|
||||
-- The above copyright notice and this permission notice shall be included in all
|
||||
-- copies or substantial portions of the Software.
|
||||
--
|
||||
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
-- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
-- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
-- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
-- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
-- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
-- SOFTWARE.
|
||||
--
|
||||
|
||||
local json = { _version = "0.1.2" }
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Encode
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local encode
|
||||
|
||||
local escape_char_map = {
|
||||
[ "\\" ] = "\\",
|
||||
[ "\"" ] = "\"",
|
||||
[ "\b" ] = "b",
|
||||
[ "\f" ] = "f",
|
||||
[ "\n" ] = "n",
|
||||
[ "\r" ] = "r",
|
||||
[ "\t" ] = "t",
|
||||
}
|
||||
|
||||
local escape_char_map_inv = { [ "/" ] = "/" }
|
||||
for k, v in pairs(escape_char_map) do
|
||||
escape_char_map_inv[v] = k
|
||||
end
|
||||
|
||||
|
||||
local function escape_char(c)
|
||||
return "\\" .. (escape_char_map[c] or string.format("u%04x", c:byte()))
|
||||
end
|
||||
|
||||
|
||||
local function encode_nil(val)
|
||||
return "null"
|
||||
end
|
||||
|
||||
|
||||
local function encode_table(val, stack)
|
||||
local res = {}
|
||||
stack = stack or {}
|
||||
|
||||
-- Circular reference?
|
||||
if stack[val] then error("circular reference") end
|
||||
|
||||
stack[val] = true
|
||||
|
||||
if rawget(val, 1) ~= nil or next(val) == nil then
|
||||
-- Treat as array -- check keys are valid and it is not sparse
|
||||
local n = 0
|
||||
for k in pairs(val) do
|
||||
if type(k) ~= "number" then
|
||||
error("invalid table: mixed or invalid key types")
|
||||
end
|
||||
n = n + 1
|
||||
end
|
||||
if n ~= #val then
|
||||
error("invalid table: sparse array")
|
||||
end
|
||||
-- Encode
|
||||
for i, v in ipairs(val) do
|
||||
table.insert(res, encode(v, stack))
|
||||
end
|
||||
stack[val] = nil
|
||||
return "[" .. table.concat(res, ",") .. "]"
|
||||
|
||||
else
|
||||
-- Treat as an object
|
||||
for k, v in pairs(val) do
|
||||
if type(k) ~= "string" then
|
||||
error("invalid table: mixed or invalid key types")
|
||||
end
|
||||
table.insert(res, encode(k, stack) .. ":" .. encode(v, stack))
|
||||
end
|
||||
stack[val] = nil
|
||||
return "{" .. table.concat(res, ",") .. "}"
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function encode_string(val)
|
||||
return '"' .. val:gsub('[%z\1-\31\\"]', escape_char) .. '"'
|
||||
end
|
||||
|
||||
|
||||
local function encode_number(val)
|
||||
-- Check for NaN, -inf and inf
|
||||
if val ~= val or val <= -math.huge or val >= math.huge then
|
||||
error("unexpected number value '" .. tostring(val) .. "'")
|
||||
end
|
||||
return string.format("%.14g", val)
|
||||
end
|
||||
|
||||
|
||||
local type_func_map = {
|
||||
[ "nil" ] = encode_nil,
|
||||
[ "table" ] = encode_table,
|
||||
[ "string" ] = encode_string,
|
||||
[ "number" ] = encode_number,
|
||||
[ "boolean" ] = tostring,
|
||||
}
|
||||
|
||||
|
||||
encode = function(val, stack)
|
||||
local t = type(val)
|
||||
local f = type_func_map[t]
|
||||
if f then
|
||||
return f(val, stack)
|
||||
end
|
||||
error("unexpected type '" .. t .. "'")
|
||||
end
|
||||
|
||||
|
||||
function json.encode(val)
|
||||
return ( encode(val) )
|
||||
end
|
||||
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Decode
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local parse
|
||||
|
||||
local function create_set(...)
|
||||
local res = {}
|
||||
for i = 1, select("#", ...) do
|
||||
res[ select(i, ...) ] = true
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local space_chars = create_set(" ", "\t", "\r", "\n")
|
||||
local delim_chars = create_set(" ", "\t", "\r", "\n", "]", "}", ",")
|
||||
local escape_chars = create_set("\\", "/", '"', "b", "f", "n", "r", "t", "u")
|
||||
local literals = create_set("true", "false", "null")
|
||||
|
||||
local literal_map = {
|
||||
[ "true" ] = true,
|
||||
[ "false" ] = false,
|
||||
[ "null" ] = nil,
|
||||
}
|
||||
|
||||
|
||||
local function next_char(str, idx, set, negate)
|
||||
for i = idx, #str do
|
||||
if set[str:sub(i, i)] ~= negate then
|
||||
return i
|
||||
end
|
||||
end
|
||||
return #str + 1
|
||||
end
|
||||
|
||||
|
||||
local function decode_error(str, idx, msg)
|
||||
local line_count = 1
|
||||
local col_count = 1
|
||||
for i = 1, idx - 1 do
|
||||
col_count = col_count + 1
|
||||
if str:sub(i, i) == "\n" then
|
||||
line_count = line_count + 1
|
||||
col_count = 1
|
||||
end
|
||||
end
|
||||
error( string.format("%s at line %d col %d", msg, line_count, col_count) )
|
||||
end
|
||||
|
||||
|
||||
local function codepoint_to_utf8(n)
|
||||
-- http://scripts.sil.org/cms/scripts/page.php?site_id=nrsi&id=iws-appendixa
|
||||
local f = math.floor
|
||||
if n <= 0x7f then
|
||||
return string.char(n)
|
||||
elseif n <= 0x7ff then
|
||||
return string.char(f(n / 64) + 192, n % 64 + 128)
|
||||
elseif n <= 0xffff then
|
||||
return string.char(f(n / 4096) + 224, f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||
elseif n <= 0x10ffff then
|
||||
return string.char(f(n / 262144) + 240, f(n % 262144 / 4096) + 128,
|
||||
f(n % 4096 / 64) + 128, n % 64 + 128)
|
||||
end
|
||||
error( string.format("invalid unicode codepoint '%x'", n) )
|
||||
end
|
||||
|
||||
|
||||
local function parse_unicode_escape(s)
|
||||
local n1 = tonumber( s:sub(1, 4), 16 )
|
||||
local n2 = tonumber( s:sub(7, 10), 16 )
|
||||
-- Surrogate pair?
|
||||
if n2 then
|
||||
return codepoint_to_utf8((n1 - 0xd800) * 0x400 + (n2 - 0xdc00) + 0x10000)
|
||||
else
|
||||
return codepoint_to_utf8(n1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
local function parse_string(str, i)
|
||||
local res = ""
|
||||
local j = i + 1
|
||||
local k = j
|
||||
|
||||
while j <= #str do
|
||||
local x = str:byte(j)
|
||||
|
||||
if x < 32 then
|
||||
decode_error(str, j, "control character in string")
|
||||
|
||||
elseif x == 92 then -- `\`: Escape
|
||||
res = res .. str:sub(k, j - 1)
|
||||
j = j + 1
|
||||
local c = str:sub(j, j)
|
||||
if c == "u" then
|
||||
local hex = str:match("^[dD][89aAbB]%x%x\\u%x%x%x%x", j + 1)
|
||||
or str:match("^%x%x%x%x", j + 1)
|
||||
or decode_error(str, j - 1, "invalid unicode escape in string")
|
||||
res = res .. parse_unicode_escape(hex)
|
||||
j = j + #hex
|
||||
else
|
||||
if not escape_chars[c] then
|
||||
decode_error(str, j - 1, "invalid escape char '" .. c .. "' in string")
|
||||
end
|
||||
res = res .. escape_char_map_inv[c]
|
||||
end
|
||||
k = j + 1
|
||||
|
||||
elseif x == 34 then -- `"`: End of string
|
||||
res = res .. str:sub(k, j - 1)
|
||||
return res, j + 1
|
||||
end
|
||||
|
||||
j = j + 1
|
||||
end
|
||||
|
||||
decode_error(str, i, "expected closing quote for string")
|
||||
end
|
||||
|
||||
|
||||
local function parse_number(str, i)
|
||||
local x = next_char(str, i, delim_chars)
|
||||
local s = str:sub(i, x - 1)
|
||||
local n = tonumber(s)
|
||||
if not n then
|
||||
decode_error(str, i, "invalid number '" .. s .. "'")
|
||||
end
|
||||
return n, x
|
||||
end
|
||||
|
||||
|
||||
local function parse_literal(str, i)
|
||||
local x = next_char(str, i, delim_chars)
|
||||
local word = str:sub(i, x - 1)
|
||||
if not literals[word] then
|
||||
decode_error(str, i, "invalid literal '" .. word .. "'")
|
||||
end
|
||||
return literal_map[word], x
|
||||
end
|
||||
|
||||
|
||||
local function parse_array(str, i)
|
||||
local res = {}
|
||||
local n = 1
|
||||
i = i + 1
|
||||
while 1 do
|
||||
local x
|
||||
i = next_char(str, i, space_chars, true)
|
||||
-- Empty / end of array?
|
||||
if str:sub(i, i) == "]" then
|
||||
i = i + 1
|
||||
break
|
||||
end
|
||||
-- Read token
|
||||
x, i = parse(str, i)
|
||||
res[n] = x
|
||||
n = n + 1
|
||||
-- Next token
|
||||
i = next_char(str, i, space_chars, true)
|
||||
local chr = str:sub(i, i)
|
||||
i = i + 1
|
||||
if chr == "]" then break end
|
||||
if chr ~= "," then decode_error(str, i, "expected ']' or ','") end
|
||||
end
|
||||
return res, i
|
||||
end
|
||||
|
||||
|
||||
local function parse_object(str, i)
|
||||
local res = {}
|
||||
i = i + 1
|
||||
while 1 do
|
||||
local key, val
|
||||
i = next_char(str, i, space_chars, true)
|
||||
-- Empty / end of object?
|
||||
if str:sub(i, i) == "}" then
|
||||
i = i + 1
|
||||
break
|
||||
end
|
||||
-- Read key
|
||||
if str:sub(i, i) ~= '"' then
|
||||
decode_error(str, i, "expected string for key")
|
||||
end
|
||||
key, i = parse(str, i)
|
||||
-- Read ':' delimiter
|
||||
i = next_char(str, i, space_chars, true)
|
||||
if str:sub(i, i) ~= ":" then
|
||||
decode_error(str, i, "expected ':' after key")
|
||||
end
|
||||
i = next_char(str, i + 1, space_chars, true)
|
||||
-- Read value
|
||||
val, i = parse(str, i)
|
||||
-- Set
|
||||
res[key] = val
|
||||
-- Next token
|
||||
i = next_char(str, i, space_chars, true)
|
||||
local chr = str:sub(i, i)
|
||||
i = i + 1
|
||||
if chr == "}" then break end
|
||||
if chr ~= "," then decode_error(str, i, "expected '}' or ','") end
|
||||
end
|
||||
return res, i
|
||||
end
|
||||
|
||||
|
||||
local char_func_map = {
|
||||
[ '"' ] = parse_string,
|
||||
[ "0" ] = parse_number,
|
||||
[ "1" ] = parse_number,
|
||||
[ "2" ] = parse_number,
|
||||
[ "3" ] = parse_number,
|
||||
[ "4" ] = parse_number,
|
||||
[ "5" ] = parse_number,
|
||||
[ "6" ] = parse_number,
|
||||
[ "7" ] = parse_number,
|
||||
[ "8" ] = parse_number,
|
||||
[ "9" ] = parse_number,
|
||||
[ "-" ] = parse_number,
|
||||
[ "t" ] = parse_literal,
|
||||
[ "f" ] = parse_literal,
|
||||
[ "n" ] = parse_literal,
|
||||
[ "[" ] = parse_array,
|
||||
[ "{" ] = parse_object,
|
||||
}
|
||||
|
||||
|
||||
parse = function(str, idx)
|
||||
local chr = str:sub(idx, idx)
|
||||
local f = char_func_map[chr]
|
||||
if f then
|
||||
return f(str, idx)
|
||||
end
|
||||
decode_error(str, idx, "unexpected character '" .. chr .. "'")
|
||||
end
|
||||
|
||||
|
||||
function json.decode(str)
|
||||
if type(str) ~= "string" then
|
||||
error("expected argument of type string, got " .. type(str))
|
||||
end
|
||||
local res, idx = parse(str, next_char(str, 1, space_chars, true))
|
||||
idx = next_char(str, idx, space_chars, true)
|
||||
if idx <= #str then
|
||||
decode_error(str, idx, "trailing garbage")
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
return json
|
||||
1
prod/Hyperion-core/lib/colors
Normal file
1
prod/Hyperion-core/lib/colors
Normal file
@@ -0,0 +1 @@
|
||||
return{white=0xFFFFFF,red=0xFF0000,green=0x00FF00,blue=0x0000FF,cyan=0x00FFFF,yellow=0xFFFF00,purple=0xFF00FF,black=0x000000,gray=0x888888,lightgrey=0xBBBBBB,darkgrey=0x444444,orange=0xFF8800,mint=0x00FF88,brown=0xa52a2a,chocolate=0xd2691e}
|
||||
1
prod/Hyperion-core/lib/fs
Normal file
1
prod/Hyperion-core/lib/fs
Normal file
@@ -0,0 +1 @@
|
||||
local a={}function a.open(b,c)local d=syscall.open(b,c)local e={close=function()return syscall.close(d)end,flush=function()syscall.fsync(d)end}if c=="r"then e.read=function(f)local g=syscall.read(d,f)return g end;e.readAll=function(h)local i={}while true do local j=syscall.read(d,h or 65536)if j==nil or#j==0 then break end;table.insert(i,j)end;return table.concat(i)end;e.readLine=function(h)local k={}local l=""local m=h or 65536;local n=false;while true do local o=l:find("\n")if o then local p=l:sub(1,o-1)l=l:sub(o+1)return p end;if n then if l~=""then local q=l;l=""return q else return nil end end;local j=syscall.read(d,m)if not j or j==""then n=true else l=l..j end end end elseif c=="w"then e.write=function(g)return syscall.write(d,g)end elseif c=="a"then e.write=function(g)return syscall.write(d,g)end else error("Invalid mode '"..c.."'",2)end;return e end;function a.readAllText(b)local r=a.open(b,"r")if not r then return false end;local s=r.readAll()r.close()return s end;function a.writeAllText(b,g)local r=a.open(b,"w")r.write(g)r.close()end;function a.appendAllText(b,g)local r=a.open(b,"a")if not r then return false end;r.write(g)r.close()end;function a.mkdir(b)return syscall.mkdir(b)end;function a.remove(b)return syscall.remove(b)end;function a.list(b)return syscall.listdir(b)end;function a.type(b)return syscall.type(b)end;function a.stat(b)return syscall.stat(b)end;function a.exists(b)return syscall.exists(b)end;function a.getcwd()return syscall.getcwd()end;function a.chdir(b)return syscall.chdir(b)end;function a.isDir(b)return syscall.type(b)=="directory"end;return a
|
||||
6
prod/Hyperion-core/lib/io
Normal file
6
prod/Hyperion-core/lib/io
Normal file
@@ -0,0 +1,6 @@
|
||||
local io = {}
|
||||
local fs = require("fs")
|
||||
|
||||
function io.open(path, mode)
|
||||
return fs.open(path, mode)
|
||||
end
|
||||
1
prod/Hyperion-firmware-ac/boot/ac/boot.lua
Normal file
1
prod/Hyperion-firmware-ac/boot/ac/boot.lua
Normal file
File diff suppressed because one or more lines are too long
1
prod/Hyperion-firmware-ccpc/boot/ccpc/boot.lua
Normal file
1
prod/Hyperion-firmware-ccpc/boot/ccpc/boot.lua
Normal file
File diff suppressed because one or more lines are too long
1
prod/Hyperion-firmware-ccpc/boot/ccpc/eeprom
Normal file
1
prod/Hyperion-firmware-ccpc/boot/ccpc/eeprom
Normal file
@@ -0,0 +1 @@
|
||||
local a=({...})[1]or"/$"local b={...}local c={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 d={}for e in pairs(_G)do if not c[e]then table.insert(d,e)end end;for f,e in ipairs(d)do _G[e]=nil end;local g=_G.term.native()for f,h in ipairs{"nativePaletteColor","nativePaletteColour","screenshot"}do g[h]=_G.term[h]end;_G.term=g;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 i={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 e,j in pairs(i)do for f,k in ipairs(j)do _G[e][k]=nil end end;local l=error;_G.error=function()end;_G.term.redirect=function()end;function _G.term.native()_G.term.native=nil;_G.term.redirect=nil;_G.error=l;term.setBackgroundColor(32768)term.setTextColor(1)term.setCursorPos(1,1)term.setCursorBlink(true)term.clear()local m=fs.open(a.."/boot/cct/boot.lua","r")if m==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;local n,o=loadstring(m.readAll(),"@bootloader")m.close()if n==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write(o)term.setCursorPos(1,3)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;setfenv(n,_G)local p=os.shutdown;os.shutdown=function()os.shutdown=p;return n(a)end end;if debug then local function q(r,s,t,u)local v,w,x=1,debug.getupvalue(r[s],u)while w~=t and w~=nil do w,x=debug.getupvalue(r[s],v)v=v+1 end;r[s]=x or r[s]end;q(_G,"loadstring","nativeloadstring",1)q(_G,"load","nativeload",5)if http then q(http,"request","nativeHTTPRequest",3)end;q(os,"shutdown","nativeShutdown",1)q(os,"reboot","nativeReboot",1)if turtle then q(turtle,"equipLeft","v",1)q(turtle,"equipRight","v",1)end;do local v,w,x=1,debug.getupvalue(peripheral.isPresent,2)while w~="native"and w~=nil do w,x=debug.getupvalue(peripheral.isPresent,v)v=v+1 end;_G.peripheral=x or peripheral end end
|
||||
1
prod/Hyperion-firmware-ccpc/boot/ccpc/initdisks
Normal file
1
prod/Hyperion-firmware-ccpc/boot/ccpc/initdisks
Normal file
@@ -0,0 +1 @@
|
||||
local a=({...})[1]local b=a.BOOT_DRIVE_PATH;local c=a.fs;local d=a.peripheral;local e={}local f={"top","bottom","left","right","front","back"}function e.getNames()local g={}for h=1,#f do local i=f[h]if d.isPresent(i)then table.insert(g,i)if d.hasType(i,"peripheral_hub")then local j=d.call(i,"getNamesRemote")for k,l in ipairs(j)do table.insert(g,l)end end end end;return g end;function e.isPresent(l)if d.isPresent(l)then return true end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return true end end;return false end;function e.getType(e)if type(e)=="string"then if d.isPresent(e)then return d.getType(e)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"getTypeRemote",e)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(m.types)end end;function e.hasType(e,n)if type(e)=="string"then if d.isPresent(e)then return d.hasType(e,n)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"hasTypeRemote",e,n)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return m.types[n]~=nil end end;function e.getMethods(l)if d.isPresent(l)then return d.getMethods(l)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"getMethodsRemote",l)end end;return nil end;function e.getName(e)local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return m.name end;function e.call(l,o,...)if d.isPresent(l)then return d.call(l,o,...)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"callRemote",l,o,...)end end;return nil end;function e.wrap(l)local p=e.getMethods(l)if not p then return nil end;local q={e.getType(l)}for r=1,#q do q[q[r]]=true end;local s=setmetatable({},{__name="peripheral",name=l,type=q[1],types=q})for k,o in ipairs(p)do s[o]=function(...)return e.call(l,o,...)end end;return s end;function e.find(t,u)local g={}for k,l in ipairs(e.getNames())do if e.hasType(l,t)then local v=e.wrap(l)if u==nil or u(l,v)then table.insert(g,v)end end end;return table.unpack(g)end;local w={}local x={}local function y(z)if not z or z==""then return"/"end;return c.combine("/",z)end;local function A(B,C,D,E)C=y(C)local F={address=B,isReadOnly=function()return D end}function F:spaceUsed()return c.getCapacity(C)-c.getFreeSpace(C)end;function F:spaceTotal()return c.getCapacity(C)end;function F:list(z)local G=c.combine(C,z)if not c.exists(G)or not c.isDir(G)then return nil,"not directory"end;return c.list(G)end;function F:fileExists(z)local G=c.combine(C,z)return c.exists(G)and not c.isDir(G)end;function F:directoryExists(z)local G=c.combine(C,z)return c.exists(G)and c.isDir(G)end;function F:type(z)local G=c.combine(C,z)if not c.exists(G)then return nil elseif c.isDir(G)then return"directory"else return"file"end end;function F:makeDirectory(z)local G=c.combine(C,z)c.makeDir(G)return true end;function F:remove(z)local G=c.combine(C,z)if c.exists(G)then c.delete(G)end;return true end;function F:setLabel(H)E.setLabel(H)end;function F:getLabel(H)return E.getLabel()end;function F:attributes(z)local G=c.combine(C,z)return c.attributes(G)end;function F:open(z,I)local G=c.combine(C,z)return c.open(G,I)end;return F end;x["$"]=A("$",b,false,{setLabel=function(H)local J=c.open("/.label","w")J.write(H)J.close()end,getLabel=function()local J=c.open("/.label","r")if not J then return"$"end;local H=J.readAll()J.close()return H end})x["rom"]=A("rom","/rom",true,{setLabel=function(H)error("Device is read-only")end,getLabel=function()return"cctrom"end})local function K()w={}for k,F in ipairs({e.find("drive")})do if F.isDiskPresent()then w[tostring(F.getDiskID())]=A("cctdisk"..tostring(F.getDiskID()),F.getMountPath(),false,c)end end end;local function L()K()local M={}for B,N in pairs(x)do M[B]=N end;for B,N in pairs(w)do M[B]=N end;return pairs(M)end;return{refresh=K,list=L}
|
||||
1
prod/Hyperion-firmware-ccpc/lib/modules/ccpc/25_gfx.kmod
Normal file
1
prod/Hyperion-firmware-ccpc/lib/modules/ccpc/25_gfx.kmod
Normal file
File diff suppressed because one or more lines are too long
1
prod/Hyperion-firmware-cct/boot/cct/boot.lua
Normal file
1
prod/Hyperion-firmware-cct/boot/cct/boot.lua
Normal file
File diff suppressed because one or more lines are too long
1
prod/Hyperion-firmware-cct/boot/cct/eeprom
Normal file
1
prod/Hyperion-firmware-cct/boot/cct/eeprom
Normal file
@@ -0,0 +1 @@
|
||||
local a=({...})[1]or"/$"local b={...}local c={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 d={}for e in pairs(_G)do if not c[e]then table.insert(d,e)end end;for f,e in ipairs(d)do _G[e]=nil end;local g=_G.term.native()for f,h in ipairs{"nativePaletteColor","nativePaletteColour","screenshot"}do g[h]=_G.term[h]end;_G.term=g;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 i={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 e,j in pairs(i)do for f,k in ipairs(j)do _G[e][k]=nil end end;local l=error;_G.error=function()end;_G.term.redirect=function()end;function _G.term.native()_G.term.native=nil;_G.term.redirect=nil;_G.error=l;term.setBackgroundColor(32768)term.setTextColor(1)term.setCursorPos(1,1)term.setCursorBlink(true)term.clear()local m=fs.open(a.."/boot/cct/boot.lua","r")if m==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not find /boot/cct/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;local n,o=loadstring(m.readAll(),"@bootloader")m.close()if n==nil then term.setCursorBlink(false)term.setTextColor(16384)term.write("Could not load /boot/cc/boot.lua. UnBIOS cannot continue.")term.setCursorPos(1,2)term.write(o)term.setCursorPos(1,3)term.write("Press any key to continue")coroutine.yield("key")os.shutdown()end;setfenv(n,_G)local p=os.shutdown;os.shutdown=function()os.shutdown=p;return n(a)end end;if debug then local function q(r,s,t,u)local v,w,x=1,debug.getupvalue(r[s],u)while w~=t and w~=nil do w,x=debug.getupvalue(r[s],v)v=v+1 end;r[s]=x or r[s]end;q(_G,"loadstring","nativeloadstring",1)q(_G,"load","nativeload",5)if http then q(http,"request","nativeHTTPRequest",3)end;q(os,"shutdown","nativeShutdown",1)q(os,"reboot","nativeReboot",1)if turtle then q(turtle,"equipLeft","v",1)q(turtle,"equipRight","v",1)end;do local v,w,x=1,debug.getupvalue(peripheral.isPresent,2)while w~="native"and w~=nil do w,x=debug.getupvalue(peripheral.isPresent,v)v=v+1 end;_G.peripheral=x or peripheral end end
|
||||
1
prod/Hyperion-firmware-cct/boot/cct/initdisks
Normal file
1
prod/Hyperion-firmware-cct/boot/cct/initdisks
Normal file
@@ -0,0 +1 @@
|
||||
local a=({...})[1]local b=a.BOOT_DRIVE_PATH;local c=a.fs;local d=a.peripheral;local e={}local f={"top","bottom","left","right","front","back"}function e.getNames()local g={}for h=1,#f do local i=f[h]if d.isPresent(i)then table.insert(g,i)if d.hasType(i,"peripheral_hub")then local j=d.call(i,"getNamesRemote")for k,l in ipairs(j)do table.insert(g,l)end end end end;return g end;function e.isPresent(l)if d.isPresent(l)then return true end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return true end end;return false end;function e.getType(e)if type(e)=="string"then if d.isPresent(e)then return d.getType(e)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"getTypeRemote",e)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(m.types)end end;function e.hasType(e,n)if type(e)=="string"then if d.isPresent(e)then return d.hasType(e,n)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",e)then return d.call(i,"hasTypeRemote",e,n)end end;return nil else local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return m.types[n]~=nil end end;function e.getMethods(l)if d.isPresent(l)then return d.getMethods(l)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"getMethodsRemote",l)end end;return nil end;function e.getName(e)local m=getmetatable(e)if not m or m.__name~="peripheral"or type(m.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return m.name end;function e.call(l,o,...)if d.isPresent(l)then return d.call(l,o,...)end;for h=1,#f do local i=f[h]if d.hasType(i,"peripheral_hub")and d.call(i,"isPresentRemote",l)then return d.call(i,"callRemote",l,o,...)end end;return nil end;function e.wrap(l)local p=e.getMethods(l)if not p then return nil end;local q={e.getType(l)}for r=1,#q do q[q[r]]=true end;local s=setmetatable({},{__name="peripheral",name=l,type=q[1],types=q})for k,o in ipairs(p)do s[o]=function(...)return e.call(l,o,...)end end;return s end;function e.find(t,u)local g={}for k,l in ipairs(e.getNames())do if e.hasType(l,t)then local v=e.wrap(l)if u==nil or u(l,v)then table.insert(g,v)end end end;return table.unpack(g)end;local w={}local x={}local function y(z)if not z or z==""then return"/"end;return c.combine("/",z)end;local function A(B,C,D,E)C=y(C)local F={address=B,isReadOnly=function()return D end}function F:spaceUsed()return c.getCapacity(C)-c.getFreeSpace(C)end;function F:spaceTotal()return c.getCapacity(C)end;function F:list(z)local G=c.combine(C,z)if not c.exists(G)or not c.isDir(G)then return nil,"not directory"end;return c.list(G)end;function F:fileExists(z)local G=c.combine(C,z)return c.exists(G)and not c.isDir(G)end;function F:directoryExists(z)local G=c.combine(C,z)return c.exists(G)and c.isDir(G)end;function F:type(z)local G=c.combine(C,z)if not c.exists(G)then return nil elseif c.isDir(G)then return"directory"else return"file"end end;function F:makeDirectory(z)local G=c.combine(C,z)c.makeDir(G)return true end;function F:remove(z)local G=c.combine(C,z)if c.exists(G)then c.delete(G)end;return true end;function F:setLabel(H)E.setLabel(H)end;function F:getLabel(H)return E.getLabel()end;function F:attributes(z)local G=c.combine(C,z)return c.attributes(G)end;function F:open(z,I)local G=c.combine(C,z)return c.open(G,I)end;return F end;x["$"]=A("$",b,false,{setLabel=function(H)local J=c.open("/.label","w")J.write(H)J.close()end,getLabel=function()local J=c.open("/.label","r")if not J then return"$"end;local H=J.readAll()J.close()return H end})x["rom"]=A("rom","/rom",true,{setLabel=function(H)error("Device is read-only")end,getLabel=function()return"cctrom"end})local function K()w={}for k,F in ipairs({e.find("drive")})do if F.isDiskPresent()then w[tostring(F.getDiskID())]=A("cctdisk"..tostring(F.getDiskID()),F.getMountPath(),false,c)end end end;local function L()K()local M={}for B,N in pairs(x)do M[B]=N end;for B,N in pairs(w)do M[B]=N end;return pairs(M)end;return{refresh=K,list=L}
|
||||
@@ -0,0 +1 @@
|
||||
local a=...a.cct={}a.cct.peripheral={}local b=a.cct.peripheral;local c=a.apis;local d=c.peripheral;local e={"top","bottom","left","right","front","back"}function b.getNames()local f={}for g=1,#e do local h=e[g]if d.isPresent(h)then table.insert(f,h)if d.hasType(h,"peripheral_hub")then local i=d.call(h,"getNamesRemote")for j,k in ipairs(i)do table.insert(f,k)end end end end;return f end;function b.isPresent(k)if d.isPresent(k)then return true end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return true end end;return false end;function b.getType(b)if type(b)=="string"then if d.isPresent(b)then return d.getType(b)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",b)then return d.call(h,"getTypeRemote",b)end end;return nil else local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return table.unpack(l.types)end end;function b.hasType(b,m)if type(b)=="string"then if d.isPresent(b)then return d.hasType(b,m)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",b)then return d.call(h,"hasTypeRemote",b,m)end end;return nil else local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.types)~="table"then error("bad argument #1 (table is not a peripheral)",2)end;return l.types[m]~=nil end end;function b.getMethods(k)if d.isPresent(k)then return d.getMethods(k)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return d.call(h,"getMethodsRemote",k)end end;return nil end;function b.getName(b)local l=getmetatable(b)if not l or l.__name~="peripheral"or type(l.name)~="string"then error("bad argument #1 (table is not a peripheral)",2)end;return l.name end;function b.call(k,n,...)if d.isPresent(k)then return d.call(k,n,...)end;for g=1,#e do local h=e[g]if d.hasType(h,"peripheral_hub")and d.call(h,"isPresentRemote",k)then return d.call(h,"callRemote",k,n,...)end end;return nil end;function b.wrap(k)local o=b.getMethods(k)if not o then return nil end;local p={b.getType(k)}for q=1,#p do p[p[q]]=true end;local r=setmetatable({},{__name="peripheral",name=k,type=p[1],types=p})for j,n in ipairs(o)do r[n]=function(...)return b.call(k,n,...)end end;return r end;function b.find(s,t)local f={}for j,k in ipairs(b.getNames())do if b.hasType(k,s)then local u=b.wrap(k)if t==nil or t(k,u)then table.insert(f,u)end end end;return table.unpack(f)end
|
||||
@@ -0,0 +1 @@
|
||||
local a=...local b=a.cct.peripheral;local c={[0xFFFFFF]=0x0001,[0xFF0000]=0x0002,[0x00FF00]=0x0004,[0x0000FF]=0x0008,[0x00FFFF]=0x0010,[0xFF00FF]=0x0020,[0xFFFF00]=0x0040,[0xFF6D00]=0x0080,[0x6DFF55]=0x0100,[0x24FFFF]=0x0200,[0x924900]=0x0400,[0x6D6D55]=0x0800,[0xDBDBAA]=0x1000,[0x6D00FF]=0x2000,[0xB6FF00]=0x4000,[0x000000]=0x8000}local d={0xFFFFFF,0xFF0000,0x00FF00,0x0000FF,0x00FFFF,0xFF00FF,0xFFFF00,0xFF6D00,0x6DFF55,0x24FFFF,0x924900,0x6D6D55,0xDBDBAA,0x6D00FF,0xB6FF00,0x000000}local e,f=0x6D6D55,0x000000;local g,h,i,j={},{},{},0;local function k(l,m)local n=nil;local o=math.huge;for p,q in pairs(l)do if p==m then return p end;local r=math.abs(p-m)if r<o then o=r;n=p end end;return n end;local function s(t)j=j+1;if j%1024==0 then h={}g={}end;if j%8192==0 then i={}end;if i[t]~=nil then return i[t]end;if h[t]~=nil then g[t]=g[t]+1;if g[t]>=16 then i[t]=h[t]h[t]=nil;g[t]=nil;return i[t]end;return h[t]end;local u=k(c,t)if not u then return nil end;local v=c[u]h[t]=v;g[t]=1;return v end;local function w(x,y)local z,A=y.getCursorPos()local B,C=y.getSize()for D=1,#x do local E=x:sub(D,D)if E=="\n"then A=A+1;z=1 elseif E=="\t"then local F=4;local G=F-(z-1)%F;y.write(string.rep(" ",G))z=z+G elseif E=="\b"then if z>1 then z=z-1;y.setCursorPos(z,A)y.write(" ")y.setCursorPos(z,A)end else if z<=B and A<=C then y.setCursorPos(z,A)y.write(E)z=z+1 end end;if z>B then z=1;A=A+1 end;if A-1>=C then y.scroll(1)A=C;y.setCursorPos(z,A)end end;y.setCursorPos(z,A)end;a.devfs.data.tty={}a.cct.ctrl,a.cct.alt=false,false;local function H(I)if I then return"T"else return"F"end end;local function J(K,L,M)K.setPaletteColor(0x1,0xFFFFFF)K.setPaletteColor(0x2,0xFF0000)K.setPaletteColor(0x4,0x00FF00)K.setPaletteColor(0x8,0x0000FF)K.setPaletteColor(0x10,0x00FFFF)K.setPaletteColor(0x20,0xFF00FF)K.setPaletteColor(0x40,0xFFFF00)K.setPaletteColor(0x80,0xFF6D00)K.setPaletteColor(0x100,0x6DFF55)K.setPaletteColor(0x200,0x24FFFF)K.setPaletteColor(0x400,0x924900)K.setPaletteColor(0x800,0x6D6D55)K.setPaletteColor(0x1000,0xDBDBAA)K.setPaletteColor(0x2000,0x6D00FF)K.setPaletteColor(0x4000,0xB6FF00)K.setPaletteColor(0x8000,0x000000)a.devfs.data["tty"][L]=function(N,O)if N=="type"then return"Terminal"elseif N=="open"then local C={read=function(P)local Q=""for D=1,P or 1 do local R={M()}if R[1]then Q=Q..R[1]end end;if Q==""then Q=nil end;return Q end,write=function(S)w(S,K)end,size=function()local T={K.getSize()}return table.concat(T,";")end,clear=function()K.clear()K.setCursorPos(1,1)end,gpos=function()local T={K.getCursorPos()}return table.concat(T,";")end,spos=function(z,A)return K.setCursorPos(z,A)end,sfgc=function(E)e=E;return K.setTextColor(s(E))end,sbgc=function(E)f=E;return K.setBackgroundColor(s(E))end,gfgc=function()return e end,gbgc=function()return f end,gctrl=function()return H(a.cct.ctrl)..";"..H(a.cct.alt)end,gplt=function()return d end}if O=="rw"then return C elseif O=="r"then C["write"]=nil;return C elseif O=="w"then C["read"]=nil;return C end end end end;local U=a.newFifo()a.cct.fifo=U;J(a.apis.term,"1",U.pop)for D,V in ipairs({b.find("monitor")})do V.setTextScale(.5)V.write("Initializing...")J(V,tostring(D+1),function()end)end
|
||||
@@ -0,0 +1 @@
|
||||
local a=...local b=a.apis.keys;a.processes.cctdeamon=function()local c=false;while true do local d={a.EFI:getMachineEvent()}if d[1]then local e=d[1]local f=d[3]local g={[b.a]=1,[b.b]=2,[b.c]=3,[b.d]=4,[b.e]=5,[b.f]=6,[b.g]=7,[b.h]=8,[b.i]=9,[b.j]=10,[b.k]=11,[b.l]=12,[b.m]=13,[b.n]=14,[b.o]=15,[b.p]=16,[b.q]=17,[b.r]=18,[b.s]=19,[b.t]=20,[b.u]=21,[b.v]=22,[b.w]=23,[b.x]=24,[b.y]=25,[b.z]=26}if e=="keyPressed"then if f==b.leftCtrl or f==b.rightCtrl then a.cct.ctrl=true elseif f==b.leftAlt or f==b.rightAlt then a.cct.alt=true end;if a.cct.ctrl then local h=g[f]if h then if h==3 then for i,j in ipairs(syscall.getTasks())do syscall.sigsend(j,1)end else a.cct.fifo.push(string.char(h))end end else local k={[b.up]="[A",[b.down]="[B",[b.right]="[C",[b.left]="[D",[b.home]="[H",[b["end"]]="[F",[b.pageUp]="[5~",[b.pageDown]="[6~",[b.delete]="[3~"}local l=k[f]if l then a.cct.fifo.push(l)end end elseif e=="keyReleased"then if f==b.leftCtrl or f==b.rightCtrl then a.cct.ctrl=false elseif f==b.leftAlt or f==b.rightAlt then a.cct.alt=false end elseif e=="keyTyped"then if f then a.cct.fifo.push(f)end elseif e=="http_success"then a.cct.httpqueue[d[2]]=nil;a.cct.httpresponse[d[2]]=d[3]elseif e=="http_failure"then a.cct.httpqueue[d[2]]=nil;a.cct.httperror[d[2]]=d[3]end;c=false else c=true end;if c then sleep(0.05)end end end
|
||||
@@ -0,0 +1 @@
|
||||
local a=...local b=a.apis.rs;local c={top=1,bottom=2,left=3,right=4,front=5,back=6}local function d(e)return function(f,g)if f=="w"then if type(g)~="boolean"then error("data: expected bool")end;b.setOutput(e,g)elseif f=="wa"then if type(g)~="number"then error("data: expected bool")end;b.setAnalogOutput(e,g)elseif f=="r"then return b.getInput(e)elseif f=="ra"then return b.getAnalogInput(e)end end end;for e,h in pairs(c)do local i=d(e)a.gpio[e]=i;a.gpio[h]=i end
|
||||
41
prod/Hyperion-firmware-oc/boot/oc/boot.lua
Normal file
41
prod/Hyperion-firmware-oc/boot/oc/boot.lua
Normal file
@@ -0,0 +1,41 @@
|
||||
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 apis={}
|
||||
for i,v in pairs(_G) do
|
||||
if not lua[i] or lua[i]==nil then
|
||||
apis[i]=v
|
||||
_G[i]=nil
|
||||
end
|
||||
end
|
||||
18
prod/Hyperion-firmware-oc/boot/oc/eeprom
Normal file
18
prod/Hyperion-firmware-oc/boot/oc/eeprom
Normal file
@@ -0,0 +1,18 @@
|
||||
checkArg=nil
|
||||
local oldcomputer=computer
|
||||
_G.computer=nil
|
||||
local os=os
|
||||
_G.os=nil
|
||||
|
||||
function component.wrap(address)
|
||||
local methods=oldcomponent.methods(address)
|
||||
local object={}
|
||||
for _,method in ipairs(methods) do
|
||||
object[method]=function(_,...)
|
||||
return oldcomponent.invoke(address,method,...)
|
||||
end
|
||||
end
|
||||
return object
|
||||
end
|
||||
|
||||
local
|
||||
1
prod/Hyperion-firmware-oc/boot/oc/initfs.lua
Normal file
1
prod/Hyperion-firmware-oc/boot/oc/initfs.lua
Normal file
@@ -0,0 +1 @@
|
||||
local fs={}
|
||||
4
prod/Hyperion-kernel/boot/fstab
Normal file
4
prod/Hyperion-kernel/boot/fstab
Normal file
@@ -0,0 +1,4 @@
|
||||
U $;/
|
||||
U devfs0000;/dev/
|
||||
U tmpfs0000;/tmp/
|
||||
U procfs0000;/proc/
|
||||
84
prod/Hyperion-kernel/boot/initfs
Normal file
84
prod/Hyperion-kernel/boot/initfs
Normal file
@@ -0,0 +1,84 @@
|
||||
-- :Minify:--
|
||||
local fs = {}
|
||||
local disks = {}
|
||||
local mounts = {}
|
||||
|
||||
local function resolve(path)
|
||||
local mountPoint = "/"
|
||||
for mount, disk in pairs(mounts) do
|
||||
if path:sub(1, #mount) == mount then
|
||||
if not mountPoint or #mount > #mountPoint then
|
||||
mountPoint = mount
|
||||
end
|
||||
end
|
||||
end
|
||||
local newPath = path:sub(#mountPoint + 1)
|
||||
return disks[mounts[mountPoint]], newPath
|
||||
end
|
||||
|
||||
function fs.update(initdisks)
|
||||
disks = {}
|
||||
for k, v in initdisks.list() do disks[k] = v end
|
||||
end
|
||||
|
||||
function fs.exists(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:directoryExists(newPath) or disk:fileExists(newPath)
|
||||
end
|
||||
|
||||
function fs.isFile(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:fileExists(newPath)
|
||||
end
|
||||
|
||||
function fs.isDir(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:directoryExists(newPath)
|
||||
end
|
||||
|
||||
function fs.list(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:list(newPath)
|
||||
end
|
||||
|
||||
function fs.makeDir(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:makeDirectory(newPath)
|
||||
end
|
||||
|
||||
function fs.remove(path)
|
||||
local disk, newPath = resolve(path)
|
||||
return disk:remove(newPath)
|
||||
end
|
||||
|
||||
function fs.readAllText(path)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "r")
|
||||
if not handle then return nil end
|
||||
local content = handle.readAll()
|
||||
handle.close()
|
||||
return content
|
||||
end
|
||||
|
||||
function fs.writeAllText(path, text)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "w")
|
||||
handle.write(text)
|
||||
handle.close()
|
||||
end
|
||||
|
||||
function fs.appendAllText(path, text)
|
||||
local disk, newPath = resolve(path)
|
||||
local handle = disk:open(newPath, "a")
|
||||
handle.write(text)
|
||||
handle.close()
|
||||
end
|
||||
|
||||
function fs.load(path) return load(fs.readAllText(path), path) end
|
||||
|
||||
function fs.mount(disk, mountPoint)
|
||||
if not disks[disk] then return end
|
||||
mounts[mountPoint] = disk
|
||||
end
|
||||
|
||||
return fs
|
||||
1
prod/Hyperion-kernel/boot/kernel.lua
Normal file
1
prod/Hyperion-kernel/boot/kernel.lua
Normal file
File diff suppressed because one or more lines are too long
12
prod/Hyperion-kernel/boot/safeboot.cfg
Normal file
12
prod/Hyperion-kernel/boot/safeboot.cfg
Normal file
@@ -0,0 +1,12 @@
|
||||
-- DO NOT EDIT THIS FILE IF YOU DO NOT KNOW WHAT YOU ARE DOING!
|
||||
-- DOING SO MAY RENDER YOUR SYSTEM UNBOOTABLE!
|
||||
|
||||
-- This file is auto-generated during the build process.
|
||||
-- DEFAULT BOOT CONFIGURATION FILE
|
||||
return {
|
||||
initPath = "/sbin/init",
|
||||
maxOpenFiles = 128,
|
||||
maxFilesPerTask = 16,
|
||||
preempt=true,
|
||||
logTaskExit=true
|
||||
}
|
||||
1
prod/Hyperion-kernel/etc/passwd
Normal file
1
prod/Hyperion-kernel/etc/passwd
Normal file
@@ -0,0 +1 @@
|
||||
0:0:root:/root:/bin/hysh
|
||||
0
prod/Hyperion-kernel/etc/shadow
Normal file
0
prod/Hyperion-kernel/etc/shadow
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/01_stdlib.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...a.allowGlobalOverwrites=true;function string.hasSuffix(b,c)return string.sub(b,#c+1)==c end;function string.hasPrefix(b,d)return string.sub(b,1,#d)==d end;function string.getSuffix(b,d)return string.sub(b,#d+1)end;function string.getPrefix(b,c)return string.sub(b,1,#c)end;function string.join(b,...)return table.concat(table.pack(b,...))end;function string.delim(b,...)return table.concat(table.pack(...),b)end;function string.split(b,e,f)assert(#e==1,"only delim len 1 supported for now")if not b then return false end;f=(f or 0)-1;local g={}local h=""for i=1,#b do local j=string.sub(b,i,i)if#g~=f and j==e then table.insert(g,h)h=""else h=h..j end end;table.insert(g,h)return g end;function table.deepcopy(k,l)l=l or{}if type(k)~='table'then return k elseif l[k]then return l[k]end;local m={}l[k]=m;for n,o in next,k,nil do local p=table.deepcopy(n,l)local q=table.deepcopy(o,l)m[p]=q end;return m end;function table.hasKey(r,s)for i,o in pairs(r)do if i==s then return o end end;return false end;function table.hasVal(r,s)for i,o in pairs(r)do if o==s then return i end end;return false end;local function t(u,v)v=v or{}if v[u]then return'"[Circular Reference]"'end;v[u]=true;local w="{"local x=true;for i,o in pairs(u)do if not x then w=w..","end;x=false;if type(i)=="string"then w=w.."[\""..i.."\"]="elseif type(i)=="number"then w=w.."["..tostring(i).."]="end;if type(o)=="table"then w=w..t(o,v)elseif type(o)=="string"then w=w.."[=["..o.."]=]"elseif type(o)=="number"or type(o)=="boolean"then w=w..tostring(o)elseif type(o)=="function"then w=w.."\""..tostring(o).."\""elseif type(o)=="thread"then w=w.."\""..tostring(o).."\""else error("serialization of type \""..type(o).."\" is not supported")end end;v[u]=nil;w=w.."}"return w end;local y=type;local z=getmetatable;function type(A,B)if B then return y(A)end;if y(A)~="table"then return y(A)else if y(z(A))=="table"then local C=z(A)if C.__type then return C.__type end else return"table"end end end;function getmetatable(A)if y(A)~="table"then return end;if y(z(A))=="table"then if z(A).__isuserdata then if y(z(A).__usermeta)=="function"then return z(A).__usermeta()else return z(A).__usermeta end else return z(A)end else return z(A)end end;function isEqualToAny(D,...)local E={...}for i=0,#E do if D==E[i]then return true end end;return false end;function isEqualToAll(D,...)local E={...}for i=0,#E do if D~=E[i]then return false end end;return true end;function table.keys(F)local D={}for G in pairs(F)do table.insert(D,G)end;return D end;function table.values(F)local D={}for H,G in pairs(F)do table.insert(D,G)end;return D end;function table.indexOf(F,I)for i,o in ipairs(F)do if o==I then return i end end;return-1 end;function table.merge(...)local E={...}local J={}local K={}for H,F in ipairs(E)do for i,o in pairs(F)do J[i]=o end;for i,o in ipairs(F)do K[#K+1]=o end end;for i,o in ipairs(K)do J[i]=o end;return J end;function string.replace(L,M,N)local O={}local i=1;local G=#L;local P=#M;while i<=G do local Q=true;if i+P-1<=G then for R=1,P do if L:sub(i+R-1,i+R-1)~=M:sub(R,R)then Q=false;break end end else Q=false end;if Q then table.insert(O,N)i=i+P else table.insert(O,L:sub(i,i))i=i+1 end end;return table.concat(O)end;function toHex(S)return string.format("%X",S)end;local function T()local U={}return setmetatable(U,{__index=function(self,V)local W=rawget(self,V)if W~=nil then return W end;return function(...)local X=table.pack(coroutine.yield("syscall",V,...))if X[1]then return table.unpack(X,2,X.n)else error(X[2],2)end end end,__newindex=function(self,n,o)rawset(self,n,o)end,__metatable=false})end;syscall=T()_makeSyscallProxy=T;table.serialize=t
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/10_vfs.kmod
Normal file
File diff suppressed because one or more lines are too long
@@ -0,0 +1 @@
|
||||
local a=...local b={}a.searchpaths={"/lib/?.lua","/lib/?","/usr/lib/?.lua","/usr/lib/?","/usr/local/lib/?.lua","/usr/local/lib/?","?.lua","?"}function require(c,...)if b[c]then return b[c]end;local d=c:gsub("%.","/")local e={}for f,g in ipairs(a.searchpaths)do local h=string.replace(g,"?",d)if h:sub(1,1)~="/"then h=a.currentTask.cwd..h end;if a.vfs.exists(h)then if a.vfs.type(h)=="directory"then h=h.."/init"end;if a.vfs.exists(h)then local i=a.vfs.open(h,"r")local j=a.vfs.read(i,1024*1024*4)a.vfs.close(i)return assert(load(j,h,"t",a._U))(...)else table.insert(e,h)end else table.insert(e,h)end end;error("Module not found: "..c.." (searched paths: "..table.concat(e,", ")..")")end
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/12_devfs.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/12_devfs.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local b={}local c={}b.address="devfs0000"b.isvirt=true;b.isReadOnly=function()return false end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function()error("EACCES")end;b.remove=function()error("EACCES")end;b.setLabel=function()error("EACCES")end;b.getLabel=function()return"devfs"end;b.attributes=function(d)return{size=0,modified=0,created=0}end;function b:open(d,e)local f=a.vfs.splitPath(d)local g=c;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENFILE")end;g=i end;if type(g[f[#f]])=="function"then return g[f[#f]]("open",e)end;error("ENFILE")end;function b:type(d,e)local f=a.vfs.splitPath(d)local g=c;if#f==0 then return"directory"end;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENFILE")end;g=i end;if type(g[f[#f]])=="function"then return g[f[#f]]("type",e)end;if type(g[f[#f]])=="table"then return"directory"end;error(type(g[f[#f]]))end;function b:list(d)local f=a.vfs.splitPath(d)local g=c;if#f==0 then return table.keys(c)end;for h=1,#f-1 do local i=g[f[h]]if type(i)~="table"then error("ENOENT")end;g=i end;if type(g[f[#f]])=="table"then return table.keys(g[f[#f]])end;error("ENOENT")end;function b:fileExists(d)local j=pcall(function()return self:type(d)end)return j end;function c.random(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)local m=""for h=1,l or 1 do m=m..string.char(math.random(0,255))end;return m end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;function c.null(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;function c.zero(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then return{read=function(l)local m=""for h=1,l or 1 do m=m..string.char(0)end;return m end}elseif e=="w"or e=="a"then return{write=function()end}else error("EACCES")end end end;if a.EFI:getEEPROM()then function c.eeprom(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then local n,o=1,a.EFI:getEEPROM()return{read=function(l)n=n+l;return o:sub(n-l,n)end}elseif e=="w"then if a.uid~=0 then error("EACCES")end;local p=true;return{write=function(c)if p then a.EFI:setEEPROM(c)else a.EFI:setEEPROM(a.EFI:getEEPROM()..c)end end}elseif e=="a"then if a.uid~=0 then error("EACCES")end;return{write=function(c)a.EFI:setEEPROM(a.EFI:getEEPROM()..c)end}else error("EACCES")end end end end;if a.EFI:getNvram()then function c.nvram(k,e)if k=="type"then return"character device"elseif k=="open"then if e=="r"then local n,q=1,a.EFI:getNvram()return{read=function(l)n=n+l;return q:sub(n-l,n)end}elseif e=="w"then if a.uid~=0 then error("EACCES")end;local p=true;return{write=function(c)if p then a.EFI:setNvram(c)else a.EFI:setNvram(a.EFI:getNvram()..c)end end}elseif e=="a"then if a.uid~=0 then error("EACCES")end;return{write=function(c)a.EFI:setNvram(a.EFI:getNvram()..c)end}else error("EACCES")end end end end;c["disk"]={}a.devfs={}a.devfs.data=c;a.devfs.proxy=b;a.disks["devfs0000"]=b
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/12_procfs.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local b={}local c={}b.address="procfs0000"b.isvirt=true;b.isReadOnly=function()return true end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function()error("EACCES")end;b.remove=function()error("EACCES")end;b.setLabel=function()error("EACCES")end;b.getLabel=function()return"procfs"end;b.attributes=function(d)return{size=0,modified=0,created=0}end;local function e(f,g)g=g or{}local h=g.uid or 0;local i=g.gid or 0;local j=g.perms or 0x3F;local k={}table.insert(k,string.char(0x02))for d,l in pairs(f)do local m=d;local n=#m;if n>255 then error("Filename too long (>255 bytes): "..m)end;local o=0x00;local p=""if l and l~=""then o=0x01;p=l end;local q=#p;if q>255 then error("cmeta too long (>255 bytes) for "..m)end;table.insert(k,string.char(n))table.insert(k,m)table.insert(k,string.char(o))table.insert(k,string.char(h%256,math.floor(h/256)%256))table.insert(k,string.char(i%256,math.floor(i/256)%256))table.insert(k,string.char(j%256,math.floor(j/256)%256))table.insert(k,string.char(q))if q>0 then table.insert(k,p)end end;return table.concat(k)end;local function r(s,t)return function(u,v)if u=="type"then return"character device"elseif u=="open"then if v=="r"then return{read=s}elseif v=="w"then return{write=t}end end end end;local function w(x)local y=tostring(x)local z=1;return r(function(A)z=z+A;return y:sub(z-A,z)end,function()error("EACCES")end)end;local function B(C)local D,E,F={},{},{}if C.fd[0]then D["0"]=C.fd[0].path end;for G,H in ipairs(C.fd)do D[tostring(G)]=tostring(H.path)end;for G,H in ipairs(C.siblings)do E[tostring(H.pid)]="/proc/"..tostring(H.pid)end;for G,H in ipairs(C.children)do F[tostring(H.pid)]="/proc/"..tostring(H.pid)end;return{[".meta"]=w(e({cwd=C.cwd,parent="/proc/"..tostring(C.parent.pid)})),uid=w(C.uid),comm=w(C.name),fd={[".meta"]=w(e(D))},siblings={[".meta"]=w(e(E))},children={[".meta"]=w(e(F))}}end;function b:open(d,v)local I=a.vfs.splitPath(d)local J=c;if tonumber(I[1])then local C=a.tasks[tostring(I[1])]local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end elseif tostring(I[1])=="self"then local C=a.currentTask;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("open",v)end end;error("ENFILE")end;function b:type(d,v)local I=a.vfs.splitPath(d)local J=c;if#I==0 then return"directory"end;if tonumber(I[1])then local C=a.tasks[I[1]]if#I==1 then return"directory"end;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end elseif tostring(I[1])=="self"then local C=a.currentTask;if#I==1 then return"directory"end;local J=B(C)for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENFILE")end;J=y end;if type(J[I[#I]])=="function"then return J[I[#I]]("type",v)end;if type(J[I[#I]])=="table"then return"directory"end end;error("ENOENT")end;function b:list(d)local I=a.vfs.splitPath(d)local J=c;if#I==0 then return table.merge(table.keys(c),table.keys(a.tasks),{"self"})end;if tonumber(I[1])then local C=a.tasks[I[1]]local J=B(C)if#I==1 then return table.keys(J)end;for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end elseif tostring(I[1])=="self"then local C=a.currentTask;local J=B(C)if#I==1 then return table.keys(J)end;for G=2,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end else for G=1,#I-1 do local y=J[I[G]]if type(y)~="table"then error("ENOENT")end;J=y end;if type(J[I[#I]])=="table"then return table.keys(J[I[#I]])end end;error("ENOENT")end;function b:fileExists(d)local K=pcall(function()return self:type(d)end)return K end;c.uptime=r(function()return tostring(a.EFI:getUptime())end,function()error("EACCES")end)a.procfs={}a.procfs.data=c;a.procfs.proxy=b;a.disks["procfs0000"]=b
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/12_tmpfs.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/12_tmpfs.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local b={}local c={}b.address="tmpfs0000"b.isvirt=true;b.isReadOnly=function()return false end;b.spaceUsed=function()return 0 end;b.spaceTotal=function()return 0 end;b.makeDirectory=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do if not g[f[h]]then g[f[h]]={}elseif type(g[f[h]])~="table"then error("ENOTDIR")end;g=g[f[h]]end end;b.remove=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f-1 do g=g[f[h]]if not g then error("ENOENT")end end;g[f[#f]]=nil end;b.setLabel=function(d,i)end;b.getLabel=function()return"tmpfs"end;b.attributes=function(d,e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do g=g[f[h]]if not g then error("ENOENT")end end;return{size=type(g)=="string"and#g or 0,modified=0,created=0}end;function b:open(e,j)local f=a.vfs.splitPath(e)local g=c;for h=1,#f-1 do if not g[f[h]]then if j=="w"then g[f[h]]={}else error("ENOENT")end elseif type(g[f[h]])~="table"then error("ENOTDIR")end;g=g[f[h]]end;local k=f[#f]if j=="r"then if type(g[k])~="string"then error("ENOENT")end;local l=g[k]local m=1;return{read=function(n)n=n or#l;local o=l:sub(m,m+n-1)m=m+#o;return o end,close=function()end}elseif j=="w"then g[k]=""local p={}return{write=function(q)p[#p+1]=q end,close=function()g[k]=table.concat(p)end}elseif j=="a"then if type(g[k])~="string"then g[k]=""end;return{write=function(q)g[k]=g[k]..q end,close=function()end}else error("EACCES")end end;function b:type(e)local f=a.vfs.splitPath(e)local g=c;if#f==0 then return"directory"end;for h=1,#f do g=g[f[h]]if not g then return false end end;if type(g)=="table"then return"directory"end;if type(g)=="string"then return"file"end end;function b:list(e)local f=a.vfs.splitPath(e)local g=c;for h=1,#f do g=g[f[h]]if not g then error("ENOENT")end end;if type(g)~="table"then error("ENOTDIR")end;local r={}for s,d in pairs(g)do table.insert(r,s)end;return r end;function b:fileExists(e)local t=self:type(e)return t=="file"or t=="directory"end;a.disks["tmpfs0000"]=b
|
||||
File diff suppressed because one or more lines are too long
1
prod/Hyperion-kernel/lib/modules/hyperion/19_fstab.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/19_fstab.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local function b(c)local d,e=1,#c;while d<=e and(c:sub(d,d)==" "or c:sub(d,d)=="\t")do d=d+1 end;while e>=d and(c:sub(e,e)==" "or c:sub(e,e)=="\t"or c:sub(e,e)=="\n"or c:sub(e,e)=="\r")do e=e-1 end;if d>e then return""end;return c:sub(d,e)end;for f,g in ipairs(string.split(a.fstab,"\n"))do g=b(g)if g~=""and g:sub(1,1)=="U"then local h;for i=3,#g do if g:sub(i,i)==";"then h=i;break end end;if not h or h==3 then a.log("Invalid fstab line: "..g.." ... Skipping.","WARN",0xFF8800)else local j=g:sub(3,h-1)local k=b(g:sub(h+1))a.log("Mounted "..j.." to "..k)if j~="$"then a.vfs.mount(k,j)end end end end
|
||||
@@ -0,0 +1 @@
|
||||
local a=...local b={}a.signal=b;function b.sigsend(c,d)if d<0 or d>256 then error("EINVAL")end;local e=a.tasks[tostring(c)]if not e then error("ENOENT")end;if not e.sigq then return end;e.sigq[#e.sigq+1]=d end;function b.sigcatch(f)local e=a.currentTask;e.sigh=f;if not e.sigq then e.sigq={}end;local g={error="",active=true}if e.sigd then e.sigd.active=false end;e.sigd=g;return g end;function b.sigignore()local e=a.currentTask;e.sigh=nil;e.sigq=nil;if e.sigd then e.sigd.active=false end;e.sigd=nil end;local h=a.syscalls;h["sigsend"]=b.sigsend;h["sigcatch"]=b.sigcatch;h["sigignore"]=b.sigignore
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/20_socket.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local b={}b.handlers={}a.socket=b;function b.registerProtocal(c,d)b.handlers[c]=d end;function b.socket()local e=a.vfs.P;local f=a.newFifo()local g=false;a.vfs.newfd({handle={read=function()if g then error("ECCON")end;return f.read()end,write=function()if g then error("ECCON")end;return f.write()end,close=function()g=true end},type="socket",refcount=1,meta={owner=a.currentTask.uid,group=a.currentTask.uid,etype=2,perms=e.OWNER_R+e.OWNER_W+e.GROUP_R+e.GROUP_W},isvirt=true})end;function b.connect(h,i)end;function b.listen(h,j)end;a.log("Loaded socket module")
|
||||
@@ -0,0 +1 @@
|
||||
local a=...a.unixSockets={}
|
||||
@@ -0,0 +1 @@
|
||||
local a={...}local b=a[1]b._G=_G;local function c(d)return setmetatable({},{__index=function(e,f)local g=d[f]if type(g)=="table"then return c(g)end;return g end,__newindex=function(h,i,j)if b.config.allowGlobalOverwrites or b.allowGlobalOverwrites then rawset(d,i,j)return end;error("Attempt to modify global variable '"..i.."'",2)end,__pairs=function(self)local function k(e,f)local l,g=next(d,f)if type(g)=="table"then g=c(g)end;return l,g end;return k,self,nil end,__ipairs=function()local m=0;return function()m=m+1;local g=d[m]if g==nil then return end;if type(g)=="table"then g=c(g)end;return m,g end end,__len=function()return#d end,__metatable=false})end;local n=load;b._U=c(b._G)b._U._G=b._U;b._U.load=function(o,p,q,r)return n(o,p,q,r or b._U)end;function b.freshUserEnv()local s={}s.syscall=_makeSyscallProxy()local t=setmetatable(s,{__index=b._U,__newindex=function(e,i,j)rawset(s,i,j)end,__metatable=false})s._G=t;s.load=function(o,p,q,r)return n(o,p,q,r or t)end;return t end
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/40_auth.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/40_auth.kmod
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
prod/Hyperion-kernel/lib/modules/hyperion/47_dbg.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/47_dbg.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local debug=debug;a._G.debug={getinfo=debug.getinfo,traceback=debug.traceback}
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/50_gpio.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/50_gpio.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...local b=a.syscalls;a.gpio={}b["gpio_write"]=function(c,d)if a.gpio[c]then return a.gpio[c]("w",d)end end;b["gpio_writeAnalog"]=function(c,d)if a.gpio[c]then return a.gpio[c]("wa",d)end end;b["gpio_read"]=function(c)if a.gpio[c]then return a.gpio[c]("r")end end;b["gpio_readAnalog"]=function(c)if a.gpio[c]then return a.gpio[c]("ra")end end
|
||||
@@ -0,0 +1 @@
|
||||
local a=...function print(...)local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)syscall.write(1,c.."\n")end;function printf(e,...)local c=string.format(e,...)syscall.write(1,c.."\n")end;function printInline(...)local b={...}local c=""for d=1,#b do c=c..tostring(b[d]).."\t"end;c=c:sub(1,-2)syscall.write(1,c)end
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/90_init.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/90_init.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...a.log("Loading init system...")a.log("InitPath: "..a.config.initPath)local b,c=pcall(a.vfs.access,a.config.initPath,"rx")if not b then a.PANIC("Init binary not executable: "..a.config.initPath.." ("..tostring(c)..")")end;local d=a.vfs.open(a.config.initPath,"r")if not d then a.panic("Failed to open "..a.config.initPath)end;local e=a.vfs.read(d,1024*1024*4)if not d then a.panic("Failed to read "..a.config.initPath)end;a.vfs.close(d)local f,g=load(e,"@sysinit","t",a._U)if not f then a.PANIC("Failed to load init system: "..g)end;a.tasks["1"]={coro=coroutine.create(function()local h,g=xpcall(f,debug.traceback,a)if not h then a.panic("Init system crashed: "..tostring(g))else a.panic("Init system exited: "..tostring(g))end end),name="sysinit",status="R",pid=1,tgid=1,uid=0,fd={},envars={},args={},exit="",sleep=0,ivs=0,vs=0,parent=a.kernelTask,siblings=a.kernelTask.children,children={},syscallReturn={},cwd="/",timeSlice=0,lastTime=0,totalTime=0,numRuns=0}a.log("created init task with PID 1")a.log("Initializing init system...")
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/91_login.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/91_login.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...if not a.vfs.exists("/root")then a.vfs.mkdir("/root")end;a.processes.login=function()local b,c=pcall(a.hpv.execspawn,"/bin/login","login")if not b then a.log("Failed to exec /bin/login: "..tostring(c),"ERROR",0xFF0000)end end
|
||||
1
prod/Hyperion-kernel/lib/modules/hyperion/92_setup.kmod
Normal file
1
prod/Hyperion-kernel/lib/modules/hyperion/92_setup.kmod
Normal file
@@ -0,0 +1 @@
|
||||
local a=...if a.firstBoot then local b=a.vfs.P;local c=a.vfs.PERM;local d=b.OWNER_R+b.OWNER_W+b.GROUP_R+b.WORLD_R;local e=b.OWNER_R+b.OWNER_W+b.OWNER_X+b.GROUP_R+b.GROUP_X+b.WORLD_R+b.WORLD_X;local f=b.OWNER_R+b.OWNER_W+b.GROUP_R;local g=b.OWNER_R+b.OWNER_W;local h=c.RWXRWXRWX;local i=c.SUID_755;local j=0x02;local k=a.disks["$"]local function l(m,n,o,p,q,r)r=r or""local s=q%256;local t=math.floor(q/256)%256;local u=(o or 0)%256;local v=math.floor((o or 0)/256)%256;local w=(p or 0)%256;local x=math.floor((p or 0)/256)%256;return string.char(#m)..m..string.char(n,u,v,w,x,s,t)..string.char(#r)..r end;local y=0x00;local function z(A,B)local C=A;if C:sub(1,1)=="/"then C=C:sub(2)end;local D=C==""and".meta"or C.."/.meta"local E={}local F,G=pcall(function()return k:open(D,"r")end)if F and G then local H=G.read(65535)if G.close then G.close()end;E=a.vfs._parseMetafile and a.vfs._parseMetafile(H)or{}end;for I,J in ipairs(B)do local m=J[1]local n=J[2]or y;local o=J[3]or 0;local p=J[4]or 0;local q=J[5]or e;local r=J[6]or""E[m]={etype=n,owner=o,group=p,perms=q,cmeta=r}end;local K=string.char(j)for m,L in pairs(E)do K=K..l(m,L.etype or y,L.owner or 0,L.group or 0,L.perms or e,L.cmeta or"")end;local M,N=pcall(function()local O=k:open(D,"w")O.write(K)O.close()end)if not M then a.log("permissions: failed to write "..D..": "..tostring(N),"WARN",0xFF8800)end end;a.log("Seeding filesystem permissions...")z("/",{{"bin",y,0,0,e},{"boot",y,0,0,e},{"dev",y,0,0,h},{"etc",y,0,0,e},{"home",y,0,0,e},{"lib",y,0,0,e},{"proc",y,0,0,h},{"root",y,0,0,g},{"sbin",y,0,0,e},{"tmp",y,0,0,h},{"usr",y,0,0,e},{"var",y,0,0,h},{"opt",y,0,0,e}})z("/bin",{{"login",y,0,0,i},{"su",y,0,0,i},{"sudo",y,0,0,i}})z("/etc",{{"passwd",y,0,0,d},{"shadow",y,0,0,g},{"pam.d",y,0,0,g}})z("/etc/pam.d",{{"secret",y,0,0,g}})a.log("Filesystem permissions seeded.")end
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user