X-Git-Url: http://git.archive.openwrt.org/?p=project%2Fluci.git;a=blobdiff_plain;f=modules%2Fluci-base%2Fluasrc%2Futil.lua;h=ce42af2fb00509779d1ef5feb9c124eb083a91cc;hp=dcf8230b3ebe573b6b37246c1ffb29f91f481ca3;hb=11f4a50b3f009a665b02564d0ceab133a1772831;hpb=ae8e971eef2be269beab9465139869055918d878 diff --git a/modules/luci-base/luasrc/util.lua b/modules/luci-base/luasrc/util.lua index dcf8230b3..ce42af2fb 100644 --- a/modules/luci-base/luasrc/util.lua +++ b/modules/luci-base/luasrc/util.lua @@ -9,13 +9,15 @@ local ldebug = require "luci.debug" local string = require "string" local coroutine = require "coroutine" local tparser = require "luci.template.parser" +local json = require "luci.jsonc" +local lhttp = require "lucihttp" local _ubus = require "ubus" local _ubus_connection = nil local getmetatable, setmetatable = getmetatable, setmetatable local rawget, rawset, unpack = rawget, rawset, unpack -local tostring, type, assert = tostring, type, assert +local tostring, type, assert, error = tostring, type, assert, error local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring local require, pcall, xpcall = require, pcall, xpcall local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit @@ -26,14 +28,27 @@ module "luci.util" -- Pythonic string formatting extension -- getmetatable("").__mod = function(a, b) + local ok, res + if not b then return a elseif type(b) == "table" then + local k, _ for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end - return a:format(unpack(b)) + + ok, res = pcall(a.format, a, unpack(b)) + if not ok then + error(res, 2) + end + return res else if type(b) == "userdata" then b = tostring(b) end - return a:format(b) + + ok, res = pcall(a.format, a, b) + if not ok then + error(res, 2) + end + return res end end @@ -146,10 +161,55 @@ function pcdata(value) return value and tparser.pcdata(tostring(value)) end +function urlencode(value) + if value ~= nil then + local str = tostring(value) + return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL) + or str + end + return nil +end + +function urldecode(value, decode_plus) + if value ~= nil then + local flag = decode_plus and lhttp.DECODE_PLUS or 0 + local str = tostring(value) + return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag) + or str + end + return nil +end + function striptags(value) return value and tparser.striptags(tostring(value)) end +function shellquote(value) + return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) +end + +-- for bash, ash and similar shells single-quoted strings are taken +-- literally except for single quotes (which terminate the string) +-- (and the exception noted below for dash (-) at the start of a +-- command line parameter). +function shellsqescape(value) + local res + res, _ = string.gsub(value, "'", "'\\''") + return res +end + +-- bash, ash and other similar shells interpret a dash (-) at the start +-- of a command-line parameters as an option indicator regardless of +-- whether it is inside a single-quoted string. It must be backlash +-- escaped to resolve this. This requires in some funky special-case +-- handling. It may actually be a property of the getopt function +-- rather than the shell proper. +function shellstartsqescape(value) + res, _ = string.gsub(value, "^\-", "\\-") + res, _ = string.gsub(res, "^-", "\-") + return shellsqescape(value) +end + -- containing the resulting substrings. The optional max parameter specifies -- the number of bytes to process, regardless of the actual length of the given -- string. The optional last parameter, regex, specifies whether the separator @@ -347,16 +407,6 @@ function clone(object, deep) end -function dtable() - return setmetatable({}, { __index = - function(tbl, key) - return rawget(tbl, key) - or rawget(rawset(tbl, key, dtable()), key) - end - }) -end - - -- Serialize the contents of a table value. function _serialize_table(t, seen) assert(not seen[t], "Recursion detected.") @@ -581,6 +631,20 @@ function execl(command) return data end + +local ubus_codes = { + "INVALID_COMMAND", + "INVALID_ARGUMENT", + "METHOD_NOT_FOUND", + "NOT_FOUND", + "NO_DATA", + "PERMISSION_DENIED", + "TIMEOUT", + "NOT_SUPPORTED", + "UNKNOWN_ERROR", + "CONNECTION_FAILED" +} + function ubus(object, method, data) if not _ubus_connection then _ubus_connection = _ubus.connect() @@ -591,7 +655,8 @@ function ubus(object, method, data) if type(data) ~= "table" then data = { } end - return _ubus_connection:call(object, method, data) + local rv, err = _ubus_connection:call(object, method, data) + return rv, err, ubus_codes[err] elseif object then return _ubus_connection:signatures(object) else @@ -600,55 +665,11 @@ function ubus(object, method, data) end function serialize_json(x, cb) - local rv, push = nil, cb - if not push then - rv = { } - push = function(tok) rv[#rv+1] = tok end - end - - if x == nil then - push("null") - elseif type(x) == "table" then - -- test if table is array like - local k, v - local n1, n2 = 0, 0 - for k in pairs(x) do n1 = n1 + 1 end - for k in ipairs(x) do n2 = n2 + 1 end - - if n1 == n2 and n1 > 0 then - push("[") - for k = 1, n2 do - if k > 1 then - push(",") - end - serialize_json(x[k], push) - end - push("]") - else - push("{") - for k, v in pairs(x) do - push("%q:" % tostring(k)) - serialize_json(v, push) - if next(x, k) then - push(",") - end - end - push("}") - end - elseif type(x) == "number" or type(x) == "boolean" then - if (x ~= x) then - -- NaN is the only value that doesn't equal to itself. - push("Number.NaN") - else - push(tostring(x)) - end + local js = json.stringify(x) + if type(cb) == "function" then + cb(js) else - push('"%s"' % tostring(x):gsub('["%z\1-\31\\]', - function(c) return '\\u%04x' % c:byte(1) end)) - end - - if not cb then - return table.concat(rv, "") + return js end end @@ -657,6 +678,24 @@ function libpath() return require "nixio.fs".dirname(ldebug.__file__) end +function checklib(fullpathexe, wantedlib) + local fs = require "nixio.fs" + local haveldd = fs.access('/usr/bin/ldd') + local haveexe = fs.access(fullpathexe) + if not haveldd or not haveexe then + return false + end + local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe))) + if not libs then + return false + end + for k, v in ipairs(split(libs)) do + if v:find(wantedlib) then + return true + end + end + return false +end -- -- Coroutine safe xpcall and pcall versions modified for Luci