diff --git a/build.sh b/build.sh index 2e701e7..52c96f5 100755 --- a/build.sh +++ b/build.sh @@ -2,7 +2,7 @@ cp ../OC-Minitel/minitel.lua service/minitel.lua mkdir build 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 .. echo '_OSVERSION="PsychOS 2.0a0"' >> build/* echo sched\(\) >> build/* diff --git a/exec/shell.lua b/exec/shell.lua index 4213cfb..9a137b9 100644 --- a/exec/shell.lua +++ b/exec/shell.lua @@ -1,3 +1,4 @@ +print(pcall(function() local shenv = {} function shenv.quit() os.setenv("run",nil) @@ -13,3 +14,4 @@ while os.getenv("run") do print(v) end end +end)) diff --git a/lib/event.lua b/lib/event.lua index e9a90d5..3f07806 100644 --- a/lib/event.lua +++ b/lib/event.lua @@ -1,5 +1,5 @@ local event = {} -function event.pull(t,...) +function event.pull(t,...) -- return an event, optionally with timeout *t* and filter *...*. local tA = {...} if type(t) == "string" then table.insert(tA,1,t) @@ -22,7 +22,7 @@ function event.pull(t,...) return nil 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") os.setenv("parent",cPid) os.spawn(function() while true do @@ -35,7 +35,7 @@ function event.listen(e,f) os.setenv("parent",op) 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)) end diff --git a/lib/minitel.lua b/lib/minitel.lua index 06dd271..efb1cb3 100644 --- a/lib/minitel.lua +++ b/lib/minitel.lua @@ -12,7 +12,7 @@ net.minport = 32768 net.maxport = 65535 net.openports = {} -function net.genPacketID() +function net.genPacketID() -- generate a random 16-character string, for use in packet IDs local npID = "" for i = 1, 16 do npID = npID .. string.char(math.random(32,126)) @@ -20,11 +20,11 @@ function net.genPacketID() return npID 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) 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 computer.pushSignal("net_send",1,to,port,data,pid) if block then return false end @@ -37,7 +37,7 @@ end -- 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 = {} if ldata:len() > net.mtu then for i = 1, ldata:len(), net.mtu do @@ -112,7 +112,7 @@ local function socket(addr,port,sclose) return conn 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 local st = computer.uptime()+net.streamdelay local est = false @@ -139,7 +139,7 @@ function net.open(to,port) return socket(to,data,sclose) end -function net.listen(port) +function net.listen(port) -- listen for connections on port *port* in a blocking manner repeat _, from, rport, data = event.pull("net_msg") until rport == port and data == "openstream" @@ -150,7 +150,7 @@ function net.listen(port) return socket(from,nport,sclose) 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) if rport == port and data == "openstream" then local nport = math.random(net.minport,net.maxport) diff --git a/lib/serialization.lua b/lib/serialization.lua index 6872df3..34425e9 100644 --- a/lib/serialization.lua +++ b/lib/serialization.lua @@ -9,7 +9,7 @@ end -- Important: pretty formatting will allow presenting non-serializable values -- 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, ["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true, ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true, @@ -130,7 +130,7 @@ function serialization.serialize(value, pretty) return result 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}}) if not result then return nil, reason diff --git a/module/createterms.lua b/module/createterms.lua index 8fdaa37..ba7b606 100644 --- a/module/createterms.lua +++ b/module/createterms.lua @@ -2,10 +2,18 @@ local ts = {} for a,_ in component.list("screen") do ts[#ts+1] = a end +local ttyn = 0 for a,_ in component.list("gpu") do 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 if #fd < 1 then - io.open("/boot/console.log","a") + io.open("/iofs/syslog","rw") end diff --git a/module/fs.lua b/module/fs.lua index 8d559e6..faaa49d 100644 --- a/module/fs.lua +++ b/module/fs.lua @@ -32,12 +32,15 @@ local function fread(self,length) if length == "*a" then length = math.huge 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 local function fwrite(self,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) if fid then local fobj = {["fs"]=fsi,["fid"]=fid,["close"]=fclose} - if mode:sub(1,1) == "r" then + if mode:find("r") then fobj.read = fread - else + end + if mode:find("w") then fobj.write = fwrite end return fobj diff --git a/module/init.lua b/module/init.lua index 663d900..681a6d1 100644 --- a/module/init.lua +++ b/module/init.lua @@ -14,7 +14,7 @@ for k,v in pairs(fd) do if v.t == "t" then os.setenv("t",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,"init") diff --git a/module/io.lua b/module/io.lua index a901cf8..171cdc2 100644 --- a/module/io.lua +++ b/module/io.lua @@ -39,7 +39,8 @@ local function fdfile(f,m) -- create a fd from a file function fdo.read(d) return fobj:read(d) end - elseif fobj.write then + end + if fobj.write then function fdo.write(d) return fobj:write(d) end diff --git a/module/iofs.lua b/module/iofs.lua new file mode 100644 index 0000000..3df233d --- /dev/null +++ b/module/iofs.lua @@ -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 diff --git a/module/sched.lua b/module/sched.lua index fbc71cb..70135ad 100644 --- a/module/sched.lua +++ b/module/sched.lua @@ -1,5 +1,5 @@ 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* tTasks[nPid] = {["c"]=coroutine.create(f),["n"]=n,["p"]=nPid,e={}} if tTasks[cPid] then diff --git a/module/syslog.lua b/module/syslog.lua new file mode 100644 index 0000000..5727caa --- /dev/null +++ b/module/syslog.lua @@ -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}) diff --git a/package.sh b/package.sh new file mode 100755 index 0000000..e601a7f --- /dev/null +++ b/package.sh @@ -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 diff --git a/service/screenblank.lua b/service/screenblank.lua new file mode 100644 index 0000000..74f18da --- /dev/null +++ b/service/screenblank.lua @@ -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 diff --git a/service/termsrv.lua b/service/termsrv.lua index c5c55cf..0058927 100644 --- a/service/termsrv.lua +++ b/service/termsrv.lua @@ -1,17 +1,25 @@ print(pcall(function() local minitel = require "minitel" local port = 22 -local logfile = "/boot/termsrv.log" +--local logfile = "/boot/termsrv.log" if logfile then local log = io.open(logfile,"a") os.setenv("t",log.fd) 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 local sock = minitel.listen(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() - local fdi, fdo = io.newfd() + local vtyf = nextvty() + local fdo = {} function fdo.read(d) return sock:read(d) end @@ -21,16 +29,21 @@ while true do function fdo.close() sock:close() 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)) local pid = spawnfile("/boot/exec/shell.lua",string.format("shell [%s:%d]",sock.addr,sock.port)) repeat coroutine.yield() until sock.state ~= "open" or not tTasks[pid] - fdo.close() + f:close() sock:close() 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)) diff --git a/service/wolbeacon.lua b/service/wolbeacon.lua new file mode 100644 index 0000000..41f6006 --- /dev/null +++ b/service/wolbeacon.lua @@ -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