debug-report 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224
  1. #!/usr/bin/lua
  2. local output_file = "/tmp/debug-report.txt"
  3. -- includes
  4. local nixio = require("nixio")
  5. local json = require("luci.jsonc")
  6. local uci = require("simple-uci").cursor()
  7. local site = require "gluon.site_config"
  8. local util = require "gluon.util"
  9. -- usefull variables
  10. local hostname = require("pretty_hostname").get(uci)
  11. local primary_mac = require("gluon.sysconfig").primary_mac
  12. local model = require("gluon.platform").get_model()
  13. local version = util.trim(io.open("/lib/gluon/gluon-version"):read("*a"))
  14. local release = util.trim(io.open("/lib/gluon/release"):read("*a"))
  15. -- get autoupdater branch
  16. local function autoupdate()
  17. local autoupdate = uci:get("autoupdater", "settings", "branch")
  18. if not uci:get_bool("autoupdater", "settings", "enabled") then
  19. autoupdate = "disabled (" .. autoupdater .. ")"
  20. end
  21. return autoupdate
  22. end
  23. -- get mesh IPs
  24. local function addresses()
  25. local addr = {}
  26. for line in io.popen("ip -family inet6 address show dev br-client"):lines() do
  27. local tmp = line:match("inet6%s+(%S+)%s+scope") or false
  28. if tmp then
  29. table.insert(addr, tmp)
  30. end
  31. end
  32. return addr
  33. end
  34. -- get memory usage
  35. local function memory()
  36. local fields = {}
  37. for k, v in io.open("/proc/meminfo"):read("*a"):gmatch("([^\n:]+):%s*(%d+) kB") do
  38. fields[k] = tonumber(v)
  39. end
  40. return string.format("%.1f %% used, %.1f %% free",(fields.MemTotal-fields.MemFree)/fields.MemTotal*100,fields.MemFree/fields.MemTotal*100)
  41. end
  42. -- get fastd public key
  43. local function pubkey()
  44. local key = util.trim(io.popen("/etc/init.d/fastd show_key mesh_vpn"):read("*a"))
  45. if key == "" then
  46. return "none"
  47. end
  48. return key
  49. end
  50. -- get location
  51. local function location()
  52. local text = "none"
  53. local locationid = uci:get_first("gluon-node-info", "location")
  54. if locationid then
  55. local location = uci:get_all("gluon-node-info", locationid)
  56. if uci:get_bool("gluon-node-info", locationid, "share_location") and location.latitude and location.longitude then
  57. text = location.latitude .. ", " .. location.longitude
  58. end
  59. end
  60. return text
  61. end
  62. -- get ip address type
  63. local function ip_proto(address)
  64. if address:match("%.") then
  65. return "IPv4"
  66. end
  67. if address:match(":") then
  68. return "IPv6"
  69. end
  70. return "???"
  71. end
  72. -- wrapper for calling systemcommands
  73. local function cmd(command)
  74. local l = io.popen(command .. " 2>&1"):read("*a")
  75. return "\n# " .. command .. "\n" .. l
  76. end
  77. -- read contents of a given file
  78. local function read_file(file)
  79. local l = io.open(file, "r"):read("*a")
  80. return "\n" .. file .. ":\n" .. l
  81. end
  82. -- blank variables
  83. local function blank(string, key)
  84. string = string:gsub(key .. "[^\n]+", key .. " -blanked-")
  85. return string
  86. end
  87. -- open output file in write mode
  88. print("Generating report ...")
  89. local out = io.open(output_file, "w")
  90. -- first of all, collect some generic information about the system
  91. out:write("---- BEGIN SYSTEM INFORMATION ----")
  92. out:write("\nHostname: " .. hostname)
  93. out:write("\nCommunity: " .. site.site_name)
  94. out:write("\nModel: " .. model)
  95. out:write("\nFirmware: " .. release .. " / " .. version)
  96. out:write("\nMAC: " .. primary_mac)
  97. out:write("\nContact: " .. uci:get_first("gluon-node-info", "owner", "contact", "none"))
  98. out:write("\nUptime: " .. util.trim(io.popen("uptime"):read("*a")))
  99. out:write("\nAutoupdater: " .. autoupdate())
  100. out:write("\nLocation: " .. location())
  101. out:write("\nIPs: " .. table.concat(addresses(), "\n "))
  102. out:write("\nPubkey: " .. pubkey())
  103. out:write("\nMemory: " .. memory())
  104. out:write("\n---- END SYSTEM INFORMATION ----\n\n")
  105. -- show cron jobs
  106. out:write("---- BEGIN CRON JOBS ----")
  107. for name in io.popen("ls /usr/lib/micron.d/"):lines() do
  108. out:write(read_file("/usr/lib/micron.d/" .. name))
  109. end
  110. out:write("---- END CRON JOBS ----\n\n")
  111. -- get autoupdater status
  112. out:write("---- BEGIN AUTOUPDATER INFORMATION ----")
  113. out:write(cmd("uci show autoupdater"))
  114. out:write(cmd("uci show autoupdater-wifi-fallback"))
  115. out:write("---- END AUTOUPDATER INFORMATION ----\n\n")
  116. -- now get some information about the network status
  117. out:write("---- BEGIN IP AND ROUTUNG INFORMATION ----")
  118. out:write(cmd("uci show network"))
  119. out:write(cmd("ip addr show"))
  120. out:write(cmd("ip route show"))
  121. out:write(cmd("ip -6 route show"))
  122. out:write("---- END IP AND ROUTUNG INFORMATION ----\n\n")
  123. -- get wireless status
  124. out:write("---- BEGIN WIRELESS INFORMATION ----")
  125. out:write(blank(cmd("uci show wireless"), "\.key="))
  126. for ifname in io.popen("iw dev"):read("*a"):gmatch("Interface%s([^\n]+)") do
  127. out:write(cmd("iwinfo " .. ifname .. " info"))
  128. if ifname:match("ibss") or ifname:match("mesh") then
  129. out:write(cmd("iwinfo " .. ifname .. " assoclist 2>&1"))
  130. end
  131. end
  132. out:write("---- END WIRELESS INFORMATION ----\n\n")
  133. -- get batman status
  134. out:write("---- BEGIN BATMAN STATUS ----")
  135. out:write(cmd("uci show batman-adv"))
  136. out:write(cmd("batctl gateways"))
  137. out:write(cmd("batctl neighbors"))
  138. out:write(cmd("batctl interface"))
  139. out:write("---- END BATMAN STATUS ----\n\n")
  140. -- get fastd status
  141. out:write("---- BEGIN FASTD STATUS ----")
  142. out:write(blank(cmd("uci show fastd"), "\.secret="))
  143. out:write(cmd("uci show simple-tc"))
  144. local stat, fastd_status = pcall(
  145. function()
  146. local fastd_sock = nixio.socket("unix", "stream")
  147. assert(fastd_sock:connect("/var/run/fastd.mesh_vpn.socket"))
  148. local decoder = json.new()
  149. local sink = decoder:sink()
  150. while true do
  151. local chunk = fastd_sock:read(2048)
  152. if not chunk or chunk:len() == 0 then break end
  153. sink(chunk)
  154. end
  155. return assert(decoder:get())
  156. end
  157. )
  158. if stat then
  159. out:write(string.format("\nfastd running for %.1f minutes\n", fastd_status.uptime/60000))
  160. local peers = 0
  161. local connections = 0
  162. for key, peer in pairs(fastd_status.peers) do
  163. peers = peers + 1
  164. if peer.connection then
  165. connections = connections + 1
  166. end
  167. end
  168. out:write(string.format("There are %i peers configured, of which %i are connected:\n", peers, connections))
  169. for key, peer in pairs(fastd_status.peers) do
  170. out:write(peer.name .. ": ")
  171. if peer.connection then
  172. out:write(string.format("connected for %.1f minutes via %s\n", peer.connection.established/60000, ip_proto(peer.address)))
  173. else
  174. out:write("not connected\n")
  175. end
  176. end
  177. else
  178. out:write("\nfastd not running\n")
  179. end
  180. out:write("---- END FASTD STATUS ----\n\n")
  181. -- get processes
  182. out:write("---- BEGIN PROCESS INFORMATION ----")
  183. out:write(cmd("ps ww"))
  184. out:write("---- END PROCESS INFORMATION ----\n\n")
  185. -- get log
  186. out:write("---- BEGIN LOG ----")
  187. out:write(cmd("logread"))
  188. out:write(cmd("dmesg"))
  189. out:write("---- END LOG ----\n\n")
  190. -- finish, close file and inform the user
  191. out:close()
  192. print("Your report has been stored at: " .. output_file )
  193. os.exit(0)