diff options
Diffstat (limited to 'modules/luci-mod-admin-full/luasrc/controller/admin')
6 files changed, 1166 insertions, 0 deletions
diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/filebrowser.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/filebrowser.lua new file mode 100644 index 0000000000..d83139fd70 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/filebrowser.lua @@ -0,0 +1,20 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> +Copyright 2008 Jo-Philipp Wich <xm@leipzig.freifunk.net> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.filebrowser", package.seeall) + +function index() + entry( {"admin", "filebrowser"}, template("cbi/filebrowser") ).leaf = true +end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/index.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/index.lua new file mode 100644 index 0000000000..4e832529d9 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/index.lua @@ -0,0 +1,49 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.index", package.seeall) + +function index() + local root = node() + if not root.target then + root.target = alias("admin") + root.index = true + end + + local page = node("admin") + page.target = firstchild() + page.title = _("Administration") + page.order = 10 + page.sysauth = "root" + page.sysauth_authenticator = "htmlauth" + page.ucidata = true + page.index = true + + -- Empty services menu to be populated by addons + entry({"admin", "services"}, firstchild(), _("Services"), 40).index = true + + entry({"admin", "logout"}, call("action_logout"), _("Logout"), 90) +end + +function action_logout() + local dsp = require "luci.dispatcher" + local sauth = require "luci.sauth" + if dsp.context.authsession then + sauth.kill(dsp.context.authsession) + dsp.context.urltoken.stok = nil + end + + luci.http.header("Set-Cookie", "sysauth=; path=" .. dsp.build_url()) + luci.http.redirect(luci.dispatcher.build_url()) +end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua new file mode 100644 index 0000000000..4388864eb1 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/network.lua @@ -0,0 +1,465 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> +Copyright 2011 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +]]-- + +module("luci.controller.admin.network", package.seeall) + +function index() + local uci = require("luci.model.uci").cursor() + local page + + page = node("admin", "network") + page.target = firstchild() + page.title = _("Network") + page.order = 50 + page.index = true + +-- if page.inreq then + local has_switch = false + + uci:foreach("network", "switch", + function(s) + has_switch = true + return false + end) + + if has_switch then + page = node("admin", "network", "vlan") + page.target = cbi("admin_network/vlan") + page.title = _("Switch") + page.order = 20 + + page = entry({"admin", "network", "switch_status"}, call("switch_status"), nil) + page.leaf = true + end + + + local has_wifi = false + + uci:foreach("wireless", "wifi-device", + function(s) + has_wifi = true + return false + end) + + if has_wifi then + page = entry({"admin", "network", "wireless_join"}, call("wifi_join"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_add"}, call("wifi_add"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_delete"}, call("wifi_delete"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_status"}, call("wifi_status"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_reconnect"}, call("wifi_reconnect"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless_shutdown"}, call("wifi_shutdown"), nil) + page.leaf = true + + page = entry({"admin", "network", "wireless"}, arcombine(template("admin_network/wifi_overview"), cbi("admin_network/wifi")), _("Wifi"), 15) + page.leaf = true + page.subindex = true + + if page.inreq then + local wdev + local net = require "luci.model.network".init(uci) + for _, wdev in ipairs(net:get_wifidevs()) do + local wnet + for _, wnet in ipairs(wdev:get_wifinets()) do + entry( + {"admin", "network", "wireless", wnet:id()}, + alias("admin", "network", "wireless"), + wdev:name() .. ": " .. wnet:shortname() + ) + end + end + end + end + + + page = entry({"admin", "network", "iface_add"}, cbi("admin_network/iface_add"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_delete"}, call("iface_delete"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_status"}, call("iface_status"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_reconnect"}, call("iface_reconnect"), nil) + page.leaf = true + + page = entry({"admin", "network", "iface_shutdown"}, call("iface_shutdown"), nil) + page.leaf = true + + page = entry({"admin", "network", "network"}, arcombine(cbi("admin_network/network"), cbi("admin_network/ifaces")), _("Interfaces"), 10) + page.leaf = true + page.subindex = true + + if page.inreq then + uci:foreach("network", "interface", + function (section) + local ifc = section[".name"] + if ifc ~= "loopback" then + entry({"admin", "network", "network", ifc}, + true, ifc:upper()) + end + end) + end + + + if nixio.fs.access("/etc/config/dhcp") then + page = node("admin", "network", "dhcp") + page.target = cbi("admin_network/dhcp") + page.title = _("DHCP and DNS") + page.order = 30 + + page = entry({"admin", "network", "dhcplease_status"}, call("lease_status"), nil) + page.leaf = true + + page = node("admin", "network", "hosts") + page.target = cbi("admin_network/hosts") + page.title = _("Hostnames") + page.order = 40 + end + + page = node("admin", "network", "routes") + page.target = cbi("admin_network/routes") + page.title = _("Static Routes") + page.order = 50 + + page = node("admin", "network", "diagnostics") + page.target = template("admin_network/diagnostics") + page.title = _("Diagnostics") + page.order = 60 + + page = entry({"admin", "network", "diag_ping"}, call("diag_ping"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_nslookup"}, call("diag_nslookup"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_traceroute"}, call("diag_traceroute"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_ping6"}, call("diag_ping6"), nil) + page.leaf = true + + page = entry({"admin", "network", "diag_traceroute6"}, call("diag_traceroute6"), nil) + page.leaf = true +-- end +end + +function wifi_join() + local function param(x) + return luci.http.formvalue(x) + end + + local function ptable(x) + x = param(x) + return x and (type(x) ~= "table" and { x } or x) or {} + end + + local dev = param("device") + local ssid = param("join") + + if dev and ssid then + local cancel = (param("cancel") or param("cbi.cancel")) and true or false + + if cancel then + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless_join?device=" .. dev)) + else + local cbi = require "luci.cbi" + local tpl = require "luci.template" + local map = luci.cbi.load("admin_network/wifi_add")[1] + + if map:parse() ~= cbi.FORM_DONE then + tpl.render("header") + map:render() + tpl.render("footer") + end + end + else + luci.template.render("admin_network/wifi_join") + end +end + +function wifi_add() + local dev = luci.http.formvalue("device") + local ntm = require "luci.model.network".init() + + dev = dev and ntm:get_wifidev(dev) + + if dev then + local net = dev:add_wifinet({ + mode = "ap", + ssid = "OpenWrt", + encryption = "none" + }) + + ntm:save("wireless") + luci.http.redirect(net:adminlink()) + end +end + +function wifi_delete(network) + local ntm = require "luci.model.network".init() + local wnet = ntm:get_wifinet(network) + if wnet then + local dev = wnet:get_device() + local nets = wnet:get_networks() + if dev then + ntm:del_wifinet(network) + ntm:commit("wireless") + local _, net + for _, net in ipairs(nets) do + if net:is_empty() then + ntm:del_network(net:name()) + ntm:commit("network") + end + end + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null") + end + end + + luci.http.redirect(luci.dispatcher.build_url("admin/network/wireless")) +end + +function iface_status(ifaces) + local netm = require "luci.model.network".init() + local rv = { } + + local iface + for iface in ifaces:gmatch("[%w%.%-_]+") do + local net = netm:get_network(iface) + local device = net and net:get_interface() + if device then + local data = { + id = iface, + proto = net:proto(), + uptime = net:uptime(), + gwaddr = net:gwaddr(), + dnsaddrs = net:dnsaddrs(), + name = device:shortname(), + type = device:type(), + ifname = device:name(), + macaddr = device:mac(), + is_up = device:is_up(), + rx_bytes = device:rx_bytes(), + tx_bytes = device:tx_bytes(), + rx_packets = device:rx_packets(), + tx_packets = device:tx_packets(), + + ipaddrs = { }, + ip6addrs = { }, + subdevices = { } + } + + local _, a + for _, a in ipairs(device:ipaddrs()) do + data.ipaddrs[#data.ipaddrs+1] = { + addr = a:host():string(), + netmask = a:mask():string(), + prefix = a:prefix() + } + end + for _, a in ipairs(device:ip6addrs()) do + if not a:is6linklocal() then + data.ip6addrs[#data.ip6addrs+1] = { + addr = a:host():string(), + netmask = a:mask():string(), + prefix = a:prefix() + } + end + end + + for _, device in ipairs(net:get_interfaces() or {}) do + data.subdevices[#data.subdevices+1] = { + name = device:shortname(), + type = device:type(), + ifname = device:name(), + macaddr = device:mac(), + macaddr = device:mac(), + is_up = device:is_up(), + rx_bytes = device:rx_bytes(), + tx_bytes = device:tx_bytes(), + rx_packets = device:rx_packets(), + tx_packets = device:tx_packets(), + } + end + + rv[#rv+1] = data + else + rv[#rv+1] = { + id = iface, + name = iface, + type = "ethernet" + } + end + end + + if #rv > 0 then + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + return + end + + luci.http.status(404, "No such device") +end + +function iface_reconnect(iface) + local netmd = require "luci.model.network".init() + local net = netmd:get_network(iface) + if net then + luci.sys.call("env -i /sbin/ifup %q >/dev/null 2>/dev/null" % iface) + luci.http.status(200, "Reconnected") + return + end + + luci.http.status(404, "No such interface") +end + +function iface_shutdown(iface) + local netmd = require "luci.model.network".init() + local net = netmd:get_network(iface) + if net then + luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.http.status(200, "Shutdown") + return + end + + luci.http.status(404, "No such interface") +end + +function iface_delete(iface) + local netmd = require "luci.model.network".init() + local net = netmd:del_network(iface) + if net then + luci.sys.call("env -i /sbin/ifdown %q >/dev/null 2>/dev/null" % iface) + luci.http.redirect(luci.dispatcher.build_url("admin/network/network")) + netmd:commit("network") + netmd:commit("wireless") + return + end + + luci.http.status(404, "No such interface") +end + +function wifi_status(devs) + local s = require "luci.tools.status" + local rv = { } + + local dev + for dev in devs:gmatch("[%w%.%-]+") do + rv[#rv+1] = s.wifi_network(dev) + end + + if #rv > 0 then + luci.http.prepare_content("application/json") + luci.http.write_json(rv) + return + end + + luci.http.status(404, "No such device") +end + +local function wifi_reconnect_shutdown(shutdown, wnet) + local netmd = require "luci.model.network".init() + local net = netmd:get_wifinet(wnet) + local dev = net:get_device() + if dev and net then + dev:set("disabled", nil) + net:set("disabled", shutdown and 1 or nil) + netmd:commit("wireless") + + luci.sys.call("env -i /bin/ubus call network reload >/dev/null 2>/dev/null") + luci.http.status(200, shutdown and "Shutdown" or "Reconnected") + + return + end + + luci.http.status(404, "No such radio") +end + +function wifi_reconnect(wnet) + wifi_reconnect_shutdown(false, wnet) +end + +function wifi_shutdown(wnet) + wifi_reconnect_shutdown(true, wnet) +end + +function lease_status() + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write('[') + luci.http.write_json(s.dhcp_leases()) + luci.http.write(',') + luci.http.write_json(s.dhcp6_leases()) + luci.http.write(']') +end + +function switch_status(switches) + local s = require "luci.tools.status" + + luci.http.prepare_content("application/json") + luci.http.write_json(s.switch_status(switches)) +end + +function diag_command(cmd, addr) + if addr and addr:match("^[a-zA-Z0-9%-%.:_]+$") then + luci.http.prepare_content("text/plain") + + local util = io.popen(cmd % addr) + if util then + while true do + local ln = util:read("*l") + if not ln then break end + luci.http.write(ln) + luci.http.write("\n") + end + + util:close() + end + + return + end + + luci.http.status(500, "Bad address") +end + +function diag_ping(addr) + diag_command("ping -c 5 -W 1 %q 2>&1", addr) +end + +function diag_traceroute(addr) + diag_command("traceroute -q 1 -w 1 -n %q 2>&1", addr) +end + +function diag_nslookup(addr) + diag_command("nslookup %q 2>&1", addr) +end + +function diag_ping6(addr) + diag_command("ping6 -c 5 %q 2>&1", addr) +end + +function diag_traceroute6(addr) + diag_command("traceroute6 -q 1 -w 2 -n %q 2>&1", addr) +end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua new file mode 100644 index 0000000000..89ebda7353 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/status.lua @@ -0,0 +1,164 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> +Copyright 2011 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.status", package.seeall) + +function index() + entry({"admin", "status"}, alias("admin", "status", "overview"), _("Status"), 20).index = true + entry({"admin", "status", "overview"}, template("admin_status/index"), _("Overview"), 1) + entry({"admin", "status", "iptables"}, call("action_iptables"), _("Firewall"), 2).leaf = true + entry({"admin", "status", "routes"}, template("admin_status/routes"), _("Routes"), 3) + entry({"admin", "status", "syslog"}, call("action_syslog"), _("System Log"), 4) + entry({"admin", "status", "dmesg"}, call("action_dmesg"), _("Kernel Log"), 5) + entry({"admin", "status", "processes"}, cbi("admin_status/processes"), _("Processes"), 6) + + entry({"admin", "status", "realtime"}, alias("admin", "status", "realtime", "load"), _("Realtime Graphs"), 7) + + entry({"admin", "status", "realtime", "load"}, template("admin_status/load"), _("Load"), 1).leaf = true + entry({"admin", "status", "realtime", "load_status"}, call("action_load")).leaf = true + + entry({"admin", "status", "realtime", "bandwidth"}, template("admin_status/bandwidth"), _("Traffic"), 2).leaf = true + entry({"admin", "status", "realtime", "bandwidth_status"}, call("action_bandwidth")).leaf = true + + entry({"admin", "status", "realtime", "wireless"}, template("admin_status/wireless"), _("Wireless"), 3).leaf = true + entry({"admin", "status", "realtime", "wireless_status"}, call("action_wireless")).leaf = true + + entry({"admin", "status", "realtime", "connections"}, template("admin_status/connections"), _("Connections"), 4).leaf = true + entry({"admin", "status", "realtime", "connections_status"}, call("action_connections")).leaf = true + + entry({"admin", "status", "nameinfo"}, call("action_nameinfo")).leaf = true +end + +function action_syslog() + local syslog = luci.sys.syslog() + luci.template.render("admin_status/syslog", {syslog=syslog}) +end + +function action_dmesg() + local dmesg = luci.sys.dmesg() + luci.template.render("admin_status/dmesg", {dmesg=dmesg}) +end + +function action_iptables() + if luci.http.formvalue("zero") then + if luci.http.formvalue("zero") == "6" then + luci.util.exec("ip6tables -Z") + else + luci.util.exec("iptables -Z") + end + luci.http.redirect( + luci.dispatcher.build_url("admin", "status", "iptables") + ) + elseif luci.http.formvalue("restart") == "1" then + luci.util.exec("/etc/init.d/firewall reload") + luci.http.redirect( + luci.dispatcher.build_url("admin", "status", "iptables") + ) + else + luci.template.render("admin_status/iptables") + end +end + +function action_bandwidth(iface) + luci.http.prepare_content("application/json") + + local bwc = io.popen("luci-bwc -i %q 2>/dev/null" % iface) + if bwc then + luci.http.write("[") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) + end + + luci.http.write("]") + bwc:close() + end +end + +function action_wireless(iface) + luci.http.prepare_content("application/json") + + local bwc = io.popen("luci-bwc -r %q 2>/dev/null" % iface) + if bwc then + luci.http.write("[") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) + end + + luci.http.write("]") + bwc:close() + end +end + +function action_load() + luci.http.prepare_content("application/json") + + local bwc = io.popen("luci-bwc -l 2>/dev/null") + if bwc then + luci.http.write("[") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) + end + + luci.http.write("]") + bwc:close() + end +end + +function action_connections() + local sys = require "luci.sys" + + luci.http.prepare_content("application/json") + + luci.http.write("{ connections: ") + luci.http.write_json(sys.net.conntrack()) + + local bwc = io.popen("luci-bwc -c 2>/dev/null") + if bwc then + luci.http.write(", statistics: [") + + while true do + local ln = bwc:read("*l") + if not ln then break end + luci.http.write(ln) + end + + luci.http.write("]") + bwc:close() + end + + luci.http.write(" }") +end + +function action_nameinfo(...) + local i + local rv = { } + for i = 1, select('#', ...) do + local addr = select(i, ...) + local fqdn = nixio.getnameinfo(addr) + rv[addr] = fqdn or (addr:match(":") and "[%s]" % addr or addr) + end + + luci.http.prepare_content("application/json") + luci.http.write_json(rv) +end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua new file mode 100644 index 0000000000..5fa4c3a387 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/system.lua @@ -0,0 +1,393 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> +Copyright 2008-2011 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.system", package.seeall) + +function index() + entry({"admin", "system"}, alias("admin", "system", "system"), _("System"), 30).index = true + entry({"admin", "system", "system"}, cbi("admin_system/system"), _("System"), 1) + entry({"admin", "system", "clock_status"}, call("action_clock_status")) + + entry({"admin", "system", "admin"}, cbi("admin_system/admin"), _("Administration"), 2) + + if nixio.fs.access("/bin/opkg") then + entry({"admin", "system", "packages"}, call("action_packages"), _("Software"), 10) + entry({"admin", "system", "packages", "ipkg"}, form("admin_system/ipkg")) + end + + entry({"admin", "system", "startup"}, form("admin_system/startup"), _("Startup"), 45) + entry({"admin", "system", "crontab"}, form("admin_system/crontab"), _("Scheduled Tasks"), 46) + + if nixio.fs.access("/etc/config/fstab") then + entry({"admin", "system", "fstab"}, cbi("admin_system/fstab"), _("Mount Points"), 50) + entry({"admin", "system", "fstab", "mount"}, cbi("admin_system/fstab/mount"), nil).leaf = true + entry({"admin", "system", "fstab", "swap"}, cbi("admin_system/fstab/swap"), nil).leaf = true + end + + if nixio.fs.access("/sys/class/leds") then + entry({"admin", "system", "leds"}, cbi("admin_system/leds"), _("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), 60) + end + + entry({"admin", "system", "flashops"}, call("action_flashops"), _("Backup / Flash Firmware"), 70) + entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles")) + + entry({"admin", "system", "reboot"}, call("action_reboot"), _("Reboot"), 90) +end + +function action_clock_status() + local set = tonumber(luci.http.formvalue("set")) + if set ~= nil and set > 0 then + local date = os.date("*t", set) + if date then + luci.sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d'" %{ + date.year, date.month, date.day, date.hour, date.min, date.sec + }) + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json({ timestring = os.date("%c") }) +end + +function action_packages() + local ipkg = require("luci.model.ipkg") + local submit = luci.http.formvalue("submit") + local changes = false + local install = { } + local remove = { } + local stdout = { "" } + local stderr = { "" } + local out, err + + -- Display + local display = luci.http.formvalue("display") or "installed" + + -- Letter + local letter = string.byte(luci.http.formvalue("letter") or "A", 1) + letter = (letter == 35 or (letter >= 65 and letter <= 90)) and letter or 65 + + -- Search query + local query = luci.http.formvalue("query") + query = (query ~= '') and query or nil + + + -- Packets to be installed + local ninst = submit and luci.http.formvalue("install") + local uinst = nil + + -- Install from URL + local url = luci.http.formvalue("url") + if url and url ~= '' and submit then + uinst = url + end + + -- Do install + if ninst then + install[ninst], out, err = ipkg.install(ninst) + stdout[#stdout+1] = out + stderr[#stderr+1] = err + changes = true + end + + if uinst then + local pkg + for pkg in luci.util.imatch(uinst) do + install[uinst], out, err = ipkg.install(pkg) + stdout[#stdout+1] = out + stderr[#stderr+1] = err + changes = true + end + end + + -- Remove packets + local rem = submit and luci.http.formvalue("remove") + if rem then + remove[rem], out, err = ipkg.remove(rem) + stdout[#stdout+1] = out + stderr[#stderr+1] = err + changes = true + end + + + -- Update all packets + local update = luci.http.formvalue("update") + if update then + update, out, err = ipkg.update() + stdout[#stdout+1] = out + stderr[#stderr+1] = err + end + + + -- Upgrade all packets + local upgrade = luci.http.formvalue("upgrade") + if upgrade then + upgrade, out, err = ipkg.upgrade() + stdout[#stdout+1] = out + stderr[#stderr+1] = err + end + + + -- List state + local no_lists = true + local old_lists = false + local tmp = nixio.fs.dir("/var/opkg-lists/") + if tmp then + for tmp in tmp do + no_lists = false + tmp = nixio.fs.stat("/var/opkg-lists/"..tmp) + if tmp and tmp.mtime < (os.time() - (24 * 60 * 60)) then + old_lists = true + break + end + end + end + + + luci.template.render("admin_system/packages", { + display = display, + letter = letter, + query = query, + install = install, + remove = remove, + update = update, + upgrade = upgrade, + no_lists = no_lists, + old_lists = old_lists, + stdout = table.concat(stdout, ""), + stderr = table.concat(stderr, "") + }) + + -- Remove index cache + if changes then + nixio.fs.unlink("/tmp/luci-indexcache") + end +end + +function action_flashops() + local sys = require "luci.sys" + local fs = require "luci.fs" + + local upgrade_avail = nixio.fs.access("/lib/upgrade/platform.sh") + local reset_avail = os.execute([[grep '"rootfs_data"' /proc/mtd >/dev/null 2>&1]]) == 0 + + local restore_cmd = "tar -xzC/ >/dev/null 2>&1" + local backup_cmd = "sysupgrade --create-backup - 2>/dev/null" + local image_tmp = "/tmp/firmware.img" + + local function image_supported() + -- XXX: yay... + return ( 0 == os.execute( + ". /lib/functions.sh; " .. + "include /lib/upgrade; " .. + "platform_check_image %q >/dev/null" + % image_tmp + ) ) + end + + local function image_checksum() + return (luci.sys.exec("md5sum %q" % image_tmp):match("^([^%s]+)")) + end + + local function storage_size() + local size = 0 + if nixio.fs.access("/proc/mtd") then + for l in io.lines("/proc/mtd") do + local d, s, e, n = l:match('^([^%s]+)%s+([^%s]+)%s+([^%s]+)%s+"([^%s]+)"') + if n == "linux" or n == "firmware" then + size = tonumber(s, 16) + break + end + end + elseif nixio.fs.access("/proc/partitions") then + for l in io.lines("/proc/partitions") do + local x, y, b, n = l:match('^%s*(%d+)%s+(%d+)%s+([^%s]+)%s+([^%s]+)') + if b and n and not n:match('[0-9]') then + size = tonumber(b) * 1024 + break + end + end + end + return size + end + + + local fp + luci.http.setfilehandler( + function(meta, chunk, eof) + if not fp then + if meta and meta.name == "image" then + fp = io.open(image_tmp, "w") + else + fp = io.popen(restore_cmd, "w") + end + end + if chunk then + fp:write(chunk) + end + if eof then + fp:close() + end + end + ) + + if luci.http.formvalue("backup") then + -- + -- Assemble file list, generate backup + -- + local reader = ltn12_popen(backup_cmd) + luci.http.header('Content-Disposition', 'attachment; filename="backup-%s-%s.tar.gz"' % { + luci.sys.hostname(), os.date("%Y-%m-%d")}) + luci.http.prepare_content("application/x-targz") + luci.ltn12.pump.all(reader, luci.http.write) + elseif luci.http.formvalue("restore") then + -- + -- Unpack received .tar.gz + -- + local upload = luci.http.formvalue("archive") + if upload and #upload > 0 then + luci.template.render("admin_system/applyreboot") + luci.sys.reboot() + end + elseif luci.http.formvalue("image") or luci.http.formvalue("step") then + -- + -- Initiate firmware flash + -- + local step = tonumber(luci.http.formvalue("step") or 1) + if step == 1 then + if image_supported() then + luci.template.render("admin_system/upgrade", { + checksum = image_checksum(), + storage = storage_size(), + size = nixio.fs.stat(image_tmp).size, + keep = (not not luci.http.formvalue("keep")) + }) + else + nixio.fs.unlink(image_tmp) + luci.template.render("admin_system/flashops", { + reset_avail = reset_avail, + upgrade_avail = upgrade_avail, + image_invalid = true + }) + end + -- + -- Start sysupgrade flash + -- + elseif step == 2 then + local keep = (luci.http.formvalue("keep") == "1") and "" or "-n" + luci.template.render("admin_system/applyreboot", { + title = luci.i18n.translate("Flashing..."), + 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."), + addr = (#keep > 0) and "192.168.1.1" or nil + }) + fork_exec("killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %q" %{ keep, image_tmp }) + end + elseif reset_avail and luci.http.formvalue("reset") then + -- + -- Reset system + -- + luci.template.render("admin_system/applyreboot", { + title = luci.i18n.translate("Erasing..."), + msg = luci.i18n.translate("The system is erasing the configuration partition now and will reboot itself when finished."), + addr = "192.168.1.1" + }) + fork_exec("killall dropbear uhttpd; sleep 1; mtd -r erase rootfs_data") + else + -- + -- Overview + -- + luci.template.render("admin_system/flashops", { + reset_avail = reset_avail, + upgrade_avail = upgrade_avail + }) + end +end + +function action_passwd() + local p1 = luci.http.formvalue("pwd1") + local p2 = luci.http.formvalue("pwd2") + local stat = nil + + if p1 or p2 then + if p1 == p2 then + stat = luci.sys.user.setpasswd("root", p1) + else + stat = 10 + end + end + + luci.template.render("admin_system/passwd", {stat=stat}) +end + +function action_reboot() + local reboot = luci.http.formvalue("reboot") + luci.template.render("admin_system/reboot", {reboot=reboot}) + if reboot then + luci.sys.reboot() + end +end + +function fork_exec(command) + local pid = nixio.fork() + if pid > 0 then + return + elseif pid == 0 then + -- change to root dir + nixio.chdir("/") + + -- patch stdin, out, err to /dev/null + local null = nixio.open("/dev/null", "w+") + if null then + nixio.dup(null, nixio.stderr) + nixio.dup(null, nixio.stdout) + nixio.dup(null, nixio.stdin) + if null:fileno() > 2 then + null:close() + end + end + + -- replace with target command + nixio.exec("/bin/sh", "-c", command) + end +end + +function ltn12_popen(command) + + local fdi, fdo = nixio.pipe() + local pid = nixio.fork() + + if pid > 0 then + fdo:close() + local close + return function() + local buffer = fdi:read(2048) + local wpid, stat = nixio.waitpid(pid, "nohang") + if not close and wpid and stat == "exited" then + close = true + end + + if buffer and #buffer > 0 then + return buffer + elseif close then + fdi:close() + return nil + end + end + elseif pid == 0 then + nixio.dup(fdo, nixio.stdout) + fdi:close() + fdo:close() + nixio.exec("/bin/sh", "-c", command) + end +end diff --git a/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua new file mode 100644 index 0000000000..34e40ee624 --- /dev/null +++ b/modules/luci-mod-admin-full/luasrc/controller/admin/uci.lua @@ -0,0 +1,75 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth <steven@midlink.org> +Copyright 2010 Jo-Philipp Wich <xm@subsignal.org> + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +$Id$ +]]-- + +module("luci.controller.admin.uci", package.seeall) + +function index() + local redir = luci.http.formvalue("redir", true) or + luci.dispatcher.build_url(unpack(luci.dispatcher.context.request)) + + entry({"admin", "uci"}, nil, _("Configuration")) + entry({"admin", "uci", "changes"}, call("action_changes"), _("Changes"), 40).query = {redir=redir} + entry({"admin", "uci", "revert"}, call("action_revert"), _("Revert"), 30).query = {redir=redir} + entry({"admin", "uci", "apply"}, call("action_apply"), _("Apply"), 20).query = {redir=redir} + entry({"admin", "uci", "saveapply"}, call("action_apply"), _("Save & Apply"), 10).query = {redir=redir} +end + +function action_changes() + local uci = luci.model.uci.cursor() + local changes = uci:changes() + + luci.template.render("admin_uci/changes", { + changes = next(changes) and changes + }) +end + +function action_apply() + local path = luci.dispatcher.context.path + local uci = luci.model.uci.cursor() + local changes = uci:changes() + local reload = {} + + -- Collect files to be applied and commit changes + for r, tbl in pairs(changes) do + table.insert(reload, r) + if path[#path] ~= "apply" then + uci:load(r) + uci:commit(r) + uci:unload(r) + end + end + + luci.template.render("admin_uci/apply", { + changes = next(changes) and changes, + configs = reload + }) +end + + +function action_revert() + local uci = luci.model.uci.cursor() + local changes = uci:changes() + + -- Collect files to be reverted + for r, tbl in pairs(changes) do + uci:load(r) + uci:revert(r) + uci:unload(r) + end + + luci.template.render("admin_uci/revert", { + changes = next(changes) and changes + }) +end |