├── LICENSE ├── README.md ├── examples ├── json-util.lua ├── ltsysctl ├── memfree └── procinfo ├── lj2procfs ├── Decoders.lua ├── ProcessEntry.lua ├── codecs │ ├── README.md │ ├── buddyinfo.lua │ ├── cgroups.lua │ ├── cmdline.lua │ ├── cpuinfo.lua │ ├── crypto.lua │ ├── devices.lua │ ├── diskstats.lua │ ├── interrupts.lua │ ├── iomem.lua │ ├── ioports.lua │ ├── kallsyms.lua │ ├── linkchaser.lua │ ├── loadavg.lua │ ├── meminfo.lua │ ├── modules.lua │ ├── net.lua │ ├── net │ │ ├── dev.lua │ │ └── netstat.lua │ ├── partitions.lua │ ├── process │ │ ├── auxv.lua │ │ ├── environ.lua │ │ ├── exe.lua │ │ ├── io.lua │ │ ├── limits.lua │ │ ├── maps.lua │ │ ├── mounts.lua │ │ ├── sched.lua │ │ └── status.lua │ ├── softirqs.lua │ ├── stat.lua │ ├── sys.lua │ ├── uptime.lua │ └── vmstat.lua ├── fs-util.lua ├── fun.lua ├── libc.lua ├── print-util.lua ├── procfs.lua └── string-util.lua ├── rockspec ├── lj2procfs-0.1-1.rockspec ├── lj2procfs-0.1-2.rockspec ├── lj2procfs-0.1-3.rockspec ├── lj2procfs-0.1-4.rockspec ├── lj2procfs-0.1-5.rockspec └── lj2procfs-0.1-6.rockspec └── testy ├── auxvinfo.lua ├── coreinfo.lua ├── countprocs.lua ├── cryptocount.lua ├── findsym.lua ├── get_allkernelinfo.lua ├── get_kernelinfo.lua ├── get_sysinfo.lua ├── lsdir.lua ├── ltflprocesses.lua ├── lthostname.lua ├── ltsysinfo.lua ├── procfile ├── procfs_files.lua ├── set_kernelinfo.lua ├── test_iterate_directory.lua ├── test_lfs.lua ├── test_procfs_procids.lua ├── test_procfs_procs.lua └── test_sysinfo.lua /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 William Adams 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # lj2procfs 2 | LuaJIT access to Linux /proc file system 3 | 4 | On Linux systems, /proc is a source of much useful information, such as the number of processes 5 | running on the machine, mount points, cpu information, threads, memory utilization, io statistics, 6 | and the like. In classic UNIX fashion, everything is a file, and they are accessed through the 7 | directory mounted under /proc. 8 | 9 | These files are variously readable either by humans or machine processes. There are numerous 10 | command line tools that make this information more or less accessible, as long as you know all the 11 | commands, and their attendant flags, quirks, and whatnot. 12 | 13 | This binding to the procfs makes accessing various aspects of the file system relatively easy. 14 | 15 | At the highest level, gaining access to the information whithin files that are directly in /proc, is 16 | as easy as the following example, which gets at the /proc/cpuinfo file. 17 | 18 | ```lua 19 | package.path = "../?.lua;"..package.path; 20 | 21 | local procfs = require("lj2procfs.procfs") 22 | local putil = require("lj2procfs.print-util") 23 | 24 | print("return {") 25 | putil.printValue(procfs.cpuinfo, " ", "cpuinfo") 26 | print("}") 27 | ``` 28 | 29 | The meat of it is the one call: procfs.cpuinfo 30 | 31 | This will return a table, which contains the already parsed information. Numeric values become lua numbers, the word "yes", becomes a boolean 'true', and everything else becomes a quoted string. Since you now have a table, 32 | you can easily use that in any way within your lua program. 33 | 34 | If you wanted to perform a task such as list which processors are associated with which cores, 35 | you could do the following: 36 | 37 | ```lua 38 | local procfs = require("lj2procfs.procfs") 39 | local fun = require("lj2procfs.fun") 40 | 41 | 42 | local function printInfo(processor) 43 | print(string.format("processor: %d, core: %d", processor.processor, processor.core_id)) 44 | end 45 | 46 | fun.each(printInfo, procfs.cpuinfo) 47 | ``` 48 | 49 | And the output might look something like this 50 | 51 | ```lua 52 | processor: 0, core: 0 53 | processor: 1, core: 1 54 | processor: 2, core: 2 55 | processor: 3, core: 3 56 | processor: 4, core: 0 57 | processor: 5, core: 1 58 | processor: 6, core: 2 59 | processor: 7, core: 3 60 | ``` 61 | 62 | There are a number of tasks which become fairly easy to perform from within lua script, such as 63 | counting the number of processes that are currently running in the system. 64 | 65 | ```lua 66 | #!/usr/bin/env luajit 67 | package.path = "../?.lua;"..package.path; 68 | 69 | local procfs = require("lj2procfs.procfs") 70 | local fun = require("lj2procfs.fun") 71 | 72 | print("Num Procs: ", fun.length(procfs.processes())) 73 | ``` 74 | 75 | Of course you could already do this by simply running 'ps', or some other command line tool. The benefit 76 | of having this binding, is that you can easily perform the task without having to shell out to get 77 | simple tasks done. This makes it far easier to incorporate the information into an automated workflow. 78 | 79 | If you wanted to go all out and print all the information about all the processes currently running 80 | on the machine, you could do the following: 81 | 82 | ```lua 83 | local procfs = require("lj2procfs.procfs") 84 | local fun = require("lj2procfs.fun") 85 | local putil = require("lj2procfs.print-util") 86 | 87 | 88 | local function printProcEntry(procEntry) 89 | print(string.format("\t[%d] = {", procEntry.Id)) 90 | 91 | for _, fileEntry in procEntry:files() do 92 | local fileValue = procEntry[fileEntry.Name] 93 | putil.printValue(fileValue, '\t\t', fileEntry.Name) 94 | end 95 | 96 | print(string.format("\t},")) 97 | end 98 | 99 | 100 | print(string.format("return {")) 101 | fun.each(printProcEntry, procfs.processes()) 102 | print(string.format("}")) 103 | ``` 104 | Which might generate some output, which partially looks like: 105 | 106 | ```lua 107 | return { 108 | [1] = { 109 | ['environ'] = { 110 | PATH = [[/sbin:/usr/sbin:/bin:/usr/bin]], 111 | HOME = [[/]], 112 | rootmnt = [[/root]], 113 | recovery = '', 114 | PWD = [[/]], 115 | TERM = [[linux]], 116 | BOOT_IMAGE = [[/vmlinuz-3.19.0-26-generic.efi.signed]], 117 | init = [[/sbin/init]], 118 | }; 119 | auxv = [[nil]], 120 | ``` 121 | 122 | Of course, you don't have to generate any output at all. You could just form 123 | queries whereby you iterate over processes, looking for specific attributes, and 124 | delivering some action based on seeing those attributes. 125 | 126 | 127 | Installation 128 | ============ 129 | 130 | There are a couple of ways to install the package into your 131 | luajit environment. The first method involves using luarocks. If 132 | you have luarocks, you can install one of the existing pre-packaged 133 | rocks from well known repositories using the following: 134 | 135 | $ luarocks install lj2procfs 136 | 137 | 138 | Alternatively, if you want to install directly from the repository 139 | you can simply copy the appropriate files into a well known lua 140 | modules directory. On Linux systems, this might be: 141 | 142 | '/usr/local/share/lua/5.1' 143 | 144 | While sitting in the l2jprocfs directory, you might do: 145 | 146 | $sudo cp -r lj2procfs /usr/local/share/lua/5.1 147 | -------------------------------------------------------------------------------- /examples/json-util.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | --[[ This util prints proc info in JSON format. 3 | Usage: ./json-util.lua stat 4 | ./json-util.lua meminfo 5 | ./json-util.lua cpuinfo 6 | ]]-- 7 | 8 | local function literalForValue(avalue) 9 | if type(avalue) == "number" or type(avalue) == "boolean" then 10 | return tostring(avalue) 11 | end 12 | 13 | local str = tostring(avalue) 14 | if str == "" then 15 | return "''" 16 | end 17 | 18 | return string.format("%s", str) 19 | end 20 | 21 | local function printValueJson(avalue, indent, name) 22 | if not avalue then return end; 23 | 24 | indent = indent or "" 25 | 26 | if type(avalue) == "table" then 27 | local list = false 28 | if name then 29 | io.write(string.format("%s\"%s\": ", indent, name)) 30 | end 31 | 32 | if #avalue > 0 then 33 | -- it's a list,so use ipairs 34 | io.write(string.format("[")) 35 | list = true 36 | -- print comma at the end of line only if the next ipair is not nil 37 | for _, value in ipairs(avalue) do 38 | printValueJson(value, indent..' ') 39 | if next(avalue, _) then 40 | io.write(string.format(",\n")) 41 | end 42 | end 43 | io.write(string.format("]\n")) 44 | else 45 | -- assume it's a dictionary, so use pairs 46 | io.write(string.format("{\n")) 47 | for key, value in pairs(avalue) do 48 | printValueJson(value, indent..' ', key) 49 | if next(avalue, key) then 50 | io.write(string.format(",")) 51 | end 52 | io.write(string.format("\n")) 53 | end 54 | end 55 | if not list then 56 | io.write(string.format("%s}", indent)) 57 | end 58 | else 59 | if name then 60 | io.write(string.format("%s\"%s\" :\"%s\"", indent, name, literalForValue(avalue))) 61 | else 62 | io.write(string.format("%s%s,\n", indent, literalForValue(avalue))) 63 | end 64 | end 65 | end 66 | 67 | -- Calling the print util here: 68 | local procfs = require("lj2procfs.procfs") 69 | local filename = nil 70 | local PID = nil 71 | 72 | if tonumber(arg[1]) then 73 | PID = tonumber(arg[1]) 74 | filename = arg[2] 75 | else 76 | filename = arg[1] 77 | end 78 | 79 | if not filename then USAGE() end 80 | 81 | io.write("{\n") 82 | if PID then 83 | printValueJson(procfs[PID][filename], ' ', tostring(PID).."_"..filename) 84 | else 85 | printValueJson(procfs[filename], " ", filename) 86 | end 87 | io.write("\n}\n") 88 | -------------------------------------------------------------------------------- /examples/ltsysctl: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --package.path = "../?.lua" 4 | 5 | --[[ 6 | get_sysinfo.lua 7 | 8 | Retrieve stuff from the /proc/sys/* directory 9 | Specify a path to a file, starting with the part 10 | after '/sys', 11 | 12 | $ ./get_sysinfo.lua kernel/panic 13 | 14 | This is consistent with the strings you might 15 | specify for a sysctl.conf file. You can use 16 | either a '/' or '.' as the path separator. 17 | --]] 18 | 19 | local procfs = require("lj2procfs.procfs") 20 | local sutil = require("lj2procfs.string-util") 21 | 22 | local path = arg[1] or "" 23 | local sep = '/' 24 | if path:find("%.") then 25 | sep = '.' 26 | end 27 | 28 | if not sutil.startswith(path,"sys") then 29 | path = "sys"..sep..path 30 | end 31 | 32 | -- The segments can be separated with either a '.' 33 | -- or '/' 34 | local segments = sutil.tsplit(path, "[%./]") 35 | 36 | local node = procfs; 37 | for i=1,#segments do 38 | node = node[segments[i]] 39 | end 40 | 41 | print(path..': ', node) 42 | -------------------------------------------------------------------------------- /examples/memfree: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --[[ 4 | This lua script acts similar to the 'free' command, which will 5 | display some interesting information about how much memory is being 6 | used in the system. 7 | 8 | This example assumes lj2procfs is installed into the lua path 9 | --]] 10 | 11 | 12 | local procfs = require("lj2procfs.procfs") 13 | 14 | local meminfo = procfs.meminfo; 15 | 16 | local memtotal = meminfo.MemTotal.size 17 | local memfree = meminfo.MemFree.size 18 | local memused = memtotal - memfree 19 | local memshared = meminfo.Shmem.size 20 | local membuffers = meminfo.Buffers.size 21 | local memcached = meminfo.Cached.size 22 | 23 | local swaptotal = meminfo.SwapTotal.size 24 | local swapfree = meminfo.SwapFree.size 25 | local swapused = swaptotal - swapfree 26 | 27 | print(string.format("%18s %10s %10s %10s %10s %10s",'total', 'used', 'free', 'shared', 'buffers', 'cached')) 28 | print(string.format("Mem: %13d %10d %10d %10d %10d %10d", memtotal, memused, memfree, memshared, membuffers, memcached)) 29 | --print(string.format("-/+ buffers/cache: %10d %10d", 1, 2)) 30 | print(string.format("Swap: %12d %10d %10d", swaptotal, swapused, swapfree)) 31 | -------------------------------------------------------------------------------- /examples/procinfo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --[[ 4 | procfile 5 | 6 | This is a general purpose /proc/ interpreter. 7 | Usage: 8 | $ sudo ./procfile filename 9 | 10 | Here, 'filname' is any one of the files listed in the 11 | /proc directory. 12 | 13 | In the cases where a decoder is implemented and sitting in the 14 | codecs/ directory, the file will be parsed, and an appropriate 15 | value will bereturned and printed in a lua form appropriate for 16 | reparsing. 17 | 18 | When there is no decoder implemented, the value returned is 19 | "NO DECODER AVAILABLE" 20 | 21 | example: 22 | $ sudo ./procfile cpuinfo 23 | $ sudo ./procfile partitions 24 | 25 | This example assumes lj2procfs is installed into the lua path 26 | 27 | --]] 28 | 29 | 30 | local procfs = require("lj2procfs.procfs") 31 | local putil = require("lj2procfs.print-util") 32 | 33 | local function USAGE() 34 | print ([[ 35 | 36 | USAGE: 37 | $ sudo ./procfile [PID] 38 | 39 | where is the name of a file in the /proc 40 | directory. 41 | 42 | Example: 43 | $ sudo ./procfile cpuinfo 44 | $ sudo ./procfile 13654 limits 45 | ]]) 46 | 47 | error() 48 | end 49 | 50 | local filename = nil 51 | local PID = nil 52 | 53 | if tonumber(arg[1]) then 54 | PID = tonumber(arg[1]) 55 | filename = arg[2] 56 | else 57 | filename = arg[1] 58 | end 59 | 60 | if not filename then USAGE() end 61 | 62 | 63 | print("return {") 64 | if PID then 65 | putil.printValue(procfs[PID][filename], ' ', tostring(PID).."_"..filename) 66 | else 67 | putil.printValue(procfs[filename], " ", filename) 68 | end 69 | print("}") 70 | -------------------------------------------------------------------------------- /lj2procfs/Decoders.lua: -------------------------------------------------------------------------------- 1 | --Decoders.lua 2 | 3 | local fun = require("lj2procfs.fun") 4 | local strutil = require("lj2procfs.string-util") 5 | 6 | local function getRawFile(path) 7 | local f = io.open(path) 8 | local str = f:read("*a") 9 | f:close() 10 | 11 | return str; 12 | end 13 | 14 | -- Use this table if you want to map from the names that 15 | -- are relative to the /proc directory, to values sitting 16 | -- directly within the codec directory 17 | --[[ 18 | local decoderMap = { 19 | ["%d+/cwd"] = "linkchaser"; 20 | ["%d+/exe"] = "linkchaser"; 21 | ["%d+/root"] = "linkchaser"; 22 | } 23 | --]] 24 | 25 | local Decoders = {} 26 | local function findDecoder(self, key) 27 | -- traverse through the mappings looking for a match 28 | --[[ 29 | for pattern, value in pairs(decoderMap) do 30 | if key:match(pattern) then 31 | key = value 32 | break; 33 | end 34 | end 35 | --]] 36 | 37 | local path = "lj2procfs.codecs."..key; 38 | --print("findDecoder(), PATH: ", path) 39 | 40 | -- try to load the intended codec file 41 | local success, codec = pcall(function() return require(path) end) 42 | if success and codec.decoder then 43 | return codec.decoder; 44 | end 45 | 46 | -- if we didn't find a decoder, use the generic raw file loading 47 | -- decoder. 48 | -- Caution: some of those files can be very large! 49 | return getRawFile; 50 | end 51 | setmetatable(Decoders, { 52 | __index = findDecoder; 53 | 54 | }) 55 | 56 | 57 | return Decoders 58 | -------------------------------------------------------------------------------- /lj2procfs/ProcessEntry.lua: -------------------------------------------------------------------------------- 1 | --ProcessEntry.lua 2 | local fs = require("lj2procfs.fs-util") 3 | local libc = require("lj2procfs.libc") 4 | local fun = require("lj2procfs.fun") 5 | local Decoders = require("lj2procfs.Decoders") 6 | 7 | 8 | 9 | local ProcessEntry = {} 10 | setmetatable(ProcessEntry, { 11 | __call = function(self, ...) 12 | return self:new(...) 13 | end, 14 | }) 15 | 16 | 17 | local ProcessEntry_mt = { 18 | __index = function(self, key) 19 | if ProcessEntry[key] then 20 | return ProcessEntry[key] 21 | end 22 | 23 | -- we are essentially a sub-class of Decoders 24 | if Decoders[key] then 25 | local path = self.Path..'/'..key; 26 | return Decoders["process."..key](path); 27 | end 28 | 29 | return "NO DECODER AVAILABLE" 30 | end, 31 | } 32 | 33 | function ProcessEntry.init(self, procId) 34 | local obj = { 35 | Id = procId; 36 | Path = string.format("/proc/%d", procId); 37 | } 38 | setmetatable(obj, ProcessEntry_mt) 39 | 40 | return obj; 41 | end 42 | 43 | function ProcessEntry.new(self, procId) 44 | return self:init(procId) 45 | end 46 | 47 | 48 | function ProcessEntry.files(self) 49 | return fs.files_in_directory(self.Path) 50 | end 51 | 52 | local function isDirectory(entry) 53 | return entry.Kind == libc.DT_DIR and 54 | entry.Name ~= '.' and 55 | entry.Name ~= '..' 56 | end 57 | 58 | function ProcessEntry.directories(self) 59 | return fun.filter(isDirectory, fs.entries_in_directory(self.Path)) 60 | end 61 | 62 | 63 | return ProcessEntry 64 | -------------------------------------------------------------------------------- /lj2procfs/codecs/README.md: -------------------------------------------------------------------------------- 1 | AVAILABLE 2 | ========= 3 | /proc/* 4 | * buddyinfo 5 | * cgroups 6 | * cmdline 7 | * cpuinfo 8 | * crypto 9 | * devices 10 | * diskstats 11 | * interrupts 12 | * iomem 13 | * ioports 14 | * kallsyms 15 | * linkchaser - cwd, exe, root 16 | * loadavg 17 | * meminfo 18 | * modules 19 | * net 20 | * partitions 21 | * softirqs 22 | * uptime 23 | * vmstat 24 | 25 | Per Process 26 | ----------- 27 | /proc/[PID]/* 28 | * environ 29 | * exe 30 | * io 31 | * limits 32 | * maps 33 | * mounts 34 | * sched 35 | * status 36 | 37 | Network 38 | ------- 39 | /proc/net 40 | * dev 41 | * netstat 42 | 43 | Sys 44 | --- 45 | /proc/sys/* 46 | /proc/sys/kernel 47 | * hostname 48 | * version 49 | 50 | TODO 51 | ==== 52 | /proc 53 | consoles 54 | dma 55 | execdomains 56 | filesystems 57 | kcore 58 | keys 59 | key-users 60 | kmsg 61 | kpagecount 62 | kpageflags 63 | locks 64 | mdstat 65 | misc 66 | mtrr 67 | pagetypeinfo 68 | sched_debug 69 | schedstat 70 | slabinfo 71 | stat 72 | swaps 73 | sysrq-trigger 74 | timer_list 75 | timer_stats 76 | version 77 | version_signature 78 | vmallocinfo 79 | zoneinfo 80 | -------------------------------------------------------------------------------- /lj2procfs/codecs/buddyinfo.lua: -------------------------------------------------------------------------------- 1 | --buddyinfo.lua 2 | -- Reference 3 | -- http://andorian.blogspot.com/2014/03/making-sense-of-procbuddyinfo.html 4 | -- 5 | local pow = math.pow 6 | 7 | local headingpattern = "Node%s+(%d+).*zone%s+(%w+)%s+(.*)" 8 | local chunkpatt = "(%d+)" 9 | 10 | local function buddyinfo(path) 11 | local tbl = {} 12 | 13 | for str in io.lines(path) do 14 | local numa_node, zone, numbers = str:match(headingpattern) 15 | 16 | if numa_node then 17 | if not tbl["numa_"..numa_node] then 18 | tbl["numa_"..numa_node] = {} 19 | end 20 | 21 | local rowTbl = {} 22 | 23 | local chunknum = 0; 24 | for chunkval in numbers:gmatch(chunkpatt) do 25 | --print(chunknum, chunkval) 26 | 27 | table.insert(rowTbl, {order = chunknum, available = tonumber(chunkval)}) 28 | chunknum = chunknum + 1 29 | end 30 | tbl["numa_"..numa_node][zone] = rowTbl; 31 | end 32 | end 33 | 34 | return tbl; 35 | end 36 | 37 | return { 38 | decoder = buddyinfo; 39 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/cgroups.lua: -------------------------------------------------------------------------------- 1 | local pattern = "(%g+)%s+(%d+)%s+(%d+)%s+(%d+)" 2 | local function decoder(path) 3 | path = path or "/proc/cgroups" 4 | 5 | local tbl = {} 6 | -- skip header line 7 | local linesToSkip = 1 8 | for str in io.lines(path) do 9 | if linesToSkip > 0 then 10 | linesToSkip = linesToSkip - 1; 11 | else 12 | local subsysName, hierarchy, numCgroups, enabled = str:match(pattern) 13 | if subsysName then 14 | tbl[subsysName] = { 15 | name = subsysName; 16 | hierarchy = tonumber(hierarchy); 17 | numCgroups = tonumber(numCgroups); 18 | enabled = tonumber(enabled) == 1; 19 | } 20 | end 21 | end 22 | end 23 | 24 | return tbl 25 | end 26 | 27 | return { 28 | decoder = decoder; 29 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/cmdline.lua: -------------------------------------------------------------------------------- 1 | -- can be used for both /proc/cmdline, and /proc/[pid]/cmdline 2 | local sutil= require("lj2procfs.string-util") 3 | 4 | local function decoder(path) 5 | -- open the file 6 | -- return full contents as a string 7 | local f = io.open(path) 8 | local str = f:read("*a") 9 | 10 | local tbl = {} 11 | -- can possibly be a string of '\0' delimited values 12 | for _, str in sutil.mstrziter(str) do 13 | table.insert(tbl,str) 14 | end 15 | 16 | return tbl; 17 | end 18 | 19 | return { 20 | decoder = decoder; 21 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/cpuinfo.lua: -------------------------------------------------------------------------------- 1 | local strutil = require("lj2procfs.string-util") 2 | 3 | local function decoder(path) 4 | path = path or "/proc/cpuinfo" 5 | 6 | local tbl = {} 7 | local currentTbl = {} 8 | for str in io.lines(path) do 9 | if str == "" then 10 | table.insert(tbl, currentTbl) 11 | currentTbl = {} 12 | else 13 | -- each of these is ':' delimited 14 | local key, value = strutil.split(str,":") 15 | key = strutil.trim(key):gsub(' ','_') 16 | 17 | 18 | if value ~= "" then 19 | value = strutil.trim(value) 20 | end 21 | 22 | if key == 'flags' then 23 | value = strutil.tsplitbool(value, ' ') 24 | else 25 | value = tonumber(value) or value 26 | if value == "yes" then 27 | value = true 28 | end 29 | end 30 | currentTbl[key] = value; 31 | end 32 | end 33 | 34 | return tbl 35 | end 36 | 37 | return { 38 | decoder = decoder; 39 | } 40 | -------------------------------------------------------------------------------- /lj2procfs/codecs/crypto.lua: -------------------------------------------------------------------------------- 1 | local strutil = require("lj2procfs.string-util") 2 | local pattern = "(%g+)%s+:%s+(%g+)" 3 | 4 | local function decoder(path) 5 | path = path or "/proc/crypto" 6 | 7 | local tbl = {} 8 | local currentTbl = {} 9 | for str in io.lines(path) do 10 | if str == "" then 11 | tbl[currentTbl.name] = currentTbl; 12 | currentTbl = {} 13 | else 14 | local key, value = str:match(pattern) 15 | if tonumber(value) then 16 | currentTbl[key] = tonumber(value) 17 | else 18 | currentTbl[key] = value; 19 | end 20 | end 21 | end 22 | 23 | return tbl 24 | end 25 | 26 | 27 | 28 | return { 29 | decoder = decoder; 30 | } 31 | -------------------------------------------------------------------------------- /lj2procfs/codecs/devices.lua: -------------------------------------------------------------------------------- 1 | local function devices(path) 2 | local devicepatt = "(%d+)%s+(.*)" 3 | local catpatt = "(%w+) devices:" 4 | local tbl = {} 5 | local catTbl = nil 6 | local category = nil; 7 | 8 | for str in io.lines(path) do 9 | 10 | if str == "" then 11 | catTbl = nil; 12 | else 13 | category = str:match(catpatt) 14 | 15 | if category then 16 | print("New CAT: ", category) 17 | tbl[category] = {} 18 | catTbl = tbl[category] 19 | else 20 | local major, desc = str:match(devicepatt) 21 | if major then 22 | 23 | table.insert(catTbl, {major = tonumber(major), device = desc}) 24 | end 25 | end 26 | end 27 | end 28 | 29 | return tbl; 30 | end 31 | 32 | return { 33 | decoder = devices; 34 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/diskstats.lua: -------------------------------------------------------------------------------- 1 | -- The field names used here are the same as for the iostat 2 | -- program. 3 | -- That program uses a 'struct io_stats' 4 | -- Here we simply use a lua table 5 | 6 | local function decoder(path) 7 | path = path or "/proc/diskstats" 8 | 9 | local tbl = {} 10 | 11 | -- If you were using 'C', this would be a 'scanf' template 12 | local pattern = "(%d+)%s+(%d+)%s+(%g+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)%s+(%d+)" 13 | 14 | -- The statistics are gathered for all devices, whether they are actual 15 | -- devices, partitions, or virtual devices. Something else can determine 16 | -- which of these are to be filtered out. 17 | for str in io.lines(path) do 18 | 19 | local major, minor, dev_name, 20 | rd_ios, rd_merges_or_rd_sec, rd_sec_or_wr_ios, rd_ticks_or_wr_sec, 21 | wr_ios, wr_merges, wr_sec, wr_ticks, ios_pgr, tot_ticks, rq_ticks = str:match(pattern) 22 | 23 | -- add entry to table 24 | tbl[dev_name] = { 25 | major = tonumber(major), 26 | minor = tonumber(minor), 27 | rd_ios = tonumber(rd_ios), 28 | rd_merges_or_rd_sec = tonumber(rd_merges_or_rd_sec), 29 | rd_sec_or_wr_ios = tonumber(rd_sec_or_wr_ios), 30 | rd_ticks_or_wr_sec = tonumber(rd_ticks_or_wr_sec), 31 | wr_ios = tonumber(wr_ios), 32 | wr_merges = tonumber(wr_merges), 33 | wr_sec = tonumber(wr_sec), 34 | wr_ticks = tonumber(wr_ticks), 35 | ios_pgr = tonumber(ios_pgr), 36 | tot_ticks = tonumber(tot_ticks), 37 | rq_ticks = tonumber(rq_ticks) 38 | } 39 | end 40 | 41 | return tbl; 42 | end 43 | 44 | return { 45 | decoder = decoder; 46 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/interrupts.lua: -------------------------------------------------------------------------------- 1 | local strutil = require("lj2procfs.string-util") 2 | 3 | local namepatt = "(%g+):(.*)" 4 | local numberspatt = "[%s*(%d+)]+" 5 | local descpatt = "[%s*(%d+)]+(.*)" 6 | 7 | local function numbers(value) 8 | num, other = string.match(value, numpatt) 9 | return num; 10 | end 11 | 12 | local function interrupts(path) 13 | path = path or "/proc/interrupts" 14 | 15 | local tbl = {} 16 | for str in io.lines(path) do 17 | local name, remainder = str:match(namepatt) 18 | if name then 19 | local numbers = remainder:match(numberspatt) 20 | local desc = remainder:match(descpatt) 21 | 22 | local cpu = 0; 23 | local valueTbl = {} 24 | for number in numbers:gmatch("%s*(%d+)") do 25 | --print("NUMBER: ", number) 26 | valueTbl["cpu"..cpu] = tonumber(number); 27 | cpu = cpu + 1; 28 | end 29 | valueTbl.description = desc 30 | tbl[name] = valueTbl 31 | 32 | end 33 | end 34 | 35 | return tbl 36 | end 37 | 38 | return { 39 | decoder = interrupts; 40 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/iomem.lua: -------------------------------------------------------------------------------- 1 | 2 | local function iomem(path) 3 | path = path or "/proc/iomem" 4 | 5 | local tbl = {} 6 | local pattern = "(%x+)-(%x+) : (.*)" 7 | for str in io.lines(path) do 8 | local low, high, desc = str:match(pattern) 9 | if low then 10 | table.insert(tbl, {low = tonumber(low,16), high = tonumber(high,16), description = desc}) 11 | end 12 | end 13 | 14 | return tbl; 15 | end 16 | 17 | return { 18 | decoder = iomem; 19 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/ioports.lua: -------------------------------------------------------------------------------- 1 | --ioports.lua 2 | local toprangepatt = "^(%x+)-(%x+)%s+:%s+(.*)" -- ^0000-0cf7 : PCI Bus 0000:00 3 | local subrangepatt = "%s+(%x+)%-(%x+)%s+:%s+(.*)" -- ' 0000-0cf7 : PCI Bus 0000:00' 4 | local leafrangepatt = " (%x+)-(%x+)%s+:%s+(.*)" -- ' 0000-0cf7 : PCI Bus 0000:00' 5 | 6 | local function ioports(path) 7 | path = path or "/proc/ioports" 8 | 9 | local tbl = {} 10 | tbl.ranges = {} 11 | 12 | for str in io.lines(path) do 13 | local lowrange,highrange, desc= str:match(toprangepatt) 14 | if lowrange then 15 | print(lowrange, highrange, desc) 16 | table.insert(tbl.ranges, {low = tonumber(lowrange,16), high = tonumber(highrange,16), description = desc}) 17 | else 18 | local sublow,subhigh,subdesc= str:match(subrangepatt) 19 | if sublow then 20 | table.insert(tbl,{low = tonumber(sublow, 16), high = tonumber(subhigh,16), description = subdesc}) 21 | end 22 | end 23 | end 24 | 25 | return tbl; 26 | end 27 | 28 | return { 29 | decoder = ioports; 30 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/kallsyms.lua: -------------------------------------------------------------------------------- 1 | local function kallsyms(path) 2 | path = path or "/proc/kallsyms" 3 | 4 | local tbl = {} 5 | local pattern = "(%x+)%s+(%g+)%s+(%g+)" 6 | 7 | for str in io.lines(path) do 8 | local loc, kind, name = str:match(pattern) 9 | if name then 10 | tbl[name] = {name = name, kind = kind, location = loc} 11 | end 12 | end 13 | 14 | return tbl 15 | end 16 | 17 | return { 18 | decoder = kallsyms; 19 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/linkchaser.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local libc = require("lj2procfs.libc") 3 | 4 | local function cwd(path) 5 | local buff = ffi.new("char [2048]") 6 | local buffsize = 2048 7 | 8 | local size = libc.readlink(path, buff, buffsize); 9 | if size > 0 then 10 | return ffi.string(buff, size) 11 | end 12 | 13 | return nil; 14 | end 15 | 16 | return { 17 | decoder = cwd; 18 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/loadavg.lua: -------------------------------------------------------------------------------- 1 | local pattern = "(%d*.%d+)%s+(%d*.%d+)%s+(%d*.%d+)%s+(%d+)/(%d+)%s+(%d+)" 2 | 3 | local function decoder(path) 4 | path = path or "/proc/loadavg" 5 | 6 | local f = io.open(path) 7 | local str = f:read("*a") 8 | f:close() 9 | 10 | local minute1avg, minute5avg, minute15avg, runnable, exist, lastpid = str:match(pattern) 11 | 12 | return { 13 | minute1avg = tonumber(minute1avg), 14 | minute5avg = tonumber(minute5avg), 15 | minute15avg = tonumber(minute15avg), 16 | runnable = tonumber(runnable), 17 | exist = tonumber(exist), 18 | lastpid = tonumber(lastpid) 19 | } 20 | 21 | end 22 | 23 | return { 24 | decoder = decoder; 25 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/meminfo.lua: -------------------------------------------------------------------------------- 1 | local function meminfo(path) 2 | path = path or "/proc/meminfo" 3 | local tbl = {} 4 | local pattern = "(%g+):%s+(%d+)%s+(%g+)" 5 | 6 | for str in io.lines(path) do 7 | local name, size, units = str:match(pattern) 8 | if name then 9 | tbl[name] = { 10 | size = tonumber(size), 11 | units = units; 12 | } 13 | end 14 | end 15 | 16 | return tbl 17 | end 18 | 19 | return { 20 | decoder = meminfo; 21 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/modules.lua: -------------------------------------------------------------------------------- 1 | local strutil = require("lj2procfs.string-util") 2 | 3 | local pattern1 = "(%g+) (%d+) (%d+)%s+-%s+(%g+)%s+(%g+)" 4 | local pattern2 = "(%g+) (%d+) (%d+)%s+(%g+),%s+(%g+)%s+(%g+)" 5 | 6 | -- For each line, the 'used' field show how many times this 7 | -- module is being used by something else 8 | -- If that 'something else' is itself a module, then the 'by' 9 | -- field indicates the names of those other modules. Otherwise, 10 | -- it is blank. 11 | local function decoder(path) 12 | path = path or "/proc/modules" 13 | 14 | local tbl = {} 15 | 16 | for str in io.lines(path) do 17 | -- first try pattern 1, as this will indicate no 'by' field 18 | local name, size, used, status, address = str:match(pattern1) 19 | if name then 20 | tbl[name] = { 21 | size = tonumber(size), 22 | used = tonumber(id), 23 | status = status, 24 | address = address, 25 | by = {}, 26 | } 27 | else 28 | -- try pattern 2, which will separate out the 'by' field 29 | -- into a table 30 | name, size, id, by, status, address = str:match(pattern2) 31 | tbl[name] = { 32 | size = tonumber(size), 33 | used = tonumber(id), 34 | by = strutil.tsplitbool(by,','), 35 | status = status, 36 | address = address, 37 | } 38 | end 39 | end 40 | 41 | return tbl; 42 | end 43 | 44 | return { 45 | decoder = decoder; 46 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/net.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local libc = require("lj2procfs.libc") 3 | 4 | local function net(path) 5 | path = path or "/proc/net" 6 | 7 | local buff = ffi.new("char [2048]") 8 | local buffsize = 2048 9 | 10 | local size = libc.readlink(path, buff, buffsize); 11 | 12 | if size > 0 then 13 | return ffi.string(buff, size) 14 | end 15 | 16 | return nil; 17 | end 18 | 19 | return { 20 | decoder = net; 21 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/net/dev.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | local labelpatt = "(%g+):(.*)" 4 | local columnValuepatt = "(%g+)" 5 | 6 | local headings = { 7 | "rx_bytes", 8 | "rx_packets", 9 | "rx_errs", 10 | "rx_drop", 11 | "rx_fifo", 12 | "rx_frame", 13 | "rx_compressed", 14 | "rx_multicast", 15 | 16 | "tx_bytes", 17 | "tx_packets", 18 | "tx_errs", 19 | "tx_drop", 20 | "tx_fifo", 21 | "tx_collisions", 22 | "tx_carrier", 23 | "tx_compressed" 24 | } 25 | 26 | local function getValueList(str) 27 | local label, remainder = str:match(labelpatt) 28 | local tbl = {} 29 | for columnValue in remainder:gmatch(columnValuepatt) do 30 | table.insert(tbl, tonumber(columnValue)) 31 | end 32 | 33 | return label, tbl; 34 | end 35 | 36 | local function net_dev(path) 37 | path = path or "/proc/net/dev" 38 | 39 | local tbl = {} 40 | local linesToSkip = 2 41 | for str in io.lines(path) do 42 | local rowTbl = {} 43 | if linesToSkip > 0 then 44 | linesToSkip = linesToSkip - 1; 45 | else 46 | local label, values = getValueList(str) 47 | for idx, name in ipairs(headings) do 48 | rowTbl[name] = values[idx]; 49 | end 50 | 51 | tbl[label] = rowTbl; 52 | end 53 | end 54 | 55 | return tbl; 56 | end 57 | 58 | return { 59 | decoder = net_dev; 60 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/net/netstat.lua: -------------------------------------------------------------------------------- 1 | --netstat.lua 2 | local labelpatt = "(%g+):(.*)" 3 | local columnNamepatt = "(%g+)" 4 | local columnValuepatt = "(%g+)" 5 | 6 | local function getHeaderList(str) 7 | local label, remainder = str:match(labelpatt) 8 | local tbl = {} 9 | for columnName in remainder:gmatch(columnNamepatt) do 10 | table.insert(tbl, columnName) 11 | --print(columnName) 12 | end 13 | 14 | return label, tbl; 15 | end 16 | 17 | local function getValueList(str) 18 | local label, remainder = str:match(labelpatt) 19 | local tbl = {} 20 | for columnValue in remainder:gmatch(columnValuepatt) do 21 | table.insert(tbl, tonumber(columnValue)) 22 | end 23 | 24 | return label, tbl; 25 | end 26 | 27 | local function netstat(path) 28 | path = path or "/proc/net/netstat" 29 | local tbl = {} 30 | local str = nil; 31 | 32 | local f = io.open(path) 33 | if not f then return nil; end 34 | 35 | while(true) do 36 | -- each entry is a combination of two lines 37 | -- the first line is the header line 38 | -- the second is the data 39 | local header = f:read() 40 | if not header then break end 41 | 42 | local label, columnNames = getHeaderList(header) 43 | 44 | if not header then break end 45 | 46 | local data = f:read() 47 | local columnLabel, columnValues = getValueList(data) 48 | 49 | local rowTbl = {} 50 | for idx, name in ipairs(columnNames) do 51 | rowTbl[name] = columnValues[idx]; 52 | end 53 | tbl[label] = rowTbl; 54 | end 55 | 56 | return tbl; 57 | end 58 | 59 | return { 60 | decoder = netstat; 61 | 62 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/partitions.lua: -------------------------------------------------------------------------------- 1 | local function decoder(path) 2 | path = path or "/proc/partitions" 3 | 4 | local tbl = {} 5 | 6 | local pattern = "%s*(%d+)%s+(%d+)%s+(%d+)%s+(%g+)" 7 | local linesToSkip = 2; 8 | for str in io.lines(path) do 9 | if linesToSkip > 0 then 10 | linesToSkip = linesToSkip - 1; 11 | else 12 | local major, minor, blocks, name = str:match(pattern) 13 | if name then 14 | tbl[name] = { 15 | name = name, 16 | major = tonumber(major), 17 | minor = tonumber(minor), 18 | blocks = tonumber(blocks) 19 | } 20 | end 21 | end 22 | end 23 | 24 | return tbl 25 | end 26 | 27 | return { 28 | decoder = decoder; 29 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/auxv.lua: -------------------------------------------------------------------------------- 1 | -- auxv_iter.lua 2 | 3 | -- An iterator over the auxv values of a process 4 | -- Assuming 'libc' is already somewhere on the path 5 | -- References 6 | -- ld-linux.so 7 | -- getauxval 8 | -- procfs 9 | 10 | 11 | local ffi = require("ffi") 12 | local libc = require("lj2procfs.libc") 13 | 14 | -- This table maps the constant values for the various 15 | -- AT_* types to their symbolic names. This table is used 16 | -- to both generate cdefs, as well as hand back symbolic names 17 | -- for the keys. 18 | local auxtbl = { 19 | [0] = "AT_NULL"; 20 | [1] = "AT_IGNORE"; 21 | [2] = "AT_EXECFD"; 22 | [3] = "AT_PHDR"; 23 | [4] = "AT_PHENT"; 24 | [5] = "AT_PHNUM"; 25 | [6] = "AT_PAGESZ"; 26 | [7] = "AT_BASE"; 27 | [8] = "AT_FLAGS"; 28 | [9] = "AT_ENTRY"; 29 | [10] = "AT_NOTELF"; 30 | [11] = "AT_UID"; 31 | [12] = "AT_EUID"; 32 | [13] = "AT_GID"; 33 | [14] = "AT_EGID"; 34 | [17] = "AT_CLKTCK"; 35 | [15] = "AT_PLATFORM"; 36 | [16] = "AT_HWCAP"; 37 | [18] = "AT_FPUCW"; 38 | [19] = "AT_DCACHEBSIZE"; 39 | [20] = "AT_ICACHEBSIZE"; 40 | [21] = "AT_UCACHEBSIZE"; 41 | [22] = "AT_IGNOREPPC"; 42 | [23] = "AT_SECURE"; 43 | [24] = "AT_BASE_PLATFORM"; 44 | [25] = "AT_RANDOM"; 45 | [26] = "AT_HWCAP2"; 46 | [31] = "AT_EXECFN"; 47 | [32] = "AT_SYSINFO"; 48 | [33] = "AT_SYSINFO_EHDR"; 49 | [34] = "AT_L1I_CACHESHAPE"; 50 | [35] = "AT_L1D_CACHESHAPE"; 51 | [36] = "AT_L2_CACHESHAPE"; 52 | } 53 | 54 | local auxsym = {} 55 | for k,v in pairs(auxtbl) do 56 | auxsym[v] = k; 57 | end 58 | 59 | 60 | -- Given a auxv key(type), and the value returned from reading 61 | -- the file, turn the value into a lua specific type. 62 | -- string pointers --> string 63 | -- int values -> number 64 | -- pointer values -> intptr_t 65 | local function strlen(str) 66 | local idx = 0; 67 | while true do 68 | if str[idx] == 0 then 69 | break 70 | end 71 | idx = idx + 1; 72 | end 73 | 74 | return idx; 75 | end 76 | 77 | local function auxvaluefortype(atype, value) 78 | 79 | -- The only time this is going to work and return a string 80 | -- value is when you are getting the auxv of 'self' 81 | --[[ 82 | if atype == auxsym.AT_EXECFN or atype == auxsym.AT_PLATFORM then 83 | local charptr = ffi.cast("char *", value) 84 | local str = ffi.string(charptr) 85 | 86 | return str; 87 | end 88 | --]] 89 | 90 | if atype == auxsym.AT_UID or atype == auxsym.AT_EUID or 91 | atype == auxsym.AT_GID or atype == auxsym.AT_EGID or 92 | atype == auxsym.AT_FLAGS or atype == auxsym.AT_PAGESZ or 93 | atype == auxsym.AT_HWCAP or atype == auxsym.AT_CLKTCK or 94 | atype == auxsym.AT_PHENT or atype == auxsym.AT_PHNUM then 95 | 96 | return tonumber(value) 97 | end 98 | 99 | if atype == auxsym.AT_SECURE then 100 | if value == 0 then 101 | return false 102 | else 103 | return true; 104 | end 105 | end 106 | 107 | 108 | return ffi.cast("intptr_t", value); 109 | end 110 | 111 | -- iterate over the auxv values at the specified path 112 | -- if no path is specified, use '/proc/self/auxv' to get 113 | -- the values for the currently running program 114 | local function auxv_iter(path) 115 | local fd = libc.open(path, libc.O_RDONLY); 116 | 117 | local params = { 118 | fd = fd; 119 | keybuff = ffi.new("intptr_t[1]"); 120 | valuebuff = ffi.new("intptr_t[1]"); 121 | buffsize = ffi.sizeof(ffi.typeof("intptr_t")); 122 | } 123 | 124 | 125 | local function gen_value(param, state) 126 | local res1 = libc.read(param.fd, param.keybuff, param.buffsize) 127 | local res2 = libc.read(param.fd, param.valuebuff, param.buffsize) 128 | local key = param.keybuff[0]; 129 | local value = param.valuebuff[0]; 130 | 131 | if key == 0 then 132 | libc.close(param.fd); 133 | return nil; 134 | end 135 | 136 | local atype = tonumber(key) 137 | local avalue = auxvaluefortype(atype, value) 138 | --print("gen_value: ", atype, avalue) 139 | 140 | return state, atype, avalue 141 | end 142 | 143 | return gen_value, params, 0 144 | 145 | end 146 | 147 | local function auxv(path) 148 | local tbl = {} 149 | for _, atype, value in auxv_iter(path) do 150 | local fieldkey = auxtbl[atype] 151 | local fieldvalue = value; 152 | 153 | --print(fieldkey, fieldvalue) 154 | tbl[fieldkey] = fieldvalue; 155 | end 156 | 157 | return tbl; 158 | end 159 | 160 | return { 161 | decoder = auxv; 162 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/environ.lua: -------------------------------------------------------------------------------- 1 | local sutil= require("lj2procfs.string-util") 2 | 3 | local function environ(path) 4 | -- open the file 5 | -- return full contents as a string 6 | local f = io.open(path) 7 | 8 | if not f then return nil end 9 | 10 | local str = f:read("*a") 11 | 12 | local tbl = {} 13 | local eqpatt = "(%g+)=(.*)" 14 | 15 | -- The environment variables are separated by a null 16 | -- terminator, so the outer iterator is over that 17 | for _, elem in sutil.mstrziter(str) do 18 | -- Each individual environment variable is a 19 | -- key=value pair, so we split those apart. 20 | local key, value = elem:match(eqpatt); 21 | tbl[key] = value; 22 | end 23 | 24 | return tbl; 25 | end 26 | 27 | return { 28 | decoder = environ; 29 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/exe.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | local libc = require("lj2procfs.libc") 3 | 4 | local function cwd(path) 5 | local buff = ffi.new("char [2048]") 6 | local buffsize = 2048 7 | 8 | local size = libc.readlink(path, buff, buffsize); 9 | if size > 0 then 10 | return ffi.string(buff, size) 11 | end 12 | 13 | return nil; 14 | end 15 | 16 | return { 17 | decoder = cwd; 18 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/io.lua: -------------------------------------------------------------------------------- 1 | 2 | local function io_func(path) 3 | local tbl = {} 4 | local colonpatt = "(%g+):%s+(.*)" 5 | 6 | for str in io.lines(path) do 7 | local key, value = str:match(colonpatt) 8 | tbl[key] = value; 9 | end 10 | 11 | return tbl 12 | end 13 | 14 | return { 15 | decoder = io_func; 16 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/limits.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | Limits associated with each of the proc's resources 3 | --]] 4 | local function limits(path) 5 | -- Soft Limit, Hard Limit, Units 6 | local tbl = {} 7 | local firstline = true; 8 | 9 | for line in io.lines(path) do 10 | if firstline then 11 | firstline = false; 12 | -- do nothing 13 | else 14 | table.insert(tbl, line) 15 | end 16 | end 17 | 18 | return tbl; 19 | end 20 | 21 | return { 22 | decoder = limits; 23 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/maps.lua: -------------------------------------------------------------------------------- 1 | --maps.lua 2 | -- perms 3 | -- r - read 4 | -- w - write 5 | -- x - execute 6 | -- s - shared 7 | -- p - private 8 | 9 | local function maps(path) 10 | local tbl = {} 11 | local pattern = "(%x+)-(%x+)%s+(%g+)%s+(%x+)%s+(%d+):(%d+)%s+(%d+)%s+(.*)" 12 | 13 | for str in io.lines(path) do 14 | local lowaddr, highaddr, perms, offset, major, minor, inode, pathname = str:match(pattern) 15 | if lowaddr then 16 | local rowTbl = { 17 | lowaddr = lowaddr, 18 | highaddr = highaddr, 19 | perms = perms, 20 | offset = offset, 21 | dev_major = tonumber(major), 22 | dev_minor = tonumber(minor), 23 | inode = tonumber(inode), 24 | path = pathname, 25 | } 26 | 27 | table.insert(tbl, rowTbl) 28 | end 29 | end 30 | 31 | return tbl; 32 | end 33 | 34 | return { 35 | decoder = maps; 36 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/mounts.lua: -------------------------------------------------------------------------------- 1 | 2 | local function mounts(path) 3 | local tbl = {} 4 | for str in io.lines(path) do 5 | table.insert(tbl, str) 6 | end 7 | 8 | return tbl 9 | end 10 | 11 | return { 12 | decoder = mounts; 13 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/sched.lua: -------------------------------------------------------------------------------- 1 | local strutil = require("lj2procfs.string-util") 2 | 3 | -- Entries look like: 4 | --[[ 5 | se.statistics.nr_wakeups_passive : 0 6 | se.statistics.nr_wakeups_idle : 0 7 | avg_atom : 0.043153 8 | avg_per_cpu : 0.247472 9 | --]] 10 | -- We want to break this out into a hierarchy of tables 11 | -- to make it easier to access 12 | 13 | local function addToTbl(tbl, key, value) 14 | print("addToTbl: key") 15 | local keyparts = strutil.tsplit(key, '%.') 16 | if #keyparts == 1 then 17 | tbl[key] = value; 18 | return 19 | else 20 | if not tbl[keyparts[1]] then 21 | tbl[keyparts[1]] = {} 22 | end 23 | currentTbl = tbl[keyparts[1]] 24 | table.remove(keyparts, 1) 25 | return addToTbl(currentTbl, table.concat(keyparts,'.'), value) 26 | end 27 | end 28 | 29 | local function sched(path) 30 | local tbl = {} 31 | local colonpatt = "(%g+)%s*:%s+(.*)" 32 | 33 | -- skip first two lines 34 | local linesToSkip = 2 35 | for str in io.lines(path) do 36 | if linesToSkip > 0 then 37 | linesToSkip = linesToSkip - 1; 38 | else 39 | -- each of these is ':' delimited 40 | local key, value = str:match(colonpatt) 41 | if key then 42 | value = tonumber(value) 43 | addToTbl(tbl, key, value) 44 | end 45 | end 46 | end 47 | 48 | return tbl 49 | end 50 | 51 | return { 52 | decoder = sched; 53 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/process/status.lua: -------------------------------------------------------------------------------- 1 | 2 | local function status(path) 3 | -- each of these is ':' delimited 4 | local pattern = "(%g+):%s+(.*)" 5 | local tbl = {} 6 | 7 | 8 | for str in io.lines(path) do 9 | print(str) 10 | local key, value = str:match(pattern) 11 | if key then 12 | tbl[key] = value; 13 | end 14 | end 15 | 16 | return tbl; 17 | end 18 | 19 | return { 20 | decoder = status; 21 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/softirqs.lua: -------------------------------------------------------------------------------- 1 | --netstat.lua 2 | local labelpatt = "(%g+):(.*)" 3 | local columnNamepatt = "(%g+)" 4 | local columnValuepatt = "(%d+)" 5 | 6 | local function getHeaderList(str) 7 | local tbl = {} 8 | for columnName in str:gmatch(columnNamepatt) do 9 | table.insert(tbl, columnName) 10 | end 11 | 12 | return tbl; 13 | end 14 | 15 | local function getValueList(str) 16 | local label, remainder = str:match(labelpatt) 17 | local tbl = {} 18 | for columnValue in remainder:gmatch(columnValuepatt) do 19 | table.insert(tbl, tonumber(columnValue)) 20 | end 21 | 22 | return label, tbl; 23 | end 24 | 25 | local function softirqs(path) 26 | path = path or "/proc/softirqs" 27 | local tbl = {} 28 | local str = nil; 29 | 30 | local f = io.open(path) 31 | if not f then return nil; end 32 | 33 | -- read column headings 34 | local firstLine = f:read(); 35 | local columnNames = getHeaderList(firstLine) 36 | 37 | while(true) do 38 | -- each entry is a combination of two lines 39 | -- the first line is the header line 40 | -- the second is the data 41 | local dataLine = f:read() 42 | if not dataLine then break end 43 | 44 | local label, columnValues = getValueList(dataLine) 45 | 46 | local rowTbl = {} 47 | for idx, name in ipairs(columnNames) do 48 | rowTbl[name] = columnValues[idx]; 49 | end 50 | tbl[label] = rowTbl; 51 | end 52 | 53 | return tbl; 54 | end 55 | 56 | return { 57 | decoder = softirqs; 58 | 59 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/stat.lua: -------------------------------------------------------------------------------- 1 | local numpatt = "(%d+)" 2 | local cpupatt = "^cpu(%d+)(.*)" 3 | local allcpupatt = "^cpu%s+(.*)" 4 | 5 | local fieldNames = { 6 | "user", 7 | "nice", 8 | "system", 9 | "idle", 10 | "iowait", 11 | "irq", 12 | "softirq", 13 | "steal", 14 | "guest", 15 | "guest_nice"; 16 | } 17 | 18 | local function readCpuValues(str) 19 | local row = {} 20 | 21 | local offset = 1; 22 | for value in str:gmatch(numpatt) do 23 | row[fieldNames[offset]] = tonumber(value) 24 | offset = offset + 1; 25 | end 26 | 27 | return row; 28 | end 29 | 30 | local function stat(path) 31 | path = path or "/proc/stat" 32 | 33 | -- read only first line to get overall information 34 | local tbl = {} 35 | tbl.cpus = {} 36 | 37 | for str in io.lines(path) do 38 | local allcpurest = str:match(allcpupatt) 39 | --print("stat.allcpu: ", allcpurest, str) 40 | if allcpurest then 41 | tbl["allcpus"] = readCpuValues(allcpurest); 42 | else 43 | local cpuid, rest = str:match(cpupatt) 44 | if cpuid then 45 | table.insert(tbl.cpus, readCpuValues(rest)) 46 | end 47 | end 48 | end 49 | 50 | return tbl; 51 | end 52 | 53 | return { 54 | decoder = stat; 55 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/sys.lua: -------------------------------------------------------------------------------- 1 | --ProcessEntry.lua 2 | local libc = require("lj2procfs.libc") 3 | local fs = require("lj2procfs.fs-util") 4 | local fun = require("lj2procfs.fun") 5 | local putil = require("lj2procfs.print-util") 6 | 7 | 8 | local function get_value(path) 9 | --print("get_value: ", path) 10 | local f = io.open(path) 11 | if not f then 12 | return nil; 13 | end 14 | 15 | local str = f:read("*a") 16 | f:close() 17 | 18 | if not str then return nil end; 19 | 20 | local vpatt = "(.*)$" 21 | local vstr = str:match(vpatt) 22 | 23 | return vstr; 24 | end 25 | 26 | local function set_value(value, path) 27 | local f, err = io.open(path, "w") 28 | 29 | if not f == nil then 30 | return false, err 31 | end 32 | 33 | f:write(value) 34 | f:close() 35 | 36 | return true; 37 | end 38 | 39 | 40 | local SysEntry = {} 41 | setmetatable(SysEntry, { 42 | __call = function(self, path) 43 | return SysEntry:new(path); 44 | end, 45 | }) 46 | 47 | local function toSysEntry(entry) 48 | --print("== ToSysEntry == ") 49 | local sentry = SysEntry:new(entry.Path); 50 | --putil.printValue(sentry) 51 | 52 | return sentry 53 | end 54 | 55 | local function interestingEntry(entry) 56 | return not (entry.Name == '.' or entry.Name == "..") 57 | end 58 | 59 | local SysEntry_mt = { 60 | __pairs = function(tbl) 61 | --print("SysEntry_mt.__pairs: ", tbl.Path, fs.isDirectory(tbl.Path)) 62 | if not fs.isDirectory(tbl.Path) then 63 | local alreadyCalled = false; 64 | local function callOnce(param, state) 65 | if alreadyCalled then return nil end; 66 | 67 | alreadyCalled = not alreadyCalled; 68 | 69 | return tbl.Path, get_value(tbl.Path) 70 | end 71 | 72 | return callOnce, tbl, false 73 | end 74 | 75 | -- return fun.map(toSysEntry, fs.files_in_directory(tbl.Path)) 76 | return fun.map(toSysEntry, fun.filter(interestingEntry, fs.entries_in_directory(tbl.Path))) 77 | end, 78 | 79 | __index = function(self, key) 80 | local path = self.Path..'/'..key; 81 | 82 | if fs.isDirectory(path) then 83 | return SysEntry(path) 84 | end 85 | 86 | return get_value(path) 87 | end, 88 | 89 | __newindex = function(self, key, value) 90 | local path = self.Path..'/'..key; 91 | return set_value(value, path) 92 | end, 93 | } 94 | 95 | function SysEntry.init(self, path) 96 | local obj = { 97 | Path = path 98 | } 99 | 100 | setmetatable(obj, SysEntry_mt); 101 | return obj; 102 | end 103 | 104 | function SysEntry.new(self, path) 105 | path = path or "/proc/sys" 106 | return self:init(path) 107 | end 108 | 109 | local function sys_decoder(path) 110 | --print("sys_decoder: ", path) 111 | return SysEntry:new(path) 112 | end 113 | 114 | local function sys_encoder(path) 115 | --print("sys_encoder: ", path) 116 | return SysEntry:new(path) 117 | end 118 | 119 | return { 120 | decoder = sys_decoder; 121 | encoder = sys_encoder; 122 | sysfs = SysEntry; 123 | } 124 | 125 | -------------------------------------------------------------------------------- /lj2procfs/codecs/uptime.lua: -------------------------------------------------------------------------------- 1 | --[[ 2 | seconds idle 3 | 4 | The first value is the number of seconds the system has been up. 5 | The second number is the accumulated number of seconds all processors 6 | have spent idle. The second number can be greater than the first 7 | in a multi-processor system. 8 | --]] 9 | local function decoder(path) 10 | path = path or "/proc/uptime" 11 | -- open the file 12 | -- return full contents as a string 13 | local f = io.open(path) 14 | local str = f:read("*a") 15 | f:close() 16 | 17 | local seconds, idle = str:match("(%d*%.?%d+)%s+(%d*%.?%d+)") 18 | return { 19 | seconds = tonumber(seconds); 20 | idle = tonumber(idle); 21 | } 22 | 23 | end 24 | 25 | return { 26 | decoder = decoder; 27 | } -------------------------------------------------------------------------------- /lj2procfs/codecs/vmstat.lua: -------------------------------------------------------------------------------- 1 | 2 | local function vmstat(path) 3 | local path = path or "/proc/vmstat" 4 | 5 | local tbl = {} 6 | local pattern = "(%g+)%s+(%d+)" 7 | 8 | for str in io.lines(path) do 9 | local key, value = str:match(pattern) 10 | if key then 11 | tbl[key] = tonumber(value) 12 | end 13 | end 14 | 15 | return tbl; 16 | end 17 | 18 | return { 19 | decoder = vmstat; 20 | } -------------------------------------------------------------------------------- /lj2procfs/fs-util.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | local libc = require("lj2procfs.libc") 4 | local sutil = require("lj2procfs.string-util") 5 | 6 | function hidden_file_allow_backup(filename) 7 | if not filename then return false end 8 | 9 | return 10 | sutil.startswith(filename, '.') or 11 | filename == "lost+found" or 12 | filename == "aquota.user" or 13 | filename == "aquota.group" or 14 | sutil.endswith(filename, ".rpmnew") or 15 | sutil.endswith(filename, ".rpmsave") or 16 | sutil.endswith(filename, ".rpmorig") or 17 | sutil.endswith(filename, ".dpkg-old") or 18 | sutil.endswith(filename, ".dpkg-new") or 19 | sutil.endswith(filename, ".dpkg-tmp") or 20 | sutil.endswith(filename, ".dpkg-dist") or 21 | sutil.endswith(filename, ".dpkg-bak") or 22 | sutil.endswith(filename, ".dpkg-backup") or 23 | sutil.endswith(filename, ".dpkg-remove") or 24 | sutil.endswith(filename, ".swp"); 25 | end 26 | 27 | function isHiddenFile(filename) 28 | if not filename then return false; end 29 | 30 | if sutil.endswith(filename, "~") then 31 | return true; 32 | end 33 | 34 | return hidden_file_allow_backup(filename); 35 | end 36 | 37 | 38 | --[[ 39 | local function isDirectory(entry) 40 | return entry.Kind == libc.DT_DIR and 41 | entry.Name ~= '.' and 42 | entry.Name ~= '..' 43 | end 44 | --]] 45 | 46 | local function isDirectory(path) 47 | local adir = libc.opendir(path); 48 | local res = adir ~= nil 49 | if adir ~= nil then 50 | libc.closedir(adir) 51 | end 52 | 53 | return res; 54 | end 55 | 56 | 57 | local function isFile(path) 58 | local fd = io.open(path) 59 | local fdtype = io.type(fd); 60 | print("FD TYPE: ", path, fdtype) 61 | local res = fdtype == "file" 62 | fd:close(); 63 | 64 | return res; 65 | end 66 | 67 | --[[ 68 | local function dirent_ensure_type(DIR *d, struct dirent *de) 69 | struct stat st; 70 | 71 | assert(d); 72 | assert(de); 73 | 74 | if (de.d_type != libc.DT_UNKNOWN) 75 | return 0; 76 | 77 | if (fstatat(dirfd(d), de->d_name, &st, AT_SYMLINK_NOFOLLOW) < 0) 78 | return -errno; 79 | 80 | de->d_type = 81 | S_ISREG(st.st_mode) ? DT_REG : 82 | S_ISDIR(st.st_mode) ? DT_DIR : 83 | S_ISLNK(st.st_mode) ? DT_LNK : 84 | S_ISFIFO(st.st_mode) ? DT_FIFO : 85 | S_ISSOCK(st.st_mode) ? DT_SOCK : 86 | S_ISCHR(st.st_mode) ? DT_CHR : 87 | S_ISBLK(st.st_mode) ? DT_BLK : 88 | DT_UNKNOWN; 89 | 90 | return 0; 91 | end 92 | --]] 93 | 94 | local function dirent_is_file(de) 95 | if de == nil then return false; end 96 | 97 | if isHiddenFile(ffi.string(de.d_name)) then 98 | return false; 99 | end 100 | 101 | if (de.d_type ~= libc.DT_REG and 102 | de.d_type ~= libc.DT_LNK and 103 | de.d_type ~= libc.DT_UNKNOWN) then 104 | return false; 105 | end 106 | 107 | return true; 108 | end 109 | 110 | --[[ 111 | local function dirent_is_file_with_suffix(const struct dirent *de, const char *suffix) 112 | assert(de); 113 | 114 | if (de.d_type ~= libc.DT_REG and 115 | de.d_type ~= libc.DT_LNK and 116 | de.d_type ~= libc.DT_UNKNOWN) then 117 | return false; 118 | end 119 | 120 | if (isHiddenFile_allow_backup(de.d_name)) then 121 | return false; 122 | end 123 | 124 | return endswith(de.d_name, suffix); 125 | end 126 | --]] 127 | 128 | local function nil_iter() 129 | return nil; 130 | end 131 | 132 | local function iterate_files_in_directory(path) 133 | local dir = libc.opendir(path) 134 | 135 | if not dir==nil then return nil_iter, nil, nil; end 136 | 137 | -- This is a 'generator' which will continue 138 | -- the iteration over files 139 | local function gen_files(dir, state) 140 | local de = nil 141 | 142 | while true do 143 | de = libc.readdir(dir) 144 | 145 | -- if we've run out of entries, then return nil 146 | if de == nil then return nil end 147 | 148 | --dirutil.dirent_ensure_type(d, de); 149 | 150 | -- check the entry to see if it's an actual file, and not 151 | -- a directory or link 152 | if dirent_is_file(de) then 153 | break; 154 | end 155 | end 156 | 157 | local entry = { 158 | Name = ffi.string(de.d_name); 159 | Kind = de.d_type; 160 | INode = de.d_ino; 161 | } 162 | entry.Path = path..'/'..entry.Name; 163 | 164 | return state, entry 165 | end 166 | 167 | -- make sure to do the finalizer 168 | -- for garbage collection 169 | ffi.gc(dir, libc.closedir); 170 | 171 | return gen_files, dir, dir; 172 | end 173 | 174 | local function entries_in_directory(path) 175 | local dir = libc.opendir(path) 176 | 177 | if dir==nil then return nil_iter, nil, nil; end 178 | 179 | 180 | -- This is a 'generator' which will continue 181 | -- the iteration over files 182 | local function gen_entries(dir, state) 183 | local de = libc.readdir(dir) 184 | -- if we've run out of entries, then return nil 185 | if de == nil then return nil end 186 | 187 | local entry = { 188 | Name = ffi.string(de.d_name); 189 | Kind = de.d_type; 190 | INode = de.d_ino; 191 | } 192 | entry.Path = path..'/'..entry.Name; 193 | 194 | return state, entry 195 | end 196 | 197 | -- make sure to do the finalizer 198 | -- for garbage collection 199 | --ffi.gc(dir, libc.closedir); 200 | 201 | return gen_entries, dir, dir; 202 | end 203 | 204 | 205 | local exports = { 206 | files_in_directory = iterate_files_in_directory; 207 | entries_in_directory = entries_in_directory; 208 | 209 | dirent_is_file = dirent_is_file; 210 | 211 | isDirectory = isDirectory; 212 | isFile = isFile; 213 | isHiddenFile = isHiddenFile 214 | } 215 | 216 | return exports 217 | -------------------------------------------------------------------------------- /lj2procfs/fun.lua: -------------------------------------------------------------------------------- 1 | --- 2 | --- Lua Fun - a high-performance functional programming library for LuaJIT 3 | --- 4 | --- Copyright (c) 2013-2014 Roman Tsisyk 5 | --- 6 | --- Distributed under the MIT/X11 License. See COPYING.md for more details. 7 | --- 8 | --- https://github.com/rtsisyk/luafun 9 | --- 10 | 11 | local exports = {} 12 | local methods = {} 13 | 14 | -------------------------------------------------------------------------------- 15 | -- Tools 16 | -------------------------------------------------------------------------------- 17 | 18 | local return_if_not_empty = function(state_x, ...) 19 | if state_x == nil then 20 | return nil 21 | end 22 | return ... 23 | end 24 | 25 | local call_if_not_empty = function(fun, state_x, ...) 26 | if state_x == nil then 27 | return nil 28 | end 29 | return state_x, fun(...) 30 | end 31 | 32 | local function deepcopy(orig) -- used by cycle() 33 | local orig_type = type(orig) 34 | local copy 35 | if orig_type == 'table' then 36 | copy = {} 37 | for orig_key, orig_value in next, orig, nil do 38 | copy[deepcopy(orig_key)] = deepcopy(orig_value) 39 | end 40 | else 41 | copy = orig 42 | end 43 | return copy 44 | end 45 | 46 | local iterator_mt = { 47 | -- usually called by for-in loop 48 | __call = function(self, param, state) 49 | return self.gen(param, state) 50 | end; 51 | __tostring = function(self) 52 | return '' 53 | end; 54 | -- add all exported methods 55 | __index = methods; 56 | } 57 | 58 | local wrap = function(gen, param, state) 59 | return setmetatable({ 60 | gen = gen, 61 | param = param, 62 | state = state 63 | }, iterator_mt), param, state 64 | end 65 | exports.wrap = wrap 66 | 67 | local unwrap = function(self) 68 | return self.gen, self.param, self.state 69 | end 70 | methods.unwrap = unwrap 71 | 72 | -------------------------------------------------------------------------------- 73 | -- Basic Functions 74 | -------------------------------------------------------------------------------- 75 | 76 | local nil_gen = function(_param, _state) 77 | return nil 78 | end 79 | 80 | local string_gen = function(param, state) 81 | local state = state + 1 82 | if state > #param then 83 | return nil 84 | end 85 | local r = string.sub(param, state, state) 86 | return state, r 87 | end 88 | 89 | local pairs_gen = pairs({ a = 0 }) -- get the generating function from pairs 90 | local map_gen = function(tab, key) 91 | local value 92 | local key, value = pairs_gen(tab, key) 93 | return key, key, value 94 | end 95 | 96 | local rawiter = function(obj, param, state) 97 | assert(obj ~= nil, "invalid iterator") 98 | if type(obj) == "table" then 99 | local mt = getmetatable(obj); 100 | if mt ~= nil then 101 | if mt == iterator_mt then 102 | return obj.gen, obj.param, obj.state 103 | elseif mt.__ipairs ~= nil then 104 | return mt.__ipairs(obj) 105 | elseif mt.__pairs ~= nil then 106 | return mt.__pairs(obj) 107 | end 108 | end 109 | if #obj > 0 then 110 | -- array 111 | return ipairs(obj) 112 | else 113 | -- hash 114 | return map_gen, obj, nil 115 | end 116 | elseif (type(obj) == "function") then 117 | return obj, param, state 118 | elseif (type(obj) == "string") then 119 | if #obj == 0 then 120 | return nil_gen, nil, nil 121 | end 122 | return string_gen, obj, 0 123 | end 124 | error(string.format('object %s of type "%s" is not iterable', 125 | obj, type(obj))) 126 | end 127 | 128 | local iter = function(obj, param, state) 129 | return wrap(rawiter(obj, param, state)) 130 | end 131 | exports.iter = iter 132 | 133 | local method0 = function(fun) 134 | return function(self) 135 | return fun(self.gen, self.param, self.state) 136 | end 137 | end 138 | 139 | local method1 = function(fun) 140 | return function(self, arg1) 141 | return fun(arg1, self.gen, self.param, self.state) 142 | end 143 | end 144 | 145 | local method2 = function(fun) 146 | return function(self, arg1, arg2) 147 | return fun(arg1, arg2, self.gen, self.param, self.state) 148 | end 149 | end 150 | 151 | local export0 = function(fun) 152 | return function(gen, param, state) 153 | return fun(rawiter(gen, param, state)) 154 | end 155 | end 156 | 157 | local export1 = function(fun) 158 | return function(arg1, gen, param, state) 159 | return fun(arg1, rawiter(gen, param, state)) 160 | end 161 | end 162 | 163 | local export2 = function(fun) 164 | return function(arg1, arg2, gen, param, state) 165 | return fun(arg1, arg2, rawiter(gen, param, state)) 166 | end 167 | end 168 | 169 | local each = function(fun, gen, param, state) 170 | repeat 171 | state = call_if_not_empty(fun, gen(param, state)) 172 | until state == nil 173 | end 174 | methods.each = method1(each) 175 | exports.each = export1(each) 176 | methods.for_each = methods.each 177 | exports.for_each = exports.each 178 | methods.foreach = methods.each 179 | exports.foreach = exports.each 180 | 181 | -------------------------------------------------------------------------------- 182 | -- Generators 183 | -------------------------------------------------------------------------------- 184 | 185 | local range_gen = function(param, state) 186 | local stop, step = param[1], param[2] 187 | local state = state + step 188 | if state > stop then 189 | return nil 190 | end 191 | return state, state 192 | end 193 | 194 | local range_rev_gen = function(param, state) 195 | local stop, step = param[1], param[2] 196 | local state = state + step 197 | if state < stop then 198 | return nil 199 | end 200 | return state, state 201 | end 202 | 203 | local range = function(start, stop, step) 204 | if step == nil then 205 | if stop == nil then 206 | if start == 0 then 207 | return nil_gen, nil, nil 208 | end 209 | stop = start 210 | start = stop > 0 and 1 or -1 211 | end 212 | step = start <= stop and 1 or -1 213 | end 214 | 215 | assert(type(start) == "number", "start must be a number") 216 | assert(type(stop) == "number", "stop must be a number") 217 | assert(type(step) == "number", "step must be a number") 218 | assert(step ~= 0, "step must not be zero") 219 | 220 | if (step > 0) then 221 | return wrap(range_gen, {stop, step}, start - step) 222 | elseif (step < 0) then 223 | return wrap(range_rev_gen, {stop, step}, start - step) 224 | end 225 | end 226 | exports.range = range 227 | 228 | local duplicate_table_gen = function(param_x, state_x) 229 | return state_x + 1, unpack(param_x) 230 | end 231 | 232 | local duplicate_fun_gen = function(param_x, state_x) 233 | return state_x + 1, param_x(state_x) 234 | end 235 | 236 | local duplicate_gen = function(param_x, state_x) 237 | return state_x + 1, param_x 238 | end 239 | 240 | local duplicate = function(...) 241 | if select('#', ...) <= 1 then 242 | return wrap(duplicate_gen, select(1, ...), 0) 243 | else 244 | return wrap(duplicate_table_gen, {...}, 0) 245 | end 246 | end 247 | exports.duplicate = duplicate 248 | exports.replicate = duplicate 249 | exports.xrepeat = duplicate 250 | 251 | local tabulate = function(fun) 252 | assert(type(fun) == "function") 253 | return wrap(duplicate_fun_gen, fun, 0) 254 | end 255 | exports.tabulate = tabulate 256 | 257 | local zeros = function() 258 | return wrap(duplicate_gen, 0, 0) 259 | end 260 | exports.zeros = zeros 261 | 262 | local ones = function() 263 | return wrap(duplicate_gen, 1, 0) 264 | end 265 | exports.ones = ones 266 | 267 | local rands_gen = function(param_x, _state_x) 268 | return 0, math.random(param_x[1], param_x[2]) 269 | end 270 | 271 | local rands_nil_gen = function(_param_x, _state_x) 272 | return 0, math.random() 273 | end 274 | 275 | local rands = function(n, m) 276 | if n == nil and m == nil then 277 | return wrap(rands_nil_gen, 0, 0) 278 | end 279 | assert(type(n) == "number", "invalid first arg to rands") 280 | if m == nil then 281 | m = n 282 | n = 0 283 | else 284 | assert(type(m) == "number", "invalid second arg to rands") 285 | end 286 | assert(n < m, "empty interval") 287 | return wrap(rands_gen, {n, m - 1}, 0) 288 | end 289 | exports.rands = rands 290 | 291 | -------------------------------------------------------------------------------- 292 | -- Slicing 293 | -------------------------------------------------------------------------------- 294 | 295 | local nth = function(n, gen_x, param_x, state_x) 296 | assert(n > 0, "invalid first argument to nth") 297 | -- An optimization for arrays and strings 298 | if gen_x == ipairs then 299 | return param_x[n] 300 | elseif gen_x == string_gen then 301 | if n < #param_x then 302 | return string.sub(param_x, n, n) 303 | else 304 | return nil 305 | end 306 | end 307 | for i=1,n-1,1 do 308 | state_x = gen_x(param_x, state_x) 309 | if state_x == nil then 310 | return nil 311 | end 312 | end 313 | return return_if_not_empty(gen_x(param_x, state_x)) 314 | end 315 | methods.nth = method1(nth) 316 | exports.nth = export1(nth) 317 | 318 | local head_call = function(state, ...) 319 | if state == nil then 320 | error("head: iterator is empty") 321 | end 322 | return ... 323 | end 324 | 325 | local head = function(gen, param, state) 326 | return head_call(gen(param, state)) 327 | end 328 | methods.head = method0(head) 329 | exports.head = export0(head) 330 | exports.car = exports.head 331 | methods.car = methods.head 332 | 333 | local tail = function(gen, param, state) 334 | state = gen(param, state) 335 | if state == nil then 336 | return wrap(nil_gen, nil, nil) 337 | end 338 | return wrap(gen, param, state) 339 | end 340 | methods.tail = method0(tail) 341 | exports.tail = export0(tail) 342 | exports.cdr = exports.tail 343 | methods.cdr = methods.tail 344 | 345 | local take_n_gen_x = function(i, state_x, ...) 346 | if state_x == nil then 347 | return nil 348 | end 349 | return {i, state_x}, ... 350 | end 351 | 352 | local take_n_gen = function(param, state) 353 | local n, gen_x, param_x = param[1], param[2], param[3] 354 | local i, state_x = state[1], state[2] 355 | if i >= n then 356 | return nil 357 | end 358 | return take_n_gen_x(i + 1, gen_x(param_x, state_x)) 359 | end 360 | 361 | local take_n = function(n, gen, param, state) 362 | assert(n >= 0, "invalid first argument to take_n") 363 | return wrap(take_n_gen, {n, gen, param}, {0, state}) 364 | end 365 | methods.take_n = method1(take_n) 366 | exports.take_n = export1(take_n) 367 | 368 | local take_while_gen_x = function(fun, state_x, ...) 369 | if state_x == nil or not fun(...) then 370 | return nil 371 | end 372 | return state_x, ... 373 | end 374 | 375 | local take_while_gen = function(param, state_x) 376 | local fun, gen_x, param_x = param[1], param[2], param[3] 377 | return take_while_gen_x(fun, gen_x(param_x, state_x)) 378 | end 379 | 380 | local take_while = function(fun, gen, param, state) 381 | assert(type(fun) == "function", "invalid first argument to take_while") 382 | return wrap(take_while_gen, {fun, gen, param}, state) 383 | end 384 | methods.take_while = method1(take_while) 385 | exports.take_while = export1(take_while) 386 | 387 | local take = function(n_or_fun, gen, param, state) 388 | if type(n_or_fun) == "number" then 389 | return take_n(n_or_fun, gen, param, state) 390 | else 391 | return take_while(n_or_fun, gen, param, state) 392 | end 393 | end 394 | methods.take = method1(take) 395 | exports.take = export1(take) 396 | 397 | local drop_n = function(n, gen, param, state) 398 | assert(n >= 0, "invalid first argument to drop_n") 399 | local i 400 | for i=1,n,1 do 401 | state = gen(param, state) 402 | if state == nil then 403 | return wrap(nil_gen, nil, nil) 404 | end 405 | end 406 | return wrap(gen, param, state) 407 | end 408 | methods.drop_n = method1(drop_n) 409 | exports.drop_n = export1(drop_n) 410 | 411 | local drop_while_x = function(fun, state_x, ...) 412 | if state_x == nil or not fun(...) then 413 | return state_x, false 414 | end 415 | return state_x, true, ... 416 | end 417 | 418 | local drop_while = function(fun, gen_x, param_x, state_x) 419 | assert(type(fun) == "function", "invalid first argument to drop_while") 420 | local cont, state_x_prev 421 | repeat 422 | state_x_prev = deepcopy(state_x) 423 | state_x, cont = drop_while_x(fun, gen_x(param_x, state_x)) 424 | until not cont 425 | if state_x == nil then 426 | return wrap(nil_gen, nil, nil) 427 | end 428 | return wrap(gen_x, param_x, state_x_prev) 429 | end 430 | methods.drop_while = method1(drop_while) 431 | exports.drop_while = export1(drop_while) 432 | 433 | local drop = function(n_or_fun, gen_x, param_x, state_x) 434 | if type(n_or_fun) == "number" then 435 | return drop_n(n_or_fun, gen_x, param_x, state_x) 436 | else 437 | return drop_while(n_or_fun, gen_x, param_x, state_x) 438 | end 439 | end 440 | methods.drop = method1(drop) 441 | exports.drop = export1(drop) 442 | 443 | local split = function(n_or_fun, gen_x, param_x, state_x) 444 | return take(n_or_fun, gen_x, param_x, state_x), 445 | drop(n_or_fun, gen_x, param_x, state_x) 446 | end 447 | methods.split = method1(split) 448 | exports.split = export1(split) 449 | methods.split_at = methods.split 450 | exports.split_at = exports.split 451 | methods.span = methods.split 452 | exports.span = exports.split 453 | 454 | -------------------------------------------------------------------------------- 455 | -- Indexing 456 | -------------------------------------------------------------------------------- 457 | 458 | local index = function(x, gen, param, state) 459 | local i = 1 460 | for _k, r in gen, param, state do 461 | if r == x then 462 | return i 463 | end 464 | i = i + 1 465 | end 466 | return nil 467 | end 468 | methods.index = method1(index) 469 | exports.index = export1(index) 470 | methods.index_of = methods.index 471 | exports.index_of = exports.index 472 | methods.elem_index = methods.index 473 | exports.elem_index = exports.index 474 | 475 | local indexes_gen = function(param, state) 476 | local x, gen_x, param_x = param[1], param[2], param[3] 477 | local i, state_x = state[1], state[2] 478 | local r 479 | while true do 480 | state_x, r = gen_x(param_x, state_x) 481 | if state_x == nil then 482 | return nil 483 | end 484 | i = i + 1 485 | if r == x then 486 | return {i, state_x}, i 487 | end 488 | end 489 | end 490 | 491 | local indexes = function(x, gen, param, state) 492 | return wrap(indexes_gen, {x, gen, param}, {0, state}) 493 | end 494 | methods.indexes = method1(indexes) 495 | exports.indexes = export1(indexes) 496 | methods.elem_indexes = methods.indexes 497 | exports.elem_indexes = exports.indexes 498 | methods.indices = methods.indexes 499 | exports.indices = exports.indexes 500 | methods.elem_indices = methods.indexes 501 | exports.elem_indices = exports.indexes 502 | 503 | -------------------------------------------------------------------------------- 504 | -- Filtering 505 | -------------------------------------------------------------------------------- 506 | 507 | local filter1_gen = function(fun, gen_x, param_x, state_x, a) 508 | while true do 509 | if state_x == nil or fun(a) then break; end 510 | state_x, a = gen_x(param_x, state_x) 511 | end 512 | return state_x, a 513 | end 514 | 515 | -- call each other 516 | local filterm_gen 517 | local filterm_gen_shrink = function(fun, gen_x, param_x, state_x) 518 | return filterm_gen(fun, gen_x, param_x, gen_x(param_x, state_x)) 519 | end 520 | 521 | filterm_gen = function(fun, gen_x, param_x, state_x, ...) 522 | if state_x == nil then 523 | return nil 524 | end 525 | if fun(...) then 526 | return state_x, ... 527 | end 528 | return filterm_gen_shrink(fun, gen_x, param_x, state_x) 529 | end 530 | 531 | local filter_detect = function(fun, gen_x, param_x, state_x, ...) 532 | if select('#', ...) < 2 then 533 | return filter1_gen(fun, gen_x, param_x, state_x, ...) 534 | else 535 | return filterm_gen(fun, gen_x, param_x, state_x, ...) 536 | end 537 | end 538 | 539 | local filter_gen = function(param, state_x) 540 | local fun, gen_x, param_x = param[1], param[2], param[3] 541 | return filter_detect(fun, gen_x, param_x, gen_x(param_x, state_x)) 542 | end 543 | 544 | local filter = function(fun, gen, param, state) 545 | return wrap(filter_gen, {fun, gen, param}, state) 546 | end 547 | methods.filter = method1(filter) 548 | exports.filter = export1(filter) 549 | methods.remove_if = methods.filter 550 | exports.remove_if = exports.filter 551 | 552 | local grep = function(fun_or_regexp, gen, param, state) 553 | local fun = fun_or_regexp 554 | if type(fun_or_regexp) == "string" then 555 | fun = function(x) return string.find(x, fun_or_regexp) ~= nil end 556 | end 557 | return filter(fun, gen, param, state) 558 | end 559 | methods.grep = method1(grep) 560 | exports.grep = export1(grep) 561 | 562 | local partition = function(fun, gen, param, state) 563 | local neg_fun = function(...) 564 | return not fun(...) 565 | end 566 | return filter(fun, gen, param, state), 567 | filter(neg_fun, gen, param, state) 568 | end 569 | methods.partition = method1(partition) 570 | exports.partition = export1(partition) 571 | 572 | -------------------------------------------------------------------------------- 573 | -- Reducing 574 | -------------------------------------------------------------------------------- 575 | 576 | local foldl_call = function(fun, start, state, ...) 577 | if state == nil then 578 | return nil, start 579 | end 580 | return state, fun(start, ...) 581 | end 582 | 583 | local foldl = function(fun, start, gen_x, param_x, state_x) 584 | while true do 585 | state_x, start = foldl_call(fun, start, gen_x(param_x, state_x)) 586 | if state_x == nil then 587 | break; 588 | end 589 | end 590 | return start 591 | end 592 | methods.foldl = method2(foldl) 593 | exports.foldl = export2(foldl) 594 | methods.reduce = methods.foldl 595 | exports.reduce = exports.foldl 596 | 597 | local length = function(gen, param, state) 598 | if gen == ipairs or gen == string_gen then 599 | return #param 600 | end 601 | local len = 0 602 | repeat 603 | state = gen(param, state) 604 | len = len + 1 605 | until state == nil 606 | return len - 1 607 | end 608 | methods.length = method0(length) 609 | exports.length = export0(length) 610 | 611 | local is_null = function(gen, param, state) 612 | return gen(param, deepcopy(state)) == nil 613 | end 614 | methods.is_null = method0(is_null) 615 | exports.is_null = export0(is_null) 616 | 617 | local is_prefix_of = function(iter_x, iter_y) 618 | local gen_x, param_x, state_x = iter(iter_x) 619 | local gen_y, param_y, state_y = iter(iter_y) 620 | 621 | local r_x, r_y 622 | for i=1,10,1 do 623 | state_x, r_x = gen_x(param_x, state_x) 624 | state_y, r_y = gen_y(param_y, state_y) 625 | if state_x == nil then 626 | return true 627 | end 628 | if state_y == nil or r_x ~= r_y then 629 | return false 630 | end 631 | end 632 | end 633 | methods.is_prefix_of = is_prefix_of 634 | exports.is_prefix_of = is_prefix_of 635 | 636 | local all = function(fun, gen_x, param_x, state_x) 637 | local r 638 | repeat 639 | state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x)) 640 | until state_x == nil or not r 641 | return state_x == nil 642 | end 643 | methods.all = method1(all) 644 | exports.all = export1(all) 645 | methods.every = methods.all 646 | exports.every = exports.all 647 | 648 | local any = function(fun, gen_x, param_x, state_x) 649 | local r 650 | repeat 651 | state_x, r = call_if_not_empty(fun, gen_x(param_x, state_x)) 652 | until state_x == nil or r 653 | return not not r 654 | end 655 | methods.any = method1(any) 656 | exports.any = export1(any) 657 | methods.some = methods.any 658 | exports.some = exports.any 659 | 660 | local sum = function(gen, param, state) 661 | local s = 0 662 | local r = 0 663 | repeat 664 | s = s + r 665 | state, r = gen(param, state) 666 | until state == nil 667 | return s 668 | end 669 | methods.sum = method0(sum) 670 | exports.sum = export0(sum) 671 | 672 | local product = function(gen, param, state) 673 | local p = 1 674 | local r = 1 675 | repeat 676 | p = p * r 677 | state, r = gen(param, state) 678 | until state == nil 679 | return p 680 | end 681 | methods.product = method0(product) 682 | exports.product = export0(product) 683 | 684 | local min_cmp = function(m, n) 685 | if n < m then return n else return m end 686 | end 687 | 688 | local max_cmp = function(m, n) 689 | if n > m then return n else return m end 690 | end 691 | 692 | local min = function(gen, param, state) 693 | local state, m = gen(param, state) 694 | if state == nil then 695 | error("min: iterator is empty") 696 | end 697 | 698 | local cmp 699 | if type(m) == "number" then 700 | -- An optimization: use math.min for numbers 701 | cmp = math.min 702 | else 703 | cmp = min_cmp 704 | end 705 | 706 | for _, r in gen, param, state do 707 | m = cmp(m, r) 708 | end 709 | return m 710 | end 711 | methods.min = method0(min) 712 | exports.min = export0(min) 713 | methods.minimum = methods.min 714 | exports.minimum = exports.min 715 | 716 | local min_by = function(cmp, gen_x, param_x, state_x) 717 | local state_x, m = gen_x(param_x, state_x) 718 | if state_x == nil then 719 | error("min: iterator is empty") 720 | end 721 | 722 | for _, r in gen_x, param_x, state_x do 723 | m = cmp(m, r) 724 | end 725 | return m 726 | end 727 | methods.min_by = method1(min_by) 728 | exports.min_by = export1(min_by) 729 | methods.minimum_by = methods.min_by 730 | exports.minimum_by = exports.min_by 731 | 732 | local max = function(gen_x, param_x, state_x) 733 | local state_x, m = gen_x(param_x, state_x) 734 | if state_x == nil then 735 | error("max: iterator is empty") 736 | end 737 | 738 | local cmp 739 | if type(m) == "number" then 740 | -- An optimization: use math.max for numbers 741 | cmp = math.max 742 | else 743 | cmp = max_cmp 744 | end 745 | 746 | for _, r in gen_x, param_x, state_x do 747 | m = cmp(m, r) 748 | end 749 | return m 750 | end 751 | methods.max = method0(max) 752 | exports.max = export0(max) 753 | methods.maximum = methods.max 754 | exports.maximum = exports.max 755 | 756 | local max_by = function(cmp, gen_x, param_x, state_x) 757 | local state_x, m = gen_x(param_x, state_x) 758 | if state_x == nil then 759 | error("max: iterator is empty") 760 | end 761 | 762 | for _, r in gen_x, param_x, state_x do 763 | m = cmp(m, r) 764 | end 765 | return m 766 | end 767 | methods.max_by = method1(max_by) 768 | exports.max_by = export1(max_by) 769 | methods.maximum_by = methods.maximum_by 770 | exports.maximum_by = exports.maximum_by 771 | 772 | local totable = function(gen_x, param_x, state_x) 773 | local tab, key, val = {} 774 | while true do 775 | state_x, val = gen_x(param_x, state_x) 776 | if state_x == nil then 777 | break 778 | end 779 | table.insert(tab, val) 780 | end 781 | return tab 782 | end 783 | methods.totable = method0(totable) 784 | exports.totable = export0(totable) 785 | 786 | local tomap = function(gen_x, param_x, state_x) 787 | local tab, key, val = {} 788 | while true do 789 | state_x, key, val = gen_x(param_x, state_x) 790 | if state_x == nil then 791 | break 792 | end 793 | tab[key] = val 794 | end 795 | return tab 796 | end 797 | methods.tomap = method0(tomap) 798 | exports.tomap = export0(tomap) 799 | 800 | -------------------------------------------------------------------------------- 801 | -- Transformations 802 | -------------------------------------------------------------------------------- 803 | 804 | local map_gen = function(param, state) 805 | local gen_x, param_x, fun = param[1], param[2], param[3] 806 | return call_if_not_empty(fun, gen_x(param_x, state)) 807 | end 808 | 809 | local map = function(fun, gen, param, state) 810 | return wrap(map_gen, {gen, param, fun}, state) 811 | end 812 | methods.map = method1(map) 813 | exports.map = export1(map) 814 | 815 | local enumerate_gen_call = function(state, i, state_x, ...) 816 | if state_x == nil then 817 | return nil 818 | end 819 | return {i + 1, state_x}, i, ... 820 | end 821 | 822 | local enumerate_gen = function(param, state) 823 | local gen_x, param_x = param[1], param[2] 824 | local i, state_x = state[1], state[2] 825 | return enumerate_gen_call(state, i, gen_x(param_x, state_x)) 826 | end 827 | 828 | local enumerate = function(gen, param, state) 829 | return wrap(enumerate_gen, {gen, param}, {1, state}) 830 | end 831 | methods.enumerate = method0(enumerate) 832 | exports.enumerate = export0(enumerate) 833 | 834 | local intersperse_call = function(i, state_x, ...) 835 | if state_x == nil then 836 | return nil 837 | end 838 | return {i + 1, state_x}, ... 839 | end 840 | 841 | local intersperse_gen = function(param, state) 842 | local x, gen_x, param_x = param[1], param[2], param[3] 843 | local i, state_x = state[1], state[2] 844 | if i % 2 == 1 then 845 | return {i + 1, state_x}, x 846 | else 847 | return intersperse_call(i, gen_x(param_x, state_x)) 848 | end 849 | end 850 | 851 | -- TODO: interperse must not add x to the tail 852 | local intersperse = function(x, gen, param, state) 853 | return wrap(intersperse_gen, {x, gen, param}, {0, state}) 854 | end 855 | methods.intersperse = method1(intersperse) 856 | exports.intersperse = export1(intersperse) 857 | 858 | -------------------------------------------------------------------------------- 859 | -- Compositions 860 | -------------------------------------------------------------------------------- 861 | 862 | local function zip_gen_r(param, state, state_new, ...) 863 | if #state_new == #param / 2 then 864 | return state_new, ... 865 | end 866 | 867 | local i = #state_new + 1 868 | local gen_x, param_x = param[2 * i - 1], param[2 * i] 869 | local state_x, r = gen_x(param_x, state[i]) 870 | if state_x == nil then 871 | return nil 872 | end 873 | table.insert(state_new, state_x) 874 | return zip_gen_r(param, state, state_new, r, ...) 875 | end 876 | 877 | local zip_gen = function(param, state) 878 | return zip_gen_r(param, state, {}) 879 | end 880 | 881 | -- A special hack for zip/chain to skip last two state, if a wrapped iterator 882 | -- has been passed 883 | local numargs = function(...) 884 | local n = select('#', ...) 885 | if n >= 3 then 886 | -- Fix last argument 887 | local it = select(n - 2, ...) 888 | if type(it) == 'table' and getmetatable(it) == iterator_mt and 889 | it.param == select(n - 1, ...) and it.state == select(n, ...) then 890 | return n - 2 891 | end 892 | end 893 | return n 894 | end 895 | 896 | local zip = function(...) 897 | local n = numargs(...) 898 | if n == 0 then 899 | return wrap(nil_gen, nil, nil) 900 | end 901 | local param = { [2 * n] = 0 } 902 | local state = { [n] = 0 } 903 | 904 | local i, gen_x, param_x, state_x 905 | for i=1,n,1 do 906 | local it = select(n - i + 1, ...) 907 | gen_x, param_x, state_x = rawiter(it) 908 | param[2 * i - 1] = gen_x 909 | param[2 * i] = param_x 910 | state[i] = state_x 911 | end 912 | 913 | return wrap(zip_gen, param, state) 914 | end 915 | methods.zip = zip 916 | exports.zip = zip 917 | 918 | local cycle_gen_call = function(param, state_x, ...) 919 | if state_x == nil then 920 | local gen_x, param_x, state_x0 = param[1], param[2], param[3] 921 | return gen_x(param_x, deepcopy(state_x0)) 922 | end 923 | return state_x, ... 924 | end 925 | 926 | local cycle_gen = function(param, state_x) 927 | local gen_x, param_x, state_x0 = param[1], param[2], param[3] 928 | return cycle_gen_call(param, gen_x(param_x, state_x)) 929 | end 930 | 931 | local cycle = function(gen, param, state) 932 | return wrap(cycle_gen, {gen, param, state}, deepcopy(state)) 933 | end 934 | methods.cycle = method0(cycle) 935 | exports.cycle = export0(cycle) 936 | 937 | -- call each other 938 | local chain_gen_r1 939 | local chain_gen_r2 = function(param, state, state_x, ...) 940 | if state_x == nil then 941 | local i = state[1] 942 | i = i + 1 943 | if i > #param / 3 then 944 | return nil 945 | end 946 | local state_x = param[3 * i] 947 | return chain_gen_r1(param, {i, state_x}) 948 | end 949 | return {state[1], state_x}, ... 950 | end 951 | 952 | chain_gen_r1 = function(param, state) 953 | local i, state_x = state[1], state[2] 954 | local gen_x, param_x = param[3 * i - 2], param[3 * i - 1] 955 | return chain_gen_r2(param, state, gen_x(param_x, state[2])) 956 | end 957 | 958 | local chain = function(...) 959 | local n = numargs(...) 960 | if n == 0 then 961 | return wrap(nil_gen, nil, nil) 962 | end 963 | 964 | local param = { [3 * n] = 0 } 965 | local i, gen_x, param_x, state_x 966 | for i=1,n,1 do 967 | local elem = select(i, ...) 968 | gen_x, param_x, state_x = iter(elem) 969 | param[3 * i - 2] = gen_x 970 | param[3 * i - 1] = param_x 971 | param[3 * i] = state_x 972 | end 973 | 974 | return wrap(chain_gen_r1, param, {1, param[3]}) 975 | end 976 | methods.chain = chain 977 | exports.chain = chain 978 | 979 | -------------------------------------------------------------------------------- 980 | -- Operators 981 | -------------------------------------------------------------------------------- 982 | 983 | operator = { 984 | ---------------------------------------------------------------------------- 985 | -- Comparison operators 986 | ---------------------------------------------------------------------------- 987 | lt = function(a, b) return a < b end, 988 | le = function(a, b) return a <= b end, 989 | eq = function(a, b) return a == b end, 990 | ne = function(a, b) return a ~= b end, 991 | ge = function(a, b) return a >= b end, 992 | gt = function(a, b) return a > b end, 993 | 994 | ---------------------------------------------------------------------------- 995 | -- Arithmetic operators 996 | ---------------------------------------------------------------------------- 997 | add = function(a, b) return a + b end, 998 | div = function(a, b) return a / b end, 999 | floordiv = function(a, b) return math.floor(a/b) end, 1000 | intdiv = function(a, b) 1001 | local q = a / b 1002 | if a >= 0 then return math.floor(q) else return math.ceil(q) end 1003 | end, 1004 | mod = function(a, b) return a % b end, 1005 | mul = function(a, b) return a * b end, 1006 | neq = function(a) return -a end, 1007 | unm = function(a) return -a end, -- an alias 1008 | pow = function(a, b) return a ^ b end, 1009 | sub = function(a, b) return a - b end, 1010 | truediv = function(a, b) return a / b end, 1011 | 1012 | ---------------------------------------------------------------------------- 1013 | -- String operators 1014 | ---------------------------------------------------------------------------- 1015 | concat = function(a, b) return a..b end, 1016 | len = function(a) return #a end, 1017 | length = function(a) return #a end, -- an alias 1018 | 1019 | ---------------------------------------------------------------------------- 1020 | -- Logical operators 1021 | ---------------------------------------------------------------------------- 1022 | land = function(a, b) return a and b end, 1023 | lor = function(a, b) return a or b end, 1024 | lnot = function(a) return not a end, 1025 | truth = function(a) return not not a end, 1026 | } 1027 | exports.operator = operator 1028 | methods.operator = operator 1029 | exports.op = operator 1030 | methods.op = operator 1031 | 1032 | -------------------------------------------------------------------------------- 1033 | -- module definitions 1034 | -------------------------------------------------------------------------------- 1035 | 1036 | -- a special syntax sugar to export all functions to the global table 1037 | setmetatable(exports, { 1038 | __call = function(t) 1039 | for k, v in pairs(t) do _G[k] = v end 1040 | end, 1041 | }) 1042 | 1043 | return exports 1044 | -------------------------------------------------------------------------------- /lj2procfs/libc.lua: -------------------------------------------------------------------------------- 1 | local ffi = require("ffi") 2 | 3 | -- These types are platform specific 4 | -- and should be taylored to match 5 | ffi.cdef[[ 6 | typedef long time_t; 7 | typedef long suseconds_t; 8 | ]] 9 | 10 | if ffi.abi("64bit") then 11 | ffi.cdef[[ 12 | typedef int64_t off_t; 13 | typedef int64_t ino_t; 14 | ]] 15 | else 16 | ffi.cdef[[ 17 | typedef int off_t; 18 | typedef int ino_t; 19 | ]] 20 | end 21 | 22 | -- These should be good for all versions of Linux 23 | ffi.cdef[[ 24 | typedef unsigned int mode_t; 25 | typedef unsigned int nlink_t; 26 | typedef uint64_t dev_t; 27 | typedef long blksize_t; 28 | typedef int64_t blkcnt_t; 29 | typedef uint64_t fsblkcnt_t; 30 | typedef uint64_t fsfilcnt_t; 31 | 32 | typedef unsigned int wint_t; 33 | typedef unsigned long wctype_t; 34 | 35 | typedef void * timer_t; 36 | typedef int clockid_t; 37 | typedef long clock_t; 38 | 39 | struct timeval { time_t tv_sec; suseconds_t tv_usec; }; 40 | struct timespec { time_t tv_sec; long tv_nsec; }; 41 | ]] 42 | 43 | ffi.cdef[[ 44 | typedef int pid_t; 45 | typedef unsigned int id_t; 46 | typedef unsigned int uid_t; 47 | typedef unsigned int gid_t; 48 | typedef int key_t; 49 | typedef unsigned int useconds_t; 50 | ]] 51 | 52 | ffi.cdef[[ 53 | typedef struct _IO_FILE FILE; 54 | ]] 55 | 56 | 57 | ffi.cdef[[ 58 | typedef int32_t __pid_t; 59 | typedef uint32_t __uid_t; 60 | typedef long __clock_t; 61 | typedef int32_t __clockid_t; 62 | typedef int32_t __gid_t; 63 | ]] 64 | 65 | 66 | 67 | -- dirent.h 68 | ffi.cdef[[ 69 | typedef off_t off64_t; 70 | typedef ino_t ino64_t; 71 | ]] 72 | 73 | ffi.cdef[[ 74 | enum { 75 | DT_UNKNOWN = 0, 76 | DT_FIFO = 1, 77 | DT_CHR = 2, 78 | DT_DIR = 4, 79 | DT_BLK = 6, 80 | DT_REG = 8, 81 | DT_LNK = 10, 82 | DT_SOCK = 12, 83 | DT_WHT = 14 84 | }; 85 | ]] 86 | 87 | ffi.cdef[[ 88 | typedef struct __dirstream DIR; 89 | 90 | struct dirent 91 | { 92 | ino_t d_ino; 93 | off_t d_off; 94 | unsigned short d_reclen; 95 | unsigned char d_type; 96 | char d_name[256]; 97 | }; 98 | ]] 99 | 100 | -- fcntl.h 101 | ffi.cdef[[ 102 | int open(const char *, int, ...); 103 | ]] 104 | 105 | ffi.cdef[[ 106 | static const int O_ACCMODE = 00000003; 107 | static const int O_RDONLY = 00000000; 108 | static const int O_WRONLY = 00000001; 109 | static const int O_RDWR = 00000002; 110 | ]] 111 | 112 | -- unistd.h 113 | local function hasSSizeT() 114 | local def = pcall(function() return ffi.typeof("ssize_t") end) 115 | return def 116 | end 117 | 118 | if not hasSSizeT() then 119 | 120 | ffi.cdef[[ 121 | typedef size_t ssize_t; 122 | ]] 123 | end 124 | 125 | ffi.cdef[[ 126 | int close(int); 127 | ssize_t read(int, void *, size_t); 128 | ssize_t write(int, const void *, size_t); 129 | ]] 130 | 131 | ffi.cdef[[ 132 | int closedir(DIR *); 133 | DIR *opendir(const char *); 134 | struct dirent *readdir(DIR *); 135 | int readdir_r(DIR *__restrict, struct dirent *__restrict, struct dirent **__restrict); 136 | 137 | ssize_t readlink(const char *__restrict, char *__restrict, size_t); 138 | 139 | ]] 140 | 141 | ffi.cdef[[ 142 | char *strchr (const char *, int); 143 | ]] 144 | 145 | 146 | 147 | local exports = {} 148 | setmetatable(exports, { 149 | __index = function(self, key) 150 | local value = nil; 151 | local success = false; 152 | 153 | 154 | -- try looking in the ffi.C namespace, for constants 155 | -- and enums 156 | success, value = pcall(function() return ffi.C[key] end) 157 | --print("looking for constant/enum: ", key, success, value) 158 | if success then 159 | rawset(self, key, value); 160 | return value; 161 | end 162 | 163 | -- Or maybe it's a type 164 | success, value = pcall(function() return ffi.typeof(key) end) 165 | if success then 166 | rawset(self, key, value); 167 | return value; 168 | end 169 | 170 | return nil; 171 | end, 172 | }) 173 | 174 | return exports 175 | -------------------------------------------------------------------------------- /lj2procfs/print-util.lua: -------------------------------------------------------------------------------- 1 | local function literalForValue(avalue) 2 | if type(avalue) == "number" or type(avalue) == "boolean" then 3 | return tostring(avalue) 4 | end 5 | 6 | local str = tostring(avalue) 7 | if str == "" then 8 | return "''" 9 | end 10 | 11 | return string.format("[[%s]]", str) 12 | end 13 | 14 | local function printValue(avalue, indent, name) 15 | if not avalue then return end; 16 | 17 | indent = indent or "" 18 | 19 | 20 | if type(avalue) == "table" then 21 | if name then 22 | print(string.format("%s['%s'] = {", indent, name)) 23 | else 24 | print(string.format("%s{", indent)) 25 | end 26 | 27 | if #avalue > 0 then 28 | -- it's a list,so use ipairs 29 | for _, value in ipairs(avalue) do 30 | printValue(value, indent..' ') 31 | end 32 | else 33 | -- assume it's a dictionary, so use pairs 34 | for key, value in pairs(avalue) do 35 | printValue(value, indent..' ', key) 36 | end 37 | end 38 | print(string.format("%s};", indent)) 39 | else 40 | if name then 41 | print(string.format("%s['%s'] = %s,", indent, name, literalForValue(avalue))) 42 | else 43 | print(string.format("%s%s,", indent, literalForValue(avalue))) 44 | end 45 | end 46 | 47 | end 48 | 49 | return { 50 | printValue = printValue; 51 | } -------------------------------------------------------------------------------- /lj2procfs/procfs.lua: -------------------------------------------------------------------------------- 1 | --procfs.lua 2 | local fs = require("lj2procfs.fs-util") 3 | local libc = require("lj2procfs.libc") 4 | local fun = require("lj2procfs.fun") 5 | local ProcessEntry = require("lj2procfs.ProcessEntry") 6 | 7 | 8 | -- take a table with a 'Name' field, which 9 | -- should be a numeric value, and return the 10 | -- ProcessEntry for it 11 | local function toProcessEntry(entry) 12 | return ProcessEntry(tonumber(entry.Name)) 13 | end 14 | 15 | local function getRawFile(path) 16 | local f = io.open(path) 17 | local str = f:read("*a") 18 | f:close() 19 | 20 | return str; 21 | end 22 | 23 | local function findDecoder(key) 24 | 25 | local path = "lj2procfs.codecs."..key; 26 | --print("findDecoder(), PATH: ", path) 27 | 28 | -- try to load the intended codec file 29 | local success, codec = pcall(function() return require(path) end) 30 | if success and codec.decoder then 31 | return codec.decoder; 32 | end 33 | 34 | return nil; 35 | end 36 | 37 | local procfs = {} 38 | 39 | 40 | setmetatable(procfs, { 41 | __index = function(self, key) 42 | 43 | -- if key is numeric, then return 44 | -- a process entry 45 | if type(key) == "number" or tonumber(key) then 46 | return ProcessEntry(tonumber(key)) 47 | end 48 | 49 | 50 | -- Finally, assume the key is a path to one 51 | -- of the files within the /proc hierarchy 52 | local path = "/proc/"..key 53 | --print("procfs.__index: ", key, path) 54 | local decoder = findDecoder(key) 55 | 56 | if decoder then 57 | return decoder(path) 58 | else 59 | return "NO DECODER AVAILABLE FOR: "..path 60 | -- return getRawFile(path) 61 | end 62 | end, 63 | }) 64 | 65 | 66 | function procfs.processes() 67 | -- map directories with numeric names to ProcessEntry 68 | return fun.map(toProcessEntry, fun.filter( 69 | function(entry) 70 | return (entry.Kind == libc.DT_DIR) and tonumber(entry.Name) 71 | end, 72 | fs.entries_in_directory("/proc"))) 73 | end 74 | 75 | 76 | return procfs -------------------------------------------------------------------------------- /lj2procfs/string-util.lua: -------------------------------------------------------------------------------- 1 | --string-util.lua 2 | local ffi = require("ffi") 3 | local fun = require("lj2procfs.fun") 4 | 5 | local floor = math.floor; 6 | 7 | 8 | local F = {} 9 | 10 | function F.startswith(s, prefix) 11 | return string.find(s, prefix, 1, true) == 1 12 | end 13 | 14 | -- returns true if string 's' ends with string 'send' 15 | function F.endswith(s, send) 16 | return #s >= #send and string.find(s, send, #s-#send+1, true) and true or false 17 | end 18 | 19 | 20 | 21 | local function gsplit(s,sep) 22 | --print('gsplit: ', #sep, string.byte(sep[0])) 23 | return coroutine.wrap(function() 24 | if s == '' or sep == '' then coroutine.yield(s) return end 25 | local lasti = 1 26 | for v,i in s:gmatch('(.-)'..sep..'()') do 27 | coroutine.yield(v) 28 | lasti = i 29 | end 30 | coroutine.yield(s:sub(lasti)) 31 | end) 32 | end 33 | 34 | local function iunpack(i,s,v1) 35 | local function pass(...) 36 | local v1 = i(s,v1) 37 | if v1 == nil then return ... end 38 | return v1, pass(...) 39 | end 40 | return pass() 41 | end 42 | 43 | function F.split(s,sep) 44 | return iunpack(gsplit(s,sep)) 45 | end 46 | 47 | local function accumulate(t,i,s,v) 48 | for v in i,s,v do 49 | t[#t+1] = v 50 | end 51 | return t 52 | end 53 | 54 | function F.tsplit(s,sep) 55 | return accumulate({}, gsplit(s,sep)) 56 | end 57 | 58 | function F.tsplitbool(s, sep) 59 | local tbl={} 60 | for v in gsplit(s,sep) do 61 | tbl[v] = true; 62 | end 63 | return tbl 64 | end 65 | 66 | function F.trim(s) 67 | local from = s:match"^%s*()" 68 | return from > #s and "" or s:match(".*%S", from) 69 | end 70 | 71 | 72 | -- a nil generator. 73 | -- good for cases when there's no data 74 | local function nil_gen(param, state) 75 | return nil 76 | end 77 | 78 | local function delim_gen(param, idx) 79 | local len = 0; 80 | 81 | while ((idx+len) < param.nelems) do 82 | --print("wchar: ", string.char(ffi.cast(param.basetypeptr, param.data)[idx + len])) 83 | if ffi.cast(param.basetypeptr, param.data)[idx + len] ~= param.separator then 84 | len = len + 1; 85 | else 86 | break 87 | end 88 | end 89 | 90 | if len == 0 then 91 | return nil; 92 | end 93 | 94 | return idx + len + 1, ffi.cast(param.basetypeptr, param.data)+idx, len 95 | end 96 | 97 | 98 | local function array_gen(param, idx) 99 | if idx >= param.nelems then 100 | return nil; 101 | end 102 | 103 | return idx+1, ffi.cast(param.basetypeptr, param.data)+idx, 1 104 | end 105 | 106 | 107 | function F.striter(params) 108 | if not params then 109 | return nil_gen, params, nil 110 | end 111 | 112 | if not params.data then 113 | return nil_gen, params, nil 114 | end 115 | 116 | params.datalength = params.datalength or #params.data 117 | if params.basetype then 118 | if type(params.basetype)== "string" then 119 | params.basetype = ffi.typeof(params.basetype) 120 | end 121 | end 122 | params.basetype = params.basetype or ffi.typeof("char") 123 | params.basetypeptr = ffi.typeof("const $ *", params.basetype) 124 | params.basetypesize = ffi.sizeof(params.basetype) 125 | params.nelems = math.floor(params.datalength / params.basetypesize) 126 | 127 | if params.separator ~= nil then 128 | return delim_gen, params, 0 129 | else 130 | return array_gen, params, 0 131 | end 132 | 133 | return nil_gen, nil, nil 134 | end 135 | 136 | function F.mstriter(data, separator, datalength) 137 | return fun.map(function(ptr,len) return ffi.string(ptr, len) end, 138 | striter({data = data, datalength = datalength, separator=separator, basetype="char"})) 139 | end 140 | 141 | -- an iterator over a string, with embedded 142 | -- '\0' bytes delimiting strings 143 | function F.mstrziter(data, datalength) 144 | datalength = datalength or #data 145 | 146 | return fun.map(function(ptr,len) return ffi.string(ptr, len) end, 147 | striter({data = data, datalength = datalength, separator=0, basetype="char"})) 148 | end 149 | 150 | -- given a unicode string which contains 151 | -- null terminated strings 152 | -- return individual ansi strings 153 | function F.wmstrziter(data, datalength) 154 | 155 | local maxLen = 255; 156 | local idx = -1; 157 | 158 | local nameBuff = ffi.new("char[256]") 159 | 160 | local function closure() 161 | idx = idx + 1; 162 | local len = 0; 163 | 164 | while len < maxLen do 165 | print("char: ", string.char(lpBuffer[idx])) 166 | if data[idx] == 0 then 167 | break 168 | end 169 | 170 | nameBuff[len] = data[idx]; 171 | len = len + 1; 172 | idx = idx + 1; 173 | end 174 | 175 | if len == 0 then 176 | return nil; 177 | end 178 | 179 | return ffi.string(nameBuff, len); 180 | end 181 | 182 | return closure; 183 | end 184 | 185 | return F 186 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-1.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-2" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-2.tar.gz", 5 | dir = "lj2procfs-0.1-2", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | This module gives you ready access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.dirent-util"] = "lj2procfs/dirent-util.lua", 29 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 30 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 31 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 32 | ["lj2procfs.path-util"] = "lj2procfs/path-util.lua", 33 | ["lj2procfs.platform"] = "lj2procfs/platform.lua", 34 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 35 | ["lj2procfs.siginfo"] = "lj2procfs/signifo.lua", 36 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 37 | ["lj2procfs.striter"] = "lj2procfs/striter.lua", 38 | 39 | -- The guts 40 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 41 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 42 | 43 | -- codecs for flat files in /proc 44 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 45 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 46 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 47 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 48 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 49 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 50 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 51 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 52 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 53 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 54 | ["lj2procfs.codecs.linkchaser"] = "lj2procfs/codecs/linkshaser.lua", 55 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 56 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 57 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 58 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 59 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 60 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 61 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 62 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 63 | 64 | -- codecs for flat files in /proc/process 65 | ["lj2procfs.codecs.environ"] = "lj2procfs/codecs/process/environ.lua", 66 | ["lj2procfs.codecs.exe"] = "lj2procfs/codecs/process/exe.lua", 67 | ["lj2procfs.codecs.io"] = "lj2procfs/codecs/process/io.lua", 68 | ["lj2procfs.codecs.limits"] = "lj2procfs/codecs/process/limits.lua", 69 | ["lj2procfs.codecs.maps"] = "lj2procfs/codecs/process/maps.lua", 70 | ["lj2procfs.codecs.mounts"] = "lj2procfs/codecs/process/mounts.lua", 71 | ["lj2procfs.codecs.sched"] = "lj2procfs/codecs/process/sched.lua", 72 | ["lj2procfs.codecs.status"] = "lj2procfs/codecs/process/status.lua", 73 | 74 | -- codecs for flat files in /proc/net 75 | ["lj2procfs.codecs.dev"] = "lj2procfs/codecs/net/dev.lua", 76 | ["lj2procfs.codecs.netstat"] = "lj2procfs/codecs/net/netstat.lua", 77 | 78 | }, 79 | } 80 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-2.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-2" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-2.tar.gz", 5 | dir = "lj2procfs-0.1-2", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | This module gives you ready access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.dirent-util"] = "lj2procfs/dirent-util.lua", 29 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 30 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 31 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 32 | ["lj2procfs.path-util"] = "lj2procfs/path-util.lua", 33 | ["lj2procfs.platform"] = "lj2procfs/platform.lua", 34 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 35 | ["lj2procfs.siginfo"] = "lj2procfs/signifo.lua", 36 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 37 | ["lj2procfs.striter"] = "lj2procfs/striter.lua", 38 | 39 | -- The guts 40 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 41 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 42 | 43 | -- codecs for flat files in /proc 44 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 45 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 46 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 47 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 48 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 49 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 50 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 51 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 52 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 53 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 54 | ["lj2procfs.codecs.linkchaser"] = "lj2procfs/codecs/linkchaser.lua", 55 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 56 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 57 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 58 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 59 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 60 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 61 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 62 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 63 | 64 | -- codecs for flat files in /proc/process 65 | ["lj2procfs.codecs.environ"] = "lj2procfs/codecs/process/environ.lua", 66 | ["lj2procfs.codecs.exe"] = "lj2procfs/codecs/process/exe.lua", 67 | ["lj2procfs.codecs.io"] = "lj2procfs/codecs/process/io.lua", 68 | ["lj2procfs.codecs.limits"] = "lj2procfs/codecs/process/limits.lua", 69 | ["lj2procfs.codecs.maps"] = "lj2procfs/codecs/process/maps.lua", 70 | ["lj2procfs.codecs.mounts"] = "lj2procfs/codecs/process/mounts.lua", 71 | ["lj2procfs.codecs.sched"] = "lj2procfs/codecs/process/sched.lua", 72 | ["lj2procfs.codecs.status"] = "lj2procfs/codecs/process/status.lua", 73 | 74 | -- codecs for flat files in /proc/net 75 | ["lj2procfs.codecs.dev"] = "lj2procfs/codecs/net/dev.lua", 76 | ["lj2procfs.codecs.netstat"] = "lj2procfs/codecs/net/netstat.lua", 77 | 78 | }, 79 | } 80 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-3.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-3" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-3.tar.gz", 5 | dir = "lj2procfs-0.1-3", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | This module gives you ready access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.dirent-util"] = "lj2procfs/dirent-util.lua", 29 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 30 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 31 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 32 | ["lj2procfs.path-util"] = "lj2procfs/path-util.lua", 33 | ["lj2procfs.platform"] = "lj2procfs/platform.lua", 34 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 35 | ["lj2procfs.siginfo"] = "lj2procfs/siginfo.lua", 36 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 37 | ["lj2procfs.striter"] = "lj2procfs/striter.lua", 38 | 39 | -- The guts 40 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 41 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 42 | ["lj2procfs.procfs"] = "lj2procfs/procfs.lua", 43 | 44 | -- codecs for flat files in /proc 45 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 46 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 47 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 48 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 49 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 50 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 51 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 52 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 53 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 54 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 55 | ["lj2procfs.codecs.linkchaser"] = "lj2procfs/codecs/linkchaser.lua", 56 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 57 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 58 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 59 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 60 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 61 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 62 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 63 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 64 | 65 | -- codecs for flat files in /proc/process 66 | ["lj2procfs.codecs.process.environ"] = "lj2procfs/codecs/process/environ.lua", 67 | ["lj2procfs.codecs.process.exe"] = "lj2procfs/codecs/process/exe.lua", 68 | ["lj2procfs.codecs.process.io"] = "lj2procfs/codecs/process/io.lua", 69 | ["lj2procfs.codecs.process.limits"] = "lj2procfs/codecs/process/limits.lua", 70 | ["lj2procfs.codecs.process.maps"] = "lj2procfs/codecs/process/maps.lua", 71 | ["lj2procfs.codecs.process.mounts"] = "lj2procfs/codecs/process/mounts.lua", 72 | ["lj2procfs.codecs.process.sched"] = "lj2procfs/codecs/process/sched.lua", 73 | ["lj2procfs.codecs.process.status"] = "lj2procfs/codecs/process/status.lua", 74 | 75 | -- codecs for flat files in /proc/net 76 | ["lj2procfs.codecs.net.dev"] = "lj2procfs/codecs/net/dev.lua", 77 | ["lj2procfs.codecs.net.netstat"] = "lj2procfs/codecs/net/netstat.lua", 78 | 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-4.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-4" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-4.tar.gz", 5 | dir = "lj2procfs-0.1-4", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | This module gives you ready access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.dirent-util"] = "lj2procfs/dirent-util.lua", 29 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 30 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 31 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 32 | ["lj2procfs.path-util"] = "lj2procfs/path-util.lua", 33 | ["lj2procfs.platform"] = "lj2procfs/platform.lua", 34 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 35 | ["lj2procfs.siginfo"] = "lj2procfs/siginfo.lua", 36 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 37 | ["lj2procfs.striter"] = "lj2procfs/striter.lua", 38 | 39 | -- The guts 40 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 41 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 42 | ["lj2procfs.procfs"] = "lj2procfs/procfs.lua", 43 | 44 | -- codecs for flat files in /proc 45 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 46 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 47 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 48 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 49 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 50 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 51 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 52 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 53 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 54 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 55 | ["lj2procfs.codecs.linkchaser"] = "lj2procfs/codecs/linkchaser.lua", 56 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 57 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 58 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 59 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 60 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 61 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 62 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 63 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 64 | 65 | -- codecs for flat files in /proc/process 66 | ["lj2procfs.codecs.process.environ"] = "lj2procfs/codecs/process/environ.lua", 67 | ["lj2procfs.codecs.process.exe"] = "lj2procfs/codecs/process/exe.lua", 68 | ["lj2procfs.codecs.process.io"] = "lj2procfs/codecs/process/io.lua", 69 | ["lj2procfs.codecs.process.limits"] = "lj2procfs/codecs/process/limits.lua", 70 | ["lj2procfs.codecs.process.maps"] = "lj2procfs/codecs/process/maps.lua", 71 | ["lj2procfs.codecs.process.mounts"] = "lj2procfs/codecs/process/mounts.lua", 72 | ["lj2procfs.codecs.process.sched"] = "lj2procfs/codecs/process/sched.lua", 73 | ["lj2procfs.codecs.process.status"] = "lj2procfs/codecs/process/status.lua", 74 | 75 | -- codecs for flat files in /proc/net 76 | ["lj2procfs.codecs.net.dev"] = "lj2procfs/codecs/net/dev.lua", 77 | ["lj2procfs.codecs.net.netstat"] = "lj2procfs/codecs/net/netstat.lua", 78 | 79 | }, 80 | } 81 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-5.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-5" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-5.tar.gz", 5 | dir = "lj2procfs-0.1-5", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | This module gives you ready access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 29 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 30 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 31 | ["lj2procfs.platform"] = "lj2procfs/platform.lua", 32 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 33 | ["lj2procfs.siginfo"] = "lj2procfs/siginfo.lua", 34 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 35 | ["lj2procfs.striter"] = "lj2procfs/striter.lua", 36 | 37 | -- The guts 38 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 39 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 40 | ["lj2procfs.procfs"] = "lj2procfs/procfs.lua", 41 | 42 | -- codecs for flat files in /proc 43 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 44 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 45 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 46 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 47 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 48 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 49 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 50 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 51 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 52 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 53 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 54 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 55 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 56 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 57 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 58 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 59 | ["lj2procfs.codecs.sys"] = "lj2procfs/codecs/sys.lua", 60 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 61 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 62 | 63 | -- codecs for flat files in /proc/process 64 | ["lj2procfs.codecs.process.environ"] = "lj2procfs/codecs/process/environ.lua", 65 | ["lj2procfs.codecs.process.exe"] = "lj2procfs/codecs/process/exe.lua", 66 | ["lj2procfs.codecs.process.io"] = "lj2procfs/codecs/process/io.lua", 67 | ["lj2procfs.codecs.process.limits"] = "lj2procfs/codecs/process/limits.lua", 68 | ["lj2procfs.codecs.process.maps"] = "lj2procfs/codecs/process/maps.lua", 69 | ["lj2procfs.codecs.process.mounts"] = "lj2procfs/codecs/process/mounts.lua", 70 | ["lj2procfs.codecs.process.sched"] = "lj2procfs/codecs/process/sched.lua", 71 | ["lj2procfs.codecs.process.status"] = "lj2procfs/codecs/process/status.lua", 72 | 73 | -- codecs for flat files in /proc/net 74 | ["lj2procfs.codecs.net.dev"] = "lj2procfs/codecs/net/dev.lua", 75 | ["lj2procfs.codecs.net.netstat"] = "lj2procfs/codecs/net/netstat.lua", 76 | 77 | }, 78 | } 79 | -------------------------------------------------------------------------------- /rockspec/lj2procfs-0.1-6.rockspec: -------------------------------------------------------------------------------- 1 | package = "lj2procfs" 2 | version = "0.1-6" 3 | source = { 4 | url = "https://github.com/wiladams/lj2procfs/archive/v0.1-6.tar.gz", 5 | dir = "lj2procfs-0.1-6", 6 | } 7 | description = { 8 | summary = "LuaJIT access to the Linux procfs", 9 | detailed = [[ 10 | LuaJIT based access to the procfs file system on Linux. 11 | This is for Linux ONLY! 12 | ]], 13 | homepage = "http://github.com/wiladams/lj2procfs", 14 | license = "MIT/X11" 15 | } 16 | 17 | supported_platforms = {"linux"} 18 | 19 | dependencies = { 20 | "lua ~> 5.1" 21 | } 22 | 23 | build = { 24 | type = "builtin", 25 | 26 | modules = { 27 | -- general programming goodness 28 | ["lj2procfs.fs-util"] = "lj2procfs/fs-util.lua", 29 | ["lj2procfs.fun"] = "lj2procfs/fun.lua", 30 | ["lj2procfs.libc"] = "lj2procfs/libc.lua", 31 | ["lj2procfs.print-util"] = "lj2procfs/print-util.lua", 32 | ["lj2procfs.string-util"] = "lj2procfs/string-util.lua", 33 | 34 | -- The guts 35 | ["lj2procfs.Decoders"] = "lj2procfs/Decoders.lua", 36 | ["lj2procfs.ProcessEntry"] = "lj2procfs/ProcessEntry.lua", 37 | ["lj2procfs.procfs"] = "lj2procfs/procfs.lua", 38 | 39 | -- codecs for flat files in /proc 40 | ["lj2procfs.codecs.buddyinfo"] = "lj2procfs/codecs/buddyinfo.lua", 41 | ["lj2procfs.codecs.cgroups"] = "lj2procfs/codecs/cgroups.lua", 42 | ["lj2procfs.codecs.cmdline"] = "lj2procfs/codecs/cmdline.lua", 43 | ["lj2procfs.codecs.cpuinfo"] = "lj2procfs/codecs/cpuinfo.lua", 44 | ["lj2procfs.codecs.crypto"] = "lj2procfs/codecs/crypto.lua", 45 | ["lj2procfs.codecs.devices"] = "lj2procfs/codecs/devices.lua", 46 | ["lj2procfs.codecs.diskstats"] = "lj2procfs/codecs/diskstats.lua", 47 | ["lj2procfs.codecs.interrupts"] = "lj2procfs/codecs/interrupts.lua", 48 | ["lj2procfs.codecs.iomem"] = "lj2procfs/codecs/iomem.lua", 49 | ["lj2procfs.codecs.ioports"] = "lj2procfs/codecs/ioports.lua", 50 | ["lj2procfs.codecs.kallsyms"] = "lj2procfs/codecs/kallsyms.lua", 51 | ["lj2procfs.codecs.loadavg"] = "lj2procfs/codecs/loadavg.lua", 52 | ["lj2procfs.codecs.meminfo"] = "lj2procfs/codecs/meminfo.lua", 53 | ["lj2procfs.codecs.modules"] = "lj2procfs/codecs/modules.lua", 54 | ["lj2procfs.codecs.net"] = "lj2procfs/codecs/net.lua", 55 | ["lj2procfs.codecs.partitions"] = "lj2procfs/codecs/partitions.lua", 56 | ["lj2procfs.codecs.softirqs"] = "lj2procfs/codecs/softirqs.lua", 57 | ["lj2procfs.codecs.stat"] = "lj2procfs/codecs/stat.lua", 58 | ["lj2procfs.codecs.sys"] = "lj2procfs/codecs/sys.lua", 59 | ["lj2procfs.codecs.uptime"] = "lj2procfs/codecs/uptime.lua", 60 | ["lj2procfs.codecs.vmstat"] = "lj2procfs/codecs/vmstat.lua", 61 | 62 | -- codecs for flat files in /proc/[PID] 63 | ["lj2procfs.codecs.process.environ"] = "lj2procfs/codecs/process/environ.lua", 64 | ["lj2procfs.codecs.process.exe"] = "lj2procfs/codecs/process/exe.lua", 65 | ["lj2procfs.codecs.process.io"] = "lj2procfs/codecs/process/io.lua", 66 | ["lj2procfs.codecs.process.limits"] = "lj2procfs/codecs/process/limits.lua", 67 | ["lj2procfs.codecs.process.maps"] = "lj2procfs/codecs/process/maps.lua", 68 | ["lj2procfs.codecs.process.mounts"] = "lj2procfs/codecs/process/mounts.lua", 69 | ["lj2procfs.codecs.process.sched"] = "lj2procfs/codecs/process/sched.lua", 70 | ["lj2procfs.codecs.process.status"] = "lj2procfs/codecs/process/status.lua", 71 | 72 | -- codecs for flat files in /proc/net 73 | ["lj2procfs.codecs.net.dev"] = "lj2procfs/codecs/net/dev.lua", 74 | ["lj2procfs.codecs.net.netstat"] = "lj2procfs/codecs/net/netstat.lua", 75 | 76 | }, 77 | } 78 | -------------------------------------------------------------------------------- /testy/auxvinfo.lua: -------------------------------------------------------------------------------- 1 | package.path = "../?.lua" 2 | 3 | assert(arg[1]) 4 | 5 | local putil = require("lj2procfs.print-util") 6 | local auxv = require("lj2procfs.codecs.process.auxv") 7 | 8 | local path = "/proc/"..arg[1].."/auxv" 9 | local tbl = auxv.decoder(path) 10 | 11 | putil.printValue(tbl) -------------------------------------------------------------------------------- /testy/coreinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --ltflcpuinfo 4 | -- Print out the /proc/cpuinfo as an interpreted table 5 | -- The text output is valid lua, so it could be transmitted 6 | -- and reconstituted fairly easily. 7 | 8 | -- This is also a demonstration of using procfs index values 9 | -- and retrieving the lua equivalent table for a value 10 | 11 | package.path = "../?.lua;"..package.path; 12 | 13 | local procfs = require("lj2procfs.procfs") 14 | local fun = require("lj2procfs.fun") 15 | 16 | 17 | local function printInfo(processor) 18 | print(string.format("processor: %d, core: %s", processor.processor, tostring(processor.core_id))) 19 | end 20 | 21 | fun.each(printInfo, procfs.cpuinfo) 22 | -------------------------------------------------------------------------------- /testy/countprocs.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local procfs = require("lj2procfs.procfs") 5 | local fun = require("lj2procfs.fun") 6 | 7 | print("Num Procs: ", fun.length(procfs.processes())) 8 | -------------------------------------------------------------------------------- /testy/cryptocount.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local fun = require("lj2procfs.fun") 5 | local procfs = require("lj2procfs.procfs") 6 | 7 | local crypts = procfs.crypto 8 | 9 | 10 | 11 | local function printEach(name, tbl) 12 | print(string.format("%20s %s", name, tbl.type)) 13 | end 14 | 15 | 16 | local function printRNGs() 17 | local function isRng(name, tbl) 18 | return tbl.type == "rng" 19 | end 20 | 21 | print("== RNGs ==") 22 | fun.each(printEach, fun.filter(isRng, crypts)) 23 | end 24 | 25 | local function printCipher() 26 | local function isCipher(name, tbl) 27 | return tbl.type:find("cipher") 28 | end 29 | 30 | print("== Ciphers ==") 31 | fun.each(printEach, fun.filter(isCipher, crypts)) 32 | end 33 | 34 | local function printHashes() 35 | local function isHash(name, tbl) 36 | return tbl.type:find("hash") 37 | end 38 | 39 | print("== Hashes ==") 40 | fun.each(printEach, fun.filter(isHash, crypts)) 41 | end 42 | 43 | local function printAll() 44 | print("Number of crypts: ", fun.length(crypts)) 45 | 46 | ---[[ 47 | printCipher(); 48 | printHashes(); 49 | printRNGs(); 50 | --]] 51 | --fun.each(printEach, crypts) 52 | end 53 | 54 | printAll(); -------------------------------------------------------------------------------- /testy/findsym.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | package.path = "../?.lua;"..package.path; 3 | 4 | --[[ 5 | Find a kernel symbol located in the /proc/kallsyms file. 6 | --]] 7 | 8 | local sym = arg[1] 9 | assert(sym, "must specify a symbol") 10 | 11 | local putil = require("lj2procfs.print-util") 12 | local sutil = require("lj2procfs.string-util") 13 | local fun = require("lj2procfs.fun") 14 | local procfs = require("lj2procfs.procfs") 15 | 16 | local kallsyms = procfs.kallsyms 17 | 18 | local function isDesiredSymbol(name, tbl) 19 | return sutil.startswith(name, sym) 20 | end 21 | 22 | local function printSymbol(name, value) 23 | putil.printValue(value) 24 | end 25 | 26 | fun.each(printSymbol, fun.filter(isDesiredSymbol, kallsyms)) -------------------------------------------------------------------------------- /testy/get_allkernelinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --lthostname.lua 4 | package.path = "../?.lua" 5 | 6 | --[[ 7 | this little utility will iterate all the files in /proc/sys/kernel 8 | and print out their values. 9 | --]] 10 | 11 | local procfs = require("lj2procfs.procfs") 12 | local fsutil = require("lj2procfs.fs-util") 13 | 14 | for _, entry in fsutil.files_in_directory("/proc/sys/kernel") do 15 | print(entry.Name) 16 | print(' ',procfs.sys.kernel[entry.Name]) 17 | end 18 | 19 | 20 | -------------------------------------------------------------------------------- /testy/get_kernelinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | package.path = "../?.lua" 4 | 5 | local procfs = require("lj2procfs.procfs") 6 | 7 | print(arg[1]..': ', procfs.sys.kernel[arg[1]]) 8 | 9 | -------------------------------------------------------------------------------- /testy/get_sysinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | package.path = "../?.lua" 4 | 5 | --[[ 6 | get_sysinfo.lua 7 | 8 | Retrieve stuff from the /proc/sys/* directory 9 | Specify a path to a file, starting with the part 10 | after '/procfs/sys', 11 | 12 | $ ./get_sysinfo.lua kernel/panic 13 | 14 | This is consistent with the strings you might 15 | specify for a sysctl.conf file. You can use 16 | either a '/' or '.' as the path separator. 17 | --]] 18 | 19 | local procfs = require("lj2procfs.procfs") 20 | local sutil = require("lj2procfs.string-util") 21 | 22 | local path = arg[1] or "" 23 | local sep = '/' 24 | if path:find("%.") then 25 | sep = '.' 26 | end 27 | 28 | if not sutil.startswith(path,"sys") then 29 | path = "sys"..sep..path 30 | end 31 | 32 | 33 | -- The segments can be separated with either a '.' 34 | -- or '/' 35 | print("path: ", path) 36 | local segments = sutil.tsplit(path, "[%./]") 37 | 38 | local node = procfs; 39 | for i=1,#segments do 40 | node = node[segments[i]] 41 | end 42 | 43 | print(path..': ', node) 44 | -------------------------------------------------------------------------------- /testy/lsdir.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local fs = require("lj2procfs.fs-util") 5 | local libc = require("lj2procfs.libc") 6 | local fun = require("lj2procfs.fun") 7 | local putil = require("lj2procfs.print-util") 8 | 9 | 10 | local function printEntries(path) 11 | print("Entries: ", path) 12 | for _, entry in fs.entries_in_directory(path) do 13 | putil.printValue(entry, ' ', entry.Name) 14 | end 15 | end 16 | 17 | 18 | local path = arg[1] or "/proc" 19 | 20 | printEntries(path) 21 | 22 | -------------------------------------------------------------------------------- /testy/ltflprocesses.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | --test_procfs_procids.lua 3 | package.path = "../?.lua;"..package.path; 4 | 5 | local procfs = require("lj2procfs.procfs") 6 | local fun = require("lj2procfs.fun") 7 | local Decoders = require("lj2procfs.Decoders") 8 | local putil = require("lj2procfs.print-util") 9 | 10 | 11 | local function printProcEntry(procEntry) 12 | print(string.format("\t[%d] = {", procEntry.Id)) 13 | 14 | for _, fileEntry in procEntry:files() do 15 | local fileValue = procEntry[fileEntry.Name] 16 | putil.printValue(fileValue, '\t\t', fileEntry.Name) 17 | end 18 | 19 | print(string.format("\t},")) 20 | 21 | collectgarbage() 22 | end 23 | 24 | 25 | print(string.format("return {")) 26 | fun.each(printProcEntry, procfs.processes()) 27 | print(string.format("}")) -------------------------------------------------------------------------------- /testy/lthostname.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --[[ 4 | An easy substitution for the 'hostname' shell command 5 | --]] 6 | 7 | package.path = "../?.lua" 8 | local procfs = require("lj2procfs.procfs") 9 | 10 | if arg[1] then 11 | procfs.sys.kernel.hostname = arg[1]; 12 | end 13 | 14 | print(procfs.sys.kernel.hostname) 15 | -------------------------------------------------------------------------------- /testy/ltsysinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | package.path = "../?.lua" 4 | 5 | --[[ 6 | get_sysinfo.lua 7 | 8 | Retrieve stuff from the /proc/sys/* directory 9 | Specify a path to a file, starting with the part 10 | after '/sys', 11 | 12 | $ ./get_sysinfo.lua kernel/panic 13 | 14 | This is consistent with the strings you might 15 | specify for a sysctl.conf file. You can use 16 | either a '/' or '.' as the path separator. 17 | --]] 18 | 19 | local procfs = require("lj2procfs.procfs") 20 | local sutil = require("lj2procfs.string-util") 21 | local sysfs = require("lj2procfs.codecs.sys") 22 | local putil = require("lj2procfs.print-util") 23 | 24 | 25 | local path = arg[1] or "" 26 | local sep = '/' 27 | if path:find("%.") then 28 | sep = '.' 29 | end 30 | 31 | 32 | 33 | -- The segments can be separated with either a '.' 34 | -- or '/' 35 | local segments = sutil.tsplit(path, "[%./]") 36 | 37 | local node = sysfs.sysfs("/sys"); 38 | for i=1,#segments do 39 | -- print(segments[i]) 40 | node = node[segments[i]] 41 | end 42 | 43 | --print("node: ", node) 44 | putil.printValue(node) 45 | -------------------------------------------------------------------------------- /testy/procfile: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | --[[ 4 | procfile 5 | 6 | This is a general purpose /proc/ interpreter. 7 | Usage: 8 | $ sudo ./procfile filename 9 | 10 | Here, 'filname' is any one of the files listed in the 11 | /proc directory. 12 | 13 | In the cases where a decoder is implemented in Decoders.lua 14 | the file will be parsed, and an appropriate value will be 15 | returned and printed in a lua form appropriate for reparsing. 16 | 17 | When there is no decoder implemented, the value returned is 18 | "NO DECODER AVAILABLE" 19 | 20 | example: 21 | $ sudo ./procfile cpuinfo 22 | $ sudo ./procfile partitions 23 | 24 | --]] 25 | 26 | package.path = "../?.lua;"..package.path; 27 | 28 | local procfs = require("lj2procfs.procfs") 29 | local putil = require("lj2procfs.print-util") 30 | 31 | local function USAGE() 32 | print ([[ 33 | 34 | USAGE: 35 | $ sudo ./procfile [PID] 36 | 37 | where is the name of a file in the /proc 38 | directory. 39 | 40 | Example: 41 | $ sudo ./procfile cpuinfo 42 | $ sudo ./procfile 13654 limits 43 | ]]) 44 | 45 | error() 46 | end 47 | 48 | local filename = nil 49 | local PID = nil 50 | 51 | if tonumber(arg[1]) then 52 | PID = tonumber(arg[1]) 53 | filename = arg[2] 54 | else 55 | filename = arg[1] 56 | end 57 | 58 | if not filename then USAGE() end 59 | 60 | 61 | print("return {") 62 | if PID then 63 | putil.printValue(procfs[PID][filename], ' ', tostring(PID).."_"..filename) 64 | else 65 | putil.printValue(procfs[filename], " ", filename) 66 | end 67 | print("}") 68 | -------------------------------------------------------------------------------- /testy/procfs_files.lua: -------------------------------------------------------------------------------- 1 | --test_procfs_procids.lua 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local procfs = require("lj2procfs.procfs") 5 | local fun = require("lj2procfs.fun") 6 | local Decoders = require("lj2procfs.Decoders") 7 | 8 | local function printTable(name, tbl, indent) 9 | indent = indent or "" 10 | --print("TABLE: ", #mapped) 11 | print(string.format("%s['%s'] = {", indent, name)) 12 | if #tbl > 0 then 13 | -- it's a list,so use ipairs 14 | for _, value in ipairs(tbl) do 15 | print(string.format("%s\t'%s',",indent, value)) 16 | end 17 | else 18 | -- assume it's a dictionary, so use pairs 19 | for key, value in pairs(tbl) do 20 | print(string.format("%s\t['%s'] = [[%s]],",indent, key, value)) 21 | end 22 | end 23 | 24 | print(string.format("%s},", indent)) 25 | end 26 | 27 | local function printFile(entry) 28 | local mapper = Decoders[entry.Name] 29 | local indent = '\t\t\t' 30 | if mapper then 31 | local mapped = mapper(entry.Path) 32 | if type(mapped) == "table" then 33 | printTable(entry.Name, mapped, indent) 34 | elseif type(mapped) == "string" then 35 | print(string.format("%s['%s'] = [[%s]],", indent, entry.Name, mapped)) 36 | end 37 | else 38 | print(string.format("%s'%s',", indent,entry.Name)) 39 | end 40 | end 41 | 42 | 43 | local function printProcfsFiles() 44 | --print(string.format("\t[%d] = {", procEntry.Id)) 45 | 46 | fun.each(printFile, procfs.files()) 47 | 48 | --print(string.format("\t},")) 49 | end 50 | 51 | print(string.format("return {")) 52 | printProcfsFiles(); 53 | print(string.format("}")) 54 | -------------------------------------------------------------------------------- /testy/set_kernelinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | package.path = "../?.lua" 4 | 5 | --[[ 6 | This little utility sets a /proc/sys/kernel/* value 7 | You can use it simply by doing: 8 | 9 | $ ./set_kernelinfo.lua key value 10 | 11 | where 'key' is one of the files in the /proc/sys/kernel directory 12 | and 'value' is a string value appropriate for that particular entry 13 | --]] 14 | local procfs = require("lj2procfs.procfs") 15 | 16 | local key = arg[1] 17 | local value = arg[2] 18 | assert(key and value, "MUST specify both key and value") 19 | 20 | procfs.sys.kernel[key] = value; 21 | 22 | 23 | -------------------------------------------------------------------------------- /testy/test_iterate_directory.lua: -------------------------------------------------------------------------------- 1 | --test_iterate_directory.lua 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local fs = require("lj2procfs.fs-util") 5 | local libc = require("lj2procfs.libc") 6 | local fun = require("lj2procfs.fun") 7 | 8 | 9 | 10 | local function printFiles(path) 11 | for _, file in fs.files_in_directory(path) do 12 | print(file.Name) 13 | end 14 | end 15 | 16 | local function printEntries(path) 17 | print("printEntries: ", path) 18 | for _, entry in fs.entries_in_directory(path) do 19 | print(entry.Name, libc.DT_DIR == entry.Kind) 20 | end 21 | end 22 | 23 | local function printEntry(entry) 24 | print(entry.Name) 25 | end 26 | 27 | local function printProcs() 28 | local function isProcess(entry) 29 | local num = tonumber(entry.Name) 30 | return entry.Kind == libc.DT_DIR and num 31 | end 32 | 33 | fun.each(printEntry, fun.filter(isProcess, fs.entries_in_directory("/proc"))) 34 | end 35 | 36 | local path = arg[1] or "/proc" 37 | 38 | printEntries(path) 39 | --printFiles(path) 40 | --printProcs(); 41 | -------------------------------------------------------------------------------- /testy/test_lfs.lua: -------------------------------------------------------------------------------- 1 | 2 | 3 | local lfs = require"lfs" 4 | 5 | function attrdir (path) 6 | for file in lfs.dir(path) do 7 | if file ~= "." and file ~= ".." then 8 | local f = path..'/'..file 9 | print ("\t "..f) 10 | local attr = lfs.attributes (f) 11 | assert (type(attr) == "table") 12 | if attr.mode == "directory" then 13 | attrdir (f) 14 | else 15 | for name, value in pairs(attr) do 16 | print (name, value) 17 | end 18 | end 19 | end 20 | end 21 | end 22 | 23 | attrdir (".") 24 | -------------------------------------------------------------------------------- /testy/test_procfs_procids.lua: -------------------------------------------------------------------------------- 1 | --test_procfs_procids.lua 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local procfs = require("lj2procfs.procfs") 5 | local fun = require("lj2procfs.fun") 6 | 7 | 8 | local function processIds() 9 | return fun.map(function(entry) return tonumber(entry.Name) end, fun.filter(isProcess, fs.entries_in_directory("/proc"))) 10 | end 11 | 12 | 13 | for _, id in processIds() do 14 | print(id) 15 | end -------------------------------------------------------------------------------- /testy/test_procfs_procs.lua: -------------------------------------------------------------------------------- 1 | --test_procfs_procids.lua 2 | package.path = "../?.lua;"..package.path; 3 | 4 | local procfs = require("lj2procfs.procfs") 5 | local fun = require("lj2procfs.fun") 6 | local Decoders = require("lj2procfs.Decoders") 7 | local putil = require("lj2procfs.print-util") 8 | 9 | 10 | 11 | local function printTable(name, tbl, indent) 12 | indent = indent or "" 13 | --print("TABLE: ", #mapped) 14 | print(string.format("%s['%s'] = {", indent, name)) 15 | if #tbl > 0 then 16 | -- it's a list,so use ipairs 17 | for _, value in ipairs(tbl) do 18 | print(string.format("%s\t'%s',",indent, value)) 19 | end 20 | else 21 | -- assume it's a dictionary, so use pairs 22 | for key, value in pairs(tbl) do 23 | print(string.format("%s\t['%s'] = [[%s]],",indent, key, value)) 24 | end 25 | end 26 | 27 | print(string.format("%s},", indent)) 28 | end 29 | 30 | local function printFile(entry) 31 | local mapper = Decoders[entry.Name] 32 | local indent = '\t\t\t' 33 | if mapper then 34 | local mapped = mapper(entry.Path) 35 | if type(mapped) == "table" then 36 | putil.printValue(mapped, indent, entry.Name) 37 | --printTable(entry.Name, mapped, indent) 38 | elseif type(mapped) == "string" then 39 | print(string.format("%s['%s'] = [[%s]],", indent, entry.Name, mapped)) 40 | end 41 | else 42 | print(string.format("%s'%s',", indent,entry.Name)) 43 | end 44 | end 45 | 46 | local function printDirectory(entry) 47 | print(string.format("\t\t\t'%s',", entry.Name)) 48 | end 49 | 50 | local function printProcessEntries() 51 | for _, procEntry in procfs.processes() do 52 | print(string.format("\t[%d] = {", procEntry.Id)) 53 | 54 | print("\t\tdirectories = {") 55 | fun.each(printDirectory, procEntry:directories()) 56 | print("\t\t},") 57 | 58 | print("\t\tfiles = {") 59 | fun.each(printFile, procEntry:files()) 60 | print("\t\t},") 61 | 62 | print(string.format("\t},")) 63 | end 64 | end 65 | 66 | print(string.format("return {")) 67 | printProcessEntries(); 68 | print(string.format("}")) -------------------------------------------------------------------------------- /testy/test_sysinfo.lua: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env luajit 2 | 3 | package.path = "../?.lua" 4 | 5 | --[[ 6 | test_sysinfo.lua 7 | 8 | Test for a specific directory 9 | --]] 10 | 11 | local procfs = require("lj2procfs.procfs") 12 | local sutil = require("lj2procfs.string-util") 13 | local sysfs = require("lj2procfs.codecs.sys") 14 | local putil = require("lj2procfs.print-util") 15 | 16 | 17 | 18 | local node = sysfs.sysfs("/sys/power"); 19 | 20 | for a, snode, c in pairs(node) do 21 | putil.printValue(snode) 22 | end 23 | 24 | --------------------------------------------------------------------------------