mirror of
https://github.com/MightyPirates/OpenComputers.git
synced 2025-09-17 19:25:20 -04:00
Merged branch master-MC1.8.9 into master-MC1.9.4
This commit is contained in:
commit
a624a468f0
@ -1,25 +0,0 @@
|
||||
local network = require "network"
|
||||
|
||||
local function fillText(text, n)
|
||||
for k = 1, n - #text do
|
||||
text = text .. " "
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local maxlen = {8, 5}
|
||||
|
||||
for interface in pairs(network.info.getInfo().interfaces) do
|
||||
maxlen[2] = maxlen[2] < #interface+1 and #interface+1 or maxlen[2]
|
||||
for _, host in ipairs(network.info.getArpTable(interface)) do
|
||||
maxlen[1] = maxlen[1] < #host+1 and #host+1 or maxlen[1]
|
||||
end
|
||||
end
|
||||
|
||||
print(fillText("Address", maxlen[1])..fillText("Iface", maxlen[2]))
|
||||
|
||||
for interface in pairs(network.info.getInfo().interfaces) do
|
||||
for _, host in ipairs(network.info.getArpTable(interface)) do
|
||||
print(fillText(host, maxlen[1])..fillText(interface, maxlen[2]))
|
||||
end
|
||||
end
|
@ -20,6 +20,6 @@ else
|
||||
end
|
||||
until not line
|
||||
file:close()
|
||||
io.write("\n")
|
||||
io.stderr:write("\n")
|
||||
end
|
||||
end
|
||||
|
@ -4,7 +4,7 @@ local filesystem = require "filesystem"
|
||||
local args = {...}
|
||||
local options = {}
|
||||
options.count = math.huge
|
||||
options.bs = 1
|
||||
options.bs = 128
|
||||
options["if"] = "-"
|
||||
options.of = "-"
|
||||
|
||||
|
@ -37,8 +37,8 @@ io.write("\x1b[999;999H\x1b6n\x1b2J\x1b[30m\x1b[47m\x1bKEdit: " .. file .. "| F1
|
||||
local code = read("\x1b", "R")
|
||||
local h, w = code:match("\x1b%[(%d+);(%d+)R")
|
||||
|
||||
local edith = h - 1
|
||||
local editw = w
|
||||
local edith = tonumber(h) - 1
|
||||
local editw = tonumber(w)
|
||||
local x, y = 1, 1
|
||||
local atline = 1
|
||||
|
||||
@ -54,10 +54,11 @@ function setcur()
|
||||
io.write("\x1b[" .. (y - atline + 2) .. ";" .. (x) .. "H")
|
||||
end
|
||||
|
||||
local iw = io.write
|
||||
local function render(startline, nlines)
|
||||
--io.write("\x1b["..(startline - atline + 1)..";1H")
|
||||
for n = 1, nlines do
|
||||
io.write("\x1b["..(startline - atline + n + 1)..";1H\x1b[K" .. unicode.sub(lines[n + startline - 1] or "", 1, editw))
|
||||
iw("\x1b["..(startline - atline + n + 1)..";1H\x1b[K" .. unicode.sub(lines[n + startline - 1] or "", 1, editw))
|
||||
end
|
||||
setcur()
|
||||
end
|
||||
@ -72,7 +73,7 @@ local charHandler
|
||||
local code = ""
|
||||
codeHandler = function(char)
|
||||
if char == "[" then code = code .. char
|
||||
elseif char == "0" then code = code .. char
|
||||
elseif char == "O" then code = code .. char
|
||||
elseif char == "3" then code = code .. char
|
||||
elseif code == "[" and char == "A" then
|
||||
charHandler = baseHandler
|
||||
@ -128,10 +129,10 @@ codeHandler = function(char)
|
||||
end
|
||||
x = x - 1
|
||||
setcur()
|
||||
elseif code == "[0" and char == "P" or char == "R" then
|
||||
elseif (code == "O" and (char == "P" or char == "R")) or (code == "[[" and (char == "A" or char == "C")) then
|
||||
run = false
|
||||
io.write("\x1b[2J")
|
||||
if char == "P" then
|
||||
iw("\x1b[2J")
|
||||
if char == "P" or char == "A" then
|
||||
local out = io.open(file, "w")
|
||||
local text = ""
|
||||
for _, line in ipairs(lines) do
|
||||
|
132
src/main/resources/assets/opencomputers/loot/plan9k/bin/find.lua
Normal file
132
src/main/resources/assets/opencomputers/loot/plan9k/bin/find.lua
Normal file
@ -0,0 +1,132 @@
|
||||
local shell = require("shell")
|
||||
local fs = require("filesystem")
|
||||
local text = require("text")
|
||||
|
||||
local USAGE =
|
||||
[===[Usage: find [path] [--type=[dfs]] [--[i]name=EXPR]
|
||||
--path if not specified, path is assumed to be current working directory
|
||||
--type returns results of a given type, d:directory, f:file, and s:symlinks
|
||||
--name specify the file name pattern. Use quote to include *. iname is
|
||||
case insensitive
|
||||
--help display this help and exit]===]
|
||||
|
||||
local args, options = shell.parse(...)
|
||||
|
||||
if (not args or not options) or options.help then
|
||||
print(USAGE)
|
||||
if not options.help then
|
||||
return 1
|
||||
else
|
||||
return -- nil return, meaning no error
|
||||
end
|
||||
end
|
||||
|
||||
if #args > 1 then
|
||||
io.stderr:write(USAGE..'\n')
|
||||
return 1
|
||||
end
|
||||
|
||||
local path = #args == 1 and args[1] or "."
|
||||
|
||||
local bDirs = true
|
||||
local bFiles = true
|
||||
local bSyms = true
|
||||
|
||||
local fileNamePattern = ""
|
||||
local bCaseSensitive = true
|
||||
|
||||
if options.iname and options.name then
|
||||
io.stderr:write("find cannot define both iname and name\n")
|
||||
return 1
|
||||
end
|
||||
|
||||
if options.type then
|
||||
bDirs = false
|
||||
bFiles = false
|
||||
bSyms = false
|
||||
|
||||
if options.type == "f" then
|
||||
bFiles = true
|
||||
elseif options.type == "d" then
|
||||
bDirs = true
|
||||
elseif options.type == "s" then
|
||||
bSyms = true
|
||||
else
|
||||
io.stderr:write(string.format("find: Unknown argument to type: %s\n", options.type))
|
||||
io.stderr:write(USAGE..'\n')
|
||||
return 1
|
||||
end
|
||||
end
|
||||
|
||||
if options.iname or options.name then
|
||||
bCaseSensitive = options.iname ~= nil
|
||||
fileNamePattern = options.iname or options.name
|
||||
|
||||
if type(fileNamePattern) ~= "string" then
|
||||
io.stderr:write('find: missing argument to `name\'\n')
|
||||
return 1
|
||||
end
|
||||
|
||||
if not bCaseSensitive then
|
||||
fileNamePattern = fileNamePattern:lower()
|
||||
end
|
||||
|
||||
-- prefix any * with . for gnu find glob matching
|
||||
fileNamePattern = text.escapeMagic(fileNamePattern)
|
||||
fileNamePattern = fileNamePattern:gsub("%%%*", ".*")
|
||||
end
|
||||
|
||||
local function isValidType(spath)
|
||||
if not fs.exists(spath) then
|
||||
return false
|
||||
end
|
||||
|
||||
if fileNamePattern:len() > 0 then
|
||||
local fileName = spath:gsub('.*/','')
|
||||
|
||||
if fileName:len() == 0 then
|
||||
return false
|
||||
end
|
||||
|
||||
local caseFileName = fileName
|
||||
|
||||
if not bCaseSensitive then
|
||||
caseFileName = caseFileName:lower()
|
||||
end
|
||||
|
||||
local s, e = caseFileName:find(fileNamePattern)
|
||||
if not s or not e then
|
||||
return false
|
||||
end
|
||||
|
||||
if s ~= 1 or e ~= caseFileName:len() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
|
||||
if fs.isDirectory(spath) then
|
||||
return bDirs
|
||||
elseif fs.isLink(spath) then
|
||||
return bSyms
|
||||
else
|
||||
return bFiles
|
||||
end
|
||||
end
|
||||
|
||||
local function visit(rpath)
|
||||
local spath = shell.resolve(rpath)
|
||||
|
||||
if isValidType(spath) then
|
||||
local result = rpath:gsub('/+$','')
|
||||
print(result)
|
||||
end
|
||||
|
||||
if fs.isDirectory(spath) then
|
||||
local list_result = fs.list(spath)
|
||||
for list_item in list_result do
|
||||
visit(rpath:gsub('/+$', '') .. '/' .. list_item)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
visit(path)
|
@ -49,7 +49,7 @@ local function unblink()
|
||||
end
|
||||
|
||||
local function reblink()
|
||||
if not blinkState then
|
||||
if not blinkState and blink then
|
||||
blinkState = not blinkState
|
||||
local char, fg, bg = component.invoke(gpu, "get", x, y)
|
||||
preblinkbg = blinkState and bg or preblinkbg
|
||||
@ -184,6 +184,15 @@ mcommands["49"] = function()component.invoke(gpu, "setBackground", 0x000000)end
|
||||
local lcommands = {}
|
||||
|
||||
lcommands["4"] = function()end --Reset to replacement mode
|
||||
lcommands["?25"] = function()
|
||||
blink = false
|
||||
end
|
||||
|
||||
local hcommands = {}
|
||||
|
||||
hcommands["?25"] = function()
|
||||
blink = true
|
||||
end
|
||||
|
||||
local ncommands = {}
|
||||
|
||||
@ -277,6 +286,20 @@ control["l"] = function(char)
|
||||
end
|
||||
end
|
||||
|
||||
control["h"] = function(char)
|
||||
commandList[#commandList + 1] = commandBuf
|
||||
if not commandList[1] or commandList[1] == "" then
|
||||
commandList[1] = "0"
|
||||
end
|
||||
for _, command in ipairs(commandList) do
|
||||
if not hcommands[command] then
|
||||
pipes.log("Unknown escape code: " .. tostring(command))
|
||||
break
|
||||
end
|
||||
hcommands[command]()
|
||||
end
|
||||
end
|
||||
|
||||
control["n"] = function(char)
|
||||
commandList[#commandList + 1] = commandBuf
|
||||
if not commandList[1] or commandList[1] == "" then
|
||||
@ -333,6 +356,23 @@ control["!"] = function(char) --Disable
|
||||
end
|
||||
end
|
||||
|
||||
-- \x1b9[Row];[Col];[Height];[Width];[Dest Row];[Dest Col]c -- copy
|
||||
control["c"] = function(char)
|
||||
if commandMode == "9" then
|
||||
commandList[#commandList + 1] = commandBuf
|
||||
if #commandList == 6 then
|
||||
component.invoke(gpu,
|
||||
"copy",
|
||||
tonumber(commandList[2]),
|
||||
tonumber(commandList[1]),
|
||||
tonumber(commandList[4]),
|
||||
tonumber(commandList[3]),
|
||||
tonumber(commandList[6]),
|
||||
tonumber(commandList[5]))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
control["r"] = function(char) --Set scroll region
|
||||
commandList[#commandList + 1] = commandBuf
|
||||
local nt, nb = tonumber(commandList[1]) or 1, tonumber(commandList[2]) or h
|
||||
|
@ -1,41 +0,0 @@
|
||||
local network = require "network"
|
||||
local computer = require "computer"
|
||||
local args = {...}
|
||||
|
||||
local function formatSize(size)
|
||||
size = tonumber(size) or size
|
||||
if type(size) ~= "number" then
|
||||
return tostring(size)
|
||||
end
|
||||
local sizes = {"", "K", "M", "G"}
|
||||
local unit = 1
|
||||
local power = 1024
|
||||
while size > power and unit < #sizes do
|
||||
unit = unit + 1
|
||||
size = size / power
|
||||
end
|
||||
return math.floor(size * 10) / 10 .. sizes[unit]
|
||||
end
|
||||
|
||||
local function align(txt)return txt .. (" "):sub(#txt+1)end
|
||||
|
||||
if #args < 1 then
|
||||
print("Network interfaces:")
|
||||
local info = network.info.getInfo()
|
||||
for node, info in pairs(info.interfaces)do
|
||||
print(align(node).."Link encap:"..info.linkName)
|
||||
print(" HWaddr "..info.selfAddr)
|
||||
if node == "lo" then print(" HWaddr "..computer.address()) end
|
||||
local pktIn, pktOut, bytesIn, bytesOut = network.info.getInterfaceInfo(node)
|
||||
print(" RX packets:"..tostring(pktIn))
|
||||
print(" TX packets:"..tostring(pktOut))
|
||||
print(" RX bytes: ".. tostring(bytesIn) .. " (" ..formatSize(bytesIn).. ") TX bytes: " ..tostring(bytesOut) .. " (".. formatSize(bytesOut) .. ")")
|
||||
end
|
||||
elseif args[1] == "bind" and args[2] then
|
||||
print("Address attached")
|
||||
network.ip.bind(args[2])
|
||||
else
|
||||
print("Usage:")
|
||||
print(" ifconfig - view network summary")
|
||||
print(" ifconfig bind [addr] - 'attach' addnitional address to computer")
|
||||
end
|
@ -1,6 +1,6 @@
|
||||
--Plan9k userspace init for pipes kernel
|
||||
|
||||
--TODO: pcall all + emergency shell(or do it higher, in pipes)
|
||||
--TODO: pcall all + emergency shell(or do it lower, in pipes)
|
||||
|
||||
local pipes = require("pipes")
|
||||
local filesystem = require("filesystem")
|
||||
@ -52,6 +52,8 @@ end
|
||||
|
||||
local sin, sout
|
||||
|
||||
local services_ran = false
|
||||
|
||||
local free_gpus = {}
|
||||
local free_screens = {}
|
||||
local used_gpus = {}
|
||||
@ -69,7 +71,9 @@ local function runtty(gpu, screen)
|
||||
local getty = os.spawnp("/bin/getty.lua", mi, mo, nil, gpu, screen)
|
||||
local readkey = os.spawnp("/bin/readkey.lua", nil, mo, mo, screen, interruptHandler)
|
||||
|
||||
if not sout then
|
||||
if not services_ran then
|
||||
services_ran = true
|
||||
|
||||
sin = si
|
||||
sout = so
|
||||
|
||||
@ -113,7 +117,7 @@ if not sout then
|
||||
io.output(sout)
|
||||
end
|
||||
|
||||
pcall(services)
|
||||
--pcall(services)
|
||||
|
||||
local kout = io.popen(function()
|
||||
if filesystem.exists("/kern.log") then
|
||||
@ -143,7 +147,6 @@ for address, ctype in component.list() do
|
||||
end
|
||||
|
||||
computer.pushSignal("init")
|
||||
os.sleep(0)
|
||||
|
||||
local signal = {}
|
||||
local on_component_add = {}
|
||||
@ -244,6 +247,16 @@ function signal.component_removed(_, addr, ctype, ...)
|
||||
end
|
||||
end
|
||||
|
||||
function signal.init()
|
||||
if not services_ran then
|
||||
services_ran = true
|
||||
|
||||
pcall(services)
|
||||
end
|
||||
end
|
||||
|
||||
os.sleep(0)
|
||||
|
||||
while true do
|
||||
local sig = {computer.pullSignal()}
|
||||
if signal[sig[1]] then
|
||||
|
@ -106,7 +106,7 @@ if #args == 0 or options.i then
|
||||
--component.gpu.setForeground(0xFFFF00)
|
||||
term.write("Enter a statement and hit enter to evaluate it.\n")
|
||||
term.write("Prefix an expression with '=' to show its value.\n")
|
||||
term.write("Press Ctrl+C to exit the interpreter.\n")
|
||||
term.write("Type os.exit() to exit the interpreter.\n")
|
||||
--component.gpu.setForeground(0xFFFFFF)
|
||||
|
||||
while term.isAvailable() do
|
||||
@ -117,8 +117,8 @@ if #args == 0 or options.i then
|
||||
if command == nil then -- eof
|
||||
return
|
||||
end
|
||||
while #history > 10 do
|
||||
table.remove(history, 1)
|
||||
while #history > 20 do
|
||||
history[#history] = nil
|
||||
end
|
||||
local code, reason
|
||||
if string.sub(command, 1, 1) == "=" then
|
||||
|
@ -10,7 +10,7 @@ if #args == 0 then
|
||||
end
|
||||
return
|
||||
end
|
||||
if #args < 2 then
|
||||
--[[if #args < 2 then
|
||||
io.write("Usage: mount [label|address path]\n")
|
||||
io.write("Note that the address may be abbreviated.")
|
||||
return
|
||||
@ -26,3 +26,11 @@ local result, reason = fs.mount(table.unpack(args))
|
||||
if not result then
|
||||
io.stderr:write(reason)
|
||||
end
|
||||
]]
|
||||
|
||||
local h = fs.open("/sys/mount")
|
||||
local r, err = h:write(table.concat(args, " "))
|
||||
h:close()
|
||||
if err then
|
||||
print("Error: " .. tostring(err))
|
||||
end
|
||||
|
@ -1,107 +0,0 @@
|
||||
local network = require "network"
|
||||
local event = require "event"
|
||||
local computer = require "computer"
|
||||
local shell = require "shell"
|
||||
|
||||
local args, options = shell.parse(...)
|
||||
|
||||
if #args < 1 or options.h or options.help then
|
||||
print("Usage: ping: [addr]")
|
||||
print(" --c= --count=[ping count] Amount of pings to send(default 6)")
|
||||
print(" --s= --size=[data size] Payload size(default 56 bytes)")
|
||||
print(" --i= --interval=[seconds] Ping interval(default 1s)")
|
||||
--print(" -d --duplicates Check for duplicate messages")
|
||||
print(" --t= --droptime=[seconds] Amount of time after which ping is")
|
||||
print(" Considered to be lost[default 8s]")
|
||||
print(" -v --verbose Output more details")
|
||||
return
|
||||
end
|
||||
|
||||
local len = tonumber(options.s) or tonumber(options.size) or 56
|
||||
|
||||
local function round(n,r) return math.floor(n*(10^r))/(10^r) end
|
||||
|
||||
local function verbose(...)
|
||||
if options.v or options.verbose then
|
||||
print(...)
|
||||
end
|
||||
end
|
||||
|
||||
local function generatePayload()
|
||||
local payload = ""
|
||||
for i = 1, len do
|
||||
local ch = string.char(math.random(0, 255))
|
||||
ch = ch == ":" and "_" or ch --Ping matcher derps hard when it finds ':' in payload
|
||||
payload = payload .. ch
|
||||
end
|
||||
return payload
|
||||
end
|
||||
|
||||
|
||||
print("PING "..args[1].." with "..tostring(len) .." bytes of data")
|
||||
|
||||
local stats = {
|
||||
transmitted = 0,
|
||||
received = 0,
|
||||
malformed = 0
|
||||
}
|
||||
|
||||
local function doSleep()
|
||||
|
||||
local deadline = computer.uptime() + (tonumber(options.i) or tonumber(options.interval) or 1)
|
||||
repeat
|
||||
computer.pullSignal(deadline - computer.uptime())
|
||||
until computer.uptime() >= deadline
|
||||
end
|
||||
|
||||
local function doPing()
|
||||
|
||||
local payload = generatePayload()
|
||||
local icmp_seq = network.icmp.ping(args[1], payload)
|
||||
stats.transmitted = stats.transmitted + 1
|
||||
verbose(tostring(len).." bytes to "..args[1]..": icmp_seq="..tostring(icmp_seq))
|
||||
local start = computer.uptime()
|
||||
|
||||
local deadline = start + (tonumber(options.t) or tonumber(options.droptime) or 8)
|
||||
local e, replier, id, inpayload
|
||||
repeat
|
||||
e, replier, id, inpayload = event.pull(deadline - computer.uptime(), "ping_reply")
|
||||
until computer.uptime() >= deadline or (e == "ping_reply" and id == icmp_seq)
|
||||
|
||||
if computer.uptime() >= deadline and e ~= "ping_reply" then
|
||||
verbose(tostring(len).." bytes lost: icmp_seq="..tostring(icmp_seq))
|
||||
elseif inpayload == payload then
|
||||
stats.received = stats.received + 1
|
||||
print(tostring(len).." bytes from "..args[1]..": icmp_seq="..tostring(icmp_seq).." time="..tostring(round(computer.uptime()-start,2)).." s")
|
||||
else
|
||||
stats.malformed = stats.malformed + 1
|
||||
verbose(tostring(#inpayload).." bytes malformed: icmp_seq="..tostring(icmp_seq).." time="..tostring(round(computer.uptime()-start,2)).." s")
|
||||
end
|
||||
end
|
||||
|
||||
local begin = computer.uptime()
|
||||
|
||||
local function outputStats()
|
||||
print("--- "..args[1].." ping statistics ---")
|
||||
print(tostring(stats.transmitted) .. " packets transmitted, "
|
||||
..tostring(stats.received) .. " received, "
|
||||
..tostring(100 - math.floor((stats.received / stats.transmitted) * 100)) .. "% packet loss, time " .. tostring(round(computer.uptime()-begin,2)))
|
||||
end
|
||||
|
||||
local state, reason = pcall(function()
|
||||
local c = 0
|
||||
repeat
|
||||
doPing()
|
||||
doSleep()
|
||||
c = c + 1
|
||||
until c == 0 or (tonumber(options.c) and c >= tonumber(options.c))
|
||||
or (tonumber(options.count) and c >= tonumber(options.count))
|
||||
or ((not tonumber(options.c)) and (not tonumber(options.count)) and c >= 8)
|
||||
end)
|
||||
|
||||
if not state then
|
||||
verbose("Stopped by: "..tostring(reason))
|
||||
end
|
||||
|
||||
outputStats()
|
||||
|
@ -170,17 +170,17 @@ function on.key_down(_, source, ascii, keycode, user)
|
||||
elseif keycode == 205 then io.stdout:write("\x1b[C")
|
||||
elseif keycode == 203 then io.stdout:write("\x1b[D")
|
||||
|
||||
elseif keycode == keyboard.keys.f1 then io.stdout:write("\x1b[0P")
|
||||
elseif keycode == keyboard.keys.f2 then io.stdout:write("\x1b[0Q")
|
||||
elseif keycode == keyboard.keys.f3 then io.stdout:write("\x1b[0R")
|
||||
elseif keycode == keyboard.keys.f4 then io.stdout:write("\x1b[0S")
|
||||
elseif keycode == keyboard.keys.f1 then io.stdout:write("\x1bOP")
|
||||
elseif keycode == keyboard.keys.f2 then io.stdout:write("\x1bOQ")
|
||||
elseif keycode == keyboard.keys.f3 then io.stdout:write("\x1bOR")
|
||||
elseif keycode == keyboard.keys.f4 then io.stdout:write("\x1bOS")
|
||||
|
||||
elseif keycode == keyboard.keys.delete then io.stdout:write("\x1b[3~")
|
||||
elseif keycode == keyboard.keys.insert then io.stdout:write("\x1b[2~")
|
||||
--elseif keycode == keyboard.keys.insert then io.stdout:write("\x1b[2~")
|
||||
elseif keycode == keyboard.keys.pageUp then io.stdout:write("\x1b[5~")
|
||||
elseif keycode == keyboard.keys.pageDown then io.stdout:write("\x1b[6~")
|
||||
elseif keycode == keyboard.keys.home then io.stdout:write("\x1b0H")
|
||||
elseif keycode == keyboard.keys["end"] then io.stdout:write("\x1b0F")
|
||||
elseif keycode == keyboard.keys.home then io.stdout:write("\x1bOH")
|
||||
elseif keycode == keyboard.keys["end"] then io.stdout:write("\x1bOF")
|
||||
elseif keycode == keyboard.keys.tab then io.stdout:write("\t")
|
||||
--TODO: rest fX keys
|
||||
end
|
||||
|
@ -1,44 +0,0 @@
|
||||
local network = require "network"
|
||||
|
||||
local function fillText(text, n)
|
||||
for k = 1, n - #text do
|
||||
text = text .. " "
|
||||
end
|
||||
return text
|
||||
end
|
||||
|
||||
local function normLine(data)
|
||||
local res = ""
|
||||
for c in data:gmatch(".") do
|
||||
if c == "\n" or c == "\r" then c = "\x1b[31m.\x1b[39m" end
|
||||
res = res .. (c:match("[%g%s]") or "\x1b[31m.\x1b[39m")
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
print("MCNET routing table")
|
||||
local routes = network.info.getRoutes()
|
||||
local maxlen = {12, 8, 6, 4, 5}
|
||||
|
||||
for host, route in pairs(routes) do
|
||||
maxlen[1] = maxlen[1] < #normLine(host)+1 and #normLine(host)+1 or maxlen[1]
|
||||
maxlen[2] = maxlen[2] < #route.router+1 and #route.router+1 or maxlen[2]
|
||||
maxlen[3] = maxlen[3] < #route.interface+1 and #route.interface+1 or maxlen[3]
|
||||
maxlen[4] = maxlen[4] < #tostring(route.age)+1 and #tostring(route.age)+1 or maxlen[4]
|
||||
maxlen[5] = maxlen[5] < #tostring(route.dist)+1 and #tostring(route.dist)+1 or maxlen[5]
|
||||
end
|
||||
|
||||
print(fillText("Destination", maxlen[1])..
|
||||
fillText("Gateway", maxlen[2])..
|
||||
fillText("Iface", maxlen[3])..
|
||||
fillText("Age", maxlen[4])..
|
||||
fillText("Dist", maxlen[5]))
|
||||
|
||||
for host, route in pairs(routes) do
|
||||
print(fillText(normLine(host), maxlen[1])..
|
||||
fillText(route.router, maxlen[2])..
|
||||
fillText(route.interface, maxlen[3])..
|
||||
fillText(tostring(route.age), maxlen[4])..
|
||||
fillText(tostring(route.dist), maxlen[5]))
|
||||
end
|
||||
|
@ -4,6 +4,8 @@ local text = require("text")
|
||||
local shell = require("shell")
|
||||
local fs = require("filesystem")
|
||||
|
||||
local arg, opt = shell.parse(...)
|
||||
|
||||
local alias = {}
|
||||
local builtin = {}
|
||||
|
||||
@ -19,6 +21,7 @@ local function parse(tokens)
|
||||
|
||||
local nextin = "-"
|
||||
local nextout = "-"
|
||||
local nexterr = nil
|
||||
local arg = {}
|
||||
|
||||
local skip = false
|
||||
@ -51,15 +54,20 @@ local function parse(tokens)
|
||||
if not tokens[k + 1]:match("[%w%._%-/~]+") then error("Syntax error") end
|
||||
nextout = tokens[k + 1]
|
||||
skip = true
|
||||
elseif token == "2>" then
|
||||
if not tokens[k + 1]:match("[%w%._%-/~]+") then error("Syntax error") end
|
||||
nexterr = tokens[k + 1]
|
||||
skip = true
|
||||
elseif token == ">>" then
|
||||
if not tokens[k + 1]:match("[%w%._%-/~]+") then error("Syntax error") end
|
||||
nextout = tokens[k + 1]
|
||||
skip = true
|
||||
print("APPEND MODE IS NOT IMPLEMENTED")
|
||||
elseif token == "&" then
|
||||
res[#res + 1] = {arg = arg, stdin = nextin, stdout = nextout, nowait = true}
|
||||
res[#res + 1] = {arg = arg, stdin = nextin, stdout = nextout, stderr = nexterr, nowait = true}
|
||||
nextout = "-"
|
||||
nextin = "-"
|
||||
nexterr = nil
|
||||
arg = {}
|
||||
end
|
||||
else
|
||||
@ -68,7 +76,7 @@ local function parse(tokens)
|
||||
end
|
||||
|
||||
if #arg > 0 then
|
||||
res[#res + 1] = {arg = arg, stdin = nextin, stdout = nextout}
|
||||
res[#res + 1] = {arg = arg, stdin = nextin, stdout = nextout, stderr = nexterr}
|
||||
end
|
||||
|
||||
return res, pipes
|
||||
@ -118,9 +126,10 @@ local function execute(cmd)
|
||||
for n, program in pairs(programs) do
|
||||
local sin = type(program.stdin) == "number" and pipes[program.stdin][1] or program.stdin == "-" and io.input() or io.open(program.stdin, "r")
|
||||
local sout = type(program.stdout) == "number" and pipes[program.stdout][2] or program.stdout == "-" and io.output() or io.open(program.stdout, "w")
|
||||
local serr = program.stderr and (program.stderr == "-" and io.output() or io.open(program.stderr, "w")) or io.stderr
|
||||
|
||||
processes[n] = {
|
||||
pid = os.spawnp(program.arg[1], sin, sout, io.stderr, table.unpack(program.arg, 2)),
|
||||
pid = os.spawnp(program.arg[1], sin, sout, serr, table.unpack(program.arg, 2)),
|
||||
stdin = sin,
|
||||
stdout = sout
|
||||
}
|
||||
@ -149,6 +158,17 @@ local function expand(value)
|
||||
return result
|
||||
end
|
||||
|
||||
local function script(file)
|
||||
for line in io.lines(file) do
|
||||
if line:sub(1,1) ~= "#" then
|
||||
if opt.x then
|
||||
print("> " .. line)
|
||||
end
|
||||
execute(text.trim(line))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-------------------
|
||||
-- Builtins
|
||||
|
||||
@ -174,10 +194,18 @@ builtin.exit = function()
|
||||
end
|
||||
|
||||
builtin.alias = function(what, ...)
|
||||
if not what then
|
||||
print("Usage: alias <alias> [command] [arguments...]")
|
||||
return
|
||||
end
|
||||
alias[what] = {...}
|
||||
end
|
||||
|
||||
builtin.unalias = function(what)
|
||||
if not what then
|
||||
print("Usage: unalias <alias>")
|
||||
return
|
||||
end
|
||||
alias[what] = nil
|
||||
end
|
||||
|
||||
@ -196,11 +224,15 @@ if fs.exists("~/.history") then
|
||||
end
|
||||
|
||||
local function log(cmd)
|
||||
local hisfile = io.open("~/.history", "a")
|
||||
if #cmd > 0 then
|
||||
hisfile:write(cmd .. "\n")
|
||||
local hisfile, err = io.open("~/.history", "a")
|
||||
if hisfile then
|
||||
if #cmd > 0 then
|
||||
hisfile:write(cmd .. "\n")
|
||||
end
|
||||
hisfile:close()
|
||||
else
|
||||
io.stderr:write("Error writing to histfile: " .. tostring(err))
|
||||
end
|
||||
hisfile:close()
|
||||
end
|
||||
|
||||
-------------------
|
||||
@ -310,10 +342,13 @@ builtin.alias("....", "cd", "../../..")
|
||||
-------------------
|
||||
-- Main loop
|
||||
|
||||
if arg[1] and fs.exists(arg[1]) then
|
||||
script(arg[1])
|
||||
return
|
||||
end
|
||||
|
||||
if fs.exists("~/.shrc") then
|
||||
for line in io.lines("~/.shrc") do
|
||||
execute(line)
|
||||
end
|
||||
script(arg[1])
|
||||
end
|
||||
|
||||
while run do
|
||||
|
@ -60,6 +60,9 @@ do
|
||||
local y = 1
|
||||
|
||||
function kernel._println(msg)
|
||||
for line in string.gmatch(tostring(msg), "([^\n]+)") do
|
||||
pcall(function()kernel.io.debug(msg)end)
|
||||
end
|
||||
if gpu and screen then
|
||||
for line in string.gmatch(tostring(msg), "([^\n]+)") do
|
||||
kernel._K.component.invoke(gpu, "set", 1, y + 3, line)
|
||||
@ -84,6 +87,7 @@ do
|
||||
end
|
||||
|
||||
kernel.io.println = kernel._println
|
||||
kernel.io.debug = function()end
|
||||
end
|
||||
|
||||
kernel.io.println(_OSVERSION .. " Starting")
|
||||
@ -97,7 +101,7 @@ local panicPull = kernel._K.computer.pullSignal
|
||||
function kernel.panic()
|
||||
kernel._println("--------------------------------------------------------")
|
||||
pcall(function()
|
||||
for s in string.gmatch(debug.traceback(), "[^\r\n]+") do
|
||||
for s in string.gmatch(tostring(debug.traceback()), "[^\r\n]+") do
|
||||
kernel._println(s)
|
||||
end
|
||||
end)
|
||||
@ -184,8 +188,13 @@ kernel.io.println("Starting base modules")
|
||||
for i = 1, #modules do
|
||||
if kernel.modules[modules[i].name].start then
|
||||
kernel.io.println("Start module " .. modules[i].name)
|
||||
local result = table.pack(pcall(kernel.modules[modules[i].name].start))
|
||||
local result = table.pack(xpcall(kernel.modules[modules[i].name].start, function(e)
|
||||
pcall(kernel._println, "Module tb: " .. debug.traceback())
|
||||
pcall(kernel._println, "E: " .. tostring(e))
|
||||
end))
|
||||
|
||||
if not result[1] then
|
||||
pcall(kernel._println, "Module start failed: " .. modules[i].name)
|
||||
pcall(kernel._println, result[2])
|
||||
kernel.panic()
|
||||
end
|
||||
|
@ -81,7 +81,7 @@ end
|
||||
local function dofile(fs, file)
|
||||
local program, reason = loadfile(fs, file)
|
||||
if program then
|
||||
local result = table.pack(pcall(program))
|
||||
local result = table.pack(true, program())
|
||||
if result[1] then
|
||||
return table.unpack(result, 2, result.n)
|
||||
else
|
||||
|
@ -0,0 +1,30 @@
|
||||
local colors = {
|
||||
[0] = "white",
|
||||
[1] = "orange",
|
||||
[2] = "magenta",
|
||||
[3] = "lightblue",
|
||||
[4] = "yellow",
|
||||
[5] = "lime",
|
||||
[6] = "pink",
|
||||
[7] = "gray",
|
||||
[8] = "silver",
|
||||
[9] = "cyan",
|
||||
[10] = "purple",
|
||||
[11] = "blue",
|
||||
[12] = "brown",
|
||||
[13] = "green",
|
||||
[14] = "red",
|
||||
[15] = "black"
|
||||
}
|
||||
|
||||
do
|
||||
local keys = {}
|
||||
for k in pairs(colors) do
|
||||
table.insert(keys, k)
|
||||
end
|
||||
for _, k in pairs(keys) do
|
||||
colors[colors[k]] = k
|
||||
end
|
||||
end
|
||||
|
||||
return colors
|
@ -98,7 +98,15 @@ function internet.socket(address, port)
|
||||
end
|
||||
|
||||
local stream = {inet = inet, socket = socket}
|
||||
|
||||
-- stream:close does a syscall, which yields, and that's not possible in
|
||||
-- the __gc metamethod. So we start a timer to do the yield/cleanup.
|
||||
local function cleanup(self)
|
||||
if not self.socket then return end
|
||||
pcall(self.socket.close)
|
||||
end
|
||||
local metatable = {__index = socketStream,
|
||||
__gc = cleanup,
|
||||
__metatable = "socketstream"}
|
||||
return setmetatable(stream, metatable)
|
||||
end
|
||||
|
@ -24,6 +24,14 @@ function split(str, pat)
|
||||
return t
|
||||
end
|
||||
|
||||
function cloneTab(t)
|
||||
local n = {}
|
||||
for k, v in pairs(t) do
|
||||
n[k] = v
|
||||
end
|
||||
return n
|
||||
end
|
||||
|
||||
--------
|
||||
|
||||
function getAllocator()
|
||||
@ -47,6 +55,14 @@ end
|
||||
|
||||
--------
|
||||
|
||||
function randomString(c)
|
||||
local s = ""
|
||||
for i = 1, c do
|
||||
s = s .. string.char(math.random(0, 255))
|
||||
end
|
||||
return s
|
||||
end
|
||||
|
||||
function uuidBin(uuid)
|
||||
local undashed = uuid:gsub("-","")
|
||||
local high = tonumber(undashed:sub(1,16), 16)
|
||||
@ -58,6 +74,10 @@ function binUUID(uuid)
|
||||
local raw = toHex(uuid)
|
||||
return raw:sub(1, 8) .. "-" .. raw:sub(9, 12) .. "-" .. raw:sub(13, 16) .. "-" .. raw:sub(17, 20) .. "-" .. raw:sub(21)
|
||||
end
|
||||
|
||||
function shortUUID()
|
||||
return toHex(randomString(2)):upper()
|
||||
end
|
||||
|
||||
--------
|
||||
|
||||
|
@ -528,7 +528,13 @@ function filesystem.open(path, mode)
|
||||
end
|
||||
|
||||
local stream = {fs = node.fs, handle = handle}
|
||||
|
||||
local function cleanup(self)
|
||||
if not self.handle then return end
|
||||
pcall(self.fs.close, self.handle)
|
||||
end
|
||||
local metatable = {__index = fileStream,
|
||||
__gc = cleanup,
|
||||
__metatable = "filestream"}
|
||||
return setmetatable(stream, metatable)
|
||||
end
|
||||
|
@ -108,7 +108,7 @@ function new(readfs, writefs)
|
||||
end
|
||||
return result
|
||||
end
|
||||
proxy.open = function(path, mode) --hnd = orig * 2 [+ 1]
|
||||
proxy.open = function(path, mode)
|
||||
if mode:sub(1, 1) == "w" then
|
||||
if readfs.exists(path) and not writefs.exists(kernel.modules.vfs.path(path)..".cfsdel."..kernel.modules.vfs.name(path)) then
|
||||
if readfs.isDirectory(path) then
|
||||
|
@ -1,9 +1,10 @@
|
||||
function start()
|
||||
if component.invoke(computer.getBootAddress(), "isReadOnly") then
|
||||
if component.invoke(computer.getBootAddress(), "isReadOnly") or (kernel.modules.special and kernel.modules.special.roroot) then
|
||||
local cow = kernel.modules.cowfs.new(computer.getBootAddress(), computer.tmpAddress())
|
||||
kernel.modules.vfs.mount(cow, "/")
|
||||
else
|
||||
kernel.modules.vfs.mount(computer.getBootAddress(), "/")
|
||||
end
|
||||
|
||||
kernel.modules.vfs.mount(computer.tmpAddress(), "/tmp")
|
||||
end
|
||||
|
@ -0,0 +1,113 @@
|
||||
proxy = {}
|
||||
data = {}
|
||||
|
||||
proxy.address = "sysfs0000"
|
||||
proxy.spaceUsed = function() return 0 end
|
||||
proxy.spaceTotal = function() return 0 end
|
||||
proxy.makeDirectory = function() error("Permission Denied") end
|
||||
proxy.isReadOnly = function() return true end
|
||||
proxy.rename = function() error("Permission Denied") end
|
||||
proxy.remove = function() error("Permission Denied") end
|
||||
proxy.setLabel = function() error("Permission Denied") end
|
||||
proxy.size = function(path)
|
||||
local seg = kernel.modules.vfs.segments(path)
|
||||
local file = data
|
||||
for _, d in pairs(seg) do
|
||||
file = file[d]
|
||||
end
|
||||
return file.size and file.size() or 0
|
||||
end
|
||||
proxy.getLabel = function() return "sysfs" end
|
||||
|
||||
local allocator, handles = kernel.modules.util.getAllocator()
|
||||
|
||||
proxy.exists = function(path)
|
||||
local seg = kernel.modules.vfs.segments(path)
|
||||
local file = data
|
||||
for _, d in pairs(seg) do
|
||||
if not file[d] then
|
||||
return false
|
||||
end
|
||||
file = file[d]
|
||||
end
|
||||
return file and true or false
|
||||
end
|
||||
proxy.open = function(path)
|
||||
kernel.io.debug("Sysfs open: " .. tostring(path))
|
||||
local seg = kernel.modules.vfs.segments(path)
|
||||
local file = data
|
||||
for _, d in pairs(seg) do
|
||||
if not file[d] then
|
||||
return nil, "File not found"
|
||||
end
|
||||
file = file[d]
|
||||
end
|
||||
local hnd = allocator:get()
|
||||
hnd.file = file
|
||||
if hnd.file.open then
|
||||
hnd.file.open(hnd)
|
||||
end
|
||||
return hnd.id
|
||||
end
|
||||
proxy.read = function(h, ...)
|
||||
return handles[h].file.read(handles[h], ...)
|
||||
end
|
||||
proxy.close = function(h)
|
||||
if handles[h].file.close then
|
||||
handles[h].file.close(handles[h])
|
||||
end
|
||||
allocator:unset(handles[h])
|
||||
end
|
||||
proxy.write = function(h, ...)
|
||||
return handles[h].file.write(handles[h], ...)
|
||||
end
|
||||
proxy.seek = function(h, ...)
|
||||
return handles[h].file.seek(handles[h], ...)
|
||||
end
|
||||
proxy.isDirectory = function(path)
|
||||
local seg = kernel.modules.vfs.segments(path)
|
||||
local dir = data
|
||||
for _, d in pairs(seg) do
|
||||
dir = dir[d]
|
||||
end
|
||||
if dir.__type then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
proxy.list = function(path)
|
||||
local seg = kernel.modules.vfs.segments(path)
|
||||
local dir = data
|
||||
for _, d in pairs(seg) do
|
||||
dir = dir[d]
|
||||
end
|
||||
if dir.__type then
|
||||
error("File is not a directory")
|
||||
end
|
||||
local list = {}
|
||||
for f, node in pairs(dir) do
|
||||
list[#list + 1] = f .. (node.__type and "" or "/")
|
||||
end
|
||||
return list
|
||||
end
|
||||
|
||||
-----
|
||||
|
||||
function roFile(data)
|
||||
return {
|
||||
__type = "f",
|
||||
read = function(h)
|
||||
if h.read then
|
||||
return nil
|
||||
end
|
||||
h.read = true
|
||||
return (type(data) == "function") and data() or tostring(data)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
data.net = {}
|
||||
|
||||
function start()
|
||||
kernel.modules.vfs.mount(proxy, "/sys")
|
||||
end
|
@ -0,0 +1,29 @@
|
||||
local devices = {}
|
||||
local dfs = kernel.modules.devfs.data
|
||||
scanners = {}
|
||||
|
||||
function register(uuid, name, device, scan)
|
||||
if devices[uuid] then
|
||||
return
|
||||
end
|
||||
|
||||
if dfs[name] then
|
||||
return
|
||||
end
|
||||
|
||||
devices[uuid] = {name = name}
|
||||
dfs[name] = device
|
||||
|
||||
if scan then
|
||||
for k, v in pairs(scanners) do
|
||||
v(device, uuid, name)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function unregister(uuid)
|
||||
if not devices[uuid] then
|
||||
return
|
||||
end
|
||||
dfs[devices[uuid].name] = nil
|
||||
end
|
@ -0,0 +1,23 @@
|
||||
filesystems = {}
|
||||
|
||||
kernel.modules.sysfs.data.mount = {
|
||||
__type = "f",
|
||||
write = function(h, data)
|
||||
local args = kernel.modules.util.split(data, "%s")
|
||||
kernel.io.println("Mount " .. table.concat(args, ","))
|
||||
if #args < 3 then
|
||||
return nil, "Invalid argument count"
|
||||
end
|
||||
if not filesystems[args[1]] then
|
||||
return nil, "Invalid filesystem"
|
||||
end
|
||||
|
||||
local proxy, err = filesystems[args[1]](table.unpack(args, 2, #args - 1))
|
||||
if not proxy then
|
||||
kernel.io.println("Error mounting " .. tostring(args[1]) .. ": " .. tostring(err))
|
||||
return nil, err
|
||||
end
|
||||
|
||||
return kernel.modules.vfs.mount(proxy, args[#args])
|
||||
end
|
||||
}
|
@ -19,7 +19,8 @@ kernel.userspace.computer.getBootAddress = kernel._K.computer.getBootAddress
|
||||
kernel.userspace.computer.shutdown = kernel.modules.gc.shutdown
|
||||
|
||||
kernel.userspace.computer.pullSignal = function(timeout)
|
||||
return coroutine.yield("signal", timeout)
|
||||
kernel.modules.threading.currentThread.deadline = computer.uptime() + (timeout or math.huge)
|
||||
return coroutine.yield("signal")
|
||||
end
|
||||
|
||||
kernel.userspace.computer.hasSignal = function(sigType)
|
||||
@ -79,11 +80,12 @@ end
|
||||
|
||||
function kernel.userspace.os.exit()
|
||||
kernel.modules.threading.kill(kernel.modules.threading.currentThread.pid)
|
||||
coroutine.yield("yield", 0)
|
||||
coroutine.yield("yield")
|
||||
end
|
||||
|
||||
function kernel.userspace.os.sleep(time)
|
||||
coroutine.yield("yield", computer.uptime() + (time or 0))
|
||||
kernel.modules.threading.currentThread.deadline = computer.uptime() + (time or 0)
|
||||
coroutine.yield("yield")
|
||||
end
|
||||
|
||||
function kernel.userspace.os.getenv(name)
|
||||
|
@ -0,0 +1,60 @@
|
||||
function buildDevice(parent, first, size)
|
||||
kernel.io.println("Partition from "..first)
|
||||
return {
|
||||
__type = "f",
|
||||
open = function(hnd)
|
||||
hnd.pos = 0
|
||||
hnd.h = {}
|
||||
parent.open(hnd.h)
|
||||
parent.seek(hnd.h, "set", first)
|
||||
end,
|
||||
size = function()
|
||||
return size
|
||||
end,
|
||||
write = function(h, data)
|
||||
parent.seek(h.h, "set", first + h.pos)
|
||||
parent.write(h.h, data:sub(1, math.min(#data, size - h.pos)))
|
||||
|
||||
h.pos = h.pos + #data
|
||||
|
||||
return not (h.pos >= size)
|
||||
end,
|
||||
read = function(h, len)
|
||||
len = math.ceil(len)
|
||||
if h.pos >= size then
|
||||
return
|
||||
end
|
||||
|
||||
-- 0 1 2 3 4 5 6 7 8
|
||||
-- - - - x x x - - -
|
||||
|
||||
parent.seek(h.h, "set", first + h.pos)
|
||||
local data = parent.read(h.h, math.min(len, size - h.pos))
|
||||
|
||||
h.pos = h.pos + len
|
||||
return data
|
||||
end,
|
||||
seek = function(h, whence, offset)
|
||||
offset = offset or 0
|
||||
if whence == "end" then
|
||||
h.pos = math.min(size, math.max(0, size - offset))
|
||||
return h.pos
|
||||
elseif whence == "set" then
|
||||
h.pos = math.min(size, math.max(0, offset))
|
||||
return h.pos
|
||||
elseif whence == "cur" then
|
||||
h.pos = math.min(size, math.max(0, h.pos + offset))
|
||||
return h.pos
|
||||
else
|
||||
error("Invalid whence")
|
||||
end
|
||||
return math.floor(h.pos)
|
||||
end,
|
||||
close = function(h)
|
||||
if parent.close then
|
||||
|
||||
end
|
||||
end
|
||||
}
|
||||
end
|
||||
|
@ -94,6 +94,7 @@ function start()
|
||||
kernel.userspace.package.preload.computer = setmetatable({}, {__index = kernel.userspace.computer})
|
||||
kernel.userspace.package.preload.io = setmetatable({}, {__index = kernel.modules.io.io})
|
||||
kernel.userspace.package.preload.unicode = setmetatable({}, {__index = kernel.userspace.unicode})
|
||||
kernel.userspace.package.preload.os = setmetatable({}, {__index = kernel.userspace.os})
|
||||
|
||||
--TODO: fix override.. maybe
|
||||
|
||||
|
@ -1,47 +1,31 @@
|
||||
chatboxes = {}
|
||||
local block = kernel.modules.block
|
||||
|
||||
local function buildDevfs()
|
||||
for file in pairs(kernel.modules.devfs.data) do
|
||||
if file:match("^chatbox") then
|
||||
kernel.modules.devfs.data[file] = nil
|
||||
end
|
||||
end
|
||||
for k, chatbox in ipairs(chatboxes) do
|
||||
kernel.modules.devfs.data["chatbox" .. chatbox:sub(1,4):upper()] = {
|
||||
__type = "f",
|
||||
open = function(hnd, mode)
|
||||
if mode == "r" then error("Invalid mode") end
|
||||
hnd.chatbox = chatbox
|
||||
end,
|
||||
size = function()
|
||||
return 2048
|
||||
end,
|
||||
write = function(h, data)
|
||||
component.invoke(chatbox, "say", data)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end
|
||||
local function buildDevice()
|
||||
return {
|
||||
__type = "f",
|
||||
open = function(hnd, mode)
|
||||
if mode == "r" then error("Invalid mode") end
|
||||
hnd.chatbox = chatbox
|
||||
end,
|
||||
size = function()
|
||||
return 2048
|
||||
end,
|
||||
write = function(h, data)
|
||||
component.invoke(chatbox, "say", data)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "chat_box" then
|
||||
chatboxes[#chatboxes + 1] = address
|
||||
buildDevfs()
|
||||
block.register(address, "chatbox" .. address:sub(1,4):upper(), buildDevice(address))
|
||||
end
|
||||
end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "chat_box" then
|
||||
local t
|
||||
for i, chatbox in ipairs(chatboxes) do
|
||||
if chatbox == address then
|
||||
t = i
|
||||
break
|
||||
end
|
||||
end
|
||||
table.remove(chatboxes, t)
|
||||
buildDevfs()
|
||||
block.unregister(address)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,47 +1,25 @@
|
||||
cards = {}
|
||||
local block = kernel.modules.block
|
||||
|
||||
|
||||
local function buildDevfs()
|
||||
for file in pairs(kernel.modules.devfs.data) do
|
||||
if file == "urandom" then
|
||||
kernel.modules.devfs.data[file] = nil
|
||||
end
|
||||
end
|
||||
|
||||
kernel.modules.devfs.data["urandom"] = {
|
||||
local function buildDevice(addr)
|
||||
return {
|
||||
__type = "f",
|
||||
read = function(h, len)
|
||||
return component.invoke(cards[1], "random", len)
|
||||
return component.invoke(addr, "random", len)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "data" then
|
||||
cards[#cards + 1] = address
|
||||
buildDevfs()
|
||||
block.register(address, "urandom", buildDevice(address))
|
||||
end
|
||||
end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "data" then
|
||||
local t
|
||||
for i, card in ipairs(cards) do
|
||||
if card == address then
|
||||
t = i
|
||||
break
|
||||
end
|
||||
end
|
||||
table.remove(cards, t)
|
||||
buildDevfs()
|
||||
block.unregister(address)
|
||||
end
|
||||
end
|
||||
|
||||
--function start()
|
||||
--for card, t in component.list("data") do
|
||||
-- onComponentAdded(_, card, t)
|
||||
--end
|
||||
--end
|
||||
|
||||
kernel.modules.keventd.listen("component_added", onComponentAdded)
|
||||
kernel.modules.keventd.listen("component_removed", onComponentRemoved)
|
||||
|
@ -1,6 +1,6 @@
|
||||
drives = {}
|
||||
local block = kernel.modules.block
|
||||
|
||||
function writeSectors(drive, data, at)
|
||||
local function writeSectors(drive, data, at)
|
||||
local sectorSize = component.invoke(drive, "getSectorSize")
|
||||
repeat
|
||||
local atSector = math.floor((at - 1) / sectorSize) + 1
|
||||
@ -16,21 +16,21 @@ function writeSectors(drive, data, at)
|
||||
local toWrite = before .. data:sub(1, writable) .. after
|
||||
data = data:sub(writable + 1)
|
||||
|
||||
kernel.io.println("Wd: " .. atSector .. "/" .. #toWrite .. ": "..inSectorStart.." [ " .. writable .. " ] "..(inSectorStart + writable) .. " #old="..#old)
|
||||
--kernel.io.println("Wd: " .. atSector .. "/" .. #toWrite .. ": "..inSectorStart.." [ " .. writable .. " ] "..(inSectorStart + writable) .. " #old="..#old)
|
||||
component.invoke(drive, "writeSector", atSector, toWrite)
|
||||
|
||||
at = at + writable
|
||||
until #data < 1
|
||||
end
|
||||
|
||||
function readSectors(drive, at, len)
|
||||
local function readSectors(drive, at, len)
|
||||
local data = ""
|
||||
local sectorSize = component.invoke(drive, "getSectorSize")
|
||||
repeat
|
||||
local atSector = math.floor(at / sectorSize) + 1
|
||||
|
||||
sector = component.invoke(drive, "readSector", atSector)
|
||||
kernel.io.println("Rsect " .. atSector .. ": " .. tostring((at - 1) % sectorSize + 1) .. " -> " .. tostring(math.min((at - 1) % sectorSize + len - #data, sectorSize)))
|
||||
--kernel.io.println("Rsect " .. atSector .. ": " .. tostring((at - 1) % sectorSize + 1) .. " -> " .. tostring(math.min((at - 1) % sectorSize + len - #data, sectorSize)))
|
||||
local read = sector:sub((at - 1) % sectorSize + 1, math.min((at - 1) % sectorSize + len - #data, sectorSize))
|
||||
|
||||
data = data .. read
|
||||
@ -39,79 +39,64 @@ function readSectors(drive, at, len)
|
||||
return data
|
||||
end
|
||||
|
||||
local function buildDevfs()
|
||||
for file in pairs(kernel.modules.devfs.data) do
|
||||
if file:match("^sd") then
|
||||
kernel.modules.devfs.data[file] = nil
|
||||
end
|
||||
end
|
||||
for k, drive in ipairs(drives) do
|
||||
kernel.modules.devfs.data["sd" .. drive:sub(1, 4):upper()] = {
|
||||
__type = "f",
|
||||
open = function(hnd)
|
||||
--component.invoke(drive, "seek", -math.huge)
|
||||
hnd.drive = drive
|
||||
hnd.pos = 1
|
||||
--kernel.io.println("Od: " .. hnd.pos .. "/" .. component.invoke(drive, "getCapacity"))
|
||||
end,
|
||||
size = function()
|
||||
return component.invoke(drive, "getCapacity")
|
||||
end,
|
||||
write = function(h, data)
|
||||
|
||||
writeSectors(drive, data, h.pos)
|
||||
--kernel.io.println("Wd: " .. h.pos .. "(+" .. #data .. ")/" .. component.invoke(drive, "getCapacity"))
|
||||
h.pos = h.pos + #data
|
||||
return not (h.pos >= component.invoke(drive, "getCapacity"))
|
||||
--TODO: do this correctly
|
||||
end,
|
||||
read = function(h, len)
|
||||
len = math.ceil(len)
|
||||
kernel.io.println("Rd " .. tostring(len) .. ": " .. h.pos .. "/" .. component.invoke(drive, "getCapacity"))
|
||||
if h.pos >= component.invoke(drive, "getCapacity") then
|
||||
return
|
||||
end
|
||||
local data = readSectors(drive, h.pos, len)
|
||||
h.pos = h.pos + len
|
||||
return data
|
||||
end,
|
||||
seek = function(h, whence, offset)
|
||||
offset = offset or 0
|
||||
if whence == "end" then
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, component.invoke(drive, "getCapacity") - offset))
|
||||
return h.pos - 1
|
||||
elseif whence == "set" then
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, 1 + offset))
|
||||
return h.pos - 1
|
||||
else
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, h.pos + offset))
|
||||
return h.pos - 1
|
||||
end
|
||||
return math.floor(h.pos)
|
||||
local function buildDevice(drive)
|
||||
return {
|
||||
__type = "f",
|
||||
open = function(hnd)
|
||||
--component.invoke(drive, "seek", -math.huge)
|
||||
hnd.drive = drive
|
||||
hnd.pos = 1
|
||||
--kernel.io.println("Od: " .. hnd.pos .. "/" .. component.invoke(drive, "getCapacity"))
|
||||
end,
|
||||
size = function()
|
||||
return component.invoke(drive, "getCapacity")
|
||||
end,
|
||||
write = function(h, data)
|
||||
|
||||
writeSectors(drive, data, h.pos)
|
||||
--kernel.io.println("Wd: " .. h.pos .. "(+" .. #data .. ")/" .. component.invoke(drive, "getCapacity"))
|
||||
h.pos = h.pos + #data
|
||||
return not (h.pos >= component.invoke(drive, "getCapacity"))
|
||||
--TODO: do this correctly
|
||||
end,
|
||||
read = function(h, len)
|
||||
len = math.ceil(len)
|
||||
--kernel.io.println("Rd " .. tostring(len) .. ": " .. h.pos .. "/" .. component.invoke(drive, "getCapacity"))
|
||||
if h.pos >= component.invoke(drive, "getCapacity") then
|
||||
return
|
||||
end
|
||||
}
|
||||
end
|
||||
local data = readSectors(drive, h.pos, len)
|
||||
h.pos = h.pos + len
|
||||
return data
|
||||
end,
|
||||
seek = function(h, whence, offset)
|
||||
offset = offset or 0
|
||||
if whence == "end" then
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, component.invoke(drive, "getCapacity") - offset + 1))
|
||||
return h.pos - 1
|
||||
elseif whence == "set" then
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, 1 + offset))
|
||||
return h.pos - 1
|
||||
else
|
||||
h.pos = math.min(component.invoke(drive, "getCapacity"), math.max(1, h.pos + offset))
|
||||
return h.pos - 1
|
||||
end
|
||||
return math.floor(h.pos)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "drive" then
|
||||
drives[#drives + 1] = address
|
||||
buildDevfs()
|
||||
block.register(address, "sd" .. address:sub(1,4):upper(), buildDevice(address), true)
|
||||
end
|
||||
end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "drive" then
|
||||
local t
|
||||
for i, drive in ipairs(drives) do
|
||||
if drive == address then
|
||||
t = i
|
||||
break
|
||||
end
|
||||
end
|
||||
table.remove(drives, t)
|
||||
buildDevfs()
|
||||
block.unregister(address)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.modules.keventd.listen("component_added", onComponentAdded)
|
||||
kernel.modules.keventd.listen("component_removed", onComponentRemoved)
|
||||
|
@ -0,0 +1,30 @@
|
||||
local block = kernel.modules.block
|
||||
local util = kernel.modules.util
|
||||
|
||||
local lba = 512
|
||||
|
||||
local function scan(device, duuid, dname)
|
||||
local h = {}
|
||||
device.open(h)
|
||||
device.seek(h, "set", 1 * lba)
|
||||
local head = device.read(h, 92)
|
||||
local sig, rev, hsize, crc, clb, blb, fusablelba, lusablelba,
|
||||
uuid, arraystart, partitions, entrysz, partcrc = string.unpack("\60c8c4I4I4xxxxI8I8I8I8c16I8I4I4I4", head)
|
||||
if sig ~= "EFI PART" or rev ~= "\0\0\1\0" then
|
||||
return
|
||||
end
|
||||
for i = 1, partitions do
|
||||
device.seek(h, "set", arraystart * lba + (i - 1) * entrysz)
|
||||
local entry = device.read(h, entrysz)
|
||||
local ptype, puuid, pstart, pend, attr, name = string.unpack("\60c16c16I8I8I8c72", entry)
|
||||
if ptype ~= ("\0"):rep(16) then
|
||||
local size = (pend - pstart + 1) * 512
|
||||
block.register(util.binUUID(puuid), dname .. "p" .. (i - 1), kernel.modules.partition.buildDevice(device, pstart * lba, size))
|
||||
end
|
||||
end
|
||||
if device.close then
|
||||
device.close(h)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.modules.block.scanners.gpt = scan
|
@ -1,5 +1,5 @@
|
||||
local io = {}
|
||||
|
||||
local threading
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
local function buffWrap(b)
|
||||
@ -37,9 +37,9 @@ function io.input(file)
|
||||
elseif not io.type(file) then
|
||||
error("bad argument #1 (string or file expected, got " .. type(file) .. ")", 2)
|
||||
end
|
||||
kernel.modules.threading.currentThread.io_input = file
|
||||
threading.currentThread.io_input = file
|
||||
end
|
||||
return kernel.modules.threading.currentThread.io_input
|
||||
return threading.currentThread.io_input
|
||||
end
|
||||
|
||||
function io.lines(filename, ...)
|
||||
@ -95,10 +95,10 @@ function io.popen(prog, mode, ...)
|
||||
|
||||
if mode == "w" then
|
||||
local newin, sink = kernel.modules.buffer.pipe()
|
||||
local thread = kernel.modules.threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
local thread = threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
|
||||
thread.io_output = kernel.modules.threading.currentThread.io_output
|
||||
thread.io_error = kernel.modules.threading.currentThread.io_error
|
||||
thread.io_output = threading.currentThread.io_output
|
||||
thread.io_error = threading.currentThread.io_error
|
||||
thread.io_input = newin
|
||||
|
||||
sink.thread = thread.pid
|
||||
@ -106,10 +106,10 @@ function io.popen(prog, mode, ...)
|
||||
elseif mode == "r" or mode == nil then
|
||||
local out, newout = kernel.modules.buffer.pipe()
|
||||
|
||||
local thread = kernel.modules.threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
local thread = threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
thread.io_output = newout
|
||||
thread.io_error = kernel.modules.threading.currentThread.io_error
|
||||
thread.io_input = kernel.modules.threading.currentThread.io_input
|
||||
thread.io_error = threading.currentThread.io_error
|
||||
thread.io_input = threading.currentThread.io_input
|
||||
|
||||
out.thread = thread.pid
|
||||
return out
|
||||
@ -117,9 +117,9 @@ function io.popen(prog, mode, ...)
|
||||
local newin, sink = kernel.modules.buffer.pipe()
|
||||
local out, newout = kernel.modules.buffer.pipe()
|
||||
|
||||
local thread = kernel.modules.threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
local thread = threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
thread.io_output = newout
|
||||
thread.io_error = kernel.modules.threading.currentThread.io_error
|
||||
thread.io_error = threading.currentThread.io_error
|
||||
thread.io_input = newin
|
||||
|
||||
sink.thread = thread.pid
|
||||
@ -127,11 +127,11 @@ function io.popen(prog, mode, ...)
|
||||
|
||||
return sink, out
|
||||
elseif mode == "" then
|
||||
local thread = kernel.modules.threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
local thread = threading.spawn(prog, 0, name, _, _, ...) --TODO: child mode somehow
|
||||
|
||||
thread.io_output = kernel.modules.threading.currentThread.io_output
|
||||
thread.io_error = kernel.modules.threading.currentThread.io_error
|
||||
thread.io_input = kernel.modules.threading.currentThread.io_input
|
||||
thread.io_output = threading.currentThread.io_output
|
||||
thread.io_error = threading.currentThread.io_error
|
||||
thread.io_input = threading.currentThread.io_input
|
||||
|
||||
return thread.pid
|
||||
end
|
||||
@ -153,9 +153,9 @@ function io.output(file)
|
||||
elseif not io.type(file) then
|
||||
error("bad argument #1 (string or file expected, got " .. type(file) .. ")", 2)
|
||||
end
|
||||
kernel.modules.threading.currentThread.io_output = file
|
||||
threading.currentThread.io_output = file
|
||||
end
|
||||
return kernel.modules.threading.currentThread.io_output
|
||||
return threading.currentThread.io_output
|
||||
end
|
||||
|
||||
function io.read(...)
|
||||
@ -198,3 +198,7 @@ setmetatable(io, {__index = function(_, k)
|
||||
end})
|
||||
|
||||
_G.io = io
|
||||
|
||||
function start()
|
||||
threading = kernel.modules.threading
|
||||
end
|
||||
|
@ -1,483 +0,0 @@
|
||||
--local network = require "network"
|
||||
|
||||
local cfg = {
|
||||
routereq_retry = 20, --Seconds betwen route seek retries
|
||||
routereq_drop = 115, --Seconds to stop seeking route
|
||||
routereq_relayage = 3, --Timeout added to each request re-sent
|
||||
route_relayage = 3, --Age added to each route sent
|
||||
route_exp = 300/2, --Remove route after being not used for this time
|
||||
route_recheck = 320/2, --Recheck each route after this amount of time
|
||||
route_age_max = 660, -- Max age of route
|
||||
ttl = 32 --Time to live
|
||||
}
|
||||
kernel.modules.procfs.data.sys.net = cfg
|
||||
|
||||
local _rawSend
|
||||
local isAccessible
|
||||
local getNodes
|
||||
--local getInterfaceInfo
|
||||
local startNetwork
|
||||
local resetRouting
|
||||
|
||||
local dataHandler --Layer 2 data handler
|
||||
|
||||
accessibleHosts = {}
|
||||
nodes = {}
|
||||
|
||||
------------------------
|
||||
--Layer 1
|
||||
|
||||
local initated = false
|
||||
|
||||
function start()
|
||||
if initated then return end
|
||||
initated = true
|
||||
|
||||
--local filesystem = require "filesystem"
|
||||
|
||||
local drivers = {}
|
||||
|
||||
for file in kernel.modules.vfs.list("/lib/modules/network") do
|
||||
|
||||
--print("Loading driver:", file)
|
||||
local ld, reason = kernel.userspace.loadfile("/lib/modules/network/"..file, nil, _G)
|
||||
if not ld then
|
||||
kernel.io.println("Network driver loading failed: " .. tostring(reason))
|
||||
end
|
||||
drivers[file] = {driver = ld()}
|
||||
|
||||
local eventHandler = {}--EVENT HANDLERS FOR DRIVER EVENTS
|
||||
--eventHandler.debug = print
|
||||
eventHandler.debug = function()end
|
||||
|
||||
function eventHandler.newHost(node, address)--New interface in net node
|
||||
--print("New host: ",node, address)
|
||||
accessibleHosts[address] = {driver = drivers[file], node = node}
|
||||
nodes[node].hosts[address] = address--mark host in node
|
||||
end
|
||||
|
||||
function eventHandler.newInterface(interface, selfAddr, linkName)--New node
|
||||
--print("New interface: ",interface, selfaddr)
|
||||
nodes[interface] = {hosts={}, driver = drivers[file], selfAddr = selfAddr, linkName = linkName}
|
||||
end
|
||||
|
||||
function eventHandler.delInterface(interface)
|
||||
nodes[interface] = nil
|
||||
for addr, host in pairs(accessibleHosts) do
|
||||
if host.node == interface then
|
||||
accessibleHosts[addr] = nil
|
||||
end
|
||||
end
|
||||
resetRouting()
|
||||
end
|
||||
|
||||
function eventHandler.recvData(data, node, origin)
|
||||
dataHandler(data, node, origin)
|
||||
end
|
||||
|
||||
function eventHandler.setListener(evt, listener)
|
||||
return kernel.modules.keventd.listen(evt, function(...)
|
||||
local args = {...}
|
||||
local res = {pcall(function()listener(table.unpack(args))end)}
|
||||
if not res[1] then
|
||||
kernel.io.println("ERROR IN NET EVENTHANDLER["..file.."]:"..tostring(res[2]))
|
||||
end
|
||||
return table.unpack(res,2)
|
||||
end)
|
||||
end
|
||||
|
||||
drivers[file].handle = drivers[file].driver.start(eventHandler)
|
||||
end
|
||||
|
||||
_rawSend = function(addr, node, data)
|
||||
--print("TrySend:",node,addr,":",data)
|
||||
if accessibleHosts[addr] then
|
||||
accessibleHosts[addr].driver.driver.send(accessibleHosts[addr].driver.handle, node, addr, data)
|
||||
end
|
||||
end
|
||||
|
||||
isAccessible = function(addr)
|
||||
if not accessibleHosts[addr] then return end
|
||||
return accessibleHosts[addr].node, accessibleHosts[addr].driver
|
||||
end
|
||||
|
||||
getNodes = function()
|
||||
return nodes
|
||||
end
|
||||
|
||||
getInterfaceInfo = function(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].driver.driver.info(interface)
|
||||
end
|
||||
end
|
||||
|
||||
kernel.io.println("Link Control initated")
|
||||
startNetwork()
|
||||
kernel.io.println("Network initated")
|
||||
end
|
||||
|
||||
------------------------
|
||||
--Layer 2
|
||||
|
||||
startNetwork = function()
|
||||
local rawSend
|
||||
--local send
|
||||
|
||||
local routeRequests = {} -- Table by dest addressed of tables {type = T[, data=..]}, types: D(own waiting data), R(route request for someone), E(routed data we should be able to route..)
|
||||
local routes = {} --Table of pairs -> [this or route] / {thisHost=true} / {router = [addr]}
|
||||
|
||||
resetRouting = function()
|
||||
for k, route in pairs(routes) do
|
||||
if not route.thisHost then
|
||||
routes[k] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
routes[computer.address()] = {thisHost=true}
|
||||
|
||||
-----Data out
|
||||
|
||||
local function onRecv(origin, data)
|
||||
--computer.pushSignal("network_message", origin, data)
|
||||
kernel.modules.libnetwork.handleData(origin, data)
|
||||
end
|
||||
|
||||
-----Sending
|
||||
|
||||
local function sendDirectData(addr, data)--D[ttl-byte][data]
|
||||
return rawSend(addr, string.pack("c1B", "D", cfg.ttl)..data)
|
||||
end
|
||||
|
||||
local function sendRoutedData(addr, data)--E[ttl-byte][hostlen-byte][dest host][hostlen-byte][origin host]message
|
||||
local nodes = getNodes()
|
||||
local msg = string.pack("c1Bs1s1", "E", cfg.ttl, addr, nodes[routes[addr].node].selfAddr) .. data
|
||||
local node, driver = isAccessible(addr)
|
||||
_rawSend(node and addr or routes[addr].router, node or routes[addr].node, msg)
|
||||
end
|
||||
|
||||
local function sendRoutedDataAs(addr, origin, data, ottl)--E[ttl-byte][hostlen-byte][dest host][hostlen-byte][origin host]message
|
||||
local msg = string.pack("c1Bs1s1", "E", ottl - 1, addr, origin) .. data
|
||||
local node, driver = isAccessible(addr)
|
||||
_rawSend(node and addr or routes[addr].router, node or routes[addr].node, msg)
|
||||
end
|
||||
|
||||
local function sendRouteRequest(addr, age)--R[ttl-byte][Addr len][Requested addr][age]
|
||||
local request = string.pack(">c1Bs1H", "R", cfg.ttl, addr, math.floor(age))
|
||||
local nodes = getNodes()
|
||||
local sent = {}
|
||||
for node, n in pairs(nodes) do
|
||||
for host in pairs(n.hosts)do
|
||||
if not sent[host]then
|
||||
sent[host] = true
|
||||
--_rawSend(host, node, base..toByte(n.selfAddr:len())..n.selfAddr)
|
||||
_rawSend(host, node, request)
|
||||
end
|
||||
end
|
||||
end
|
||||
sent = nil
|
||||
end
|
||||
|
||||
local function sendHostFound(dest, age, addr, dist)--H[ttl-byte][age-short][distance][Found host]
|
||||
--kernel.io.println("found "..addr.." for "..dest)
|
||||
if dest ~= "localhost" then
|
||||
return rawSend(dest, "H"..string.pack(">BHB", cfg.ttl, math.floor(age + cfg.route_relayage), dist)..addr)
|
||||
end
|
||||
end
|
||||
|
||||
rawSend = function(addr, data)
|
||||
local node, driver = isAccessible(addr)
|
||||
if node then
|
||||
_rawSend(addr, node, data)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
send = function(addr, data)
|
||||
if type(addr) ~= "string" then error("Address must be string!!") end
|
||||
if not sendDirectData(addr, data) then--Try send directly
|
||||
if routes[addr] then
|
||||
if routes[addr].thisHost then
|
||||
onRecv("localhost", data)--it's this host, use loopback
|
||||
else
|
||||
sendRoutedData(addr, data)--We know route, try to send it that way
|
||||
routes[addr].active = computer.uptime()
|
||||
end
|
||||
else
|
||||
--route is unknown, we have to request it if we haven't done so already
|
||||
if not routeRequests[addr] then
|
||||
routeRequests[addr] = {update = computer.uptime(), timeout = computer.uptime()}
|
||||
routeRequests[addr][#routeRequests[addr]+1] = {type = "D", data = data}
|
||||
sendRouteRequest(addr, 0)
|
||||
else
|
||||
routeRequests[addr].timeout = computer.uptime()
|
||||
routeRequests[addr][#routeRequests[addr]+1] = {type = "D", data = data}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local function processRouteRequests(host, age, dist)
|
||||
if routeRequests[host] then
|
||||
age = age or (computer.uptime() - routeRequests[host].timeout)
|
||||
for t, request in pairs(routeRequests[host]) do
|
||||
if type(request) == "table" then
|
||||
if request.type == "D" then
|
||||
sendRoutedData(host, request.data)
|
||||
elseif request.type == "E" then
|
||||
if request.ttl-1 > 1 then
|
||||
sendRoutedDataAs(host, request.origin, request.data, request.ttl)
|
||||
end
|
||||
elseif request.type == "R" then
|
||||
sendHostFound(request.host, age, host, dist or 1)
|
||||
end
|
||||
end
|
||||
end
|
||||
routeRequests[host] = nil
|
||||
end
|
||||
end
|
||||
|
||||
local function checkRouteDest(dest, origin, node, data)
|
||||
local nodes = getNodes()
|
||||
if dest == nodes[node].selfAddr then
|
||||
return true
|
||||
elseif routes[dest] and routes[dest].thisHost then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
bindAddr = function(addr)
|
||||
routes[addr] = {thisHost=true, dist = 0}
|
||||
processRouteRequests(addr, 0, 1)
|
||||
end
|
||||
|
||||
kernel.modules.keventd.listen("hostname", function(_, name) bindAddr(name)end)
|
||||
|
||||
dataHandler = function(data, node, origin)
|
||||
if data:sub(1,1) == "D" then --Direct data
|
||||
onRecv(origin, data:sub(3))
|
||||
elseif data:sub(1,1) == "E" then --Routed data
|
||||
--local ttl = data:byte(2)
|
||||
--local dest, destlen = readSizeStr(data, 3)
|
||||
--local orig, origlen = readSizeStr(data, 3+destlen)
|
||||
local ttl, dest, orig, dstart = string.unpack(">Bs1s1", data, 2)
|
||||
local dat = data:sub(dstart)
|
||||
|
||||
|
||||
if checkRouteDest(dest, orig, node, dat) then
|
||||
onRecv(orig, dat)
|
||||
else
|
||||
local _node, driver = isAccessible(dest)
|
||||
if _node then --Have direct route
|
||||
if ttl-1 > 0 then
|
||||
kernel.io.println("Direct hop orig="..orig.." -> dest="..dest)
|
||||
sendRoutedDataAs(dest, orig, dat, ttl)
|
||||
end
|
||||
else
|
||||
if routes[dest] then --Have route
|
||||
if ttl-1 > 0 then
|
||||
sendRoutedDataAs(dest, orig, dat, ttl)
|
||||
routes[dest].active = computer.uptime()
|
||||
end
|
||||
else --Need to find route
|
||||
if not routeRequests[dest] then
|
||||
routeRequests[dest] = {update = computer.uptime(), timeout = computer.uptime()}
|
||||
end
|
||||
routeRequests[dest].timeout = computer.uptime()
|
||||
if not routeRequests[dest] then routeRequests[dest] = {update = computer.uptime(), timeout = computer.uptime()} end
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "E", origin = orig, ttl = ttl, data = dat}
|
||||
sendRouteRequest(dest, 0)
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif data:sub(1,1) == "R" then --Route request
|
||||
--local dest, l = readSizeStr(data, 3)
|
||||
local nttl, dest, age = string.unpack(">Bs1H", data, 2)
|
||||
if age > cfg.routereq_drop then
|
||||
return
|
||||
end
|
||||
if not routeRequests[dest] then
|
||||
|
||||
--check if accessible interface
|
||||
local nodes = getNodes()
|
||||
for _node, n in pairs(nodes) do
|
||||
if _node ~= node then --requested host won't ever be in same node
|
||||
for host in pairs(n.hosts)do
|
||||
if host == dest then
|
||||
--Found it!
|
||||
sendHostFound(origin, 0, dest, 1)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--check if route known
|
||||
if routes[dest] then
|
||||
if routes[dest].thisHost then
|
||||
--sendHostFound(origin, nodes[node].selfAddr)
|
||||
sendHostFound(origin, 0 , dest, 1)
|
||||
elseif routes[dest].router ~= origin then--Router might have rebooted and is asking about route
|
||||
sendHostFound(origin, computer.uptime() - routes[dest].age, dest, routes[dest].dist + 1)
|
||||
--routes[dest].active = computer.uptime()
|
||||
end
|
||||
return
|
||||
end
|
||||
|
||||
if isAccessible(dest) then
|
||||
kernel.io.println("Attempt to seek route to direct host(0x1WAT)")
|
||||
kernel.io.println("seeker " .. origin .. " to " .. dest)
|
||||
return
|
||||
end
|
||||
|
||||
routeRequests[dest] = {update = computer.uptime(), timeout = computer.uptime() - age}
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "R", host = origin}
|
||||
|
||||
--local nttl = data:byte(2)-1
|
||||
if nttl > 1 then
|
||||
local sent = {}
|
||||
--Bcast request
|
||||
for _node, n in pairs(nodes) do
|
||||
if _node ~= node then --We mustn't send it to origin node
|
||||
for host in pairs(n.hosts) do
|
||||
if not sent[host] then
|
||||
sent[host] = true
|
||||
--resend route request
|
||||
local msg = string.pack(">c1Bs1H", "R", nttl - 1, dest, age + cfg.routereq_relayage)
|
||||
_rawSend(host, _node, msg)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
sent = nil
|
||||
else
|
||||
if isAccessible(dest) then
|
||||
kernel.io.println("Attempt to seek route to direct host(0x2WAT)")
|
||||
kernel.io.println("seeker " .. origin .. " to " .. dest)
|
||||
return
|
||||
end
|
||||
--we've already requested this addr so if we get the route
|
||||
--we'll respond. TODO: Duplicates?
|
||||
if computer.uptime() - routeRequests[dest].timeout > age then
|
||||
routeRequests[dest].timeout = computer.uptime() - age
|
||||
end
|
||||
routeRequests[dest][#routeRequests[dest]+1] = {type = "R", host = origin}
|
||||
end
|
||||
elseif data:sub(1,1) == "H" then --Host found
|
||||
local nttl, age, dist, n = string.unpack(">BHB", data, 2)
|
||||
local host = data:sub(n)
|
||||
|
||||
if not isAccessible(host) then
|
||||
if not routes[host] then
|
||||
routes[host] = {
|
||||
router = origin,
|
||||
node = node,
|
||||
age = computer.uptime() - age,
|
||||
active = computer.uptime(),
|
||||
dist = dist
|
||||
}
|
||||
processRouteRequests(host, age, dist + 1)
|
||||
else
|
||||
if (routes[host].dist > dist) or
|
||||
((routes[host].age < computer.uptime() - age) and (routes[host].dist >= dist)) then
|
||||
routes[host] = {
|
||||
router = origin,
|
||||
node = node,
|
||||
age = computer.uptime() - age,
|
||||
active = routes[host].active,
|
||||
dist = dist
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--network.core.setCallback("send", send)
|
||||
--network.core.setCallback("bind", bindAddr)
|
||||
|
||||
---------------
|
||||
--Network stats&info
|
||||
|
||||
function getInfo()
|
||||
local res = {}
|
||||
|
||||
res.interfaces = {}
|
||||
for k, node in pairs(getNodes())do
|
||||
res.interfaces[k] = {selfAddr = node.selfAddr, linkName = node.linkName}
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function getRoutingTable()
|
||||
local res = {}
|
||||
local now = computer.uptime()
|
||||
|
||||
for k,v in pairs(routeRequests) do
|
||||
res[k] = {router = "", interface = "", age = now - v.timeout, dist = 0}
|
||||
end
|
||||
|
||||
for k,v in pairs(routes) do
|
||||
if v.router then
|
||||
res[k] = {router = v.router, interface = v.node, age = now - v.age, dist = v.dist}
|
||||
elseif v.thisHost then
|
||||
res[k] = {router = computer.address(), interface = "lo", age = 0, dist = 0}
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
function getArpTable(interface)
|
||||
local res = {}
|
||||
for k in pairs(nodes[interface].hosts)do
|
||||
table.insert(res, k)
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
--network.core.setCallback("netstat", getInfo)
|
||||
--network.core.setCallback("intstat", getInterfaceInfo)
|
||||
--network.core.setCallback("routetab", getRoutingTable)
|
||||
--network.core.setCallback("arptab", getArpTable)
|
||||
|
||||
--network.core.lockCore()
|
||||
|
||||
kernel.modules.timer.add(function()
|
||||
local now = computer.uptime()
|
||||
--Route request timeouts, re-requests
|
||||
for host, request in pairs(routeRequests) do
|
||||
if now - request.update >= cfg.routereq_retry then
|
||||
if routes[host] then
|
||||
processRouteRequests(host, now - routes[host].age, routes[host].dist + 1)
|
||||
else
|
||||
sendRouteRequest(host, now - request.update)
|
||||
request.update = computer.uptime()
|
||||
end
|
||||
end
|
||||
if now - request.timeout >= cfg.routereq_drop then
|
||||
routeRequests[host] = nil
|
||||
end
|
||||
end
|
||||
|
||||
--Route timeouts, rechecks,
|
||||
for host, route in pairs(routes) do
|
||||
if not route.thisHost then
|
||||
local age = now - route.age
|
||||
if age >= cfg.route_recheck then
|
||||
sendRouteRequest(host, 0)
|
||||
end
|
||||
if age >= cfg.route_age_max then
|
||||
routes[host] = nil
|
||||
else
|
||||
if now - route.active >= cfg.route_exp then
|
||||
routes[host] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end, 5)
|
||||
end
|
||||
|
@ -1,50 +1,34 @@
|
||||
programmers = {}
|
||||
local block = kernel.modules.block
|
||||
|
||||
local function buildDevfs()
|
||||
for file in pairs(kernel.modules.devfs.data) do
|
||||
if file:match("^nfc") then
|
||||
kernel.modules.devfs.data[file] = nil
|
||||
end
|
||||
end
|
||||
for k, nfc in ipairs(programmers) do
|
||||
kernel.modules.devfs.data["nfc" .. nfc:sub(1,4):upper()] = {
|
||||
__type = "f",
|
||||
open = function(hnd, mode)
|
||||
if mode == "r" then error("Invalid mode") end
|
||||
hnd.nfc = nfc
|
||||
end,
|
||||
size = function()
|
||||
return 2048
|
||||
end,
|
||||
write = function(h, data)
|
||||
if component.invoke(nfc, "isDataWaiting") then
|
||||
component.invoke(nfc, "clearNFCData")
|
||||
end
|
||||
component.invoke(nfc, "writeNFCData", data)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end
|
||||
local function buildDevice(uuid)
|
||||
return {
|
||||
__type = "f",
|
||||
open = function(hnd, mode)
|
||||
if mode == "r" then error("Invalid mode") end
|
||||
hnd.nfc = uuid
|
||||
end,
|
||||
size = function()
|
||||
return 2048
|
||||
end,
|
||||
write = function(h, data)
|
||||
if component.invoke(uuid, "isDataWaiting") then
|
||||
component.invoke(uuid, "clearNFCData")
|
||||
end
|
||||
component.invoke(uuid, "writeNFCData", data)
|
||||
return true
|
||||
end,
|
||||
}
|
||||
end
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "NFCProgrammer" then
|
||||
programmers[#programmers + 1] = address
|
||||
buildDevfs()
|
||||
block.register(address, "nfc" .. address:sub(1,4):upper(), buildDevice(address))
|
||||
end
|
||||
end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "NFCProgrammer" then
|
||||
local t
|
||||
for i, nfc in ipairs(programmers) do
|
||||
if nfc == address then
|
||||
t = i
|
||||
break
|
||||
end
|
||||
end
|
||||
table.remove(programmers, t)
|
||||
buildDevfs()
|
||||
block.unregister(address)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -1,78 +1,56 @@
|
||||
tapes = {}
|
||||
local block = kernel.modules.block
|
||||
|
||||
local function buildDevfs()
|
||||
for file in pairs(kernel.modules.devfs.data) do
|
||||
if file:match("^tape") then
|
||||
kernel.modules.devfs.data[file] = nil
|
||||
end
|
||||
end
|
||||
for k, tape in ipairs(tapes) do
|
||||
kernel.modules.devfs.data["tape" .. tape:sub(1,4):upper()] = {
|
||||
__type = "f",
|
||||
open = function(hnd)
|
||||
if not component.invoke(tape, "isReady") then
|
||||
error("Tape drive is not ready")
|
||||
end
|
||||
component.invoke(tape, "seek", -math.huge)
|
||||
hnd.tape = tape
|
||||
hnd.pos = 0
|
||||
end,
|
||||
size = function()
|
||||
return component.invoke(tape, "getSize")
|
||||
end,
|
||||
write = function(h, data)
|
||||
component.invoke(tape, "write", data)
|
||||
h.pos = h.pos + #data
|
||||
return not (h.pos >= component.invoke(tape, "getSize"))
|
||||
--TODO: do this correctly
|
||||
end,
|
||||
read = function(h, len)
|
||||
if h.pos >= component.invoke(tape, "getSize") then
|
||||
return
|
||||
end
|
||||
h.pos = h.pos + len
|
||||
return component.invoke(tape, "read", len)
|
||||
end,
|
||||
seek = function(h, whence, offset)
|
||||
if whence == "end" then
|
||||
h.pos = h.pos + component.invoke(tape, "seek", component.invoke(tape, "getSize") - h.pos - (offset or 0))
|
||||
elseif whence == "set" then
|
||||
h.pos = h.pos + component.invoke(tape, "seek", (offset or 0) - h.pos)
|
||||
else
|
||||
h.pos = h.pos + component.invoke(tape, "seek", offset or 0)
|
||||
end
|
||||
return math.floor(h.pos)
|
||||
local function buildDevice(tape)
|
||||
return {
|
||||
__type = "f",
|
||||
open = function(hnd)
|
||||
if not component.invoke(tape, "isReady") then
|
||||
error("Tape drive is not ready")
|
||||
end
|
||||
}
|
||||
end
|
||||
component.invoke(tape, "seek", -math.huge)
|
||||
hnd.tape = tape
|
||||
hnd.pos = 0
|
||||
end,
|
||||
size = function()
|
||||
return component.invoke(tape, "getSize")
|
||||
end,
|
||||
write = function(h, data)
|
||||
component.invoke(tape, "write", data)
|
||||
h.pos = h.pos + #data
|
||||
return not (h.pos >= component.invoke(tape, "getSize"))
|
||||
--TODO: do this correctly
|
||||
end,
|
||||
read = function(h, len)
|
||||
if h.pos >= component.invoke(tape, "getSize") then
|
||||
return
|
||||
end
|
||||
h.pos = h.pos + len
|
||||
return component.invoke(tape, "read", len)
|
||||
end,
|
||||
seek = function(h, whence, offset)
|
||||
if whence == "end" then
|
||||
h.pos = h.pos + component.invoke(tape, "seek", component.invoke(tape, "getSize") - h.pos - (offset or 0))
|
||||
elseif whence == "set" then
|
||||
h.pos = h.pos + component.invoke(tape, "seek", (offset or 0) - h.pos)
|
||||
else
|
||||
h.pos = h.pos + component.invoke(tape, "seek", offset or 0)
|
||||
end
|
||||
return math.floor(h.pos)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
local function onComponentAdded(_, address, componentType)
|
||||
if componentType == "tape_drive" then
|
||||
tapes[#tapes + 1] = address
|
||||
buildDevfs()
|
||||
block.register(address, "tape" .. address:sub(1,4):upper(), buildDevice(address))
|
||||
end
|
||||
end
|
||||
|
||||
local function onComponentRemoved(_, address, componentType)
|
||||
if componentType == "tape_drive" then
|
||||
local t
|
||||
for i, tape in ipairs(tapes) do
|
||||
if tape == address then
|
||||
t = i
|
||||
break
|
||||
end
|
||||
end
|
||||
table.remove(tapes, t)
|
||||
buildDevfs()
|
||||
block.unregister(address)
|
||||
end
|
||||
end
|
||||
|
||||
--function start()
|
||||
-- for tape, t in component.list("tape_drive") do
|
||||
-- onComponentAdded(_, tape, t)
|
||||
-- end
|
||||
--end
|
||||
|
||||
kernel.modules.keventd.listen("component_added", onComponentAdded)
|
||||
kernel.modules.keventd.listen("component_removed", onComponentRemoved)
|
||||
|
@ -1,279 +0,0 @@
|
||||
--local event = require "event"
|
||||
|
||||
local driver
|
||||
|
||||
network = {}
|
||||
internal = {}
|
||||
|
||||
|
||||
------------
|
||||
--ICMP
|
||||
|
||||
network.icmp = {}
|
||||
internal.icmp = {}
|
||||
|
||||
local pingid = 0
|
||||
function network.icmp.ping(addr, payload)
|
||||
pingid = pingid + 1
|
||||
driver.send(addr, "IP"..computer.address()..":"..tostring(pingid)..":"..payload)
|
||||
return pingid
|
||||
end
|
||||
|
||||
function internal.icmp.handle(origin, data)
|
||||
if data:sub(2,2) == "P" then
|
||||
local matcher = data:sub(3):gmatch("[^:]+")
|
||||
local compid = matcher()
|
||||
local id = tonumber(matcher())
|
||||
local payload = matcher()
|
||||
if compid == computer.address() then
|
||||
computer.pushSignal("ping_reply", origin, tonumber(id), payload)
|
||||
else
|
||||
driver.send(origin, data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
------------
|
||||
--Datagrams - UDP like protocol
|
||||
|
||||
network.udp = {}
|
||||
internal.udp = {ports = {}}
|
||||
|
||||
function internal.udp.checkPortRange(port)
|
||||
if port < 0 or port > 65535 then error("Wrong port!")end
|
||||
end
|
||||
|
||||
function network.udp.open(port)
|
||||
if not port then
|
||||
port = 49151 + math.floor(math.random() * 16384)
|
||||
--TODO: check allocated port
|
||||
end
|
||||
internal.udp.checkPortRange(port)
|
||||
if kernel.modules.threading.currentThread then
|
||||
internal.udp.ports[port] = kernel.modules.threading.currentThread.pid
|
||||
else
|
||||
internal.udp.ports[port] = true
|
||||
end
|
||||
return port
|
||||
end
|
||||
|
||||
function network.udp.close(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.udp.ports[port] = nil
|
||||
end
|
||||
|
||||
function network.udp.send(addr, port, data)
|
||||
internal.udp.checkPortRange(port)
|
||||
driver.send(addr, "D".. string.char(math.floor(port/256))..string.char(port%256)..data)
|
||||
end
|
||||
|
||||
function internal.udp.handle(origin, data)
|
||||
local port = data:byte(2)*256 + data:byte(3)
|
||||
if internal.udp.ports[port] then
|
||||
computer.pushSignal("datagram", origin, port, data:sub(4))
|
||||
end
|
||||
end
|
||||
|
||||
function internal.udp.cleanProcess(thread)
|
||||
for port, pid in pairs(internal.udp.ports) do
|
||||
if pid == thread.pid then
|
||||
internal.udp.ports[port] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------
|
||||
--TCP - TCP like protocol
|
||||
|
||||
--O[port,2B][openers channel,2B] --Try open connection
|
||||
--A[opened channel,2B][openers channel,2B] --Accept connection
|
||||
--R[openers channel,2B] --Reject connection i.e. closed port
|
||||
--C[remote channel,2B] --Close connection(user request or adta at closed/wrong channel)
|
||||
--D[remote channel,2B][data] --Data
|
||||
|
||||
network.tcp = {}
|
||||
internal.tcp = {ports = {}, channels = {}, freeCh = 1}
|
||||
|
||||
function network.tcp.listen(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
if kernel.modules.threading.currentThread then
|
||||
internal.tcp.ports[port] = kernel.modules.threading.currentThread.pid
|
||||
else
|
||||
internal.tcp.ports[port] = true
|
||||
end
|
||||
end
|
||||
|
||||
function network.tcp.unlisten(port)
|
||||
internal.udp.checkPortRange(port)
|
||||
internal.tcp.ports[port] = nil
|
||||
end
|
||||
|
||||
function network.tcp.open(addr, port)
|
||||
if not port then
|
||||
port = 49151 + math.floor(math.random() * 16384)
|
||||
--TODO: check allocated port
|
||||
end
|
||||
internal.udp.checkPortRange(port)
|
||||
local ch = internal.tcp.freeCh
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].next then
|
||||
internal.tcp.freeCh = internal.tcp.channels[ch].next
|
||||
else
|
||||
internal.tcp.freeCh = #internal.tcp.channels+2
|
||||
end
|
||||
--kernel.io.println("TCP: use ch " .. ch)
|
||||
internal.tcp.channels[ch] = {open = false, waiting = true, addr = addr, port = port}--mark openning
|
||||
if kernel.modules.threading.currentThread then
|
||||
internal.tcp.channels[ch].owner = kernel.modules.threading.currentThread.pid
|
||||
end
|
||||
driver.send(addr, "TO".. string.char(math.floor(port/256))..string.char(port%256).. string.char(math.floor(ch/256))..string.char(ch%256))
|
||||
return ch
|
||||
end
|
||||
|
||||
function network.tcp.close(channel)
|
||||
if internal.tcp.channels[channel] then
|
||||
if internal.tcp.channels[channel].open or internal.tcp.channels[channel].waiting then
|
||||
driver.send(internal.tcp.channels[channel].addr, "TC".. string.char(math.floor(internal.tcp.channels[channel].remote/256))..string.char(internal.tcp.channels[channel].remote%256))
|
||||
end
|
||||
internal.tcp.channels[channel] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = channel
|
||||
--computer.pushSignal("tcp_close", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
end
|
||||
|
||||
function network.tcp.send(channel, data)
|
||||
if internal.tcp.channels[channel] and internal.tcp.channels[channel].open then
|
||||
driver.send(internal.tcp.channels[channel].addr, "TD".. string.char(math.floor(internal.tcp.channels[channel].remote/256))..string.char(internal.tcp.channels[channel].remote%256)..data)
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function internal.tcp.handle(origin, data)
|
||||
if data:sub(2,2) == "O" then
|
||||
local port = data:byte(3)*256 + data:byte(4)
|
||||
local rchan = data:byte(5)*256 + data:byte(6)
|
||||
|
||||
if internal.tcp.ports[port] then
|
||||
local ch = internal.tcp.freeCh
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].next then
|
||||
internal.tcp.freeCh = internal.tcp.channels[ch].next
|
||||
else
|
||||
internal.tcp.freeCh = #internal.tcp.channels+2
|
||||
end
|
||||
--kernel.io.println("TCP: use ch " .. ch)
|
||||
internal.tcp.channels[ch] = {open = true, remote = rchan, addr = origin, port = port}
|
||||
if type(internal.tcp.ports[port]) == "number" then
|
||||
internal.tcp.channels[ch].owner = internal.tcp.ports[port]
|
||||
end
|
||||
driver.send(origin, "TA".. string.char(math.floor(ch/256))..string.char(ch%256) .. string.char(math.floor(rchan/256)) .. string.char(rchan%256))
|
||||
computer.pushSignal("tcp", "connection", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port, "incoming")
|
||||
else
|
||||
driver.send(origin, "TR".. string.char(math.floor(rchan/256))..string.char(rchan%256))
|
||||
end
|
||||
elseif data:sub(2,2) == "R" then
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].waiting then
|
||||
computer.pushSignal("tcp" ,"close", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
internal.tcp.channels[ch] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = ch
|
||||
end
|
||||
elseif data:sub(2,2) == "A" then
|
||||
local remote = data:byte(3)*256 + data:byte(4)
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].waiting then
|
||||
internal.tcp.channels[ch].waiting = nil
|
||||
internal.tcp.channels[ch].open = true
|
||||
internal.tcp.channels[ch].remote = remote
|
||||
computer.pushSignal("tcp", "connection", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
elseif data:sub(2,2) == "C" then
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].open then
|
||||
internal.tcp.channels[ch] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = ch
|
||||
computer.pushSignal("tcp" ,"close", ch, internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
elseif data:sub(2,2) == "D" then --TODO: check source
|
||||
local ch = data:byte(3)*256 + data:byte(4)
|
||||
if internal.tcp.channels[ch] and internal.tcp.channels[ch].open then
|
||||
computer.pushSignal("tcp", "message", ch, data:sub(5), internal.tcp.channels[ch].addr, internal.tcp.channels[ch].port)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function internal.tcp.cleanup()
|
||||
for channel, _ in pairs(internal.tcp.channels) do
|
||||
if internal.tcp.channels[channel].open or internal.tcp.channels[channel].waiting then
|
||||
if internal.tcp.channels[channel].open or internal.tcp.channels[channel].waiting then
|
||||
driver.send(internal.tcp.channels[channel].addr, "TC".. string.char(math.floor(internal.tcp.channels[channel].remote/256))..string.char(internal.tcp.channels[channel].remote%256))
|
||||
end
|
||||
internal.tcp.channels[channel] = {next = internal.tcp.freeCh}
|
||||
internal.tcp.freeCh = channel
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function internal.tcp.cleanProcess(thread)
|
||||
for channel, _ in pairs(internal.tcp.channels) do
|
||||
if internal.tcp.channels[channel].owner == thread.pid then
|
||||
network.tcp.close(channel)
|
||||
end
|
||||
end
|
||||
for port, pid in pairs(internal.tcp.ports) do
|
||||
if pid == thread.pid then
|
||||
internal.tcp.ports[port] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-----------
|
||||
--IP
|
||||
|
||||
network.ip = {}
|
||||
|
||||
function network.ip.bind(addr)
|
||||
driver.bind(addr)
|
||||
end
|
||||
|
||||
------------
|
||||
--Data processing
|
||||
|
||||
function handleData(origin, data)
|
||||
if data:sub(1,1) == "I" then internal.icmp.handle(origin, data)
|
||||
elseif data:sub(1,1) == "T" then internal.tcp.handle(origin, data)
|
||||
elseif data:sub(1,1) == "D" then internal.udp.handle(origin, data) end
|
||||
end
|
||||
|
||||
|
||||
------------
|
||||
--Info
|
||||
|
||||
network.info = {}
|
||||
network.info.getInfo = function(...)return driver.netstat(...) end
|
||||
network.info.getInterfaceInfo = function(...)return driver.intstat(...) end
|
||||
network.info.getRoutes = function(...)return driver.routetab(...) end
|
||||
network.info.getArpTable = function(...)return driver.arptab(...) end
|
||||
|
||||
------------
|
||||
|
||||
kernel.userspace.package.preload.network = network
|
||||
|
||||
function start()
|
||||
driver = {
|
||||
send = kernel.modules.network.send,
|
||||
bind = kernel.modules.network.bindAddr,
|
||||
netstat = kernel.modules.network.getInfo,
|
||||
intstat = kernel.modules.network.getInterfaceInfo,
|
||||
routetab = kernel.modules.network.getRoutingTable,
|
||||
arptab = kernel.modules.network.getArpTable,
|
||||
}
|
||||
|
||||
kernel.modules.gc.onShutdown(function()
|
||||
internal.tcp.cleanup()
|
||||
end)
|
||||
|
||||
kernel.modules.gc.onProcessKilled(function(thread)
|
||||
internal.tcp.cleanProcess(thread)
|
||||
internal.udp.cleanProcess(thread)
|
||||
end)
|
||||
end
|
@ -1,36 +1,39 @@
|
||||
threads = {}
|
||||
currentThread = nil
|
||||
eventFilters = {signal = {}}
|
||||
|
||||
local threadMode = {
|
||||
top = 0,
|
||||
child = 1
|
||||
}
|
||||
|
||||
local function getPendingThreads()
|
||||
local res = {}
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro and #thread.eventQueue > 0 then
|
||||
res[#res + 1] = thread
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
local function getResumableThreads(threads_)
|
||||
local res = {}
|
||||
for _,thread in ipairs(threads_) do
|
||||
for n,event in ipairs(thread.eventQueue) do
|
||||
if event[1] == thread.currentHandler then
|
||||
table.remove(thread.eventQueue, n)
|
||||
thread.currentEvent = event
|
||||
res[#res + 1] = thread
|
||||
break
|
||||
function countThreadSignals(thread, signal)
|
||||
local n = 0
|
||||
local first = 0
|
||||
for i, sig in ipairs(thread.eventQueue) do
|
||||
if sig[1] == signal then
|
||||
n = n + 1
|
||||
if first < 1 then
|
||||
first = i
|
||||
end
|
||||
end
|
||||
end
|
||||
return res
|
||||
return n, first
|
||||
end
|
||||
|
||||
local deadline = math.huge
|
||||
local pullSignal = computer.pullSignal
|
||||
computer.pullSignal = function()
|
||||
pcall(kernel._println, "Attempted to use non threaded signal pulling")
|
||||
pcall(kernel._println, debug.traceback())
|
||||
kernel.panic()
|
||||
end
|
||||
|
||||
function eachThread(func)
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro then
|
||||
func(thread)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--------------
|
||||
|
||||
local firstFree = 1
|
||||
local nextUid = 1
|
||||
|
||||
@ -77,6 +80,7 @@ function spawn(exec, child, name, isthread, _, ...)
|
||||
end)}
|
||||
return table.unpack(r, 2)
|
||||
end),
|
||||
deadline = computer.uptime(),
|
||||
sandbox = isthread and currentThread.sandbox or kernel.modules.manageg.newsandbox(),
|
||||
currentHandler = "arg",
|
||||
currentHandlerArg = nil,
|
||||
@ -113,76 +117,106 @@ function spawn(exec, child, name, isthread, _, ...)
|
||||
terminate = kill
|
||||
}
|
||||
|
||||
kernel.io.debug("Spawn thread " .. tostring(name))
|
||||
|
||||
return thread
|
||||
end
|
||||
|
||||
function countThreadSignals(thread, signal)
|
||||
local n = 0
|
||||
local first = 0
|
||||
for i, sig in ipairs(thread.eventQueue) do
|
||||
if sig[1] == signal then
|
||||
n = n + 1
|
||||
if first < 1 then
|
||||
first = i
|
||||
end
|
||||
---
|
||||
|
||||
local function getPendingThreads()
|
||||
local res = {}
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro then
|
||||
res[#res + 1] = thread
|
||||
end
|
||||
end
|
||||
return n, first
|
||||
return res
|
||||
end
|
||||
|
||||
local deadline = math.huge
|
||||
local pullSignal = computer.pullSignal
|
||||
computer.pullSignal = function()
|
||||
pcall(kernel._println, "Attempted to use non threaded signal pulling")
|
||||
pcall(kernel._println, debug.traceback())
|
||||
kernel.panic()
|
||||
local function getResumableThreads(threads_)
|
||||
local res = {}
|
||||
for _,thread in ipairs(threads_) do
|
||||
thread.currentEvent = nil
|
||||
for n,event in ipairs(thread.eventQueue) do
|
||||
if event[1] == thread.currentHandler then
|
||||
table.remove(thread.eventQueue, n)
|
||||
thread.currentEvent = event
|
||||
res[#res + 1] = thread
|
||||
break
|
||||
end
|
||||
end
|
||||
if not thread.currentEvent and thread.deadline <= computer.uptime() then
|
||||
thread.currentEvent = {"timeout"}
|
||||
res[#res + 1] = thread
|
||||
end
|
||||
end
|
||||
return res
|
||||
end
|
||||
|
||||
|
||||
local function processSignals()
|
||||
deadline = math.huge
|
||||
for _, thread in ipairs(threads) do
|
||||
if (thread.currentHandler == "yield" or thread.currentHandler == "signal")
|
||||
and deadline > (tonumber(thread.currentHandlerArg) or math.huge) then
|
||||
deadline = thread.currentHandlerArg or math.huge
|
||||
if deadline > (thread.deadline or math.huge) then
|
||||
if not thread.deadline then
|
||||
kernel.io.println("Nil deadline for " .. thread.name .. " on " .. tostring(thread.currentHandler))
|
||||
end
|
||||
deadline = thread.deadline
|
||||
end
|
||||
end
|
||||
--kernel.io.println("Deadline: "..(deadline - computer.uptime()))
|
||||
--kernel.io.debug("Pull deadline: "..(deadline - computer.uptime()))
|
||||
local sig = {"signal", pullSignal(deadline - computer.uptime())}
|
||||
|
||||
local function filt(f, signal, ...)
|
||||
if not signal then
|
||||
return true
|
||||
end
|
||||
if type(f[signal]) == "table" then
|
||||
return filt(f[signal], ...)
|
||||
end
|
||||
return (not f[signal]) and true or (function(...)
|
||||
local s, e = xpcall(f[signal], function(err)
|
||||
kernel._println("Signal filter error:")
|
||||
kernel._println(tostring(e))
|
||||
kernel._println(debug.traceback())
|
||||
kernel.panic("Signal filtering failed")
|
||||
end, ...)
|
||||
return s and e
|
||||
end)(...)
|
||||
end
|
||||
if not filt(eventFilters, table.unpack(sig)) then
|
||||
sig = {}
|
||||
end
|
||||
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro then
|
||||
local nsig, oldest = countThreadSignals(thread, "signal")
|
||||
if nsig > thread.maxPendingSignals then --TODO: make it a bit more intelligent
|
||||
table.remove(thread.eventQueue, oldest)
|
||||
end
|
||||
if thread.currentHandler == "yield" then
|
||||
--[[if thread.currentHandler == "yield" then
|
||||
--kernel.io.println("yield ck: "..tostring((thread.currentHandlerArg or math.huge) - computer.uptime()))
|
||||
if (thread.currentHandlerArg or math.huge) <= computer.uptime() then
|
||||
thread.eventQueue[#thread.eventQueue + 1] = {"yield"}
|
||||
end
|
||||
end
|
||||
if thread.cgroups.signal.global then
|
||||
end]]--
|
||||
if thread.cgroups.signal.global and sig[2] then
|
||||
local nsig, oldest = countThreadSignals(thread, "signal")
|
||||
if nsig > thread.maxPendingSignals then --TODO: make it a bit more intelligent
|
||||
table.remove(thread.eventQueue, oldest)
|
||||
end
|
||||
|
||||
thread.eventQueue[#thread.eventQueue + 1] = sig
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function eachThread(func)
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro then
|
||||
func(thread)
|
||||
end
|
||||
end
|
||||
end
|
||||
----
|
||||
|
||||
local lastYield = computer.uptime()
|
||||
|
||||
yieldTime = 3
|
||||
function checkTimeout()
|
||||
local uptime = computer.uptime()
|
||||
|
||||
if uptime - lastYield > 3 then
|
||||
if uptime - lastYield > yieldTime then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
@ -190,27 +224,8 @@ end
|
||||
|
||||
function start()
|
||||
while true do
|
||||
-- pending = getPendingThreads()
|
||||
--local resumable = getResumableThreads(pending)
|
||||
|
||||
local pending = {}
|
||||
for _, thread in ipairs(threads) do
|
||||
if thread.coro and #thread.eventQueue > 0 then
|
||||
pending[#pending + 1] = thread
|
||||
end
|
||||
end
|
||||
|
||||
local resumable = {}
|
||||
for _,thread in ipairs(pending) do
|
||||
for n,event in ipairs(thread.eventQueue) do
|
||||
if event[1] == thread.currentHandler then
|
||||
table.remove(thread.eventQueue, n)
|
||||
thread.currentEvent = event
|
||||
resumable[#resumable + 1] = thread
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
local pending = getPendingThreads()
|
||||
local resumable = getResumableThreads(pending)
|
||||
|
||||
lastYield = computer.uptime()
|
||||
while #resumable > 0 do
|
||||
@ -218,7 +233,8 @@ function start()
|
||||
--kernel.io.println("Resume " .. tostring(thread.name) .. " with "
|
||||
-- .. tostring(type(thread.currentEvent) == "table" and thread.currentEvent[1] or "unknown")
|
||||
-- ..(thread.currentEvent[2] and (", " .. tostring(thread.currentEvent[2])) or ""))
|
||||
|
||||
|
||||
thread.deadline = math.huge
|
||||
kernel.modules.manageg.protect(thread.sandbox)
|
||||
currentThread = thread
|
||||
local state, reason, arg = coroutine.resume(thread.coro, table.unpack(thread.currentEvent, 2))
|
||||
@ -228,11 +244,12 @@ function start()
|
||||
if not state or coroutine.status(thread.coro) == "dead" then
|
||||
kill(thread.pid)
|
||||
if reason then
|
||||
kernel.io.println("Thread " .. tostring(thread.name) .. "(" .. tostring(thread.pid) .. ") dead: "
|
||||
kernel.io.println("Thread " .. tostring(thread.name) .. "(" .. tostring(thread.pid) .. ") died: "
|
||||
.. tostring(reason or "unknown/done") .. ", after "
|
||||
.. tostring(type(thread.currentEvent) == "table" and thread.currentEvent[1] or "unknown"))
|
||||
end
|
||||
else
|
||||
--kernel.io.println("Yield arg from " .. tostring(thread.name) .. ": " .. tostring(arg))
|
||||
thread.currentEvent = nil
|
||||
thread.currentHandler = reason
|
||||
thread.currentHandlerArg = arg
|
||||
|
@ -43,6 +43,16 @@ function userKill(pid, signal, ...)
|
||||
return true
|
||||
end
|
||||
|
||||
function select(timeout, ...)
|
||||
checkArg(1, timeout, "number")
|
||||
local funcs = {}
|
||||
for n, f in ipairs(...) do
|
||||
checkArg(n + 1, f, "function")
|
||||
funcs[n] = coroutine.create(f)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function setKillHandler(signal, handler) --WAT
|
||||
if not kernel.modules.threading.threads[pid]
|
||||
or not kernel.modules.threading.threads[pid].coro then
|
||||
|
@ -14,7 +14,7 @@ function add(func, time)
|
||||
if deadline > timer.next then
|
||||
deadline = timer.next
|
||||
if thread.currentHandler == "yield" then
|
||||
thread.currentHandlerArg = deadline
|
||||
thread.deadline = deadline
|
||||
end
|
||||
end
|
||||
|
||||
@ -66,9 +66,9 @@ thread = kernel.modules.threading.spawn(function()
|
||||
end
|
||||
end
|
||||
end
|
||||
local dl = deadline
|
||||
thread.deadline = deadline
|
||||
deadline = math.huge
|
||||
coroutine.yield("yield", dl)
|
||||
coroutine.yield("yield")
|
||||
end
|
||||
end, 0, "[timer]")
|
||||
|
||||
|
@ -1,26 +0,0 @@
|
||||
local driver = {}
|
||||
|
||||
local pktIn,pktOut,bytesIn,bytesOut = 0,0,0,0
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHandler.newInterface("lo", "localhost", "Local Loopback")
|
||||
eventHandler.newHost("lo", "localhost")
|
||||
return {send = function(data)eventHandler.recvData(data, "lo", "localhost")end}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if interface == "lo" and destination == "localhost" then
|
||||
pktIn, pktOut = pktIn+1,pktOut+1
|
||||
bytesIn,bytesOut = bytesIn + data:len(), bytesOut + data:len()
|
||||
handle.send(data)
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if interface == "lo" then
|
||||
return pktIn,pktOut,bytesIn,bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
@ -1,94 +0,0 @@
|
||||
--[[
|
||||
Communication on port 1!
|
||||
Node protocol:
|
||||
Hello/broadcast(sent by new host in node): \0 (modem addersses are in event)
|
||||
Hi/direct(sent by hosts to new host): \1 (^)
|
||||
OHAI/direct(Ack of Hi(\1)) \2
|
||||
Host quitting/broadcast \3 (^)
|
||||
Data/direct \4[data] (origin from event)
|
||||
]]
|
||||
local driver = {}
|
||||
|
||||
local nodes = {}
|
||||
local eventHnd
|
||||
|
||||
local PKT_BEACON = "\32"
|
||||
local PKT_REGISTER = "\1"
|
||||
local PKT_REGISTER_ACK = "\2"
|
||||
local PKT_QUIT = "\3"
|
||||
local PKT_DATA = "\4"
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHnd = eventHandler
|
||||
|
||||
eventHandler.setListener("modem_message", function(_, interface, origin, port, _, data)
|
||||
if not nodes[interface] then return end --other kind of modem(possibly tunnel)
|
||||
|
||||
eventHandler.debug("modemmsg["..nodes[interface].name.."]/"..origin..":"..data)
|
||||
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
|
||||
if data:sub(1,1) == PKT_BEACON then
|
||||
component.invoke(interface, "send", origin, 1, PKT_REGISTER )
|
||||
elseif data:sub(1,1) == PKT_REGISTER then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
component.invoke(interface, "send", origin, 1, PKT_REGISTER_ACK)
|
||||
elseif data:sub(1,1) == PKT_REGISTER_ACK then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == PKT_QUIT then
|
||||
eventHandler.delHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == PKT_DATA then
|
||||
eventHandler.recvData(data:sub(2), nodes[interface].name, origin)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
eventHandler.setListener("component_added", function(_, int, ctype)
|
||||
if ctype ~= "modem" then return end
|
||||
local name = "eth" .. int:sub(1, 4):upper()
|
||||
eventHandler.newInterface(name, int, "Ethernet")
|
||||
|
||||
nodes[name] = {modem = int, name = name, pktIn = 0, pktOut = 1, bytesIn = 0, bytesOut = 1}
|
||||
nodes[int] = nodes[name]
|
||||
|
||||
component.invoke(int, "open", 1)
|
||||
component.invoke(int, "broadcast", 1, PKT_BEACON)
|
||||
|
||||
eventHandler.newHost(name, int)--register loopback
|
||||
end)
|
||||
|
||||
eventHandler.setListener("component_removed", function(_, int, ctype)
|
||||
if ctype ~= "modem" then return end
|
||||
local name = "eth" .. int:sub(1, 4):upper()
|
||||
nodes[name] = nil
|
||||
nodes[int] = nil
|
||||
eventHnd.delInterface(int)
|
||||
end)
|
||||
return {}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if nodes[interface] then
|
||||
if nodes[interface].modem == destination then
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + data:len()
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
eventHnd.recvData(data, interface, destination)
|
||||
else
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + 1 + data:len()
|
||||
component.invoke(nodes[interface].modem, "send", destination, 1, PKT_DATA..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].pktIn,nodes[interface].pktOut,nodes[interface].bytesIn,nodes[interface].bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
@ -1,72 +0,0 @@
|
||||
--For protocol info look to at modem driver
|
||||
|
||||
local driver = {}
|
||||
|
||||
local nodes = {}
|
||||
local eventHnd
|
||||
|
||||
function driver.start(eventHandler)
|
||||
eventHnd = eventHandler
|
||||
|
||||
eventHandler.setListener("modem_message", function(_, interface, origin, port, _, data)
|
||||
if not nodes[interface] then return end --other kind of modem(possibly modem)
|
||||
|
||||
eventHandler.debug("modemmsg["..nodes[interface].name.."]/"..origin..":"..data)
|
||||
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
|
||||
if data:sub(1,1) == "H" then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
component.invoke(interface, "send", "I")
|
||||
eventHandler.debug("REPL:",interface,origin)
|
||||
elseif data:sub(1,1) == "I"then
|
||||
eventHandler.newHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "Q"then
|
||||
eventHandler.delHost(nodes[interface].name, origin)
|
||||
elseif data:sub(1,1) == "D"then
|
||||
eventHandler.recvData(data:sub(2), nodes[interface].name, origin)
|
||||
end
|
||||
|
||||
end)
|
||||
|
||||
for int in component.list("tunnel", true)do
|
||||
eventHandler.newInterface("tun" .. int:sub(1, 4):upper(), int, "Tunnel")
|
||||
|
||||
nodes["tun" .. int:sub(1, 4):upper()] = {modem = int, name = "tun" .. int:sub(1, 4):upper(), pktIn = 0, pktOut = 1, bytesIn = 0, bytesOut = 1}
|
||||
nodes[int] = nodes["tun" .. int:sub(1, 4):upper()]
|
||||
|
||||
component.invoke(int, "send", "H")
|
||||
|
||||
eventHandler.newHost("tun" .. int:sub(1, 4):upper(), int)--register loopback
|
||||
end
|
||||
|
||||
--eventHandler.newInterface("lo", "localhost", "Local Loopback")
|
||||
--eventHandler.newHost("lo", "localhost")
|
||||
return {}
|
||||
end
|
||||
|
||||
function driver.send(handle, interface, destination, data)
|
||||
if nodes[interface] then
|
||||
if nodes[interface].modem == destination then
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + data:len()
|
||||
nodes[interface].pktIn = nodes[interface].pktIn + 1
|
||||
nodes[interface].bytesIn = nodes[interface].bytesIn + data:len()
|
||||
eventHnd.recvData(data, interface, destination)
|
||||
else
|
||||
nodes[interface].pktOut = nodes[interface].pktOut + 1
|
||||
nodes[interface].bytesOut = nodes[interface].bytesOut + 1 + data:len()
|
||||
component.invoke(nodes[interface].modem, "send", "D"..data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function driver.info(interface)
|
||||
if nodes[interface] then
|
||||
return nodes[interface].pktIn,nodes[interface].pktOut,nodes[interface].bytesIn,nodes[interface].bytesOut
|
||||
end
|
||||
return 0,0,0,0
|
||||
end
|
||||
|
||||
return driver
|
@ -0,0 +1,62 @@
|
||||
local sides = {
|
||||
[0] = "bottom",
|
||||
[1] = "top",
|
||||
[2] = "back",
|
||||
[3] = "front",
|
||||
[4] = "right",
|
||||
[5] = "left",
|
||||
[6] = "unknown",
|
||||
|
||||
bottom = 0,
|
||||
top = 1,
|
||||
back = 2,
|
||||
front = 3,
|
||||
right = 4,
|
||||
left = 5,
|
||||
unknown = 6,
|
||||
|
||||
down = 0,
|
||||
up = 1,
|
||||
north = 2,
|
||||
south = 3,
|
||||
west = 4,
|
||||
east = 5,
|
||||
|
||||
negy = 0,
|
||||
posy = 1,
|
||||
negz = 2,
|
||||
posz = 3,
|
||||
negx = 4,
|
||||
posx = 5,
|
||||
|
||||
forward = 3
|
||||
}
|
||||
|
||||
local metatable = getmetatable(sides) or {}
|
||||
|
||||
-- sides[0..5] are mapped to itertable[1..6].
|
||||
local itertable = {
|
||||
sides[0],
|
||||
sides[1],
|
||||
sides[2],
|
||||
sides[3],
|
||||
sides[4],
|
||||
sides[5]
|
||||
}
|
||||
|
||||
-- Future-proofing against the possible introduction of additional
|
||||
-- logical sides (e.g. [7] = "all", [8] = "none", etc.).
|
||||
function metatable.__len(sides)
|
||||
return #itertable
|
||||
end
|
||||
|
||||
-- Allow `sides` to be iterated over like a normal (1-based) array.
|
||||
function metatable.__ipairs(sides)
|
||||
return ipairs(itertable)
|
||||
end
|
||||
|
||||
setmetatable(sides, metatable)
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
return sides
|
@ -1,3 +1,5 @@
|
||||
local component = require "component"
|
||||
|
||||
local term = {}
|
||||
|
||||
term.escape = "\x1b"
|
||||
@ -278,6 +280,10 @@ function term.getInfo()
|
||||
return gpu, screen
|
||||
end
|
||||
|
||||
function term.gpu()
|
||||
local addr = term.getInfo()
|
||||
return component.proxy(addr)
|
||||
end
|
||||
|
||||
|
||||
function term.clear()
|
||||
@ -317,7 +323,15 @@ function term.isAvailable()
|
||||
end
|
||||
|
||||
function term.setCursorBlink(enabled)
|
||||
if enabled then
|
||||
io.write("\x1b[?25h")
|
||||
else
|
||||
io.write("\x1b[?25l")
|
||||
end
|
||||
end
|
||||
|
||||
function term.getCursorBlink(enabled)
|
||||
return true
|
||||
end
|
||||
|
||||
function term.read(history, dobreak, hint, pwchar)
|
||||
@ -436,7 +450,7 @@ function term.read(history, dobreak, hint, pwchar)
|
||||
--x = x
|
||||
io.write("\x1b[K" .. after .. "\x1b[" .. unicode.len(after) .. "D")
|
||||
end
|
||||
elseif mode == "0" then
|
||||
elseif mode == "O" then
|
||||
local act = io.read(1)
|
||||
if act == "H" then
|
||||
io.write("\x1b["..(x - 1).."D")
|
||||
|
@ -0,0 +1,47 @@
|
||||
--[[ go, makes the robot go a specified number of blocks in a certain direction or turn around.
|
||||
Author: Vexatos
|
||||
]]
|
||||
local robot=require("robot")
|
||||
local shell=require("shell")
|
||||
local args = shell.parse(...)
|
||||
if #args<1 then
|
||||
print("'go' - Makes the robot go in a certain direction")
|
||||
print("Usage:")
|
||||
print("'go forward [number]' to make the robot go forward a number of blocks (defaults to 1)")
|
||||
print("'go back [number]' to make the robot go backwards")
|
||||
print("'go up [number]' to make the robot go upwards")
|
||||
print("'go down [number]' to make the robot go downwards")
|
||||
print("'go left [number]' to make the robot turn left a number of times")
|
||||
print("'go right [number]' to make the robot turn right a number of times")
|
||||
return
|
||||
end
|
||||
local distance = args[2] or 1
|
||||
|
||||
if not tonumber(distance) or tonumber(distance) <= 0 then
|
||||
io.stderr:write(distance..": not a positive number!\n")
|
||||
return
|
||||
end
|
||||
|
||||
distance = math.floor(tonumber(distance))
|
||||
local action
|
||||
|
||||
if args[1] == "forward" then
|
||||
action = robot.forward
|
||||
elseif args[1] == "back" then
|
||||
action = robot.back
|
||||
elseif args[1] == "left" then
|
||||
action = robot.turnLeft
|
||||
elseif args[1] == "right" then
|
||||
action = robot.turnRight
|
||||
elseif args[1] == "up" then
|
||||
action = robot.up
|
||||
elseif args[1] == "down" then
|
||||
action = robot.down
|
||||
else
|
||||
io.stderr:write(args[1]..": not a valid direction!\n")
|
||||
return
|
||||
end
|
||||
|
||||
for i = 1,distance do
|
||||
action()
|
||||
end
|
@ -82,13 +82,13 @@ ocBackend = {
|
||||
--print(" -U, --upgrade")
|
||||
--print(" Upgrade or add package(s) to the system and install the required")
|
||||
--print(" dependencies from sync repositories. Either a URL or file path can be")
|
||||
--print(" specified. This is a ?remove-then-add? process.")
|
||||
--print(" specified. This is a “remove-then-add” process.")
|
||||
print(" -y, --update")
|
||||
print(" Update package lists for backends that require such action")
|
||||
print(" -u, --upgrades")
|
||||
print(" Upgrade all packages that are out-of-date on the")
|
||||
print(" local system. Only package versions are used to find outdated packages;")
|
||||
print(" replacements are not checked here. This is a ?remove-then-add? process.")
|
||||
print(" replacements are not checked here. This is a “remove-then-add” process.")
|
||||
print(" -f, --force")
|
||||
print(" Force operation, in case of upgrade it redownloads all packages")
|
||||
print(" --root='/some/dir'")
|
||||
@ -289,7 +289,13 @@ mptFrontend = {
|
||||
end
|
||||
local updateResp = backend.getText(config.frontend.mpt.api.."update", toCheck)
|
||||
if updateResp then
|
||||
local updateList = load("return "..updateResp)() or {}
|
||||
local upd, err = load("return "..updateResp)
|
||||
if not upd then
|
||||
print("Update error: " .. tostring(err))
|
||||
print("Data: " .. tostring(updateResp))
|
||||
os.exit(1)
|
||||
end
|
||||
local updateList = upd() or {}
|
||||
local res = {}
|
||||
for _, entry in ipairs(updateList) do
|
||||
res[entry.package] = {checksum = entry.checksum}
|
||||
@ -338,7 +344,7 @@ mirrorFrontend = {
|
||||
local todo = {}
|
||||
for pack, data in pairs(base.installed) do
|
||||
if data.frontend == mirrorFrontend.name then
|
||||
if mirrorFrontend.base.installed[pack] and
|
||||
if mirrorFrontend.base and mirrorFrontend.base.installed[pack] and
|
||||
mirrorFrontend.base.installed[pack].data.checksum ~= base.installed[pack].data.checksum .. (core.data.force and "WAT" or "") then
|
||||
todo[pack] = {}
|
||||
end
|
||||
@ -390,7 +396,7 @@ oppmFrontend = {
|
||||
if packages then
|
||||
for name, package in pairs(packages) do
|
||||
local metadata = {
|
||||
files = expandOppmFiles(package.files),
|
||||
files = expandOppmFiles(package.files or {}),
|
||||
dependencies = keys(package.dependencies or {}),
|
||||
repo = repoid,
|
||||
version = package.version
|
||||
|
@ -1,64 +0,0 @@
|
||||
local network = require "network"
|
||||
local event = require "event"
|
||||
|
||||
local args = {...}
|
||||
|
||||
local listen = false
|
||||
local port = -1
|
||||
local addr
|
||||
|
||||
for _,par in ipairs(args) do
|
||||
if par == "-l" then
|
||||
listen = true
|
||||
elseif port < 1 then
|
||||
local p = tonumber(par)
|
||||
if p then
|
||||
port = p
|
||||
end
|
||||
else
|
||||
addr = par
|
||||
end
|
||||
end
|
||||
|
||||
if port < 0 then error("Unspecified port")end
|
||||
if not listen and not addr then error("Unspecified address")end
|
||||
|
||||
local chanel
|
||||
local function handleTcp()
|
||||
while true do
|
||||
while io.input().remaining() ~= 0 do
|
||||
local data = io.read(math.min(io.input().remaining(), 7000))
|
||||
if not data then
|
||||
|
||||
end
|
||||
network.tcp.send(chanel, data)
|
||||
end
|
||||
local e = {event.pull()}
|
||||
if e[1] then
|
||||
if e[1] == "tcp" then
|
||||
if e[2] == "connection" then
|
||||
if listen and e[5] == port and e[6] == "incoming" then
|
||||
network.tcp.unlisten(port)
|
||||
print("connected")
|
||||
elseif not listen and e[3] == chanel and e[6] ~= "incoming" then
|
||||
chanel = e[3]
|
||||
print("connected")
|
||||
end
|
||||
elseif e[2] == "close" and e[3] == chanel then
|
||||
print("Connection closed")
|
||||
return
|
||||
elseif e[2] == "message" and e[3] == chanel then
|
||||
io.write(e[4])
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if listen then
|
||||
network.tcp.listen(port)
|
||||
handleTcp()
|
||||
else
|
||||
chanel = network.tcp.open(addr, port)
|
||||
handleTcp()
|
||||
end
|
@ -0,0 +1,281 @@
|
||||
local component = require("component")
|
||||
local sides = require("sides")
|
||||
|
||||
local robot = {}
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- General
|
||||
|
||||
function robot.name()
|
||||
return component.robot.name()
|
||||
end
|
||||
|
||||
function robot.level()
|
||||
if component.isAvailable("experience") then
|
||||
return component.experience.level()
|
||||
else
|
||||
return 0
|
||||
end
|
||||
end
|
||||
|
||||
function robot.getLightColor()
|
||||
return component.robot.getLightColor()
|
||||
end
|
||||
|
||||
function robot.setLightColor(value)
|
||||
return component.robot.setLightColor(value)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- World
|
||||
|
||||
function robot.detect()
|
||||
return component.robot.detect(sides.front)
|
||||
end
|
||||
|
||||
function robot.detectUp()
|
||||
return component.robot.detect(sides.up)
|
||||
end
|
||||
|
||||
function robot.detectDown()
|
||||
return component.robot.detect(sides.down)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Inventory
|
||||
|
||||
function robot.inventorySize()
|
||||
return component.robot.inventorySize()
|
||||
end
|
||||
|
||||
|
||||
function robot.select(...)
|
||||
return component.robot.select(...)
|
||||
end
|
||||
|
||||
function robot.count(...)
|
||||
return component.robot.count(...)
|
||||
end
|
||||
|
||||
function robot.space(...)
|
||||
return component.robot.space(...)
|
||||
end
|
||||
|
||||
function robot.compareTo(...)
|
||||
return component.robot.compareTo(...)
|
||||
end
|
||||
|
||||
function robot.transferTo(...)
|
||||
return component.robot.transferTo(...)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Inventory + World
|
||||
|
||||
function robot.compare()
|
||||
return component.robot.compare(sides.front)
|
||||
end
|
||||
|
||||
function robot.compareUp()
|
||||
return component.robot.compare(sides.up)
|
||||
end
|
||||
|
||||
function robot.compareDown()
|
||||
return component.robot.compare(sides.down)
|
||||
end
|
||||
|
||||
function robot.drop(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drop(sides.front, count)
|
||||
end
|
||||
|
||||
function robot.dropUp(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drop(sides.up, count)
|
||||
end
|
||||
|
||||
function robot.dropDown(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drop(sides.down, count)
|
||||
end
|
||||
|
||||
function robot.place(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.place(sides.front, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.placeUp(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.place(sides.up, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.placeDown(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.place(sides.down, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.suck(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.suck(sides.front, count)
|
||||
end
|
||||
|
||||
function robot.suckUp(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.suck(sides.up, count)
|
||||
end
|
||||
|
||||
function robot.suckDown(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.suck(sides.down, count)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Tool
|
||||
|
||||
function robot.durability()
|
||||
return component.robot.durability()
|
||||
end
|
||||
|
||||
|
||||
function robot.swing(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.swing(sides.front, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.swingUp(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.swing(sides.up, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.swingDown(side, sneaky)
|
||||
checkArg(1, side, "nil", "number")
|
||||
return component.robot.swing(sides.down, side, sneaky ~= nil and sneaky ~= false)
|
||||
end
|
||||
|
||||
function robot.use(side, sneaky, duration)
|
||||
checkArg(1, side, "nil", "number")
|
||||
checkArg(3, duration, "nil", "number")
|
||||
return component.robot.use(sides.front, side, sneaky ~= nil and sneaky ~= false, duration)
|
||||
end
|
||||
|
||||
function robot.useUp(side, sneaky, duration)
|
||||
checkArg(1, side, "nil", "number")
|
||||
checkArg(3, duration, "nil", "number")
|
||||
return component.robot.use(sides.up, side, sneaky ~= nil and sneaky ~= false, duration)
|
||||
end
|
||||
|
||||
function robot.useDown(side, sneaky, duration)
|
||||
checkArg(1, side, "nil", "number")
|
||||
checkArg(3, duration, "nil", "number")
|
||||
return component.robot.use(sides.down, side, sneaky ~= nil and sneaky ~= false, duration)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Movement
|
||||
|
||||
function robot.forward()
|
||||
return component.robot.move(sides.front)
|
||||
end
|
||||
|
||||
function robot.back()
|
||||
return component.robot.move(sides.back)
|
||||
end
|
||||
|
||||
function robot.up()
|
||||
return component.robot.move(sides.up)
|
||||
end
|
||||
|
||||
function robot.down()
|
||||
return component.robot.move(sides.down)
|
||||
end
|
||||
|
||||
|
||||
function robot.turnLeft()
|
||||
return component.robot.turn(false)
|
||||
end
|
||||
|
||||
function robot.turnRight()
|
||||
return component.robot.turn(true)
|
||||
end
|
||||
|
||||
function robot.turnAround()
|
||||
local turn = math.random() < 0.5 and robot.turnLeft or robot.turnRight
|
||||
return turn() and turn()
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Tank
|
||||
|
||||
function robot.tankCount()
|
||||
return component.robot.tankCount()
|
||||
end
|
||||
|
||||
|
||||
function robot.selectTank(tank)
|
||||
return component.robot.selectTank(tank)
|
||||
end
|
||||
|
||||
function robot.tankLevel(...)
|
||||
return component.robot.tankLevel(...)
|
||||
end
|
||||
|
||||
function robot.tankSpace(...)
|
||||
return component.robot.tankSpace(...)
|
||||
end
|
||||
|
||||
function robot.compareFluidTo(...)
|
||||
return component.robot.compareFluidTo(...)
|
||||
end
|
||||
|
||||
function robot.transferFluidTo(...)
|
||||
return component.robot.transferFluidTo(...)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
-- Tank + World
|
||||
|
||||
function robot.compareFluid()
|
||||
return component.robot.compareFluid(sides.front)
|
||||
end
|
||||
|
||||
function robot.compareFluidUp()
|
||||
return component.robot.compareFluid(sides.up)
|
||||
end
|
||||
|
||||
function robot.compareFluidDown()
|
||||
return component.robot.compareFluid(sides.down)
|
||||
end
|
||||
|
||||
function robot.drain(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drain(sides.front, count)
|
||||
end
|
||||
|
||||
function robot.drainUp(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drain(sides.up, count)
|
||||
end
|
||||
|
||||
function robot.drainDown(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.drain(sides.down, count)
|
||||
end
|
||||
|
||||
function robot.fill(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.fill(sides.front, count)
|
||||
end
|
||||
|
||||
function robot.fillUp(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.fill(sides.up, count)
|
||||
end
|
||||
|
||||
function robot.fillDown(count)
|
||||
checkArg(1, count, "nil", "number")
|
||||
return component.robot.fill(sides.down, count)
|
||||
end
|
||||
|
||||
-------------------------------------------------------------------------------
|
||||
|
||||
return robot
|
@ -1 +1 @@
|
||||
{database="/var/lib/mpt/base.db",frontend={mpt={api="http://mpt.magik6k.net/api/"}},cacheDir="/var/lib/mpt/cache/"}
|
||||
{frontend={mpt={api="http://mpt.magik6k.net/api/"}},cacheDir="/var/lib/mpt/cache/",database="/var/lib/mpt/base.db"}
|
File diff suppressed because one or more lines are too long
Loading…
x
Reference in New Issue
Block a user