1 -- Copyright 2008 Steven Barth <steven@midlink.org>
2 -- Licensed to the public under the Apache License 2.0.
4 local io = require "io"
5 local math = require "math"
6 local table = require "table"
7 local debug = require "debug"
8 local ldebug = require "luci.debug"
9 local string = require "string"
10 local coroutine = require "coroutine"
11 local tparser = require "luci.template.parser"
12 local json = require "luci.jsonc"
13 local lhttp = require "lucihttp"
15 local _ubus = require "ubus"
16 local _ubus_connection = nil
18 local getmetatable, setmetatable = getmetatable, setmetatable
19 local rawget, rawset, unpack, select = rawget, rawset, unpack, select
20 local tostring, type, assert, error = tostring, type, assert, error
21 local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring
22 local require, pcall, xpcall = require, pcall, xpcall
23 local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
28 -- Pythonic string formatting extension
30 getmetatable("").__mod = function(a, b)
35 elseif type(b) == "table" then
37 for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end
39 ok, res = pcall(a.format, a, unpack(b))
45 if type(b) == "userdata" then b = tostring(b) end
47 ok, res = pcall(a.format, a, b)
57 -- Class helper routines
60 -- Instantiates a class
61 local function _instantiate(class, ...)
62 local inst = setmetatable({}, {__index = class})
71 -- The class object can be instantiated by calling itself.
72 -- Any class functions or shared parameters can be attached to this object.
73 -- Attaching a table to the class object makes this table shared between
74 -- all instances of this class. For object parameters use the __init__ function.
75 -- Classes can inherit member functions and values from a base class.
76 -- Class can be instantiated by calling them. All parameters will be passed
77 -- to the __init__ function of this class - if such a function exists.
78 -- The __init__ function must be used to set any object parameters that are not shared
79 -- with other objects of this class. Any return values will be ignored.
81 return setmetatable({}, {
82 __call = _instantiate,
87 function instanceof(object, class)
88 local meta = getmetatable(object)
89 while meta and meta.__index do
90 if meta.__index == class then
93 meta = getmetatable(meta.__index)
100 -- Scope manipulation routines
103 coxpt = setmetatable({}, { __mode = "kv" })
108 __index = function(self, key)
109 local t = rawget(self, coxpt[coroutine.running()]
110 or coroutine.running() or 0)
114 __newindex = function(self, key, value)
115 local c = coxpt[coroutine.running()] or coroutine.running() or 0
116 local r = rawget(self, c)
118 rawset(self, c, { [key] = value })
125 -- the current active coroutine. A thread local store is private a table object
126 -- whose values can't be accessed from outside of the running coroutine.
127 function threadlocal(tbl)
128 return setmetatable(tbl or {}, tl_meta)
133 -- Debugging routines
137 return io.stderr:write(tostring(obj) .. "\n")
140 function dumptable(t, maxdepth, i, seen)
142 seen = seen or setmetatable({}, {__mode="k"})
144 for k,v in pairs(t) do
145 perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v))
146 if type(v) == "table" and (not maxdepth or i < maxdepth) then
149 dumptable(v, maxdepth, i+1, seen)
151 perror(string.rep("\t", i) .. "*** RECURSION ***")
159 -- String and data manipulation routines
162 function pcdata(value)
163 return value and tparser.pcdata(tostring(value))
166 function urlencode(value)
168 local str = tostring(value)
169 return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL)
175 function urldecode(value, decode_plus)
177 local flag = decode_plus and lhttp.DECODE_PLUS or 0
178 local str = tostring(value)
179 return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag)
185 function striptags(value)
186 return value and tparser.striptags(tostring(value))
189 function shellquote(value)
190 return string.format("'%s'", string.gsub(value or "", "'", "'\\''"))
193 -- for bash, ash and similar shells single-quoted strings are taken
194 -- literally except for single quotes (which terminate the string)
195 -- (and the exception noted below for dash (-) at the start of a
196 -- command line parameter).
197 function shellsqescape(value)
199 res, _ = string.gsub(value, "'", "'\\''")
203 -- bash, ash and other similar shells interpret a dash (-) at the start
204 -- of a command-line parameters as an option indicator regardless of
205 -- whether it is inside a single-quoted string. It must be backlash
206 -- escaped to resolve this. This requires in some funky special-case
207 -- handling. It may actually be a property of the getopt function
208 -- rather than the shell proper.
209 function shellstartsqescape(value)
210 res, _ = string.gsub(value, "^\-", "\\-")
211 res, _ = string.gsub(res, "^-", "\-")
212 return shellsqescape(value)
215 -- containing the resulting substrings. The optional max parameter specifies
216 -- the number of bytes to process, regardless of the actual length of the given
217 -- string. The optional last parameter, regex, specifies whether the separator
218 -- sequence is interpreted as regular expression.
219 -- pattern as regular expression (optional, default is false)
220 function split(str, pat, max, regex)
240 local s, e = str:find(pat, c, not regex)
242 if s and max < 0 then
245 t[#t+1] = str:sub(c, s and s - 1)
247 c = e and e + 1 or #str + 1
248 until not s or max < 0
254 return (str:gsub("^%s*(.-)%s*$", "%1"))
257 function cmatch(str, pat)
259 for _ in str:gmatch(pat) do count = count + 1 end
263 -- one token per invocation, the tokens are separated by whitespace. If the
264 -- input value is a table, it is transformed into a string first. A nil value
265 -- will result in a valid iterator which aborts with the first invocation.
267 if type(v) == "table" then
274 elseif type(v) == "number" or type(v) == "boolean" then
283 elseif type(v) == "userdata" or type(v) == "string" then
284 return tostring(v):gmatch("%S+")
287 return function() end
290 -- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
291 -- Recognized units are:
292 -- o "y" - one year (60*60*24*366)
293 -- o "m" - one month (60*60*24*31)
294 -- o "w" - one week (60*60*24*7)
295 -- o "d" - one day (60*60*24)
296 -- o "h" - one hour (60*60)
297 -- o "min" - one minute (60)
298 -- o "kb" - one kilobyte (1024)
299 -- o "mb" - one megabyte (1024*1024)
300 -- o "gb" - one gigabyte (1024*1024*1024)
301 -- o "kib" - one si kilobyte (1000)
302 -- o "mib" - one si megabyte (1000*1000)
303 -- o "gib" - one si gigabyte (1000*1000*1000)
304 function parse_units(ustr)
311 y = 60 * 60 * 24 * 366,
312 m = 60 * 60 * 24 * 31,
313 w = 60 * 60 * 24 * 7,
321 gb = 1024 * 1024 * 1024,
323 -- storage sizes (si)
326 gib = 1000 * 1000 * 1000
329 -- parse input string
330 for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
332 local num = spec:gsub("[^0-9%.]+$","")
333 local spn = spec:gsub("^[0-9%.]+", "")
335 if map[spn] or map[spn:sub(1,1)] then
336 val = val + num * ( map[spn] or map[spn:sub(1,1)] )
346 -- also register functions above in the central string class for convenience
347 string.pcdata = pcdata
348 string.striptags = striptags
351 string.cmatch = cmatch
352 string.parse_units = parse_units
355 function append(src, ...)
356 for i, a in ipairs({...}) do
357 if type(a) == "table" then
358 for j, v in ipairs(a) do
368 function combine(...)
369 return append({}, ...)
372 function contains(table, value)
373 for k, v in pairs(table) do
381 -- Both table are - in fact - merged together.
382 function update(t, updates)
383 for k, v in pairs(updates) do
391 for k, _ in kspairs(t) do
398 function clone(object, deep)
401 for k, v in pairs(object) do
402 if deep and type(v) == "table" then
408 return setmetatable(copy, getmetatable(object))
412 -- Serialize the contents of a table value.
413 function _serialize_table(t, seen)
414 assert(not seen[t], "Recursion detected.")
421 for k, v in pairs(t) do
422 if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then
423 k = serialize_data(k, seen)
424 v = serialize_data(v, seen)
425 data = data .. ( #data > 0 and ", " or "" ) ..
426 '[' .. k .. '] = ' .. v
433 local v = serialize_data(t[i], seen)
434 idata = idata .. ( #idata > 0 and ", " or "" ) .. v
437 return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
440 -- with loadstring().
441 function serialize_data(val, seen)
442 seen = seen or setmetatable({}, {__mode="k"})
446 elseif type(val) == "number" then
448 elseif type(val) == "string" then
450 elseif type(val) == "boolean" then
451 return val and "true" or "false"
452 elseif type(val) == "function" then
453 return "loadstring(%q)" % get_bytecode(val)
454 elseif type(val) == "table" then
455 return "{ " .. _serialize_table(val, seen) .. " }"
457 return '"[unhandled data type:' .. type(val) .. ']"'
461 function restore_data(str)
462 return loadstring("return " .. str)()
467 -- Byte code manipulation routines
470 -- will be stripped before it is returned.
471 function get_bytecode(val)
474 if type(val) == "function" then
475 code = string.dump(val)
477 code = string.dump( loadstring( "return " .. serialize_data(val) ) )
480 return code -- and strip_bytecode(code)
483 -- numbers and debugging numbers will be discarded. Original version by
484 -- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
485 function strip_bytecode(code)
486 local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
489 subint = function(code, i, l)
492 val = val * 256 + code:byte(i + n - 1)
497 subint = function(code, i, l)
500 val = val * 256 + code:byte(i + n - 1)
506 local function strip_function(code)
507 local count, offset = subint(code, 1, size)
508 local stripped = { string.rep("\0", size) }
509 local dirty = offset + count
510 offset = offset + count + int * 2 + 4
511 offset = offset + int + subint(code, offset, int) * ins
512 count, offset = subint(code, offset, int)
515 t, offset = subint(code, offset, 1)
519 offset = offset + size + subint(code, offset, size)
521 offset = offset + num
522 elseif t == 254 or t == 9 then
523 offset = offset + lnum
526 count, offset = subint(code, offset, int)
527 stripped[#stripped+1] = code:sub(dirty, offset - 1)
529 local proto, off = strip_function(code:sub(offset, -1))
530 stripped[#stripped+1] = proto
531 offset = offset + off - 1
533 offset = offset + subint(code, offset, int) * int + int
534 count, offset = subint(code, offset, int)
536 offset = offset + subint(code, offset, size) + size + int * 2
538 count, offset = subint(code, offset, int)
540 offset = offset + subint(code, offset, size) + size
542 stripped[#stripped+1] = string.rep("\0", int * 3)
543 return table.concat(stripped), offset
546 return code:sub(1,12) .. strip_function(code:sub(13,-1))
551 -- Sorting iterator functions
554 function _sortiter( t, f )
558 for k, v in pairs(t) do
564 table.sort( keys, f )
568 if _pos <= #keys then
569 return keys[_pos], t[keys[_pos]], _pos
574 -- the provided callback function.
576 return _sortiter( t, f )
579 -- The table pairs are sorted by key.
581 return _sortiter( t )
584 -- The table pairs are sorted by value.
586 return _sortiter( t, function (a,b) return t[a] < t[b] end )
591 -- System utility functions
595 return string.byte(string.dump(function() end), 7) == 0
598 function exec(command)
599 local pp = io.popen(command)
600 local data = pp:read("*a")
606 function execi(command)
607 local pp = io.popen(command)
609 return pp and function()
610 local line = pp:read()
621 function execl(command)
622 local pp = io.popen(command)
628 if (line == nil) then break end
650 local function ubus_return(...)
651 if select('#', ...) == 2 then
652 local rv, err = select(1, ...), select(2, ...)
653 if rv == nil and type(err) == "number" then
654 return nil, err, ubus_codes[err]
661 function ubus(object, method, data)
662 if not _ubus_connection then
663 _ubus_connection = _ubus.connect()
664 assert(_ubus_connection, "Unable to establish ubus connection")
667 if object and method then
668 if type(data) ~= "table" then
671 return ubus_return(_ubus_connection:call(object, method, data))
673 return _ubus_connection:signatures(object)
675 return _ubus_connection:objects()
679 function serialize_json(x, cb)
680 local js = json.stringify(x)
681 if type(cb) == "function" then
690 return require "nixio.fs".dirname(ldebug.__file__)
693 function checklib(fullpathexe, wantedlib)
694 local fs = require "nixio.fs"
695 local haveldd = fs.access('/usr/bin/ldd')
696 local haveexe = fs.access(fullpathexe)
697 if not haveldd or not haveexe then
700 local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe)))
704 for k, v in ipairs(split(libs)) do
705 if v:find(wantedlib) then
712 -------------------------------------------------------------------------------
713 -- Coroutine safe xpcall and pcall versions
715 -- Encapsulates the protected calls with a coroutine based loop, so errors can
716 -- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines
717 -- yielding inside the call to pcall or xpcall.
719 -- Authors: Roberto Ierusalimschy and Andre Carregal
720 -- Contributors: Thomas Harning Jr., Ignacio BurgueƱo, Fabio Mascarenhas
722 -- Copyright 2005 - Kepler Project
724 -- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $
725 -------------------------------------------------------------------------------
727 -------------------------------------------------------------------------------
728 -- Implements xpcall with coroutines
729 -------------------------------------------------------------------------------
730 local coromap = setmetatable({}, { __mode = "k" })
732 local function handleReturnValue(err, co, status, ...)
734 return false, err(debug.traceback(co, (...)), ...)
736 if coroutine.status(co) == 'suspended' then
737 return performResume(err, co, coroutine.yield(...))
743 function performResume(err, co, ...)
744 return handleReturnValue(err, co, coroutine.resume(co, ...))
747 local function id(trace, ...)
751 function coxpcall(f, err, ...)
752 local current = coroutine.running()
757 if select("#", ...) > 0 then
758 local oldf, params = f, { ... }
759 f = function() return oldf(unpack(params)) end
761 return xpcall(f, err)
764 local res, co = pcall(coroutine.create, f)
766 local newf = function(...) return f(...) end
767 co = coroutine.create(newf)
769 coromap[co] = current
770 coxpt[co] = coxpt[current] or current or 0
771 return performResume(err, co, ...)
775 function copcall(f, ...)
776 return coxpcall(f, id, ...)