ipkg.lua 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. -- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
  2. -- Copyright 2008 Steven Barth <steven@midlink.org>
  3. -- Licensed to the public under the Apache License 2.0.
  4. local os = require "os"
  5. local io = require "io"
  6. local fs = require "nixio.fs"
  7. local util = require "luci.util"
  8. local type = type
  9. local pairs = pairs
  10. local error = error
  11. local table = table
  12. local ipkg = "opkg --force-removal-of-dependent-packages --force-overwrite --nocase"
  13. local icfg = "/etc/opkg.conf"
  14. module "luci.model.ipkg"
  15. -- Internal action function
  16. local function _action(cmd, ...)
  17. local pkg = ""
  18. for k, v in pairs({...}) do
  19. pkg = pkg .. " '" .. v:gsub("'", "") .. "'"
  20. end
  21. local c = "%s %s %s >/tmp/opkg.stdout 2>/tmp/opkg.stderr" %{ ipkg, cmd, pkg }
  22. local r = os.execute(c)
  23. local e = fs.readfile("/tmp/opkg.stderr")
  24. local o = fs.readfile("/tmp/opkg.stdout")
  25. fs.unlink("/tmp/opkg.stderr")
  26. fs.unlink("/tmp/opkg.stdout")
  27. return r, o or "", e or ""
  28. end
  29. -- Internal parser function
  30. local function _parselist(rawdata)
  31. if type(rawdata) ~= "function" then
  32. error("OPKG: Invalid rawdata given")
  33. end
  34. local data = {}
  35. local c = {}
  36. local l = nil
  37. for line in rawdata do
  38. if line:sub(1, 1) ~= " " then
  39. local key, val = line:match("(.-): ?(.*)%s*")
  40. if key and val then
  41. if key == "Package" then
  42. c = {Package = val}
  43. data[val] = c
  44. elseif key == "Status" then
  45. c.Status = {}
  46. for j in val:gmatch("([^ ]+)") do
  47. c.Status[j] = true
  48. end
  49. else
  50. c[key] = val
  51. end
  52. l = key
  53. end
  54. else
  55. -- Multi-line field
  56. c[l] = c[l] .. "\n" .. line
  57. end
  58. end
  59. return data
  60. end
  61. -- Internal lookup function
  62. local function _lookup(act, pkg)
  63. local cmd = ipkg .. " " .. act
  64. if pkg then
  65. cmd = cmd .. " '" .. pkg:gsub("'", "") .. "'"
  66. end
  67. -- OPKG sometimes kills the whole machine because it sucks
  68. -- Therefore we have to use a sucky approach too and use
  69. -- tmpfiles instead of directly reading the output
  70. local tmpfile = os.tmpname()
  71. os.execute(cmd .. (" >%s 2>/dev/null" % tmpfile))
  72. local data = _parselist(io.lines(tmpfile))
  73. os.remove(tmpfile)
  74. return data
  75. end
  76. function info(pkg)
  77. return _lookup("info", pkg)
  78. end
  79. function status(pkg)
  80. return _lookup("status", pkg)
  81. end
  82. function install(...)
  83. return _action("install", ...)
  84. end
  85. function installed(pkg)
  86. local p = status(pkg)[pkg]
  87. return (p and p.Status and p.Status.installed)
  88. end
  89. function remove(...)
  90. return _action("remove", ...)
  91. end
  92. function update()
  93. return _action("update")
  94. end
  95. function upgrade()
  96. return _action("upgrade")
  97. end
  98. -- List helper
  99. function _list(action, pat, cb)
  100. local fd = io.popen(ipkg .. " " .. action ..
  101. (pat and (" '%s'" % pat:gsub("'", "")) or ""))
  102. if fd then
  103. local name, version, sz, desc
  104. while true do
  105. local line = fd:read("*l")
  106. if not line then break end
  107. name, version, sz, desc = line:match("^(.-) %- (.-) %- (.-) %- (.+)")
  108. if not name then
  109. name, version, sz = line:match("^(.-) %- (.-) %- (.+)")
  110. desc = ""
  111. end
  112. if name and version then
  113. if #version > 26 then
  114. version = version:sub(1,21) .. ".." .. version:sub(-3,-1)
  115. end
  116. cb(name, version, sz, desc)
  117. end
  118. name = nil
  119. version = nil
  120. sz = nil
  121. desc = nil
  122. end
  123. fd:close()
  124. end
  125. end
  126. function list_all(pat, cb)
  127. _list("list --size", pat, cb)
  128. end
  129. function list_installed(pat, cb)
  130. _list("list_installed --size", pat, cb)
  131. end
  132. function find(pat, cb)
  133. _list("find --size", pat, cb)
  134. end
  135. function overlay_root()
  136. local od = "/"
  137. local fd = io.open(icfg, "r")
  138. if fd then
  139. local ln
  140. repeat
  141. ln = fd:read("*l")
  142. if ln and ln:match("^%s*option%s+overlay_root%s+") then
  143. od = ln:match("^%s*option%s+overlay_root%s+(%S+)")
  144. local s = fs.stat(od)
  145. if not s or s.type ~= "dir" then
  146. od = "/"
  147. end
  148. break
  149. end
  150. until not ln
  151. fd:close()
  152. end
  153. return od
  154. end