├── LICENSE ├── README.md ├── mrfs ├── 09_mrfs.lua └── mkfs.mrfs.lua ├── openloader-init └── init.lua ├── pipes ├── 01_gc.lua ├── 01_util.lua ├── 02_cmd.lua ├── 05_vfs.lua ├── 06_cowfs.lua ├── 09_rootfs.lua ├── 10_devfs.lua ├── 10_procfs.lua ├── 10_sysfs.lua ├── 11_block.lua ├── 15_keventd.lua ├── 15_userspace.lua ├── 16_buffer.lua ├── 16_component.lua ├── 16_require.lua ├── 17_io.lua ├── 17_ipc.lua ├── 17_keyboard.lua ├── 18_pty.lua ├── 18_syscall.lua ├── 19_cgroups.lua ├── 19_manageg.lua ├── 20_threading.lua ├── 21_threadUtil.lua ├── 21_timer.lua ├── 25_init.lua └── pipes ├── plan9k-containers └── sandbox.lua ├── plan9k-core ├── bin │ ├── getty.lua │ ├── init.lua │ ├── rc.lua │ └── readkey.lua └── lib │ └── rc.lua ├── plan9k-corelibs ├── colors.lua ├── event.lua ├── serialization.lua ├── shell.lua ├── sides.lua ├── term.lua └── text.lua ├── plan9k-coreutil ├── clear.lua ├── components.lua ├── dmesg.lua ├── echo.lua ├── hostname.lua ├── kill.lua ├── label.lua ├── lua.lua ├── passwd.lua ├── ps.lua ├── reboot.lua ├── resolution.lua ├── shutdown.lua ├── sleep.lua ├── uptime.lua ├── watch.lua └── wc.lua ├── plan9k-data ├── base64.lua ├── deflate.lua ├── gpg.lua ├── inflate.lua ├── md5sum.lua └── sha256sum.lua ├── plan9k-doc-core └── plan9k.md ├── plan9k-drivers ├── 12_mount.lua ├── 16_partition.lua ├── 17_chatbox.lua ├── 17_data.lua ├── 17_drive.lua ├── 17_eeprom.lua ├── 17_gpt.lua ├── 17_nfc.lua └── 17_tape.lua ├── plan9k-edit └── edit.lua ├── plan9k-extra ├── autoupdate.lua ├── go.lua └── robot.lua ├── plan9k-filesystems ├── mkdosfs.lua ├── mount.msdos.lua └── msdosfs.lua ├── plan9k-fsutil ├── cat.lua ├── cp.lua ├── dd.lua ├── df.lua ├── du.lua ├── find.lua ├── ln.lua ├── ls.lua ├── mkdir.lua ├── more.lua ├── mount.cow.lua ├── mount.lua ├── mv.lua ├── pwd.lua ├── rm.lua ├── tee.lua └── touch.lua ├── plan9k-installer └── install.lua ├── plan9k-ip ├── 02_ringbuffer.lua ├── 11_interface.lua ├── 12_ip.lua ├── 13_gateway.lua ├── 13_ocnet.lua ├── 13_router.lua ├── 14_linked.lua ├── 14_tcpudp.lua ├── 17_network.lua ├── ip.lua ├── nc.lua ├── netctl.lua └── ping.lua ├── plan9k-man └── man.lua ├── plan9k-network ├── internet.lua ├── pastebin.lua └── wget.lua ├── plan9k-ohcp-server ├── 13_ohcpSrv.lua └── ohcpd.lua ├── plan9k-ohcp ├── 14_ohcp.lua ├── ohcp.lua └── ohcpd.lua ├── plan9k-shell └── sh.lua ├── plan9k-ssh ├── rc.d │ └── sshd.lua ├── ssh.lua ├── sshd.lua └── sshsession.lua ├── plan9k └── .prop ├── programs.cfg └── routed ├── rc.d └── routed.lua └── routed.lua /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2016 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Plan9k 2 | Repository for Plan9k 3 | 4 | You should put Plan9k related issues here. 5 | If you feel you can help with the docs poke me at #oc on EsperNet IRC. 6 | -------------------------------------------------------------------------------- /mrfs/mkfs.mrfs.lua: -------------------------------------------------------------------------------- 1 | local fs = require "filesystem" 2 | local args = {...} 3 | 4 | local dev = args[1] or error("Must specify a file") 5 | 6 | local device = fs.open(dev, "wb") 7 | 8 | local sectors = math.floor(device:seek("end", 0)/512) 9 | print(sectors .. " sectors") 10 | device:seek("set", 0) 11 | 12 | local magic = string.char(0xD4, 0x99, 0xC6, 0xE2) 13 | local lbs = 9 -- 2 ^ 9 = 512 14 | local volId = 0 15 | local volCount = 1 16 | 17 | local blocks = sectors 18 | local dataTop = 1 19 | local firstFree = 1 20 | 21 | local usedBlocks = 4 22 | local inodeAllocations = 1 23 | local firstFreeInode = 1 24 | local VGID = math.random(1000000000000000) 25 | 26 | local superBlock = string.pack("\60c4BBxBxI8I8I8I8I8I8c16", magic, lbs, volId, volCount, blocks, dataTop, firstFree, usedBlocks, inodeAllocations, firstFreeInode, VGID) .. ("\0"):rep(188) 27 | local rootNodeBolck = string.pack("\60BHHHxI8I4I8I8I8I8xxxxxx", 1, 0xFF80, 0, 0, 0, 0, 0, 0, 0, 0) 28 | local rootDps = string.pack("\60I8BBI8I4xx", 0, 0, 0, 0, 0) 29 | 30 | print("Boot record size: " .. #superBlock) 31 | device:write((superBlock .. ("\0"):rep(512)):sub(1, 512)) 32 | 33 | print("Inode 0 start: " .. tostring(device:seek("set", (blocks - 1) * 512))) 34 | device:write((rootNodeBolck .. ("\0"):rep(512)):sub(1, 512)) 35 | -------------------------------------------------------------------------------- /openloader-init/init.lua: -------------------------------------------------------------------------------- 1 | _G._OSVERSION = "OpenLoader 0.3" 2 | local component = component or require('component') 3 | local computer = computer or require('computer') 4 | local unicode = unicode or require('unicode') 5 | 6 | local eeprom = component.list("eeprom")() 7 | computer.getBootAddress = function() 8 | return component.invoke(eeprom, "getData") 9 | end 10 | computer.setBootAddress = function(address) 11 | return component.invoke(eeprom, "setData", address) 12 | end 13 | 14 | local gpu = component.list("gpu")() 15 | local w, h 16 | 17 | local screen = component.list('screen')() 18 | 19 | local function gpucast(op, arg, ...) 20 | local res = {} 21 | local n = 1 22 | for address in component.list('screen') do 23 | component.invoke(gpu, "bind", address) 24 | if type(arg) == "table" then 25 | res[#res + 1] = {component.invoke(gpu, op, table.unpack(arg[n]))} 26 | else 27 | res[#res + 1] = {component.invoke(gpu, op, arg, ...)} 28 | end 29 | n = n + 1 30 | end 31 | return res 32 | end 33 | 34 | local cls = function()end 35 | if gpu and screen then 36 | --component.invoke(gpu, "bind", screen) 37 | w, h = component.invoke(gpu, "getResolution") 38 | local res = gpucast("getResolution") 39 | gpucast("setResolution", res) 40 | gpucast("setBackground", 0x000000) 41 | gpucast("setForeground", 0xFFFFFF) 42 | for _, e in ipairs(res)do 43 | table.insert(e, 1, 1) 44 | table.insert(e, 1, 1) 45 | e[#e+1] = " " 46 | end 47 | gpucast("fill", res) 48 | cls = function()gpucast("fill", res)end 49 | end 50 | local y = 1 51 | local function status(msg) 52 | if gpu and screen then 53 | gpucast("set", 1, y, msg) 54 | if y == h then 55 | gpucast("copy", 1, 2, w, h - 1, 0, -1) 56 | gpucast("fill", 1, h, w, 1, " ") 57 | else 58 | y = y + 1 59 | end 60 | end 61 | end 62 | 63 | local function loadfile(fs, file) 64 | --status("> " .. file) 65 | local handle, reason = component.invoke(fs,"open",file) 66 | if not handle then 67 | error(reason) 68 | end 69 | local buffer = "" 70 | repeat 71 | local data, reason = component.invoke(fs,"read",handle,math.huge) 72 | if not data and reason then 73 | error(reason) 74 | end 75 | buffer = buffer .. (data or "") 76 | until not data 77 | component.invoke(fs,"close",handle) 78 | return load(buffer, "=" .. file) 79 | end 80 | 81 | local function dofile(fs, file) 82 | local program, reason = loadfile(fs, file) 83 | if program then 84 | local result = table.pack(true, program()) 85 | if result[1] then 86 | return table.unpack(result, 2, result.n) 87 | else 88 | error(result[2]) 89 | end 90 | else 91 | error(reason) 92 | end 93 | end 94 | 95 | local function boot(kernel) 96 | status("BOOTING") 97 | _G.computer.getBootAddress = function()return kernel.address end 98 | cls() 99 | dofile(kernel.address, kernel.fpx .. kernel.file) 100 | end 101 | 102 | local function labelText(fs) 103 | local lbl = component.invoke(fs, "getLabel") 104 | if lbl then return " ('"..lbl.."')" else return "" end 105 | end 106 | 107 | status(_OSVERSION) 108 | status("Select what to boot:") 109 | 110 | local osList = {} 111 | 112 | for fs in component.list("filesystem") do 113 | if component.invoke(fs, "isDirectory", "boot/kernel/")then 114 | for _,file in ipairs(component.invoke(fs, "list", "boot/kernel/")) do 115 | osList[#osList+1] = {fpx = "boot/kernel/", file = file, address = fs} 116 | status(tostring(#osList).."."..file.." from "..(fs:sub(1,3))..labelText(fs)) 117 | end 118 | end 119 | if fs ~= computer.getBootAddress() and component.invoke(fs, "exists", "init.lua") then 120 | local osName = "init.lua" 121 | if component.invoke(fs, "exists", ".osprop") then 122 | pcall(function() 123 | local prop = dofile(fs, ".osprop") 124 | osName = (prop and prop.name) or "init.lua" 125 | end) 126 | end 127 | osList[#osList+1] = {fpx = "", file = "init.lua", address = fs} 128 | status(tostring(#osList).."."..osName.." from "..(fs:sub(1,3))..labelText(fs)) 129 | end 130 | end 131 | status("Select os: ") 132 | if #osList == 1 then 133 | boot(osList[1]) 134 | end 135 | if #osList == 0 then 136 | error("No OS found") 137 | while true do computer.pullSignal() end 138 | end 139 | while true do 140 | local sig = {computer.pullSignal()} 141 | if sig[1] == "key_down" then 142 | if sig[4] >= 2 and sig[4] <= 11 then 143 | if osList[sig[4]-1] then 144 | boot(osList[sig[4]-1]) 145 | else 146 | status("Not found!") 147 | end 148 | end 149 | end 150 | end 151 | error("System crashed") 152 | while true do computer.pullSignal() end 153 | -------------------------------------------------------------------------------- /pipes/01_gc.lua: -------------------------------------------------------------------------------- 1 | local onshutdown = {} 2 | local onprocessdead = {} 3 | 4 | function onShutdown(callback) 5 | if type(callback) ~= "function" then 6 | error("GC callback is not a function") 7 | end 8 | onshutdown[#onshutdown + 1] = callback 9 | end 10 | 11 | function shutdown(...) 12 | for _, callback in ipairs(onshutdown) do 13 | pcall(callback) 14 | end 15 | computer.shutdown(...) 16 | end 17 | 18 | function onProcessKilled(callback) 19 | if type(callback) ~= "function" then 20 | error("GC callback is not a function") 21 | end 22 | onprocessdead[#onprocessdead + 1] = callback 23 | end 24 | 25 | function processkilled(...) 26 | for _, callback in ipairs(onprocessdead) do 27 | pcall(callback, ...) 28 | end 29 | end 30 | -------------------------------------------------------------------------------- /pipes/01_util.lua: -------------------------------------------------------------------------------- 1 | function split(str, pat) 2 | local t = {} 3 | if type(pat) == "number" then 4 | while #str > 0 do 5 | table.insert(t, str:sub(1, pat)) 6 | str = str:sub(pat + 1) 7 | end 8 | else 9 | local fpat = "(.-)" .. pat 10 | local last_end = 1 11 | local s, e, cap = str:find(fpat, 1) 12 | while s do 13 | if s ~= 1 or cap ~= "" then 14 | table.insert(t, cap) 15 | end 16 | last_end = e+1 17 | s, e, cap = str:find(fpat, last_end) 18 | end 19 | if last_end <= #str then 20 | cap = str:sub(last_end) 21 | table.insert(t, cap) 22 | end 23 | end 24 | return t 25 | end 26 | 27 | function cloneTab(t) 28 | local n = {} 29 | for k, v in pairs(t) do 30 | n[k] = v 31 | end 32 | return n 33 | end 34 | 35 | -------- 36 | 37 | function getAllocator() 38 | local allocator = {next = 1} 39 | local list = {} 40 | function allocator:get() 41 | local n = self.next 42 | self.next = (list[n] and list[n].next) or (#list + 2) 43 | list[n] = {id = n} 44 | return list[n] 45 | end 46 | 47 | function allocator:unset(e) 48 | local eid = e.id 49 | list[eid] = {next = self.next} 50 | self.next = eid 51 | return list[n] 52 | end 53 | return allocator, list 54 | end 55 | 56 | -------- 57 | 58 | function randomString(c) 59 | local s = "" 60 | for i = 1, c do 61 | s = s .. string.char(math.random(0, 255)) 62 | end 63 | return s 64 | end 65 | 66 | function uuidBin(uuid) 67 | local undashed = uuid:gsub("-","") 68 | local high = tonumber(undashed:sub(1,16), 16) 69 | local low = tonumber(undashed:sub(17), 16) 70 | return string.pack(">I8I8", high, low) 71 | end 72 | 73 | function binUUID(uuid) 74 | local raw = toHex(uuid) 75 | return raw:sub(1, 8) .. "-" .. raw:sub(9, 12) .. "-" .. raw:sub(13, 16) .. "-" .. raw:sub(17, 20) .. "-" .. raw:sub(21) 76 | end 77 | 78 | function shortUUID() 79 | return toHex(randomString(2)):upper() 80 | end 81 | 82 | -------- 83 | 84 | -------- 85 | 86 | local function sixteen(val) 87 | if val < 10 then 88 | return string.char(48 + val) 89 | else 90 | return string.char(97 + val - 10) 91 | end 92 | end 93 | 94 | function toHex(bin) 95 | local res = "" 96 | for i = 1, #bin do 97 | local byte = bin:byte(i) 98 | res = res .. sixteen(byte >> 4) .. sixteen(byte & 0x0F) 99 | end 100 | return res 101 | end 102 | -------------------------------------------------------------------------------- /pipes/02_cmd.lua: -------------------------------------------------------------------------------- 1 | commands = {} 2 | 3 | function execute(comm) 4 | local command = kernel.modules.util.split(comm," ") 5 | kernel.io.println("Execute: "..command[1]) 6 | if commands[command[1]] then 7 | table.remove(command, 1) 8 | return commands[command[1]](table.unpack(command)) 9 | end 10 | return "KCMD: Command not found!" 11 | end 12 | 13 | commands.shutdomn = kernel.modules.gc.shutdown -------------------------------------------------------------------------------- /pipes/09_rootfs.lua: -------------------------------------------------------------------------------- 1 | function start() 2 | if component.invoke(computer.getBootAddress(), "isReadOnly") or (kernel.modules.special and kernel.modules.special.roroot) then 3 | local cow = kernel.modules.cowfs.new(computer.getBootAddress(), computer.tmpAddress()) 4 | kernel.modules.vfs.mount(cow, "/") 5 | else 6 | kernel.modules.vfs.mount(computer.getBootAddress(), "/") 7 | end 8 | 9 | kernel.modules.vfs.mount(computer.tmpAddress(), "/tmp") 10 | end 11 | -------------------------------------------------------------------------------- /pipes/10_devfs.lua: -------------------------------------------------------------------------------- 1 | proxy = {} 2 | data = {} 3 | 4 | proxy.address = "devfs0000" 5 | proxy.spaceUsed = function() return 0 end 6 | proxy.spaceTotal = function() return 0 end 7 | proxy.makeDirectory = function() error("Permission Denied") end 8 | proxy.isReadOnly = function() return true end 9 | proxy.rename = function() error("Permission Denied") end 10 | proxy.remove = function() error("Permission Denied") end 11 | proxy.setLabel = function() error("Permission Denied") end 12 | proxy.size = function(path) 13 | local seg = kernel.modules.vfs.segments(path) 14 | local file = data 15 | for _, d in pairs(seg) do 16 | file = file[d] 17 | end 18 | return file.size and file.size() or 0 19 | end 20 | proxy.getLabel = function() return "devfs" end 21 | 22 | local allocator, handles = kernel.modules.util.getAllocator() 23 | 24 | proxy.exists = function(path) 25 | local seg = kernel.modules.vfs.segments(path) 26 | local file = data 27 | for _, d in pairs(seg) do 28 | if not file[d] then 29 | return false 30 | end 31 | file = file[d] 32 | end 33 | return file and true or false 34 | end 35 | proxy.open = function(path) 36 | local seg = kernel.modules.vfs.segments(path) 37 | local file = data 38 | for _, d in pairs(seg) do 39 | if not file[d] then 40 | return nil, "File not found" 41 | end 42 | file = file[d] 43 | end 44 | local hnd = allocator:get() 45 | hnd.file = file 46 | if hnd.file.open then 47 | hnd.file.open(hnd) 48 | end 49 | return hnd.id 50 | end 51 | proxy.read = function(h, ...) 52 | return handles[h].file.read(handles[h], ...) 53 | end 54 | proxy.close = function(h) 55 | if handles[h].file.close then 56 | handles[h].file.close(handles[h]) 57 | end 58 | allocator:unset(handles[h]) 59 | end 60 | proxy.write = function(h, ...) 61 | return handles[h].file.write(handles[h], ...) 62 | end 63 | proxy.seek = function(h, ...) 64 | return handles[h].file.seek(handles[h], ...) 65 | end 66 | proxy.isDirectory = function(path) 67 | local seg = kernel.modules.vfs.segments(path) 68 | local dir = data 69 | for _, d in pairs(seg) do 70 | dir = dir[d] 71 | end 72 | if dir.__type then 73 | return false 74 | end 75 | return true 76 | end 77 | proxy.list = function(path) 78 | local seg = kernel.modules.vfs.segments(path) 79 | local dir = data 80 | for _, d in pairs(seg) do 81 | dir = dir[d] 82 | end 83 | if dir.__type then 84 | error("File is not a directory") 85 | end 86 | local list = {} 87 | for f, node in pairs(dir) do 88 | list[#list + 1] = f .. (node.__type and "" or "/") 89 | end 90 | return list 91 | end 92 | 93 | data.pts = {} 94 | data.null = { 95 | __type = "f", 96 | write = function()end 97 | } 98 | data.kmsg = { 99 | __type = "f", 100 | write = function(h, data) 101 | kernel.io.println(data) 102 | end 103 | } 104 | data.kcmd = { 105 | __type = "f", 106 | open = function(h) h.buf = "" end, 107 | write = function(h, data) 108 | h.buf = h.buf .. kernel.modules.cmd.execute(data) or "" 109 | end, 110 | read = function(h) 111 | local res = h.buf 112 | h.buf = "" 113 | return res 114 | end, 115 | close = function(h) h.buf = nil end 116 | } 117 | data.zero = { 118 | __type = "f", 119 | read = function(h, c) 120 | c = c or 1 121 | return ("\0"):rep(c > (2^16) and (2^16) or c) 122 | end 123 | } 124 | data.random = { 125 | __type = "f", 126 | read = function(h, c) 127 | c = c or 1 128 | local s = "" 129 | for i = 1, c do 130 | s = s .. string.char(math.random(0, 255)) 131 | end 132 | return s 133 | end 134 | } 135 | 136 | function start() 137 | kernel.modules.vfs.mount(proxy, "/dev") 138 | end 139 | 140 | -------------------------------------------------------------------------------- /pipes/10_procfs.lua: -------------------------------------------------------------------------------- 1 | proxy = {} 2 | data = {} 3 | local realroot = computer.getBootAddress() 4 | 5 | -------------- 6 | -- Utils 7 | local random = math.random 8 | local bootID 9 | local function uuid() 10 | local template ='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' 11 | return string.gsub(template, '[xy]', function (c) 12 | local v = (c == 'x') and random(0, 0xf) or random(8, 0xb) 13 | return string.format('%x', v) 14 | end) 15 | end 16 | 17 | -------------- 18 | -- Actual code 19 | 20 | 21 | proxy.address = "procfs000" 22 | proxy.spaceUsed = function() return 0 end 23 | proxy.spaceTotal = function() return 0 end 24 | proxy.makeDirectory = function() error("Permission Denied") end 25 | proxy.isReadOnly = function() return true end 26 | proxy.rename = function() error("Permission Denied") end 27 | proxy.remove = function() error("Permission Denied") end 28 | proxy.setLabel = function() error("Permission Denied") end 29 | proxy.seek = function() error("Not supported") end 30 | proxy.getLabel = function() return "procfs" end 31 | 32 | local allocator, handles = kernel.modules.util.getAllocator() 33 | 34 | proxy.exists = function()end 35 | 36 | proxy.open = function(path) 37 | local seg = kernel.modules.vfs.segments(path) 38 | local file = data 39 | for _, d in pairs(seg) do 40 | file = file[d] 41 | end 42 | local hnd = allocator:get() 43 | hnd.data = type(file) == "function" and file() or tostring(file) 44 | hnd.at = 1 45 | function hnd:read(n) 46 | n = n or #self.data 47 | local d = string.sub(self.data, self.at, self.at + n) 48 | self.at = self.at + n 49 | return #d > 0 and d or nil 50 | end 51 | return hnd.id 52 | end 53 | 54 | proxy.read = function(h, n) 55 | return handles[h]:read(n) 56 | end 57 | 58 | proxy.close = function(h) 59 | allocator:unset(handles[h]) 60 | end 61 | 62 | proxy.write = function() error("Permission Denied") end 63 | 64 | proxy.size = function(path) 65 | local seg = kernel.modules.vfs.segments(path) 66 | local file = data 67 | for _, d in pairs(seg) do 68 | file = file[d] 69 | end 70 | return type(file) == "function" and #(file()) or 0 71 | end 72 | 73 | proxy.isDirectory = function() 74 | 75 | end 76 | 77 | proxy.list = function(path) 78 | local seg = kernel.modules.vfs.segments(path) 79 | local dir = data 80 | for _, d in pairs(seg) do 81 | dir = dir[d] 82 | end 83 | local list = {} 84 | for pid, thr in pairs(kernel.modules.threading.threads) do 85 | if thr.coro and dir == data then 86 | list[#list + 1] = tostring(pid) .. "/" 87 | end 88 | end 89 | if type(dir) ~= "table" then 90 | return nil, "Not a directory" 91 | end 92 | for f, node in pairs(dir) do 93 | list[#list + 1] = f .. (type(node) == "table" and "/" or "") 94 | end 95 | return list 96 | end 97 | 98 | data.meminfo = function() 99 | return "MemTotal: " .. math.floor(computer.totalMemory() / 1024) .. " kB\n" 100 | .. "MemFree: " .. math.floor(computer.freeMemory() / 1024) .. " kB\n" 101 | --Buffers?? 102 | end 103 | 104 | data.cpuinfo = function() 105 | return "processor : 0\n" .. 106 | "vendor_id : OpenComputersLua\n" .. 107 | "cpu family : 1\n" .. 108 | "model : 1\n" .. 109 | "model name : OpenComputers Lua CPU @ unkown Tier\n" .. 110 | "microcode : " .. (string.pack and "0x53" or "0x52") .. "\n" .. 111 | "physical id : 0\n" 112 | end 113 | 114 | data.uptime = function() 115 | return tostring(computer.uptime()) 116 | end 117 | 118 | data.sys = {} 119 | 120 | data.sys.kernel = {} 121 | data.sys.fs = {} 122 | 123 | 124 | data.sys.kernel.random = {} 125 | 126 | data.sys.kernel.random.uuid = function() 127 | return uuid() 128 | end 129 | 130 | data.sys.kernel.random.boot_id = function() 131 | return bootID 132 | end 133 | 134 | data.sys.kernel.version = function()return _OSVERSION end 135 | 136 | data.sys.kernel.poweroff_cmd = function()return "/bin/shutdown.lua" end 137 | 138 | data.sys.kernel["real-root-dev"] = function()return realroot end 139 | 140 | setmetatable(data, {__index = function(_, k) 141 | if tonumber(k) and kernel.modules.threading.threads[tonumber(k)] and kernel.modules.threading.threads[tonumber(k)].coro then 142 | return { 143 | comm = function()return kernel.modules.threading.threads[tonumber(k)].name end, 144 | limits = function() 145 | local limits = "Limit Units Soft Limit\n" 146 | limits = limits .. "Max pending signals signals " .. kernel.modules.threading.threads[tonumber(k)].maxPendingSignals .. "\n" 147 | limits = limits .. "Max open files files " .. kernel.modules.threading.threads[tonumber(k)].maxOpenFiles .. "\n" 148 | return limits 149 | end, 150 | status = function() 151 | local status = "" 152 | status = status .. "Name: " .. kernel.modules.threading.threads[tonumber(k)].name .. "\n" 153 | status = status .. "State: " .. coroutine.status(kernel.modules.threading.threads[tonumber(k)].coro) .. "\n" 154 | status = status .. "Pid: " .. kernel.modules.threading.threads[tonumber(k)].pid .. "\n" 155 | status = status .. "Uid: " .. kernel.modules.threading.threads[tonumber(k)].uid .. "\n" 156 | 157 | --TODO: count actual signals 158 | status = status .. "SigQ: " .. #kernel.modules.threading.threads[tonumber(k)].eventQueue .. "/" .. kernel.modules.threading.threads[tonumber(k)].maxPendingSignals .. "\n" 159 | status = status .. "CurH: " .. kernel.modules.threading.threads[tonumber(k)].currentHandler .. "\n" 160 | return status 161 | end 162 | } 163 | end 164 | end}) 165 | 166 | function start() 167 | kernel.modules.vfs.mount(proxy, "/proc") 168 | bootID = uuid() 169 | kernel.io.println("Boot UUID is " .. bootID) 170 | end 171 | -------------------------------------------------------------------------------- /pipes/10_sysfs.lua: -------------------------------------------------------------------------------- 1 | proxy = {} 2 | data = {} 3 | 4 | proxy.address = "sysfs0000" 5 | proxy.spaceUsed = function() return 0 end 6 | proxy.spaceTotal = function() return 0 end 7 | proxy.makeDirectory = function() error("Permission Denied") end 8 | proxy.isReadOnly = function() return true end 9 | proxy.rename = function() error("Permission Denied") end 10 | proxy.remove = function() error("Permission Denied") end 11 | proxy.setLabel = function() error("Permission Denied") end 12 | proxy.size = function(path) 13 | local seg = kernel.modules.vfs.segments(path) 14 | local file = data 15 | for _, d in pairs(seg) do 16 | file = file[d] 17 | end 18 | return file.size and file.size() or 0 19 | end 20 | proxy.getLabel = function() return "sysfs" end 21 | 22 | local allocator, handles = kernel.modules.util.getAllocator() 23 | 24 | proxy.exists = function(path) 25 | local seg = kernel.modules.vfs.segments(path) 26 | local file = data 27 | for _, d in pairs(seg) do 28 | if not file[d] then 29 | return false 30 | end 31 | file = file[d] 32 | end 33 | return file and true or false 34 | end 35 | proxy.open = function(path) 36 | kernel.io.debug("Sysfs open: " .. tostring(path)) 37 | local seg = kernel.modules.vfs.segments(path) 38 | local file = data 39 | for _, d in pairs(seg) do 40 | if not file[d] then 41 | return nil, "File not found" 42 | end 43 | file = file[d] 44 | end 45 | local hnd = allocator:get() 46 | hnd.file = file 47 | if hnd.file.open then 48 | hnd.file.open(hnd) 49 | end 50 | return hnd.id 51 | end 52 | proxy.read = function(h, ...) 53 | return handles[h].file.read(handles[h], ...) 54 | end 55 | proxy.close = function(h) 56 | if handles[h].file.close then 57 | handles[h].file.close(handles[h]) 58 | end 59 | allocator:unset(handles[h]) 60 | end 61 | proxy.write = function(h, ...) 62 | return handles[h].file.write(handles[h], ...) 63 | end 64 | proxy.seek = function(h, ...) 65 | return handles[h].file.seek(handles[h], ...) 66 | end 67 | proxy.isDirectory = function(path) 68 | local seg = kernel.modules.vfs.segments(path) 69 | local dir = data 70 | for _, d in pairs(seg) do 71 | dir = dir[d] 72 | end 73 | if dir.__type then 74 | return false 75 | end 76 | return true 77 | end 78 | proxy.list = function(path) 79 | local seg = kernel.modules.vfs.segments(path) 80 | local dir = data 81 | for _, d in pairs(seg) do 82 | dir = dir[d] 83 | end 84 | if dir.__type then 85 | error("File is not a directory") 86 | end 87 | local list = {} 88 | for f, node in pairs(dir) do 89 | list[#list + 1] = f .. (node.__type and "" or "/") 90 | end 91 | return list 92 | end 93 | 94 | ----- 95 | 96 | function roFile(data) 97 | return { 98 | __type = "f", 99 | read = function(h) 100 | if h.read then 101 | return nil 102 | end 103 | h.read = true 104 | return (type(data) == "function") and data() or tostring(data) 105 | end 106 | } 107 | end 108 | 109 | data.net = {} 110 | 111 | function start() 112 | kernel.modules.vfs.mount(proxy, "/sys") 113 | end 114 | -------------------------------------------------------------------------------- /pipes/11_block.lua: -------------------------------------------------------------------------------- 1 | local devices = {} 2 | local dfs = kernel.modules.devfs.data 3 | scanners = {} 4 | 5 | function register(uuid, name, device, scan) 6 | if devices[uuid] then 7 | return 8 | end 9 | 10 | if dfs[name] then 11 | return 12 | end 13 | 14 | devices[uuid] = {name = name} 15 | dfs[name] = device 16 | 17 | if scan then 18 | for k, v in pairs(scanners) do 19 | v(device, uuid, name) 20 | end 21 | end 22 | end 23 | 24 | function unregister(uuid) 25 | if not devices[uuid] then 26 | return 27 | end 28 | dfs[devices[uuid].name] = nil 29 | end 30 | -------------------------------------------------------------------------------- /pipes/15_keventd.lua: -------------------------------------------------------------------------------- 1 | listeners = {} 2 | 3 | function listen(signal, listener) 4 | listeners[signal] = listeners[signal] or {} 5 | listeners[signal][#listeners[signal] + 1] = listener 6 | end 7 | 8 | function start() 9 | thread = kernel.modules.threading.spawn(function() 10 | while true do 11 | local sig = {coroutine.yield("signal", dl)} 12 | if listeners[sig[1]] then 13 | for _, listener in pairs(listeners[sig[1]]) do 14 | --pcall(kernel.io.println, "KEVD: "..sig[1]) 15 | xpcall(listener, function(e) 16 | kernel.io.println("keventd error("..tostring(sig[1]).."): "..tostring(e)) 17 | pcall(kernel.io.println, debug.traceback()) 18 | end, table.unpack(sig)) 19 | end 20 | end 21 | end 22 | end, 0, "[keventd]") 23 | setmetatable(thread.env, {__index = kernel.modules.init.thread.env}) 24 | end 25 | -------------------------------------------------------------------------------- /pipes/15_userspace.lua: -------------------------------------------------------------------------------- 1 | kernel.userspace = setmetatable({}, {__index = kernel._K}) 2 | 3 | kernel.userspace.computer = {} 4 | 5 | kernel.userspace.computer.address = kernel._K.computer.address 6 | kernel.userspace.computer.tmpAddress = kernel._K.computer.tmpAddress 7 | kernel.userspace.computer.freeMemory = kernel._K.computer.freeMemory 8 | kernel.userspace.computer.totalMemory = kernel._K.computer.totalMemory 9 | kernel.userspace.computer.energy = kernel._K.computer.energy 10 | kernel.userspace.computer.maxEnergy = kernel._K.computer.maxEnergy 11 | kernel.userspace.computer.isAvailable = kernel._K.computer.isAvailable 12 | kernel.userspace.computer.users = kernel._K.computer.users 13 | kernel.userspace.computer.addUser = kernel._K.computer.addUser 14 | kernel.userspace.computer.removeUser = kernel._K.computer.removeUser 15 | kernel.userspace.computer.pushSignal = kernel._K.computer.pushSignal 16 | kernel.userspace.computer.uptime = kernel._K.computer.uptime 17 | kernel.userspace.computer.getBootAddress = kernel._K.computer.getBootAddress 18 | 19 | kernel.userspace.computer.shutdown = kernel.modules.gc.shutdown 20 | 21 | kernel.userspace.computer.pullSignal = function(timeout) 22 | kernel.modules.threading.currentThread.deadline = computer.uptime() + (timeout or math.huge) 23 | return coroutine.yield("signal") 24 | end 25 | 26 | kernel.userspace.computer.hasSignal = function(sigType) 27 | for _,v in ipairs(kernel.modules.threading.currentThread.eventQueue) do 28 | if v[1] == (sigType or "signal") then 29 | return true 30 | end 31 | end 32 | return false 33 | end 34 | 35 | kernel.userspace.coroutine = {} 36 | 37 | kernel.userspace.os = setmetatable({}, {__index = kernel._K.os}) 38 | 39 | kernel.userspace.os.remove = kernel.modules.vfs.remove 40 | kernel.userspace.os.rename = kernel.modules.vfs.rename 41 | 42 | function kernel.userspace.os.spawn(prog, ...) 43 | local isThread = type(prog) == "function" 44 | local name = isThread and kernel.modules.threading.currentThread.name or "unknown" 45 | if type(prog) == "string" then 46 | name = kernel.modules.vfs.resolve(prog) 47 | prog, reason = kernel._G.loadfile(prog, nil, kernel._G) 48 | if not prog then 49 | error(tostring(reason) .. ": " .. tostring(prog)) 50 | end 51 | end 52 | local thread = kernel.modules.threading.spawn(prog, 0, name, isThread, _, ...) 53 | thread.io_output = kernel.modules.threading.currentThread.io_output 54 | thread.io_input = kernel.modules.threading.currentThread.io_input 55 | thread.io_error = kernel.modules.threading.currentThread.io_error 56 | return thread.pid 57 | end 58 | 59 | function kernel.userspace.os.spawnp(prog, stdin, stdout, stderr, ...) 60 | local isThread = type(prog) == "function" 61 | local name = isThread and kernel.modules.threading.currentThread.name or "unknown" 62 | if type(prog) == "string" then 63 | name = kernel.modules.vfs.resolve(prog) 64 | prog, reason = kernel._G.loadfile(prog, nil, kernel._G) 65 | if not prog then 66 | error(tostring(reason) .. ": " .. tostring(prog)) 67 | end 68 | end 69 | local thread = kernel.modules.threading.spawn(prog, 0, name, isThread, _, ...) 70 | thread.env["_"] = name 71 | thread.io_output = stdout --todo: check types! 72 | thread.io_error = stderr --todo: check types! 73 | thread.io_input = stdin 74 | return thread.pid 75 | end 76 | 77 | function kernel.userspace.os.kill(pid, signal) 78 | return kernel.modules.threadUtil.userKill(pid, signal or "terminate") 79 | end 80 | 81 | function kernel.userspace.os.exit() 82 | kernel.modules.threading.kill(kernel.modules.threading.currentThread.pid) 83 | coroutine.yield("yield") 84 | end 85 | 86 | function kernel.userspace.os.sleep(time) 87 | kernel.modules.threading.currentThread.deadline = computer.uptime() + (time or 0) 88 | coroutine.yield("yield") 89 | end 90 | 91 | function kernel.userspace.os.getenv(name) 92 | return kernel.modules.threading.currentThread.env[name] 93 | end 94 | 95 | function kernel.userspace.os.setenv(name, value) 96 | kernel.modules.threading.currentThread.env[name] = value 97 | end 98 | 99 | function kernel.userspace.dofile(filename, env) 100 | local program, reason = kernel.userspace.loadfile(filename, nil, env or kernel._G) 101 | if not program then 102 | return error(reason, 0) 103 | end 104 | return program() 105 | end 106 | 107 | function kernel.userspace.loadfile(filename, mode, env) 108 | local file, reason = kernel.modules.io.io.open(filename) 109 | if not file then 110 | return nil, reason 111 | end 112 | local source, reason = file:read("*a") 113 | file:close() 114 | if not source then 115 | return nil, reason 116 | end 117 | if string.sub(source, 1, 1) == "#" then 118 | local endline = string.find(source, "\n", 2, true) 119 | if endline then 120 | source = string.sub(source, endline + 1) 121 | else 122 | source = "" 123 | end 124 | end 125 | return kernel._G.load(source, "=" .. filename, mode, env or kernel._G) 126 | end 127 | 128 | function kernel.userspace.load(ld, source, mode, env) 129 | return load(ld, source, mode, env or kernel._G) 130 | end 131 | 132 | function kernel.userspace.print(...) 133 | local args = table.pack(...) 134 | kernel.modules.io.io.stdout:setvbuf("line") 135 | for i = 1, args.n do 136 | local arg = tostring(args[i]) 137 | if i > 1 then 138 | arg = "\t" .. arg 139 | end 140 | kernel.modules.io.io.stdout:write(arg) 141 | end 142 | kernel.modules.io.io.stdout:write("\n") 143 | kernel.modules.io.io.stdout:setvbuf("no") 144 | kernel.modules.io.io.stdout:flush() 145 | end 146 | 147 | kernel.userspace.coroutine = {} 148 | 149 | --lua 5.3 <-> 5.2 compat 150 | kernel.userspace.bit32 = bit32 or load([[return { 151 | band = function(a, b) return a & b end, 152 | bor = function(a, b) return a | b end, 153 | bxor = function(a, b) return a ~ b end, 154 | bnot = function(a) return ~a end, 155 | rshift = function(a, n) return a >> n end, 156 | lshift = function(a, n) return a << n end, 157 | }]])() 158 | -------------------------------------------------------------------------------- /pipes/16_require.lua: -------------------------------------------------------------------------------- 1 | 2 | kernel.userspace.package = {} 3 | 4 | kernel.userspace.package.loaded = {} 5 | kernel.userspace.package.preload = {} 6 | kernel.userspace.package.loading = {} 7 | kernel.userspace.package.searchers = {} 8 | 9 | local function preloadSearcher(module) 10 | return kernel.userspace.package.preload[module] 11 | end 12 | 13 | function kernel.userspace.package.searchpath(name, path, sep, rep) 14 | checkArg(1, name, "string") 15 | checkArg(2, path, "string") 16 | sep = sep or '.' 17 | rep = rep or '/' 18 | sep, rep = '%' .. sep, rep 19 | name = string.gsub(name, sep, rep) 20 | local fs = kernel.modules.vfs 21 | local errorFiles = {} 22 | for subPath in string.gmatch(path, "([^;]+)") do 23 | subPath = string.gsub(subPath, "?", name) 24 | if subPath:sub(1, 1) ~= "/" and os.getenv then 25 | subPath = fs.concat(kernel.userspace.os.getenv("PWD") or "/", subPath) 26 | end 27 | if fs.exists(subPath) then 28 | local file = kernel.modules.io.io.open(subPath, "r") 29 | if file then 30 | file:close() 31 | return subPath 32 | end 33 | end 34 | table.insert(errorFiles, "\tno file '" .. subPath .. "'") 35 | end 36 | return nil, table.concat(errorFiles, "\n") 37 | end 38 | 39 | local function pathSearcher(module) 40 | local filepath, reason = kernel.userspace.package.searchpath(module, kernel.userspace.os.getenv("LIBPATH")) 41 | if filepath then 42 | local loader 43 | loader, reason = kernel.userspace.loadfile(filepath, "bt", setmetatable({},{__index = kernel.userspace})) 44 | if loader then 45 | local state 46 | state, reason = pcall(loader) 47 | if state then 48 | return reason 49 | end 50 | end 51 | end 52 | return nil, reason 53 | end 54 | 55 | kernel.userspace.package.searchers[#kernel.userspace.package.searchers + 1] = preloadSearcher 56 | kernel.userspace.package.searchers[#kernel.userspace.package.searchers + 1] = pathSearcher 57 | 58 | --TODO: possibly wrap result into metatable 59 | kernel.userspace.require = function(module) 60 | --kernel.io.println(module) 61 | if kernel.userspace.package.loaded[module] then 62 | return kernel.userspace.package.loaded[module] 63 | else 64 | if kernel.userspace.package.loading[module] then 65 | error("Already loading "..tostring(module)) 66 | else 67 | local reason 68 | 69 | kernel.userspace.package.loading[module] = true 70 | for _, searcher in ipairs(kernel.userspace.package.searchers) do 71 | local success, mod, res = pcall(searcher, module) 72 | if success and mod then 73 | kernel.userspace.package.loading[module] = nil 74 | kernel.userspace.package.loaded[module] = mod 75 | return mod 76 | elseif (not success) and mod then 77 | reason = mod 78 | elseif res then 79 | reason = res 80 | end 81 | end 82 | kernel.userspace.package.loading[module] = nil 83 | error(string.format("Could not load module '%s': %s", module, reason or "module returned nil")) 84 | end 85 | end 86 | end 87 | 88 | function start() 89 | kernel.userspace.package.preload.package = kernel.userspace.package --TODO TODO TODO: METATABLE THIZ!!!!!!!! 90 | kernel.userspace.package.preload.filesystem = setmetatable({}, {__index = kernel.modules.vfs}) 91 | kernel.userspace.package.preload.buffer = setmetatable({}, {__index = kernel.modules.buffer}) 92 | kernel.userspace.package.preload.bit32 = setmetatable({}, {__index = kernel.userspace.bit32}) 93 | kernel.userspace.package.preload.component = setmetatable({}, {__index = kernel.userspace.component}) 94 | kernel.userspace.package.preload.computer = setmetatable({}, {__index = kernel.userspace.computer}) 95 | kernel.userspace.package.preload.io = setmetatable({}, {__index = kernel.modules.io.io}) 96 | kernel.userspace.package.preload.unicode = setmetatable({}, {__index = kernel.userspace.unicode}) 97 | kernel.userspace.package.preload.os = setmetatable({}, {__index = kernel.userspace.os}) 98 | 99 | --TODO: fix override.. maybe 100 | 101 | setmetatable(kernel.userspace.package.preload, { 102 | __index = function(t, k) 103 | return kernel.modules.threading.currentThread.cgroups.module.preload[k] 104 | end, 105 | __newindex = function(t, k, v) 106 | kernel.modules.threading.currentThread.cgroups.module.preload[k] = v 107 | end 108 | }) 109 | 110 | setmetatable(kernel.userspace.package.loaded, { 111 | __index = function(t, k) 112 | return kernel.modules.threading.currentThread.cgroups.module.loaded[k] 113 | end, 114 | __newindex = function(t, k, v) 115 | kernel.modules.threading.currentThread.cgroups.module.loaded[k] = v 116 | end 117 | }) 118 | 119 | setmetatable(kernel.userspace.package.loading, { 120 | __index = function(t, k) 121 | return kernel.modules.threading.currentThread.cgroups.module.loading[k] 122 | end, 123 | __newindex = function(t, k, v) 124 | kernel.modules.threading.currentThread.cgroups.module.loading[k] = v 125 | end 126 | }) 127 | 128 | setmetatable(kernel.userspace.package.searchers, { 129 | __index = function(t, k) 130 | return kernel.modules.threading.currentThread.cgroups.module.searchers[k] 131 | end, 132 | __newindex = function(t, k, v) 133 | kernel.modules.threading.currentThread.cgroups.module.searchers[k] = v 134 | end 135 | }) 136 | end -------------------------------------------------------------------------------- /pipes/17_ipc.lua: -------------------------------------------------------------------------------- 1 | function wrap(data, name) 2 | if type(data) == "table" then 3 | for k, v in pairs(data) do 4 | data[k] = wrap(v, k) 5 | end 6 | return data 7 | elseif type(data) == "function" then 8 | local sandbox = kernel.modules.threading.currentThread.sandbox 9 | local remThread = kernel.modules.threading.currentThread 10 | return function(...) 11 | local thread = kernel.modules.threading.currentThread 12 | kernel.modules.manageg.protect(sandbox) 13 | kernel.modules.threading.currentThread = remThread 14 | local res = {xpcall(data, debug.traceback, ...)} 15 | kernel.modules.threading.currentThread = thread 16 | kernel.modules.manageg.unprotect() 17 | if not res[1] then 18 | error((tostring(res[2]) or "Unknown IPC error") .. (name and (" on " .. tostring(name)) or "")) 19 | else 20 | return table.unpack(res, 2) 21 | end 22 | end 23 | else 24 | return data 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /pipes/17_keyboard.lua: -------------------------------------------------------------------------------- 1 | local keyboard = {pressedChars = {}, pressedCodes = {}} 2 | 3 | keyboard.keys = { 4 | ["1"] = 0x02, 5 | ["2"] = 0x03, 6 | ["3"] = 0x04, 7 | ["4"] = 0x05, 8 | ["5"] = 0x06, 9 | ["6"] = 0x07, 10 | ["7"] = 0x08, 11 | ["8"] = 0x09, 12 | ["9"] = 0x0A, 13 | ["0"] = 0x0B, 14 | a = 0x1E, 15 | b = 0x30, 16 | c = 0x2E, 17 | d = 0x20, 18 | e = 0x12, 19 | f = 0x21, 20 | g = 0x22, 21 | h = 0x23, 22 | i = 0x17, 23 | j = 0x24, 24 | k = 0x25, 25 | l = 0x26, 26 | m = 0x32, 27 | n = 0x31, 28 | o = 0x18, 29 | p = 0x19, 30 | q = 0x10, 31 | r = 0x13, 32 | s = 0x1F, 33 | t = 0x14, 34 | u = 0x16, 35 | v = 0x2F, 36 | w = 0x11, 37 | x = 0x2D, 38 | y = 0x15, 39 | z = 0x2C, 40 | 41 | apostrophe = 0x28, 42 | at = 0x91, 43 | back = 0x0E, -- backspace 44 | backslash = 0x2B, 45 | colon = 0x92, 46 | comma = 0x33, 47 | enter = 0x1C, 48 | equals = 0x0D, 49 | grave = 0x29, -- accent grave 50 | lbracket = 0x1A, 51 | lcontrol = 0x1D, 52 | lmenu = 0x38, -- left Alt 53 | lshift = 0x2A, 54 | minus = 0x0C, 55 | numlock = 0x45, 56 | pause = 0xC5, 57 | period = 0x34, 58 | rbracket = 0x1B, 59 | rcontrol = 0x9D, 60 | rmenu = 0xB8, -- right Alt 61 | rshift = 0x36, 62 | scroll = 0x46, -- Scroll Lock 63 | semicolon = 0x27, 64 | slash = 0x35, -- / on main keyboard 65 | space = 0x39, 66 | stop = 0x95, 67 | tab = 0x0F, 68 | underline = 0x93, 69 | 70 | -- Keypad (and numpad with numlock off) 71 | up = 0xC8, 72 | down = 0xD0, 73 | left = 0xCB, 74 | right = 0xCD, 75 | home = 0xC7, 76 | ["end"] = 0xCF, 77 | pageUp = 0xC9, 78 | pageDown = 0xD1, 79 | insert = 0xD2, 80 | delete = 0xD3, 81 | 82 | -- Function keys 83 | f1 = 0x3B, 84 | f2 = 0x3C, 85 | f3 = 0x3D, 86 | f4 = 0x3E, 87 | f5 = 0x3F, 88 | f6 = 0x40, 89 | f7 = 0x41, 90 | f8 = 0x42, 91 | f9 = 0x43, 92 | f10 = 0x44, 93 | f11 = 0x57, 94 | f12 = 0x58, 95 | f13 = 0x64, 96 | f14 = 0x65, 97 | f15 = 0x66, 98 | f16 = 0x67, 99 | f17 = 0x68, 100 | f18 = 0x69, 101 | f19 = 0x71, 102 | 103 | -- Japanese keyboards 104 | kana = 0x70, 105 | kanji = 0x94, 106 | convert = 0x79, 107 | noconvert = 0x7B, 108 | yen = 0x7D, 109 | circumflex = 0x90, 110 | ax = 0x96, 111 | 112 | -- Numpad 113 | numpad0 = 0x52, 114 | numpad1 = 0x4F, 115 | numpad2 = 0x50, 116 | numpad3 = 0x51, 117 | numpad4 = 0x4B, 118 | numpad5 = 0x4C, 119 | numpad6 = 0x4D, 120 | numpad7 = 0x47, 121 | numpad8 = 0x48, 122 | numpad9 = 0x49, 123 | numpadmul = 0x37, 124 | numpaddiv = 0xB5, 125 | numpadsub = 0x4A, 126 | numpadadd = 0x4E, 127 | numpaddecimal = 0x53, 128 | numpadcomma = 0xB3, 129 | numpadenter = 0x9C, 130 | numpadequals = 0x8D, 131 | } 132 | 133 | -- Create inverse mapping for name lookup. 134 | do 135 | local keys = {} 136 | for k in pairs(keyboard.keys) do 137 | table.insert(keys, k) 138 | end 139 | for _, k in pairs(keys) do 140 | keyboard.keys[keyboard.keys[k]] = k 141 | end 142 | end 143 | 144 | ------------------------------------------------------------------------------- 145 | 146 | function keyboard.isAltDown() 147 | return (keyboard.pressedCodes[keyboard.keys.lmenu] or keyboard.pressedCodes[keyboard.keys.rmenu]) ~= nil 148 | end 149 | 150 | function keyboard.isControl(char) 151 | return type(char) == "number" and (char < 0x20 or (char >= 0x7F and char <= 0x9F)) 152 | end 153 | 154 | function keyboard.isControlDown() 155 | return (keyboard.pressedCodes[keyboard.keys.lcontrol] or keyboard.pressedCodes[keyboard.keys.rcontrol]) ~= nil 156 | end 157 | 158 | function keyboard.isKeyDown(charOrCode) 159 | checkArg(1, charOrCode, "string", "number") 160 | if type(charOrCode) == "string" then 161 | return keyboard.pressedChars[charOrCode] 162 | elseif type(charOrCode) == "number" then 163 | return keyboard.pressedCodes[charOrCode] 164 | end 165 | end 166 | 167 | function keyboard.isShiftDown() 168 | return (keyboard.pressedCodes[keyboard.keys.lshift] or keyboard.pressedCodes[keyboard.keys.rshift]) ~= nil 169 | end 170 | 171 | ------------------------------------------------------------------------------- 172 | 173 | kernel.userspace.package.preload.keyboard = keyboard 174 | 175 | function start() 176 | local function onKeyDown(_, address, char, code) 177 | if component.isPrimary(address) then 178 | keyboard.pressedChars[char] = true 179 | keyboard.pressedCodes[code] = true 180 | end 181 | end 182 | 183 | local function onKeyUp(_, address, char, code) 184 | if component.isPrimary(address) then 185 | keyboard.pressedChars[char] = nil 186 | keyboard.pressedCodes[code] = nil 187 | end 188 | end 189 | 190 | local function onComponentUnavailable(_, componentType) 191 | if componentType == "keyboard" then 192 | keyboard.pressedChars = {} 193 | keyboard.pressedCodes = {} 194 | end 195 | end 196 | 197 | kernel.modules.keventd.listen("key_down", onKeyDown) 198 | kernel.modules.keventd.listen("key_up", onKeyUp) 199 | kernel.modules.keventd.listen("component_unavailable", onComponentUnavailable) 200 | end 201 | -------------------------------------------------------------------------------- /pipes/18_pty.lua: -------------------------------------------------------------------------------- 1 | allocator, list = kernel.modules.util.getAllocator() 2 | 3 | function new() 4 | local pty = allocator:get() 5 | pty.mi, pty.so = kernel.modules.buffer.pipe() 6 | pty.si, pty.mo = kernel.modules.buffer.pipe() 7 | 8 | function pty:read(...) 9 | return self.si:read(...) 10 | end 11 | 12 | function pty:write(...) 13 | return self.so:write(...) 14 | end 15 | 16 | return pty.id, pty.mi, pty.mo, pty.si, pty.so 17 | end 18 | 19 | function nextPty(at) 20 | local pty = at and tonumber(at) + 1 or 1 21 | if not list[pty] then 22 | return 23 | elseif list[pty].next then 24 | return nextPty(pty) 25 | else 26 | return pty, { 27 | __type = "f", 28 | read = function(h, ...) 29 | return list[pty]:read(...) 30 | end, 31 | write = function(h, ...) 32 | return list[pty]:write(...) 33 | end 34 | } 35 | end 36 | end 37 | 38 | function start() 39 | setmetatable(kernel.modules.devfs.data.pts, { 40 | __newindex = function()error("Access denied")end, 41 | __index = function(_,k) 42 | if list[tonumber(k)] and list[tonumber(k)].id then 43 | return { 44 | __type = "f", 45 | read = function(h, ...) 46 | return list[tonumber(k)]:read(...) 47 | end, 48 | write = function(h, ...) 49 | return list[tonumber(k)]:write(...) 50 | end 51 | } 52 | end 53 | end, 54 | __pairs = function() 55 | local lastIndex = nil 56 | return function() 57 | local k, v = nextPty(lastIndex) 58 | lastIndex = k 59 | if not k then return end 60 | return k and tostring(k), k and v 61 | end 62 | end 63 | }) 64 | end 65 | -------------------------------------------------------------------------------- /pipes/18_syscall.lua: -------------------------------------------------------------------------------- 1 | kernel.userspace.package.preload.pipes = {} 2 | 3 | kernel.userspace.package.preload.pipes.setKernelOutput = function(sink) 4 | kernel.io.println = function(str) 5 | sink:setvbuf("line") 6 | sink:write("[dmesg] ") 7 | sink:write(tostring(str)) 8 | sink:write("\n") 9 | sink:setvbuf("no") 10 | sink:flush() 11 | end 12 | end 13 | 14 | function start() 15 | kernel.userspace.package.preload.pipes.joinThread = kernel.modules.threadUtil.joinThread 16 | kernel.userspace.package.preload.pipes.getThreadInfo = kernel.modules.threadUtil.getThreadInfo 17 | kernel.userspace.package.preload.pipes.setKillHandler = kernel.modules.threadUtil.setKillHandler 18 | kernel.userspace.package.preload.pipes.getPid = function() 19 | return kernel.modules.threading.currentThread.pid, kernel.modules.threading.currentThread.uid 20 | end 21 | 22 | kernel.userspace.package.preload.pipes.shouldYield = kernel.modules.threading.checkTimeout 23 | kernel.userspace.package.preload.pipes.setTimer = kernel.modules.timer.add 24 | kernel.userspace.package.preload.pipes.removeTimer = kernel.modules.timer.remove 25 | kernel.userspace.package.preload.pipes.setThreadName = function(name) 26 | kernel.modules.threading.currentThread.name = name 27 | end 28 | kernel.userspace.package.preload.pipes.log = function(msg) 29 | kernel.io.println(msg) 30 | end 31 | 32 | kernel.userspace.package.preload.pipes.openPty = kernel.modules.pty.new 33 | kernel.userspace.package.preload.pipes.cowProxy = kernel.modules.cowfs.new 34 | 35 | kernel.userspace.package.preload.pipes.wrapIPC = kernel.modules.ipc.wrap 36 | 37 | kernel.userspace.package.preload.pipes.setns = kernel.modules.cgroups.new 38 | end -------------------------------------------------------------------------------- /pipes/19_cgroups.lua: -------------------------------------------------------------------------------- 1 | local function newGroup() 2 | local group = { 3 | childs = {}, 4 | processes = {} 5 | } 6 | return group 7 | end 8 | 9 | spawnGroupGetters = {} 10 | groupConstructors = {} 11 | 12 | groupConstructors.signal = function(global) 13 | local group = newGroup() 14 | group.global = global --boolean 15 | return group 16 | end 17 | 18 | groupConstructors.filesystem = function(root) 19 | local group = newGroup() 20 | group.root = root 21 | return group 22 | end 23 | 24 | groupConstructors.network = function() 25 | local group = newGroup() 26 | group.interfaces = {} 27 | return group 28 | end 29 | 30 | groupConstructors.module = function() 31 | local group = newGroup() 32 | 33 | group.preload = { 34 | package = kernel.userspace.package, --TODO TODO TODO: METATABLE THIZ!!!!!!!! 35 | filesystem = setmetatable({}, {__index = kernel.modules.vfs}), 36 | buffer = setmetatable({}, {__index = kernel.modules.buffer}), 37 | bit32 = setmetatable({}, {__index = kernel.userspace.bit32}), 38 | component = setmetatable({}, {__index = kernel.userspace.component}), 39 | computer = setmetatable({}, {__index = kernel.userspace.computer}), 40 | io = setmetatable({}, {__index = kernel.modules.io.io}), 41 | unicode = setmetatable({}, {__index = kernel.userspace.unicode}), 42 | } 43 | group.loaded = {} 44 | group.loading = {} 45 | group.searchers = {} 46 | return group 47 | end 48 | 49 | groupConstructors.component = function(parent, wl, bl) 50 | local group = newGroup() 51 | group.parent = parent 52 | group.whitelist = wl 53 | group.blacklist = bl 54 | group.adding = not parent and kernel.modules.component.kernelGroup.adding or {} 55 | group.removing = not parent and kernel.modules.component.kernelGroup.removing or {} 56 | group.primaries = not parent and kernel.modules.component.kernelGroup.primaries or {} 57 | group.allow = function(addr) 58 | if not group.parent or group.parent.allow(addr) then 59 | return (not group.whitelist or group.whitelist[addr]) and (not group.blacklist or (not group.blacklist[addr])) 60 | end 61 | end 62 | return group 63 | end 64 | 65 | ------------------------------ 66 | 67 | spawnGroupGetters.signal = function() 68 | if not kernel.modules.threading.currentThread then 69 | return groupConstructors.signal(true) 70 | else 71 | return kernel.modules.threading.currentThread.cgroups.signal 72 | end 73 | end 74 | 75 | spawnGroupGetters.filesystem = function() 76 | if not kernel.modules.threading.currentThread then 77 | return groupConstructors.filesystem(true) 78 | else 79 | return kernel.modules.threading.currentThread.cgroups.filesystem 80 | end 81 | end 82 | 83 | spawnGroupGetters.network = function() 84 | if not kernel.modules.threading.currentThread then 85 | return groupConstructors.network() 86 | else 87 | return kernel.modules.threading.currentThread.cgroups.network 88 | end 89 | end 90 | 91 | spawnGroupGetters.module = function() 92 | if not kernel.modules.threading.currentThread then 93 | return groupConstructors.module() 94 | else 95 | return kernel.modules.threading.currentThread.cgroups.module 96 | end 97 | end 98 | 99 | spawnGroupGetters.component = function() 100 | if not kernel.modules.threading.currentThread then 101 | return groupConstructors.component() 102 | else 103 | return kernel.modules.threading.currentThread.cgroups.component 104 | end 105 | end 106 | 107 | ------------------------------ 108 | --Signal group functions 109 | 110 | function pushSignal(...) 111 | for k, thread in pairs(kernel.modules.threading.currentThread.cgroups.signal.processes) do 112 | thread.eventQueue[#thread.eventQueue + 1] = {"signal", ...} 113 | end 114 | end 115 | 116 | ------------------------------ 117 | 118 | userConstructors = {} 119 | 120 | function userConstructors.module() 121 | return groupConstructors.module() 122 | end 123 | 124 | function userConstructors.component(wl, bl) 125 | return groupConstructors.component(kernel.modules.threading.currentThread and kernel.modules.threading.currentThread.cgroups.component, wl, bl) 126 | end 127 | 128 | ------------------------------ 129 | 130 | function new(pid, name, ...) 131 | if kernel.modules.threading.currentThread.pid ~= pid and 132 | (not kernel.modules.threading.threads[pid] or 133 | not kernel.modules.threading.threads[pid].parent or 134 | kernel.modules.threading.threads[pid].parent.uid ~= kernel.modules.threading.currentThread.uid) then 135 | error("Permission denied") 136 | end 137 | if not userConstructors[name] then 138 | error("No cgroup constructor for name") 139 | end 140 | kernel.modules.threading.threads[pid].cgroups[name] = userConstructors[name](...) 141 | end 142 | 143 | -------------------------------------------------------------------------------- /pipes/19_manageg.lua: -------------------------------------------------------------------------------- 1 | local metatable = {__index = kernel._K, __newindex=function()end} 2 | 3 | function start() 4 | metatable.__index = kernel.userspace 5 | setmetatable(kernel._G, metatable) 6 | end 7 | 8 | function newsandbox() 9 | local sandbox = {} 10 | sandbox._G = sandbox 11 | sandbox.__STRICT = false 12 | 13 | local mt = {} 14 | mt.__declared = {} 15 | 16 | mt.__index = function(t, n) 17 | local res = kernel.userspace[n] 18 | if res then 19 | return res 20 | end 21 | if sandbox.__STRICT and (not mt.__declared[n]) then 22 | error("variable '"..n.."' is not declared", 2) 23 | end 24 | return rawget(t, n) 25 | end 26 | 27 | mt.__newindex = function(t, n, v) 28 | if sandbox.__STRICT and (not mt.__declared[n]) then 29 | error("assign to undeclared variable '"..n.."'", 2) 30 | end 31 | rawset(t, n, v) 32 | end 33 | 34 | return setmetatable(sandbox, mt) 35 | end 36 | 37 | --User function. Defines globals for strict mode. 38 | function global(sandbox, ...) 39 | for _, v in ipairs{...} do getmetatable(mt).__declared[v] = true end 40 | end 41 | 42 | 43 | local protectionStack = {{newindex = function()end, index = kernel.userspace}} 44 | 45 | function protect(sandbox) 46 | table.insert(protectionStack, { 47 | newindex = metatable.__newindex, 48 | index = metatable.__index 49 | }) 50 | metatable.__newindex = sandbox 51 | metatable.__index = sandbox 52 | end 53 | 54 | function unprotect() 55 | local prot = table.remove(protectionStack, protectionStack.n) 56 | metatable.__newindex = prot.newindex 57 | metatable.__index = prot.index 58 | end -------------------------------------------------------------------------------- /pipes/21_threadUtil.lua: -------------------------------------------------------------------------------- 1 | function joinThread(pid) 2 | --coroutine.yield("yield", 0) 3 | while true do 4 | local dead = coroutine.yield("kill") 5 | if pid == dead then 6 | break 7 | end 8 | end 9 | end 10 | 11 | function getThreadInfo() 12 | local info = {} 13 | kernel.modules.threading.eachThread(function(thread) 14 | info[thread.pid] = { 15 | pid = thread.pid, 16 | uid = thread.uid, 17 | name = thread.name, 18 | parent = thread.parent and thread.parent.pid or nil 19 | } 20 | end) 21 | return info 22 | end 23 | 24 | function userKill(pid, signal, ...) 25 | if not kernel.modules.threading.threads[pid] 26 | or not kernel.modules.threading.threads[pid].coro then 27 | return nil, "Thread does not exists" 28 | end 29 | if not kernel.modules.threading.threads[pid].kill[signal] then 30 | return nil, "Unknown signal" 31 | end 32 | local args = {...} 33 | local thread = kernel.modules.threading.threads[pid] 34 | kernel.modules.manageg.protect(thread.sandbox) 35 | --TODO: probably set threading.currentThread here 36 | local res, reason = pcall(function() 37 | thread.kill[signal](table.unpack(args)) 38 | end) 39 | kernel.modules.manageg.unprotect() 40 | if not res then 41 | kernel.modules.threading.kill(pid) 42 | end 43 | return true 44 | end 45 | 46 | function select(timeout, ...) 47 | checkArg(1, timeout, "number") 48 | local funcs = {} 49 | for n, f in ipairs(...) do 50 | checkArg(n + 1, f, "function") 51 | funcs[n] = coroutine.create(f) 52 | end 53 | 54 | end 55 | 56 | function setKillHandler(signal, handler) --WAT 57 | if not kernel.modules.threading.threads[pid] 58 | or not kernel.modules.threading.threads[pid].coro then 59 | return nil, "Thread does not exists" 60 | end 61 | if signal == "kill" then 62 | return nil, "Cannot override kill" 63 | end 64 | kernel.modules.threading.threads[pid].kill[signal] = handler 65 | return true 66 | end 67 | -------------------------------------------------------------------------------- /pipes/21_timer.lua: -------------------------------------------------------------------------------- 1 | timers = {} 2 | local nextTimer = 1 3 | local deadline = math.huge 4 | thread = nil 5 | 6 | function add(func, time) 7 | local timer = { 8 | func = func, 9 | time = time, 10 | thread = kernel.modules.threading.currentThread or "kernel", 11 | next = computer.uptime() + time 12 | } 13 | 14 | if deadline > timer.next then 15 | deadline = timer.next 16 | if thread.currentHandler == "yield" then 17 | thread.deadline = deadline 18 | end 19 | end 20 | 21 | local n = nextTimer 22 | if timers[n] then 23 | nextTimer = timers[n].next 24 | else 25 | nextTimer = nextTimer + 1 26 | end 27 | 28 | timers[n] = timer 29 | return n 30 | end 31 | 32 | function remove(tid) 33 | --TODO: rights check 34 | timers[tid] = {next = nextTimer} 35 | nextTimer = tid 36 | end 37 | 38 | thread = kernel.modules.threading.spawn(function() 39 | while true do 40 | local now = computer.uptime() 41 | for n, timer in ipairs(timers) do 42 | if timer.thread then 43 | if timer.next <= now then 44 | if type(timer.thread) == "table" then 45 | kernel.modules.manageg.protect(timer.thread.sandbox) 46 | kernel.modules.threading.currentThread = timer.thread 47 | end 48 | local res, reason = pcall(timer.func, now) 49 | if type(timer.thread) == "table" then 50 | kernel.modules.threading.currentThread = thread 51 | kernel.modules.manageg.unprotect() 52 | end 53 | if res then 54 | timer.next = now + timer.time 55 | if deadline > timer.next then 56 | deadline = timer.next 57 | end 58 | else 59 | kernel.io.println("Timer " .. n .. " died: " .. tostring(reason)) 60 | remove(n) 61 | end 62 | else 63 | if deadline > timer.next then 64 | deadline = timer.next 65 | end 66 | end 67 | end 68 | end 69 | thread.deadline = deadline 70 | deadline = math.huge 71 | coroutine.yield("yield") 72 | end 73 | end, 0, "[timer]") 74 | 75 | -------------------------------------------------------------------------------- /pipes/25_init.lua: -------------------------------------------------------------------------------- 1 | kernel.io.println("Installing init thread") 2 | 3 | thread = kernel.modules.threading.spawn(function() 4 | kernel.io.println("Execute init") 5 | 6 | kernel._G.dofile("/bin/init.lua", kernel._G) 7 | kernel.io.println("Init is dead") 8 | kernel.panic() 9 | end, 0, "[init]") 10 | 11 | --HAX 12 | setmetatable(kernel.modules.timer.thread.env, {__index = thread.env}) 13 | -------------------------------------------------------------------------------- /plan9k-containers/sandbox.lua: -------------------------------------------------------------------------------- 1 | local shell = require("shell") 2 | local kernel = require("pipes") 3 | local component = require("component") 4 | 5 | local args = {...} 6 | local options = {} 7 | 8 | for _, v in ipairs(args) do 9 | if v:sub(1,2) == "--" then 10 | options[v:sub(3)] = true 11 | elseif v:sub(1,1) == "-" then 12 | options[v:sub(2)] = true 13 | end 14 | end 15 | 16 | if options.h or options.help then 17 | print([[sandbox [flow] [spawn [file] [args Nargs ...] ]... 18 | Sandbox a processes/process tree 19 | Options: 20 | -h --help - this help 21 | Commands: 22 | spawn file [args Nargs ...] - spawn process 23 | join - wait for last process to finish 24 | module - create module cgroup 25 | component - create component cgroup 26 | befor this command put: 27 | wl [addr] - whitelist a component 28 | bl [addr] - blacklist a component 29 | quietin, quietout, quieterr - disable stdin/out/err 30 | Example usages: 31 | sandbox module spawn /usr/bin/myprog.lua args 3 hello 123 world join 32 | - Spawns myprog in new module cgroup with 3 arguments and wait for it 33 | sandbox module spawn /bin/a.lua spawn /bin/b.lua 34 | - Spawns 2 programs in new common module cgroup 35 | sandbox bl 0ab component spawn /bin/a.lua 36 | - Spawn process with disallowed access to componet starting with address 0ab 37 | sandbox wl fc0 wl fcd component spawn /bin/a.lua 38 | - Spawns process wich can only acces 2 specified components 39 | sandbox -b quietin quietout /bin/a.lua 40 | - Spawns process in background 41 | ]]) 42 | return 43 | end 44 | 45 | --[[ 46 | local program = os.getenv("SHELL") or "/bin/sh.lua" 47 | 48 | if #args > 0 then 49 | program = table.remove(args, 1) 50 | end 51 | 52 | local module 53 | if options.m or options.module then 54 | module = kernel.setns(kernel.getPid(), "module") 55 | end 56 | 57 | local pid = os.spawn(program, table.unpack(args)) 58 | 59 | kernel.joinThread(pid) 60 | ]] 61 | 62 | local lastpid = nil 63 | local stdin = io.stdin 64 | local stdout = io.stdout 65 | local stderr = io.stderr 66 | 67 | local module 68 | local componentcg 69 | local wl = nil 70 | local bl = nil 71 | local n =1 72 | while n <= #args do 73 | if args[n]:sub(1,1) == "-" then 74 | elseif args[n] == "spawn" then 75 | local name = args[n + 1] 76 | local arg = {} 77 | if args[n+2] == "args" then 78 | local narg = tonumber(args[n + 3]) 79 | for i = 1, narg do 80 | arg[#arg + 1]= args[n + 3 + i] 81 | end 82 | n = n + 2 + narg 83 | end 84 | n = n + 1 85 | lastpid = os.spawnp(name, stdin, stdout, stderr, table.unpack(arg)) 86 | elseif args[n] == "join" then 87 | kernel.joinThread(lastpid) 88 | elseif args[n] == "quietin" then 89 | stdin = io.open("/dev/null", "r") 90 | elseif args[n] == "quietout" then 91 | stdout = io.open("/dev/null", "w") 92 | elseif args[n] == "quieterr" then 93 | stderr = io.open("/dev/null", "w") 94 | elseif args[n] == "module" then 95 | module = kernel.setns(kernel.getPid(), "module") 96 | elseif args[n] == "wl" then 97 | if not wl then wl = {} end 98 | wl[component.get(args[n + 1])] = true 99 | n = n + 1 100 | elseif args[n] == "bl" then 101 | if not bl then bl = {} end 102 | bl[component.get(args[n + 1])] = true 103 | n = n + 1 104 | elseif args[n] == "component" then 105 | componentcg = kernel.setns(kernel.getPid(), "component", wl, bl) 106 | else 107 | print("Unknown command '"..args[n] .."'") 108 | return 109 | end 110 | n = n + 1 111 | end 112 | -------------------------------------------------------------------------------- /plan9k-core/bin/rc.lua: -------------------------------------------------------------------------------- 1 | local rc = require('rc') 2 | 3 | local args = table.pack(...) 4 | if args.n < 1 then 5 | io.write("Usage: rc [command] [args...]\n") 6 | return 7 | end 8 | 9 | local result, reason = rc.runCommand(table.unpack(args)) 10 | 11 | if not result then 12 | io.stderr:write(reason .. "\n") 13 | end 14 | -------------------------------------------------------------------------------- /plan9k-core/lib/rc.lua: -------------------------------------------------------------------------------- 1 | local fs = require('filesystem') 2 | local serialization = require('serialization') 3 | 4 | -- Keeps track of loaded scripts to retain local values between invocation 5 | -- of their command callbacks. 6 | local loaded = {} 7 | 8 | local rc = {} 9 | 10 | local function saveConfig(conf) 11 | local file, reason = io.open('/etc/rc.cfg', 'w') 12 | if not file then 13 | return nil, reason 14 | end 15 | for key, value in pairs(conf) do 16 | file:write(tostring(key) .. " = " .. serialization.serialize(value) .. "\n") 17 | end 18 | 19 | file:close() 20 | return true 21 | end 22 | 23 | local function loadConfig() 24 | local env = {} 25 | if not fs.exists('/etc/rc.cfg') then 26 | saveConfig({enabled={}}) 27 | end 28 | local result, reason = loadfile('/etc/rc.cfg', 't', env) 29 | if result then 30 | result, reason = xpcall(result, debug.traceback) 31 | if result then 32 | return env 33 | end 34 | end 35 | return nil, reason 36 | end 37 | 38 | function rc.load(name, args) 39 | if loaded[name] then 40 | return loaded[name] 41 | end 42 | local fileName = fs.concat('/etc/rc.d/', name .. '.lua') 43 | local env = setmetatable({args = args}, {__index = _G}) 44 | local result, reason = loadfile(fileName, 't', env) 45 | if result then 46 | result, reason = xpcall(result, debug.traceback) 47 | if result then 48 | loaded[name] = env 49 | return env 50 | end 51 | end 52 | return nil, reason 53 | end 54 | 55 | function rc.unload(name) 56 | loaded[name] = nil 57 | end 58 | 59 | local function rawRunCommand(conf, name, cmd, args, ...) 60 | local result, what = rc.load(name, args) 61 | if result then 62 | if not cmd then 63 | io.output():write("Commands for service " .. name .. "\n") 64 | for command, val in pairs(result) do 65 | if type(val) == "function" then 66 | io.output():write(tostring(command) .. " ") 67 | end 68 | end 69 | return true 70 | elseif type(result[cmd]) == "function" then 71 | res, what = xpcall(result[cmd], debug.traceback, ...) 72 | if res then 73 | return true 74 | end 75 | elseif cmd == "restart" and type(result["stop"]) == "function" and type(result["start"]) == "function" then 76 | res, what = xpcall(result["stop"], debug.traceback, ...) 77 | if res then 78 | res, what = xpcall(result["start"], debug.traceback, ...) 79 | if res then 80 | return true 81 | end 82 | end 83 | elseif cmd == "enable" then 84 | conf.enabled = conf.enabled or {} 85 | for _, _name in ipairs(conf.enabled) do 86 | if name == _name then 87 | return nil, "Service already enabled" 88 | end 89 | end 90 | conf.enabled[#conf.enabled + 1] = name 91 | return saveConfig(conf) 92 | elseif cmd == "disable" then 93 | conf.enabled = conf.enabled or {} 94 | for n, _name in ipairs(conf.enabled) do 95 | if name == _name then 96 | table.remove(conf.enabled, n) 97 | end 98 | end 99 | return saveConfig(conf) 100 | else 101 | what = "Command '" .. cmd .. "' not found in daemon '" .. name .. "'" 102 | end 103 | end 104 | return nil, what 105 | end 106 | 107 | function rc.runCommand(name, cmd, ...) 108 | local conf, reason = loadConfig() 109 | if not conf then 110 | return nil, reason 111 | end 112 | return rawRunCommand(conf, name, cmd, conf[name], ...) 113 | end 114 | 115 | function rc.allRunCommand(cmd, ...) 116 | local conf, reason = loadConfig() 117 | if not conf then 118 | return nil, reason 119 | end 120 | local results = {} 121 | for _, name in ipairs(conf.enabled or {}) do 122 | results[name] = table.pack(rawRunCommand(conf, name, cmd, conf[name], ...)) 123 | end 124 | return results 125 | end 126 | 127 | return rc 128 | -------------------------------------------------------------------------------- /plan9k-corelibs/colors.lua: -------------------------------------------------------------------------------- 1 | local colors = { 2 | [0] = "white", 3 | [1] = "orange", 4 | [2] = "magenta", 5 | [3] = "lightblue", 6 | [4] = "yellow", 7 | [5] = "lime", 8 | [6] = "pink", 9 | [7] = "gray", 10 | [8] = "silver", 11 | [9] = "cyan", 12 | [10] = "purple", 13 | [11] = "blue", 14 | [12] = "brown", 15 | [13] = "green", 16 | [14] = "red", 17 | [15] = "black" 18 | } 19 | 20 | do 21 | local keys = {} 22 | for k in pairs(colors) do 23 | table.insert(keys, k) 24 | end 25 | for _, k in pairs(keys) do 26 | colors[colors[k]] = k 27 | end 28 | end 29 | 30 | return colors 31 | -------------------------------------------------------------------------------- /plan9k-corelibs/serialization.lua: -------------------------------------------------------------------------------- 1 | local serialization = {} 2 | 3 | -- Important: pretty formatting will allow presenting non-serializable values 4 | -- but may generate output that cannot be unserialized back. 5 | function serialization.serialize(value, pretty) 6 | local kw = {["and"]=true, ["break"]=true, ["do"]=true, ["else"]=true, 7 | ["elseif"]=true, ["end"]=true, ["false"]=true, ["for"]=true, 8 | ["function"]=true, ["goto"]=true, ["if"]=true, ["in"]=true, 9 | ["local"]=true, ["nil"]=true, ["not"]=true, ["or"]=true, 10 | ["repeat"]=true, ["return"]=true, ["then"]=true, ["true"]=true, 11 | ["until"]=true, ["while"]=true} 12 | local id = "^[%a_][%w_]*$" 13 | local ts = {} 14 | local function s(v, l) 15 | local t = type(v) 16 | if t == "nil" then 17 | return "nil" 18 | elseif t == "boolean" then 19 | return v and "true" or "false" 20 | elseif t == "number" then 21 | if v ~= v then 22 | return "0/0" 23 | elseif v == math.huge then 24 | return "math.huge" 25 | elseif v == -math.huge then 26 | return "-math.huge" 27 | else 28 | return tostring(v) 29 | end 30 | elseif t == "string" then 31 | return string.format("%q", v):gsub("\\\n","\\n") 32 | elseif t == "table" and pretty and getmetatable(v) and getmetatable(v).__tostring then 33 | return tostring(v) 34 | elseif t == "table" then 35 | if ts[v] then 36 | if pretty then 37 | return "recursion" 38 | else 39 | error("tables with cycles are not supported") 40 | end 41 | end 42 | ts[v] = true 43 | local i, r = 1, nil 44 | local f 45 | if pretty then 46 | local ks, sks, oks = {}, {}, {} 47 | for k in pairs(v) do 48 | if type(k) == "number" then 49 | table.insert(ks, k) 50 | elseif type(k) == "string" then 51 | table.insert(sks, k) 52 | else 53 | table.insert(oks, k) 54 | end 55 | end 56 | table.sort(ks) 57 | table.sort(sks) 58 | for _, k in ipairs(sks) do 59 | table.insert(ks, k) 60 | end 61 | for _, k in ipairs(oks) do 62 | table.insert(ks, k) 63 | end 64 | local n = 0 65 | f = table.pack(function() 66 | n = n + 1 67 | local k = ks[n] 68 | if k ~= nil then 69 | return k, v[k] 70 | else 71 | return nil 72 | end 73 | end) 74 | else 75 | f = table.pack(pairs(v)) 76 | end 77 | for k, v in table.unpack(f) do 78 | if r then 79 | r = r .. "," .. (pretty and ("\n" .. string.rep(" ", l)) or "") 80 | else 81 | r = "{" 82 | end 83 | local tk = type(k) 84 | if tk == "number" and k == i then 85 | i = i + 1 86 | r = r .. s(v, l + 1) 87 | else 88 | if tk == "string" and not kw[k] and string.match(k, id) then 89 | r = r .. k 90 | else 91 | r = r .. "[" .. s(k, l + 1) .. "]" 92 | end 93 | r = r .. "=" .. s(v, l + 1) 94 | end 95 | end 96 | ts[v] = nil -- allow writing same table more than once 97 | return (r or "{") .. "}" 98 | else 99 | if pretty then 100 | return tostring(t) 101 | else 102 | error("unsupported type: " .. t) 103 | end 104 | end 105 | end 106 | local result = s(value, 1) 107 | local limit = type(pretty) == "number" and pretty or 10 108 | if pretty then 109 | local truncate = 0 110 | while limit > 0 and truncate do 111 | truncate = string.find(result, "\n", truncate + 1, true) 112 | limit = limit - 1 113 | end 114 | if truncate then 115 | return result:sub(1, truncate) .. "..." 116 | end 117 | end 118 | return result 119 | end 120 | 121 | function serialization.unserialize(data) 122 | checkArg(1, data, "string") 123 | local result, reason = load("return " .. data, "=data", _, {math={huge=math.huge}}) 124 | if not result then 125 | return nil, reason 126 | end 127 | local ok, output = pcall(result) 128 | if not ok then 129 | return nil, output 130 | end 131 | return output 132 | end 133 | 134 | return serialization 135 | 136 | -------------------------------------------------------------------------------- /plan9k-corelibs/shell.lua: -------------------------------------------------------------------------------- 1 | local fs = require("filesystem") 2 | local text = require("text") 3 | local unicode = require("unicode") 4 | 5 | local shell = {} 6 | local aliases = {} 7 | 8 | -- Cache loaded shells for command execution. This puts the requirement on 9 | -- shells that they do not keep a global state, since they may be called 10 | -- multiple times, but reduces memory usage a lot. 11 | local shells = setmetatable({}, {__mode="v"}) 12 | 13 | local function getShell() 14 | local shellPath = os.getenv("SHELL") or "/bin/sh.lua" 15 | local shellName, reason = shell.resolve(shellPath, "lua") 16 | if not shellName then 17 | return nil, "cannot resolve shell `" .. shellPath .. "': " .. reason 18 | end 19 | if shells[shellName] then 20 | return shells[shellName] 21 | end 22 | local sh, reason = loadfile(shellName, "t", env) 23 | if sh then 24 | shells[shellName] = sh 25 | end 26 | return sh, reason 27 | end 28 | 29 | local function findFile(name, ext) 30 | checkArg(1, name, "string") 31 | local function findIn(dir) 32 | if dir:sub(1, 1) ~= "/" then 33 | dir = shell.resolve(dir) 34 | end 35 | dir = fs.concat(fs.concat(dir, name), "..") 36 | local name = fs.name(name) 37 | local list = fs.list(dir) 38 | if list then 39 | local files = {} 40 | for file in list do 41 | files[file] = true 42 | end 43 | if ext and unicode.sub(name, -(1 + unicode.len(ext))) == "." .. ext then 44 | -- Name already contains extension, prioritize. 45 | if files[name] then 46 | return true, fs.concat(dir, name) 47 | end 48 | elseif files[name] then 49 | -- Check exact name. 50 | return true, fs.concat(dir, name) 51 | elseif ext then 52 | -- Check name with automatially added extension. 53 | local name = name .. "." .. ext 54 | if files[name] then 55 | return true, fs.concat(dir, name) 56 | end 57 | end 58 | end 59 | return false 60 | end 61 | if unicode.sub(name, 1, 1) == "/" then 62 | local found, where = findIn("/") 63 | if found then return where end 64 | elseif unicode.sub(name, 1, 2) == "./" then 65 | local found, where = findIn(shell.getWorkingDirectory()) 66 | if found then return where end 67 | else 68 | for path in string.gmatch(shell.getPath(), "[^:]+") do 69 | local found, where = findIn(path) 70 | if found then return where end 71 | end 72 | end 73 | return false 74 | end 75 | 76 | ------------------------------------------------------------------------------- 77 | 78 | function shell.getAlias(alias) 79 | return aliases[alias] 80 | end 81 | 82 | function shell.setAlias(alias, value) 83 | checkArg(1, alias, "string") 84 | checkArg(2, value, "string", "nil") 85 | aliases[alias] = value 86 | end 87 | 88 | function shell.aliases() 89 | return pairs(aliases) 90 | end 91 | 92 | function shell.resolveAlias(command, args) 93 | checkArg(1, command, "string") 94 | checkArg(2, args, "table", "nil") 95 | args = args or {} 96 | local program, lastProgram = command, nil 97 | while true do 98 | local tokens = text.tokenize(shell.getAlias(program) or program) 99 | program = tokens[1] 100 | if program == lastProgram then 101 | break 102 | end 103 | lastProgram = program 104 | for i = #tokens, 2, -1 do 105 | table.insert(args, 1, tokens[i]) 106 | end 107 | end 108 | return program, args 109 | end 110 | 111 | function shell.getWorkingDirectory() 112 | return os.getenv("PWD") 113 | end 114 | 115 | function shell.setWorkingDirectory(dir) 116 | checkArg(1, dir, "string") 117 | dir = fs.canonical(dir) .. "/" 118 | if dir == "//" then dir = "/" end 119 | if fs.isDirectory(dir) then 120 | os.setenv("PWD", dir) 121 | return true 122 | else 123 | return nil, "not a directory" 124 | end 125 | end 126 | 127 | function shell.getPath() 128 | return os.getenv("PATH") 129 | end 130 | 131 | function shell.setPath(value) 132 | os.setenv("PATH", value) 133 | end 134 | 135 | function shell.resolve(path, ext) 136 | if path == "-" then return path end 137 | if ext then 138 | checkArg(2, ext, "string") 139 | local where = findFile(path, ext) 140 | if where then 141 | return where 142 | else 143 | return nil, "file not found" 144 | end 145 | else 146 | return path 147 | --[[if unicode.sub(path, 1, 1) == "/" then 148 | return fs.canonical(path) 149 | elseif unicode.sub(path, 1, 2) == "~/" then 150 | return fs.concat(os.getenv("HOME"), path:sub(2)) 151 | else 152 | return fs.concat(shell.getWorkingDirectory(), path) 153 | end ]]-- 154 | end 155 | end 156 | 157 | function shell.execute(command, env, ...) 158 | local sh, reason = getShell() 159 | if not sh then 160 | return false, reason 161 | end 162 | local result = table.pack(pcall(sh, env, command, ...)) 163 | if not result[1] and type(result[2]) == "table" and result[2].reason == "terminated" then 164 | if result[2].code then 165 | return true 166 | else 167 | return false, "terminated" 168 | end 169 | end 170 | return table.unpack(result, 1, result.n) 171 | end 172 | 173 | function shell.parse(...) 174 | local params = table.pack(...) 175 | local args = {} 176 | local options = {} 177 | local doneWithOptions = false 178 | for i = 1, params.n do 179 | local param = params[i] 180 | if not doneWithOptions and type(param) == "string" then 181 | if param == "--" then 182 | doneWithOptions = true -- stop processing options at `--` 183 | elseif unicode.sub(param, 1, 2) == "--" then 184 | if param:match("%-%-(.-)=") ~= nil then 185 | options[param:match("%-%-(.-)=")] = param:match("=(.*)") 186 | else 187 | options[unicode.sub(param, 3)] = true 188 | end 189 | elseif unicode.sub(param, 1, 1) == "-" and param ~= "-" then 190 | for j = 2, unicode.len(param) do 191 | options[unicode.sub(param, j, j)] = true 192 | end 193 | else 194 | table.insert(args, param) 195 | end 196 | else 197 | table.insert(args, param) 198 | end 199 | end 200 | return args, options 201 | end 202 | 203 | ------------------------------------------------------------------------------- 204 | 205 | return shell 206 | 207 | -------------------------------------------------------------------------------- /plan9k-corelibs/sides.lua: -------------------------------------------------------------------------------- 1 | local sides = { 2 | [0] = "bottom", 3 | [1] = "top", 4 | [2] = "back", 5 | [3] = "front", 6 | [4] = "right", 7 | [5] = "left", 8 | [6] = "unknown", 9 | 10 | bottom = 0, 11 | top = 1, 12 | back = 2, 13 | front = 3, 14 | right = 4, 15 | left = 5, 16 | unknown = 6, 17 | 18 | down = 0, 19 | up = 1, 20 | north = 2, 21 | south = 3, 22 | west = 4, 23 | east = 5, 24 | 25 | negy = 0, 26 | posy = 1, 27 | negz = 2, 28 | posz = 3, 29 | negx = 4, 30 | posx = 5, 31 | 32 | forward = 3 33 | } 34 | 35 | local metatable = getmetatable(sides) or {} 36 | 37 | -- sides[0..5] are mapped to itertable[1..6]. 38 | local itertable = { 39 | sides[0], 40 | sides[1], 41 | sides[2], 42 | sides[3], 43 | sides[4], 44 | sides[5] 45 | } 46 | 47 | -- Future-proofing against the possible introduction of additional 48 | -- logical sides (e.g. [7] = "all", [8] = "none", etc.). 49 | function metatable.__len(sides) 50 | return #itertable 51 | end 52 | 53 | -- Allow `sides` to be iterated over like a normal (1-based) array. 54 | function metatable.__ipairs(sides) 55 | return ipairs(itertable) 56 | end 57 | 58 | setmetatable(sides, metatable) 59 | 60 | ------------------------------------------------------------------------------- 61 | 62 | return sides 63 | -------------------------------------------------------------------------------- /plan9k-corelibs/text.lua: -------------------------------------------------------------------------------- 1 | local unicode = require("unicode") 2 | 3 | local text = {} 4 | 5 | function text.detab(value, tabWidth) 6 | checkArg(1, value, "string") 7 | checkArg(2, tabWidth, "number", "nil") 8 | tabWidth = tabWidth or 8 9 | local function rep(match) 10 | local spaces = tabWidth - match:len() % tabWidth 11 | return match .. string.rep(" ", spaces) 12 | end 13 | local result = value:gsub("([^\n]-)\t", rep) -- truncate results 14 | return result 15 | end 16 | 17 | function text.padRight(value, length) 18 | checkArg(1, value, "string", "nil") 19 | checkArg(2, length, "number") 20 | if not value or unicode.wlen(value) == 0 then 21 | return string.rep(" ", length) 22 | else 23 | return value .. string.rep(" ", length - unicode.wlen(value)) 24 | end 25 | end 26 | 27 | function text.padLeft(value, length) 28 | checkArg(1, value, "string", "nil") 29 | checkArg(2, length, "number") 30 | if not value or unicode.wlen(value) == 0 then 31 | return string.rep(" ", length) 32 | else 33 | return string.rep(" ", length - unicode.wlen(value)) .. value 34 | end 35 | end 36 | 37 | function text.trim(value) -- from http://lua-users.org/wiki/StringTrim 38 | local from = string.match(value, "^%s*()") 39 | return from > #value and "" or string.match(value, ".*%S", from) 40 | end 41 | 42 | function text.wrap(value, width, maxWidth) 43 | checkArg(1, value, "string") 44 | checkArg(2, width, "number") 45 | checkArg(3, maxWidth, "number") 46 | local line, nl = value:match("([^\r\n]*)(\r?\n?)") -- read until newline 47 | if unicode.wlen(line) > width then -- do we even need to wrap? 48 | local partial = unicode.wtrunc(line, width) 49 | local wrapped = partial:match("(.*[^a-zA-Z0-9._()'`=])") 50 | if wrapped or unicode.wlen(line) > maxWidth then 51 | partial = wrapped or partial 52 | return partial, unicode.sub(value, unicode.len(partial) + 1), true 53 | else 54 | return "", value, true -- write in new line. 55 | end 56 | end 57 | local start = unicode.len(line) + unicode.len(nl) + 1 58 | return line, start <= unicode.len(value) and unicode.sub(value, start) or nil, unicode.len(nl) > 0 59 | end 60 | 61 | function text.wrappedLines(value, width, maxWidth) 62 | local line, nl 63 | return function() 64 | if value then 65 | line, value, nl = text.wrap(value, width, maxWidth) 66 | return line 67 | end 68 | end 69 | end 70 | 71 | ------------------------------------------------------------------------------- 72 | 73 | local operators = {";", "&&", "||", "|"} 74 | local function checkOp(string) 75 | for _, v in pairs(operators) do 76 | if unicode.sub(v, 1, unicode.len(string)) == string then 77 | return true 78 | end 79 | end 80 | return false 81 | end 82 | 83 | function text.tokenize(value) 84 | checkArg(1, value, "string") 85 | local tokens, token = {}, "" 86 | local escaped, quoted, start = false, false, -1 87 | local op = false 88 | for i = 1, unicode.len(value) do 89 | local char = unicode.sub(value, i, i) 90 | if escaped then -- escaped character 91 | escaped = false 92 | token = token..char 93 | else 94 | local newOp 95 | if op then 96 | newOp = token..char 97 | else 98 | newOp = char 99 | end 100 | if checkOp(newOp) then -- part of operator? 101 | if not op then -- delimit token if start of operator 102 | table.insert(tokens, token) 103 | op = true 104 | end 105 | token = newOp 106 | else 107 | if op then -- end of operator? 108 | local foundOp = false 109 | for _, v in pairs(operators) do 110 | if v == token then 111 | table.insert(tokens, token) 112 | foundOp = true 113 | end 114 | end 115 | if not foundOp then 116 | tokens[#tokens] = tokens[#tokens]..token 117 | end 118 | token = "" 119 | op = false 120 | end 121 | 122 | -- Continue with regular matching 123 | if char == "\\" and quoted ~= "'" then -- escape character? 124 | escaped = true 125 | token = token..char 126 | elseif char == quoted then -- end of quoted string 127 | quoted = false 128 | token = token..char 129 | elseif (char == "'" or char == '"' or char == '`') and not quoted then 130 | quoted = char 131 | start = i 132 | token = token..char 133 | elseif string.find(char, "%s") and not quoted then -- delimiter 134 | if token ~= "" then 135 | table.insert(tokens, token) 136 | token = "" 137 | end 138 | else -- normal char 139 | token = token..char 140 | end 141 | end 142 | end 143 | end 144 | if quoted then 145 | return nil, "unclosed quote at index " .. start, quoted 146 | end 147 | if token ~= "" then 148 | table.insert(tokens, token) 149 | end 150 | return tokens 151 | end 152 | 153 | ------------------------------------------------------------------------------- 154 | 155 | return text 156 | 157 | -------------------------------------------------------------------------------- /plan9k-coreutil/clear.lua: -------------------------------------------------------------------------------- 1 | local term = require("term") 2 | 3 | term.clear() 4 | -------------------------------------------------------------------------------- /plan9k-coreutil/components.lua: -------------------------------------------------------------------------------- 1 | local component = require("component") 2 | local shell = require("shell") 3 | local text = require("text") 4 | 5 | local args, options = shell.parse(...) 6 | local count = tonumber(options.limit) or math.huge 7 | 8 | local components = {} 9 | local padTo = 1 10 | 11 | if #args == 0 then -- get all components if no filters given. 12 | args[1] = "" 13 | end 14 | for _, filter in ipairs(args) do 15 | for address, name in component.list(filter) do 16 | if name:len() > padTo then 17 | padTo = name:len() + 2 18 | end 19 | components[address] = name 20 | end 21 | end 22 | 23 | padTo = padTo + 8 - padTo % 8 24 | for address, name in pairs(components) do 25 | io.write(text.padRight(name, padTo) .. address .. '\n') 26 | 27 | if options.l then 28 | local proxy = component.proxy(address) 29 | local padTo = 1 30 | local methods = {} 31 | for name, member in pairs(proxy) do 32 | if type(member) == "table" or type(member) == "function" then 33 | if name:len() > padTo then 34 | padTo = name:len() + 2 35 | end 36 | table.insert(methods, name) 37 | end 38 | end 39 | table.sort(methods) 40 | padTo = padTo + 8 - padTo % 8 41 | 42 | for _, name in ipairs(methods) do 43 | local doc = tostring(proxy[name]) 44 | io.write(" " .. text.padRight(name, padTo) .. doc .. '\n') 45 | end 46 | end 47 | 48 | count = count - 1 49 | if count <= 0 then 50 | break 51 | end 52 | end 53 | -------------------------------------------------------------------------------- /plan9k-coreutil/dmesg.lua: -------------------------------------------------------------------------------- 1 | local event = require "event" 2 | local component = require "component" 3 | local keyboard = require "keyboard" 4 | local serialization = require "serialization" 5 | 6 | local args = {...} 7 | local color, isPal, evt 8 | 9 | local function normLine(data) 10 | local res = "" 11 | for c in data:gmatch(".") do 12 | if c == "\n" or c == "\r" then c = "\x1b[31m.\x1b[39m" end 13 | res = res .. (c:match("[%g%s]") or "\x1b[31m.\x1b[39m") 14 | end 15 | return res 16 | end 17 | 18 | --- 19 | local dataExpanders = {} 20 | 21 | local mcnetTransportTypes = { 22 | ["I"] = function(localAddress, remoteAddress, data) 23 | print("\t>>> ICMP") 24 | end, 25 | ["T"] = function(localAddress, remoteAddress, data) 26 | print("\t>>> TCP port=") 27 | end, 28 | ["D"] = function(localAddress, remoteAddress, data) 29 | print("\t>>> UDP port=") 30 | end, 31 | } 32 | 33 | local mcnetTypes = { 34 | ["H"] = function(localAddress, remoteAddress, data) 35 | local ttl, age, dist, n = string.unpack(">BHB", data) 36 | local host = data:sub(n) 37 | print("\t>> L2 mcnet HOST_FOUND ttl=" .. ttl .. " age=" .. age .. " dist=" .. dist .. " host=" .. normLine(host)) 38 | end, 39 | ["R"] = function(localAddress, remoteAddress, data) 40 | local ttl, dest, age = string.unpack(">Bs1H", data) 41 | print("\t>> L2 mcnet SEEK_ROUTE ttl=" .. ttl .. " age=" .. age .. " dest=" .. normLine(dest)) 42 | end, 43 | ["D"] = function(localAddress, remoteAddress, data) 44 | local ttl = string.unpack(">B", data) 45 | print("\t>> L2 mcnet DIRECT_DATA ttl=" .. ttl) 46 | if mcnetTransportTypes[data:sub(2,2)] then 47 | mcnetTransportTypes[data:sub(2,2)](localAddress, remoteAddress, data:sub(3)) 48 | else 49 | print("\t\t>> L2 Unknown mcnet packet") 50 | end 51 | end, 52 | ["E"] = function(localAddress, remoteAddress, data) 53 | local ttl, dest, orig, dstart = string.unpack(">Bs1s1", data) 54 | local dat = data:sub(dstart) 55 | print("\t>> L2 mcnet ROUTED_DATA ttl=" .. ttl .. " dest=" .. normLine(dest) .. " origin=" .. orig) 56 | if mcnetTransportTypes[dat:sub(1,1)] then 57 | mcnetTransportTypes[dat:sub(1,1)](localAddress, remoteAddress, dat:sub(2)) 58 | else 59 | print("\t\t>> L2 Unknown mcnet packet") 60 | end 61 | end, 62 | } 63 | 64 | local ethTypes = { 65 | ["\0"] = function(localAddress, remoteAddress, msg) --PKT_BEACON_OLD 66 | print("\t> L1 PKT_OLD_BEACON remote=" .. remoteAddress) 67 | end, 68 | ["\32"] = function(localAddress, remoteAddress, msg) --PKT_BEACON 69 | print("\t> L1 PKT_BEACON remote=" .. remoteAddress) 70 | end, 71 | ["\1"] = function(localAddress, remoteAddress, msg) --PKT_REGISTER 72 | print("\t> L1 PKT_REGISTER remote=" .. remoteAddress) 73 | end, 74 | ["\2"] = function(localAddress, remoteAddress, msg) --PKT_REGISTER_ACK 75 | print("\t> L1 PKT_REGISTER_ACK remote=" .. remoteAddress) 76 | end, 77 | ["\4"] = function(localAddress, remoteAddress, msg) --PKT_DATA 78 | print("\t> L1 PKT_DATA remote=" .. remoteAddress) 79 | if mcnetTypes[msg:sub(1,1)] then 80 | mcnetTypes[msg:sub(1,1)](localAddress, remoteAddress, msg:sub(2)) 81 | else 82 | print("\t>> L2 Unknown mcnet packet "..normLine(msg:sub(1,1)).."("..string.unpack("B",msg)..")") 83 | end 84 | end, 85 | ["\3"] = function(localAddress, remoteAddress, msg) --PKT_QUIT 86 | print("\t> L1 PKT_QUIT remote=" .. remoteAddress) 87 | end, 88 | 89 | } 90 | 91 | function dataExpanders.modem_message(_, localAddress, remoteAddress, port, distance, msg) 92 | print("\tport=" .. port .. ", distance=" .. distance) 93 | if port == 1 then 94 | if ethTypes[msg:sub(1,1)] then 95 | ethTypes[msg:sub(1,1)](localAddress, remoteAddress, msg:sub(2)) 96 | else 97 | print("\t> Unknown/OldNetwork modem message") 98 | end 99 | end 100 | io.write("\n") 101 | end 102 | 103 | --- 104 | 105 | io.write("Press 'Ctrl-C' to exit\n") 106 | --pcall(function() 107 | repeat 108 | if #args > 0 then 109 | evt = table.pack(event.pullMultiple("interrupted", table.unpack(args))) 110 | else 111 | evt = table.pack(event.pull()) 112 | end 113 | if evt[1] then 114 | io.write("\x1b[31m[" .. os.date("%T") .. "] \x1b[32m") 115 | io.write(tostring(evt[1]) .. string.rep(" ", math.max(10 - #tostring(evt[1]), 0) + 1)) 116 | io.write("\x1b[33m" .. tostring(evt[2]) .. string.rep(" ", 37 - #tostring(evt[2])) .. "\x1b[39m") 117 | if evt.n > 2 then 118 | for i = 3, evt.n do 119 | io.write(" " .. normLine(tostring(evt[i]))) 120 | end 121 | end 122 | io.write("\n") 123 | if dataExpanders[evt[1]] then 124 | dataExpanders[evt[1]](table.unpack(evt)) 125 | end 126 | end 127 | until evt[1] == "interrupted" 128 | --end) 129 | 130 | 131 | 132 | -------------------------------------------------------------------------------- /plan9k-coreutil/echo.lua: -------------------------------------------------------------------------------- 1 | local args = table.pack(...) 2 | for i = 1, #args do 3 | if i > 1 then 4 | io.write(" ") 5 | end 6 | io.write(args[i]) 7 | end 8 | io.write("\n") -------------------------------------------------------------------------------- /plan9k-coreutil/hostname.lua: -------------------------------------------------------------------------------- 1 | local args = {...} 2 | if args[1] then 3 | local file, reason = io.open("/etc/hostname", "w") 4 | if not file then 5 | io.stderr:write(reason .. "\n") 6 | else 7 | file:write(args[1]) 8 | file:close() 9 | os.setenv("HOSTNAME", args[1]) 10 | os.setenv("PS1", "\x1b[33m$HOSTNAME\x1b[32m:\x1b[33m$PWD\x1b[31m#\x1b[39m ") 11 | computer.pushSignal("hostname", args[1]) 12 | end 13 | else 14 | local file = io.open("/etc/hostname") 15 | if file then 16 | io.write(file:read("*l"), "\n") 17 | file:close() 18 | else 19 | io.stderr:write("Hostname not set\n") 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /plan9k-coreutil/kill.lua: -------------------------------------------------------------------------------- 1 | local args = {...} 2 | local pid = tonumber(args[1]) 3 | if not pid then error("Usage: kill [pid]") end 4 | local res, reason = os.kill(pid, "kill") 5 | 6 | if not res then 7 | error(reason) 8 | end 9 | -------------------------------------------------------------------------------- /plan9k-coreutil/label.lua: -------------------------------------------------------------------------------- 1 | local fs = require("filesystem") 2 | local shell = require("shell") 3 | 4 | local args, options = shell.parse(...) 5 | if #args < 1 then 6 | io.write("Usage: label [-a] [