@@ -2,7 +2,7 @@ | |||||
cp ../OC-Minitel/minitel.lua service/minitel.lua | cp ../OC-Minitel/minitel.lua service/minitel.lua | ||||
mkdir build | mkdir build | ||||
cd module | cd module | ||||
cat sched.lua vt100.lua fs.lua loadfile.lua vt-task.lua io.lua createterms.lua init.lua > ../build/psychos.lua | |||||
cat sched.lua syslog.lua vt100.lua fs.lua iofs.lua loadfile.lua vt-task.lua io.lua createterms.lua init.lua > ../build/psychos.lua | |||||
cd .. | cd .. | ||||
echo '_OSVERSION="PsychOS 2.0a0"' >> build/* | echo '_OSVERSION="PsychOS 2.0a0"' >> build/* | ||||
echo sched\(\) >> build/* | echo sched\(\) >> build/* |
@@ -1,3 +1,4 @@ | |||||
print(pcall(function() | |||||
local shenv = {} | local shenv = {} | ||||
function shenv.quit() | function shenv.quit() | ||||
os.setenv("run",nil) | os.setenv("run",nil) | ||||
@@ -13,3 +14,4 @@ while os.getenv("run") do | |||||
print(v) | print(v) | ||||
end | end | ||||
end | end | ||||
end)) |
@@ -1,5 +1,5 @@ | |||||
local event = {} | local event = {} | ||||
function event.pull(t,...) | |||||
function event.pull(t,...) -- return an event, optionally with timeout *t* and filter *...*. | |||||
local tA = {...} | local tA = {...} | ||||
if type(t) == "string" then | if type(t) == "string" then | ||||
table.insert(tA,1,t) | table.insert(tA,1,t) | ||||
@@ -22,7 +22,7 @@ function event.pull(t,...) | |||||
return nil | return nil | ||||
end | end | ||||
function event.listen(e,f) | |||||
function event.listen(e,f) -- run function *f* for every occurance of event *e* | |||||
local op = os.getenv("parent") | local op = os.getenv("parent") | ||||
os.setenv("parent",cPid) | os.setenv("parent",cPid) | ||||
os.spawn(function() while true do | os.spawn(function() while true do | ||||
@@ -35,7 +35,7 @@ function event.listen(e,f) | |||||
os.setenv("parent",op) | os.setenv("parent",op) | ||||
end | end | ||||
function event.ignore(e,f) | |||||
function event.ignore(e,f) -- stop function *f* running for every occurance of event *e* | |||||
computer.pushSignal("unlisten",e,tostring(f)) | computer.pushSignal("unlisten",e,tostring(f)) | ||||
end | end | ||||
@@ -12,7 +12,7 @@ net.minport = 32768 | |||||
net.maxport = 65535 | net.maxport = 65535 | ||||
net.openports = {} | net.openports = {} | ||||
function net.genPacketID() | |||||
function net.genPacketID() -- generate a random 16-character string, for use in packet IDs | |||||
local npID = "" | local npID = "" | ||||
for i = 1, 16 do | for i = 1, 16 do | ||||
npID = npID .. string.char(math.random(32,126)) | npID = npID .. string.char(math.random(32,126)) | ||||
@@ -20,11 +20,11 @@ function net.genPacketID() | |||||
return npID | return npID | ||||
end | end | ||||
function net.usend(to,port,data,npID) | |||||
function net.usend(to,port,data,npID) -- send an unreliable packet to host *to* on port *port* with data *data*, optionally with the packet ID *npID* | |||||
computer.pushSignal("net_send",0,to,port,data,npID) | computer.pushSignal("net_send",0,to,port,data,npID) | ||||
end | end | ||||
function net.rsend(to,port,data,block) | |||||
function net.rsend(to,port,data,block) -- send a reliable packet to host *to* on port *port* with data *data*, with *block* set to true to disable blocking | |||||
local pid, stime = net.genPacketID(), computer.uptime() + net.streamdelay | local pid, stime = net.genPacketID(), computer.uptime() + net.streamdelay | ||||
computer.pushSignal("net_send",1,to,port,data,pid) | computer.pushSignal("net_send",1,to,port,data,pid) | ||||
if block then return false end | if block then return false end | ||||
@@ -37,7 +37,7 @@ end | |||||
-- ordered packet delivery, layer 4? | -- ordered packet delivery, layer 4? | ||||
function net.send(to,port,ldata) | |||||
function net.send(to,port,ldata) -- send arbitrary data *ldata* reliably to host *to* on port *port* | |||||
local tdata = {} | local tdata = {} | ||||
if ldata:len() > net.mtu then | if ldata:len() > net.mtu then | ||||
for i = 1, ldata:len(), net.mtu do | for i = 1, ldata:len(), net.mtu do | ||||
@@ -112,7 +112,7 @@ local function socket(addr,port,sclose) | |||||
return conn | return conn | ||||
end | end | ||||
function net.open(to,port) | |||||
function net.open(to,port) -- open a socket to host *to* on port *port* | |||||
if not net.rsend(to,port,"openstream") then return false, "no ack from host" end | if not net.rsend(to,port,"openstream") then return false, "no ack from host" end | ||||
local st = computer.uptime()+net.streamdelay | local st = computer.uptime()+net.streamdelay | ||||
local est = false | local est = false | ||||
@@ -139,7 +139,7 @@ function net.open(to,port) | |||||
return socket(to,data,sclose) | return socket(to,data,sclose) | ||||
end | end | ||||
function net.listen(port) | |||||
function net.listen(port) -- listen for connections on port *port* in a blocking manner | |||||
repeat | repeat | ||||
_, from, rport, data = event.pull("net_msg") | _, from, rport, data = event.pull("net_msg") | ||||
until rport == port and data == "openstream" | until rport == port and data == "openstream" | ||||
@@ -150,7 +150,7 @@ function net.listen(port) | |||||
return socket(from,nport,sclose) | return socket(from,nport,sclose) | ||||
end | end | ||||
function net.flisten(port,listener) | |||||
function net.flisten(port,listener) -- run function *listener* on a connection to *port* | |||||
local function helper(_,from,rport,data) | local function helper(_,from,rport,data) | ||||
if rport == port and data == "openstream" then | if rport == port and data == "openstream" then | ||||
local nport = math.random(net.minport,net.maxport) | local nport = math.random(net.minport,net.maxport) | ||||
@@ -9,7 +9,7 @@ end | |||||
-- Important: pretty formatting will allow presenting non-serializable values | -- Important: pretty formatting will allow presenting non-serializable values | ||||
-- but may generate output that cannot be unserialized back. | -- but may generate output that cannot be unserialized back. | ||||
function serialization.serialize(value, pretty) | |||||
function serialization.serialize(value, pretty) -- serialize *value* into a string, optionally in a nicely formatted manner when *pretty* is set | |||||
local kw = {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, | local kw = {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, | ||||
["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true, | ["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true, | ||||
["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true, | ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true, | ||||
@@ -130,7 +130,7 @@ function serialization.serialize(value, pretty) | |||||
return result | return result | ||||
end | end | ||||
function serialization.unserialize(data) | |||||
function serialization.unserialize(data) -- returns the data contained in serialized string *data* | |||||
local result, reason = load("return " .. data, "=data", nil, {math={huge=math.huge}}) | local result, reason = load("return " .. data, "=data", nil, {math={huge=math.huge}}) | ||||
if not result then | if not result then | ||||
return nil, reason | return nil, reason | ||||
@@ -2,10 +2,18 @@ local ts = {} | |||||
for a,_ in component.list("screen") do | for a,_ in component.list("screen") do | ||||
ts[#ts+1] = a | ts[#ts+1] = a | ||||
end | end | ||||
local ttyn = 0 | |||||
for a,_ in component.list("gpu") do | for a,_ in component.list("gpu") do | ||||
local r,w = vtemu(a,table.remove(ts,1)) | local r,w = vtemu(a,table.remove(ts,1)) | ||||
fd[#fd+1] = {["read"]=r,["write"]=w,["close"]=function() w("\27[2J\27[H") end,["t"]="t"} | |||||
-- fd[#fd+1] = {["read"]=r,["write"]=w,["close"]=function() w("\27[2J\27[H") end,["t"]="t"} | |||||
iofs.register("tty"..tostring(ttyn),function() return r,w,function() w("\27[2J\27[H") end end) | |||||
local f = io.open("/iofs/tty"..tostring(ttyn),"rw") | |||||
fd[f.fd].t = "t" | |||||
ttyn = ttyn + 1 | |||||
end | |||||
do | |||||
iofs.register("syslog",function() return function() return "" end, function(msg) syslog(msg,nil,tTasks[cPid].n) end, function() return true end end) | |||||
end | end | ||||
if #fd < 1 then | if #fd < 1 then | ||||
io.open("/boot/console.log","a") | |||||
io.open("/iofs/syslog","rw") | |||||
end | end |
@@ -32,12 +32,15 @@ local function fread(self,length) | |||||
if length == "*a" then | if length == "*a" then | ||||
length = math.huge | length = math.huge | ||||
end | end | ||||
local rstr, lstr = "", "" | |||||
repeat | |||||
lstr = fs.mounts[self.fs].read(self.fid,math.min(2^16,length-rstr:len())) or "" | |||||
rstr = rstr .. lstr | |||||
until rstr:len() == length or lstr == "" | |||||
return rstr | |||||
if type(length) == "number" then | |||||
local rstr, lstr = "", "" | |||||
repeat | |||||
lstr = fs.mounts[self.fs].read(self.fid,math.min(2^16,length-rstr:len())) or "" | |||||
rstr = rstr .. lstr | |||||
until rstr:len() == length or lstr == "" | |||||
return rstr | |||||
end | |||||
return fs.mounts[self.fs].read(self.fid,length) | |||||
end | end | ||||
local function fwrite(self,data) | local function fwrite(self,data) | ||||
fs.mounts[self.fs].write(self.fid,data) | fs.mounts[self.fs].write(self.fid,data) | ||||
@@ -53,9 +56,10 @@ function fs.open(path,mode) -- opens file *path* with mode *mode* | |||||
local fid = fs.mounts[fsi].open(path,mode) | local fid = fs.mounts[fsi].open(path,mode) | ||||
if fid then | if fid then | ||||
local fobj = {["fs"]=fsi,["fid"]=fid,["close"]=fclose} | local fobj = {["fs"]=fsi,["fid"]=fid,["close"]=fclose} | ||||
if mode:sub(1,1) == "r" then | |||||
if mode:find("r") then | |||||
fobj.read = fread | fobj.read = fread | ||||
else | |||||
end | |||||
if mode:find("w") then | |||||
fobj.write = fwrite | fobj.write = fwrite | ||||
end | end | ||||
return fobj | return fobj | ||||
@@ -14,7 +14,7 @@ for k,v in pairs(fd) do | |||||
if v.t == "t" then | if v.t == "t" then | ||||
os.setenv("t",k) | os.setenv("t",k) | ||||
print("Spawning a shell for terminal #"..tostring(k)) | print("Spawning a shell for terminal #"..tostring(k)) | ||||
spawnfile("/boot/exec/shell.lua","shell #"..tostring(k)) | |||||
spawnfile("/boot/exec/shell.lua","shell [local:"..tostring(k).."]") | |||||
end | end | ||||
end | end | ||||
end)) end,"init") | end)) end,"init") |
@@ -39,7 +39,8 @@ local function fdfile(f,m) -- create a fd from a file | |||||
function fdo.read(d) | function fdo.read(d) | ||||
return fobj:read(d) | return fobj:read(d) | ||||
end | end | ||||
elseif fobj.write then | |||||
end | |||||
if fobj.write then | |||||
function fdo.write(d) | function fdo.write(d) | ||||
return fobj:write(d) | return fobj:write(d) | ||||
end | end | ||||
@@ -0,0 +1,64 @@ | |||||
iofs = {} | |||||
iofs.files = {} | |||||
iofs.fds = {} | |||||
iofs.nextfd = 0 | |||||
iofs.component = {} | |||||
local function rfalse() | |||||
return false | |||||
end | |||||
function iofs.component.getLabel() | |||||
return "iofs" | |||||
end | |||||
iofs.component.spaceUsed, iofs.component.spaceTotal, iofs.component.isReadOnly, iofs.component.isDirectory,iofs.component.size, iofs.component.setLabel = function() return computer.totalMemory()-computer.freeMemory() end, computer.totalMemory, rfalse, rfalse, rfalse, rfalse | |||||
function iofs.component.exists(fname) | |||||
return iofs.files[fname] ~= nil | |||||
end | |||||
function iofs.component.list() | |||||
local t = {} | |||||
for k,v in pairs(iofs.files) do | |||||
t[#t+1] = k | |||||
end | |||||
return t | |||||
end | |||||
function iofs.component.open(fname, mode) | |||||
fname=fname:gsub("/","") | |||||
if iofs.files[fname] then | |||||
local r,w,c,s = iofs.files[fname](mode) | |||||
iofs.fds[iofs.nextfd] = {["read"]=r or rfalse,["write"]=w or rfalse,["seek"]=s or rfalse,["close"]=c or rfalse} | |||||
iofs.nextfd = iofs.nextfd + 1 | |||||
return iofs.nextfd - 1 | |||||
end | |||||
return false | |||||
end | |||||
function iofs.component.read(fd,count) | |||||
if iofs.fds[fd] then | |||||
return iofs.fds[fd].read(count) | |||||
end | |||||
end | |||||
function iofs.component.write(fd,data) | |||||
if iofs.fds[fd] then | |||||
return iofs.fds[fd].write(data) | |||||
end | |||||
end | |||||
function iofs.component.close(fd) | |||||
if iofs.fds[fd] then | |||||
iofs.fds[fd].close() | |||||
end | |||||
iofs.fds[fd] = nil | |||||
end | |||||
function iofs.component.seek(fd,...) | |||||
if iofs.fds[fd] then | |||||
return iofs.fds[fd].seek(...) | |||||
end | |||||
end | |||||
function iofs.register(fname,fopen) -- Register a new iofs node with the name *fname* that will run the function *fopen* when opened. This function should return a function for read, a function for write, and a function for close, in that order. | |||||
iofs.files[fname] = fopen | |||||
end | |||||
fs.mounts.iofs = iofs.component |
@@ -1,5 +1,5 @@ | |||||
do | do | ||||
tTasks,nPid,nTimeout,cPid = {},1,1,0 -- table of tasks, next process ID, event timeout, current PID | |||||
tTasks,nPid,nTimeout,cPid = {},1,0,0 -- table of tasks, next process ID, event timeout, current PID | |||||
function os.spawn(f,n) -- creates a process from function *f* with name *n* | function os.spawn(f,n) -- creates a process from function *f* with name *n* | ||||
tTasks[nPid] = {["c"]=coroutine.create(f),["n"]=n,["p"]=nPid,e={}} | tTasks[nPid] = {["c"]=coroutine.create(f),["n"]=n,["p"]=nPid,e={}} | ||||
if tTasks[cPid] then | if tTasks[cPid] then | ||||
@@ -0,0 +1,14 @@ | |||||
syslog = {} | |||||
syslog.emergency = 0 | |||||
syslog.alert = 1 | |||||
syslog.critical = 2 | |||||
syslog.error = 3 | |||||
syslog.warning = 4 | |||||
syslog.notice = 5 | |||||
syslog.info = 6 | |||||
syslog.debug = 7 | |||||
setmetatable(syslog,{__call = function(_,msg, level, service) | |||||
level, service = level or syslog.info, service or process.info().path | |||||
computer.pushSignal("syslog",msg, level, service) | |||||
end}) |
@@ -0,0 +1,6 @@ | |||||
#!/bin/bash | |||||
rm -r psychos | |||||
mkdir psychos | |||||
cp -r exec/ lib/ service/ psychos/ | |||||
cp build/psychos.lua psychos/init.lua | |||||
tree -if psychos/ | cpio -oHbin > psychos.cpio |
@@ -0,0 +1,21 @@ | |||||
local lastkey = computer.uptime() | |||||
local state = true | |||||
local delay = 60 | |||||
while true do | |||||
tEv = {coroutine.yield()} | |||||
if tEv[1] == "key_down" then | |||||
lastkey = computer.uptime() | |||||
if not state then | |||||
for addr in component.list("screen") do | |||||
component.invoke(addr,"turnOn") | |||||
end | |||||
state = true | |||||
end | |||||
end | |||||
if computer.uptime() > lastkey + delay and state then | |||||
for addr in component.list("screen") do | |||||
component.invoke(addr,"turnOff") | |||||
end | |||||
state = false | |||||
end | |||||
end |
@@ -1,17 +1,25 @@ | |||||
print(pcall(function() | print(pcall(function() | ||||
local minitel = require "minitel" | local minitel = require "minitel" | ||||
local port = 22 | local port = 22 | ||||
local logfile = "/boot/termsrv.log" | |||||
--local logfile = "/boot/termsrv.log" | |||||
if logfile then | if logfile then | ||||
local log = io.open(logfile,"a") | local log = io.open(logfile,"a") | ||||
os.setenv("t",log.fd) | os.setenv("t",log.fd) | ||||
end | end | ||||
local function nextvty() | |||||
local vtyn = -1 | |||||
repeat | |||||
vtyn = vtyn + 1 | |||||
until not fs.exists("/iofs/vty"..tostring(vtyn)) | |||||
return "vty"..tostring(vtyn) | |||||
end | |||||
while true do | while true do | ||||
local sock = minitel.listen(port) | local sock = minitel.listen(port) | ||||
print(string.format("[%s] Connection from %s:%d",os.date("%Y-%m-%d %H:%M"),sock.addr,sock.port)) | print(string.format("[%s] Connection from %s:%d",os.date("%Y-%m-%d %H:%M"),sock.addr,sock.port)) | ||||
os.spawn(function() _G.worked = {pcall(function() | os.spawn(function() _G.worked = {pcall(function() | ||||
local fdi, fdo = io.newfd() | |||||
local vtyf = nextvty() | |||||
local fdo = {} | |||||
function fdo.read(d) | function fdo.read(d) | ||||
return sock:read(d) | return sock:read(d) | ||||
end | end | ||||
@@ -21,16 +29,21 @@ while true do | |||||
function fdo.close() | function fdo.close() | ||||
sock:close() | sock:close() | ||||
end | end | ||||
fd[fdi] = fdo | |||||
os.setenv("t",fdi) | |||||
iofs.register(vtyf,function() return fdo.read, fdo.write, fdo.close end) | |||||
local f = io.open("/iofs/"..vtyf,"rw") | |||||
print(vtyf, f.fd) | |||||
local ot = os.getenv("t") | |||||
os.setenv("t",f.fd) | |||||
sock:write(string.format("Connected to %s on port %d\n",computer.address():sub(1,8),sock.port)) | sock:write(string.format("Connected to %s on port %d\n",computer.address():sub(1,8),sock.port)) | ||||
local pid = spawnfile("/boot/exec/shell.lua",string.format("shell [%s:%d]",sock.addr,sock.port)) | local pid = spawnfile("/boot/exec/shell.lua",string.format("shell [%s:%d]",sock.addr,sock.port)) | ||||
repeat | repeat | ||||
coroutine.yield() | coroutine.yield() | ||||
until sock.state ~= "open" or not tTasks[pid] | until sock.state ~= "open" or not tTasks[pid] | ||||
fdo.close() | |||||
f:close() | |||||
sock:close() | sock:close() | ||||
os.kill(pid) | os.kill(pid) | ||||
os.setenv("t",ot) | |||||
print(string.format("Session %s:%d ended",sock.addr,sock.port)) | |||||
end)} end,string.format("remote login [%s:%d]",sock.addr,sock.port)) | end)} end,string.format("remote login [%s:%d]",sock.addr,sock.port)) | ||||
end | end | ||||
end)) | end)) |
@@ -0,0 +1,18 @@ | |||||
local delay = 60 | |||||
local port = 3442 | |||||
local message = "WoLBeacon" | |||||
for modem in component.list("modem") do | |||||
component.invoke(modem,"setWakeMessage",message) | |||||
end | |||||
local ltime = computer.uptime() | |||||
while true do | |||||
if computer.uptime() > ltime+delay then | |||||
for modem in component.list("modem") do | |||||
component.invoke(modem,"broadcast",port,message) | |||||
end | |||||
ltime=computer.uptime() | |||||
end | |||||
coroutine.yield() | |||||
end |