do -- so local works -- task format: -- { -- ["n"] = "name", -- ["c"] = coroutine of task, -- ["e"] = { table, of, environment, variables }, -- ["p"] = parent pid, -- ["u"] = user ID, -- ["ep"]= event queue pointer -- } local tT,nP,rg,eq,p = {},1,_G,{},1 -- taskTable,nextPid,real _G,event queue _G.cT,sbt,C,T,io = 0,{},coroutine,table,io -- currentTask,sandboxTable function _G.spawn(n,f,e) tT[nP] = {} local function nf() log(xpcall(f)) end tT[nP].c = coroutine.create(nf) tT[nP].n = n tT[nP].p = cT or -1 if tT[cT] then tT[nP].u,tT[nP].ep,tT[nP].e = tT[cT].u,tT[cT].ep,e or tT[cT].e or {["PWD"]="/boot",["PATH"]="/boot/exec:."} else tT[nP].u,tT[nP].ep,tT[nP].e = "superuser",1,{["PWD"]="/boot",["PATH"]="/boot/exec:."} end nP = nP + 1 return nP-1 end function _G.sched() _G.sched = nil while #tT > 0 do eq[#eq+1]={computer.pullSignal(p)} -- add the latest event to the eq if #eq > 16 then table.remove(eq,1) -- remove the earliest if the eq is full for pid,proc in pairs(tT) do if proc.ep > 1 then proc.ep = proc.ep - 1 -- decrement pointers for tasks to keep them on the same ones end end end for pid,proc in pairs(tT) do if coroutine.status(proc.c) == "dead" then tT[pid] = nil else cT=pid for i = 1,tT[pid].ep, #eq do _G.ev = eq[#eq] -- make an ev for MultICE compat coroutine.resume(proc.c) end end end end end _G.event = {} function event.get() -- get the next event in the queue, or nil if eq[tT[cT].ep] then tT[cT].ep = tT[cT].ep + 1 if tT[cT].ep > 17 then tT[cT].ep = 17 end return eq[tT[cT].ep - 1] end end function event.pull(t,time) -- return or wait for the next event, optionally with the first param matching t time = time or math.huge time = time + computer.uptime() while computer.uptime() < time do local e = event.get() if e then if t then if e[1] == t then return table.unpack(e) end else return table.unpack(e) end end coroutine.yield() end end event.push = computer.pushSignal function os.getenv(k) -- gets an envionment variable from tT[cT].e if tT[cT] then return tT[cT].e[k] end end function os.setenv(k,v) -- sets " if tT[cT] then tT[cT].e[k] = v end end function os.tasks() -- returns a table of tasks running on the system local t = {} for k,v in pairs(tT) do t[k] = v.n end return t end function os.taskinfo(pid) -- returns info on a task if tT[pid] then return tT[pid].n,tT[pid].p,tT[pid].u end end function os.genenv() local et = {} setmetatable(et,{__index=_G}) return et end -- user stuff from here local ut = {} local function flushut() local f = fs.open("/boot/sys/users.dat","wb") if f then for k,v in pairs(ut) do fs.write(f,k.."\t"..v[1].."\t"..v[2].."\n") end fs.close(f) return true end return false end local function readut() local f=fs.open("/boot/sys/users.dat","rb") if not f then return false end local C=fs.readall(f) fs.close(f) for line in C:gmatch("[^\n]+") do local username,hpass,salt = line:match("(.+)\t(.+)\t(.+)") if username and hpass and salt then ut[username] = {hpass,salt} end end end function os.setuid(user) if tT[cT].u == "superuser" and ut[user] then tT[cT].u = user return true end return false end function os.getuid(pid) pid = pid or cT return tT[pid].u end function os.users() local t = {} for k,v in pairs(ut) do t[#t+1] = k end return t end function os.verifyuser(username,pass) if sha then if ut[username] then if sha.sha256(pass..ut[username][2]) == ut[username][1] then return true end end return false end return true end function os.gensalt(len) local S = "" for i = 1, len do S=S..string.char(math.random(32,126)) end return S end function os.setuser(username,hpass,salt,...) if tT[cT].u == "superuser" then if hpass == nil then ut[username] = nil else ut[username] = {hpass, salt,...} flushut() end end end function os.su(user,pass) if os.verifyuser(user,pass) then log(tT[cT].u .. " su'd to "..user,6,1,true) tT[cT].u = user return true end return false end spawn("read users",readut) end