1.2 dev #19
No files matched your search
@@ -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")
|
||||||
|
|||||||
@@ -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")
|
||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|
||||||
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.
@@ -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"},
|
||||||
|
|||||||
+13
-5
@@ -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.
|
||||||
|
|||||||
@@ -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, "")
|
||||||
Whitespace-only changes.
Whitespace-only changes.
@@ -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
|
||||||
File diff suppressed because it is too large.
Load diff
@@ -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
|
||||||
@@ -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)
|
||||||
|
|||||||
@@ -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