2
0

util.lua 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Licensed to the public under the Apache License 2.0.
  3. local io = require "io"
  4. local math = require "math"
  5. local table = require "table"
  6. local debug = require "debug"
  7. local ldebug = require "luci.debug"
  8. local string = require "string"
  9. local coroutine = require "coroutine"
  10. local tparser = require "luci.template.parser"
  11. local json = require "luci.jsonc"
  12. local lhttp = require "lucihttp"
  13. local _ubus = require "ubus"
  14. local _ubus_connection = nil
  15. local getmetatable, setmetatable = getmetatable, setmetatable
  16. local rawget, rawset, unpack, select = rawget, rawset, unpack, select
  17. local tostring, type, assert, error = tostring, type, assert, error
  18. local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring
  19. local require, pcall, xpcall = require, pcall, xpcall
  20. local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit
  21. module "luci.util"
  22. --
  23. -- Pythonic string formatting extension
  24. --
  25. getmetatable("").__mod = function(a, b)
  26. local ok, res
  27. if not b then
  28. return a
  29. elseif type(b) == "table" then
  30. local k, _
  31. for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end
  32. ok, res = pcall(a.format, a, unpack(b))
  33. if not ok then
  34. error(res, 2)
  35. end
  36. return res
  37. else
  38. if type(b) == "userdata" then b = tostring(b) end
  39. ok, res = pcall(a.format, a, b)
  40. if not ok then
  41. error(res, 2)
  42. end
  43. return res
  44. end
  45. end
  46. --
  47. -- Class helper routines
  48. --
  49. -- Instantiates a class
  50. local function _instantiate(class, ...)
  51. local inst = setmetatable({}, {__index = class})
  52. if inst.__init__ then
  53. inst:__init__(...)
  54. end
  55. return inst
  56. end
  57. -- The class object can be instantiated by calling itself.
  58. -- Any class functions or shared parameters can be attached to this object.
  59. -- Attaching a table to the class object makes this table shared between
  60. -- all instances of this class. For object parameters use the __init__ function.
  61. -- Classes can inherit member functions and values from a base class.
  62. -- Class can be instantiated by calling them. All parameters will be passed
  63. -- to the __init__ function of this class - if such a function exists.
  64. -- The __init__ function must be used to set any object parameters that are not shared
  65. -- with other objects of this class. Any return values will be ignored.
  66. function class(base)
  67. return setmetatable({}, {
  68. __call = _instantiate,
  69. __index = base
  70. })
  71. end
  72. function instanceof(object, class)
  73. local meta = getmetatable(object)
  74. while meta and meta.__index do
  75. if meta.__index == class then
  76. return true
  77. end
  78. meta = getmetatable(meta.__index)
  79. end
  80. return false
  81. end
  82. --
  83. -- Scope manipulation routines
  84. --
  85. function threadlocal(tbl)
  86. return tbl or {}
  87. end
  88. --
  89. -- Debugging routines
  90. --
  91. function perror(obj)
  92. return io.stderr:write(tostring(obj) .. "\n")
  93. end
  94. function dumptable(t, maxdepth, i, seen)
  95. i = i or 0
  96. seen = seen or setmetatable({}, {__mode="k"})
  97. for k,v in pairs(t) do
  98. perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v))
  99. if type(v) == "table" and (not maxdepth or i < maxdepth) then
  100. if not seen[v] then
  101. seen[v] = true
  102. dumptable(v, maxdepth, i+1, seen)
  103. else
  104. perror(string.rep("\t", i) .. "*** RECURSION ***")
  105. end
  106. end
  107. end
  108. end
  109. --
  110. -- String and data manipulation routines
  111. --
  112. -- compatibility wrapper for xml.pcdata
  113. function pcdata(value)
  114. local xml = require "luci.xml"
  115. perror("luci.util.pcdata() has been replaced by luci.xml.pcdata() - Please update your code.")
  116. return xml.pcdata(value)
  117. end
  118. function urlencode(value)
  119. if value ~= nil then
  120. local str = tostring(value)
  121. return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL)
  122. or str
  123. end
  124. return nil
  125. end
  126. function urldecode(value, decode_plus)
  127. if value ~= nil then
  128. local flag = decode_plus and lhttp.DECODE_PLUS or 0
  129. local str = tostring(value)
  130. return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag)
  131. or str
  132. end
  133. return nil
  134. end
  135. -- compatibility wrapper for xml.striptags
  136. function striptags(value)
  137. local xml = require "luci.xml"
  138. perror("luci.util.striptags() has been replaced by luci.xml.striptags() - Please update your code.")
  139. return xml.striptags(value)
  140. end
  141. function shellquote(value)
  142. return string.format("'%s'", string.gsub(value or "", "'", "'\\''"))
  143. end
  144. -- for bash, ash and similar shells single-quoted strings are taken
  145. -- literally except for single quotes (which terminate the string)
  146. -- (and the exception noted below for dash (-) at the start of a
  147. -- command line parameter).
  148. function shellsqescape(value)
  149. local res
  150. res, _ = string.gsub(value, "'", "'\\''")
  151. return res
  152. end
  153. -- bash, ash and other similar shells interpret a dash (-) at the start
  154. -- of a command-line parameters as an option indicator regardless of
  155. -- whether it is inside a single-quoted string. It must be backlash
  156. -- escaped to resolve this. This requires in some funky special-case
  157. -- handling. It may actually be a property of the getopt function
  158. -- rather than the shell proper.
  159. function shellstartsqescape(value)
  160. res, _ = string.gsub(value, "^%-", "\\-")
  161. return shellsqescape(res)
  162. end
  163. -- containing the resulting substrings. The optional max parameter specifies
  164. -- the number of bytes to process, regardless of the actual length of the given
  165. -- string. The optional last parameter, regex, specifies whether the separator
  166. -- sequence is interpreted as regular expression.
  167. -- pattern as regular expression (optional, default is false)
  168. function split(str, pat, max, regex)
  169. pat = pat or "\n"
  170. max = max or #str
  171. local t = {}
  172. local c = 1
  173. if #str == 0 then
  174. return {""}
  175. end
  176. if #pat == 0 then
  177. return nil
  178. end
  179. if max == 0 then
  180. return str
  181. end
  182. repeat
  183. local s, e = str:find(pat, c, not regex)
  184. max = max - 1
  185. if s and max < 0 then
  186. t[#t+1] = str:sub(c)
  187. else
  188. t[#t+1] = str:sub(c, s and s - 1)
  189. end
  190. c = e and e + 1 or #str + 1
  191. until not s or max < 0
  192. return t
  193. end
  194. function trim(str)
  195. return (str:gsub("^%s*(.-)%s*$", "%1"))
  196. end
  197. function cmatch(str, pat)
  198. local count = 0
  199. for _ in str:gmatch(pat) do count = count + 1 end
  200. return count
  201. end
  202. -- one token per invocation, the tokens are separated by whitespace. If the
  203. -- input value is a table, it is transformed into a string first. A nil value
  204. -- will result in a valid iterator which aborts with the first invocation.
  205. function imatch(v)
  206. if type(v) == "table" then
  207. local k = nil
  208. return function()
  209. k = next(v, k)
  210. return v[k]
  211. end
  212. elseif type(v) == "number" or type(v) == "boolean" then
  213. local x = true
  214. return function()
  215. if x then
  216. x = false
  217. return tostring(v)
  218. end
  219. end
  220. elseif type(v) == "userdata" or type(v) == "string" then
  221. return tostring(v):gmatch("%S+")
  222. end
  223. return function() end
  224. end
  225. -- value or 0 if the unit is unknown. Upper- or lower case is irrelevant.
  226. -- Recognized units are:
  227. -- o "y" - one year (60*60*24*366)
  228. -- o "m" - one month (60*60*24*31)
  229. -- o "w" - one week (60*60*24*7)
  230. -- o "d" - one day (60*60*24)
  231. -- o "h" - one hour (60*60)
  232. -- o "min" - one minute (60)
  233. -- o "kb" - one kilobyte (1024)
  234. -- o "mb" - one megabyte (1024*1024)
  235. -- o "gb" - one gigabyte (1024*1024*1024)
  236. -- o "kib" - one si kilobyte (1000)
  237. -- o "mib" - one si megabyte (1000*1000)
  238. -- o "gib" - one si gigabyte (1000*1000*1000)
  239. function parse_units(ustr)
  240. local val = 0
  241. -- unit map
  242. local map = {
  243. -- date stuff
  244. y = 60 * 60 * 24 * 366,
  245. m = 60 * 60 * 24 * 31,
  246. w = 60 * 60 * 24 * 7,
  247. d = 60 * 60 * 24,
  248. h = 60 * 60,
  249. min = 60,
  250. -- storage sizes
  251. kb = 1024,
  252. mb = 1024 * 1024,
  253. gb = 1024 * 1024 * 1024,
  254. -- storage sizes (si)
  255. kib = 1000,
  256. mib = 1000 * 1000,
  257. gib = 1000 * 1000 * 1000
  258. }
  259. -- parse input string
  260. for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do
  261. local num = spec:gsub("[^0-9%.]+$","")
  262. local spn = spec:gsub("^[0-9%.]+", "")
  263. if map[spn] or map[spn:sub(1,1)] then
  264. val = val + num * ( map[spn] or map[spn:sub(1,1)] )
  265. else
  266. val = val + num
  267. end
  268. end
  269. return val
  270. end
  271. -- also register functions above in the central string class for convenience
  272. string.split = split
  273. string.trim = trim
  274. string.cmatch = cmatch
  275. string.parse_units = parse_units
  276. function append(src, ...)
  277. for i, a in ipairs({...}) do
  278. if type(a) == "table" then
  279. for j, v in ipairs(a) do
  280. src[#src+1] = v
  281. end
  282. else
  283. src[#src+1] = a
  284. end
  285. end
  286. return src
  287. end
  288. function combine(...)
  289. return append({}, ...)
  290. end
  291. function contains(table, value)
  292. for k, v in pairs(table) do
  293. if value == v then
  294. return k
  295. end
  296. end
  297. return false
  298. end
  299. -- Both table are - in fact - merged together.
  300. function update(t, updates)
  301. for k, v in pairs(updates) do
  302. t[k] = v
  303. end
  304. end
  305. function keys(t)
  306. local keys = { }
  307. if t then
  308. for k, _ in kspairs(t) do
  309. keys[#keys+1] = k
  310. end
  311. end
  312. return keys
  313. end
  314. function clone(object, deep)
  315. local copy = {}
  316. for k, v in pairs(object) do
  317. if deep and type(v) == "table" then
  318. v = clone(v, deep)
  319. end
  320. copy[k] = v
  321. end
  322. return setmetatable(copy, getmetatable(object))
  323. end
  324. -- Serialize the contents of a table value.
  325. function _serialize_table(t, seen)
  326. assert(not seen[t], "Recursion detected.")
  327. seen[t] = true
  328. local data = ""
  329. local idata = ""
  330. local ilen = 0
  331. for k, v in pairs(t) do
  332. if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then
  333. k = serialize_data(k, seen)
  334. v = serialize_data(v, seen)
  335. data = data .. ( #data > 0 and ", " or "" ) ..
  336. '[' .. k .. '] = ' .. v
  337. elseif k > ilen then
  338. ilen = k
  339. end
  340. end
  341. for i = 1, ilen do
  342. local v = serialize_data(t[i], seen)
  343. idata = idata .. ( #idata > 0 and ", " or "" ) .. v
  344. end
  345. return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data
  346. end
  347. -- with loadstring().
  348. function serialize_data(val, seen)
  349. seen = seen or setmetatable({}, {__mode="k"})
  350. if val == nil then
  351. return "nil"
  352. elseif type(val) == "number" then
  353. return val
  354. elseif type(val) == "string" then
  355. return "%q" % val
  356. elseif type(val) == "boolean" then
  357. return val and "true" or "false"
  358. elseif type(val) == "function" then
  359. return "loadstring(%q)" % get_bytecode(val)
  360. elseif type(val) == "table" then
  361. return "{ " .. _serialize_table(val, seen) .. " }"
  362. else
  363. return '"[unhandled data type:' .. type(val) .. ']"'
  364. end
  365. end
  366. function restore_data(str)
  367. return loadstring("return " .. str)()
  368. end
  369. --
  370. -- Byte code manipulation routines
  371. --
  372. -- will be stripped before it is returned.
  373. function get_bytecode(val)
  374. local code
  375. if type(val) == "function" then
  376. code = string.dump(val)
  377. else
  378. code = string.dump( loadstring( "return " .. serialize_data(val) ) )
  379. end
  380. return code -- and strip_bytecode(code)
  381. end
  382. -- numbers and debugging numbers will be discarded. Original version by
  383. -- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html)
  384. function strip_bytecode(code)
  385. local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12)
  386. local subint
  387. if endian == 1 then
  388. subint = function(code, i, l)
  389. local val = 0
  390. for n = l, 1, -1 do
  391. val = val * 256 + code:byte(i + n - 1)
  392. end
  393. return val, i + l
  394. end
  395. else
  396. subint = function(code, i, l)
  397. local val = 0
  398. for n = 1, l, 1 do
  399. val = val * 256 + code:byte(i + n - 1)
  400. end
  401. return val, i + l
  402. end
  403. end
  404. local function strip_function(code)
  405. local count, offset = subint(code, 1, size)
  406. local stripped = { string.rep("\0", size) }
  407. local dirty = offset + count
  408. offset = offset + count + int * 2 + 4
  409. offset = offset + int + subint(code, offset, int) * ins
  410. count, offset = subint(code, offset, int)
  411. for n = 1, count do
  412. local t
  413. t, offset = subint(code, offset, 1)
  414. if t == 1 then
  415. offset = offset + 1
  416. elseif t == 4 then
  417. offset = offset + size + subint(code, offset, size)
  418. elseif t == 3 then
  419. offset = offset + num
  420. elseif t == 254 or t == 9 then
  421. offset = offset + lnum
  422. end
  423. end
  424. count, offset = subint(code, offset, int)
  425. stripped[#stripped+1] = code:sub(dirty, offset - 1)
  426. for n = 1, count do
  427. local proto, off = strip_function(code:sub(offset, -1))
  428. stripped[#stripped+1] = proto
  429. offset = offset + off - 1
  430. end
  431. offset = offset + subint(code, offset, int) * int + int
  432. count, offset = subint(code, offset, int)
  433. for n = 1, count do
  434. offset = offset + subint(code, offset, size) + size + int * 2
  435. end
  436. count, offset = subint(code, offset, int)
  437. for n = 1, count do
  438. offset = offset + subint(code, offset, size) + size
  439. end
  440. stripped[#stripped+1] = string.rep("\0", int * 3)
  441. return table.concat(stripped), offset
  442. end
  443. return code:sub(1,12) .. strip_function(code:sub(13,-1))
  444. end
  445. --
  446. -- Sorting iterator functions
  447. --
  448. function _sortiter( t, f )
  449. local keys = { }
  450. local k, v
  451. for k, v in pairs(t) do
  452. keys[#keys+1] = k
  453. end
  454. local _pos = 0
  455. table.sort( keys, f )
  456. return function()
  457. _pos = _pos + 1
  458. if _pos <= #keys then
  459. return keys[_pos], t[keys[_pos]], _pos
  460. end
  461. end
  462. end
  463. -- the provided callback function.
  464. function spairs(t,f)
  465. return _sortiter( t, f )
  466. end
  467. -- The table pairs are sorted by key.
  468. function kspairs(t)
  469. return _sortiter( t )
  470. end
  471. -- The table pairs are sorted by value.
  472. function vspairs(t)
  473. return _sortiter( t, function (a,b) return t[a] < t[b] end )
  474. end
  475. --
  476. -- System utility functions
  477. --
  478. function bigendian()
  479. return string.byte(string.dump(function() end), 7) == 0
  480. end
  481. function exec(command)
  482. local pp = io.popen(command)
  483. local data = pp:read("*a")
  484. pp:close()
  485. return data
  486. end
  487. function execi(command)
  488. local pp = io.popen(command)
  489. return pp and function()
  490. local line = pp:read()
  491. if not line then
  492. pp:close()
  493. end
  494. return line
  495. end
  496. end
  497. -- Deprecated
  498. function execl(command)
  499. local pp = io.popen(command)
  500. local line = ""
  501. local data = {}
  502. while true do
  503. line = pp:read()
  504. if (line == nil) then break end
  505. data[#data+1] = line
  506. end
  507. pp:close()
  508. return data
  509. end
  510. local ubus_codes = {
  511. "INVALID_COMMAND",
  512. "INVALID_ARGUMENT",
  513. "METHOD_NOT_FOUND",
  514. "NOT_FOUND",
  515. "NO_DATA",
  516. "PERMISSION_DENIED",
  517. "TIMEOUT",
  518. "NOT_SUPPORTED",
  519. "UNKNOWN_ERROR",
  520. "CONNECTION_FAILED"
  521. }
  522. local function ubus_return(...)
  523. if select('#', ...) == 2 then
  524. local rv, err = select(1, ...), select(2, ...)
  525. if rv == nil and type(err) == "number" then
  526. return nil, err, ubus_codes[err]
  527. end
  528. end
  529. return ...
  530. end
  531. function ubus(object, method, data, path, timeout)
  532. if not _ubus_connection then
  533. _ubus_connection = _ubus.connect(path, timeout)
  534. assert(_ubus_connection, "Unable to establish ubus connection")
  535. end
  536. if object and method then
  537. if type(data) ~= "table" then
  538. data = { }
  539. end
  540. return ubus_return(_ubus_connection:call(object, method, data))
  541. elseif object then
  542. return _ubus_connection:signatures(object)
  543. else
  544. return _ubus_connection:objects()
  545. end
  546. end
  547. function serialize_json(x, cb)
  548. local js = json.stringify(x)
  549. if type(cb) == "function" then
  550. cb(js)
  551. else
  552. return js
  553. end
  554. end
  555. function libpath()
  556. return require "nixio.fs".dirname(ldebug.__file__)
  557. end
  558. function checklib(fullpathexe, wantedlib)
  559. local fs = require "nixio.fs"
  560. local haveldd = fs.access('/usr/bin/ldd')
  561. local haveexe = fs.access(fullpathexe)
  562. if not haveldd or not haveexe then
  563. return false
  564. end
  565. local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe)))
  566. if not libs then
  567. return false
  568. end
  569. for k, v in ipairs(split(libs)) do
  570. if v:find(wantedlib) then
  571. return true
  572. end
  573. end
  574. return false
  575. end
  576. -------------------------------------------------------------------------------
  577. -- Coroutine safe xpcall and pcall versions
  578. --
  579. -- Encapsulates the protected calls with a coroutine based loop, so errors can
  580. -- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines
  581. -- yielding inside the call to pcall or xpcall.
  582. --
  583. -- Authors: Roberto Ierusalimschy and Andre Carregal
  584. -- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas
  585. --
  586. -- Copyright 2005 - Kepler Project
  587. --
  588. -- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $
  589. -------------------------------------------------------------------------------
  590. -------------------------------------------------------------------------------
  591. -- Implements xpcall with coroutines
  592. -------------------------------------------------------------------------------
  593. local coromap = setmetatable({}, { __mode = "k" })
  594. local function handleReturnValue(err, co, status, ...)
  595. if not status then
  596. return false, err(debug.traceback(co, (...)), ...)
  597. end
  598. if coroutine.status(co) == 'suspended' then
  599. return performResume(err, co, coroutine.yield(...))
  600. else
  601. return true, ...
  602. end
  603. end
  604. function performResume(err, co, ...)
  605. return handleReturnValue(err, co, coroutine.resume(co, ...))
  606. end
  607. local function id(trace, ...)
  608. return trace
  609. end
  610. function coxpcall(f, err, ...)
  611. local current = coroutine.running()
  612. if not current then
  613. if err == id then
  614. return pcall(f, ...)
  615. else
  616. if select("#", ...) > 0 then
  617. local oldf, params = f, { ... }
  618. f = function() return oldf(unpack(params)) end
  619. end
  620. return xpcall(f, err)
  621. end
  622. else
  623. local res, co = pcall(coroutine.create, f)
  624. if not res then
  625. local newf = function(...) return f(...) end
  626. co = coroutine.create(newf)
  627. end
  628. coromap[co] = current
  629. return performResume(err, co, ...)
  630. end
  631. end
  632. function copcall(f, ...)
  633. return coxpcall(f, id, ...)
  634. end