failsafe.lua 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. -- Copyright 2008 Steven Barth <steven@midlink.org>
  2. -- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org>
  3. -- Copyright 2012 Daniel Golle <dgolle@allnet.de>
  4. -- Licensed to the public under the Apache License 2.0.
  5. module("luci.controller.failsafe.failsafe", package.seeall)
  6. function index()
  7. local root = node()
  8. if not root.target then
  9. root.target = alias("failsafe")
  10. root.index = true
  11. end
  12. page = node()
  13. page.lock = true
  14. page.target = alias("failsafe")
  15. page.subindex = true
  16. page.index = false
  17. page = node("failsafe")
  18. page.title = _("Fail-safe")
  19. page.target = alias("failsafe", "flashops")
  20. page.order = 5
  21. page.setuser = "root"
  22. page.setgroup = "root"
  23. page.index = true
  24. entry({"failsafe", "flashops"}, call("action_flashops"), _("Flash Firmware"), 70).index = true
  25. entry({"failsafe", "reboot"}, call("action_reboot"), _("Reboot"), 90)
  26. end
  27. function action_flashops()
  28. local sys = require "luci.sys"
  29. local fs = require "nixio.fs"
  30. local upgrade_avail = fs.access("/lib/upgrade/platform.sh")
  31. local reset_avail = os.execute([[grep '"rootfs_data"' /proc/mtd >/dev/null 2>&1]]) == 0
  32. local image_tmp = "/tmp/firmware.img"
  33. local function image_supported()
  34. -- XXX: yay...
  35. return ( 0 == os.execute(
  36. ". /lib/functions.sh; " ..
  37. "include /lib/upgrade; " ..
  38. "platform_check_image %q >/dev/null"
  39. % image_tmp
  40. ) )
  41. end
  42. local function image_checksum()
  43. return (luci.sys.exec("md5sum %q" % image_tmp):match("^([^%s]+)"))
  44. end
  45. local function storage_size()
  46. local size = 0
  47. if fs.access("/proc/mtd") then
  48. for l in io.lines("/proc/mtd") do
  49. local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"')
  50. if n == "linux" or n == "firmware" then
  51. size = tonumber(s, 16)
  52. break
  53. end
  54. end
  55. elseif fs.access("/proc/partitions") then
  56. for l in io.lines("/proc/partitions") do
  57. local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)')
  58. if b and n and not n:match('[0-9]') then
  59. size = tonumber(b) * 1024
  60. break
  61. end
  62. end
  63. end
  64. return size
  65. end
  66. local fp
  67. luci.http.setfilehandler(
  68. function(meta, chunk, eof)
  69. if not fp then
  70. if meta and meta.name == "image" then
  71. fp = io.open(image_tmp, "w")
  72. end
  73. end
  74. if fp then
  75. if chunk then
  76. fp:write(chunk)
  77. end
  78. if eof then
  79. fp:close()
  80. end
  81. end
  82. end
  83. )
  84. if luci.http.formvalue("image") or luci.http.formvalue("step") then
  85. --
  86. -- Initiate firmware flash
  87. --
  88. local step = tonumber(luci.http.formvalue("step") or 1)
  89. if step == 1 then
  90. if image_supported() then
  91. luci.template.render("failsafe/upgrade", {
  92. checksum = image_checksum(),
  93. storage = storage_size(),
  94. size = (fs.stat(image_tmp, "size") or 0),
  95. keep = false
  96. })
  97. else
  98. fs.unlink(image_tmp)
  99. luci.template.render("failsafe/flashops", {
  100. reset_avail = reset_avail,
  101. upgrade_avail = upgrade_avail,
  102. image_invalid = true
  103. })
  104. end
  105. --
  106. -- Start sysupgrade flash
  107. --
  108. elseif step == 2 then
  109. local keep = (luci.http.formvalue("keep") == "1") and "" or "-n"
  110. luci.template.render("failsafe/applyreboot", {
  111. title = luci.i18n.translate("Flashing..."),
  112. msg = luci.i18n.translate("The system is flashing now.<br /> DO NOT POWER OFF THE DEVICE!<br /> Wait a few minutes before you try to reconnect. It might be necessary to renew the address of your computer to reach the device again, depending on your settings."),
  113. addr = (#keep > 0) and "192.168.1.1" or nil
  114. })
  115. fork_exec("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %q" %{ keep, image_tmp })
  116. end
  117. else
  118. --
  119. -- Overview
  120. --
  121. luci.template.render("failsafe/flashops", {
  122. reset_avail = reset_avail,
  123. upgrade_avail = upgrade_avail
  124. })
  125. end
  126. end
  127. function action_reboot()
  128. local reboot = luci.http.formvalue("reboot")
  129. luci.template.render("failsafe/reboot", {reboot=reboot})
  130. if reboot then
  131. luci.sys.reboot()
  132. end
  133. end
  134. function fork_exec(command)
  135. local pid = nixio.fork()
  136. if pid > 0 then
  137. return
  138. elseif pid == 0 then
  139. -- change to root dir
  140. nixio.chdir("/")
  141. -- patch stdin, out, err to /dev/null
  142. local null = nixio.open("/dev/null", "w+")
  143. if null then
  144. nixio.dup(null, nixio.stderr)
  145. nixio.dup(null, nixio.stdout)
  146. nixio.dup(null, nixio.stdin)
  147. if null:fileno() > 2 then
  148. null:close()
  149. end
  150. end
  151. -- replace with target command
  152. nixio.exec("/bin/sh", "-c", command)
  153. end
  154. end
  155. function ltn12_popen(command)
  156. local fdi, fdo = nixio.pipe()
  157. local pid = nixio.fork()
  158. if pid > 0 then
  159. fdo:close()
  160. local close
  161. return function()
  162. local buffer = fdi:read(2048)
  163. local wpid, stat = nixio.waitpid(pid, "nohang")
  164. if not close and wpid and stat == "exited" then
  165. close = true
  166. end
  167. if buffer and #buffer > 0 then
  168. return buffer
  169. elseif close then
  170. fdi:close()
  171. return nil
  172. end
  173. end
  174. elseif pid == 0 then
  175. nixio.dup(fdo, nixio.stdout)
  176. fdi:close()
  177. fdo:close()
  178. nixio.exec("/bin/sh", "-c", command)
  179. end
  180. end