Compare commits
60
Commits
1.2.2
...
1.2.4-dev_2
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9b338328f0 | ||
|
|
4f9eebade2 | ||
|
|
d08935b68a | ||
|
|
45b46cf3c4 | ||
|
|
aeea68bc9b | ||
|
|
f983b13d56 | ||
|
|
03c5b106c4 | ||
|
|
08323e00ff | ||
|
|
5e3cdbe40c | ||
|
|
8762b8f022 | ||
|
|
677b2cccec | ||
|
|
a5e8624368 | ||
|
|
bbda3b3937 | ||
|
|
585d39bec2 | ||
|
|
b08b14763a | ||
|
|
de6696003b | ||
|
|
9220281365 | ||
|
|
813ddabd9d | ||
|
|
5177639d71 | ||
|
|
528b4f31bd | ||
|
|
60162c7c57 | ||
|
|
18f5c454bb | ||
|
|
849ecb7dd6 | ||
|
|
e41bd6bee7 | ||
|
|
359198c1ea | ||
|
|
beebf01223 | ||
|
|
2d4ea1bbf4 | ||
|
|
ea3a7e99a7 | ||
|
|
be0fe5dc5a | ||
|
|
12669d9f82 | ||
|
|
f12159bfb9 | ||
|
|
1590e1f3f7 | ||
|
|
a69f945b91 | ||
|
|
7da67899db | ||
|
|
62e032e4c5 | ||
|
|
6fefa2d9ff | ||
|
|
bb354cc706 | ||
|
|
fabc061731 | ||
|
|
82c3e2b346 | ||
|
|
e2e1d5b8a5 | ||
|
|
9342b9b2b3 | ||
|
|
9a7db6c243 | ||
|
|
c7545e6947 | ||
|
|
b7f52dd17b | ||
|
|
eb5bed0f09 | ||
|
|
1827a463eb | ||
|
|
b532a63fc6 | ||
|
|
4e5a4172bf | ||
|
|
31ce894fda | ||
|
|
16c900de84 | ||
|
|
413afd96de | ||
|
|
a0a0ac69d4 | ||
|
|
17453983ad | ||
|
|
a6550aa069 | ||
|
|
02e7b3897c | ||
|
|
34b89a8e34 | ||
|
|
0eabfebd0f | ||
|
|
5b2e5eac65 | ||
|
|
415064480a | ||
|
|
f00453f703 |
No files matched your search
Vendored
+2
-1
@@ -5,6 +5,7 @@
|
|||||||
"syscall",
|
"syscall",
|
||||||
"printf",
|
"printf",
|
||||||
"printInline",
|
"printInline",
|
||||||
"toHex"
|
"toHex",
|
||||||
|
"loadcstr"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
[](https://pinestore.cc/projects/225/hyperionos)
|
||||||
# HyperionOS
|
# HyperionOS
|
||||||
|
|
||||||
HyperionOS is a modular, hybrid kernel operating system written entirely in Lua. It features a custom task scheduler, virtual filesystem, syscall interface, and separates core functionality from user-space services.
|
HyperionOS is a modular, hybrid kernel operating system written entirely in Lua. It features a custom task scheduler, virtual filesystem, syscall interface, and separates core functionality from user-space services.
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
local name = syscall.getTask(syscall.getpid()).name
|
|
||||||
local fs = require("sys.fs")
|
|
||||||
|
|
||||||
if not args[1] then
|
|
||||||
while true do
|
|
||||||
local content = syscall.read(0, 1024)
|
|
||||||
if not content or content == "" then break end
|
|
||||||
printInline(content)
|
|
||||||
end
|
|
||||||
print("")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
for _, arg in ipairs(args) do
|
|
||||||
local filePath = arg
|
|
||||||
if filePath:sub(1,1) ~= "/" then
|
|
||||||
filePath = syscall.getcwd().."/"..filePath
|
|
||||||
end
|
|
||||||
|
|
||||||
if not fs.exists(filePath) then
|
|
||||||
print(name..": Cannot access '"..arg.."': No such file.")
|
|
||||||
else
|
|
||||||
local fd = syscall.open(filePath, "r")
|
|
||||||
while true do
|
|
||||||
local content = syscall.read(fd, 1024)
|
|
||||||
if not content or content == "" then break end
|
|
||||||
printInline(content)
|
|
||||||
end
|
|
||||||
syscall.close(fd)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
print("")
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
syscall.devctl(1,"clear")
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
print(table.concat(args, " "))
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
syscall.open("/dev/tty/tty1","r")
|
|
||||||
syscall.open("/dev/tty/tty1","w")
|
|
||||||
syscall.open("/dev/null","r")
|
|
||||||
syscall.devctl(1,"clear")
|
|
||||||
syscall.devctl(1,"sfgc",1)
|
|
||||||
syscall.devctl(1,"spos",1,1)
|
|
||||||
print("HyperionOS hysh Shell")
|
|
||||||
local str=""
|
|
||||||
local stopInput=false
|
|
||||||
local proc=0
|
|
||||||
local fs=require("sys.fs")
|
|
||||||
local timeout=false
|
|
||||||
syscall.setEnviron("SHELL","simpleshell")
|
|
||||||
printInline("> ")
|
|
||||||
syscall.sigcatch(function(sig)
|
|
||||||
if sig==1 then
|
|
||||||
syscall.kill(proc)
|
|
||||||
print("Terminated")
|
|
||||||
printInline("> ")
|
|
||||||
stopInput=false
|
|
||||||
end
|
|
||||||
end)
|
|
||||||
|
|
||||||
while true do
|
|
||||||
if not stopInput then
|
|
||||||
local input=syscall.read(0)
|
|
||||||
if input then
|
|
||||||
if input=="\b" then
|
|
||||||
if #str>0 then
|
|
||||||
str=str:sub(1,#str-1)
|
|
||||||
printInline("\b")
|
|
||||||
end
|
|
||||||
elseif input=="\n" then
|
|
||||||
print("")
|
|
||||||
stopInput=true
|
|
||||||
if str == "" then
|
|
||||||
printInline("> ")
|
|
||||||
stopInput=false
|
|
||||||
else
|
|
||||||
local path=nil
|
|
||||||
local split=string.split(str, " ")
|
|
||||||
if fs.exists("/bin/"..split[1]) then
|
|
||||||
path="/bin/"..split[1]
|
|
||||||
elseif fs.exists("/bin/"..split[1]..".lua") then
|
|
||||||
path="/bin/"..split[1]..".lua"
|
|
||||||
end
|
|
||||||
if not path then
|
|
||||||
print("Program not found")
|
|
||||||
printInline("> ")
|
|
||||||
stopInput=false
|
|
||||||
else
|
|
||||||
local text = fs.readAllText(path)
|
|
||||||
local program, err = load(text, path)
|
|
||||||
if not program then
|
|
||||||
print(err)
|
|
||||||
printInline("> ")
|
|
||||||
end
|
|
||||||
proc = syscall.spawn(function(...)
|
|
||||||
syscall.open("/dev/tty/tty1","r")
|
|
||||||
syscall.open("/dev/tty/tty1","w")
|
|
||||||
syscall.open("/dev/null","w")
|
|
||||||
program(...)
|
|
||||||
end, path, nil, {table.unpack(split, 2)})
|
|
||||||
end
|
|
||||||
str=""
|
|
||||||
end
|
|
||||||
else
|
|
||||||
str=str..input
|
|
||||||
printInline(input)
|
|
||||||
end
|
|
||||||
timeout=false
|
|
||||||
else
|
|
||||||
timeout=true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
local exited, code = syscall.collect(proc)
|
|
||||||
if exited then
|
|
||||||
if code then
|
|
||||||
print("\nTask exited with code:\n"..tostring(code))
|
|
||||||
end
|
|
||||||
printInline("> ")
|
|
||||||
stopInput=false
|
|
||||||
end
|
|
||||||
timeout=true
|
|
||||||
end
|
|
||||||
if timeout then
|
|
||||||
if stopInput then
|
|
||||||
sleep(.5)
|
|
||||||
else
|
|
||||||
sleep(.05)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
print("HyperionOS lua")
|
|
||||||
local str=""
|
|
||||||
local stopInput=false
|
|
||||||
local timeout=false
|
|
||||||
local luaEnv=setmetatable({},{__index=_ENV})
|
|
||||||
printInline("> ")
|
|
||||||
while true do
|
|
||||||
local input=syscall.read(0)
|
|
||||||
if input then
|
|
||||||
if input=="\b" then
|
|
||||||
if #str>0 then
|
|
||||||
str=str:sub(1,#str-1)
|
|
||||||
printInline("\b")
|
|
||||||
end
|
|
||||||
elseif input=="\n" then
|
|
||||||
print("")
|
|
||||||
stopInput=true
|
|
||||||
if str == "" then
|
|
||||||
printInline("> ")
|
|
||||||
stopInput=false
|
|
||||||
elseif str == "exit()" then
|
|
||||||
break
|
|
||||||
else
|
|
||||||
local func=load(str,"@Lua","t",luaEnv)
|
|
||||||
local ok,err = xpcall(func, debug.traceback)
|
|
||||||
if not ok then
|
|
||||||
print(err)
|
|
||||||
end
|
|
||||||
printInline("\n> ")
|
|
||||||
str=""
|
|
||||||
end
|
|
||||||
str=""
|
|
||||||
else
|
|
||||||
str=str..input
|
|
||||||
printInline(input)
|
|
||||||
end
|
|
||||||
timeout=false
|
|
||||||
else
|
|
||||||
timeout=true
|
|
||||||
end
|
|
||||||
|
|
||||||
if timeout then
|
|
||||||
if stopInput then
|
|
||||||
sleep(.5)
|
|
||||||
else
|
|
||||||
sleep(.05)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@@ -1,23 +0,0 @@
|
|||||||
local args = {...}
|
|
||||||
local name = syscall.getTask(syscall.getpid()).name
|
|
||||||
if #args == 0 then
|
|
||||||
print(name..": Missing operand.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
local fs = require("sys.fs")
|
|
||||||
local newDir = args[1]
|
|
||||||
if newDir:sub(1, 1) ~= "/" then
|
|
||||||
newDir = syscall.getcwd().."/"..newDir
|
|
||||||
end
|
|
||||||
|
|
||||||
if newDir:sub(#newDir, #newDir) ~= "/" then
|
|
||||||
newDir = newDir.."/"
|
|
||||||
end
|
|
||||||
|
|
||||||
if fs.isDir(newDir) then
|
|
||||||
print(name..": Cannot create directory '"..args[1].."': Directory already exists.")
|
|
||||||
return
|
|
||||||
end
|
|
||||||
|
|
||||||
fs.mkdir(newDir)
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
print(syscall.getcwd())
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
local syscalls=syscall.sysdump()
|
|
||||||
for i=1, #syscalls do
|
|
||||||
print(syscalls[i])
|
|
||||||
end
|
|
||||||
print("Total # of syscalls: "..tostring(#syscalls))
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
print((syscall.getUsername() or "Unknown"))
|
|
||||||
@@ -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
|
||||||
|
}
|
||||||
File renamed without changes.
File renamed without changes.
@@ -1,5 +1,5 @@
|
|||||||
local io = {}
|
local io = {}
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
|
|
||||||
function io.open(path, mode)
|
function io.open(path, mode)
|
||||||
return fs.open(path, mode)
|
return fs.open(path, mode)
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
local sys = {}
|
|
||||||
local fs = require("sys.fs")
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
return sys
|
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
local sys = {}
|
|
||||||
sys.fs = require("sys.fs")
|
|
||||||
sys.hpv = require("sys.hpv")
|
|
||||||
sys.ipc = require("sys.ipc")
|
|
||||||
return sys
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
local ipc = {}
|
|
||||||
|
|
||||||
return ipc
|
|
||||||
@@ -1,71 +0,0 @@
|
|||||||
local term = {}
|
|
||||||
|
|
||||||
function term.clear()
|
|
||||||
coroutine.yield("VFS_write", 1, "\27C\25")
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.setCursorPos(x, y)
|
|
||||||
coroutine.yield("VFS_write", 1, "\27cs"..tostring(y)..";"..tostring(x).."\25")
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.size()
|
|
||||||
coroutine.yield("VFS_write", 1, "\27ts\25")
|
|
||||||
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
|
|
||||||
if not ok then error("Failed to get terminal size") end
|
|
||||||
local x, y = string.match(data, "%R(%d+);(%d+)\25")
|
|
||||||
return tonumber(x), tonumber(y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.getCursorPos()
|
|
||||||
coroutine.yield("VFS_write", 1, "\27gc\25")
|
|
||||||
local ok, data = coroutine.yield("VFS_read", 0, 16) -- read response
|
|
||||||
if not ok then error("Failed to get cursor position") end
|
|
||||||
local y, x = string.match(data, "%R(%d+);(%d+)\25")
|
|
||||||
return tonumber(x), tonumber(y)
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.write(data)
|
|
||||||
coroutine.yield("VFS_write", 1, data)
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.setTextColor(color)
|
|
||||||
local ok, err = coroutine.yield("VFS_type", 1)
|
|
||||||
if not ok then error(err) end
|
|
||||||
if ok ~= "tty" then return end
|
|
||||||
coroutine.yield("VFS_write", 1, "\27f"..tostring(color).."\25")
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.setBackgroundColor(color)
|
|
||||||
local ok, err = coroutine.yield("VFS_type", 1)
|
|
||||||
if not ok then error(err) end
|
|
||||||
if ok ~= "tty" then return end
|
|
||||||
coroutine.yield("VFS_write", 1, "\27b"..tostring(color).."\25")
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.isColor()
|
|
||||||
local ok, err = coroutine.yield("VFS_type", 1)
|
|
||||||
if not ok then error(err) end
|
|
||||||
return ok == "tty"
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.scroll(n)
|
|
||||||
coroutine.yield("VFS_write", 1, "\27S"..tostring(n).."\25")
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.setDefault(color, layer)
|
|
||||||
if layer then
|
|
||||||
coroutine.yield("VFS_write", 1, "\27F"..tostring(color).."\25")
|
|
||||||
else
|
|
||||||
coroutine.yield("VFS_write", 1, "\27B"..tostring(color).."\25")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function term.showCursor(show)
|
|
||||||
if show then
|
|
||||||
coroutine.yield("VFS_write", 1, "\27sc\25")
|
|
||||||
else
|
|
||||||
coroutine.yield("VFS_write", 1, "\27hc\25")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return term
|
|
||||||
@@ -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
|
||||||
@@ -0,0 +1,316 @@
|
|||||||
|
-- :Minify:--
|
||||||
|
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||||
|
---@diagnostic disable-next-line: undefined-global
|
||||||
|
local term = term
|
||||||
|
local os = os
|
||||||
|
local function write(text)
|
||||||
|
local x, y = term.getCursorPos()
|
||||||
|
local w, h = term.getSize()
|
||||||
|
|
||||||
|
for i = 1, #text do
|
||||||
|
local c = text:sub(i, i)
|
||||||
|
|
||||||
|
if c == "\n" then
|
||||||
|
y = y + 1
|
||||||
|
x = 1
|
||||||
|
elseif c == "\t" then
|
||||||
|
local tabSize = 4
|
||||||
|
local spaces = tabSize - ((x - 1) % tabSize)
|
||||||
|
term.write(string.rep(" ", spaces))
|
||||||
|
x = x + spaces
|
||||||
|
elseif c == "\b" then
|
||||||
|
if x > 1 then
|
||||||
|
x = x - 1
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(" ")
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if x <= w and y <= h then
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(c)
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x > w then
|
||||||
|
x = 1
|
||||||
|
y = y + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if y - 1 >= h then
|
||||||
|
term.scroll(1)
|
||||||
|
y = h
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function displaySuperBadError(err)
|
||||||
|
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
|
||||||
|
|
||||||
|
term.setCursorBlink(false)
|
||||||
|
local ok, err = xpcall(function()
|
||||||
|
local apis = {BOOT_DRIVE_PATH = BOOT_DRIVE_PATH}
|
||||||
|
|
||||||
|
local lua = {
|
||||||
|
coroutine = true,
|
||||||
|
debug = 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 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 acekeys={
|
||||||
|
[apis.keys.enter]="\n",
|
||||||
|
[apis.keys.tab]="\t",
|
||||||
|
[apis.keys.backspace]="\b",
|
||||||
|
[apis.keys.up]="\17",
|
||||||
|
[apis.keys.down]="\18",
|
||||||
|
[apis.keys.left]="\19",
|
||||||
|
[apis.keys.right]="\20",
|
||||||
|
}
|
||||||
|
|
||||||
|
function sleep(time)
|
||||||
|
local stoptime = apis.os.clock() + (time)
|
||||||
|
while stoptime > apis.os.clock() do end
|
||||||
|
end
|
||||||
|
|
||||||
|
apis.term.setPaletteColor(0x1, 0xFFFFFF) -- #000000
|
||||||
|
apis.term.setPaletteColor(0x2, 0xFF0000) -- #FFFFFF
|
||||||
|
apis.term.setPaletteColor(0x4, 0x00FF00) -- #FF0000
|
||||||
|
apis.term.setPaletteColor(0x8, 0x0000FF) -- #00FF00
|
||||||
|
apis.term.setPaletteColor(0x10, 0x00FFFF) -- #0000FF
|
||||||
|
apis.term.setPaletteColor(0x20, 0xFF00FF) -- #00FFFF
|
||||||
|
apis.term.setPaletteColor(0x40, 0xFFFF00) -- #FF00FF
|
||||||
|
apis.term.setPaletteColor(0x80, 0xFF6D00) -- #FFFF00
|
||||||
|
apis.term.setPaletteColor(0x100, 0x6DFF55) -- #FF6D00
|
||||||
|
apis.term.setPaletteColor(0x200, 0x24FFFF) -- #6DFF55
|
||||||
|
apis.term.setPaletteColor(0x400, 0x924900) -- #24FFFF
|
||||||
|
apis.term.setPaletteColor(0x800, 0x6D6D55) -- #924900
|
||||||
|
apis.term.setPaletteColor(0x1000, 0xDBDBAA) -- #6D6D55
|
||||||
|
apis.term.setPaletteColor(0x2000, 0x6D00FF) -- #DBDBAA
|
||||||
|
apis.term.setPaletteColor(0x4000, 0xB6FF00) -- #6D00FF
|
||||||
|
apis.term.setPaletteColor(0x8000, 0x000000) -- #B6FF00
|
||||||
|
|
||||||
|
local function getFile(path)
|
||||||
|
local file = apis.fs.open(path, "r")
|
||||||
|
if not file then
|
||||||
|
displaySuperBadError("Could not open file: " .. path)
|
||||||
|
end
|
||||||
|
local content = file.readAll()
|
||||||
|
file.close()
|
||||||
|
return content
|
||||||
|
end
|
||||||
|
|
||||||
|
local Kernel = load(getFile(BOOT_DRIVE_PATH .. "/boot/kernel.lua"),"@Kernel")
|
||||||
|
local initFs = load(getFile(BOOT_DRIVE_PATH .. "/boot/cct/initdisks"),"@Init_disks")(apis)
|
||||||
|
local fs = load(getFile(BOOT_DRIVE_PATH .. "/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 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,
|
||||||
|
getMachineEvent = function()
|
||||||
|
if #eventQueue > 0 then
|
||||||
|
return table.unpack(table.remove(eventQueue, 1))
|
||||||
|
else
|
||||||
|
return nil
|
||||||
|
end
|
||||||
|
end,
|
||||||
|
getEEPROM = function() return getFile("/startup.lua") end,
|
||||||
|
setEEPROM = function(_, text)
|
||||||
|
local h = apis.fs.open("/startup.lua", "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",
|
||||||
|
{
|
||||||
|
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
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local BOOT_DRIVE_PATH=({...})[1] or "/$"
|
||||||
|
-- UnBIOS by JackMacWindows
|
||||||
|
-- This will undo most of the changes/additions made in the BIOS, but some things may remain wrapped if `debug` is unavailable
|
||||||
|
-- To use, just place a `bios.lua` in the root of the drive, and run this program
|
||||||
|
-- Here's a list of things that are irreversibly changed:
|
||||||
|
-- * both `bit` and `bit32` are kept for compatibility
|
||||||
|
-- * string metatable blocking (on old versions of CC)
|
||||||
|
-- In addition, if `debug` is not available these things are also irreversibly changed:
|
||||||
|
-- * old Lua 5.1 `load` function (for loading from a function)
|
||||||
|
-- * `loadstring` prefixing (before CC:T 1.96.0)
|
||||||
|
-- * `http.request`
|
||||||
|
-- * `os.shutdown` and `os.reboot`
|
||||||
|
-- * `peripheral`
|
||||||
|
-- * `turtle.equip[Left|Right]`
|
||||||
|
-- Licensed under the MIT license
|
||||||
|
local args = {...}
|
||||||
|
local keptAPIs = {keys=true, bit32 = true, bit = true, ccemux = true, config = true, coroutine = true, debug = true, fs = true, http = true, mounter = true, os = true, periphemu = true, peripheral = true, redstone = true, rs = true, term = true, utf8 = true, _HOST = true, _CC_DEFAULT_SETTINGS = true, _CC_DISABLE_LUA51_FEATURES = true, _VERSION = true, assert = true, collectgarbage = true, error = true, gcinfo = true, getfenv = true, getmetatable = true, ipairs = true, __inext = true,load = true, loadstring = true, math = true, newproxy = true, next = true, pairs = true, pcall = true, rawequal = true, rawget = true, rawlen = true, rawset = true, select = true, setfenv = true, setmetatable = true, string = true, table = true, tonumber = true, tostring = true, type = true, unpack = true, xpcall = true, turtle = true, pocket = true, commands = true, _G = true}
|
||||||
|
local t = {}
|
||||||
|
for k in pairs(_G) do if not keptAPIs[k] then table.insert(t, k) end end
|
||||||
|
for _,k in ipairs(t) do _G[k] = nil end
|
||||||
|
local native = _G.term.native()
|
||||||
|
for _, method in ipairs {"nativePaletteColor", "nativePaletteColour", "screenshot"} do native[method] = _G.term[method] end
|
||||||
|
_G.term = native
|
||||||
|
if _G.http then
|
||||||
|
_G.http.checkURL = _G.http.checkURLAsync
|
||||||
|
_G.http.websocket = _G.http.websocketAsync
|
||||||
|
end
|
||||||
|
if _G.commands then _G.commands = _G.commands.native end
|
||||||
|
if _G.turtle then _G.turtle.native, _G.turtle.craft = nil end
|
||||||
|
local delete = {os = {"version", "pullEventRaw", "pullEvent", "run", "loadAPI", "unloadAPI", "sleep"}, http = _G.http and {"get", "post", "put", "delete", "patch", "options", "head", "trace", "listen", "checkURLAsync", "websocketAsync"}, fs = {"complete", "isDriveRoot"}}
|
||||||
|
for k,v in pairs(delete) do for _,a in ipairs(v) do _G[k][a] = nil end end
|
||||||
|
-- Set up TLCO
|
||||||
|
-- This functions by crashing `rednet.run` by removing `os.pullEventRaw`. Normally
|
||||||
|
-- this would cause `parallel` to throw an error, but we replace `error` with an
|
||||||
|
-- empty placeholder to let it continue and return without throwing. This results
|
||||||
|
-- in the `pcall` returning successfully, preventing the error-displaying code
|
||||||
|
-- from running - essentially making it so that `os.shutdown` is called immediately
|
||||||
|
-- after the new BIOS exits.
|
||||||
|
--
|
||||||
|
-- From there, the setup code is placed in `term.native` since it's the first
|
||||||
|
-- thing called after `parallel` exits. This loads the new BIOS and prepares it
|
||||||
|
-- for execution. Finally, it overwrites `os.shutdown` with the new function to
|
||||||
|
-- allow it to be the last function called in the original BIOS, and returns.
|
||||||
|
-- From there execution continues, calling the `term.redirect` dummy, skipping
|
||||||
|
-- over the error-handling code (since `pcall` returned ok), and calling
|
||||||
|
-- `os.shutdown()`. The real `os.shutdown` is re-added, and the new BIOS is tail
|
||||||
|
-- called, which effectively makes it run as the main chunk.
|
||||||
|
local olderror = error
|
||||||
|
_G.error = function() end
|
||||||
|
_G.term.redirect = function() end
|
||||||
|
function _G.term.native()
|
||||||
|
_G.term.native = nil
|
||||||
|
_G.term.redirect = nil
|
||||||
|
_G.error = olderror
|
||||||
|
term.setBackgroundColor(32768)
|
||||||
|
term.setTextColor(1)
|
||||||
|
term.setCursorPos(1, 1)
|
||||||
|
term.setCursorBlink(true)
|
||||||
|
term.clear()
|
||||||
|
local file = fs.open(BOOT_DRIVE_PATH.."/boot/cct/boot.lua", "r")
|
||||||
|
if file == 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 fn, err = loadstring(file.readAll(), "@bootloader")
|
||||||
|
file.close()
|
||||||
|
if fn == 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(err)
|
||||||
|
term.setCursorPos(1, 3)
|
||||||
|
term.write("Press any key to continue")
|
||||||
|
coroutine.yield("key")
|
||||||
|
os.shutdown()
|
||||||
|
end
|
||||||
|
setfenv(fn, _G)
|
||||||
|
local oldshutdown = os.shutdown
|
||||||
|
os.shutdown = function()
|
||||||
|
os.shutdown = oldshutdown
|
||||||
|
return fn(BOOT_DRIVE_PATH)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if debug then
|
||||||
|
-- Restore functions that were overwritten in the BIOS
|
||||||
|
-- Apparently this has to be done *after* redefining term.native
|
||||||
|
local function restoreValue(tab, idx, name, hint)
|
||||||
|
local i, key, value = 1, debug.getupvalue(tab[idx], hint)
|
||||||
|
while key ~= name and key ~= nil do
|
||||||
|
key, value = debug.getupvalue(tab[idx], i)
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
tab[idx] = value or tab[idx]
|
||||||
|
end
|
||||||
|
restoreValue(_G, "loadstring", "nativeloadstring", 1)
|
||||||
|
restoreValue(_G, "load", "nativeload", 5)
|
||||||
|
if http then restoreValue(http, "request", "nativeHTTPRequest", 3) end
|
||||||
|
restoreValue(os, "shutdown", "nativeShutdown", 1)
|
||||||
|
restoreValue(os, "reboot", "nativeReboot", 1)
|
||||||
|
if turtle then
|
||||||
|
restoreValue(turtle, "equipLeft", "v", 1)
|
||||||
|
restoreValue(turtle, "equipRight", "v", 1)
|
||||||
|
end
|
||||||
|
do
|
||||||
|
local i, key, value = 1, debug.getupvalue(peripheral.isPresent, 2)
|
||||||
|
while key ~= "native" and key ~= nil do
|
||||||
|
key, value = debug.getupvalue(peripheral.isPresent, i)
|
||||||
|
i=i+1
|
||||||
|
end
|
||||||
|
_G.peripheral = value or peripheral
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
-- :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}
|
||||||
+39
-8
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
local apis = kernel.apis
|
local apis = kernel.apis
|
||||||
local native = apis.peripheral
|
local native = apis.peripheral
|
||||||
@@ -311,13 +311,24 @@ local fifo = kernel.newFifo()
|
|||||||
kernel.processes.cctmond = function()
|
kernel.processes.cctmond = function()
|
||||||
local timeout = false
|
local timeout = false
|
||||||
while true do
|
while true do
|
||||||
local event = {kernel.computer:getMachineEvent()}
|
local event = {kernel.EFI:getMachineEvent()}
|
||||||
|
|
||||||
if event[1] then
|
if event[1] then
|
||||||
local eventType = event[1]
|
local eventType = event[1]
|
||||||
local charOrKey = event[3]
|
local charOrKey = event[3]
|
||||||
|
|
||||||
-- Update modifier keys
|
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 eventType == "keyPressed" then
|
||||||
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
if charOrKey == apis.keys.leftCtrl or charOrKey == apis.keys.rightCtrl then
|
||||||
ctrl = true
|
ctrl = true
|
||||||
@@ -325,11 +336,31 @@ kernel.processes.cctmond = function()
|
|||||||
alt = true
|
alt = true
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Handle Ctrl+C
|
if ctrl then
|
||||||
if ctrl and charOrKey == apis.keys.c then
|
local ctrlByte = ctrlKeyMap[charOrKey]
|
||||||
|
if ctrlByte then
|
||||||
|
if ctrlByte == 3 then
|
||||||
for _, task in ipairs(syscall.getTasks()) do
|
for _, task in ipairs(syscall.getTasks()) do
|
||||||
syscall.sigsend(task, 1) -- SIGINT
|
syscall.sigsend(task, 1)
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
elseif eventType == "keyReleased" then
|
elseif eventType == "keyReleased" then
|
||||||
@@ -354,10 +385,10 @@ kernel.processes.cctmond = function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
newtty(apis.term, "TTY1", fifo.pop)
|
newtty(apis.term, "1", fifo.pop)
|
||||||
|
|
||||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||||
v.setTextScale(.5)
|
v.setTextScale(.5)
|
||||||
v.write("Initializing...")
|
v.write("Initializing...")
|
||||||
newtty(v,"TTY"..tostring(i+1),function () end)
|
newtty(v,tostring(i+1),function () end)
|
||||||
end
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
local BOOT_DRIVE_PATH = ({...})[1] or "/$"
|
||||||
---@diagnostic disable-next-line: undefined-global
|
---@diagnostic disable-next-line: undefined-global
|
||||||
local term = term
|
local term = term
|
||||||
@@ -71,7 +71,6 @@ local ok, err = xpcall(function()
|
|||||||
collectgarbage = true,
|
collectgarbage = true,
|
||||||
error = true,
|
error = true,
|
||||||
gcinfo = true,
|
gcinfo = true,
|
||||||
getfenv = true,
|
|
||||||
getmetatable = true,
|
getmetatable = true,
|
||||||
ipairs = true,
|
ipairs = true,
|
||||||
__inext = true,
|
__inext = true,
|
||||||
@@ -85,7 +84,6 @@ local ok, err = xpcall(function()
|
|||||||
rawlen = true,
|
rawlen = true,
|
||||||
rawset = true,
|
rawset = true,
|
||||||
select = true,
|
select = true,
|
||||||
setfenv = true,
|
|
||||||
setmetatable = true,
|
setmetatable = true,
|
||||||
string = true,
|
string = true,
|
||||||
table = true,
|
table = true,
|
||||||
@@ -154,17 +152,99 @@ local ok, err = xpcall(function()
|
|||||||
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
if not initFs then displaySuperBadError("Could not load initdisks.") end
|
||||||
if not fs then displaySuperBadError("Could not load initfs.") 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 eventQueue = {}
|
local eventQueue = {}
|
||||||
|
|
||||||
local function queueEvent(event, ...)
|
local function queueEvent(event, ...)
|
||||||
table.insert(eventQueue, {event, ...})
|
table.insert(eventQueue, {event, ...})
|
||||||
end
|
end
|
||||||
|
|
||||||
local computer = {
|
local colors = {
|
||||||
time = function() return apis.os.epoch("utc") end,
|
[0x000000]=0x0001,
|
||||||
clock = function() return apis.os.clock() * 1000 end,
|
[0xFFFFFF]=0x0002,
|
||||||
shutdown = apis.os.shutdown,
|
[0xFF0000]=0x0004,
|
||||||
reboot = apis.os.reboot,
|
[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()
|
getMachineEvent = function()
|
||||||
if #eventQueue > 0 then
|
if #eventQueue > 0 then
|
||||||
return table.unpack(table.remove(eventQueue, 1))
|
return table.unpack(table.remove(eventQueue, 1))
|
||||||
@@ -177,56 +257,10 @@ local ok, err = xpcall(function()
|
|||||||
local h = apis.fs.open("/startup.lua", "w")
|
local h = apis.fs.open("/startup.lua", "w")
|
||||||
h.write(text)
|
h.write(text)
|
||||||
h.close()
|
h.close()
|
||||||
end
|
end,
|
||||||
}
|
initfs=fs,
|
||||||
|
disks=initFs,
|
||||||
local icolors = {
|
screenCtl={
|
||||||
[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,
|
print = function(_, text) write(text .. "\n") end,
|
||||||
printInline = function(_, text) write(text) end,
|
printInline = function(_, text) write(text) end,
|
||||||
clear = function()
|
clear = function()
|
||||||
@@ -239,25 +273,51 @@ local ok, err = xpcall(function()
|
|||||||
getCursorPos = function() return apis.term.getCursorPos() end,
|
getCursorPos = function() return apis.term.getCursorPos() end,
|
||||||
getSize = function() return apis.term.getSize() end,
|
getSize = function() return apis.term.getSize() end,
|
||||||
setBackgroundColor = function(_, color)
|
setBackgroundColor = function(_, color)
|
||||||
apis.term.setBackgroundColor(colors[color])
|
apis.term.setBackgroundColor(aprox(color))
|
||||||
end,
|
end,
|
||||||
setTextColor = function(_, color)
|
setTextColor = function(_, color)
|
||||||
apis.term.setTextColor(colors[color])
|
apis.term.setTextColor(aprox(color))
|
||||||
end,
|
end,
|
||||||
getBackgroundColor = function()
|
getBackgroundColor = function()
|
||||||
return icolors[apis.term.getBackgroundColor()]
|
return bg
|
||||||
end,
|
end,
|
||||||
getTextColor = function()
|
getTextColor = function()
|
||||||
return icolors[apis.term.getTextColor()]
|
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
|
||||||
}, computer, fs, "$")
|
|
||||||
if not ok then displaySuperBadError(err) end
|
|
||||||
end)
|
end)
|
||||||
|
|
||||||
function coroutine.resumeWithTimeout(co, timeout, ...)
|
function coroutine.resumeWithTimeout(co, timeout, ...)
|
||||||
local startTime = computer.time()
|
local startTime = EFI.getEpochMs()
|
||||||
debug.sethook(co, function()
|
debug.sethook(co, function()
|
||||||
if computer.time() > startTime + timeout then
|
if EFI.getEpochMs() > startTime + timeout then
|
||||||
return coroutine.yield("timeout")
|
return coroutine.yield("timeout")
|
||||||
end
|
end
|
||||||
end, "", 1000)
|
end, "", 1000)
|
||||||
@@ -306,11 +366,15 @@ local ok, err = xpcall(function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
if status == "error" or coroutine.status(kernelCoro) == "dead" then
|
||||||
|
if EFI.reboot then
|
||||||
|
apis.os.reboot()
|
||||||
|
end
|
||||||
displaySuperBadError("Kernel error: " .. tostring(err))
|
displaySuperBadError("Kernel error: " .. tostring(err))
|
||||||
coroutine.yield("key")
|
coroutine.yield("key")
|
||||||
end
|
end
|
||||||
|
initFs:refresh()
|
||||||
end
|
end
|
||||||
end, debug.traceback)
|
end, debug.traceback)
|
||||||
|
|
||||||
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
if not ok then displaySuperBadError("Fatal error during boot: " .. err) end
|
||||||
while true do coroutine.yield() end
|
while true do coroutine.yield("key") end
|
||||||
@@ -1,36 +1,152 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local apis = ({...})[1]
|
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 fs = apis.fs
|
||||||
local native = apis.peripheral
|
local native = apis.peripheral
|
||||||
local peripheral = {}
|
local peripheral = {}
|
||||||
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
local sides = {"top", "bottom", "left", "right", "front", "back"}
|
||||||
|
|
||||||
function peripheral.getType(name)
|
function peripheral.getNames()
|
||||||
if native.isPresent(name) then return native.getType(name) end
|
local results = {}
|
||||||
for n = 1, #sides do
|
for n = 1, #sides do
|
||||||
local side = sides[n]
|
local side = sides[n]
|
||||||
if native.hasType(side, "peripheral_hub") and
|
if native.isPresent(side) then
|
||||||
native.call(side, "isPresentRemote", name) then
|
table.insert(results, side)
|
||||||
return native.call(side, "getTypeRemote", name)
|
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
|
||||||
end
|
end
|
||||||
return nil
|
return nil
|
||||||
end
|
end
|
||||||
|
|
||||||
function peripheral.getNames()
|
function peripheral.getName(peripheral)
|
||||||
local names = {}
|
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
|
for n = 1, #sides do
|
||||||
local side = sides[n]
|
local side = sides[n]
|
||||||
if native.isPresent(side) then table.insert(names, side) end
|
if native.hasType(side, "peripheral_hub") and native.call(side, "isPresentRemote", name) then
|
||||||
if native.hasType(side, "peripheral_hub") then
|
return native.call(side, "callRemote", name, method, ...)
|
||||||
local hubSides = native.call(side, "getConnectedSides")
|
end
|
||||||
for _, hubSide in ipairs(hubSides) do
|
end
|
||||||
table.insert(names, hubSide)
|
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
|
end
|
||||||
end
|
end
|
||||||
return names
|
return table.unpack(results)
|
||||||
end
|
end
|
||||||
|
|
||||||
local disks = {}
|
local disks = {}
|
||||||
@@ -125,19 +241,20 @@ internal["$"] = createDisk("$", BOOT_DRIVE_PATH, false, {
|
|||||||
end
|
end
|
||||||
})
|
})
|
||||||
|
|
||||||
local function refresh()
|
internal["rom"] = createDisk("rom", "/rom", true, {
|
||||||
for id, _ in pairs(disks) do
|
setLabel = function(label)
|
||||||
if not peripheral.getType(id) then disks[id] = nil end
|
error("Device is read-only")
|
||||||
|
end,
|
||||||
|
getLabel = function()
|
||||||
|
return "cctrom"
|
||||||
end
|
end
|
||||||
|
})
|
||||||
|
|
||||||
for _, name in ipairs(peripheral.getNames()) do
|
local function refresh()
|
||||||
if peripheral.getType(name) == "disk" then
|
disks={}
|
||||||
if not disks[name] then
|
for _, disk in ipairs({peripheral.find("drive")}) do
|
||||||
local mount = disk.getMountPath(name)
|
if disk.isDiskPresent() then
|
||||||
if mount then
|
disks[tostring(disk.getDiskID())]=createDisk("cctdisk"..tostring(disk.getDiskID()), disk.getMountPath(), false, fs)
|
||||||
disks[name] = createDisk(name, mount, false, disk)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
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,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
|
||||||
@@ -0,0 +1,306 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
local peripheral=kernel.cct.peripheral
|
||||||
|
local keys=kernel.apis.keys
|
||||||
|
|
||||||
|
local colors = {
|
||||||
|
[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 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 function write(text, term)
|
||||||
|
local x, y = term.getCursorPos()
|
||||||
|
local w, h = term.getSize()
|
||||||
|
|
||||||
|
for i = 1, #text do
|
||||||
|
local c = text:sub(i, i)
|
||||||
|
|
||||||
|
if c == "\n" then
|
||||||
|
y = y + 1
|
||||||
|
x = 1
|
||||||
|
elseif c == "\t" then
|
||||||
|
local tabSize = 4
|
||||||
|
local spaces = tabSize - ((x - 1) % tabSize)
|
||||||
|
term.write(string.rep(" ", spaces))
|
||||||
|
x = x + spaces
|
||||||
|
elseif c == "\b" then
|
||||||
|
if x > 1 then
|
||||||
|
x = x - 1
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(" ")
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if x <= w and y <= h then
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
term.write(c)
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x > w then
|
||||||
|
x = 1
|
||||||
|
y = y + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if y - 1 >= h then
|
||||||
|
term.scroll(1)
|
||||||
|
y = h
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
term.setCursorPos(x, y)
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.devfs.data.tty={}
|
||||||
|
local ctrl,alt = false, false
|
||||||
|
|
||||||
|
local function serializeBool(bool)
|
||||||
|
if bool then
|
||||||
|
return "T"
|
||||||
|
else
|
||||||
|
return "F"
|
||||||
|
end
|
||||||
|
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(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"
|
||||||
|
elseif op=="open" then
|
||||||
|
local h = {
|
||||||
|
read=function(amount)
|
||||||
|
local rv=""
|
||||||
|
for i=1, amount or 1 do
|
||||||
|
local event = {ev()}
|
||||||
|
if event[1] then
|
||||||
|
rv=rv..event[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if rv=="" then rv=nil end
|
||||||
|
return rv
|
||||||
|
end,
|
||||||
|
write=function(content)
|
||||||
|
write(content, obj)
|
||||||
|
end,
|
||||||
|
size=function()
|
||||||
|
local s={obj.getSize()}
|
||||||
|
return table.concat(s,";")
|
||||||
|
end,
|
||||||
|
clear=function()
|
||||||
|
obj.clear()
|
||||||
|
obj.setCursorPos(1,1)
|
||||||
|
end,
|
||||||
|
gpos=function()
|
||||||
|
local s={obj.getCursorPos()}
|
||||||
|
return table.concat(s,";")
|
||||||
|
end,
|
||||||
|
spos=function(x,y)
|
||||||
|
return obj.setCursorPos(x,y)
|
||||||
|
end,
|
||||||
|
sfgc=function(c)
|
||||||
|
fg=c
|
||||||
|
return obj.setTextColor(aprox(c))
|
||||||
|
end,
|
||||||
|
sbgc=function(c)
|
||||||
|
bg=c
|
||||||
|
return obj.setBackgroundColor(aprox(c))
|
||||||
|
end,
|
||||||
|
gfgc=function()
|
||||||
|
return fg
|
||||||
|
end,
|
||||||
|
gbgc=function()
|
||||||
|
return bg
|
||||||
|
end,
|
||||||
|
gctrl=function()
|
||||||
|
return serializeBool(ctrl)..";"..serializeBool(alt)
|
||||||
|
end
|
||||||
|
}
|
||||||
|
if mode=="rw" then
|
||||||
|
return h
|
||||||
|
elseif mode=="r" then
|
||||||
|
h["write"]=nil
|
||||||
|
return h
|
||||||
|
elseif mode=="w" then
|
||||||
|
h["read"]=nil
|
||||||
|
return h
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local fifo = kernel.newFifo()
|
||||||
|
|
||||||
|
kernel.processes.cctmond = 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
|
||||||
|
ctrl = true
|
||||||
|
elseif charOrKey == keys.leftAlt or charOrKey == 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 = {
|
||||||
|
[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 fifo.push(special) end
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif eventType == "keyReleased" then
|
||||||
|
if charOrKey == keys.leftCtrl or charOrKey == keys.rightCtrl then
|
||||||
|
ctrl = false
|
||||||
|
elseif charOrKey == keys.leftAlt or charOrKey == 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(kernel.apis.term, "1", fifo.pop)
|
||||||
|
|
||||||
|
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||||
|
v.setTextScale(.5)
|
||||||
|
v.write("Initializing...")
|
||||||
|
newtty(v,tostring(i+1),function () end)
|
||||||
|
end
|
||||||
File renamed without changes.
File renamed without changes.
@@ -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
|
||||||
Whitespace-only changes.
@@ -1,3 +1,4 @@
|
|||||||
U $;/
|
U $;/
|
||||||
U devfs0000;/dev/
|
U devfs0000;/dev/
|
||||||
U tmpfs0000;/tmp/
|
U tmpfs0000;/tmp/
|
||||||
|
U procfs0000;/proc/
|
||||||
@@ -1,14 +1,12 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local args = {...}
|
local EFI=...
|
||||||
local apis = args[1]
|
local screen=EFI.screenCtl
|
||||||
local disks = args[2]
|
local ifs=EFI.initfs
|
||||||
local arch = args[3]
|
local disks=EFI.disks
|
||||||
local screen = args[5]
|
local arch=EFI.architecture
|
||||||
local computer = args[6]
|
|
||||||
local ifs = args[7]
|
|
||||||
local kernel = {}
|
local kernel = {}
|
||||||
kernel.LOG_Text=""
|
kernel.LOG_Text=""
|
||||||
kernel.version="HyperionOS V1.2.0"
|
kernel.version="HyperionOS V1.2.3"
|
||||||
kernel.process = "Kernel"
|
kernel.process = "Kernel"
|
||||||
kernel.users={[0]="root",[1]="User"}
|
kernel.users={[0]="root",[1]="User"}
|
||||||
kernel.hostname = "hyperion"
|
kernel.hostname = "hyperion"
|
||||||
@@ -26,28 +24,31 @@ _G.sleep=nil
|
|||||||
local windowsExp = false
|
local windowsExp = false
|
||||||
|
|
||||||
function kernel.log(msg, level, c)
|
function kernel.log(msg, level, c)
|
||||||
c=c or 12
|
c=c or 0x6D6D6D
|
||||||
kernel.LOG_Text = kernel.LOG_Text..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
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
|
if kernel.status == "start" then
|
||||||
screen:setTextColor(c)
|
screen:setTextColor(c)
|
||||||
screen:print(string.format("%X",c-1).." "..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
|
elseif kernel.status == "term" then
|
||||||
kernel.standbyTask=kernel.currentTask
|
kernel.standbyTask=kernel.currentTask
|
||||||
kernel.currentTask=kernel.kernelTask
|
kernel.currentTask=kernel.kernelTask
|
||||||
kernel.vfs.devctl(1,"sfgc",c)
|
local file=kernel.vfs.open("/dev/console", "w")
|
||||||
kernel.vfs.write(1,string.format("%X",c-1).." "..tostring(computer:time()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
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
|
kernel.currentTask=kernel.standbyTask
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.PANIC(msg)
|
function kernel.PANIC(msg)
|
||||||
if kernel.status~="Panic" then
|
if kernel.status~="Panic" then
|
||||||
kernel.log("PANIC: "..msg, "PANIC")
|
kernel.log("PANIC: "..msg, "PANIC", 0xFF0000)
|
||||||
pcall(kernel["saveLog"])
|
pcall(kernel["saveLog"])
|
||||||
kernel.status="Panic"
|
kernel.status="Panic"
|
||||||
kernel.reason=msg
|
kernel.reason=msg
|
||||||
screen:setTextColor(2)
|
screen:enable()
|
||||||
screen:setBackgroundColor(16)
|
screen:setTextColor(0xFF0000)
|
||||||
|
screen:setBackgroundColor(0x000000)
|
||||||
screen:clear()
|
screen:clear()
|
||||||
screen:setCursorPos(1,1)
|
screen:setCursorPos(1,1)
|
||||||
screen:print(kernel.LOG_Text)
|
screen:print(kernel.LOG_Text)
|
||||||
@@ -56,18 +57,19 @@ function kernel.PANIC(msg)
|
|||||||
kernel.exitMain = true
|
kernel.exitMain = true
|
||||||
end
|
end
|
||||||
while true do
|
while true do
|
||||||
local event={computer:getMachineEvent()}
|
local event={EFI:getMachineEvent()}
|
||||||
if event[1]=="keyPressed" then
|
if event[1]=="keyPressed" then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
computer:reboot()
|
EFI.reboot=true
|
||||||
|
error("KERNEL PANIC")
|
||||||
end
|
end
|
||||||
kernel.panic=kernel.PANIC
|
kernel.panic=kernel.PANIC
|
||||||
|
|
||||||
if windowsExp then
|
if windowsExp then
|
||||||
screen:setTextColor(1)
|
screen:setTextColor(0xFFFFFF)
|
||||||
screen:setBackgroundColor(4)
|
screen:setBackgroundColor(0x0000FF)
|
||||||
screen:clear()
|
screen:clear()
|
||||||
local w,h = screen:getSize()
|
local w,h = screen:getSize()
|
||||||
screen:setCursorPos(3,5)
|
screen:setCursorPos(3,5)
|
||||||
@@ -113,8 +115,9 @@ local split = function(str, delim, maxResultCountOrNil)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not ifs.isFile("/boot/boot.cfg") then
|
if not ifs.isFile("/boot/boot.cfg") then
|
||||||
kernel.log("boot.cfg missing or corrupted!, Attempting to write recovery boot.cfg", "ERROR", 2)
|
kernel.log("First boot detected writing boot.cfg", "INFO", 0x00FF00)
|
||||||
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
ifs.writeAllText("/boot/boot.cfg",ifs.readAllText("/boot/safeboot.cfg"))
|
||||||
|
kernel.firstBoot=true
|
||||||
end
|
end
|
||||||
|
|
||||||
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
local initCfgFunc, err = load(ifs.readAllText("/boot/boot.cfg"), "@boot.cfg")
|
||||||
@@ -129,24 +132,34 @@ if not initCfgStatus then
|
|||||||
end
|
end
|
||||||
kernel.config = config
|
kernel.config = config
|
||||||
|
|
||||||
|
local skip=false
|
||||||
for i,v in ipairs(split(fstab,"\n")) do
|
for i,v in ipairs(split(fstab,"\n")) do
|
||||||
if v:sub(1,1)=="U" then
|
if v:sub(1,1)=="U" then
|
||||||
local id=""
|
local id=""
|
||||||
for i=3,#v do
|
for i=3,#v do
|
||||||
if v:sub(i,i)==";" then
|
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)
|
id=v:sub(3,i-1)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if not skip then
|
||||||
local path=v:sub(#id+4)
|
local path=v:sub(#id+4)
|
||||||
ifs.mount(id,path)
|
ifs.mount(id,path)
|
||||||
::endline::
|
else
|
||||||
|
skip=false
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
kernel.log("Disks initialized")
|
kernel.log("Disks initialized")
|
||||||
|
|
||||||
function kernel.saveLog()
|
function kernel.saveLog()
|
||||||
|
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)
|
ifs.writeAllText("/var/log/syslog.log", kernel.LOG_Text)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.newFifo()
|
function kernel.newFifo()
|
||||||
@@ -186,7 +199,7 @@ kernel.log("Gathering modules")
|
|||||||
for _, i in ipairs(ifs.list("/lib/modules")) do
|
for _, i in ipairs(ifs.list("/lib/modules")) do
|
||||||
local modlist = ifs.list("/lib/modules/"..i)
|
local modlist = ifs.list("/lib/modules/"..i)
|
||||||
if not modlist then
|
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
|
else
|
||||||
for _,v in ipairs(modlist) do
|
for _,v in ipairs(modlist) do
|
||||||
local prior=tonumber(v:sub(1,2))
|
local prior=tonumber(v:sub(1,2))
|
||||||
@@ -198,8 +211,8 @@ for _, i in ipairs(ifs.list("/lib/modules")) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
kernel.ifs=ifs
|
kernel.ifs=ifs
|
||||||
kernel.apis=apis
|
kernel.apis=EFI.firmware
|
||||||
kernel.computer=computer
|
kernel.EFI=EFI
|
||||||
kernel.arch=arch
|
kernel.arch=arch
|
||||||
kernel.initdisks=disks
|
kernel.initdisks=disks
|
||||||
kernel.screen=screen
|
kernel.screen=screen
|
||||||
@@ -228,16 +241,19 @@ kernel.kernelTask = {
|
|||||||
kernel.currentTask = kernel.kernelTask
|
kernel.currentTask = kernel.kernelTask
|
||||||
|
|
||||||
function kernel.shutdown()
|
function kernel.shutdown()
|
||||||
kernel.computer:shutdown()
|
kernel.exitMain=true
|
||||||
|
kernel.status="shutdown"
|
||||||
end
|
end
|
||||||
|
|
||||||
function kernel.reboot()
|
function kernel.reboot()
|
||||||
kernel.computer:reboot()
|
kernel.exitMain=true
|
||||||
|
kernel.status="reboot"
|
||||||
end
|
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["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["getUsername"]=function(uid) return kernel.users[uid or kernel.uid] end
|
||||||
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
kernel.syscalls["getHostname"]=function() return kernel.hostname end
|
||||||
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
kernel.syscalls["getHost"]=function() return kernel.apis._HOST end
|
||||||
@@ -251,30 +267,35 @@ kernel.syscalls["sysdump"]=function()
|
|||||||
end
|
end
|
||||||
return rv
|
return rv
|
||||||
end
|
end
|
||||||
kernel.syscalls["test"]=function() return true end
|
kernel.syscalls["reboot"]=kernel.reboot
|
||||||
|
kernel.syscalls["shutdown"]=kernel.shutdown
|
||||||
|
|
||||||
kernel.log("Running modules")
|
kernel.log("Running modules")
|
||||||
for _,p in ipairs(modules) do
|
for _,p in ipairs(modules) do
|
||||||
for _,v in ipairs(p) do
|
for _,v in ipairs(p) do
|
||||||
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)
|
local code=ifs.readAllText(v)
|
||||||
if not code then
|
if not code then
|
||||||
kernel.log("ModuReadErr: "..v, "WARN", 8)
|
kernel.panic("Failed to read module "..v)
|
||||||
goto skip
|
|
||||||
end
|
end
|
||||||
local func,err=load(code,"@"..v)
|
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)
|
local status, err = xpcall(func,debug.traceback, kernel)
|
||||||
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
if not status then kernel.panic("ModuRunErr: "..tostring(err)) end
|
||||||
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 5) end
|
if kernel.config.showModLoad then kernel.log("Loaded module "..v, "DBUG", 0x00FFFF) end
|
||||||
::skip::
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("Kernel initialized successfully.")
|
kernel.log("Kernel initialized successfully.")
|
||||||
|
kernel.saveLog()
|
||||||
kernel.status="running"
|
kernel.status="running"
|
||||||
|
screen:disable()
|
||||||
kernel.main()
|
kernel.main()
|
||||||
|
kernel.panic("Exited main???")
|
||||||
if kernel.status=="panic" then
|
if kernel.status=="panic" then
|
||||||
kernel.panic()
|
kernel.panic(kernel.reason)
|
||||||
|
end
|
||||||
|
if kernel.status=="reboot" then
|
||||||
|
EFI.reboot=true
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
kernel.PANIC("Execution complete")
|
|
||||||
@@ -4,8 +4,9 @@
|
|||||||
-- This file is auto-generated during the build process.
|
-- This file is auto-generated during the build process.
|
||||||
-- DEFAULT BOOT CONFIGURATION FILE
|
-- DEFAULT BOOT CONFIGURATION FILE
|
||||||
return {
|
return {
|
||||||
initPath = "/sbin/init.lua",
|
initPath = "/sbin/init",
|
||||||
maxOpenFiles = 128,
|
maxOpenFiles = 128,
|
||||||
maxFilesPerTask = 16,
|
maxFilesPerTask = 16,
|
||||||
preempt=true
|
preempt=true,
|
||||||
|
logTaskExit=true
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,5 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
|
--- @diagnostic disable: duplicate-set-field
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
kernel.allowGlobalOverwrites = true
|
kernel.allowGlobalOverwrites = true
|
||||||
|
|
||||||
@@ -172,6 +173,27 @@ function table.indexOf(t, value)
|
|||||||
return -1
|
return -1
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function table.merge(...)
|
||||||
|
local args={...}
|
||||||
|
local out = {}
|
||||||
|
local outi = {}
|
||||||
|
|
||||||
|
for _,t in ipairs(args) do
|
||||||
|
for i,v in pairs(t) do
|
||||||
|
out[i]=v
|
||||||
|
end
|
||||||
|
for i,v in ipairs(t) do
|
||||||
|
outi[#outi+1]=v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
for i,v in ipairs(outi) do
|
||||||
|
out[i]=v
|
||||||
|
end
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
function string.replace(s, target, repl)
|
function string.replace(s, target, repl)
|
||||||
local result = {}
|
local result = {}
|
||||||
local i = 1
|
local i = 1
|
||||||
@@ -207,8 +229,12 @@ function toHex(num)
|
|||||||
return string.format("%X", num)
|
return string.format("%X", num)
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall = setmetatable({}, {
|
local function makeSyscallProxy()
|
||||||
|
local backing = {}
|
||||||
|
return setmetatable(backing, {
|
||||||
__index = function(self, name)
|
__index = function(self, name)
|
||||||
|
local raw = rawget(self, name)
|
||||||
|
if raw ~= nil then return raw end
|
||||||
return function(...)
|
return function(...)
|
||||||
local res = table.pack(coroutine.yield("syscall", name, ...))
|
local res = table.pack(coroutine.yield("syscall", name, ...))
|
||||||
if res[1] then
|
if res[1] then
|
||||||
@@ -217,7 +243,16 @@ syscall = setmetatable({}, {
|
|||||||
error(res[2], 2)
|
error(res[2], 2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end,
|
||||||
})
|
__newindex = function(self, k, v)
|
||||||
|
rawset(self, k, v)
|
||||||
|
end,
|
||||||
|
__metatable=false
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
syscall = makeSyscallProxy()
|
||||||
|
|
||||||
|
_makeSyscallProxy = makeSyscallProxy
|
||||||
|
|
||||||
table.serialize = serialize
|
table.serialize = serialize
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
local vfs = {}
|
local vfs = {}
|
||||||
kernel.vfs = vfs
|
kernel.vfs = vfs
|
||||||
@@ -113,57 +113,23 @@ end
|
|||||||
|
|
||||||
local SAFE_COMPONENT_PATTERN = "^[A-Za-z0-9_.+%-%@%(%)%[%]]+$"
|
local SAFE_COMPONENT_PATTERN = "^[A-Za-z0-9_.+%-%@%(%)%[%]]+$"
|
||||||
|
|
||||||
local function normalizePath(path)
|
local function tokenizePath(path)
|
||||||
local task = kernel.currentTask
|
local isAbsolute = (path:sub(1,1) == "/")
|
||||||
local cwd = task.cwd or "/"
|
local tokens = {}
|
||||||
|
for comp in (path .. "/"):gmatch("([^/]*)/") do
|
||||||
|
table.insert(tokens, comp)
|
||||||
|
end
|
||||||
|
return isAbsolute, tokens
|
||||||
|
end
|
||||||
|
|
||||||
if path:sub(1, 1) ~= "/" then
|
local function validateComponent(comp)
|
||||||
path = cwd .. "/" .. path
|
local lower = comp:lower()
|
||||||
|
if not lower:match(SAFE_COMPONENT_PATTERN) then
|
||||||
|
error("EINVAL: illegal characters in path component: " .. comp, 3)
|
||||||
end
|
end
|
||||||
|
if lower == ".meta" then
|
||||||
local stack = {}
|
error("EINVAL: reserved path component: .meta", 3)
|
||||||
local i = 1
|
|
||||||
local len = #path
|
|
||||||
while i <= len do
|
|
||||||
local j = path:find("/", i, true)
|
|
||||||
local comp
|
|
||||||
if j then
|
|
||||||
comp = path:sub(i, j - 1)
|
|
||||||
i = j + 1
|
|
||||||
else
|
|
||||||
comp = path:sub(i)
|
|
||||||
i = len + 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
comp = comp:match("^%s*(.-)%s*$")
|
|
||||||
|
|
||||||
if comp == "" or comp == "." then
|
|
||||||
elseif comp == ".." then
|
|
||||||
if #stack > 0 then
|
|
||||||
table.remove(stack)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
comp = comp:lower()
|
|
||||||
if not comp:match(SAFE_COMPONENT_PATTERN) then
|
|
||||||
error("EINVAL: illegal characters in path component: " .. comp, 2)
|
|
||||||
end
|
|
||||||
if comp == ".meta" then
|
|
||||||
error("EINVAL: reserved path component: " .. comp, 2)
|
|
||||||
end
|
|
||||||
table.insert(stack, comp)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local result = "/" .. table.concat(stack, "/")
|
|
||||||
|
|
||||||
local root = task and task.root
|
|
||||||
if root and root ~= "/" then
|
|
||||||
if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then
|
|
||||||
result = root
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return result
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.splitPath(path)
|
function vfs.splitPath(path)
|
||||||
@@ -222,47 +188,205 @@ local function readMetaEntry(disk, parentDiskPath, filename)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local MAX_SYMLINK = 16
|
local MAX_SYMLINK = 16
|
||||||
local function resolveSymlinks(path, noFollow, _depth)
|
|
||||||
_depth = _depth or 0
|
|
||||||
if _depth > MAX_SYMLINK then error("ELOOP") end
|
|
||||||
path = normalizePath(path)
|
|
||||||
|
|
||||||
local parts = {}
|
local function namei(path, noFollow, symDepth)
|
||||||
for p in path:gmatch("[^/]+") do table.insert(parts, p) end
|
symDepth = symDepth or 0
|
||||||
|
if symDepth > MAX_SYMLINK then error("ELOOP") end
|
||||||
|
|
||||||
local resolved = ""
|
local task = kernel.currentTask
|
||||||
|
local euid = (task and (task.euid or task.uid)) or kernel.uid
|
||||||
|
local groups = (task and task.groups) or kernel.groups or {}
|
||||||
|
local root = (task and task.root) or "/"
|
||||||
|
local cwd = (task and task.cwd) or "/"
|
||||||
|
|
||||||
for i, part in ipairs(parts) do
|
if root ~= "/" and root:sub(-1) == "/" then root = root:sub(1,-2) end
|
||||||
local candidate = resolved == "" and ("/" .. part) or (resolved .. "/" .. part)
|
|
||||||
|
|
||||||
if noFollow and i == #parts then
|
local function canTraverse(entry)
|
||||||
resolved = candidate
|
if euid == 0 then return true end
|
||||||
break
|
if not entry then return true end
|
||||||
|
local bits = entry.perms
|
||||||
|
if euid == entry.owner and bit_is_set(bits, 9) then return true end
|
||||||
|
if entry.group then
|
||||||
|
for _, gid in ipairs(groups) do
|
||||||
|
if gid == entry.group and bit_is_set(bits, 8) then return true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return bit_is_set(bits, 7)
|
||||||
end
|
end
|
||||||
|
|
||||||
local disk, parentDisk = resolveMount(resolved == "" and "/" or resolved)
|
local isAbsolute, tokens = tokenizePath(path)
|
||||||
local entry = readMetaEntry(disk, parentDisk, part)
|
|
||||||
|
local stack = {}
|
||||||
|
|
||||||
|
if isAbsolute then
|
||||||
|
stack = {}
|
||||||
|
else
|
||||||
|
for seg in cwd:gmatch("[^/]+") do table.insert(stack, seg) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local i = 1
|
||||||
|
while i <= #tokens do
|
||||||
|
local comp = tokens[i]
|
||||||
|
i = i + 1
|
||||||
|
|
||||||
|
comp = comp:match("^%s*(.-)%s*$")
|
||||||
|
|
||||||
|
if comp == "" or comp == "." then
|
||||||
|
elseif comp == ".." then
|
||||||
|
local currentPath = "/" .. table.concat(stack, "/")
|
||||||
|
|
||||||
|
local jailStack = {}
|
||||||
|
if root ~= "/" then
|
||||||
|
for seg in root:gmatch("[^/]+") do table.insert(jailStack, seg) end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #stack <= #jailStack then
|
||||||
|
stack = {}
|
||||||
|
for _, seg in ipairs(jailStack) do table.insert(stack, seg) end
|
||||||
|
else
|
||||||
|
local exitName = stack[#stack]
|
||||||
|
local parentPath = "/" .. table.concat(stack, "/", 1, #stack - 1)
|
||||||
|
if parentPath == "/" then parentPath = "/" end
|
||||||
|
|
||||||
|
local okM, diskM, dpM = pcall(resolveMount, parentPath == "" and "/" or parentPath)
|
||||||
|
if okM and diskM then
|
||||||
|
local entry = readMetaEntry(diskM, dpM, exitName)
|
||||||
|
if entry then
|
||||||
|
if entry.etype ~= 0x00 then
|
||||||
|
error("ENOTDIR: not a directory: " .. currentPath)
|
||||||
|
end
|
||||||
|
if not canTraverse(entry) then
|
||||||
|
error("EACCES: permission denied traversing " .. currentPath)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local okD, diskD, dpD = pcall(resolveMount, currentPath)
|
||||||
|
if okD and diskD then
|
||||||
|
local dtype = diskD:type(dpD)
|
||||||
|
if dtype ~= nil and dtype ~= "directory" then
|
||||||
|
error("ENOTDIR: not a directory: " .. currentPath)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
table.remove(stack)
|
||||||
|
end
|
||||||
|
|
||||||
|
else
|
||||||
|
validateComponent(comp)
|
||||||
|
local lname = comp:lower()
|
||||||
|
|
||||||
|
local curPath = "/" .. table.concat(stack, "/")
|
||||||
|
|
||||||
|
local okM, diskM, dpM = pcall(resolveMount, curPath == "/" and "/" or curPath)
|
||||||
|
local entry = nil
|
||||||
|
if okM and diskM then
|
||||||
|
entry = readMetaEntry(diskM, dpM, lname)
|
||||||
|
end
|
||||||
|
|
||||||
|
local isFinal = (i > #tokens)
|
||||||
|
|
||||||
if entry and entry.etype == 0x01 then
|
if entry and entry.etype == 0x01 then
|
||||||
|
if isFinal and noFollow then
|
||||||
|
table.insert(stack, lname)
|
||||||
|
else
|
||||||
|
symDepth = symDepth + 1
|
||||||
|
if symDepth > MAX_SYMLINK then error("ELOOP") end
|
||||||
|
|
||||||
local target = entry.cmeta
|
local target = entry.cmeta
|
||||||
if target:sub(1,1) ~= "/" then
|
if not target or target == "" then
|
||||||
target = (resolved == "" and "/" or resolved) .. "/" .. target
|
error("ENOENT: empty symlink target")
|
||||||
end
|
|
||||||
if i < #parts then
|
|
||||||
target = target .. "/" .. table.concat(parts, "/", i+1, #parts)
|
|
||||||
end
|
|
||||||
return resolveSymlinks(normalizePath(target), noFollow, _depth + 1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
resolved = candidate
|
local symIsAbs, symTokens = tokenizePath(target)
|
||||||
|
|
||||||
|
if symIsAbs then
|
||||||
|
stack = {}
|
||||||
|
if root ~= "/" then
|
||||||
|
for seg in root:gmatch("[^/]+") do table.insert(stack, seg) end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if resolved == "" then resolved = "/" end
|
local fresh = {}
|
||||||
return resolved
|
for j = 1, i - 2 do table.insert(fresh, tokens[j]) end
|
||||||
|
local insertAt = #fresh + 1
|
||||||
|
for _, t in ipairs(symTokens) do table.insert(fresh, t) end
|
||||||
|
for j = i, #tokens do table.insert(fresh, tokens[j]) end
|
||||||
|
tokens = fresh
|
||||||
|
i = insertAt
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(stack, lname)
|
||||||
|
|
||||||
|
if not isFinal then
|
||||||
|
local newPath = "/" .. table.concat(stack, "/")
|
||||||
|
local okD, diskD, dpD = pcall(resolveMount, newPath)
|
||||||
|
if okD and diskD then
|
||||||
|
local dtype = diskD:type(dpD)
|
||||||
|
if dtype ~= nil and dtype ~= "directory" then
|
||||||
|
error("ENOTDIR: not a directory: " .. newPath)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not canTraverse(entry) then
|
||||||
|
error("EACCES: permission denied traversing " .. newPath)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = "/" .. table.concat(stack, "/")
|
||||||
|
|
||||||
|
if root ~= "/" then
|
||||||
|
if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then
|
||||||
|
result = root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
|
local function normalizePath(path)
|
||||||
|
local task = kernel.currentTask
|
||||||
|
local cwd = (task and task.cwd) or "/"
|
||||||
|
local root = (task and task.root) or "/"
|
||||||
|
if root ~= "/" and root:sub(-1) == "/" then root = root:sub(1,-2) end
|
||||||
|
|
||||||
|
local isAbsolute, tokens = tokenizePath(path)
|
||||||
|
local stack = {}
|
||||||
|
|
||||||
|
if not isAbsolute then
|
||||||
|
for seg in cwd:gmatch("[^/]+") do table.insert(stack, seg) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local jailStack = {}
|
||||||
|
if root ~= "/" then
|
||||||
|
for seg in root:gmatch("[^/]+") do table.insert(jailStack, seg) end
|
||||||
|
end
|
||||||
|
|
||||||
|
for _, comp in ipairs(tokens) do
|
||||||
|
comp = comp:match("^%s*(.-)%s*$")
|
||||||
|
if comp == "" or comp == "." then
|
||||||
|
elseif comp == ".." then
|
||||||
|
if #stack > #jailStack then
|
||||||
|
table.remove(stack)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(stack, comp:lower())
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local result = "/" .. table.concat(stack, "/")
|
||||||
|
if root ~= "/" then
|
||||||
|
if result ~= root and result:sub(1, #root + 1) ~= root .. "/" then
|
||||||
|
result = root
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
local function resolvePath(path, noFollow)
|
local function resolvePath(path, noFollow)
|
||||||
local real = resolveSymlinks(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
local disk, diskPath = resolveMount(real)
|
local disk, diskPath = resolveMount(real)
|
||||||
if kernel.config.logPathResolution then
|
if kernel.config.logPathResolution then
|
||||||
kernel.log("resolvePath '"..path.."' -> '"..real.."' diskPath '"..diskPath.."'")
|
kernel.log("resolvePath '"..path.."' -> '"..real.."' diskPath '"..diskPath.."'")
|
||||||
@@ -271,24 +395,38 @@ local function resolvePath(path, noFollow)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getFileMeta(path, noFollow)
|
local function getFileMeta(path, noFollow)
|
||||||
local real = resolveSymlinks(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
|
|
||||||
local parts = {}
|
if real == "/" then
|
||||||
for p in real:gmatch("[^/]+") do table.insert(parts, p) end
|
return { etype = 0x00, owner = 0, group = 0, perms = 62, cmeta = "" }
|
||||||
|
end
|
||||||
|
|
||||||
local default = { etype = 0x00, owner = 0, group = 0, perms = 63, cmeta = "" }
|
local cur = real
|
||||||
if #parts == 0 then return default end
|
|
||||||
|
|
||||||
local parentNorm = "/" .. table.concat(parts, "/", 1, #parts - 1)
|
-- FML i hated implementing this - Astronand
|
||||||
if parentNorm == "" then parentNorm = "/" end
|
while true do
|
||||||
local disk, parentDiskPath = resolveMount(parentNorm)
|
local parent, name = cur:match("^(.*)/([^/]+)$")
|
||||||
local entry = readMetaEntry(disk, parentDiskPath, parts[#parts])
|
if not parent or parent == "" then parent = "/" end
|
||||||
if entry then return entry end
|
|
||||||
return default
|
local disk, parentDiskPath = resolveMount(parent)
|
||||||
|
local entry = readMetaEntry(disk, parentDiskPath, name)
|
||||||
|
|
||||||
|
if entry then
|
||||||
|
return entry
|
||||||
|
end
|
||||||
|
|
||||||
|
if parent == "/" or cur == "/" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
cur = parent
|
||||||
|
end
|
||||||
|
|
||||||
|
return { etype = 0x00, owner = 0, group = 0, perms = 63, cmeta = "" }
|
||||||
end
|
end
|
||||||
|
|
||||||
local function writeMetaEntry(path, name, entry, noFollow)
|
local function writeMetaEntry(path, name, entry, noFollow)
|
||||||
local real = resolveSymlinks(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
local disk, diskPath = resolveMount(real)
|
local disk, diskPath = resolveMount(real)
|
||||||
|
|
||||||
local mp
|
local mp
|
||||||
@@ -487,6 +625,7 @@ function vfs.open(path, mode)
|
|||||||
if mode == "r" and bit_is_set(meta.perms, 6) then
|
if mode == "r" and bit_is_set(meta.perms, 6) then
|
||||||
fobj.suid_owner = meta.owner
|
fobj.suid_owner = meta.owner
|
||||||
end
|
end
|
||||||
|
if disk.isvirt then fobj.isvirt=true end
|
||||||
task.fd[fd] = fobj
|
task.fd[fd] = fobj
|
||||||
if not disk.isvirt then total = total + 1 end
|
if not disk.isvirt then total = total + 1 end
|
||||||
return fd
|
return fd
|
||||||
@@ -535,8 +674,10 @@ function vfs.close(fd)
|
|||||||
local task = kernel.currentTask
|
local task = kernel.currentTask
|
||||||
local file = task.fd[fd]
|
local file = task.fd[fd]
|
||||||
if not file then error("EBADF") end
|
if not file then error("EBADF") end
|
||||||
task.fd[fd] = nil
|
if not task.fd[fd].isvirt then
|
||||||
total = total - 1
|
total = total - 1
|
||||||
|
end
|
||||||
|
task.fd[fd] = nil
|
||||||
file.refcount = file.refcount - 1
|
file.refcount = file.refcount - 1
|
||||||
if file.refcount <= 0 and file.handle and file.handle.close then
|
if file.refcount <= 0 and file.handle and file.handle.close then
|
||||||
file.handle.close()
|
file.handle.close()
|
||||||
@@ -668,7 +809,7 @@ function vfs.mkdir(path)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vfs.remove(path)
|
function vfs.remove(path)
|
||||||
local norm = resolveSymlinks(path, true)
|
local norm = namei(path, true)
|
||||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
local parentMeta = getFileMeta(parent)
|
local parentMeta = getFileMeta(parent)
|
||||||
@@ -681,7 +822,7 @@ function vfs.remove(path)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if meta.etype == 0x01 then
|
if meta.etype == 0x01 then
|
||||||
local norm = resolveSymlinks(path, true)
|
local norm = namei(path, true)
|
||||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
local name = norm:match("[^/]+$")
|
local name = norm:match("[^/]+$")
|
||||||
@@ -747,7 +888,7 @@ function vfs.access(path, mode)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function updateMeta(path, fn, noFollow)
|
local function updateMeta(path, fn, noFollow)
|
||||||
local real = resolveSymlinks(path, noFollow)
|
local real = namei(path, noFollow)
|
||||||
local norm = real
|
local norm = real
|
||||||
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
local parent = norm:match("^(.*)/[^/]+$") or "/"
|
||||||
if parent == "" then parent = "/" end
|
if parent == "" then parent = "/" end
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
local cache = {}
|
local cache = {}
|
||||||
kernel.searchpaths = {
|
kernel.searchpaths = {
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ proxy.getLabel = function() return "devfs" end
|
|||||||
proxy.attributes = function(path) return {
|
proxy.attributes = function(path) return {
|
||||||
size = 0,
|
size = 0,
|
||||||
modified = 0,
|
modified = 0,
|
||||||
created = 0,
|
created = 0
|
||||||
} end
|
} end
|
||||||
|
|
||||||
function proxy:open(path, mode)
|
function proxy:open(path, mode)
|
||||||
@@ -50,7 +50,7 @@ function proxy:type(path, mode)
|
|||||||
if type(step[steps[#steps]]) == "table" then
|
if type(step[steps[#steps]]) == "table" then
|
||||||
return "directory"
|
return "directory"
|
||||||
end
|
end
|
||||||
error("ENOENT")
|
error(type(step[steps[#steps]]))
|
||||||
end
|
end
|
||||||
|
|
||||||
function proxy:list(path)
|
function proxy:list(path)
|
||||||
@@ -140,6 +140,68 @@ function data.zero(op, mode)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
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
|
||||||
|
return {
|
||||||
|
write=function(data)
|
||||||
|
kernel.EFI:setEEPROM(data)
|
||||||
|
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
|
||||||
|
|
||||||
|
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
|
||||||
|
return {
|
||||||
|
write=function(data)
|
||||||
|
kernel.EFI:setNvram(data)
|
||||||
|
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
|
||||||
|
|
||||||
data["disk"]={}
|
data["disk"]={}
|
||||||
kernel.devfs={}
|
kernel.devfs={}
|
||||||
kernel.devfs.data=data
|
kernel.devfs.data=data
|
||||||
|
|||||||
@@ -0,0 +1,265 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
|
||||||
|
local proxy = {}
|
||||||
|
local data = {}
|
||||||
|
|
||||||
|
proxy.address = "procfs0000"
|
||||||
|
proxy.isvirt = true
|
||||||
|
proxy.isReadOnly = function() return false end
|
||||||
|
proxy.spaceUsed = function() return 0 end
|
||||||
|
proxy.spaceTotal = function() return 0 end
|
||||||
|
proxy.makeDirectory = function() error("EACCES") end
|
||||||
|
proxy.remove = function() error("EACCES") end
|
||||||
|
proxy.setLabel = function() error("EACCES") end
|
||||||
|
proxy.getLabel = function() return "procfs" end
|
||||||
|
proxy.attributes = function(path) return {
|
||||||
|
size = 0,
|
||||||
|
modified = 0,
|
||||||
|
created = 0
|
||||||
|
} end
|
||||||
|
|
||||||
|
local function buildMeta(entries, opts)
|
||||||
|
opts = opts or {}
|
||||||
|
local uid = opts.uid or 0
|
||||||
|
local gid = opts.gid or 0
|
||||||
|
local perms = opts.perms or 0x3F -- default read/write for owner/group/world
|
||||||
|
|
||||||
|
local chunks = {}
|
||||||
|
table.insert(chunks, string.char(0x02)) -- version header
|
||||||
|
|
||||||
|
for path, target in pairs(entries) do
|
||||||
|
local name = path
|
||||||
|
local nameLen = #name
|
||||||
|
if nameLen > 255 then
|
||||||
|
error("Filename too long (>255 bytes): "..name)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Determine entry type: 0x01 = symlink if target ~= nil and target ~= ""
|
||||||
|
local entryType = 0x00
|
||||||
|
local cmeta = ""
|
||||||
|
if target and target ~= "" then
|
||||||
|
entryType = 0x01
|
||||||
|
cmeta = target
|
||||||
|
end
|
||||||
|
local cmetaLen = #cmeta
|
||||||
|
if cmetaLen > 255 then
|
||||||
|
error("cmeta too long (>255 bytes) for "..name)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Build entry as bytes
|
||||||
|
table.insert(chunks, string.char(nameLen)) -- name length
|
||||||
|
table.insert(chunks, name) -- name
|
||||||
|
table.insert(chunks, string.char(entryType)) -- entry type
|
||||||
|
table.insert(chunks, string.char(uid % 256, math.floor(uid/256) % 256)) -- uid
|
||||||
|
table.insert(chunks, string.char(gid % 256, math.floor(gid/256) % 256)) -- gid
|
||||||
|
table.insert(chunks, string.char(perms % 256, math.floor(perms/256) % 256)) -- perms
|
||||||
|
table.insert(chunks, string.char(cmetaLen)) -- cmeta length
|
||||||
|
if cmetaLen > 0 then
|
||||||
|
table.insert(chunks, cmeta)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return table.concat(chunks)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function simpleFile(r,w)
|
||||||
|
return function(op, mode)
|
||||||
|
if op=="type" then
|
||||||
|
return "character device"
|
||||||
|
elseif op=="open" then
|
||||||
|
if mode=="r" then
|
||||||
|
return {
|
||||||
|
read=r
|
||||||
|
}
|
||||||
|
elseif mode=="w" then
|
||||||
|
return {
|
||||||
|
write=w
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function strFile(str)
|
||||||
|
local dat=tostring(str)
|
||||||
|
local pos=1
|
||||||
|
return simpleFile(function(amount)
|
||||||
|
pos=pos+amount
|
||||||
|
return dat:sub(pos-amount, pos)
|
||||||
|
end,function() error("EACCES") end)
|
||||||
|
end
|
||||||
|
|
||||||
|
local function newtaskproxy(task)
|
||||||
|
local files,siblings,children={},{},{}
|
||||||
|
if task.fd[0] then files["0"]=task.fd[0].path end
|
||||||
|
for i,v in ipairs(task.fd) do
|
||||||
|
files[tostring(i)]=tostring(v.path)
|
||||||
|
end
|
||||||
|
for i,v in ipairs(task.siblings) do
|
||||||
|
siblings[tostring(v.pid)]="/proc/"..tostring(v.pid)
|
||||||
|
end
|
||||||
|
for i,v in ipairs(task.children) do
|
||||||
|
children[tostring(v.pid)]="/proc/"..tostring(v.pid)
|
||||||
|
end
|
||||||
|
return {
|
||||||
|
[".meta"]=strFile(buildMeta({cwd=task.cwd,parent="/proc/"..tostring(task.parent.pid)})),
|
||||||
|
uid=strFile(task.uid),
|
||||||
|
comm=strFile(task.name),
|
||||||
|
fd={
|
||||||
|
[".meta"]=strFile(buildMeta(files))
|
||||||
|
},
|
||||||
|
siblings={
|
||||||
|
[".meta"]=strFile(buildMeta(siblings))
|
||||||
|
},
|
||||||
|
children={
|
||||||
|
[".meta"]=strFile(buildMeta(children))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function proxy:open(path, mode)
|
||||||
|
local steps = kernel.vfs.splitPath(path)
|
||||||
|
local step = data
|
||||||
|
if tonumber(steps[1]) then
|
||||||
|
local task=kernel.tasks[tostring(steps[1])]
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("open", mode)
|
||||||
|
end
|
||||||
|
elseif tostring(steps[1])=="self" then
|
||||||
|
local task=kernel.currentTask
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("open", mode)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i=1, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("open", mode)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error("ENFILE")
|
||||||
|
end
|
||||||
|
|
||||||
|
function proxy:type(path, mode)
|
||||||
|
local steps = kernel.vfs.splitPath(path)
|
||||||
|
local step = data
|
||||||
|
if #steps == 0 then
|
||||||
|
return "directory"
|
||||||
|
end
|
||||||
|
if tonumber(steps[1]) then
|
||||||
|
local task=kernel.tasks[steps[1]]
|
||||||
|
if #steps==1 then return "directory" end
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("type", mode)
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return "directory"
|
||||||
|
end
|
||||||
|
elseif tostring(steps[1])=="self" then
|
||||||
|
local task=kernel.currentTask
|
||||||
|
if #steps==1 then return "directory" end
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("type", mode)
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return "directory"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i=1, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENFILE") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "function" then
|
||||||
|
return step[steps[#steps]]("type", mode)
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return "directory"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error("ENOENT")
|
||||||
|
end
|
||||||
|
|
||||||
|
function proxy:list(path)
|
||||||
|
local steps = kernel.vfs.splitPath(path)
|
||||||
|
local step = data
|
||||||
|
if #steps == 0 then
|
||||||
|
return table.merge(table.keys(data),table.keys(kernel.tasks),{"self"})
|
||||||
|
end
|
||||||
|
if tonumber(steps[1]) then
|
||||||
|
local task=kernel.tasks[steps[1]]
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
if #steps==1 then return table.keys(step) end
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENOENT") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return table.keys(step[steps[#steps]])
|
||||||
|
end
|
||||||
|
elseif tostring(steps[1])=="self" then
|
||||||
|
local task=kernel.currentTask
|
||||||
|
local step = newtaskproxy(task)
|
||||||
|
if #steps==1 then return table.keys(step) end
|
||||||
|
for i=2, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENOENT") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return table.keys(step[steps[#steps]])
|
||||||
|
end
|
||||||
|
else
|
||||||
|
for i=1, #steps-1 do
|
||||||
|
local dat = step[steps[i]]
|
||||||
|
if type(dat) ~= "table" then error("ENOENT") end
|
||||||
|
step=dat
|
||||||
|
end
|
||||||
|
if type(step[steps[#steps]]) == "table" then
|
||||||
|
return table.keys(step[steps[#steps]])
|
||||||
|
end
|
||||||
|
end
|
||||||
|
error("ENOENT")
|
||||||
|
end
|
||||||
|
|
||||||
|
function proxy:fileExists(path)
|
||||||
|
local ok = pcall(function()
|
||||||
|
return self:type(path)
|
||||||
|
end)
|
||||||
|
return ok
|
||||||
|
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
|
||||||
|
kernel.disks["procfs0000"]=proxy
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
|
|
||||||
local proxy = {}
|
local proxy = {}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
-- Loop device driver:
|
-- Loop device driver:
|
||||||
--
|
--
|
||||||
-- BIND (directory) - re-routes VFS calls into a host directory subtree.
|
-- BIND (directory) - re-routes VFS calls into a host directory subtree.
|
||||||
|
|||||||
@@ -1,22 +0,0 @@
|
|||||||
---- :Minify:--
|
|
||||||
--local kernel = ...
|
|
||||||
--
|
|
||||||
--local timeout = false
|
|
||||||
--kernel.processes.keventd = function()
|
|
||||||
-- while true do
|
|
||||||
-- local event = {kernel.computer:getMachineEvent()}
|
|
||||||
-- if event[1] then
|
|
||||||
-- if event[1] == "keyTyped" then
|
|
||||||
-- if event[3] == "\x1b^s" then
|
|
||||||
-- kernel.shutdown()
|
|
||||||
-- elseif event[3] == "\x1b^r" then
|
|
||||||
-- kernel.reboot()
|
|
||||||
-- end
|
|
||||||
-- end
|
|
||||||
-- timeout = false
|
|
||||||
-- else
|
|
||||||
-- timeout = true
|
|
||||||
-- end
|
|
||||||
-- if timeout then sleep(.05) end
|
|
||||||
-- end
|
|
||||||
--end
|
|
||||||
@@ -21,7 +21,7 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
if not semicolon_pos or semicolon_pos == 3 then
|
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
|
else
|
||||||
local id = line:sub(3, semicolon_pos - 1)
|
local id = line:sub(3, semicolon_pos - 1)
|
||||||
local path = trim(line:sub(semicolon_pos + 1))
|
local path = trim(line:sub(semicolon_pos + 1))
|
||||||
|
|||||||
@@ -1,11 +1,8 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
-- Supports:
|
-- Supports:
|
||||||
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
||||||
-- AF_INET - network sockets with three backends:
|
-- 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)
|
-- Implemented by drivers but expect http:// and https://
|
||||||
-- 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
|
|
||||||
--
|
--
|
||||||
-- Socket lifecycle:
|
-- Socket lifecycle:
|
||||||
-- fd = syscall.socket(domain, socktype) -- "unix"/"inet", "stream"/"dgram"
|
-- fd = syscall.socket(domain, socktype) -- "unix"/"inet", "stream"/"dgram"
|
||||||
@@ -18,539 +15,9 @@
|
|||||||
-- syscall.sockshutdown(fd) -- half-close send side
|
-- syscall.sockshutdown(fd) -- half-close send side
|
||||||
-- -- normal vfs.close(fd) closes the socket
|
-- -- normal vfs.close(fd) closes the socket
|
||||||
|
|
||||||
local kernel = ...
|
local kernel=...
|
||||||
|
local socket={}
|
||||||
|
kernel.socket=socket
|
||||||
|
|
||||||
local sockets = {}
|
|
||||||
local unixSocks = {}
|
|
||||||
local nextSockId = 1
|
|
||||||
|
|
||||||
local function allocSockId()
|
|
||||||
local id = nextSockId
|
|
||||||
nextSockId = nextSockId + 1
|
|
||||||
return id
|
|
||||||
end
|
|
||||||
|
|
||||||
local function parseAddress(addr)
|
|
||||||
if not addr then error("EINVAL") end
|
|
||||||
|
|
||||||
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"
|
|
||||||
})
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
kernel.log("Loaded socket module")
|
kernel.log("Loaded socket module")
|
||||||
@@ -1,395 +0,0 @@
|
|||||||
-- :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 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
|
|
||||||
}
|
|
||||||
|
|
||||||
local function write(text, term)
|
|
||||||
local x, y = term.getCursorPos()
|
|
||||||
local w, h = term.getSize()
|
|
||||||
|
|
||||||
for i = 1, #text do
|
|
||||||
local c = text:sub(i, i)
|
|
||||||
|
|
||||||
if c == "\n" then
|
|
||||||
y = y + 1
|
|
||||||
x = 1
|
|
||||||
elseif c == "\t" then
|
|
||||||
local tabSize = 4
|
|
||||||
local spaces = tabSize - ((x - 1) % tabSize)
|
|
||||||
term.write(string.rep(" ", spaces))
|
|
||||||
x = x + spaces
|
|
||||||
elseif c == "\b" then
|
|
||||||
if x > 1 then
|
|
||||||
x = x - 1
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
term.write(" ")
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
if x <= w and y <= h then
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
term.write(c)
|
|
||||||
x = x + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if x > w then
|
|
||||||
x = 1
|
|
||||||
y = y + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
if y - 1 >= h then
|
|
||||||
term.scroll(1)
|
|
||||||
y = h
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
term.setCursorPos(x, y)
|
|
||||||
end
|
|
||||||
|
|
||||||
kernel.devfs.data.tty={}
|
|
||||||
local ctrl,alt = false, false
|
|
||||||
|
|
||||||
local function serializeBool(bool)
|
|
||||||
if bool then
|
|
||||||
return "T"
|
|
||||||
else
|
|
||||||
return "F"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function newtty(obj, id, ev)
|
|
||||||
kernel.devfs.data["tty"][id] = function(op, mode)
|
|
||||||
if op=="type" then
|
|
||||||
return "character device"
|
|
||||||
elseif op=="open" then
|
|
||||||
local h = {
|
|
||||||
read=function(amount)
|
|
||||||
local rv=""
|
|
||||||
for i=1, amount or 1 do
|
|
||||||
local event = {ev()}
|
|
||||||
if event[1] then
|
|
||||||
rv=rv..event[1]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if rv=="" then rv=nil end
|
|
||||||
return rv
|
|
||||||
end,
|
|
||||||
write=function(content)
|
|
||||||
write(content, obj)
|
|
||||||
end,
|
|
||||||
size=function()
|
|
||||||
local s={obj.getSize()}
|
|
||||||
return table.concat(s,";")
|
|
||||||
end,
|
|
||||||
clear=function()
|
|
||||||
obj.clear()
|
|
||||||
obj.setCursorPos(1,1)
|
|
||||||
end,
|
|
||||||
gpos=function()
|
|
||||||
local s={obj.getCursorPos()}
|
|
||||||
return table.concat(s,";")
|
|
||||||
end,
|
|
||||||
spos=function(x,y)
|
|
||||||
return obj.setCursorPos(x,y)
|
|
||||||
end,
|
|
||||||
sfgc=function(c)
|
|
||||||
return obj.setTextColor(colors[c])
|
|
||||||
end,
|
|
||||||
sbgc=function(c)
|
|
||||||
return obj.setBackgroundColor(colors[c])
|
|
||||||
end,
|
|
||||||
gfgc=function()
|
|
||||||
return icolors[obj.getTextColor()]
|
|
||||||
end,
|
|
||||||
gbgc=function()
|
|
||||||
return icolors[obj.getBackgroundColor()]
|
|
||||||
end,
|
|
||||||
gctrl=function()
|
|
||||||
return serializeBool(ctrl)..";"..serializeBool(alt)
|
|
||||||
end
|
|
||||||
}
|
|
||||||
if mode=="rw" then
|
|
||||||
return h
|
|
||||||
elseif mode=="r" then
|
|
||||||
h["write"]=nil
|
|
||||||
return h
|
|
||||||
elseif mode=="w" then
|
|
||||||
h["read"]=nil
|
|
||||||
return h
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local fifo = kernel.newFifo()
|
|
||||||
|
|
||||||
local ctrlLetterKeys = nil
|
|
||||||
local specialKeys = nil
|
|
||||||
|
|
||||||
local function buildKeyMaps()
|
|
||||||
if ctrlLetterKeys then return end
|
|
||||||
local k = apis.keys
|
|
||||||
ctrlLetterKeys = {}
|
|
||||||
local letters = {
|
|
||||||
{k.a,1},{k.b,2},{k.c,3},{k.d,4},{k.e,5},{k.f,6},{k.g,7},
|
|
||||||
{k.h,8}, {k.j,10},{k.k,11},{k.l,12},{k.m,13},
|
|
||||||
{k.n,14},{k.o,15},{k.p,16},
|
|
||||||
{k.u,21},{k.v,22},{k.w,23},{k.x,24},{k.y,25},{k.z,26},
|
|
||||||
}
|
|
||||||
for _, pair in ipairs(letters) do
|
|
||||||
ctrlLetterKeys[pair[1]] = string.char(pair[2])
|
|
||||||
end
|
|
||||||
specialKeys = {
|
|
||||||
[k.home] = "\1",
|
|
||||||
[k.delete] = "\4",
|
|
||||||
[k["end"]] = "\5",
|
|
||||||
[k.pageUp] = "\2",
|
|
||||||
[k.pageDown]= "\12",
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
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]
|
|
||||||
|
|
||||||
buildKeyMaps()
|
|
||||||
|
|
||||||
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 and charOrKey == apis.keys.c then
|
|
||||||
for _, task in ipairs(syscall.getTasks()) do
|
|
||||||
syscall.sigsend(task, 1)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if ctrl and ctrlLetterKeys[charOrKey] then
|
|
||||||
fifo.push(ctrlLetterKeys[charOrKey])
|
|
||||||
end
|
|
||||||
|
|
||||||
if specialKeys[charOrKey] then
|
|
||||||
fifo.push(specialKeys[charOrKey])
|
|
||||||
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, "tty1", fifo.pop)
|
|
||||||
|
|
||||||
|
|
||||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
|
||||||
v.setTextScale(.5)
|
|
||||||
v.write("Initializing...")
|
|
||||||
newtty(v,"tty"..tostring(i+1),function () end)
|
|
||||||
end
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local args = {...}
|
local args = {...}
|
||||||
local kernel = args[1]
|
local kernel = args[1]
|
||||||
kernel._G = _G
|
kernel._G = _G
|
||||||
@@ -55,3 +55,19 @@ local origLoad = load
|
|||||||
kernel._U = readonly(kernel._G)
|
kernel._U = readonly(kernel._G)
|
||||||
kernel._U._G = kernel._U
|
kernel._U._G = kernel._U
|
||||||
kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
kernel._U.load = function(a,b,c,d) return origLoad(a,b,c,d or kernel._U) end
|
||||||
|
|
||||||
|
function kernel.freshUserEnv()
|
||||||
|
local locals = {}
|
||||||
|
locals.syscall = _makeSyscallProxy()
|
||||||
|
|
||||||
|
local env = setmetatable(locals, {
|
||||||
|
__index = kernel._U,
|
||||||
|
__newindex = function(_, k, v) rawset(locals, k, v) end,
|
||||||
|
__metatable=false
|
||||||
|
})
|
||||||
|
|
||||||
|
locals._G = env
|
||||||
|
locals.load = function(a, b, c, d) return origLoad(a, b, c, d or env) end
|
||||||
|
|
||||||
|
return env
|
||||||
|
end
|
||||||
@@ -139,7 +139,7 @@ end
|
|||||||
if not blake2s then error("Failed to load blake2s") end
|
if not blake2s then error("Failed to load blake2s") end
|
||||||
|
|
||||||
if not kernel.vfs.exists("/etc/pam.d/secret") then
|
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 = ""
|
local key = ""
|
||||||
for i = 1, 256 do key = key .. string.char(math.random(0, 255)) end
|
for i = 1, 256 do key = key .. string.char(math.random(0, 255)) end
|
||||||
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
|
local handle = kernel.vfs.open("/etc/pam.d/secret", "w")
|
||||||
@@ -236,19 +236,18 @@ local function nextUID()
|
|||||||
return max + 1
|
return max + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function auth.login(username, password)
|
function auth.login(uid, password)
|
||||||
if type(username) ~= "string" or type(password) ~= "string" then
|
if type(uid) ~= "number" or type(password) ~= "string" then
|
||||||
return nil, "Authentication failure"
|
return nil, "Authentication failure"
|
||||||
end
|
end
|
||||||
|
|
||||||
local entry = getPasswdByUsername(username)
|
local entry = getPasswdByUID(uid)
|
||||||
if not entry then
|
if not entry then
|
||||||
-- timing attack resistance
|
-- timing attack resistance
|
||||||
hashPassword(password, "aaaaaaaaaaaaaaaa")
|
hashPassword(password, "aaaaaaaaaaaaaaaa")
|
||||||
return nil, "Authentication failure"
|
return nil, "Authentication failure"
|
||||||
end
|
end
|
||||||
|
|
||||||
local uid = tonumber(entry[1])
|
|
||||||
local sEntry = getShadowByUID(uid)
|
local sEntry = getShadowByUID(uid)
|
||||||
if not sEntry then
|
if not sEntry then
|
||||||
hashPassword(password, "aaaaaaaaaaaaaaaa")
|
hashPassword(password, "aaaaaaaaaaaaaaaa")
|
||||||
@@ -273,7 +272,7 @@ function auth.login(username, password)
|
|||||||
_task.egid = tonumber(entry[2]) or uid
|
_task.egid = tonumber(entry[2]) or uid
|
||||||
end
|
end
|
||||||
|
|
||||||
kernel.log("AUTH: login uid=" .. tostring(uid) .. " (" .. username .. ")")
|
kernel.log("AUTH: login uid=" .. tostring(uid) .. " (" .. getPasswdByUID(uid)[3] .. ")")
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -11,14 +11,16 @@ local function bit_is_set(num, bit)
|
|||||||
return math.floor(num / (2 ^ bit)) % 2 == 1
|
return math.floor(num / (2 ^ bit)) % 2 == 1
|
||||||
end
|
end
|
||||||
|
|
||||||
local function loadExecutable(path, env)
|
local function loadExecutable(path)
|
||||||
kernel.vfs.access(path, "rx")
|
kernel.vfs.access(path, "rx")
|
||||||
|
|
||||||
local fd = kernel.vfs.open(path, "r")
|
local fd = kernel.vfs.open(path, "r")
|
||||||
local data = kernel.vfs.read(fd, 1024 * 1024 * 4)
|
local data = kernel.vfs.read(fd, 1024 * 1024 * 4)
|
||||||
kernel.vfs.close(fd)
|
kernel.vfs.close(fd)
|
||||||
|
|
||||||
local func, err = load(data, "@" .. path, "t", env or kernel._U)
|
local env = kernel.freshUserEnv()
|
||||||
|
|
||||||
|
local func, err = load(data, "@" .. path, "t", env)
|
||||||
if not func then error("ENOEXEC: " .. tostring(err)) end
|
if not func then error("ENOEXEC: " .. tostring(err)) end
|
||||||
|
|
||||||
local meta = kernel.vfs.lstat(path)
|
local meta = kernel.vfs.lstat(path)
|
||||||
@@ -39,11 +41,11 @@ local function createTask(func, name, envars, args, tgid, real_uid, eff_uid)
|
|||||||
|
|
||||||
if kernel.config.logTaskExit then
|
if kernel.config.logTaskExit then
|
||||||
if not ok 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
|
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
|
else
|
||||||
kernel.log("Task " .. tostring(id) .. " exited without code", "INFO")
|
kernel.log("Task " .. tostring(id) .. " exited without code", "DBUG", 0x00FFFF)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -108,7 +110,7 @@ function sys.execspawn(path, name, envars, args, tgid)
|
|||||||
kernel.log(
|
kernel.log(
|
||||||
"execspawn: suid exec '" .. path ..
|
"execspawn: suid exec '" .. path ..
|
||||||
"' caller_uid=" .. tostring(real_uid) ..
|
"' caller_uid=" .. tostring(real_uid) ..
|
||||||
" -> euid=" .. tostring(euid), "INFO"
|
" -> euid=" .. tostring(euid)
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -134,9 +136,9 @@ function sys.exec(path, args, envars)
|
|||||||
local ok, err = xpcall(func, debug.traceback, table.unpack(task.args))
|
local ok, err = xpcall(func, debug.traceback, table.unpack(task.args))
|
||||||
if kernel.config.logTaskExit then
|
if kernel.config.logTaskExit then
|
||||||
if not ok 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
|
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
|
||||||
end
|
end
|
||||||
if type(err) == "number" then tasks[tostring(task.pid)].exit = err end
|
if type(err) == "number" then tasks[tostring(task.pid)].exit = err end
|
||||||
@@ -153,7 +155,7 @@ end
|
|||||||
|
|
||||||
function sys.sleep(s)
|
function sys.sleep(s)
|
||||||
kernel.currentTask.status = "S"
|
kernel.currentTask.status = "S"
|
||||||
kernel.currentTask.sleep = kernel.computer:time() + s * 1000
|
kernel.currentTask.sleep = kernel.EFI:getEpochMs() + s * 1000
|
||||||
coroutine.yield()
|
coroutine.yield()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -258,9 +260,9 @@ function sys.exit(code)
|
|||||||
local task = kernel.currentTask
|
local task = kernel.currentTask
|
||||||
if kernel.config.logTaskExit then
|
if kernel.config.logTaskExit then
|
||||||
if code 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
|
else
|
||||||
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "INFO")
|
kernel.log("Task " .. tostring(task.pid) .. " exited without code", "DBUG", 0x00FFFF)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
tasks[tostring(task.pid)].status = "Z"
|
tasks[tostring(task.pid)].status = "Z"
|
||||||
@@ -301,9 +303,9 @@ local function reapDeadTasks()
|
|||||||
task.syscallReturn = nil
|
task.syscallReturn = nil
|
||||||
task.sleep = nil
|
task.sleep = nil
|
||||||
task.fd = 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
|
and task.status == "Z" then
|
||||||
for _, child in ipairs(task.children) do
|
for _, child in ipairs(task.children) do
|
||||||
child.parent = tasks["1"]
|
child.parent = tasks["1"]
|
||||||
@@ -341,7 +343,7 @@ function kernel.main()
|
|||||||
local taskTimes = {}
|
local taskTimes = {}
|
||||||
|
|
||||||
for pid, task in pairs(tasks) do
|
for pid, task in pairs(tasks) do
|
||||||
if task.status == "S" and kernel.computer:time() >= task.sleep then
|
if task.status == "S" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||||
task.status = "R"
|
task.status = "R"
|
||||||
task.sleep = 0
|
task.sleep = 0
|
||||||
end
|
end
|
||||||
@@ -357,15 +359,30 @@ function kernel.main()
|
|||||||
|
|
||||||
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
if task.sigq and #task.sigq ~= 0 and task.sigh then
|
||||||
local coro = coroutine.create(task.sigh)
|
local coro = coroutine.create(task.sigh)
|
||||||
if kernel.config.preempt then
|
local sigret = { coroutine.resume(coro, table.remove(task.sigq, 1)) }
|
||||||
resumeWithTimeout(coro, task.timeSlice, 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
|
else
|
||||||
coroutine.resume(coro, table.remove(task.sigq, 1))
|
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) }
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if task.status == "R" then
|
if task.status == "R" then
|
||||||
local startTime = kernel.computer:time()
|
local startTime = kernel.EFI:getEpochMs()
|
||||||
local ret
|
local ret
|
||||||
|
|
||||||
if kernel.config.preempt then
|
if kernel.config.preempt then
|
||||||
@@ -374,7 +391,7 @@ function kernel.main()
|
|||||||
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
ret = { coroutine.resume(task.coro, table.unpack(task.syscallReturn)) }
|
||||||
end
|
end
|
||||||
|
|
||||||
local elapsed = kernel.computer:time() - startTime
|
local elapsed = kernel.EFI:getEpochMs() - startTime
|
||||||
task.lastTime = elapsed
|
task.lastTime = elapsed
|
||||||
task.totalTime = (task.totalTime or 0) + elapsed
|
task.totalTime = (task.totalTime or 0) + elapsed
|
||||||
task.numRuns = (task.numRuns or 0) + 1
|
task.numRuns = (task.numRuns or 0) + 1
|
||||||
@@ -386,7 +403,7 @@ function kernel.main()
|
|||||||
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
if elapsed >= Tmax then Tmax_hit = Tmax_hit + 1 end
|
||||||
|
|
||||||
if ret[1] == "error" or ret[1] == false then
|
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.status = "Z"
|
||||||
task.exit = "processHandlerException: " .. tostring(ret[2])
|
task.exit = "processHandlerException: " .. tostring(ret[2])
|
||||||
|
|
||||||
@@ -401,9 +418,9 @@ function kernel.main()
|
|||||||
local scname = ret[3]
|
local scname = ret[3]
|
||||||
if kernel.syscalls[scname] then
|
if kernel.syscalls[scname] then
|
||||||
if kernel.config.debugSyscalls 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
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -411,12 +428,12 @@ function kernel.main()
|
|||||||
|
|
||||||
if kernel.config.debugSyscalls then
|
if kernel.config.debugSyscalls then
|
||||||
if not sysret[1] 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
|
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
|
for i = 2, #sysret do
|
||||||
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local kernel=...
|
local kernel=...
|
||||||
local sysc=kernel.syscalls
|
local sysc=kernel.syscalls
|
||||||
kernel.gpio={}
|
kernel.gpio={}
|
||||||
@@ -8,8 +9,20 @@ sysc["gpio_write"]=function(pin, data)
|
|||||||
end
|
end
|
||||||
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)
|
sysc["gpio_read"]=function(pin)
|
||||||
if kernel.gpio[pin] then
|
if kernel.gpio[pin] then
|
||||||
return kernel.gpio[pin]("r")
|
return kernel.gpio[pin]("r")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
sysc["gpio_readAnalog"]=function(pin)
|
||||||
|
if kernel.gpio[pin] then
|
||||||
|
return kernel.gpio[pin]("ra")
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
function print(...)
|
function print(...)
|
||||||
local args = {...}
|
local args = {...}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
kernel.log("Loading init system...")
|
kernel.log("Loading init system...")
|
||||||
kernel.log("InitPath: " .. kernel.config.initPath)
|
kernel.log("InitPath: " .. kernel.config.initPath)
|
||||||
@@ -9,11 +9,13 @@ if not initOk then
|
|||||||
end
|
end
|
||||||
|
|
||||||
local handle = kernel.vfs.open(kernel.config.initPath, "r")
|
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)
|
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)
|
kernel.vfs.close(handle)
|
||||||
|
|
||||||
local initFunc, err = load(data, "@sysinit", "t", kernel._U)
|
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"] = {
|
kernel.tasks["1"] = {
|
||||||
coro = coroutine.create(function()
|
coro = coroutine.create(function()
|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
-- :Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
|
|
||||||
kernel.processes.login = function()
|
kernel.processes.login = function()
|
||||||
local ok, err = pcall(syscall.execspawn, "/bin/login", "login")
|
local ok, err = pcall(kernel.hpv.execspawn, "/bin/login", "login")
|
||||||
if not ok then
|
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
|
||||||
end
|
end
|
||||||
@@ -1,233 +0,0 @@
|
|||||||
-- :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
|
|
||||||
|
|
||||||
kernel.log("Seeding filesystem permissions...", "INFO")
|
|
||||||
|
|
||||||
mergeMeta("/", {
|
|
||||||
{"bin", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"boot", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"dev", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"etc", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"home", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"lib", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"root", REG, 0, 0, RW____ },
|
|
||||||
{"sbin", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"tmp", REG, 0, 0, RWXRWXRWX},
|
|
||||||
{"usr", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"var", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/boot", {
|
|
||||||
{"kernel.lua", REG, 0, 0, RW_R_R },
|
|
||||||
{"boot.cfg", REG, 0, 0, RW_R_R },
|
|
||||||
{"safeboot.cfg", REG, 0, 0, RW_R_R },
|
|
||||||
{"fstab", REG, 0, 0, RW_R_R },
|
|
||||||
{"initfs", REG, 0, 0, RW_R_R },
|
|
||||||
{"cct", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"oc", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/boot/cct", {
|
|
||||||
{"boot.lua", REG, 0, 0, RW_R_R},
|
|
||||||
{"initdisks", REG, 0, 0, RW_R_R},
|
|
||||||
{"eeprom", REG, 0, 0, RW_R_R},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/boot/oc", {
|
|
||||||
{"boot.lua", REG, 0, 0, RW_R_R},
|
|
||||||
{"initfs.lua",REG, 0, 0, RW_R_R},
|
|
||||||
{"eeprom", REG, 0, 0, RW_R_R},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/sbin", {
|
|
||||||
{"init.lua", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/bin", {
|
|
||||||
{"cat", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"chattr", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"chgrp", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"chmod", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"chown", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"chroot", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"clear", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"echo", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hfetch", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"help", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hysh", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"hyshex", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"id", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"install", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"ln", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"login", REG, 0, 0, SUID_755 },
|
|
||||||
{"loimgcreate", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"looptest", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"losetup", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"ls", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"lsusers", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"lua", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"luaold", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"micro", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"mkdir", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"mount", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"passwd", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"ps", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"pwd", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"readlink", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"sed", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"socktest", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"spm", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"startup", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"su", REG, 0, 0, SUID_755 },
|
|
||||||
{"sudo", REG, 0, 0, SUID_755 },
|
|
||||||
{"sysdump", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"umount", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"useradd", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"userdel", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"usermod", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"whoami", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"yes", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/bin/startup", {
|
|
||||||
{"test.lua", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/lib", {
|
|
||||||
{"sys", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"modules", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"crypto", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"store", REG, 0, 0, RWX_RX_RX},
|
|
||||||
{"snip", REG, 0, 0, RW_R_R },
|
|
||||||
{"io", REG, 0, 0, RW_R_R },
|
|
||||||
{"bit32", REG, 0, 0, RW_R_R },
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/lib/sys", {
|
|
||||||
{"fs", REG, 0, 0, RW_R_R},
|
|
||||||
{"hpv", REG, 0, 0, RW_R_R},
|
|
||||||
{"ipc", REG, 0, 0, RW_R_R},
|
|
||||||
{"term", REG, 0, 0, RW_R_R},
|
|
||||||
{"init", REG, 0, 0, RW_R_R},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/lib/modules", {
|
|
||||||
{"hyperion", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/lib/modules/hyperion", {
|
|
||||||
{"01_stdlib.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"10_vfs.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"11_require.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"12_devfs.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"12_tmpfs.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"13_loopdev.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"14_keventd.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"19_fstab.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"20_signals.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"20_socket.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"26_tty.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"30_userspace.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"40_auth.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"45_hypervisor.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"47_dbg.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"50_gpio.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"70_stdlibadv.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"90_init.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"91_login.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"92_permissions.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
{"99_final.kmod", REG, 0, 0, RW_R_R},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/etc", {
|
|
||||||
{"passwd", REG, 0, 0, RW_R_R },
|
|
||||||
{"shadow", REG, 0, 0, RW____ },
|
|
||||||
{"pam.d", REG, 0, 0, RWX_RX_RX},
|
|
||||||
})
|
|
||||||
|
|
||||||
mergeMeta("/etc/pam.d", {
|
|
||||||
{"secret", REG, 0, 0, RW____},
|
|
||||||
})
|
|
||||||
|
|
||||||
kernel.log("Filesystem permissions seeded.", "INFO")
|
|
||||||
@@ -0,0 +1,120 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
|
||||||
|
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("/", {
|
||||||
|
{"bin", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"boot", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"dev", REG, 0, 0, RWXRWXRWX},
|
||||||
|
{"etc", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"home", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"lib", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"root", REG, 0, 0, RW____ },
|
||||||
|
{"sbin", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"tmp", REG, 0, 0, RWXRWXRWX},
|
||||||
|
{"usr", REG, 0, 0, RWX_RX_RX},
|
||||||
|
{"var", REG, 0, 0, RWXRWXRWX},
|
||||||
|
{"opt", REG, 0, 0, RWX_RX_RX},
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/bin", {
|
||||||
|
{"login", REG, 0, 0, SUID_755 },
|
||||||
|
{"su", REG, 0, 0, SUID_755 },
|
||||||
|
{"sudo", REG, 0, 0, SUID_755 },
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/etc", {
|
||||||
|
{"passwd", REG, 0, 0, RW_R_R },
|
||||||
|
{"shadow", REG, 0, 0, RW____ },
|
||||||
|
{"pam.d", REG, 0, 0, RW____ },
|
||||||
|
})
|
||||||
|
|
||||||
|
mergeMeta("/etc/pam.d", {
|
||||||
|
{"secret", REG, 0, 0, RW____},
|
||||||
|
})
|
||||||
|
|
||||||
|
kernel.log("Filesystem permissions seeded.")
|
||||||
|
end
|
||||||
@@ -1,2 +1,3 @@
|
|||||||
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
kernel.allowGlobalOverwrites = false
|
kernel.allowGlobalOverwrites = false
|
||||||
Whitespace-only changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
@@ -261,16 +261,16 @@ local function render()
|
|||||||
syscall.write(1, "\n")
|
syscall.write(1, "\n")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
syscall.devctl(1, "sfgc", 16)
|
syscall.devctl(1, "sfgc", 0x000000)
|
||||||
syscall.devctl(1, "sbgc", 13)
|
syscall.devctl(1, "sbgc", 0xDBDBDB)
|
||||||
local pct = math.floor(math.min(100, (scroll + pageSize) / totalLines * 100))
|
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] ",
|
local status = string.format(" help -- line %d/%d (%d%%) [up/down: scroll q: quit] ",
|
||||||
scroll + 1, totalLines, pct)
|
scroll + 1, totalLines, pct)
|
||||||
if #status > screenW then status = status:sub(1, screenW) end
|
if #status > screenW then status = status:sub(1, screenW) end
|
||||||
syscall.devctl(1, "spos", 1, screenH)
|
syscall.devctl(1, "spos", 1, screenH)
|
||||||
syscall.write(1, status .. string.rep(" ", screenW - #status))
|
syscall.write(1, status .. string.rep(" ", screenW - #status))
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
syscall.devctl(1, "sbgc", 16)
|
syscall.devctl(1, "sbgc", 0x000000)
|
||||||
dirty = false
|
dirty = false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -281,7 +281,7 @@ if totalLines <= pageSize then
|
|||||||
syscall.devctl(1, "sfgc", line[2])
|
syscall.devctl(1, "sfgc", line[2])
|
||||||
syscall.write(1, line[1] .. "\n")
|
syscall.write(1, line[1] .. "\n")
|
||||||
end
|
end
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -305,5 +305,5 @@ end
|
|||||||
|
|
||||||
syscall.devctl(1, "clear")
|
syscall.devctl(1, "clear")
|
||||||
syscall.devctl(1, "spos", 1, 1)
|
syscall.devctl(1, "spos", 1, 1)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
syscall.devctl(1, "sbgc", 16)
|
syscall.devctl(1, "sbgc", 0x000000)
|
||||||
@@ -3,11 +3,11 @@
|
|||||||
-- 1=white, 2=red, 3=green, 4=blue, 5=cyan, 6=magenta, 7=yellow
|
-- 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
|
-- 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_LOGO = 0x00FFFF -- cyan
|
||||||
local C_WHITE = 1 -- white
|
local C_WHITE = 0xFFFFFF -- white
|
||||||
local C_LABEL = 13 -- light grey (key names)
|
local C_LABEL = 0xDBDBDB -- light grey (key names)
|
||||||
local C_SEP = 12 -- dark grey (---- separator)
|
local C_SEP = 0x6D6D6D -- dark grey (---- separator)
|
||||||
local C_USER = 3 -- green (user@host)
|
local C_USER = 0x00FF00 -- green (user@host)
|
||||||
|
|
||||||
local function c(col) syscall.devctl(1, "sfgc", col) end
|
local function c(col) syscall.devctl(1, "sfgc", col) end
|
||||||
|
|
||||||
@@ -1,21 +1,21 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
syscall.open("/dev/tty/tty1","r") --stdin (Device 0)
|
syscall.open("/dev/tty/1","r") --stdin (Device 0)
|
||||||
syscall.open("/dev/tty/tty1","w") --stdout (Device 1)
|
syscall.open("/dev/tty/1","w") --stdout (Device 1)
|
||||||
syscall.open("/dev/null","w") --stderr (device 2)
|
syscall.open("/dev/null","w") --stderr (device 2)
|
||||||
|
|
||||||
local success, errorMsg = xpcall(function()
|
local success, errorMsg = xpcall(function()
|
||||||
|
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
|
|
||||||
syscall.devctl(1,"clear")
|
syscall.devctl(1,"clear")
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
syscall.devctl(1,"spos",1,1)
|
syscall.devctl(1,"spos",1,1)
|
||||||
print("HyperionOS hysh Shell")
|
print("HyperionOS hysh Shell")
|
||||||
|
|
||||||
local userhost = (syscall.getUsername() or "Unknown").."@"..(syscall.getHostname() or "Unknown")
|
local userhost = (syscall.getUsername() or "Unknown").."@"..(syscall.getHostname() or "Unknown")
|
||||||
local commandHistory = {}
|
local commandHistory = {}
|
||||||
local terminate = false
|
local terminate = false
|
||||||
syscall.setEnviron("SHELL","rtbash")
|
syscall.setEnviron("SHELL","hysh")
|
||||||
syscall.setEnviron("PATH","/bin/")
|
syscall.setEnviron("PATH","/bin/")
|
||||||
local _home = syscall.getEnviron("HOME")
|
local _home = syscall.getEnviron("HOME")
|
||||||
if _home and _home ~= "" then
|
if _home and _home ~= "" then
|
||||||
@@ -26,8 +26,27 @@ else
|
|||||||
end
|
end
|
||||||
local oldWD = ""
|
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
|
for i = 1, 16 do
|
||||||
syscall.devctl(1,"sbgc",i); printInline(" ")
|
syscall.devctl(1,"sbgc",colors[i]); printInline(" ")
|
||||||
end
|
end
|
||||||
print("\n")
|
print("\n")
|
||||||
|
|
||||||
@@ -133,8 +152,6 @@ local function copyfile(src, dst)
|
|||||||
if not data then return false, err end
|
if not data then return false, err end
|
||||||
local ok, err2 = writefile(dst, data)
|
local ok, err2 = writefile(dst, data)
|
||||||
if not ok then return false, err2 end
|
if not ok then return false, err2 end
|
||||||
local ok2, stat = pcall(syscall.stat, src)
|
|
||||||
if ok2 and stat and stat.perms then pcall(syscall.chmod, dst, stat.perms) end
|
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -223,7 +240,7 @@ end
|
|||||||
|
|
||||||
builtinCmds.clear = function()
|
builtinCmds.clear = function()
|
||||||
syscall.devctl(1,"clear")
|
syscall.devctl(1,"clear")
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
syscall.devctl(1,"spos",1,1)
|
syscall.devctl(1,"spos",1,1)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -431,7 +448,7 @@ builtinCmds.head = function(...)
|
|||||||
local multi = #files > 1
|
local multi = #files > 1
|
||||||
local function dohead(text, label)
|
local function dohead(text, label)
|
||||||
if multi then
|
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
|
end
|
||||||
local count = 0
|
local count = 0
|
||||||
for line in (text.."\n"):gmatch("([^\n]*)\n") do
|
for line in (text.."\n"):gmatch("([^\n]*)\n") do
|
||||||
@@ -470,7 +487,7 @@ builtinCmds.tail = function(...)
|
|||||||
local multi = #files > 1
|
local multi = #files > 1
|
||||||
local function dotail(text, label)
|
local function dotail(text, label)
|
||||||
if multi then
|
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
|
end
|
||||||
local lines = splitlines(text)
|
local lines = splitlines(text)
|
||||||
local start = math.max(1, #lines - n + 1)
|
local start = math.max(1, #lines - n + 1)
|
||||||
@@ -810,14 +827,168 @@ builtinCmds.df = function(...)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local function listDir(dir, prefix)
|
||||||
|
local ok, entries = pcall(syscall.listdir, dir)
|
||||||
|
if not ok or not entries then return {} end
|
||||||
|
local results = {}
|
||||||
|
for _, e in ipairs(entries) do
|
||||||
|
if prefix == "" or e:sub(1, #prefix) == prefix then
|
||||||
|
local fullpath = (dir == "/" and "/" or dir.."/")..e
|
||||||
|
local t = syscall.type(fullpath)
|
||||||
|
results[#results+1] = t == "directory" and (e.."/") or e
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(results)
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
local function listCommands(prefix)
|
||||||
|
local results = {}
|
||||||
|
local seen = {}
|
||||||
|
for name in pairs(builtinCmds) do
|
||||||
|
if prefix == "" or name:sub(1, #prefix) == prefix then
|
||||||
|
if not seen[name] then results[#results+1] = name; seen[name] = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
local paths = string.split(syscall.getEnviron("PATH") or "/bin/", ":")
|
||||||
|
for _, p in ipairs(paths) do
|
||||||
|
local ok, entries = pcall(syscall.listdir, p)
|
||||||
|
if ok and entries then
|
||||||
|
for _, e in ipairs(entries) do
|
||||||
|
local fullpath = (p:sub(-1)=="/" and p or p.."/")..e
|
||||||
|
local xok = pcall(syscall.access, fullpath, "x")
|
||||||
|
if xok and (prefix == "" or e:sub(1, #prefix) == prefix) then
|
||||||
|
if not seen[e] then results[#results+1] = e; seen[e] = true end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(results)
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
local function commonPrefix(list)
|
||||||
|
if #list == 0 then return "" end
|
||||||
|
local pre = list[1]
|
||||||
|
for i = 2, #list do
|
||||||
|
local s = list[i]
|
||||||
|
local j = 1
|
||||||
|
while j <= #pre and j <= #s and pre:sub(j,j) == s:sub(j,j) do j = j+1 end
|
||||||
|
pre = pre:sub(1, j-1)
|
||||||
|
if pre == "" then return "" end
|
||||||
|
end
|
||||||
|
return pre
|
||||||
|
end
|
||||||
|
|
||||||
|
local function showCompletions(completions)
|
||||||
|
syscall.write(1, "\n")
|
||||||
|
local W = 51
|
||||||
|
local maxlen = 0
|
||||||
|
for _, c in ipairs(completions) do if #c > maxlen then maxlen = #c end end
|
||||||
|
local colw = maxlen + 2
|
||||||
|
local cols = math.max(1, math.floor(W / colw))
|
||||||
|
local i = 0
|
||||||
|
for _, c in ipairs(completions) do
|
||||||
|
local padded = c .. string.rep(" ", colw - #c)
|
||||||
|
syscall.write(1, padded)
|
||||||
|
i = i + 1
|
||||||
|
if i % cols == 0 then syscall.write(1, "\n") end
|
||||||
|
end
|
||||||
|
if i % cols ~= 0 then syscall.write(1, "\n") end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parseForCompletion(input, cursorPos)
|
||||||
|
local sofar = input:sub(1, cursorPos - 1)
|
||||||
|
local tokens = {}
|
||||||
|
for tok in sofar:gmatch("%S+") do tokens[#tokens+1] = tok end
|
||||||
|
local partial = sofar:match("%S+$") or ""
|
||||||
|
local isFirst = (#tokens == 0) or (sofar:sub(-1) ~= " " and #tokens == 1)
|
||||||
|
|
||||||
|
local partialDir, partialBase
|
||||||
|
if partial:find("/") then
|
||||||
|
partialDir = partial:match("^(.*/)") or "/"
|
||||||
|
partialBase = partial:match("[^/]*$") or ""
|
||||||
|
else
|
||||||
|
partialDir = nil
|
||||||
|
partialBase = partial
|
||||||
|
end
|
||||||
|
|
||||||
|
return tokens, partial, isFirst, partialDir, partialBase
|
||||||
|
end
|
||||||
|
|
||||||
|
local tabState = { last = nil, idx = 0, list = {} }
|
||||||
|
|
||||||
|
local function doTabComplete(input, cursorPos)
|
||||||
|
local tokens, partial, isFirst, partialDir, partialBase = parseForCompletion(input, cursorPos)
|
||||||
|
|
||||||
|
local candidates
|
||||||
|
if isFirst then
|
||||||
|
if partialDir then
|
||||||
|
local dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir)
|
||||||
|
candidates = listDir(dir, partialBase)
|
||||||
|
for i, c in ipairs(candidates) do candidates[i] = partialDir..c end
|
||||||
|
else
|
||||||
|
candidates = listCommands(partialBase)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local dir, base
|
||||||
|
if partialDir then
|
||||||
|
dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir)
|
||||||
|
base = partialBase
|
||||||
|
else
|
||||||
|
dir = syscall.getcwd()
|
||||||
|
base = partialBase
|
||||||
|
end
|
||||||
|
candidates = listDir(dir, base)
|
||||||
|
if partialDir then
|
||||||
|
for i, c in ipairs(candidates) do candidates[i] = partialDir..c end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if #candidates == 0 then
|
||||||
|
return input, cursorPos, false
|
||||||
|
end
|
||||||
|
|
||||||
|
local context = input.."\0"..tostring(cursorPos)
|
||||||
|
if tabState.last ~= context then
|
||||||
|
tabState.last = context
|
||||||
|
tabState.idx = 0
|
||||||
|
tabState.list = candidates
|
||||||
|
end
|
||||||
|
|
||||||
|
if #candidates == 1 then
|
||||||
|
local completed = candidates[1]
|
||||||
|
local before = input:sub(1, cursorPos - 1 - #partial)
|
||||||
|
local after = input:sub(cursorPos)
|
||||||
|
local newInput = before .. completed .. after
|
||||||
|
local newCursor = #before + #completed + 1
|
||||||
|
tabState.last = nil
|
||||||
|
return newInput, newCursor, true
|
||||||
|
end
|
||||||
|
|
||||||
|
local pre = commonPrefix(candidates)
|
||||||
|
if #pre > #partial then
|
||||||
|
local before = input:sub(1, cursorPos - 1 - #partial)
|
||||||
|
local after = input:sub(cursorPos)
|
||||||
|
local newInput = before .. pre .. after
|
||||||
|
local newCursor = #before + #pre + 1
|
||||||
|
tabState.last = newInput.."\0"..tostring(newCursor)
|
||||||
|
tabState.list = candidates
|
||||||
|
return newInput, newCursor, true
|
||||||
|
else
|
||||||
|
showCompletions(candidates)
|
||||||
|
return input, cursorPos, true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
local function getUserInput()
|
local function getUserInput()
|
||||||
syscall.devctl(1,"sfgc",3)
|
syscall.devctl(1,"sfgc",0x00FF00)
|
||||||
syscall.write(1, userhost)
|
syscall.write(1, userhost)
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
syscall.write(1, ":")
|
syscall.write(1, ":")
|
||||||
syscall.devctl(1,"sfgc",10)
|
syscall.devctl(1,"sfgc",0x24FFFF)
|
||||||
syscall.write(1, syscall.getcwd())
|
syscall.write(1, syscall.getcwd())
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
syscall.write(1, "$ ")
|
syscall.write(1, "$ ")
|
||||||
local curOffsetStr = syscall.devctl(1, "gpos")
|
local curOffsetStr = syscall.devctl(1, "gpos")
|
||||||
local curOffsetX = tonumber(curOffsetStr:sub(1, curOffsetStr:find(";")-1))
|
local curOffsetX = tonumber(curOffsetStr:sub(1, curOffsetStr:find(";")-1))
|
||||||
@@ -829,33 +1000,78 @@ local function getUserInput()
|
|||||||
local history = 0
|
local history = 0
|
||||||
local dirty = true
|
local dirty = true
|
||||||
|
|
||||||
|
local function getGhostSuffix()
|
||||||
|
if #input == 0 then return "" end
|
||||||
|
local _, partial, isFirst, partialDir, partialBase = parseForCompletion(input, cursorPos)
|
||||||
|
if cursorPos ~= #input + 1 then return "" end
|
||||||
|
local candidates
|
||||||
|
if isFirst then
|
||||||
|
if partialDir then
|
||||||
|
local dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir)
|
||||||
|
candidates = listDir(dir, partialBase)
|
||||||
|
for i, c in ipairs(candidates) do candidates[i] = partialDir..c end
|
||||||
|
else
|
||||||
|
candidates = listCommands(partialBase)
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local dir, base
|
||||||
|
if partialDir then
|
||||||
|
dir = partialDir:sub(1,1) == "/" and partialDir or (syscall.getcwd().."/"..partialDir)
|
||||||
|
base = partialBase
|
||||||
|
else
|
||||||
|
dir = syscall.getcwd()
|
||||||
|
base = partialBase
|
||||||
|
end
|
||||||
|
candidates = listDir(dir, base)
|
||||||
|
if partialDir then
|
||||||
|
for i, c in ipairs(candidates) do candidates[i] = partialDir..c end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #candidates == 0 then return "" end
|
||||||
|
local pre = commonPrefix(candidates)
|
||||||
|
if #pre > #partial then
|
||||||
|
return pre:sub(#partial + 1)
|
||||||
|
end
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
local function redraw()
|
local function redraw()
|
||||||
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
syscall.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||||
syscall.write(1, string.sub(input, 1, cursorPos-1))
|
syscall.write(1, string.sub(input, 1, cursorPos-1))
|
||||||
if blinkState then
|
if blinkState then
|
||||||
syscall.devctl(1,"sfgc",16); syscall.devctl(1,"sbgc",1)
|
syscall.devctl(1,"sfgc",0x000000); syscall.devctl(1,"sbgc",0xFFFFFF)
|
||||||
end
|
end
|
||||||
if cursorPos > #input then
|
if cursorPos > #input then
|
||||||
syscall.write(1, " ")
|
syscall.write(1, " ")
|
||||||
else
|
else
|
||||||
syscall.write(1, string.sub(input, cursorPos, cursorPos))
|
syscall.write(1, string.sub(input, cursorPos, cursorPos))
|
||||||
end
|
end
|
||||||
syscall.devctl(1,"sfgc",1); syscall.devctl(1,"sbgc",16)
|
syscall.devctl(1,"sfgc",0xFFFFFF); syscall.devctl(1,"sbgc",0x000000)
|
||||||
syscall.write(1, string.sub(input, cursorPos+1) .. " ")
|
local after = string.sub(input, cursorPos+1)
|
||||||
|
syscall.write(1, after)
|
||||||
|
local ghost = getGhostSuffix()
|
||||||
|
if #ghost > 0 then
|
||||||
|
syscall.devctl(1,"sfgc",0x6D00FF)
|
||||||
|
syscall.write(1, ghost)
|
||||||
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
|
syscall.write(1, " ")
|
||||||
|
else
|
||||||
|
syscall.write(1, " ")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local key = syscall.read(0)
|
local key = syscall.read(0)
|
||||||
if key and key ~= "" then
|
if key and key ~= "" then
|
||||||
if key=="\19" then if cursorPos>1 then cursorPos=cursorPos-1;dirty=true end
|
if key=="[D" then if cursorPos>1 then cursorPos=cursorPos-1;dirty=true end
|
||||||
elseif key=="\20" then if cursorPos<=#input then cursorPos=cursorPos+1;dirty=true end
|
elseif key=="[C" then if cursorPos<=#input then cursorPos=cursorPos+1;dirty=true end
|
||||||
elseif key=="\17" then
|
elseif key=="[A" then
|
||||||
if history<#commandHistory then
|
if history<#commandHistory then
|
||||||
history=history+1
|
history=history+1
|
||||||
input=commandHistory[#commandHistory-history+1]
|
input=commandHistory[#commandHistory-history+1]
|
||||||
cursorPos=#input+1;dirty=true
|
cursorPos=#input+1;dirty=true
|
||||||
end
|
end
|
||||||
elseif key=="\18" then
|
elseif key=="[B" then
|
||||||
if history>1 then
|
if history>1 then
|
||||||
history=history-1
|
history=history-1
|
||||||
input=commandHistory[#commandHistory-history+1]
|
input=commandHistory[#commandHistory-history+1]
|
||||||
@@ -863,17 +1079,49 @@ local function getUserInput()
|
|||||||
elseif history==1 then
|
elseif history==1 then
|
||||||
history=0;input="";cursorPos=1;dirty=true
|
history=0;input="";cursorPos=1;dirty=true
|
||||||
end
|
end
|
||||||
|
elseif key=="[H" then cursorPos=1;dirty=true
|
||||||
|
elseif key=="[F" then cursorPos=#input+1;dirty=true
|
||||||
|
elseif key=="[3~" then
|
||||||
|
if cursorPos<=#input then
|
||||||
|
input=string.sub(input,1,cursorPos-1)..string.sub(input,cursorPos+1)
|
||||||
|
dirty=true
|
||||||
|
end
|
||||||
|
elseif key=="\t" then
|
||||||
|
local newInput, newCursor, needsRedraw = doTabComplete(input, cursorPos)
|
||||||
|
if needsRedraw then
|
||||||
|
input = newInput; cursorPos = newCursor
|
||||||
|
local posStr = syscall.devctl(1, "gpos")
|
||||||
|
local sep = posStr:find(";")
|
||||||
|
local px = tonumber(posStr:sub(1, sep-1))
|
||||||
|
local py = tonumber(posStr:sub(sep+1))
|
||||||
|
if px > 1 then
|
||||||
|
syscall.devctl(1,"spos",1,py)
|
||||||
|
local tsz = syscall.devctl(1,"size") or "51;19"
|
||||||
|
local tw = tonumber(tsz:match("^(%d+)")) or 51
|
||||||
|
syscall.write(1, string.rep(" ", tw))
|
||||||
|
syscall.devctl(1,"spos",1,py)
|
||||||
|
end
|
||||||
|
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))
|
||||||
|
curOffsetY = tonumber(posStr:sub(sep+1))
|
||||||
|
dirty = true
|
||||||
|
end
|
||||||
elseif key=="\b" then
|
elseif key=="\b" then
|
||||||
if cursorPos>1 then
|
if cursorPos>1 then
|
||||||
input=string.sub(input,1,cursorPos-2)..string.sub(input,cursorPos)
|
input=string.sub(input,1,cursorPos-2)..string.sub(input,cursorPos)
|
||||||
cursorPos=cursorPos-1;dirty=true
|
cursorPos=cursorPos-1;dirty=true
|
||||||
end
|
end
|
||||||
elseif key=="\n" then
|
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.devctl(1,"spos",curOffsetX,curOffsetY)
|
||||||
syscall.write(1, input.." \n")
|
syscall.write(1, input.." \n")
|
||||||
return input
|
return input
|
||||||
else
|
elseif #key == 1 and key:byte(1) >= 32 and key:byte(1) < 127 then
|
||||||
input=string.sub(input,1,cursorPos-1)..key..string.sub(input,cursorPos)
|
input=string.sub(input,1,cursorPos-1)..key..string.sub(input,cursorPos)
|
||||||
cursorPos=cursorPos+1;dirty=true
|
cursorPos=cursorPos+1;dirty=true
|
||||||
end
|
end
|
||||||
@@ -885,7 +1133,7 @@ local function getUserInput()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function printError(progName, msg)
|
local function printError(progName, msg)
|
||||||
syscall.devctl(1,"sfgc",2)
|
syscall.devctl(1,"sfgc",0xFF0000)
|
||||||
local s = tostring(msg)
|
local s = tostring(msg)
|
||||||
local line, rest = s:match("%]:(%d+): (.+)$")
|
local line, rest = s:match("%]:(%d+): (.+)$")
|
||||||
if not line then line, rest = s:match(":(%d+): (.+)$") end
|
if not line then line, rest = s:match(":(%d+): (.+)$") end
|
||||||
@@ -894,7 +1142,7 @@ local function printError(progName, msg)
|
|||||||
else
|
else
|
||||||
print(progName..": "..s)
|
print(progName..": "..s)
|
||||||
end
|
end
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function runCommand(command)
|
local function runCommand(command)
|
||||||
@@ -942,27 +1190,20 @@ local function runCommand(command)
|
|||||||
|
|
||||||
local xok, xerr = pcall(syscall.access, cmdPath, "x")
|
local xok, xerr = pcall(syscall.access, cmdPath, "x")
|
||||||
if not xok then
|
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
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local text = fs.readAllText(cmdPath)
|
local proc = syscall.spawn(function()
|
||||||
local program, err = load(text, progName)
|
-- Open standard fds so programs that don't do it themselves work correctly.
|
||||||
if not program then
|
syscall.open("/dev/tty/1", "r") -- fd 0 stdin
|
||||||
syscall.devctl(1,"sfgc",2)
|
syscall.open("/dev/tty/1", "w") -- fd 1 stdout
|
||||||
local line, rest = tostring(err):match(":(%d+): (.+)$")
|
syscall.open("/dev/null", "w") -- fd 2 stderr
|
||||||
if line then printInline(progName..": load error on line "..line..": "); print(rest)
|
-- exec replaces this coroutine's code with a fresh isolated environment
|
||||||
else print(progName..": load error: "..tostring(err)) end
|
-- compiled from disk by the kernel (via loadExecutable -> freshUserEnv),
|
||||||
syscall.devctl(1,"sfgc",1); return
|
-- so the child cannot share any upvalue or syscall table state with hysh.
|
||||||
end
|
syscall.exec(cmdPath, {table.unpack(args, 2)})
|
||||||
|
end, progName)
|
||||||
local proc = syscall.spawn(function(...)
|
|
||||||
syscall.open("/dev/tty/tty1","r")
|
|
||||||
syscall.open("/dev/tty/tty1","w")
|
|
||||||
syscall.open("/dev/null","w")
|
|
||||||
local ok2, msg = pcall(program, ...)
|
|
||||||
if not ok2 then printError(progName, msg) end
|
|
||||||
end, progName, nil, {table.unpack(args, 2)})
|
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
local exited, code = syscall.collect(proc)
|
local exited, code = syscall.collect(proc)
|
||||||
@@ -973,8 +1214,8 @@ local function runCommand(command)
|
|||||||
if terminate then
|
if terminate then
|
||||||
local ok2 = syscall.kill(proc)
|
local ok2 = syscall.kill(proc)
|
||||||
if ok2 then
|
if ok2 then
|
||||||
syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",2)
|
syscall.devctl(1,"sbgc",16); syscall.devctl(1,"sfgc",0xFF0000)
|
||||||
print("\nProgram Terminated."); syscall.devctl(1,"sfgc",1)
|
print("\nProgram Terminated."); syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
end
|
end
|
||||||
terminate = false; break
|
terminate = false; break
|
||||||
end
|
end
|
||||||
@@ -996,8 +1237,8 @@ end, debug.traceback)
|
|||||||
|
|
||||||
if not success then
|
if not success then
|
||||||
syscall.log("Error running shell: "..errorMsg, "ERROR")
|
syscall.log("Error running shell: "..errorMsg, "ERROR")
|
||||||
syscall.devctl(1,"sfgc",2)
|
syscall.devctl(1,"sfgc",0xFF0000)
|
||||||
syscall.devctl(1,"sbgc",16)
|
syscall.devctl(1,"sbgc",0x000000)
|
||||||
print()
|
print()
|
||||||
print("Error running shell: ")
|
print("Error running shell: ")
|
||||||
print(errorMsg)
|
print(errorMsg)
|
||||||
File renamed without changes.
@@ -0,0 +1,3 @@
|
|||||||
|
local args={...}
|
||||||
|
table.insert(args, "-lah")
|
||||||
|
syscall.exec("/bin/ls", args)
|
||||||
File renamed without changes.
@@ -1,6 +1,6 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
syscall.open("/dev/tty/tty1", "r") --stdin (fd 0)
|
syscall.open("/dev/tty/1", "r") --stdin (fd 0)
|
||||||
syscall.open("/dev/tty/tty1", "w") --stdout (fd 1)
|
syscall.open("/dev/tty/1", "w") --stdout (fd 1)
|
||||||
syscall.open("/dev/null", "w") --stderr (fd 2)
|
syscall.open("/dev/null", "w") --stderr (fd 2)
|
||||||
|
|
||||||
|
|
||||||
@@ -37,9 +37,9 @@ local function firstBoot()
|
|||||||
|
|
||||||
syscall.devctl(1, "clear")
|
syscall.devctl(1, "clear")
|
||||||
syscall.devctl(1, "spos", 1, 1)
|
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.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")
|
syscall.write(1, "No root password is set. Please create one now.\n\n")
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
@@ -49,25 +49,25 @@ local function firstBoot()
|
|||||||
local pw2 = readLine("*")
|
local pw2 = readLine("*")
|
||||||
|
|
||||||
if pw1 ~= pw2 then
|
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.write(1, "Passwords do not match. Try again.\n\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
elseif #pw1 < 6 then
|
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.write(1, "Password too short (minimum 6 characters).\n\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
else
|
else
|
||||||
local ok, err = syscall.setpassword(0, pw1)
|
local ok, err = syscall.setpassword(0, pw1)
|
||||||
if ok then
|
if ok then
|
||||||
syscall.devctl(1, "sfgc", 3)
|
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||||
syscall.write(1, "Root password set.\n\n")
|
syscall.write(1, "Root password set.\n\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
sleep(0.5)
|
sleep(0.5)
|
||||||
break
|
break
|
||||||
else
|
else
|
||||||
syscall.devctl(1, "sfgc", 2)
|
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||||
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
syscall.write(1, "Error: " .. tostring(err) .. "\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -112,8 +112,8 @@ end
|
|||||||
|
|
||||||
local function doLogin()
|
local function doLogin()
|
||||||
syscall.devctl(1, "clear")
|
syscall.devctl(1, "clear")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
syscall.devctl(1, "sbgc", 16)
|
syscall.devctl(1, "sbgc", 0x000000)
|
||||||
syscall.devctl(1, "spos", 1, 1)
|
syscall.devctl(1, "spos", 1, 1)
|
||||||
|
|
||||||
local hostname = syscall.getHostname() or "hyperion"
|
local hostname = syscall.getHostname() or "hyperion"
|
||||||
@@ -122,16 +122,17 @@ local function doLogin()
|
|||||||
|
|
||||||
local attempts = 0
|
local attempts = 0
|
||||||
while attempts < MAX_ATTEMPTS do
|
while attempts < MAX_ATTEMPTS do
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
syscall.write(1, "Username: ")
|
syscall.write(1, "Username: ")
|
||||||
local username = readLine(nil)
|
local username = readLine(nil)
|
||||||
|
|
||||||
if username == "" then goto continue end
|
if username ~= "" then
|
||||||
|
|
||||||
syscall.write(1, "Password: ")
|
syscall.write(1, "Password: ")
|
||||||
local password = readLine("*")
|
local password = readLine("*")
|
||||||
|
local uid = syscall.getuidbyname(username)
|
||||||
|
|
||||||
local ok, err = syscall.login(username, password)
|
local ok, err = syscall.login(uid, password)
|
||||||
if ok then
|
if ok then
|
||||||
local uid = syscall.getuid()
|
local uid = syscall.getuid()
|
||||||
local pwent = syscall.getpasswd(uid)
|
local pwent = syscall.getpasswd(uid)
|
||||||
@@ -139,9 +140,9 @@ local function doLogin()
|
|||||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||||
local homedir = (pwent and pwent.homedir) or "/"
|
local homedir = (pwent and pwent.homedir) or "/"
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 3)
|
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||||
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
syscall.write(1, "\nWelcome, " .. username .. "!\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
sleep(0.3)
|
sleep(0.3)
|
||||||
|
|
||||||
spawnShell(username, uid, shell, homedir)
|
spawnShell(username, uid, shell, homedir)
|
||||||
@@ -149,17 +150,16 @@ local function doLogin()
|
|||||||
else
|
else
|
||||||
attempts = attempts + 1
|
attempts = attempts + 1
|
||||||
sleep(1)
|
sleep(1)
|
||||||
syscall.devctl(1, "sfgc", 2)
|
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||||
syscall.write(1, "Login incorrect.\n\n")
|
syscall.write(1, "Login incorrect.\n\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
::continue::
|
syscall.devctl(1, "sfgc", 0xFF0000)
|
||||||
end
|
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 2)
|
|
||||||
syscall.write(1, "Maximum login attempts exceeded.\n")
|
syscall.write(1, "Maximum login attempts exceeded.\n")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
sleep(5)
|
sleep(5)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -43,7 +43,7 @@ if opts.help then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
|
|
||||||
if opts.x then
|
if opts.x then
|
||||||
if #args < 2 then
|
if #args < 2 then
|
||||||
@@ -110,9 +110,9 @@ if opts.x then
|
|||||||
pcall(syscall.umount, tmpMnt)
|
pcall(syscall.umount, tmpMnt)
|
||||||
pcall(syscall.lodetach, loopId)
|
pcall(syscall.lodetach, loopId)
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": extracted "..count.." file(s) to "..destPath)
|
print(name..": extracted "..count.." file(s) to "..destPath)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -150,8 +150,8 @@ local lineCount = 0
|
|||||||
for _ in imgStr:gmatch("\n") do lineCount = lineCount + 1 end
|
for _ in imgStr:gmatch("\n") do lineCount = lineCount + 1 end
|
||||||
local byteCount = #imgStr
|
local byteCount = #imgStr
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": image written to "..imgPath)
|
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))
|
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 info = devs[id]
|
||||||
local mode = (type(info) == "table" and info.mode) or "bind"
|
local mode = (type(info) == "table" and info.mode) or "bind"
|
||||||
local path = (type(info) == "table" and info.path) or tostring(info)
|
local path = (type(info) == "table" and info.path) or tostring(info)
|
||||||
local colour = mode == "image" and 5 or 4
|
local colour = mode == "image" and 0x00FFFF or 0x0000FF
|
||||||
syscall.devctl(1, "sfgc", 3)
|
syscall.devctl(1, "sfgc", 0x00FF00)
|
||||||
printInline(string.format("%-10s", id))
|
printInline(string.format("%-10s", id))
|
||||||
syscall.devctl(1, "sfgc", colour)
|
syscall.devctl(1, "sfgc", colour)
|
||||||
printInline(string.format("%-7s", "["..mode.."]"))
|
printInline(string.format("%-7s", "["..mode.."]"))
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
print(" "..path)
|
print(" "..path)
|
||||||
end
|
end
|
||||||
if not any then
|
if not any then
|
||||||
syscall.devctl(1, "sfgc", 14)
|
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||||
print(name..": no loop devices attached")
|
print(name..": no loop devices attached")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@@ -92,9 +92,9 @@ if opts.d then
|
|||||||
end
|
end
|
||||||
print(name..": "..msg); syscall.exit(1); return
|
print(name..": "..msg); syscall.exit(1); return
|
||||||
end
|
end
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": detached "..id)
|
print(name..": detached "..id)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -45,7 +45,7 @@ if cloptions.help then
|
|||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
local dir = args[1] or ""
|
local dir = args[1] or ""
|
||||||
if dir:sub(1, 1) ~= "/" then
|
if dir:sub(1, 1) ~= "/" then
|
||||||
dir = syscall.getcwd() .. "/" .. dir
|
dir = syscall.getcwd() .. "/" .. dir
|
||||||
@@ -84,7 +84,7 @@ local function humanSize(size)
|
|||||||
size = size / 1024
|
size = size / 1024
|
||||||
scale = scale + 1
|
scale = scale + 1
|
||||||
end
|
end
|
||||||
if scale == 0 then return tostring(size) end
|
if scale == 0 then return tostring(size).."B" end
|
||||||
if size < 10 then
|
if size < 10 then
|
||||||
return string.format("%.1f%s", size, sizePrefixes[scale])
|
return string.format("%.1f%s", size, sizePrefixes[scale])
|
||||||
end
|
end
|
||||||
@@ -136,26 +136,26 @@ if cloptions.l then
|
|||||||
printInline(tostring(mtime) .. " ")
|
printInline(tostring(mtime) .. " ")
|
||||||
|
|
||||||
if isSym then
|
if isSym then
|
||||||
syscall.devctl(1, "sfgc", 6)
|
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||||
printInline(v)
|
printInline(v)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
local ok, target = pcall(syscall.readlink, fullPath)
|
local ok, target = pcall(syscall.readlink, fullPath)
|
||||||
if ok then
|
if ok then
|
||||||
printInline(" -> ")
|
printInline(" -> ")
|
||||||
local targetExists = pcall(syscall.stat, fullPath)
|
local targetExists = pcall(syscall.stat, fullPath)
|
||||||
syscall.devctl(1, "sfgc", targetExists and 6 or 2)
|
syscall.devctl(1, "sfgc", targetExists and 0xFF00FF or 0xFF0000)
|
||||||
printInline(target)
|
printInline(target)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
end
|
end
|
||||||
elseif isDir then
|
elseif isDir then
|
||||||
syscall.devctl(1, "sfgc", 4)
|
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||||
printInline(v)
|
printInline(v)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
else
|
else
|
||||||
local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1)
|
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)
|
printInline(v)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
end
|
end
|
||||||
print("")
|
print("")
|
||||||
end
|
end
|
||||||
@@ -175,16 +175,16 @@ for i, v in ipairs(list) do
|
|||||||
local isSym = stat and stat.etype == 0x01
|
local isSym = stat and stat.etype == 0x01
|
||||||
|
|
||||||
if isSym then
|
if isSym then
|
||||||
syscall.devctl(1, "sfgc", 6)
|
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||||
elseif isDir then
|
elseif isDir then
|
||||||
syscall.devctl(1, "sfgc", 4)
|
syscall.devctl(1, "sfgc", 0x6D00FF)
|
||||||
else
|
else
|
||||||
local isExec = stat and stat.perms and (math.floor(stat.perms / (2^9)) % 2 == 1)
|
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
|
end
|
||||||
|
|
||||||
printInline(v)
|
printInline(v)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
printInline((" "):rep(colWidth - #v))
|
printInline((" "):rep(colWidth - #v))
|
||||||
|
|
||||||
if i % numCols == 0 then print("") end
|
if i % numCols == 0 then print("") end
|
||||||
@@ -5,15 +5,15 @@ if not users or #users == 0 then
|
|||||||
return
|
return
|
||||||
end
|
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.format("%-6s %-6s %-16s %-20s %s", "UID", "GID", "Username", "Home", "Shell"))
|
||||||
print(string.rep("-", 65))
|
print(string.rep("-", 65))
|
||||||
syscall.devctl(1,"sfgc",1)
|
syscall.devctl(1,"sfgc",0xFFFFFF)
|
||||||
|
|
||||||
for _, u in ipairs(users) do
|
for _, u in ipairs(users) do
|
||||||
local lock_marker = u.locked and " [locked]" or ""
|
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",
|
print(string.format("%-6d %-6d %-16s %-20s %s%s",
|
||||||
u.uid, u.gid, u.username, u.homedir, u.shell, lock_marker))
|
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
|
end
|
||||||
@@ -69,17 +69,17 @@ if #args == 0 and not opts.o then
|
|||||||
end
|
end
|
||||||
|
|
||||||
if next(loDevs) == nil then
|
if next(loDevs) == nil then
|
||||||
syscall.devctl(1, "sfgc", 14)
|
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||||
print("(no loop devices attached)")
|
print("(no loop devices attached)")
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
for id, info in pairs(loDevs) do
|
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)
|
syscall.devctl(1, "sfgc", colour)
|
||||||
printInline(info.mode.." "..id)
|
printInline(info.mode.." "..id)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
print(" on "..info.path)
|
print(" on "..info.path)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
@@ -119,9 +119,9 @@ if opts.o and opts.o:lower() == "loop" then
|
|||||||
print(name..": mount: "..msg); syscall.exit(1); return
|
print(name..": mount: "..msg); syscall.exit(1); return
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": "..loopId.." mounted at "..dest)
|
print(name..": "..loopId.." mounted at "..dest)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -141,9 +141,9 @@ if #args == 2 then
|
|||||||
print(name..": "..msg); syscall.exit(1); return
|
print(name..": "..msg); syscall.exit(1); return
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": "..loopId.." mounted at "..dest)
|
print(name..": "..loopId.." mounted at "..dest)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -9,7 +9,7 @@ local currentUid = syscall.getuid()
|
|||||||
|
|
||||||
local targetUid
|
local targetUid
|
||||||
if targetName then
|
if targetName then
|
||||||
targetUid = syscall.getuid(targetName)
|
targetUid = syscall.getuid()
|
||||||
if not targetUid then
|
if not targetUid then
|
||||||
print("passwd: user '" .. targetName .. "' does not exist")
|
print("passwd: user '" .. targetName .. "' does not exist")
|
||||||
syscall.exit(1); return
|
syscall.exit(1); return
|
||||||
@@ -36,7 +36,7 @@ if currentUid ~= 0 then
|
|||||||
if #cur > 0 then cur=cur:sub(1,-2); syscall.write(1,"\b \b") end
|
if #cur > 0 then cur=cur:sub(1,-2); syscall.write(1,"\b \b") end
|
||||||
else cur=cur..ch; syscall.write(1,"*") end
|
else cur=cur..ch; syscall.write(1,"*") end
|
||||||
end
|
end
|
||||||
local ok, err = syscall.elevate(targetName, cur)
|
local ok, err = syscall.login(targetUid, cur)
|
||||||
if not ok then
|
if not ok then
|
||||||
sleep(1)
|
sleep(1)
|
||||||
print("passwd: authentication failure")
|
print("passwd: authentication failure")
|
||||||
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
for i,v in ipairs(syscall.getTasks()) do
|
for i,v in ipairs(syscall.getTasks()) do
|
||||||
local task = syscall.getTask(v)
|
local task = syscall.getTask(v)
|
||||||
print(task.pid,task.username,task.name,task.status)
|
print(task.pid,task.username,task.name,task.status)
|
||||||
File renamed without changes.
@@ -1,7 +1,15 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local targetUser = ({ ... })[1] or "root"
|
local targetUser = ({ ... })[1]
|
||||||
local currentUid = syscall.getuid()
|
local currentUid = syscall.getuid()
|
||||||
local targetUid = syscall.getuidbyname(targetUser)
|
if syscall.geteuid()~=0 then
|
||||||
|
syscall.exec("/bin/su", {...})
|
||||||
|
end
|
||||||
|
local targetUid
|
||||||
|
if targetUser then
|
||||||
|
targetUid = syscall.getuidbyname(targetUser)
|
||||||
|
else
|
||||||
|
targetUid = 0
|
||||||
|
end
|
||||||
|
|
||||||
if not targetUid then
|
if not targetUid then
|
||||||
print("su: user '" .. targetUser .. "' does not exist")
|
print("su: user '" .. targetUser .. "' does not exist")
|
||||||
@@ -25,20 +33,21 @@ if currentUid ~= 0 then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, err = syscall.elevate(targetUser, pw)
|
local ok, err = syscall.login(targetUid, pw)
|
||||||
if not ok then
|
if not ok then
|
||||||
sleep(1)
|
sleep(1)
|
||||||
print("su: Authentication failure")
|
print("su: Authentication failure")
|
||||||
syscall.exit(1)
|
syscall.exit(1)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
else
|
||||||
|
syscall.setuid(targetUid)
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall.setuid(targetUid)
|
|
||||||
|
|
||||||
local pwent = syscall.getpasswd(targetUid)
|
local pwent = syscall.getpasswd(targetUid)
|
||||||
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
local shell = (pwent and pwent.shell) or "/bin/hysh"
|
||||||
local homedir = (pwent and pwent.homedir) or "/"
|
local homedir = (pwent and pwent.homedir) or "/"
|
||||||
|
local username= (pwent and pwent.username)or "Unknown"
|
||||||
|
|
||||||
local ok_cd, err_cd = pcall(syscall.chdir, homedir)
|
local ok_cd, err_cd = pcall(syscall.chdir, homedir)
|
||||||
if not ok_cd then
|
if not ok_cd then
|
||||||
@@ -46,7 +55,7 @@ if not ok_cd then
|
|||||||
syscall.chdir(homedir)
|
syscall.chdir(homedir)
|
||||||
end
|
end
|
||||||
syscall.setEnviron("HOME", homedir)
|
syscall.setEnviron("HOME", homedir)
|
||||||
syscall.setEnviron("USER", targetUser)
|
syscall.setEnviron("USER", username)
|
||||||
syscall.setEnviron("SHELL", shell)
|
syscall.setEnviron("SHELL", shell)
|
||||||
|
|
||||||
local ok, err = pcall(syscall.exec, shell)
|
local ok, err = pcall(syscall.exec, shell)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
|
|
||||||
local cmdArgs = {...}
|
local cmdArgs = {...}
|
||||||
local targetUser = "root"
|
local targetUser = "root"
|
||||||
@@ -55,7 +55,7 @@ if currentUid ~= 0 then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local ok, err = syscall.elevate("root", pw)
|
local ok, err = syscall.login(0, pw)
|
||||||
if not ok then
|
if not ok then
|
||||||
sleep(1)
|
sleep(1)
|
||||||
print("sudo: Authentication failure")
|
print("sudo: Authentication failure")
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local path=...
|
||||||
|
path=path or "/dev/tty/1"
|
||||||
|
local syscalls=syscall.sysdump()
|
||||||
|
local fd=syscall.open(path,"w")
|
||||||
|
for i=1, #syscalls do
|
||||||
|
syscall.write(fd,syscalls[i].."\n")
|
||||||
|
end
|
||||||
|
syscall.write(fd,"Total # of syscalls: "..tostring(#syscalls))
|
||||||
|
syscall.close(fd)
|
||||||
@@ -59,9 +59,9 @@ if opts.l then
|
|||||||
end
|
end
|
||||||
print(name..": "..msg); syscall.exit(1); return
|
print(name..": "..msg); syscall.exit(1); return
|
||||||
end
|
end
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": detached "..id)
|
print(name..": detached "..id)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -95,17 +95,17 @@ if not ok then
|
|||||||
print(name..": "..msg); syscall.exit(1); return
|
print(name..": "..msg); syscall.exit(1); return
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall.devctl(1, "sfgc", 10)
|
syscall.devctl(1, "sfgc", 0x00FFFF)
|
||||||
print(name..": unmounted "..mpt)
|
print(name..": unmounted "..mpt)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
|
|
||||||
if loopIdToDetach then
|
if loopIdToDetach then
|
||||||
for _, id in ipairs(loopIdToDetach) do
|
for _, id in ipairs(loopIdToDetach) do
|
||||||
local dok = pcall(syscall.lodetach, id)
|
local dok = pcall(syscall.lodetach, id)
|
||||||
if dok then
|
if dok then
|
||||||
syscall.devctl(1, "sfgc", 14)
|
syscall.devctl(1, "sfgc", 0xFF00FF)
|
||||||
print(name..": auto-detached "..id)
|
print(name..": auto-detached "..id)
|
||||||
syscall.devctl(1, "sfgc", 1)
|
syscall.devctl(1, "sfgc", 0xFFFFFF)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
File renamed without changes.
@@ -29,7 +29,7 @@ if not ok then
|
|||||||
end
|
end
|
||||||
|
|
||||||
if removeHome and pwent and pwent.homedir then
|
if removeHome and pwent and pwent.homedir then
|
||||||
local fs = require("sys.fs")
|
local fs = require("fs")
|
||||||
local ok2, err2 = pcall(function()
|
local ok2, err2 = pcall(function()
|
||||||
local function rmdir(path)
|
local function rmdir(path)
|
||||||
for _, f in ipairs(fs.list(path) or {}) do
|
for _, f in ipairs(fs.list(path) or {}) do
|
||||||
File renamed without changes.
@@ -1,3 +1,4 @@
|
|||||||
|
--:Minify:--
|
||||||
local args = {...}
|
local args = {...}
|
||||||
while true do
|
while true do
|
||||||
if #args == 0 then
|
if #args == 0 then
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
local ini = {}
|
||||||
|
|
||||||
|
function ini.parse(str)
|
||||||
|
local config = {}
|
||||||
|
local section = nil
|
||||||
|
|
||||||
|
for line in str:gmatch("[^\r\n]+") do
|
||||||
|
-- trim whitespace
|
||||||
|
line = line:match("^%s*(.-)%s*$")
|
||||||
|
|
||||||
|
-- skip empty lines and comments
|
||||||
|
if line ~= "" and not line:match("^[;#]") then
|
||||||
|
-- section
|
||||||
|
local sec = line:match("^%[(.-)%]$")
|
||||||
|
if sec then
|
||||||
|
section = sec
|
||||||
|
config[section] = config[section] or {}
|
||||||
|
else
|
||||||
|
-- key=value
|
||||||
|
local key, value = line:match("^(.-)=(.*)$")
|
||||||
|
if key then
|
||||||
|
key = key:match("^%s*(.-)%s*$")
|
||||||
|
value = value:match("^%s*(.-)%s*$")
|
||||||
|
|
||||||
|
if section then
|
||||||
|
config[section][key] = value
|
||||||
|
else
|
||||||
|
config[key] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return config
|
||||||
|
end
|
||||||
|
|
||||||
|
return ini
|
||||||
@@ -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,14 +1,14 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local C_PROMPT = 7
|
local C_PROMPT = 0xFFFF00
|
||||||
local C_CONT = 13
|
local C_CONT = 0xDBDBDB
|
||||||
local C_OUT = 5
|
local C_OUT = 0x00FFFF
|
||||||
local C_ERR = 2
|
local C_ERR = 0xFF0000
|
||||||
local C_KEY = 3
|
local C_KEY = 0x00FF00
|
||||||
local C_STR = 9
|
local C_STR = 0x00FF88
|
||||||
local C_NUM = 10
|
local C_NUM = 0x24FFFF
|
||||||
local C_BOOL = 8
|
local C_BOOL = 0xFF6D00
|
||||||
local C_NIL = 12
|
local C_NIL = 0x6D6D6D
|
||||||
local C_TABLE = 13
|
local C_TABLE = 0xDBDBDB
|
||||||
|
|
||||||
local function c(col) syscall.devctl(1, "sfgc", col) end
|
local function c(col) syscall.devctl(1, "sfgc", col) end
|
||||||
local function w(s) syscall.write(1, tostring(s)) end
|
local function w(s) syscall.write(1, tostring(s)) end
|
||||||
@@ -250,9 +250,9 @@ local function getUserInput(prompt, history)
|
|||||||
local function redraw()
|
local function redraw()
|
||||||
syscall.devctl(1, "spos", ox, oy)
|
syscall.devctl(1, "spos", ox, oy)
|
||||||
w(input:sub(1, cursor-1))
|
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))
|
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) .. " ")
|
w(input:sub(cursor+1) .. " ")
|
||||||
dirty = false
|
dirty = false
|
||||||
end
|
end
|
||||||
@@ -260,17 +260,17 @@ local function getUserInput(prompt, history)
|
|||||||
while true do
|
while true do
|
||||||
local key = syscall.read(0)
|
local key = syscall.read(0)
|
||||||
if key and key ~= "" then
|
if key and key ~= "" then
|
||||||
if key == "\19" then
|
if key == "[C" then
|
||||||
if cursor > 1 then cursor = cursor - 1; dirty = true end
|
if cursor > 1 then cursor = cursor - 1; dirty = true end
|
||||||
elseif key == "\20" then
|
elseif key == "[D" then
|
||||||
if cursor <= #input then cursor = cursor + 1; dirty = true end
|
if cursor <= #input then cursor = cursor + 1; dirty = true end
|
||||||
elseif key == "\17" then
|
elseif key == "[A" then
|
||||||
if history and histIdx < #history then
|
if history and histIdx < #history then
|
||||||
histIdx = histIdx + 1
|
histIdx = histIdx + 1
|
||||||
input = history[#history - histIdx + 1]
|
input = history[#history - histIdx + 1]
|
||||||
cursor = #input + 1; dirty = true
|
cursor = #input + 1; dirty = true
|
||||||
end
|
end
|
||||||
elseif key == "\18" then
|
elseif key == "[B" then
|
||||||
if histIdx > 1 then
|
if histIdx > 1 then
|
||||||
histIdx = histIdx - 1
|
histIdx = histIdx - 1
|
||||||
input = history[#history - histIdx + 1]
|
input = history[#history - histIdx + 1]
|
||||||
@@ -284,13 +284,13 @@ local function getUserInput(prompt, history)
|
|||||||
cursor = cursor - 1; dirty = true
|
cursor = cursor - 1; dirty = true
|
||||||
end
|
end
|
||||||
elseif key == "\n" then
|
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)
|
syscall.devctl(1,"spos",ox,oy)
|
||||||
w(input .. " \n")
|
w(input .. " \n")
|
||||||
return input
|
return input
|
||||||
else
|
elseif #key == 1 and key:byte(1) >= 32 and key:byte(1) < 127 then
|
||||||
input = input:sub(1, cursor-1) .. key .. input:sub(cursor)
|
input=string.sub(input,1,cursor-1)..key..string.sub(input,cursor)
|
||||||
cursor = cursor + 1; dirty = true
|
cursor=cursor+1;dirty=true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
local nb = (math.floor(syscall.getUptime() / 500) % 2) == 0
|
local nb = (math.floor(syscall.getUptime() / 500) % 2) == 0
|
||||||
@@ -299,8 +299,6 @@ local function getUserInput(prompt, history)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
syscall.devctl(1, "clear")
|
|
||||||
syscall.devctl(1, "spos", 1, 1)
|
|
||||||
c(C_PROMPT); w("HyperionOS " .. _VERSION .. "\n")
|
c(C_PROMPT); w("HyperionOS " .. _VERSION .. "\n")
|
||||||
c(C_NIL)
|
c(C_NIL)
|
||||||
w("Interactive Lua REPL. exit() to quit.\n\n")
|
w("Interactive Lua REPL. exit() to quit.\n\n")
|
||||||
@@ -310,7 +308,7 @@ local history = {}
|
|||||||
|
|
||||||
while true do
|
while true do
|
||||||
local code = getUserInput("lua> ", history)
|
local code = getUserInput("lua> ", history)
|
||||||
if code == "" then goto continue end
|
if code ~= "" then
|
||||||
|
|
||||||
while isIncomplete(code) do
|
while isIncomplete(code) do
|
||||||
code = code .. "\n" .. getUserInput("... ", nil)
|
code = code .. "\n" .. getUserInput("... ", nil)
|
||||||
@@ -321,5 +319,5 @@ while true do
|
|||||||
end
|
end
|
||||||
|
|
||||||
runCode(code)
|
runCode(code)
|
||||||
::continue::
|
end
|
||||||
end
|
end
|
||||||
@@ -135,16 +135,16 @@ local function pad(s, w)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function drawTop()
|
local function drawTop()
|
||||||
tpos(1,1); tbg(4); tfg(16)
|
tpos(1,1); tbg(0x0000FF); tfg(0x000000)
|
||||||
local left = " edit" .. (fname and (" - "..fname) or "")
|
local left = " edit" .. (fname and (" - "..fname) or "")
|
||||||
if dirty then left = left .. " [+]" end
|
if dirty then left = left .. " [+]" end
|
||||||
local right = tostring(cy)..","..tostring(cx).." "
|
local right = tostring(cy)..","..tostring(cx).." "
|
||||||
twrite(pad(left..string.rep(" ", math.max(1, W-#left-#right))..right, W))
|
twrite(pad(left..string.rep(" ", math.max(1, W-#left-#right))..right, W))
|
||||||
tbg(16); tfg(1)
|
tbg(0x000000); tfg(0xFFFFFF)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function drawBottom()
|
local function drawBottom()
|
||||||
tpos(1, H); tbg(4); tfg(16)
|
tpos(1, H); tbg(0x0000FF); tfg(0x000000)
|
||||||
if msg ~= "" then
|
if msg ~= "" then
|
||||||
if msgErr then tbg(2) end
|
if msgErr then tbg(2) end
|
||||||
twrite(pad(" "..msg, W))
|
twrite(pad(" "..msg, W))
|
||||||
@@ -152,7 +152,7 @@ local function drawBottom()
|
|||||||
else
|
else
|
||||||
twrite(pad(" ^W Save ^X Quit+Save ^P Quit ^K Cut ^U Paste ^F Find ^G Go", W))
|
twrite(pad(" ^W Save ^X Quit+Save ^P Quit ^K Cut ^U Paste ^F Find ^G Go", W))
|
||||||
end
|
end
|
||||||
tbg(16); tfg(1)
|
tbg(0x000000); tfg(0xFFFFFF)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function drawLines(map)
|
local function drawLines(map)
|
||||||
@@ -177,29 +177,29 @@ local function drawLines(map)
|
|||||||
local curCh = ci > #seg and " " or seg:sub(ci, ci)
|
local curCh = ci > #seg and " " or seg:sub(ci, ci)
|
||||||
local after = seg:sub(ci+1)
|
local after = seg:sub(ci+1)
|
||||||
|
|
||||||
tfg(1); tbg(16); twrite(before)
|
tfg(0xFFFFFF); tbg(0x000000); twrite(before)
|
||||||
if blinkState then tfg(16); tbg(1) else tfg(1); tbg(16) end
|
if blinkState then tfg(0x000000); tbg(0xFFFFFF) else tfg(0xFFFFFF); tbg(0x000000) end
|
||||||
twrite(curCh)
|
twrite(curCh)
|
||||||
tfg(1); tbg(16); twrite(after)
|
tfg(0xFFFFFF); tbg(0x000000); twrite(after)
|
||||||
local drawn = #before + 1 + #after
|
local drawn = #before + 1 + #after
|
||||||
if drawn < W then twrite(string.rep(" ", W - drawn)) end
|
if drawn < W then twrite(string.rep(" ", W - drawn)) end
|
||||||
else
|
else
|
||||||
if li == sLine and sPat ~= "" and entry[2] == 1 then
|
if li == sLine and sPat ~= "" and entry[2] == 1 then
|
||||||
local s, e = seg:find(sPat)
|
local s, e = seg:find(sPat)
|
||||||
if s then
|
if s then
|
||||||
tfg(1); tbg(16); twrite(seg:sub(1,s-1))
|
tfg(0xFFFFFF); tbg(0x000000); twrite(seg:sub(1,s-1))
|
||||||
tfg(16); tbg(3); twrite(seg:sub(s,e))
|
tfg(0x000000); tbg(0x00FF00); twrite(seg:sub(s,e))
|
||||||
tfg(1); tbg(16); twrite(seg:sub(e+1))
|
tfg(0xFFFFFF); tbg(0x000000); twrite(seg:sub(e+1))
|
||||||
twrite(string.rep(" ", W - #seg))
|
twrite(string.rep(" ", W - #seg))
|
||||||
else
|
else
|
||||||
tfg(1); tbg(16); twrite(pad(seg, W))
|
tfg(0xFFFFFF); tbg(0x000000); twrite(pad(seg, W))
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
tfg(1); tbg(16); twrite(pad(seg, W))
|
tfg(0xFFFFFF); tbg(0x000000); twrite(pad(seg, W))
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
tfg(13); tbg(16); twrite(pad("~", W)); tfg(1)
|
tfg(0xDBDBDB); tbg(0x000000); twrite(pad("~", W)); tfg(0xFFFFFF)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -212,18 +212,18 @@ local function redraw()
|
|||||||
drawLines(map)
|
drawLines(map)
|
||||||
drawBottom()
|
drawBottom()
|
||||||
tpos(1, H)
|
tpos(1, H)
|
||||||
tbg(16); tfg(1)
|
tbg(0x000000); tfg(0xFFFFFF)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function prompt(label, default)
|
local function prompt(label, default)
|
||||||
local inp = default or ""
|
local inp = default or ""
|
||||||
while true do
|
while true do
|
||||||
tpos(1, H); tbg(3); tfg(16)
|
tpos(1, H); tbg(0x00FF00); tfg(0x000000)
|
||||||
twrite(pad(" "..label..inp.." ", W))
|
twrite(pad(" "..label..inp.." ", W))
|
||||||
tbg(16); tfg(1)
|
tbg(0x000000); tfg(0xFFFFFF)
|
||||||
local key = syscall.read(0)
|
local key = syscall.read(0)
|
||||||
if not key or key == "" then sleep(0.02)
|
if not key or key == "" then sleep(0.02)
|
||||||
elseif key == "\27" then return nil
|
elseif key == "" then return nil
|
||||||
elseif key == "\n" then return inp
|
elseif key == "\n" then return inp
|
||||||
elseif key == "\b" then if #inp > 0 then inp = inp:sub(1,-2) end
|
elseif key == "\b" then if #inp > 0 then inp = inp:sub(1,-2) end
|
||||||
else
|
else
|
||||||
@@ -359,31 +359,29 @@ while running do
|
|||||||
local key = syscall.read(0)
|
local key = syscall.read(0)
|
||||||
if key and key ~= "" then
|
if key and key ~= "" then
|
||||||
local b = key:byte(1)
|
local b = key:byte(1)
|
||||||
if key == "\17" then moveCursorUp(map); dirty=true
|
if key == "[A" then moveCursorUp(map); dirty=true
|
||||||
elseif key == "\18" then moveCursorDown(map); dirty=true
|
elseif key == "[B" then moveCursorDown(map); dirty=true
|
||||||
elseif key == "\19" then
|
elseif key == "[C" then
|
||||||
if cx > 1 then cx=cx-1
|
|
||||||
elseif cy > 1 then cy=cy-1; cx=#lines[cy]+1 end
|
|
||||||
dirty=true
|
|
||||||
elseif key == "\20" then
|
|
||||||
if cx <= #lines[cy] then cx=cx+1
|
if cx <= #lines[cy] then cx=cx+1
|
||||||
elseif cy < #lines then cy=cy+1; cx=1 end
|
elseif cy < #lines then cy=cy+1; cx=1 end
|
||||||
dirty=true
|
dirty=true
|
||||||
|
elseif key == "[D" then
|
||||||
|
if cx > 1 then cx=cx-1
|
||||||
|
elseif cy > 1 then cy=cy-1; cx=#lines[cy]+1 end
|
||||||
|
dirty=true
|
||||||
|
elseif key == "[H" then cx=1; dirty=true
|
||||||
|
elseif key == "[F" then cx=#lines[cy]+1; dirty=true
|
||||||
|
elseif key == "[5~" then for _=1,ROWS do moveCursorUp(map) end; dirty=true
|
||||||
|
elseif key == "[6~" then for _=1,ROWS do moveCursorDown(map) end; dirty=true
|
||||||
|
elseif key == "[3~" then delRight()
|
||||||
elseif key == "\n" then newline()
|
elseif key == "\n" then newline()
|
||||||
elseif key == "\b" then delLeft()
|
elseif key == "\b" then delLeft()
|
||||||
elseif key == "\t" then for _=1,4 do insChar(" ") end
|
elseif key == "\t" then for _=1,4 do insChar(" ") end
|
||||||
elseif b == 1 then cx=1; dirty=true
|
|
||||||
elseif b == 2 then
|
|
||||||
for _=1,ROWS do moveCursorUp(map) end; dirty=true
|
|
||||||
elseif b == 4 then delRight()
|
|
||||||
elseif b == 5 then cx=#lines[cy]+1; dirty=true
|
|
||||||
elseif b == 6 then
|
elseif b == 6 then
|
||||||
local p=prompt("Find: ",sPat); dirty=true
|
local p=prompt("Find: ",sPat); dirty=true
|
||||||
if p then sPat=p; sLine=0; findNext() end
|
if p then sPat=p; sLine=0; findNext() end
|
||||||
elseif b == 7 then goToLine()
|
elseif b == 7 then goToLine()
|
||||||
elseif b == 11 then cutLine()
|
elseif b == 11 then cutLine()
|
||||||
elseif b == 12 then
|
|
||||||
for _=1,ROWS do moveCursorDown(map) end; dirty=true
|
|
||||||
elseif b == 14 then
|
elseif b == 14 then
|
||||||
if sPat=="" then
|
if sPat=="" then
|
||||||
local p=prompt("Find: ",""); dirty=true
|
local p=prompt("Find: ",""); dirty=true
|
||||||
@@ -415,9 +413,7 @@ while running do
|
|||||||
redraw()
|
redraw()
|
||||||
dirty = false
|
dirty = false
|
||||||
end
|
end
|
||||||
|
|
||||||
sleep(0.05)
|
|
||||||
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 ""))
|
print("edit: exited"..(fname and (" - "..fname) or ""))
|
||||||
@@ -139,12 +139,9 @@ local function parseCommands(src)
|
|||||||
local c = src:sub(pos, pos)
|
local c = src:sub(pos, pos)
|
||||||
if c == "\n" or c == ";" then
|
if c == "\n" or c == ";" then
|
||||||
pos = pos + 1
|
pos = pos + 1
|
||||||
goto continue
|
elseif c == "#" then
|
||||||
end
|
|
||||||
if c == "#" then
|
|
||||||
while pos <= len and src:sub(pos,pos) ~= "\n" do pos = pos + 1 end
|
while pos <= len and src:sub(pos,pos) ~= "\n" do pos = pos + 1 end
|
||||||
goto continue
|
else
|
||||||
end
|
|
||||||
|
|
||||||
local addr1, addr2
|
local addr1, addr2
|
||||||
addr1, pos = parseAddr(src, pos)
|
addr1, pos = parseAddr(src, pos)
|
||||||
@@ -203,8 +200,7 @@ local function parseCommands(src)
|
|||||||
elseif cmd == "\n" or cmd == ";" then
|
elseif cmd == "\n" or cmd == ";" then
|
||||||
else
|
else
|
||||||
end
|
end
|
||||||
|
end
|
||||||
::continue::
|
|
||||||
end
|
end
|
||||||
|
|
||||||
return cmds
|
return cmds
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
local args={...}
|
||||||
|
|
||||||
|
local json=require("json")
|
||||||
|
local http=require("http")
|
||||||
|
local rootRepo="https://git.astronand.dev/Hyperion/HyperionOS/raw/branch/main/spm/spm.src"
|
||||||
|
|
||||||
@@ -0,0 +1 @@
|
|||||||
|
[symlinks]
|
||||||
@@ -0,0 +1,4 @@
|
|||||||
|
local args={...}
|
||||||
|
syscall.remove("/sbin/init")
|
||||||
|
syscall.symlink("/usr/lib/sysinit/sysinit", "/sbin/init")
|
||||||
|
syscall.exec("/sbin/init", args)
|
||||||
@@ -1,15 +1,16 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local kernel=...
|
local kernel=...
|
||||||
local fs=require("sys.fs")
|
local fs=require("fs")
|
||||||
|
kernel.log("Sysinit started...")
|
||||||
|
|
||||||
for i,v in pairs(kernel.processes) do
|
for i,v in pairs(kernel.processes) do
|
||||||
kernel.log("Spawning kernel task "..i)
|
kernel.log("Spawning kernel task "..i)
|
||||||
syscall.spawn(function()
|
syscall.spawn(function()
|
||||||
local status, err = pcall(v)
|
local status, err = pcall(v)
|
||||||
if not status then
|
if not status then
|
||||||
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR")
|
kernel.log("Error executing kernel task '" .. i .. "': " .. err, "ERROR", 0xFF0000)
|
||||||
else
|
else
|
||||||
kernel.log("Successfully executed kernel task: " .. i, "INFO")
|
kernel.log("Successfully executed kernel task: " .. i)
|
||||||
end
|
end
|
||||||
end, i)
|
end, i)
|
||||||
end
|
end
|
||||||
@@ -17,23 +18,24 @@ end
|
|||||||
if not fs.exists("/bin/startup") then
|
if not fs.exists("/bin/startup") then
|
||||||
fs.mkdir("/bin/startup")
|
fs.mkdir("/bin/startup")
|
||||||
end
|
end
|
||||||
|
|
||||||
local files = fs.list("/bin/startup")
|
local files = fs.list("/bin/startup")
|
||||||
if not files then error("Failed to list /bin/startup") end
|
if not files then error("Failed to list /bin/startup") end
|
||||||
for i,v in ipairs(files) do
|
for i,v in ipairs(files) do
|
||||||
if v:sub(-4) == ".lua" then
|
if v:sub(-4) == ".lua" then
|
||||||
local filepath = "/bin/startup/" .. v
|
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)
|
local startupFunc, err = load(fs.readAllText(filepath), "@" .. filepath)
|
||||||
if not startupFunc then
|
if not startupFunc then
|
||||||
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR")
|
kernel.log("Error loading startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||||
else
|
else
|
||||||
syscall.spawn(function()
|
syscall.spawn(function()
|
||||||
syscall.setuid(1)
|
syscall.setuid(1)
|
||||||
local status, err = pcall(startupFunc)
|
local status, err = pcall(startupFunc)
|
||||||
if not status then
|
if not status then
|
||||||
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR")
|
kernel.log("Error executing startup script '" .. filepath .. "': " .. err, "ERROR", 0xFF0000)
|
||||||
else
|
else
|
||||||
kernel.log("Successfully executed startup script: " .. filepath, "INFO")
|
kernel.log("Successfully executed startup script: " .. filepath)
|
||||||
end
|
end
|
||||||
end, "startup:" .. v)
|
end, "startup:" .. v)
|
||||||
end
|
end
|
||||||
@@ -41,6 +43,6 @@ for i,v in ipairs(files) do
|
|||||||
end
|
end
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
sleep(1)
|
sleep(5)
|
||||||
kernel.saveLog()
|
kernel.saveLog()
|
||||||
end
|
end
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
local fs=require("sys.fs")
|
local fs=require("fs")
|
||||||
local units=fs.list("/usr/lib/hunit/")
|
local units=fs.list("/usr/lib/hunit/")
|
||||||
fs.mkdir("/tmp/hunit/")
|
fs.mkdir("/tmp/hunit/")
|
||||||
local errors={}
|
local errors={}
|
||||||
|
|||||||
Loaded 100 of 109 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user