1
0

util.lua 17 KB

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