Merge pull request #2210 from magik6k/master-MC1.7.10

Update Plan9k(Fixed PR)
This commit is contained in:
Vexatos 2016-12-30 16:19:58 +01:00 committed by GitHub
commit dcdf8346f3
51 changed files with 1294 additions and 1618 deletions

View File

@ -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

View File

@ -20,6 +20,6 @@ else
end
until not line
file:close()
io.write("\n")
io.stderr:write("\n")
end
end

View File

@ -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 = "-"

View File

@ -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

View 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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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()

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
--------

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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
}

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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]")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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