added seperate input and working on http / sockets
This commit is contained in:
@@ -0,0 +1,201 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local http = {}
|
||||||
|
|
||||||
|
local syscall = syscall
|
||||||
|
|
||||||
|
local function parseUrl(url)
|
||||||
|
local proto, host, path =
|
||||||
|
url:match(
|
||||||
|
"^(https?://)([^/]+)(/.*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
if not proto then
|
||||||
|
proto, host =
|
||||||
|
url:match(
|
||||||
|
"^(https?://)([^/]+)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
path = "/"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not proto then
|
||||||
|
return nil, "EINVAL"
|
||||||
|
end
|
||||||
|
|
||||||
|
return host, path
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buildRequest(req)
|
||||||
|
local host, path =
|
||||||
|
parseUrl(req.url)
|
||||||
|
|
||||||
|
if not host then
|
||||||
|
return nil, path
|
||||||
|
end
|
||||||
|
|
||||||
|
local method =
|
||||||
|
req.method or "GET"
|
||||||
|
|
||||||
|
local body =
|
||||||
|
req.body or ""
|
||||||
|
|
||||||
|
local headers =
|
||||||
|
table.deepcopy(
|
||||||
|
req.headers or {}
|
||||||
|
)
|
||||||
|
|
||||||
|
headers.Host =
|
||||||
|
headers.Host or host
|
||||||
|
|
||||||
|
headers.Connection =
|
||||||
|
headers.Connection or "close"
|
||||||
|
|
||||||
|
if body ~= "" then
|
||||||
|
headers["Content-Length"] =
|
||||||
|
tostring(#body)
|
||||||
|
end
|
||||||
|
|
||||||
|
local out = {
|
||||||
|
method ..
|
||||||
|
" " ..
|
||||||
|
path ..
|
||||||
|
" HTTP/1.1"
|
||||||
|
}
|
||||||
|
|
||||||
|
for k, v in pairs(headers) do
|
||||||
|
out[#out + 1] =
|
||||||
|
tostring(k) ..
|
||||||
|
": " ..
|
||||||
|
tostring(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] = ""
|
||||||
|
out[#out + 1] = body
|
||||||
|
|
||||||
|
return table.concat(out, "\r\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
local function parseResponse(raw)
|
||||||
|
local headerEnd =
|
||||||
|
raw:find(
|
||||||
|
"\r\n\r\n",
|
||||||
|
1,
|
||||||
|
true
|
||||||
|
)
|
||||||
|
|
||||||
|
if not headerEnd then
|
||||||
|
return nil, "EBADMSG"
|
||||||
|
end
|
||||||
|
|
||||||
|
local headerPart =
|
||||||
|
raw:sub(1, headerEnd - 1)
|
||||||
|
|
||||||
|
local body =
|
||||||
|
raw:sub(headerEnd + 4)
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
|
||||||
|
for line in headerPart:gmatch("[^\r\n]+") do
|
||||||
|
lines[#lines + 1] = line
|
||||||
|
end
|
||||||
|
|
||||||
|
local _, code, msg =
|
||||||
|
lines[1]:match(
|
||||||
|
"^(HTTP/%S+)%s+(%d+)%s*(.*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
local headers = {}
|
||||||
|
|
||||||
|
for i = 2, #lines do
|
||||||
|
local k, v =
|
||||||
|
lines[i]:match(
|
||||||
|
"^([^:]+):%s*(.*)$"
|
||||||
|
)
|
||||||
|
|
||||||
|
if k then
|
||||||
|
headers[k:lower()] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return {
|
||||||
|
code = tonumber(code),
|
||||||
|
message = msg,
|
||||||
|
headers = headers,
|
||||||
|
body = body
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
local function readAll(fd)
|
||||||
|
local out = ""
|
||||||
|
|
||||||
|
while true do
|
||||||
|
local chunk =
|
||||||
|
syscall.read(fd, 4096)
|
||||||
|
|
||||||
|
if not chunk or chunk == "" then
|
||||||
|
break
|
||||||
|
end
|
||||||
|
|
||||||
|
out = out .. chunk
|
||||||
|
end
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.request(req)
|
||||||
|
local raw, err =
|
||||||
|
buildRequest(req)
|
||||||
|
|
||||||
|
if not raw then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local fd =
|
||||||
|
syscall.socket(0, 0)
|
||||||
|
|
||||||
|
if not fd then
|
||||||
|
return nil, "ESOCKET"
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok, err =
|
||||||
|
syscall.connect(fd, req.url)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
syscall.close(fd)
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok2, err2 =
|
||||||
|
syscall.write(fd, raw)
|
||||||
|
|
||||||
|
if not ok2 then
|
||||||
|
syscall.close(fd)
|
||||||
|
return nil, err2
|
||||||
|
end
|
||||||
|
|
||||||
|
local resp =
|
||||||
|
readAll(fd)
|
||||||
|
|
||||||
|
syscall.close(fd)
|
||||||
|
|
||||||
|
return parseResponse(resp)
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.get(url, headers)
|
||||||
|
return http.request({
|
||||||
|
url = url,
|
||||||
|
method = "GET",
|
||||||
|
headers = headers
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function http.post(url, body, headers)
|
||||||
|
return http.request({
|
||||||
|
url = url,
|
||||||
|
method = "POST",
|
||||||
|
body = body,
|
||||||
|
headers = headers
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
return http
|
||||||
@@ -1 +1,306 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
|
||||||
|
local handler = {}
|
||||||
|
|
||||||
|
local http = kernel.apis.http
|
||||||
|
|
||||||
|
kernel.cct.httpqueue = kernel.cct.httpqueue or {}
|
||||||
|
kernel.cct.httpresponse = kernel.cct.httpresponse or {}
|
||||||
|
kernel.cct.httperror = kernel.cct.httperror or {}
|
||||||
|
|
||||||
|
local function parseRawRequest(raw)
|
||||||
|
local sepLen = 4
|
||||||
|
|
||||||
|
local headerEnd =
|
||||||
|
raw:find("\r\n\r\n", 1, true)
|
||||||
|
|
||||||
|
if not headerEnd then
|
||||||
|
headerEnd =
|
||||||
|
raw:find("\n\n", 1, true)
|
||||||
|
|
||||||
|
sepLen = 2
|
||||||
|
end
|
||||||
|
|
||||||
|
local headerPart
|
||||||
|
local body = ""
|
||||||
|
|
||||||
|
if headerEnd then
|
||||||
|
headerPart = raw:sub(1, headerEnd - 1)
|
||||||
|
body = raw:sub(headerEnd + sepLen)
|
||||||
|
else
|
||||||
|
headerPart = raw
|
||||||
|
end
|
||||||
|
|
||||||
|
local lines = {}
|
||||||
|
|
||||||
|
for line in headerPart:gmatch("[^\r\n]+") do
|
||||||
|
lines[#lines + 1] = line
|
||||||
|
end
|
||||||
|
|
||||||
|
if #lines == 0 then
|
||||||
|
return nil, "EINVAL"
|
||||||
|
end
|
||||||
|
|
||||||
|
local method, path =
|
||||||
|
lines[1]:match("^(%S+)%s+(%S+)")
|
||||||
|
|
||||||
|
if not method or not path then
|
||||||
|
return nil, "EBADMSG"
|
||||||
|
end
|
||||||
|
|
||||||
|
local headers = {}
|
||||||
|
|
||||||
|
for i = 2, #lines do
|
||||||
|
local k, v =
|
||||||
|
lines[i]:match("^([^:]+):%s*(.*)$")
|
||||||
|
|
||||||
|
if k then
|
||||||
|
headers[k] = v
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local host = headers.Host or headers.host
|
||||||
|
|
||||||
|
if not host and not path:match("^https?://") then
|
||||||
|
return nil, "EHOSTUNREACH"
|
||||||
|
end
|
||||||
|
|
||||||
|
local url
|
||||||
|
|
||||||
|
if path:match("^https?://") then
|
||||||
|
url = path
|
||||||
|
else
|
||||||
|
url = "http://" .. host .. path
|
||||||
|
end
|
||||||
|
|
||||||
|
local req = {
|
||||||
|
url = url,
|
||||||
|
method = method,
|
||||||
|
headers = headers
|
||||||
|
}
|
||||||
|
|
||||||
|
if body ~= "" then
|
||||||
|
req.body = body
|
||||||
|
end
|
||||||
|
|
||||||
|
return req
|
||||||
|
end
|
||||||
|
|
||||||
|
local function buildResponse(resp)
|
||||||
|
if not resp then
|
||||||
|
return nil, "EINVAL"
|
||||||
|
end
|
||||||
|
|
||||||
|
local code, msg = resp.getResponseCode()
|
||||||
|
|
||||||
|
local headers =
|
||||||
|
resp:getResponseHeaders()
|
||||||
|
|
||||||
|
local body =
|
||||||
|
resp:readAll() or ""
|
||||||
|
|
||||||
|
local out = {
|
||||||
|
"HTTP/1.1 " ..
|
||||||
|
tostring(code) ..
|
||||||
|
" " ..
|
||||||
|
tostring(msg)
|
||||||
|
}
|
||||||
|
|
||||||
|
local hasLength = false
|
||||||
|
|
||||||
|
for k, v in pairs(headers or {}) do
|
||||||
|
if k:lower() == "content-length" then
|
||||||
|
hasLength = true
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] =
|
||||||
|
tostring(k) ..
|
||||||
|
": " ..
|
||||||
|
tostring(v)
|
||||||
|
end
|
||||||
|
|
||||||
|
if not hasLength then
|
||||||
|
out[#out + 1] =
|
||||||
|
"Content-Length: " ..
|
||||||
|
tostring(#body)
|
||||||
|
end
|
||||||
|
|
||||||
|
out[#out + 1] = ""
|
||||||
|
out[#out + 1] = body
|
||||||
|
|
||||||
|
return table.concat(out, "\r\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
function handler.connect(fd, address)
|
||||||
|
local fdo = kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
if not fdo then
|
||||||
|
return nil, "EBADF"
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.socket.rbuf = ""
|
||||||
|
fdo.socket.closed = false
|
||||||
|
fdo.socket.httpid = nil
|
||||||
|
|
||||||
|
fdo.handle.write = function(raw)
|
||||||
|
local req, err =
|
||||||
|
parseRawRequest(raw)
|
||||||
|
|
||||||
|
if not req then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
local id =
|
||||||
|
tostring(kernel.uuid())
|
||||||
|
|
||||||
|
fdo.socket.httpid = id
|
||||||
|
|
||||||
|
kernel.cct.httpqueue[id] = true
|
||||||
|
|
||||||
|
local ok, err =
|
||||||
|
http.request(req, id)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.handle.read = function(count)
|
||||||
|
count = count or 4096
|
||||||
|
|
||||||
|
local sock = fdo.socket
|
||||||
|
|
||||||
|
if #sock.rbuf > 0 then
|
||||||
|
local out =
|
||||||
|
sock.rbuf:sub(1, count)
|
||||||
|
|
||||||
|
sock.rbuf =
|
||||||
|
sock.rbuf:sub(count + 1)
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
local id = sock.httpid
|
||||||
|
|
||||||
|
if not id then
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
local function finish(resp)
|
||||||
|
sock.rbuf =
|
||||||
|
buildResponse(resp) or ""
|
||||||
|
|
||||||
|
local out =
|
||||||
|
sock.rbuf:sub(1, count)
|
||||||
|
|
||||||
|
sock.rbuf =
|
||||||
|
sock.rbuf:sub(count + 1)
|
||||||
|
|
||||||
|
return out
|
||||||
|
end
|
||||||
|
|
||||||
|
if kernel.cct.httpresponse[id] then
|
||||||
|
local resp =
|
||||||
|
kernel.cct.httpresponse[id]
|
||||||
|
|
||||||
|
kernel.cct.httpresponse[id] = nil
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
|
||||||
|
return finish(resp)
|
||||||
|
end
|
||||||
|
|
||||||
|
if kernel.cct.httperror[id] then
|
||||||
|
local err =
|
||||||
|
kernel.cct.httperror[id]
|
||||||
|
|
||||||
|
kernel.cct.httperror[id] = nil
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.currentTask.status = "D"
|
||||||
|
|
||||||
|
local coro
|
||||||
|
|
||||||
|
coro = function()
|
||||||
|
if kernel.cct.httpresponse[id] then
|
||||||
|
local resp =
|
||||||
|
kernel.cct.httpresponse[id]
|
||||||
|
|
||||||
|
kernel.cct.httpresponse[id] = nil
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
|
||||||
|
kernel.asyncReturn(
|
||||||
|
finish(resp)
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
if kernel.cct.httperror[id] then
|
||||||
|
local err =
|
||||||
|
kernel.cct.httperror[id]
|
||||||
|
|
||||||
|
kernel.cct.httperror[id] = nil
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
|
||||||
|
kernel.asyncReturn(
|
||||||
|
nil,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.currentTask.ksh =
|
||||||
|
coroutine.create(function()
|
||||||
|
local ok, err =
|
||||||
|
xpcall(
|
||||||
|
coro,
|
||||||
|
debug.traceback
|
||||||
|
)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
kernel.asyncReturn(
|
||||||
|
nil,
|
||||||
|
err
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.handle.close = function()
|
||||||
|
fdo.socket.closed = true
|
||||||
|
|
||||||
|
local id =
|
||||||
|
fdo.socket.httpid
|
||||||
|
|
||||||
|
if id then
|
||||||
|
kernel.cct.httpqueue[id] = nil
|
||||||
|
kernel.cct.httpresponse[id] = nil
|
||||||
|
kernel.cct.httperror[id] = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.socket.registerProtocal(
|
||||||
|
"http://",
|
||||||
|
handler
|
||||||
|
)
|
||||||
|
|
||||||
|
kernel.socket.registerProtocal(
|
||||||
|
"https://",
|
||||||
|
handler
|
||||||
|
)
|
||||||
@@ -223,6 +223,9 @@ local function newtty(obj, id, ev)
|
|||||||
gctrl=function()
|
gctrl=function()
|
||||||
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
return serializeBool(kernel.cct.ctrl)..";"..serializeBool(kernel.cct.alt)
|
||||||
end,
|
end,
|
||||||
|
isvirt=function()
|
||||||
|
return false
|
||||||
|
end,
|
||||||
gplt=function()
|
gplt=function()
|
||||||
return plt
|
return plt
|
||||||
end
|
end
|
||||||
@@ -243,8 +246,39 @@ end
|
|||||||
local fifo = kernel.newFifo()
|
local fifo = kernel.newFifo()
|
||||||
kernel.cct.fifo=fifo
|
kernel.cct.fifo=fifo
|
||||||
|
|
||||||
newtty(kernel.apis.term, "1", fifo.pop)
|
newtty(kernel.apis.term, "1", function() end)
|
||||||
|
|
||||||
for i,v in ipairs({peripheral.find("monitor")}) do
|
for i,v in ipairs({peripheral.find("monitor")}) do
|
||||||
newtty(v,tostring(i+1),function () end)
|
newtty(v,tostring(i+1),function () end)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.devfs.data["input"]["keyboard1"] = function(op, mode)
|
||||||
|
if op=="type" then
|
||||||
|
return "Keyboard"
|
||||||
|
elseif op=="open" then
|
||||||
|
local h = {
|
||||||
|
read=function(amount)
|
||||||
|
local rv=""
|
||||||
|
for i=1, amount or 1 do
|
||||||
|
local event = {fifo.pop()}
|
||||||
|
if event[1] then
|
||||||
|
rv=rv..event[1]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if rv=="" then rv=nil end
|
||||||
|
return rv
|
||||||
|
end,
|
||||||
|
write=function(content)
|
||||||
|
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
|
||||||
@@ -4,6 +4,7 @@ local keys=kernel.apis.keys
|
|||||||
|
|
||||||
kernel.processes.cctdeamon = function()
|
kernel.processes.cctdeamon = function()
|
||||||
local timeout = false
|
local timeout = false
|
||||||
|
kernel.log("CCT deamon started")
|
||||||
while true do
|
while true do
|
||||||
local event = {kernel.EFI:getMachineEvent()}
|
local event = {kernel.EFI:getMachineEvent()}
|
||||||
|
|
||||||
@@ -66,6 +67,12 @@ kernel.processes.cctdeamon = function()
|
|||||||
|
|
||||||
elseif eventType == "keyTyped" then
|
elseif eventType == "keyTyped" then
|
||||||
if charOrKey then kernel.cct.fifo.push(charOrKey) end
|
if charOrKey then kernel.cct.fifo.push(charOrKey) end
|
||||||
|
elseif eventType == "mouse_scroll" then
|
||||||
|
if event[2] == 1 then
|
||||||
|
kernel.cct.fifo.push("[nS")
|
||||||
|
else
|
||||||
|
kernel.cct.fifo.push("[nT")
|
||||||
|
end
|
||||||
elseif eventType == "http_success" then
|
elseif eventType == "http_success" then
|
||||||
kernel.cct.httpqueue[event[2]]=nil
|
kernel.cct.httpqueue[event[2]]=nil
|
||||||
kernel.cct.httpresponse[event[2]]=event[3]
|
kernel.cct.httpresponse[event[2]]=event[3]
|
||||||
@@ -84,3 +91,5 @@ kernel.processes.cctdeamon = function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
kernel.log("CCT deamon queued for execution")
|
||||||
@@ -19,26 +19,34 @@ kernel.status = "start"
|
|||||||
kernel.key = {}
|
kernel.key = {}
|
||||||
kernel.cache = {}
|
kernel.cache = {}
|
||||||
kernel.cache.preload = {}
|
kernel.cache.preload = {}
|
||||||
|
kernel.unixSockets={}
|
||||||
kernel._G=_G
|
kernel._G=_G
|
||||||
kernel.sleep=sleep
|
kernel.sleep=sleep
|
||||||
|
|
||||||
_G.sleep=nil
|
_G.sleep=nil
|
||||||
local windowsExp = true
|
local windowsExp = false
|
||||||
|
|
||||||
function kernel.log(msg, level, c)
|
function kernel.log(msg, level, c, nopanic)
|
||||||
c=c or 0x6D6D6D
|
local f=function()
|
||||||
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
c=c or 0x6D6D6D
|
||||||
if kernel.status == "start" then
|
kernel.LOG_Text = kernel.LOG_Text..tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n"
|
||||||
screen:setTextColor(c)
|
if kernel.status == "start" then
|
||||||
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
screen:setTextColor(c)
|
||||||
elseif kernel.status == "term" then
|
screen:print(tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg)
|
||||||
kernel.standbyTask=kernel.currentTask
|
elseif kernel.status == "term" then
|
||||||
kernel.currentTask=kernel.kernelTask
|
kernel.standbyTask=kernel.currentTask
|
||||||
local file=kernel.vfs.open("/dev/console", "w")
|
kernel.currentTask=kernel.kernelTask
|
||||||
kernel.vfs.devctl(file,"sfgc",c)
|
local file=kernel.vfs.open("/dev/console", "w")
|
||||||
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
kernel.vfs.devctl(file,"sfgc",c)
|
||||||
kernel.vfs.close(file)
|
kernel.vfs.write(file,tostring(EFI:date()).." "..kernel.users[kernel.uid].." "..kernel.process.."["..tostring(level or "INFO").."]: "..msg.."\n")
|
||||||
kernel.currentTask=kernel.standbyTask
|
kernel.vfs.close(file)
|
||||||
|
kernel.currentTask=kernel.standbyTask
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local ok,err = xpcall(f,debug.traceback)
|
||||||
|
if not ok and not nopanic then
|
||||||
|
kernel.panic(err)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -246,6 +254,15 @@ function kernel.reboot()
|
|||||||
kernel.status="reboot"
|
kernel.status="reboot"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function kernel.halt()
|
||||||
|
kernel.exitMain=true
|
||||||
|
kernel.status="halt"
|
||||||
|
end
|
||||||
|
|
||||||
|
function kernel.asyncReturn(...)
|
||||||
|
kernel.currentTask.syscallReturn = {...}
|
||||||
|
end
|
||||||
|
|
||||||
kernel.syscalls["time"]=function() return kernel.EFI:getEpochMs() end
|
kernel.syscalls["time"]=function() return kernel.EFI:getEpochMs() end
|
||||||
kernel.syscalls["date"]=function() return kernel.EFI:date() end
|
kernel.syscalls["date"]=function() return kernel.EFI:date() end
|
||||||
kernel.syscalls["log"]=kernel.log
|
kernel.syscalls["log"]=kernel.log
|
||||||
@@ -264,8 +281,21 @@ kernel.syscalls["sysdump"]=function()
|
|||||||
end
|
end
|
||||||
return rv
|
return rv
|
||||||
end
|
end
|
||||||
kernel.syscalls["reboot"]=kernel.reboot
|
kernel.syscalls["reboot"]=function()
|
||||||
kernel.syscalls["shutdown"]=kernel.shutdown
|
if kernel.uid==0 or kernel.groups.wheel then
|
||||||
|
kernel.reboot()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
kernel.syscalls["shutdown"]=function()
|
||||||
|
if kernel.uid==0 or kernel.groups.wheel then
|
||||||
|
kernel.shutdown()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
kernel.syscalls["halt"]=function()
|
||||||
|
if kernel.uid==0 or kernel.groups.wheel then
|
||||||
|
kernel.halt()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
kernel.log("Running modules")
|
kernel.log("Running modules")
|
||||||
for _,p in ipairs(modules) do
|
for _,p in ipairs(modules) do
|
||||||
@@ -287,11 +317,18 @@ kernel.log("Kernel initialized successfully.")
|
|||||||
kernel.saveLog()
|
kernel.saveLog()
|
||||||
kernel.status="running"
|
kernel.status="running"
|
||||||
screen:disable()
|
screen:disable()
|
||||||
kernel.main()
|
local ok,err = xpcall(kernel.main, debug.traceback)
|
||||||
|
if not ok then
|
||||||
|
kernel.panic(err)
|
||||||
|
end
|
||||||
if kernel.status=="panic" then
|
if kernel.status=="panic" then
|
||||||
kernel.panic(kernel.reason)
|
kernel.panic(kernel.reason)
|
||||||
end
|
end
|
||||||
if kernel.status=="reboot" then
|
if kernel.status=="reboot" then
|
||||||
EFI.reboot=true
|
EFI.reboot=true
|
||||||
return true
|
return true
|
||||||
|
elseif kernel.status=="halt" then
|
||||||
|
kernel.log("System halted.")
|
||||||
|
kernel.saveLog()
|
||||||
|
while true do end
|
||||||
end
|
end
|
||||||
@@ -7,5 +7,5 @@ return {
|
|||||||
initPath = "/sbin/init",
|
initPath = "/sbin/init",
|
||||||
maxOpenFiles = 128,
|
maxOpenFiles = 128,
|
||||||
maxFilesPerTask = 16,
|
maxFilesPerTask = 16,
|
||||||
preempt=true
|
preempt = true,
|
||||||
}
|
}
|
||||||
@@ -229,6 +229,23 @@ function toHex(num)
|
|||||||
return string.format("%X", num)
|
return string.format("%X", num)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local st={
|
||||||
|
push=function(self,...) table.insert(self.contents,{...}) end,
|
||||||
|
pop=function(self) return table.unpack(table.remove(self.contents)) end,
|
||||||
|
}
|
||||||
|
local q={
|
||||||
|
push=function(self,...) table.insert(self.contents,{...}) end,
|
||||||
|
pop=function(self) return table.unpack(table.remove(self.contents,1)) end,
|
||||||
|
}
|
||||||
|
|
||||||
|
function stack()
|
||||||
|
return setmetatable({contents={}}, {__index=st})
|
||||||
|
end
|
||||||
|
|
||||||
|
function queue()
|
||||||
|
return setmetatable({contents={}}, {__index=q})
|
||||||
|
end
|
||||||
|
|
||||||
local function makeSyscallProxy()
|
local function makeSyscallProxy()
|
||||||
local backing = {}
|
local backing = {}
|
||||||
return setmetatable(backing, {
|
return setmetatable(backing, {
|
||||||
|
|||||||
@@ -542,6 +542,7 @@ local function allocFD(task)
|
|||||||
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
if fd >= kernel.config.maxFilesPerTask then error("ENFILE") end
|
||||||
return fd
|
return fd
|
||||||
end
|
end
|
||||||
|
|
||||||
local function checkSystemLimit()
|
local function checkSystemLimit()
|
||||||
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
if total >= kernel.config.maxOpenFiles - 16 then error("ENFILE") end
|
||||||
end
|
end
|
||||||
@@ -555,27 +556,88 @@ function vfs.newfd(fdobj)
|
|||||||
return fd
|
return fd
|
||||||
end
|
end
|
||||||
|
|
||||||
function vfs.mount(target, diskOrId)
|
function vfs.mount(target, diskOrId, bind)
|
||||||
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
local _euid = (kernel.currentTask and (kernel.currentTask.euid or kernel.currentTask.uid)) or kernel.uid
|
||||||
if _euid ~= 0 then error("EPERM") end
|
if _euid ~= 0 then error("EPERM") end
|
||||||
if not target then error("EINVAL") end
|
if not target then error("EINVAL") end
|
||||||
target = normalizeMountPoint(target)
|
target = normalizeMountPoint(target)
|
||||||
local drive, path = resolvePath(target)
|
local drive, path = resolvePath(target)
|
||||||
if not drive:directoryExists(path) then drive:makeDirectory(path) end
|
if not drive:directoryExists(path) then
|
||||||
if drive:type(target) ~= "directory" then error("EINVAL") end
|
drive:makeDirectory(path)
|
||||||
|
end
|
||||||
|
if drive:type(path) ~= "directory" then
|
||||||
|
error("EINVAL")
|
||||||
|
end
|
||||||
local disk, id
|
local disk, id
|
||||||
if type(diskOrId) == "string" then
|
-- bind mount
|
||||||
disk = kernel.disks[diskOrId]
|
if bind then
|
||||||
if not disk then error("ENODEV") end
|
local src = normalizeMountPoint(diskOrId)
|
||||||
checkDisk(disk); id = diskOrId
|
local srcDrive = resolvePath(src)
|
||||||
elseif type(diskOrId) == "table" then
|
if not srcDrive then error("ENOENT") end
|
||||||
checkDisk(diskOrId); disk = diskOrId
|
id = "bind:" .. src
|
||||||
id = disk.address; vfs.disks[id] = disk
|
disk = {
|
||||||
else error("EINVAL") end
|
address = id,
|
||||||
|
isBind = true,
|
||||||
|
source = srcDrive,
|
||||||
|
exists = function(_, p)
|
||||||
|
return srcDrive:exists(p)
|
||||||
|
end,
|
||||||
|
type = function(_, p)
|
||||||
|
return srcDrive:type(p)
|
||||||
|
end,
|
||||||
|
list = function(_, p)
|
||||||
|
return srcDrive:list(p)
|
||||||
|
end,
|
||||||
|
open = function(_, ...)
|
||||||
|
return srcDrive:open(...)
|
||||||
|
end,
|
||||||
|
remove = function(_, p)
|
||||||
|
return srcDrive:remove(p)
|
||||||
|
end,
|
||||||
|
makeDirectory = function(_, p)
|
||||||
|
return srcDrive:makeDirectory(p)
|
||||||
|
end,
|
||||||
|
rename = function(_, a, b)
|
||||||
|
return srcDrive:rename(a, b)
|
||||||
|
end,
|
||||||
|
size = function(_, p)
|
||||||
|
return srcDrive:size(p)
|
||||||
|
end,
|
||||||
|
lastModified = function(_, p)
|
||||||
|
return srcDrive:lastModified(p)
|
||||||
|
end,
|
||||||
|
isReadOnly = function()
|
||||||
|
return srcDrive:isReadOnly()
|
||||||
|
end,
|
||||||
|
spaceTotal = function()
|
||||||
|
return srcDrive:spaceTotal()
|
||||||
|
end,
|
||||||
|
spaceUsed = function()
|
||||||
|
return srcDrive:spaceUsed()
|
||||||
|
end
|
||||||
|
}
|
||||||
|
vfs.disks[id] = disk
|
||||||
|
else
|
||||||
|
if type(diskOrId) == "string" then
|
||||||
|
disk = vfs.disks[diskOrId]
|
||||||
|
if not disk then error("ENODEV") end
|
||||||
|
checkDisk(disk)
|
||||||
|
id = diskOrId
|
||||||
|
elseif type(diskOrId) == "table" then
|
||||||
|
checkDisk(diskOrId)
|
||||||
|
disk = diskOrId
|
||||||
|
id = disk.address
|
||||||
|
vfs.disks[id] = disk
|
||||||
|
else
|
||||||
|
error("EINVAL")
|
||||||
|
end
|
||||||
|
end
|
||||||
if vfs.mounts[id] then error("EBUSY") end
|
if vfs.mounts[id] then error("EBUSY") end
|
||||||
for _, mp in pairs(vfs.mounts) do if mp == target then error("EBUSY") end end
|
for _, mp in pairs(vfs.mounts) do
|
||||||
|
if mp == target then
|
||||||
|
error("EBUSY")
|
||||||
|
end
|
||||||
|
end
|
||||||
vfs.mounts[id] = target
|
vfs.mounts[id] = target
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -588,7 +650,11 @@ function vfs.umount(target)
|
|||||||
for id, mp in pairs(vfs.mounts) do
|
for id, mp in pairs(vfs.mounts) do
|
||||||
if mp == target then
|
if mp == target then
|
||||||
if id == "$" then error("EBUSY") end
|
if id == "$" then error("EBUSY") end
|
||||||
vfs.mounts[id] = nil; return true
|
vfs.mounts[id] = nil
|
||||||
|
if vfs.disks[id] and vfs.disks[id].isBind then
|
||||||
|
vfs.disks[id] = nil
|
||||||
|
end
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
error("EINVAL")
|
error("EINVAL")
|
||||||
|
|||||||
63
Src/Hyperion-kernel/data/lib/modules/hyperion/11_ld.kmod
Normal file
63
Src/Hyperion-kernel/data/lib/modules/hyperion/11_ld.kmod
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
local cache = {}
|
||||||
|
kernel.searchpaths = {
|
||||||
|
"?", "?.lua", "/lib/?", "/lib/?.lua", "/usr/lib/?", "/usr/lib/?.lua",
|
||||||
|
"/usr/local/lib/?", "/usr/local/lib/?.lua"
|
||||||
|
}
|
||||||
|
kernel.reqcache = cache
|
||||||
|
|
||||||
|
local function require(module, ...)
|
||||||
|
if cache[module] then return cache[module].ret end
|
||||||
|
kernel.currentTask.status = "D"
|
||||||
|
local args = {...}
|
||||||
|
kernel.currentTask.ksh = coroutine.create(function()
|
||||||
|
local coro = function()
|
||||||
|
for _, path in ipairs(kernel.searchpaths) do
|
||||||
|
local filepath = path:gsub("?", module)
|
||||||
|
if kernel.vfs.exists(filepath) then
|
||||||
|
if kernel.vfs.type(filepath) == "directory" then
|
||||||
|
filepath = filepath .. "/init.lua"
|
||||||
|
if kernel.vfs.type(filepath) == "directory" then
|
||||||
|
kernel.asyncReturn(false, "Module not found: "..module)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local fd = kernel.vfs.open(filepath, "r")
|
||||||
|
local chunks = {}
|
||||||
|
while true do
|
||||||
|
local chunk = kernel.vfs.read(fd, 4096)
|
||||||
|
if not chunk or chunk == "" then break end
|
||||||
|
chunks[#chunks + 1] = chunk
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
kernel.vfs.close(fd)
|
||||||
|
local data = table.concat(chunks)
|
||||||
|
local func, err = load(data, "@"..module, "t", kernel._U)
|
||||||
|
if not func then
|
||||||
|
kernel.asyncReturn(false, "Error loading module "..module..": "..tostring(err))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local ok, ret = xpcall(func, debug.traceback, table.unpack(args))
|
||||||
|
if not ok then
|
||||||
|
kernel.asyncReturn(false, "Error running module "..module..": "..tostring(ret))
|
||||||
|
return
|
||||||
|
end
|
||||||
|
cache[module] = {ret = ret, expires = kernel.EFI:getEpochMs() + 120000}
|
||||||
|
kernel.asyncReturn(true, ret)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
coroutine.yield()
|
||||||
|
end
|
||||||
|
kernel.asyncReturn(false, "Module not found: "..module)
|
||||||
|
end
|
||||||
|
local status, err = xpcall(coro, debug.traceback)
|
||||||
|
if not status then
|
||||||
|
kernel.asyncReturn(false, "Error in require coroutine for module "..module..": "..tostring(err))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.syscalls["require"] = require
|
||||||
|
_G.require = function(...) return syscall.require(...) end
|
||||||
@@ -1,40 +0,0 @@
|
|||||||
--:Minify:--
|
|
||||||
local kernel = ...
|
|
||||||
local cache = {}
|
|
||||||
kernel.searchpaths = {
|
|
||||||
"/lib/?.lua", "/lib/?", "/usr/lib/?.lua", "/usr/lib/?",
|
|
||||||
"/usr/local/lib/?.lua", "/usr/local/lib/?", "?.lua", "?"
|
|
||||||
}
|
|
||||||
|
|
||||||
function require(module, ...)
|
|
||||||
if cache[module] then return cache[module] end
|
|
||||||
local modpath = module:gsub("%.", "/")
|
|
||||||
local failed = {}
|
|
||||||
for _, path in ipairs(kernel.searchpaths) do
|
|
||||||
local full_path = string.replace(path, "?", modpath)
|
|
||||||
if full_path:sub(1, 1) ~= "/" then
|
|
||||||
full_path = kernel.currentTask.cwd .. full_path
|
|
||||||
end
|
|
||||||
|
|
||||||
if kernel.vfs.exists(full_path) then
|
|
||||||
if kernel.vfs.type(full_path) == "directory" then
|
|
||||||
full_path = full_path .. "/init"
|
|
||||||
end
|
|
||||||
|
|
||||||
if kernel.vfs.exists(full_path) then
|
|
||||||
local handle = kernel.vfs.open(full_path, "r")
|
|
||||||
local file_content = kernel.vfs.read(handle, 1024 * 1024 * 4)
|
|
||||||
kernel.vfs.close(handle)
|
|
||||||
|
|
||||||
return
|
|
||||||
assert(load(file_content, full_path, "t", kernel._U))(...)
|
|
||||||
else
|
|
||||||
table.insert(failed, full_path)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
table.insert(failed, full_path)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
error("Module not found: " .. module .. " (searched paths: " .. table.concat(failed, ", ") .. ")")
|
|
||||||
end
|
|
||||||
@@ -140,6 +140,83 @@ function data.zero(op, mode)
|
|||||||
end
|
end
|
||||||
end
|
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 "file"
|
||||||
|
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
|
||||||
|
|
||||||
|
data[".meta"]=strFile(buildMeta({
|
||||||
|
stdin="/proc/self/fd/0",
|
||||||
|
stdout="/proc/self/fd/1",
|
||||||
|
log="/var/log/syslog.log"
|
||||||
|
}))
|
||||||
|
|
||||||
if kernel.EFI:getEEPROM() then
|
if kernel.EFI:getEEPROM() then
|
||||||
function data.eeprom(op, mode)
|
function data.eeprom(op, mode)
|
||||||
if op=="type" then
|
if op=="type" then
|
||||||
@@ -216,7 +293,8 @@ if kernel.EFI:getNvram() then
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
data["disk"]={}
|
data["disk"]={["by-id"]={}, ["by-path"]={}, ["by-label"]={}}
|
||||||
|
data["input"]={}
|
||||||
kernel.devfs={}
|
kernel.devfs={}
|
||||||
kernel.devfs.data=data
|
kernel.devfs.data=data
|
||||||
kernel.devfs.proxy=proxy
|
kernel.devfs.proxy=proxy
|
||||||
|
|||||||
@@ -114,7 +114,8 @@ local function newtaskproxy(task)
|
|||||||
},
|
},
|
||||||
children={
|
children={
|
||||||
[".meta"]=strFile(buildMeta(children))
|
[".meta"]=strFile(buildMeta(children))
|
||||||
}
|
},
|
||||||
|
pid=strFile(task.pid)
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,134 +1,141 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
local kernel = ...
|
local kernel = ...
|
||||||
|
|
||||||
local proxy = {}
|
kernel.vfs.remove("/tmp")
|
||||||
local data = {}
|
kernel.vfs.mkdir("/tmp")
|
||||||
|
if not kernel.config.tmpToDisk then
|
||||||
|
local proxy = {}
|
||||||
|
local data = {}
|
||||||
|
|
||||||
proxy.address = "tmpfs0000"
|
proxy.address = "tmpfs0000"
|
||||||
proxy.isvirt = true
|
proxy.isvirt = true
|
||||||
proxy.isReadOnly = function() return false end
|
proxy.isReadOnly = function() return false end
|
||||||
|
|
||||||
proxy.spaceUsed = function() return 0 end
|
proxy.spaceUsed = function() return 0 end
|
||||||
proxy.spaceTotal = function() return 0 end
|
proxy.spaceTotal = function() return 0 end
|
||||||
|
|
||||||
proxy.makeDirectory = function(_, path)
|
proxy.makeDirectory = function(_, path)
|
||||||
local steps = kernel.vfs.splitPath(path)
|
local steps = kernel.vfs.splitPath(path)
|
||||||
local step = data
|
local step = data
|
||||||
for i=1,#steps do
|
for i=1,#steps do
|
||||||
if not step[steps[i]] then
|
if not step[steps[i]] then
|
||||||
step[steps[i]] = {}
|
step[steps[i]] = {}
|
||||||
elseif type(step[steps[i]]) ~= "table" then
|
elseif type(step[steps[i]]) ~= "table" then
|
||||||
error("ENOTDIR")
|
error("ENOTDIR")
|
||||||
|
end
|
||||||
|
step = step[steps[i]]
|
||||||
end
|
end
|
||||||
step = step[steps[i]]
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
proxy.remove = function(_, path)
|
proxy.remove = function(_, path)
|
||||||
local steps = kernel.vfs.splitPath(path)
|
local steps = kernel.vfs.splitPath(path)
|
||||||
local step = data
|
local step = data
|
||||||
for i=1,#steps-1 do
|
for i=1,#steps-1 do
|
||||||
step = step[steps[i]]
|
step = step[steps[i]]
|
||||||
if not step then error("ENOENT") end
|
if not step then error("ENOENT") end
|
||||||
end
|
|
||||||
step[steps[#steps]] = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
proxy.setLabel = function(_, label) end
|
|
||||||
proxy.getLabel = function() return "tmpfs" end
|
|
||||||
|
|
||||||
proxy.attributes = function(_, path)
|
|
||||||
local steps = kernel.vfs.splitPath(path)
|
|
||||||
local step = data
|
|
||||||
for i=1,#steps do
|
|
||||||
step = step[steps[i]]
|
|
||||||
if not step then error("ENOENT") end
|
|
||||||
end
|
|
||||||
return {
|
|
||||||
size = type(step) == "string" and #step or 0,
|
|
||||||
modified = 0,
|
|
||||||
created = 0,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy:open(path, mode)
|
|
||||||
local steps = kernel.vfs.splitPath(path)
|
|
||||||
local step = data
|
|
||||||
for i=1,#steps-1 do
|
|
||||||
if not step[steps[i]] then
|
|
||||||
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
|
|
||||||
elseif type(step[steps[i]]) ~= "table" then
|
|
||||||
error("ENOTDIR")
|
|
||||||
end
|
end
|
||||||
step = step[steps[i]]
|
step[steps[#steps]] = nil
|
||||||
end
|
end
|
||||||
local filename = steps[#steps]
|
|
||||||
|
|
||||||
if mode == "r" then
|
proxy.setLabel = function(_, label) end
|
||||||
if type(step[filename]) ~= "string" then error("ENOENT") end
|
proxy.getLabel = function() return "tmpfs" end
|
||||||
local content = step[filename]
|
|
||||||
local pos = 1
|
proxy.attributes = function(_, path)
|
||||||
|
local steps = kernel.vfs.splitPath(path)
|
||||||
|
local step = data
|
||||||
|
for i=1,#steps do
|
||||||
|
step = step[steps[i]]
|
||||||
|
if not step then error("ENOENT") end
|
||||||
|
end
|
||||||
return {
|
return {
|
||||||
read = function(amount)
|
size = type(step) == "string" and #step or 0,
|
||||||
amount = amount or #content
|
modified = 0,
|
||||||
local chunk = content:sub(pos, pos+amount-1)
|
created = 0,
|
||||||
pos = pos + #chunk
|
|
||||||
return chunk
|
|
||||||
end,
|
|
||||||
close = function() end,
|
|
||||||
}
|
}
|
||||||
elseif mode == "w" then
|
|
||||||
step[filename] = ""
|
|
||||||
local buf = {}
|
|
||||||
return {
|
|
||||||
write = function(str)
|
|
||||||
buf[#buf + 1] = str
|
|
||||||
end,
|
|
||||||
close = function()
|
|
||||||
step[filename] = table.concat(buf)
|
|
||||||
end,
|
|
||||||
}
|
|
||||||
elseif mode == "a" then
|
|
||||||
if type(step[filename]) ~= "string" then step[filename] = "" end
|
|
||||||
return {
|
|
||||||
write = function(str)
|
|
||||||
step[filename] = step[filename] .. str
|
|
||||||
end,
|
|
||||||
close = function() end,
|
|
||||||
}
|
|
||||||
else
|
|
||||||
error("EACCES")
|
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
|
||||||
function proxy:type(path)
|
function proxy:open(path, mode)
|
||||||
local steps = kernel.vfs.splitPath(path)
|
local steps = kernel.vfs.splitPath(path)
|
||||||
local step = data
|
local step = data
|
||||||
if #steps == 0 then return "directory" end
|
for i=1,#steps-1 do
|
||||||
for i=1,#steps do
|
if not step[steps[i]] then
|
||||||
step = step[steps[i]]
|
if mode == "w" then step[steps[i]] = {} else error("ENOENT") end
|
||||||
if not step then return false end
|
elseif type(step[steps[i]]) ~= "table" then
|
||||||
|
error("ENOTDIR")
|
||||||
|
end
|
||||||
|
step = step[steps[i]]
|
||||||
|
end
|
||||||
|
local filename = steps[#steps]
|
||||||
|
|
||||||
|
if mode == "r" then
|
||||||
|
if type(step[filename]) ~= "string" then error("ENOENT") end
|
||||||
|
local content = step[filename]
|
||||||
|
local pos = 1
|
||||||
|
return {
|
||||||
|
read = function(amount)
|
||||||
|
amount = amount or #content
|
||||||
|
local chunk = content:sub(pos, pos+amount-1)
|
||||||
|
pos = pos + #chunk
|
||||||
|
return chunk
|
||||||
|
end,
|
||||||
|
close = function() end,
|
||||||
|
}
|
||||||
|
elseif mode == "w" then
|
||||||
|
step[filename] = ""
|
||||||
|
local buf = {}
|
||||||
|
return {
|
||||||
|
write = function(str)
|
||||||
|
buf[#buf + 1] = str
|
||||||
|
end,
|
||||||
|
close = function()
|
||||||
|
step[filename] = table.concat(buf)
|
||||||
|
end,
|
||||||
|
}
|
||||||
|
elseif mode == "a" then
|
||||||
|
if type(step[filename]) ~= "string" then step[filename] = "" end
|
||||||
|
return {
|
||||||
|
write = function(str)
|
||||||
|
step[filename] = step[filename] .. str
|
||||||
|
end,
|
||||||
|
close = function() end,
|
||||||
|
}
|
||||||
|
else
|
||||||
|
error("EACCES")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
if type(step) == "table" then return "directory" end
|
|
||||||
if type(step) == "string" then return "file" end
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy:list(path)
|
function proxy:type(path)
|
||||||
local steps = kernel.vfs.splitPath(path)
|
local steps = kernel.vfs.splitPath(path)
|
||||||
local step = data
|
local step = data
|
||||||
for i=1,#steps do
|
if #steps == 0 then return "directory" end
|
||||||
step = step[steps[i]]
|
for i=1,#steps do
|
||||||
if not step then error("ENOENT") end
|
step = step[steps[i]]
|
||||||
|
if not step then return false end
|
||||||
|
end
|
||||||
|
if type(step) == "table" then return "directory" end
|
||||||
|
if type(step) == "string" then return "file" end
|
||||||
end
|
end
|
||||||
if type(step) ~= "table" then error("ENOTDIR") end
|
|
||||||
local keys = {}
|
|
||||||
for k,_ in pairs(step) do table.insert(keys, k) end
|
|
||||||
return keys
|
|
||||||
end
|
|
||||||
|
|
||||||
function proxy:fileExists(path)
|
function proxy:list(path)
|
||||||
local t = self:type(path)
|
local steps = kernel.vfs.splitPath(path)
|
||||||
return t == "file" or t == "directory"
|
local step = data
|
||||||
end
|
for i=1,#steps do
|
||||||
|
step = step[steps[i]]
|
||||||
|
if not step then error("ENOENT") end
|
||||||
|
end
|
||||||
|
if type(step) ~= "table" then error("ENOTDIR") end
|
||||||
|
local keys = {}
|
||||||
|
for k,_ in pairs(step) do table.insert(keys, k) end
|
||||||
|
return keys
|
||||||
|
end
|
||||||
|
|
||||||
kernel.disks["tmpfs0000"] = proxy
|
function proxy:fileExists(path)
|
||||||
|
local t = self:type(path)
|
||||||
|
return t == "file" or t == "directory"
|
||||||
|
end
|
||||||
|
|
||||||
|
kernel.disks["tmpfs0000"] = proxy
|
||||||
|
else
|
||||||
|
kernel.log("tmpToDisk enabled, skipping tmpfs module")
|
||||||
|
kernel.log("tmpfs0000 will passthrough to /tmp on the disk")
|
||||||
|
end
|
||||||
@@ -25,10 +25,11 @@ for _, line in ipairs(string.split(kernel.fstab, "\n")) do
|
|||||||
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))
|
||||||
kernel.log("Mounted "..id.." to "..path)
|
kernel.log("Mounting '"..id.."' to '"..path.."'")
|
||||||
if id ~= "$" then
|
if id ~= "$" then
|
||||||
kernel.vfs.mount(path, id)
|
kernel.vfs.mount(path, id)
|
||||||
end
|
end
|
||||||
|
kernel.log("Mounted "..id.." to "..path)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -1,67 +1,194 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
-- Supports:
|
local kernel = ...
|
||||||
-- AF_UNIX - local IPC via /var/run/*.sock paths
|
|
||||||
-- AF_INET - network sockets with three backends:
|
|
||||||
-- Implemented by drivers but expect http:// and https://
|
|
||||||
--
|
|
||||||
-- Socket lifecycle:
|
|
||||||
-- fd = syscall.socket(domain, socktype) -- "unix"/"inet", "stream"/"dgram"
|
|
||||||
-- syscall.bind(fd, address) -- server: claim address
|
|
||||||
-- syscall.listen(fd, backlog) -- server: mark as listening
|
|
||||||
-- cfd = syscall.accept(fd) -- server: get connected client fd (blocking poll)
|
|
||||||
-- syscall.connect(fd, address) -- client: connect to server
|
|
||||||
-- syscall.send(fd, data) -- send bytes
|
|
||||||
-- syscall.recv(fd, len) -- receive bytes (blocking poll, returns "" on nothing)
|
|
||||||
-- syscall.sockshutdown(fd) -- half-close send side
|
|
||||||
-- -- normal vfs.close(fd) closes the socket
|
|
||||||
|
|
||||||
local kernel=...
|
local socket = {}
|
||||||
local socket={}
|
|
||||||
socket.handlers={}
|
|
||||||
kernel.socket=socket
|
|
||||||
|
|
||||||
function socket.registerProtocal(protocal, handler)
|
socket.handlers = {}
|
||||||
socket.handlers[protocal] = handler
|
|
||||||
|
kernel.socket = socket
|
||||||
|
|
||||||
|
local P = kernel.vfs.P
|
||||||
|
local sys = kernel.syscalls
|
||||||
|
|
||||||
|
function socket.registerProtocal(proto, handler)
|
||||||
|
socket.handlers[proto] = handler
|
||||||
end
|
end
|
||||||
|
|
||||||
function socket.socket()
|
local function getHandler(address)
|
||||||
local P=kernel.vfs.P
|
for proto, handler in pairs(socket.handlers) do
|
||||||
local data=kernel.newFifo()
|
if string.hasPrefix(address, proto) then
|
||||||
local isClosed=false
|
return handler
|
||||||
return kernel.vfs.newfd({
|
end
|
||||||
handle={
|
end
|
||||||
read=function() if isClosed then error("ECCON") end return data.pop() end,
|
end
|
||||||
write=function(data) if isClosed then error("ECCON") end return data.push(data) end,
|
|
||||||
close=function() isClosed = true end
|
function socket.socket(domain, socktype)
|
||||||
|
local fd = kernel.vfs.newfd({
|
||||||
|
handle = {},
|
||||||
|
|
||||||
|
type = "socket",
|
||||||
|
|
||||||
|
refcount = 1,
|
||||||
|
|
||||||
|
socket = {
|
||||||
|
connected = false,
|
||||||
|
protocol = nil,
|
||||||
|
address = nil
|
||||||
},
|
},
|
||||||
type="socket",
|
|
||||||
refcount=1,
|
meta = {
|
||||||
socket={},
|
owner = kernel.currentTask.uid,
|
||||||
meta={
|
group = kernel.currentTask.uid,
|
||||||
owner=kernel.currentTask.uid,
|
etype = 2,
|
||||||
group=kernel.currentTask.uid,
|
|
||||||
etype=2,
|
perms =
|
||||||
perms=P.OWNER_R+P.OWNER_W+P.GROUP_R+P.GROUP_W
|
P.OWNER_R +
|
||||||
|
P.OWNER_W +
|
||||||
|
P.GROUP_R +
|
||||||
|
P.GROUP_W
|
||||||
},
|
},
|
||||||
isvirt=true
|
|
||||||
|
isvirt = true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
local fdo = kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
fdo.handle.read = function()
|
||||||
|
return ""
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.handle.write = function()
|
||||||
|
return nil, "ENOTCONN"
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.handle.close = function()
|
||||||
|
fdo.socket.connected = false
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
return fd
|
||||||
end
|
end
|
||||||
|
|
||||||
function socket.connect(fd, address)
|
function socket.connect(fd, address)
|
||||||
local handler
|
local fdo = kernel.currentTask.fd[fd]
|
||||||
for k, v in pairs(socket.handlers) do
|
|
||||||
if string.hasPrefix(address, k) then
|
if not fdo then
|
||||||
handler=v
|
return nil, "EBADF"
|
||||||
end
|
|
||||||
end
|
end
|
||||||
handler.connect(kernel.currentTask.fd[fd], address)
|
|
||||||
|
if fdo.type ~= "socket" then
|
||||||
|
return nil, "ENOTSOCK"
|
||||||
|
end
|
||||||
|
|
||||||
|
local handler =
|
||||||
|
getHandler(address)
|
||||||
|
|
||||||
|
if not handler then
|
||||||
|
return nil, "EPROTONOSUPPORT"
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.socket.protocol = handler
|
||||||
|
fdo.socket.address = address
|
||||||
|
|
||||||
|
local ok, err =
|
||||||
|
handler.connect(fd, address)
|
||||||
|
|
||||||
|
if not ok then
|
||||||
|
return nil, err
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.socket.connected = true
|
||||||
|
|
||||||
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function socket.listen(fd, backlog)
|
function socket.listen(fd, backlog)
|
||||||
error("Not Implemented")
|
local fdo =
|
||||||
|
kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
if not fdo then
|
||||||
|
return nil, "EBADF"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fdo.handle.listen then
|
||||||
|
return nil, "EOPNOTSUPP"
|
||||||
|
end
|
||||||
|
|
||||||
|
return fdo.handle.listen(backlog)
|
||||||
end
|
end
|
||||||
|
|
||||||
local sys=kernel.syscalls
|
function socket.send(fd, data)
|
||||||
sys["socket"]=socket.socket
|
local fdo =
|
||||||
|
kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
if not fdo then
|
||||||
|
return nil, "EBADF"
|
||||||
|
end
|
||||||
|
|
||||||
|
if fdo.type ~= "socket" then
|
||||||
|
return nil, "ENOTSOCK"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fdo.socket.connected then
|
||||||
|
return nil, "ENOTCONN"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fdo.handle.write then
|
||||||
|
return nil, "EOPNOTSUPP"
|
||||||
|
end
|
||||||
|
|
||||||
|
return fdo.handle.write(data)
|
||||||
|
end
|
||||||
|
|
||||||
|
function socket.recv(fd, amount)
|
||||||
|
local fdo =
|
||||||
|
kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
if not fdo then
|
||||||
|
return nil, "EBADF"
|
||||||
|
end
|
||||||
|
|
||||||
|
if fdo.type ~= "socket" then
|
||||||
|
return nil, "ENOTSOCK"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fdo.socket.connected then
|
||||||
|
return nil, "ENOTCONN"
|
||||||
|
end
|
||||||
|
|
||||||
|
if not fdo.handle.read then
|
||||||
|
return nil, "EOPNOTSUPP"
|
||||||
|
end
|
||||||
|
|
||||||
|
return fdo.handle.read(amount)
|
||||||
|
end
|
||||||
|
|
||||||
|
function socket.sockshutdown(fd)
|
||||||
|
local fdo =
|
||||||
|
kernel.currentTask.fd[fd]
|
||||||
|
|
||||||
|
if not fdo then
|
||||||
|
return nil, "EBADF"
|
||||||
|
end
|
||||||
|
|
||||||
|
if fdo.type ~= "socket" then
|
||||||
|
return nil, "ENOTSOCK"
|
||||||
|
end
|
||||||
|
|
||||||
|
if fdo.handle.close then
|
||||||
|
return fdo.handle.close()
|
||||||
|
end
|
||||||
|
|
||||||
|
fdo.socket.connected = false
|
||||||
|
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
sys.socket = socket.socket
|
||||||
|
sys.connect = socket.connect
|
||||||
|
sys.listen = socket.listen
|
||||||
|
sys.send = socket.send
|
||||||
|
sys.recv = socket.recv
|
||||||
|
sys.sockshutdown = socket.sockshutdown
|
||||||
|
|
||||||
kernel.log("Loaded socket module")
|
kernel.log("Loaded socket module")
|
||||||
129
Src/Hyperion-kernel/data/lib/modules/hyperion/30_vterm.kmod
Normal file
129
Src/Hyperion-kernel/data/lib/modules/hyperion/30_vterm.kmod
Normal file
@@ -0,0 +1,129 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local kernel = ...
|
||||||
|
|
||||||
|
local vterms = {}
|
||||||
|
|
||||||
|
local function createVt(id, width, height)
|
||||||
|
local vt = {
|
||||||
|
id = id,
|
||||||
|
width = width,
|
||||||
|
height = height,
|
||||||
|
buffer = {},
|
||||||
|
cursorX = 1,
|
||||||
|
cursorY = 1,
|
||||||
|
fgColor = 0xFFFFFF,
|
||||||
|
bgColor = 0x000000,
|
||||||
|
obj = {}
|
||||||
|
}
|
||||||
|
|
||||||
|
for y = 1, height do
|
||||||
|
vt.buffer[y] = {}
|
||||||
|
for x = 1, width do
|
||||||
|
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function scroll(lines)
|
||||||
|
for _ = 1, lines do
|
||||||
|
table.remove(vt.buffer, 1)
|
||||||
|
vt.buffer[vt.height] = {}
|
||||||
|
for x = 1, vt.width do
|
||||||
|
vt.buffer[vt.height][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:write(content)
|
||||||
|
local x, y = vt.cursorX, vt.cursorY
|
||||||
|
if x>vt.width then return end
|
||||||
|
if y>vt.height then return end
|
||||||
|
for i = 1, #content do
|
||||||
|
local c = content: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)
|
||||||
|
for _ = 1, spaces do
|
||||||
|
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
x = x + 1
|
||||||
|
if x > vt.width then
|
||||||
|
x = 1
|
||||||
|
y = y + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
elseif c == "\b" then
|
||||||
|
if x > 1 then
|
||||||
|
x = x - 1
|
||||||
|
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
end
|
||||||
|
else
|
||||||
|
if x <= vt.width and y <= vt.height then
|
||||||
|
vt.buffer[y][x] = {char = c, fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
x = x + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if x > vt.width then
|
||||||
|
x = 1
|
||||||
|
y = y + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
if y > vt.height then
|
||||||
|
scroll(1)
|
||||||
|
y = vt.height
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
vt.cursorX, vt.cursorY = x, y
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:spos(x, y)
|
||||||
|
vt.cursorX = tonumber(x)
|
||||||
|
vt.cursorY = tonumber(y)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:gpos()
|
||||||
|
return tostring(vt.cursorX)..";"..tostring(vt.cursorY)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:sfgc(color)
|
||||||
|
vt.fgColor = tonumber(color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:sbgc(color)
|
||||||
|
vt.bgColor = tonumber(color)
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:gfgc()
|
||||||
|
return vt.fgColor
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:gbgc()
|
||||||
|
return vt.bgColor
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:gplt()
|
||||||
|
return 24
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:clear()
|
||||||
|
for y = 1, vt.height do
|
||||||
|
for x = 1, vt.width do
|
||||||
|
vt.buffer[y][x] = {char = " ", fgColor = vt.fgColor, bgColor = vt.bgColor}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
vt.cursorX, vt.cursorY = 1, 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:isvirt()
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function vt.obj:gctrl()
|
||||||
|
return serializeBool(vt.ctrl)..";"..serializeBool(vt.alt)
|
||||||
|
end
|
||||||
|
|
||||||
|
return vt
|
||||||
|
end
|
||||||
@@ -21,7 +21,7 @@ local function loadExecutable(path)
|
|||||||
local env = kernel.freshUserEnv()
|
local env = kernel.freshUserEnv()
|
||||||
|
|
||||||
local func, err = load(data, "@" .. path, "t", env)
|
local func, err = load(data, "@" .. path, "t", env)
|
||||||
if not func then error("ENOEXEC: " .. tostring(err)) end
|
if not func then kernel.log("Failed to load executable: " .. tostring(err).. " : ".. tostring(path)); error("ENOEXEC: " .. tostring(err)) end
|
||||||
|
|
||||||
local meta = kernel.vfs.lstat(path)
|
local meta = kernel.vfs.lstat(path)
|
||||||
local suid_set = bit_is_set(meta.perms, 6)
|
local suid_set = bit_is_set(meta.perms, 6)
|
||||||
@@ -211,6 +211,8 @@ function sys.kill(pid, force)
|
|||||||
return false, "Task is already dead"
|
return false, "Task is already dead"
|
||||||
elseif task.status == "D" and not force then
|
elseif task.status == "D" and not force then
|
||||||
return false, "Cannot kill task waiting for IO"
|
return false, "Cannot kill task waiting for IO"
|
||||||
|
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||||
|
return false, "Different user"
|
||||||
end
|
end
|
||||||
local caller = kernel.currentTask
|
local caller = kernel.currentTask
|
||||||
local ceuid = caller and (caller.euid or caller.uid) or kernel.uid
|
local ceuid = caller and (caller.euid or caller.uid) or kernel.uid
|
||||||
@@ -227,6 +229,8 @@ function sys.stop(pid)
|
|||||||
return false, "Task does not exist"
|
return false, "Task does not exist"
|
||||||
elseif task.status ~= "R" and task.status ~= "S" then
|
elseif task.status ~= "R" and task.status ~= "S" then
|
||||||
return false, "Cannot stop non-running task"
|
return false, "Cannot stop non-running task"
|
||||||
|
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||||
|
return false, "Different user"
|
||||||
else
|
else
|
||||||
if task.status == "S" then
|
if task.status == "S" then
|
||||||
task.status = "ST"
|
task.status = "ST"
|
||||||
@@ -243,6 +247,8 @@ function sys.continue(pid)
|
|||||||
return false, "Task does not exist"
|
return false, "Task does not exist"
|
||||||
elseif task.status ~= "T" and task.status ~= "ST" then
|
elseif task.status ~= "T" and task.status ~= "ST" then
|
||||||
return false, "Task is not stopped"
|
return false, "Task is not stopped"
|
||||||
|
elseif task.euid ~= kernel.uid and kernel.uid ~= 0 then
|
||||||
|
return false, "Different user"
|
||||||
else
|
else
|
||||||
if task.status == "ST" then
|
if task.status == "ST" then
|
||||||
task.status = "S"
|
task.status = "S"
|
||||||
@@ -299,20 +305,21 @@ function sys.getuid() return kernel.currentTask.uid end
|
|||||||
local function reapDeadTasks()
|
local function reapDeadTasks()
|
||||||
for pid, task in pairs(tasks) do
|
for pid, task in pairs(tasks) do
|
||||||
if task.status == "Z" and not task.reapTime then
|
if task.status == "Z" and not task.reapTime then
|
||||||
task.coro = nil
|
if task.pid == 1 then kernel.panic("Attempted to gc init!") end
|
||||||
task.ivs = nil
|
task.coro = nil
|
||||||
task.vs = nil
|
task.ivs = nil
|
||||||
task.args = nil
|
task.vs = nil
|
||||||
task.envars = nil
|
task.args = nil
|
||||||
task.cwd = nil
|
task.envars = nil
|
||||||
task.numRuns = nil
|
task.cwd = nil
|
||||||
task.totalTime = nil
|
task.numRuns = nil
|
||||||
task.lastTime = nil
|
task.totalTime = nil
|
||||||
task.timeSlice = nil
|
task.lastTime = nil
|
||||||
|
task.timeSlice = nil
|
||||||
task.syscallReturn = nil
|
task.syscallReturn = nil
|
||||||
task.sleep = nil
|
task.sleep = nil
|
||||||
task.fd = nil
|
task.fd = nil
|
||||||
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
task.reapTime = kernel.EFI:getEpochMs() + 30000
|
||||||
|
|
||||||
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
elseif task.reapTime and kernel.EFI:getEpochMs() > task.reapTime
|
||||||
and task.status == "Z" then
|
and task.status == "Z" then
|
||||||
@@ -344,7 +351,23 @@ local k_max = 0.5
|
|||||||
local B = 0.01
|
local B = 0.01
|
||||||
|
|
||||||
function kernel.main()
|
function kernel.main()
|
||||||
|
kernel.log("Starting main loop...")
|
||||||
|
kernel.saveLog()
|
||||||
|
local stopLog=5
|
||||||
|
local logTasks=100
|
||||||
|
|
||||||
while not kernel.exitMain do
|
while not kernel.exitMain do
|
||||||
|
if kernel.config.logTasks then
|
||||||
|
if logTasks<0 then
|
||||||
|
kernel.log("Active Tasks:")
|
||||||
|
for i,v in pairs(tasks) do
|
||||||
|
kernel.log(v.name.." : "..v.status.." : "..tostring(v.pid).." : "..tostring(v.exit))
|
||||||
|
end
|
||||||
|
kernel.log("[END BLOCK]")
|
||||||
|
logTasks=100
|
||||||
|
end
|
||||||
|
logTasks=logTasks-1
|
||||||
|
end
|
||||||
local N = 0
|
local N = 0
|
||||||
local Tmin_hit = 0
|
local Tmin_hit = 0
|
||||||
local Tmax_hit = 0
|
local Tmax_hit = 0
|
||||||
@@ -352,6 +375,7 @@ function kernel.main()
|
|||||||
local taskTimes = {}
|
local taskTimes = {}
|
||||||
|
|
||||||
for pid, task in pairs(tasks) do
|
for pid, task in pairs(tasks) do
|
||||||
|
if kernel.exitMain then break end
|
||||||
kernel.currentTask = task
|
kernel.currentTask = task
|
||||||
kernel.uid = task.euid or task.uid
|
kernel.uid = task.euid or task.uid
|
||||||
kernel.process = task.name
|
kernel.process = task.name
|
||||||
@@ -366,9 +390,29 @@ function kernel.main()
|
|||||||
task.sleep = 0
|
task.sleep = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if task.status == "DS" and kernel.EFI:getEpochMs() >= task.sleep then
|
||||||
|
task.status = "D"
|
||||||
|
task.sleep = 0
|
||||||
|
end
|
||||||
|
|
||||||
if task.status == "D" then
|
if task.status == "D" then
|
||||||
if task.ksh then
|
if task.ksh then
|
||||||
coroutine.resume(task.ksh)
|
coroutine.resume(task.ksh)
|
||||||
|
if coroutine.status(task.ksh) == "dead" then
|
||||||
|
task.ksh = nil
|
||||||
|
if task.status == "D" then
|
||||||
|
task.status = "R"
|
||||||
|
end
|
||||||
|
|
||||||
|
if kernel.config.debugSyscalls then
|
||||||
|
kernel.log("Task " .. task.pid .. " IO wait completed", "DBUG", 0x00FFFF)
|
||||||
|
local sysret = task.syscallReturn
|
||||||
|
for i = 2, #sysret do
|
||||||
|
local v = type(sysret[i]) == "table" and table.serialize(sysret[i]) or tostring(sysret[i])
|
||||||
|
kernel.log(" retval[" .. (i-1) .. "] = " .. v, "DBUG", 0x00FFFF)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -405,7 +449,9 @@ function kernel.main()
|
|||||||
if task.status == "R" then
|
if task.status == "R" then
|
||||||
local startTime = kernel.EFI:getEpochMs()
|
local startTime = kernel.EFI:getEpochMs()
|
||||||
local ret
|
local ret
|
||||||
|
if stopLog > 0 then
|
||||||
|
kernel.log("Running task " .. tostring(task.pid) .. " (" .. task.name .. ") with time slice " .. string.format("%.3f", task.timeSlice) .. "s", "DBUG", 0x00FFFF)
|
||||||
|
end
|
||||||
if kernel.config.preempt then
|
if kernel.config.preempt then
|
||||||
if not task.debugger then
|
if not task.debugger then
|
||||||
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
ret = { resumeWithTimeout(task.coro, task.timeSlice, table.unpack(task.syscallReturn)) }
|
||||||
@@ -491,6 +537,11 @@ function kernel.main()
|
|||||||
end
|
end
|
||||||
|
|
||||||
reapDeadTasks()
|
reapDeadTasks()
|
||||||
|
if stopLog > 0 then
|
||||||
|
kernel.log("Executed " .. N .. " tasks, avg time: " .. string.format("%.2f", T_prev_avg) .. "ms, var: " .. string.format("%.2f", T_prev_var) .. ", B: " .. string.format("%.5f", B))
|
||||||
|
stopLog = stopLog - 1
|
||||||
|
kernel.saveLog()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
11
Src/Hyperion-kernel/data/lib/modules/hyperion/90_kgc.kmod
Normal file
11
Src/Hyperion-kernel/data/lib/modules/hyperion/90_kgc.kmod
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
local kernel = ...
|
||||||
|
kernel.processes.kgc = function()
|
||||||
|
while true do
|
||||||
|
for i,v in pairs(kernel.reqcache) do
|
||||||
|
if v.expires and kernel.EFI:getEpochMs() > v.expires then
|
||||||
|
kernel.reqcache[i] = nil
|
||||||
|
end
|
||||||
|
end
|
||||||
|
kernel.sleep(5000)
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
syscall.open("/dev/tty/1", "r") --stdin (fd 0)
|
syscall.open("/dev/input/keyboard1", "r") --stdin (fd 0)
|
||||||
syscall.open("/dev/tty/1", "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)
|
||||||
|
|
||||||
3
Src/hysh/control/symlinks.json
Normal file
3
Src/hysh/control/symlinks.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"/bin/sh": "/bin/hysh"
|
||||||
|
}
|
||||||
@@ -107,6 +107,7 @@ local COMMANDS = {
|
|||||||
{ name="whoami", usage="whoami", desc="Print the current username.", flags={} },
|
{ name="whoami", usage="whoami", desc="Print the current username.", flags={} },
|
||||||
{ name="id", usage="id [username]", desc="Print user identity (uid, gid).", flags={} },
|
{ name="id", usage="id [username]", desc="Print user identity (uid, gid).", flags={} },
|
||||||
{ name="ps", usage="ps", desc="List running tasks with pid, user, name, and status.", flags={} },
|
{ name="ps", usage="ps", desc="List running tasks with pid, user, name, and status.", flags={} },
|
||||||
|
{ name="hyperctl", usage="hyperctl <command> [service]", desc="Control system services (start, stop, restart, status, list, enable, disable).", flags={} },
|
||||||
{ name="hostname", usage="hostname [NAME]", desc="Print or set the system hostname.", flags={} },
|
{ name="hostname", usage="hostname [NAME]", desc="Print or set the system hostname.", flags={} },
|
||||||
{ name="uname", usage="uname [-asnrm]", desc="Print system information (OS name, hostname, release, machine).", flags={
|
{ name="uname", usage="uname [-asnrm]", desc="Print system information (OS name, hostname, release, machine).", flags={
|
||||||
{"-a","Print all fields"},
|
{"-a","Print all fields"},
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
--:Minify:--
|
--:Minify:--
|
||||||
syscall.open("/dev/tty/1","r") --stdin (Device 0)
|
local success, errorMsg = xpcall(function()
|
||||||
|
|
||||||
|
syscall.open("/dev/input/keyboard1","r") --stdin (Device 0)
|
||||||
syscall.open("/dev/tty/1","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 fs = require("fs")
|
local fs = require("fs")
|
||||||
|
|
||||||
syscall.devctl(1,"clear")
|
syscall.devctl(1,"clear")
|
||||||
@@ -833,6 +833,14 @@ builtinCmds.ops = function()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
builtinCmds.reboot = function ()
|
||||||
|
syscall.reboot()
|
||||||
|
end
|
||||||
|
|
||||||
|
builtinCmds.shutdown = function ()
|
||||||
|
syscall.shutdown()
|
||||||
|
end
|
||||||
|
|
||||||
local function listDir(dir, prefix)
|
local function listDir(dir, prefix)
|
||||||
local ok, entries = pcall(syscall.listdir, dir)
|
local ok, entries = pcall(syscall.listdir, dir)
|
||||||
if not ok or not entries then return {} end
|
if not ok or not entries then return {} end
|
||||||
@@ -1203,9 +1211,9 @@ local function runCommand(command)
|
|||||||
|
|
||||||
local proc = syscall.spawn(function()
|
local proc = syscall.spawn(function()
|
||||||
-- Open standard fds so programs that don't do it themselves work correctly.
|
-- Open standard fds so programs that don't do it themselves work correctly.
|
||||||
syscall.open("/dev/tty/1", "r") -- fd 0 stdin
|
syscall.open("/dev/input/keyboard1", "r") -- fd 0 stdin
|
||||||
syscall.open("/dev/tty/1", "w") -- fd 1 stdout
|
syscall.open("/dev/tty/1", "w") -- fd 1 stdout
|
||||||
syscall.open("/dev/null", "w") -- fd 2 stderr
|
syscall.open("/dev/null", "w") -- fd 2 stderr
|
||||||
-- exec replaces this coroutine's code with a fresh isolated environment
|
-- exec replaces this coroutine's code with a fresh isolated environment
|
||||||
-- compiled from disk by the kernel (via loadExecutable -> freshUserEnv),
|
-- compiled from disk by the kernel (via loadExecutable -> freshUserEnv),
|
||||||
-- so the child cannot share any upvalue or syscall table state with hysh.
|
-- so the child cannot share any upvalue or syscall table state with hysh.
|
||||||
|
|||||||
113
Src/hysh/data/bin/tree
Normal file
113
Src/hysh/data/bin/tree
Normal file
@@ -0,0 +1,113 @@
|
|||||||
|
--:Minify:--
|
||||||
|
local cloptions = {
|
||||||
|
a = false,
|
||||||
|
h = false,
|
||||||
|
l = false,
|
||||||
|
help = false,
|
||||||
|
}
|
||||||
|
local inpArgs = { ... }
|
||||||
|
local args = {}
|
||||||
|
local name = syscall.getTask(syscall.getpid()).name
|
||||||
|
|
||||||
|
for _, v in pairs(inpArgs) do
|
||||||
|
if v:sub(1, 2) == "--" then
|
||||||
|
local opt = v:sub(3)
|
||||||
|
if cloptions[opt] == nil then
|
||||||
|
print(name .. ": unrecognized option '" .. v .. "'.")
|
||||||
|
print("try '" .. name .. " --help' for more information.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
cloptions[opt] = true
|
||||||
|
elseif v:sub(1, 1) == "-" then
|
||||||
|
for i = 2, #v do
|
||||||
|
local opt = v:sub(i, i)
|
||||||
|
if cloptions[opt] == nil then
|
||||||
|
print(name .. ": invalid option '-" .. opt .. "'.")
|
||||||
|
print("try '" .. name .. " --help' for more information.")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
cloptions[opt] = true
|
||||||
|
end
|
||||||
|
else
|
||||||
|
table.insert(args, v)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if cloptions.help then
|
||||||
|
print("Usage: " .. name .. " [OPTION]... [DIR]")
|
||||||
|
print("List all entries in the specified DIRectory, or cwd if not specified.")
|
||||||
|
print("Display directory tree structure.")
|
||||||
|
print("")
|
||||||
|
print("Options:")
|
||||||
|
print(" -a do not ignore entries starting with .")
|
||||||
|
print(" -h with -l, print sizes in human readable format (e.g., 1K 234M 2G)")
|
||||||
|
print(" -l use a long listing format (show file sizes)")
|
||||||
|
print(" --help display this help and exit")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local fs = require("fs")
|
||||||
|
local dir = args[1] or ""
|
||||||
|
if dir:sub(1, 1) ~= "/" then
|
||||||
|
dir = syscall.getcwd() .. "/" .. dir
|
||||||
|
end
|
||||||
|
if dir:sub(-1) ~= "/" then dir = dir .. "/" end
|
||||||
|
|
||||||
|
if not fs.isDir(dir) then
|
||||||
|
print(name .. ": cannot access '" .. (args[1] or dir) .. "': no such directory")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
|
local function format_size(size)
|
||||||
|
if not cloptions.h then return tostring(size) end
|
||||||
|
if size < 1024 then return tostring(size) .. "B"
|
||||||
|
elseif size < 1024*1024 then return string.format("%.1fK", size/1024)
|
||||||
|
elseif size < 1024*1024*1024 then return string.format("%.1fM", size/1024/1024)
|
||||||
|
else return string.format("%.1fG", size/1024/1024/1024) end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function pdir(current_dir, level, prefix)
|
||||||
|
prefix = prefix or ""
|
||||||
|
local list = fs.list(current_dir)
|
||||||
|
if not cloptions.a then
|
||||||
|
for i = #list, 1, -1 do
|
||||||
|
if list[i]:sub(1, 1) == "." then table.remove(list, i) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
table.sort(list)
|
||||||
|
if current_dir:sub(-1) ~= "/" then current_dir = current_dir .. "/" end
|
||||||
|
|
||||||
|
for i, entry in ipairs(list) do
|
||||||
|
local full_path = current_dir .. entry
|
||||||
|
local is_last = (i == #list)
|
||||||
|
local branch = is_last and "`--" or "|--"
|
||||||
|
local indent = prefix .. branch
|
||||||
|
local suffix = ""
|
||||||
|
local info = ""
|
||||||
|
|
||||||
|
if fs.isDir(full_path) then
|
||||||
|
suffix = "/"
|
||||||
|
end
|
||||||
|
|
||||||
|
if cloptions.l then
|
||||||
|
local stat = fs.stat and fs.stat(full_path)
|
||||||
|
if stat then
|
||||||
|
local size = stat.size or 0
|
||||||
|
info = " " .. format_size(size)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
print(indent .. entry .. suffix .. info)
|
||||||
|
|
||||||
|
if fs.isDir(full_path) then
|
||||||
|
local new_prefix = prefix .. (is_last and " " or "| ")
|
||||||
|
pcall(pdir, full_path, level + 1, new_prefix)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Print root directory
|
||||||
|
local root_name = dir:sub(1, -2) -- remove trailing /
|
||||||
|
if root_name == "" then root_name = "/" end
|
||||||
|
print(root_name)
|
||||||
|
pdir(dir, 0, "")
|
||||||
0
Src/installer/data/bin/hyperion-build
Normal file
0
Src/installer/data/bin/hyperion-build
Normal file
0
Src/installer/data/bin/install
Normal file
0
Src/installer/data/bin/install
Normal file
29
Src/minify/data/bin/minify
Normal file
29
Src/minify/data/bin/minify
Normal file
@@ -0,0 +1,29 @@
|
|||||||
|
|
||||||
|
local function usageError()
|
||||||
|
print(
|
||||||
|
"\nusage: minify <file> or unminify <file>\n" ..
|
||||||
|
" The modified code will be printed to the stdout, pipe it to a file,\n" ..
|
||||||
|
" or something else as desired EG:\n\n" ..
|
||||||
|
" minify minify input.lua > output.lua\n\n" ..
|
||||||
|
" * minify will minify the code in the file.\n" ..
|
||||||
|
" * unminify will beautify the code and replace the variable names with easily\n" ..
|
||||||
|
" find-replacable ones to aide in reverse engineering minified code.\n")
|
||||||
|
syscall.exit(0)
|
||||||
|
end
|
||||||
|
|
||||||
|
local args = {...}
|
||||||
|
|
||||||
|
if #args ~= 2 then
|
||||||
|
usageError()
|
||||||
|
end
|
||||||
|
|
||||||
|
local minify = require("minify")
|
||||||
|
local fs = require("fs")
|
||||||
|
|
||||||
|
if args[1] == 'minify' then
|
||||||
|
print(minify.minify(fs.readAllText(args[2])))
|
||||||
|
elseif args[1] == 'unminify' then
|
||||||
|
print(minify.beautify(fs.readAllText(args[2])))
|
||||||
|
else
|
||||||
|
usageError()
|
||||||
|
end
|
||||||
3106
Src/minify/data/lib/minify.lua
Normal file
3106
Src/minify/data/lib/minify.lua
Normal file
File diff suppressed because it is too large
Load Diff
136
Src/pid/data/lib/pid.lua
Normal file
136
Src/pid/data/lib/pid.lua
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
--:Minify:--
|
||||||
|
|
||||||
|
local pid = {}
|
||||||
|
pid.__index = pid
|
||||||
|
|
||||||
|
local function clamp(value, minimum, maximum)
|
||||||
|
if minimum and value < minimum then
|
||||||
|
return minimum
|
||||||
|
end
|
||||||
|
if maximum and value > maximum then
|
||||||
|
return maximum
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
local function assertNumber(value, name)
|
||||||
|
if type(value) ~= "number" then
|
||||||
|
error("pid: " .. name .. " must be a number")
|
||||||
|
end
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid.new(kp, ki, kd, options)
|
||||||
|
assertNumber(kp, "kp")
|
||||||
|
assertNumber(ki, "ki")
|
||||||
|
assertNumber(kd, "kd")
|
||||||
|
|
||||||
|
options = options or {}
|
||||||
|
|
||||||
|
local controller = setmetatable({
|
||||||
|
kp = kp,
|
||||||
|
ki = ki,
|
||||||
|
kd = kd,
|
||||||
|
setpoint = options.setpoint or 0,
|
||||||
|
outputMin = options.outputMin,
|
||||||
|
outputMax = options.outputMax,
|
||||||
|
integralMin = options.integralMin,
|
||||||
|
integralMax = options.integralMax,
|
||||||
|
lastError = 0,
|
||||||
|
integral = 0,
|
||||||
|
lastMeasurement = nil,
|
||||||
|
lastOutput = 0,
|
||||||
|
lastTime = nil,
|
||||||
|
}, pid)
|
||||||
|
|
||||||
|
return controller
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:reset()
|
||||||
|
self.lastError = 0
|
||||||
|
self.integral = 0
|
||||||
|
self.lastMeasurement = nil
|
||||||
|
self.lastOutput = 0
|
||||||
|
self.lastTime = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:setSetpoint(setpoint)
|
||||||
|
assertNumber(setpoint, "setpoint")
|
||||||
|
self.setpoint = setpoint
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:setCoefficients(kp, ki, kd)
|
||||||
|
assertNumber(kp, "kp")
|
||||||
|
assertNumber(ki, "ki")
|
||||||
|
assertNumber(kd, "kd")
|
||||||
|
self.kp = kp
|
||||||
|
self.ki = ki
|
||||||
|
self.kd = kd
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:setOutputLimits(minimum, maximum)
|
||||||
|
if minimum ~= nil then assertNumber(minimum, "outputMin") end
|
||||||
|
if maximum ~= nil then assertNumber(maximum, "outputMax") end
|
||||||
|
if minimum and maximum and minimum > maximum then
|
||||||
|
error("pid: outputMin must be <= outputMax")
|
||||||
|
end
|
||||||
|
self.outputMin = minimum
|
||||||
|
self.outputMax = maximum
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:setIntegralLimits(minimum, maximum)
|
||||||
|
if minimum ~= nil then assertNumber(minimum, "integralMin") end
|
||||||
|
if maximum ~= nil then assertNumber(maximum, "integralMax") end
|
||||||
|
if minimum and maximum and minimum > maximum then
|
||||||
|
error("pid: integralMin must be <= integralMax")
|
||||||
|
end
|
||||||
|
self.integralMin = minimum
|
||||||
|
self.integralMax = maximum
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:update(measurement, dt)
|
||||||
|
assertNumber(measurement, "measurement")
|
||||||
|
assertNumber(dt, "dt")
|
||||||
|
if dt <= 0 then
|
||||||
|
error("pid: dt must be greater than zero")
|
||||||
|
end
|
||||||
|
|
||||||
|
local errorValue = self.setpoint - measurement
|
||||||
|
self.integral = clamp(self.integral + errorValue * dt, self.integralMin, self.integralMax)
|
||||||
|
local derivative = 0
|
||||||
|
if self.lastTime ~= nil then
|
||||||
|
derivative = (errorValue - self.lastError) / dt
|
||||||
|
end
|
||||||
|
|
||||||
|
local output = self.kp * errorValue + self.ki * self.integral + self.kd * derivative
|
||||||
|
output = clamp(output, self.outputMin, self.outputMax)
|
||||||
|
|
||||||
|
self.lastError = errorValue
|
||||||
|
self.lastMeasurement = measurement
|
||||||
|
self.lastOutput = output
|
||||||
|
self.lastTime = (self.lastTime or 0) + dt
|
||||||
|
|
||||||
|
return output
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:compute(measurement, dt)
|
||||||
|
return self:update(measurement, dt)
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:getState()
|
||||||
|
return {
|
||||||
|
setpoint = self.setpoint,
|
||||||
|
kp = self.kp,
|
||||||
|
ki = self.ki,
|
||||||
|
kd = self.kd,
|
||||||
|
integral = self.integral,
|
||||||
|
lastError = self.lastError,
|
||||||
|
lastOutput = self.lastOutput,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function pid:resetIntegral()
|
||||||
|
self.integral = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
return pid
|
||||||
3
Src/sysinit/control/symlinks.json
Normal file
3
Src/sysinit/control/symlinks.json
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"/sbin/init": "/usr/lib/sysinit/sysinit"
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@
|
|||||||
local kernel=...
|
local kernel=...
|
||||||
local fs=require("fs")
|
local fs=require("fs")
|
||||||
kernel.log("Sysinit started...")
|
kernel.log("Sysinit started...")
|
||||||
|
kernel.saveLog()
|
||||||
|
|
||||||
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)
|
||||||
@@ -41,6 +42,7 @@ for i,v in ipairs(files) do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
kernel.saveLog()
|
||||||
|
|
||||||
while true do
|
while true do
|
||||||
sleep(5)
|
sleep(5)
|
||||||
|
|||||||
3
build.py
3
build.py
@@ -28,6 +28,7 @@ import shutil
|
|||||||
import argparse
|
import argparse
|
||||||
import subprocess
|
import subprocess
|
||||||
import json
|
import json
|
||||||
|
import os
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from typing import Union
|
from typing import Union
|
||||||
|
|
||||||
@@ -71,7 +72,7 @@ def has_minify_header(path: Path) -> bool:
|
|||||||
|
|
||||||
def minify_file(src: Path) -> str:
|
def minify_file(src: Path) -> str:
|
||||||
result = subprocess.run(
|
result = subprocess.run(
|
||||||
["luamin.cmd", "-f", str(src)],
|
["npm", "exec", "luamin", "--", "-f", str(src)],
|
||||||
capture_output=True,
|
capture_output=True,
|
||||||
text=True
|
text=True
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -29,4 +29,7 @@ logTaskExit<bool>
|
|||||||
|
|
||||||
showModLoad<bool>
|
showModLoad<bool>
|
||||||
log module loads
|
log module loads
|
||||||
|
|
||||||
|
tmpToDisk<bool>
|
||||||
|
writes tmp to disk instead of ram
|
||||||
```
|
```
|
||||||
Reference in New Issue
Block a user