#!/usr/bin/lua local output_file = "/tmp/debug-report.txt" -- includes local nixio = require("nixio") local json = require("luci.jsonc") local uci = require("simple-uci").cursor() local site = require "gluon.site" local util = require "gluon.util" -- usefull variables local hostname = require("pretty_hostname").get(uci) local primary_mac = require("gluon.sysconfig").primary_mac local model = require("gluon.platform").get_model() local version = util.trim(io.open("/lib/gluon/gluon-version"):read("*a")) local release = util.trim(io.open("/lib/gluon/release"):read("*a")) -- get autoupdater branch local function autoupdate() local autoupdate = uci:get("autoupdater", "settings", "branch") if not uci:get_bool("autoupdater", "settings", "enabled") then autoupdate = "disabled (" .. autoupdater .. ")" end return autoupdate end -- get mesh IPs local function addresses() local addr = {} for line in io.popen("ip -family inet6 address show dev br-client"):lines() do local tmp = line:match("inet6%s+(%S+)%s+scope") or false if tmp then table.insert(addr, tmp) end end return addr end -- get memory usage local function memory() local fields = {} for k, v in io.open("/proc/meminfo"):read("*a"):gmatch("([^\n:]+):%s*(%d+) kB") do fields[k] = tonumber(v) end return string.format("%.1f %% used, %.1f %% free",(fields.MemTotal-fields.MemFree)/fields.MemTotal*100,fields.MemFree/fields.MemTotal*100) end -- get fastd public key local function pubkey() local key = util.trim(io.popen("/etc/init.d/fastd show_key mesh_vpn"):read("*a")) if key == "" then return "none" end return key end -- get location local function location() local text = "none" local locationid = uci:get_first("gluon-node-info", "location") if locationid then local location = uci:get_all("gluon-node-info", locationid) if uci:get_bool("gluon-node-info", locationid, "share_location") and location.latitude and location.longitude then text = location.latitude .. ", " .. location.longitude end end return text end -- get ip address type local function ip_proto(address) if address:match("%.") then return "IPv4" end if address:match(":") then return "IPv6" end return "???" end -- wrapper for calling systemcommands local function cmd(command) local l = io.popen(command .. " 2>&1"):read("*a") return "\n# " .. command .. "\n" .. l end -- read contents of a given file local function read_file(file) local l = io.open(file, "r"):read("*a") return "\n" .. file .. ":\n" .. l end -- blank variables local function blank(string, key) string = string:gsub(key .. "[^\n]+", key .. " -blanked-") return string end -- open output file in write mode print("Generating report ...") local out = io.open(output_file, "w") -- first of all, collect some generic information about the system out:write("---- BEGIN SYSTEM INFORMATION ----") out:write("\nHostname: " .. hostname) out:write("\nCommunity: " .. site.site_name()) out:write("\nModel: " .. model) out:write("\nFirmware: " .. release .. " / " .. version) out:write("\nMAC: " .. primary_mac) out:write("\nContact: " .. uci:get_first("gluon-node-info", "owner", "contact", "none")) out:write("\nUptime: " .. util.trim(io.popen("uptime"):read("*a"))) out:write("\nAutoupdater: " .. autoupdate()) out:write("\nLocation: " .. location()) out:write("\nIPs: " .. table.concat(addresses(), "\n ")) out:write("\nPubkey: " .. pubkey()) out:write("\nMemory: " .. memory()) out:write("\n---- END SYSTEM INFORMATION ----\n\n") -- show cron jobs out:write("---- BEGIN CRON JOBS ----") for name in io.popen("ls /usr/lib/micron.d/"):lines() do out:write(read_file("/usr/lib/micron.d/" .. name)) end out:write("---- END CRON JOBS ----\n\n") -- get autoupdater status out:write("---- BEGIN AUTOUPDATER INFORMATION ----") out:write(cmd("uci show autoupdater")) out:write(cmd("uci show autoupdater-wifi-fallback")) out:write("---- END AUTOUPDATER INFORMATION ----\n\n") -- now get some information about the network status out:write("---- BEGIN IP AND ROUTUNG INFORMATION ----") out:write(cmd("uci show network")) out:write(cmd("ip addr show")) out:write(cmd("ip route show")) out:write(cmd("ip -6 route show")) out:write("---- END IP AND ROUTUNG INFORMATION ----\n\n") -- get wireless status out:write("---- BEGIN WIRELESS INFORMATION ----") out:write(blank(cmd("uci show wireless"), "\.key=")) for ifname in io.popen("iw dev"):read("*a"):gmatch("Interface%s([^\n]+)") do out:write(cmd("iwinfo " .. ifname .. " info")) if ifname:match("ibss") or ifname:match("mesh") then out:write(cmd("iwinfo " .. ifname .. " assoclist 2>&1")) end end out:write("---- END WIRELESS INFORMATION ----\n\n") -- get batman status out:write("---- BEGIN BATMAN STATUS ----") out:write(cmd("uci show batman-adv")) out:write(cmd("batctl gateways")) out:write(cmd("batctl neighbors")) out:write(cmd("batctl interface")) out:write("---- END BATMAN STATUS ----\n\n") -- get fastd status out:write("---- BEGIN FASTD STATUS ----") out:write(blank(cmd("uci show fastd"), "\.secret=")) out:write(cmd("uci show simple-tc")) local stat, fastd_status = pcall( function() local fastd_sock = nixio.socket("unix", "stream") assert(fastd_sock:connect("/var/run/fastd.mesh_vpn.socket")) local decoder = json.new() local sink = decoder:sink() while true do local chunk = fastd_sock:read(2048) if not chunk or chunk:len() == 0 then break end sink(chunk) end return assert(decoder:get()) end ) if stat then out:write(string.format("\nfastd running for %.1f minutes\n", fastd_status.uptime/60000)) local peers = 0 local connections = 0 for key, peer in pairs(fastd_status.peers) do peers = peers + 1 if peer.connection then connections = connections + 1 end end out:write(string.format("There are %i peers configured, of which %i are connected:\n", peers, connections)) for key, peer in pairs(fastd_status.peers) do out:write(peer.name .. ": ") if peer.connection then out:write(string.format("connected for %.1f minutes via %s\n", peer.connection.established/60000, ip_proto(peer.address))) else out:write("not connected\n") end end else out:write("\nfastd not running\n") end out:write("---- END FASTD STATUS ----\n\n") -- get processes out:write("---- BEGIN PROCESS INFORMATION ----") out:write(cmd("ps ww")) out:write("---- END PROCESS INFORMATION ----\n\n") -- get log out:write("---- BEGIN LOG ----") out:write(cmd("logread")) out:write(cmd("dmesg")) out:write("---- END LOG ----\n\n") -- finish, close file and inform the user out:close() print("Your report has been stored at: " .. output_file ) os.exit(0)