diff options
Diffstat (limited to 'modules/luci-mod-system/luasrc')
19 files changed, 2307 insertions, 0 deletions
diff --git a/modules/luci-mod-system/luasrc/controller/admin/system.lua b/modules/luci-mod-system/luasrc/controller/admin/system.lua new file mode 100644 index 0000000000..4e83769ee0 --- /dev/null +++ b/modules/luci-mod-system/luasrc/controller/admin/system.lua @@ -0,0 +1,469 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +module("luci.controller.admin.system", package.seeall) + +function index() + local fs = require "nixio.fs" + + entry({"admin", "system", "system"}, cbi("admin_system/system"), _("System"), 1) + entry({"admin", "system", "clock_status"}, post_on({ set = true }, "action_clock_status")) + + entry({"admin", "system", "admin"}, cbi("admin_system/admin"), _("Administration"), 2) + + if fs.access("/bin/opkg") then + entry({"admin", "system", "packages"}, post_on({ exec = "1" }, "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 fs.access("/sbin/block") and 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 + + local nodes, number = fs.glob("/sys/class/leds/*") + if number > 0 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", "reset"}, post("action_reset")) + entry({"admin", "system", "flashops", "backup"}, post("action_backup")) + entry({"admin", "system", "flashops", "backupmtdblock"}, post("action_backupmtdblock")) + entry({"admin", "system", "flashops", "backupfiles"}, form("admin_system/backupfiles")) + + -- call() instead of post() due to upload handling! + entry({"admin", "system", "flashops", "restore"}, call("action_restore")) + entry({"admin", "system", "flashops", "sysupgrade"}, call("action_sysupgrade")) + + entry({"admin", "system", "reboot"}, template("admin_system/reboot"), _("Reboot"), 90) + entry({"admin", "system", "reboot", "call"}, post("action_reboot")) +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 + }) + luci.sys.call("/etc/init.d/sysfixtime restart") + end + end + + luci.http.prepare_content("application/json") + luci.http.write_json({ timestring = os.date("%c") }) +end + +function action_packages() + local fs = require "nixio.fs" + local ipkg = require "luci.model.ipkg" + local submit = (luci.http.formvalue("exec") == "1") + local update, upgrade + local changes = false + local install = { } + local remove = { } + local stdout = { "" } + local stderr = { "" } + local out, err + + -- Display + local display = luci.http.formvalue("display") or "available" + + -- 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 + + + -- Modifying actions + if submit then + -- Packets to be installed + local ninst = luci.http.formvalue("install") + local uinst = nil + + -- Install from URL + local url = luci.http.formvalue("url") + if url and url ~= '' 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 = 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 + 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 + upgrade = luci.http.formvalue("upgrade") + if upgrade then + upgrade, out, err = ipkg.upgrade() + stdout[#stdout+1] = out + stderr[#stderr+1] = err + end + end + + + -- List state + local no_lists = true + local old_lists = false + if fs.access("/var/opkg-lists/") then + local list + for list in fs.dir("/var/opkg-lists/") do + no_lists = false + if (fs.stat("/var/opkg-lists/"..list, "mtime") or 0) < (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 + fs.unlink("/tmp/luci-indexcache") + end +end + +local function image_supported(image) + return (os.execute("sysupgrade -T %q >/dev/null" % image) == 0) +end + +local function image_checksum(image) + return (luci.sys.exec("md5sum %q" % image):match("^([^%s]+)")) +end + +local function image_sha256_checksum(image) + return (luci.sys.exec("sha256sum %q" % image):match("^([^%s]+)")) +end + +local function supports_sysupgrade() + return nixio.fs.access("/lib/upgrade/platform.sh") +end + +local function supports_reset() + return (os.execute([[grep -sq "^overlayfs:/overlay / overlay " /proc/mounts]]) == 0) +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 + + +function action_flashops() + -- + -- Overview + -- + luci.template.render("admin_system/flashops", { + reset_avail = supports_reset(), + upgrade_avail = supports_sysupgrade() + }) +end + +function action_sysupgrade() + local fs = require "nixio.fs" + local http = require "luci.http" + local image_tmp = "/tmp/firmware.img" + + local fp + http.setfilehandler( + function(meta, chunk, eof) + if not fp and meta and meta.name == "image" then + fp = io.open(image_tmp, "w") + end + if fp and chunk then + fp:write(chunk) + end + if fp and eof then + fp:close() + end + end + ) + + if not luci.dispatcher.test_post_security() then + fs.unlink(image_tmp) + return + end + + -- + -- Cancel firmware flash + -- + if http.formvalue("cancel") then + fs.unlink(image_tmp) + http.redirect(luci.dispatcher.build_url('admin/system/flashops')) + return + end + + -- + -- Initiate firmware flash + -- + local step = tonumber(http.formvalue("step")) or 1 + if step == 1 then + local force = http.formvalue("force") + if image_supported(image_tmp) or force then + luci.template.render("admin_system/upgrade", { + checksum = image_checksum(image_tmp), + sha256ch = image_sha256_checksum(image_tmp), + storage = storage_size(), + size = (fs.stat(image_tmp, "size") or 0), + keep = (not not http.formvalue("keep")), + force = (not not http.formvalue("force")) + }) + else + fs.unlink(image_tmp) + luci.template.render("admin_system/flashops", { + reset_avail = supports_reset(), + upgrade_avail = supports_sysupgrade(), + image_invalid = true + }) + end + + -- + -- Start sysupgrade flash + -- + elseif step == 2 then + local keep = (http.formvalue("keep") == "1") and "" or "-n" + local force = (http.formvalue("force") == "1") and "-F" or "" + 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 (#force > 0) and "192.168.1.1" or nil + }) + fork_exec("sleep 1; killall dropbear uhttpd; sleep 1; /sbin/sysupgrade %s %s %q" %{ keep, force, image_tmp }) + end +end + +function action_backup() + local reader = ltn12_popen("sysupgrade --create-backup - 2>/dev/null") + + 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) +end + +function action_backupmtdblock() + local http = require "luci.http" + local mv = http.formvalue("mtdblockname") + local m, s, n = mv:match('^([^%s]+)/([^%s]+)/([^%s]+)') + + local reader = ltn12_popen("dd if=/dev/mtd%s conv=fsync,notrunc 2>/dev/null" % n) + + luci.http.header( + 'Content-Disposition', 'attachment; filename="backup-%s-%s-%s.bin"' %{ + luci.sys.hostname(), m, + os.date("%Y-%m-%d") + }) + + luci.http.prepare_content("application/octet-stream") + luci.ltn12.pump.all(reader, luci.http.write) +end + +function action_restore() + local fs = require "nixio.fs" + local http = require "luci.http" + local archive_tmp = "/tmp/restore.tar.gz" + + local fp + http.setfilehandler( + function(meta, chunk, eof) + if not fp and meta and meta.name == "archive" then + fp = io.open(archive_tmp, "w") + end + if fp and chunk then + fp:write(chunk) + end + if fp and eof then + fp:close() + end + end + ) + + if not luci.dispatcher.test_post_security() then + fs.unlink(archive_tmp) + return + end + + local upload = http.formvalue("archive") + if upload and #upload > 0 then + if os.execute("gunzip -t %q >/dev/null 2>&1" % archive_tmp) == 0 then + luci.template.render("admin_system/applyreboot") + os.execute("tar -C / -xzf %q >/dev/null 2>&1" % archive_tmp) + luci.sys.reboot() + else + luci.template.render("admin_system/flashops", { + reset_avail = supports_reset(), + upgrade_avail = supports_sysupgrade(), + backup_invalid = true + }) + end + return + end + + http.redirect(luci.dispatcher.build_url('admin/system/flashops')) +end + +function action_reset() + if supports_reset() then + 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("sleep 1; killall dropbear uhttpd; sleep 1; jffs2reset -y && reboot") + return + end + + http.redirect(luci.dispatcher.build_url('admin/system/flashops')) +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() + luci.sys.reboot() +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-system/luasrc/model/cbi/admin_system/admin.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/admin.lua new file mode 100644 index 0000000000..6c1c1235c5 --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/admin.lua @@ -0,0 +1,122 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" + +m = Map("system", translate("Router Password"), + translate("Changes the administrator password for accessing the device")) + +s = m:section(TypedSection, "_dummy", "") +s.addremove = false +s.anonymous = true + +pw1 = s:option(Value, "pw1", translate("Password")) +pw1.password = true + +pw2 = s:option(Value, "pw2", translate("Confirmation")) +pw2.password = true + +function s.cfgsections() + return { "_pass" } +end + +function m.parse(map) + local v1 = pw1:formvalue("_pass") + local v2 = pw2:formvalue("_pass") + + if v1 and v2 and #v1 > 0 and #v2 > 0 then + if v1 == v2 then + if luci.sys.user.setpasswd(luci.dispatcher.context.authuser, v1) == 0 then + m.message = translate("Password successfully changed!") + else + m.message = translate("Unknown Error, password not changed!") + end + else + m.message = translate("Given password confirmation did not match, password not changed!") + end + end + + Map.parse(map) +end + + +if fs.access("/etc/config/dropbear") then + +m2 = Map("dropbear", translate("SSH Access"), + translate("Dropbear offers <abbr title=\"Secure Shell\">SSH</abbr> network shell access and an integrated <abbr title=\"Secure Copy\">SCP</abbr> server")) + +s = m2:section(TypedSection, "dropbear", translate("Dropbear Instance")) +s.anonymous = true +s.addremove = true + + +ni = s:option(Value, "Interface", translate("Interface"), + translate("Listen only on the given interface or, if unspecified, on all")) + +ni.template = "cbi/network_netlist" +ni.nocreate = true +ni.unspecified = true + + +pt = s:option(Value, "Port", translate("Port"), + translate("Specifies the listening port of this <em>Dropbear</em> instance")) + +pt.datatype = "port" +pt.default = 22 + + +pa = s:option(Flag, "PasswordAuth", translate("Password authentication"), + translate("Allow <abbr title=\"Secure Shell\">SSH</abbr> password authentication")) + +pa.enabled = "on" +pa.disabled = "off" +pa.default = pa.enabled +pa.rmempty = false + + +ra = s:option(Flag, "RootPasswordAuth", translate("Allow root logins with password"), + translate("Allow the <em>root</em> user to login with password")) + +ra.enabled = "on" +ra.disabled = "off" +ra.default = ra.enabled + + +gp = s:option(Flag, "GatewayPorts", translate("Gateway ports"), + translate("Allow remote hosts to connect to local SSH forwarded ports")) + +gp.enabled = "on" +gp.disabled = "off" +gp.default = gp.disabled + + +s2 = m2:section(TypedSection, "_dummy", translate("SSH-Keys"), + translate("Here you can paste public SSH-Keys (one per line) for SSH public-key authentication.")) +s2.addremove = false +s2.anonymous = true +s2.template = "cbi/tblsection" + +function s2.cfgsections() + return { "_keys" } +end + +keys = s2:option(TextValue, "_data", "") +keys.wrap = "off" +keys.rows = 3 + +function keys.cfgvalue() + return fs.readfile("/etc/dropbear/authorized_keys") or "" +end + +function keys.write(self, section, value) + return fs.writefile("/etc/dropbear/authorized_keys", value:gsub("\r\n", "\n")) +end + +function keys.remove(self, section, value) + return fs.writefile("/etc/dropbear/authorized_keys", "") +end + +end + +return m, m2 diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua new file mode 100644 index 0000000000..ee2401e93d --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/backupfiles.lua @@ -0,0 +1,80 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +if luci.http.formvalue("cbid.luci.1._list") then + luci.http.redirect(luci.dispatcher.build_url("admin/system/flashops/backupfiles") .. "?display=list") +elseif luci.http.formvalue("cbid.luci.1._edit") then + luci.http.redirect(luci.dispatcher.build_url("admin/system/flashops/backupfiles") .. "?display=edit") + return +end + +m = SimpleForm("luci", translate("Backup file list")) +m:append(Template("admin_system/backupfiles")) + +if luci.http.formvalue("display") ~= "list" then + f = m:section(SimpleSection, nil, translate("This is a list of shell glob patterns for matching files and directories to include during sysupgrade. Modified files in /etc/config/ and certain other configurations are automatically preserved.")) + + l = f:option(Button, "_list", translate("Show current backup file list")) + l.inputtitle = translate("Open list...") + l.inputstyle = "apply" + + c = f:option(TextValue, "_custom") + c.rmempty = false + c.cols = 70 + c.rows = 30 + + c.cfgvalue = function(self, section) + return nixio.fs.readfile("/etc/sysupgrade.conf") + end + + c.write = function(self, section, value) + value = value:gsub("\r\n?", "\n") + return nixio.fs.writefile("/etc/sysupgrade.conf", value) + end +else + m.submit = false + m.reset = false + + f = m:section(SimpleSection, nil, translate("Below is the determined list of files to backup. It consists of changed configuration files marked by opkg, essential base files and the user defined backup patterns.")) + + l = f:option(Button, "_edit", translate("Back to configuration")) + l.inputtitle = translate("Close list...") + l.inputstyle = "link" + + + d = f:option(DummyValue, "_detected") + d.rawhtml = true + d.cfgvalue = function(s) + local list = io.popen( + "( find $(sed -ne '/^[[:space:]]*$/d; /^#/d; p' /etc/sysupgrade.conf " .. + "/lib/upgrade/keep.d/* 2>/dev/null) -type f 2>/dev/null; " .. + "opkg list-changed-conffiles ) | sort -u" + ) + + if list then + local files = { "<ul>" } + + while true do + local ln = list:read("*l") + if not ln then + break + else + files[#files+1] = "<li>" + files[#files+1] = luci.util.pcdata(ln) + files[#files+1] = "</li>" + end + end + + list:close() + files[#files+1] = "</ul>" + + return table.concat(files, "") + end + + return "<em>" .. translate("No files found") .. "</em>" + end + +end + +return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/crontab.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/crontab.lua new file mode 100644 index 0000000000..016a6199aa --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/crontab.lua @@ -0,0 +1,32 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2008-2013 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local cronfile = "/etc/crontabs/root" + +f = SimpleForm("crontab", translate("Scheduled Tasks"), + translate("This is the system crontab in which scheduled tasks can be defined.") .. + translate("<br/>Note: you need to manually restart the cron service if the " .. + "crontab file was empty before editing.")) + +t = f:field(TextValue, "crons") +t.rmempty = true +t.rows = 10 +function t.cfgvalue() + return fs.readfile(cronfile) or "" +end + +function f.handle(self, state, data) + if state == FORM_VALID then + if data.crons then + fs.writefile(cronfile, data.crons:gsub("\r\n", "\n")) + luci.sys.call("/usr/bin/crontab %q" % cronfile) + else + fs.writefile(cronfile, "") + end + end + return true +end + +return f diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua new file mode 100644 index 0000000000..3ce5351bf0 --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab.lua @@ -0,0 +1,270 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Licensed to the public under the Apache License 2.0. + +require("luci.tools.webadmin") + +local fs = require "nixio.fs" +local util = require "nixio.util" +local tp = require "luci.template.parser" + +local block = io.popen("block info", "r") +local ln, dev, devices = nil, nil, {} + +repeat + ln = block:read("*l") + dev = ln and ln:match("^/dev/(.-):") + + if dev then + local e, s, key, val = { } + + for key, val in ln:gmatch([[(%w+)="(.-)"]]) do + e[key:lower()] = val + devices[val] = e + end + + s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev))) + + e.dev = "/dev/%s" % dev + e.size = s and math.floor(s / 2048) + + devices[e.dev] = e + end +until not ln + +block:close() + +m = Map("fstab", translate("Mount Points")) +s = m:section(TypedSection, "global", translate("Global Settings")) +s.addremove = false +s.anonymous = true + +detect = s:option(Button, "block_detect", translate("Generate Config"), translate("Find all currently attached filesystems and swap and replace configuration with defaults based on what was detected")) +detect.inputstyle = "reload" + +detect.write = function(self, section) + luci.sys.call("block detect >/etc/config/fstab") + luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab")) +end + +o = s:option(Flag, "anon_swap", translate("Anonymous Swap"), translate("Mount swap not specifically configured")) +o.default = o.disabled +o.rmempty = false + +o = s:option(Flag, "anon_mount", translate("Anonymous Mount"), translate("Mount filesystems not specifically configured")) +o.default = o.disabled +o.rmempty = false + +o = s:option(Flag, "auto_swap", translate("Automount Swap"), translate("Automatically mount swap on hotplug")) +o.default = o.enabled +o.rmempty = false + +o = s:option(Flag, "auto_mount", translate("Automount Filesystem"), translate("Automatically mount filesystems on hotplug")) +o.default = o.enabled +o.rmempty = false + +o = s:option(Flag, "check_fs", translate("Check filesystems before mount"), translate("Automatically check filesystem for errors before mounting")) +o.default = o.disabled +o.rmempty = false + +local mounts = luci.sys.mounts() +local non_system_mounts = {} +for rawmount, val in pairs(mounts) do + if (string.find(val.mountpoint, "/tmp/.jail") == nil) then + repeat + val.umount = false + if (val.mountpoint == "/") then + break + elseif (val.mountpoint == "/overlay") then + break + elseif (val.mountpoint == "/rom") then + break + elseif (val.mountpoint == "/tmp") then + break + elseif (val.mountpoint == "/tmp/shm") then + break + elseif (val.mountpoint == "/tmp/upgrade") then + break + elseif (val.mountpoint == "/dev") then + break + end + val.umount = true + until true + non_system_mounts[rawmount] = val + end +end + +v = m:section(Table, non_system_mounts, translate("Mounted file systems")) + +fs = v:option(DummyValue, "fs", translate("Filesystem")) + +mp = v:option(DummyValue, "mountpoint", translate("Mount Point")) + +avail = v:option(DummyValue, "avail", translate("Available")) +function avail.cfgvalue(self, section) + return luci.tools.webadmin.byte_format( + ( tonumber(mounts[section].available) or 0 ) * 1024 + ) .. " / " .. luci.tools.webadmin.byte_format( + ( tonumber(mounts[section].blocks) or 0 ) * 1024 + ) +end + +used = v:option(DummyValue, "used", translate("Used")) +function used.cfgvalue(self, section) + return ( mounts[section].percent or "0%" ) .. " (" .. + luci.tools.webadmin.byte_format( + ( tonumber(mounts[section].used) or 0 ) * 1024 + ) .. ")" +end + +unmount = v:option(Button, "unmount", translate("Unmount")) +unmount.render = function(self, section, scope) + if non_system_mounts[section].umount then + self.title = translate("Unmount") + self.inputstyle = "remove" + Button.render(self, section, scope) + end +end + +unmount.write = function(self, section) + if non_system_mounts[section].umount then + luci.sys.call("/bin/umount '%s'" % luci.util.shellstartsqescape(non_system_mounts[section].mountpoint)) + return luci.http.redirect(luci.dispatcher.build_url("admin/system", "fstab")) + end +end + +mount = m:section(TypedSection, "mount", translate("Mount Points"), translate("Mount Points define at which point a memory device will be attached to the filesystem")) +mount.anonymous = true +mount.addremove = true +mount.template = "cbi/tblsection" +mount.extedit = luci.dispatcher.build_url("admin/system/fstab/mount/%s") + +mount.create = function(...) + local sid = TypedSection.create(...) + if sid then + luci.http.redirect(mount.extedit % sid) + return + end +end + + +mount:option(Flag, "enabled", translate("Enabled")).rmempty = false + +dev = mount:option(DummyValue, "device", translate("Device")) +dev.rawhtml = true +dev.cfgvalue = function(self, section) + local v, e + + v = m.uci:get("fstab", section, "uuid") + e = v and devices[v:lower()] + if v and e and e.size then + return "UUID: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size } + elseif v and e then + return "UUID: %s (%s)" %{ tp.pcdata(v), e.dev } + elseif v then + return "UUID: %s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") } + end + + v = m.uci:get("fstab", section, "label") + e = v and devices[v] + if v and e and e.size then + return "Label: %s (%s, %d MB)" %{ tp.pcdata(v), e.dev, e.size } + elseif v and e then + return "Label: %s (%s)" %{ tp.pcdata(v), e.dev } + elseif v then + return "Label: %s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") } + end + + v = Value.cfgvalue(self, section) or "?" + e = v and devices[v] + if v and e and e.size then + return "%s (%d MB)" %{ tp.pcdata(v), e.size } + elseif v and e then + return tp.pcdata(v) + elseif v then + return "%s (<em>%s</em>)" %{ tp.pcdata(v), translate("not present") } + end +end + +mp = mount:option(DummyValue, "target", translate("Mount Point")) +mp.cfgvalue = function(self, section) + if m.uci:get("fstab", section, "is_rootfs") == "1" then + return "/overlay" + else + return Value.cfgvalue(self, section) or "?" + end +end + +fs = mount:option(DummyValue, "fstype", translate("Filesystem")) +fs.cfgvalue = function(self, section) + local v, e + + v = m.uci:get("fstab", section, "uuid") + v = v and v:lower() or m.uci:get("fstab", section, "label") + v = v or m.uci:get("fstab", section, "device") + + e = v and devices[v] + + return e and e.type or m.uci:get("fstab", section, "fstype") or "?" +end + +op = mount:option(DummyValue, "options", translate("Options")) +op.cfgvalue = function(self, section) + return Value.cfgvalue(self, section) or "defaults" +end + +rf = mount:option(DummyValue, "is_rootfs", translate("Root")) +rf.cfgvalue = function(self, section) + local target = m.uci:get("fstab", section, "target") + if target == "/" then + return translate("yes") + elseif target == "/overlay" then + return translate("overlay") + else + return translate("no") + end +end + +ck = mount:option(DummyValue, "enabled_fsck", translate("Check")) +ck.cfgvalue = function(self, section) + return Value.cfgvalue(self, section) == "1" + and translate("yes") or translate("no") +end + + +swap = m:section(TypedSection, "swap", "SWAP", translate("If your physical memory is insufficient unused data can be temporarily swapped to a swap-device resulting in a higher amount of usable <abbr title=\"Random Access Memory\">RAM</abbr>. Be aware that swapping data is a very slow process as the swap-device cannot be accessed with the high datarates of the <abbr title=\"Random Access Memory\">RAM</abbr>.")) +swap.anonymous = true +swap.addremove = true +swap.template = "cbi/tblsection" +swap.extedit = luci.dispatcher.build_url("admin/system/fstab/swap/%s") + +swap.create = function(...) + local sid = TypedSection.create(...) + if sid then + luci.http.redirect(swap.extedit % sid) + return + end +end + + +swap:option(Flag, "enabled", translate("Enabled")).rmempty = false + +dev = swap:option(DummyValue, "device", translate("Device")) +dev.cfgvalue = function(self, section) + local v + + v = m.uci:get("fstab", section, "uuid") + if v then return "UUID: %s" % v end + + v = m.uci:get("fstab", section, "label") + if v then return "Label: %s" % v end + + v = Value.cfgvalue(self, section) or "?" + e = v and devices[v] + if v and e and e.size then + return "%s (%s MB)" % {v, e.size} + else + return v + end +end + +return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua new file mode 100644 index 0000000000..a85872afad --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/mount.lua @@ -0,0 +1,151 @@ +-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local util = require "nixio.util" + +local has_fscheck = fs.access("/usr/sbin/e2fsck") + +local block = io.popen("block info", "r") +local ln, dev, devices = nil, nil, {} + +repeat + ln = block:read("*l") + dev = ln and ln:match("^/dev/(.-):") + + if dev then + local e, s, key, val = { } + + for key, val in ln:gmatch([[(%w+)="(.-)"]]) do + e[key:lower()] = val + end + + s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev))) + + e.dev = "/dev/%s" % dev + e.size = s and math.floor(s / 2048) + + devices[#devices+1] = e + end +until not ln + +block:close() + + +m = Map("fstab", translate("Mount Points - Mount Entry")) +m.redirect = luci.dispatcher.build_url("admin/system/fstab") + +if not arg[1] or m.uci:get("fstab", arg[1]) ~= "mount" then + luci.http.redirect(m.redirect) + return +end + + + +mount = m:section(NamedSection, arg[1], "mount", translate("Mount Entry")) +mount.anonymous = true +mount.addremove = false + +mount:tab("general", translate("General Settings")) +mount:tab("advanced", translate("Advanced Settings")) + + +mount:taboption("general", Flag, "enabled", translate("Enable this mount")).rmempty = false + + +o = mount:taboption("general", Value, "uuid", translate("UUID"), + translate("If specified, mount the device by its UUID instead of a fixed device node")) + +o:value("", translate("-- match by uuid --")) + +for i, d in ipairs(devices) do + if d.uuid and d.size then + o:value(d.uuid, "%s (%s, %d MB)" %{ d.uuid, d.dev, d.size }) + elseif d.uuid then + o:value(d.uuid, "%s (%s)" %{ d.uuid, d.dev }) + end +end + + +o = mount:taboption("general", Value, "label", translate("Label"), + translate("If specified, mount the device by the partition label instead of a fixed device node")) + +o:value("", translate("-- match by label --")) + +o:depends("uuid", "") + +for i, d in ipairs(devices) do + if d.label and d.size then + o:value(d.label, "%s (%s, %d MB)" %{ d.label, d.dev, d.size }) + elseif d.label then + o:value(d.label, "%s (%s)" %{ d.label, d.dev }) + end +end + + +o = mount:taboption("general", Value, "device", translate("Device"), + translate("The device file of the memory or partition (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)")) + +o:value("", translate("-- match by device --")) + +o:depends({ uuid = "", label = "" }) + +for i, d in ipairs(devices) do + if d.size then + o:value(d.dev, "%s (%d MB)" %{ d.dev, d.size }) + else + o:value(d.dev) + end +end + + +o = mount:taboption("general", Value, "target", translate("Mount point"), + translate("Specifies the directory the device is attached to")) + +o:value("/", translate("Use as root filesystem (/)")) +o:value("/overlay", translate("Use as external overlay (/overlay)")) + + +o = mount:taboption("general", DummyValue, "__notice", translate("Root preparation")) +o:depends("target", "/") +o.rawhtml = true +o.default = [[ +<p>%s</p><pre>mkdir -p /tmp/introot +mkdir -p /tmp/extroot +mount --bind / /tmp/introot +mount /dev/sda1 /tmp/extroot +tar -C /tmp/introot -cvf - . | tar -C /tmp/extroot -xf - +umount /tmp/introot +umount /tmp/extroot</pre> +]] %{ + translate("Make sure to clone the root filesystem using something like the commands below:"), + +} + + +o = mount:taboption("advanced", Value, "fstype", translate("Filesystem"), + translate("The filesystem that was used to format the memory (<abbr title=\"for example\">e.g.</abbr> <samp><abbr title=\"Third Extended Filesystem\">ext3</abbr></samp>)")) + +o:value("", "auto") + +local fs +for fs in io.lines("/proc/filesystems") do + fs = fs:match("%S+") + if fs ~= "nodev" then + o:value(fs) + end +end + + +o = mount:taboption("advanced", Value, "options", translate("Mount options"), + translate("See \"mount\" manpage for details")) + +o.placeholder = "defaults" + + +if has_fscheck then + o = mount:taboption("advanced", Flag, "enabled_fsck", translate("Run filesystem check"), + translate("Run a filesystem check before mounting the device")) +end + +return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua new file mode 100644 index 0000000000..82468d5fcc --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/fstab/swap.lua @@ -0,0 +1,54 @@ +-- Copyright 2010 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local util = require "nixio.util" + +local devices = {} +util.consume((fs.glob("/dev/sd*")), devices) +util.consume((fs.glob("/dev/hd*")), devices) +util.consume((fs.glob("/dev/scd*")), devices) +util.consume((fs.glob("/dev/mmc*")), devices) + +local size = {} +for i, dev in ipairs(devices) do + local s = tonumber((fs.readfile("/sys/class/block/%s/size" % dev:sub(6)))) + size[dev] = s and math.floor(s / 2048) +end + + +m = Map("fstab", translate("Mount Points - Swap Entry")) +m.redirect = luci.dispatcher.build_url("admin/system/fstab") + +if not arg[1] or m.uci:get("fstab", arg[1]) ~= "swap" then + luci.http.redirect(m.redirect) + return +end + + +mount = m:section(NamedSection, arg[1], "swap", translate("Swap Entry")) +mount.anonymous = true +mount.addremove = false + +mount:tab("general", translate("General Settings")) +mount:tab("advanced", translate("Advanced Settings")) + + +mount:taboption("general", Flag, "enabled", translate("Enable this swap")).rmempty = false + + +o = mount:taboption("general", Value, "device", translate("Device"), + translate("The device file of the memory or partition (<abbr title=\"for example\">e.g.</abbr> <code>/dev/sda1</code>)")) + +for i, d in ipairs(devices) do + o:value(d, size[d] and "%s (%s MB)" % {d, size[d]}) +end + +o = mount:taboption("advanced", Value, "uuid", translate("UUID"), + translate("If specified, mount the device by its UUID instead of a fixed device node")) + +o = mount:taboption("advanced", Value, "label", translate("Label"), + translate("If specified, mount the device by the partition label instead of a fixed device node")) + + +return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua new file mode 100644 index 0000000000..7c6d7e1c66 --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/ipkg.lua @@ -0,0 +1,64 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2008-2011 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local ipkgfile = "/etc/opkg.conf" +local distfeeds = "/etc/opkg/distfeeds.conf" +local customfeeds = "/etc/opkg/customfeeds.conf" + +f = SimpleForm("ipkgconf", translate("OPKG-Configuration"), translate("General options for opkg")) + +f:append(Template("admin_system/ipkg")) + +t = f:field(TextValue, "lines") +t.wrap = "off" +t.rows = 10 +function t.cfgvalue() + return nixio.fs.readfile(ipkgfile) or "" +end + +function t.write(self, section, data) + return nixio.fs.writefile(ipkgfile, data:gsub("\r\n", "\n")) +end + +function f.handle(self, state, data) + return true +end + +g = SimpleForm("distfeedconf", translate("Distribution feeds"), + translate("Build/distribution specific feed definitions. This file will NOT be preserved in any sysupgrade.")) + +d = g:field(TextValue, "lines2") +d.wrap = "off" +d.rows = 10 +function d.cfgvalue() + return nixio.fs.readfile(distfeeds) or "" +end + +function d.write(self, section, data) + return nixio.fs.writefile(distfeeds, data:gsub("\r\n", "\n")) +end + +function g.handle(self, state, data) + return true +end + +h = SimpleForm("customfeedconf", translate("Custom feeds"), + translate("Custom feed definitions, e.g. private feeds. This file can be preserved in a sysupgrade.")) + +c = h:field(TextValue, "lines3") +c.wrap = "off" +c.rows = 10 +function c.cfgvalue() + return nixio.fs.readfile(customfeeds) or "" +end + +function c.write(self, section, data) + return nixio.fs.writefile(customfeeds, data:gsub("\r\n", "\n")) +end + +function h.handle(self, state, data) + return true +end + +return f, g, h diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua new file mode 100644 index 0000000000..2ea044e16a --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/leds.lua @@ -0,0 +1,158 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Licensed to the public under the Apache License 2.0. + +m = Map("system", translate("<abbr title=\"Light Emitting Diode\">LED</abbr> Configuration"), translate("Customizes the behaviour of the device <abbr title=\"Light Emitting Diode\">LED</abbr>s if possible.")) + +local sysfs_path = "/sys/class/leds/" +local leds = {} + +local fs = require "nixio.fs" +local nu = require "nixio.util" +local util = require "luci.util" + +if fs.access(sysfs_path) then + leds = nu.consume((fs.dir(sysfs_path))) +end + +if #leds == 0 then + return m +end + + +s = m:section(TypedSection, "led", "") +s.anonymous = true +s.addremove = true + +function s.parse(self, ...) + TypedSection.parse(self, ...) + os.execute("/etc/init.d/led enable") +end + + +s:option(Value, "name", translate("Name")) + + +sysfs = s:option(ListValue, "sysfs", translate("<abbr title=\"Light Emitting Diode\">LED</abbr> Name")) +for k, v in ipairs(leds) do + sysfs:value(v) +end + +s:option(Flag, "default", translate("Default state")).rmempty = false + + +trigger = s:option(ListValue, "trigger", translate("Trigger")) + +local triggers = fs.readfile(sysfs_path .. leds[1] .. "/trigger") +for t in triggers:gmatch("[%w-]+") do + trigger:value(t, translate(t:gsub("-", ""))) +end + + +delayon = s:option(Value, "delayon", translate ("On-State Delay")) +delayon:depends("trigger", "timer") + +delayoff = s:option(Value, "delayoff", translate ("Off-State Delay")) +delayoff:depends("trigger", "timer") + + +dev = s:option(ListValue, "_net_dev", translate("Device")) +dev.rmempty = true +dev:value("") +dev:depends("trigger", "netdev") + +function dev.cfgvalue(self, section) + return m.uci:get("system", section, "dev") +end + +function dev.write(self, section, value) + m.uci:set("system", section, "dev", value) +end + +function dev.remove(self, section) + local t = trigger:formvalue(section) + if t ~= "netdev" and t ~= "usbdev" then + m.uci:delete("system", section, "dev") + end +end + +for k, v in pairs(luci.sys.net.devices()) do + if v ~= "lo" then + dev:value(v) + end +end + + +mode = s:option(MultiValue, "mode", translate("Trigger Mode")) +mode.rmempty = true +mode:depends("trigger", "netdev") +mode:value("link", translate("Link On")) +mode:value("tx", translate("Transmit")) +mode:value("rx", translate("Receive")) + + +usbdev = s:option(ListValue, "_usb_dev", translate("USB Device")) +usbdev:depends("trigger", "usbdev") +usbdev.rmempty = true +usbdev:value("") + +function usbdev.cfgvalue(self, section) + return m.uci:get("system", section, "dev") +end + +function usbdev.write(self, section, value) + m.uci:set("system", section, "dev", value) +end + +function usbdev.remove(self, section) + local t = trigger:formvalue(section) + if t ~= "netdev" and t ~= "usbdev" then + m.uci:delete("system", section, "dev") + end +end + + +usbport = s:option(MultiValue, "port", translate("USB Ports")) +usbport:depends("trigger", "usbport") +usbport.rmempty = true +usbport.widget = "checkbox" +usbport.cast = "table" +usbport.size = 1 + +function usbport.valuelist(self, section) + local port, ports = nil, {} + for port in util.imatch(m.uci:get("system", section, "port")) do + local b, n = port:match("^usb(%d+)-port(%d+)$") + if not (b and n) then + b, n = port:match("^(%d+)-(%d+)$") + end + if b and n then + ports[#ports+1] = "usb%u-port%u" %{ tonumber(b), tonumber(n) } + end + end + return ports +end + +function usbport.validate(self, value) + return type(value) == "string" and { value } or value +end + + +for p in nixio.fs.glob("/sys/bus/usb/devices/[0-9]*/manufacturer") do + local id = p:match("%d+-%d+") + local mf = nixio.fs.readfile("/sys/bus/usb/devices/" .. id .. "/manufacturer") or "?" + local pr = nixio.fs.readfile("/sys/bus/usb/devices/" .. id .. "/product") or "?" + usbdev:value(id, "%s (%s - %s)" %{ id, mf, pr }) +end + +for p in nixio.fs.glob("/sys/bus/usb/devices/*/usb[0-9]*-port[0-9]*") do + local bus, port = p:match("usb(%d+)-port(%d+)") + if bus and port then + usbport:value("usb%u-port%u" %{ tonumber(bus), tonumber(port) }, + "Hub %u, Port %u" %{ tonumber(bus), tonumber(port) }) + end +end + +port_mask = s:option(Value, "port_mask", translate ("Switch Port Mask")) +port_mask:depends("trigger", "switch0") + +return m diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua new file mode 100644 index 0000000000..9e19ac50a2 --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/startup.lua @@ -0,0 +1,97 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2010-2012 Jo-Philipp Wich <jow@openwrt.org> +-- Copyright 2010 Manuel Munz <freifunk at somakoma dot de> +-- Licensed to the public under the Apache License 2.0. + +local fs = require "nixio.fs" +local sys = require "luci.sys" + +local inits = { } + +for _, name in ipairs(sys.init.names()) do + local index = sys.init.index(name) + local enabled = sys.init.enabled(name) + + if index < 255 then + inits["%02i.%s" % { index, name }] = { + name = name, + index = tostring(index), + enabled = enabled + } + end +end + + +m = SimpleForm("initmgr", translate("Initscripts"), translate("You can enable or disable installed init scripts here. Changes will applied after a device reboot.<br /><strong>Warning: If you disable essential init scripts like \"network\", your device might become inaccessible!</strong>")) +m.reset = false +m.submit = false + + +s = m:section(Table, inits) + +i = s:option(DummyValue, "index", translate("Start priority")) +n = s:option(DummyValue, "name", translate("Initscript")) + + +e = s:option(Button, "endisable", translate("Enable/Disable")) + +e.render = function(self, section, scope) + if inits[section].enabled then + self.title = translate("Enabled") + self.inputstyle = "save" + else + self.title = translate("Disabled") + self.inputstyle = "reset" + end + + Button.render(self, section, scope) +end + +e.write = function(self, section) + if inits[section].enabled then + inits[section].enabled = false + return sys.init.disable(inits[section].name) + else + inits[section].enabled = true + return sys.init.enable(inits[section].name) + end +end + + +start = s:option(Button, "start", translate("Start")) +start.inputstyle = "apply" +start.write = function(self, section) + sys.call("/etc/init.d/%s %s >/dev/null" %{ inits[section].name, self.option }) +end + +restart = s:option(Button, "restart", translate("Restart")) +restart.inputstyle = "reload" +restart.write = start.write + +stop = s:option(Button, "stop", translate("Stop")) +stop.inputstyle = "remove" +stop.write = start.write + + + +f = SimpleForm("rc", translate("Local Startup"), + translate("This is the content of /etc/rc.local. Insert your own commands here (in front of 'exit 0') to execute them at the end of the boot process.")) + +t = f:field(TextValue, "rcs") +t.rmempty = true +t.rows = 20 + +function t.cfgvalue() + return fs.readfile("/etc/rc.local") or "" +end + +function f.handle(self, state, data) + if state == FORM_VALID then + if data.rcs then + fs.writefile("/etc/rc.local", data.rcs:gsub("\r\n", "\n")) + end + end + return true +end + +return m, f diff --git a/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua b/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua new file mode 100644 index 0000000000..c7fdfcddba --- /dev/null +++ b/modules/luci-mod-system/luasrc/model/cbi/admin_system/system.lua @@ -0,0 +1,224 @@ +-- Copyright 2008 Steven Barth <steven@midlink.org> +-- Copyright 2011 Jo-Philipp Wich <jow@openwrt.org> +-- Licensed to the public under the Apache License 2.0. + +local sys = require "luci.sys" +local zones = require "luci.sys.zoneinfo" +local fs = require "nixio.fs" +local conf = require "luci.config" + +local m, s, o +local has_ntpd = fs.access("/usr/sbin/ntpd") + +m = Map("system", translate("System"), translate("Here you can configure the basic aspects of your device like its hostname or the timezone.")) +m:chain("luci") + + +s = m:section(TypedSection, "system", translate("System Properties")) +s.anonymous = true +s.addremove = false + +s:tab("general", translate("General Settings")) +s:tab("logging", translate("Logging")) +s:tab("language", translate("Language and Style")) + + +-- +-- System Properties +-- + +o = s:taboption("general", DummyValue, "_systime", translate("Local Time")) +o.template = "admin_system/clock_status" + + +o = s:taboption("general", Value, "hostname", translate("Hostname")) +o.datatype = "hostname" + +function o.write(self, section, value) + Value.write(self, section, value) + sys.hostname(value) +end + + +o = s:taboption("general", ListValue, "zonename", translate("Timezone")) +o:value("UTC") + +for i, zone in ipairs(zones.TZ) do + o:value(zone[1]) +end + +function o.write(self, section, value) + local function lookup_zone(title) + for _, zone in ipairs(zones.TZ) do + if zone[1] == title then return zone[2] end + end + end + + AbstractValue.write(self, section, value) + local timezone = lookup_zone(value) or "GMT0" + self.map.uci:set("system", section, "timezone", timezone) + fs.writefile("/etc/TZ", timezone .. "\n") +end + + +-- +-- Logging +-- + +o = s:taboption("logging", Value, "log_size", translate("System log buffer size"), "kiB") +o.optional = true +o.placeholder = 16 +o.datatype = "uinteger" + +o = s:taboption("logging", Value, "log_ip", translate("External system log server")) +o.optional = true +o.placeholder = "0.0.0.0" +o.datatype = "ip4addr" + +o = s:taboption("logging", Value, "log_port", translate("External system log server port")) +o.optional = true +o.placeholder = 514 +o.datatype = "port" + +o = s:taboption("logging", ListValue, "log_proto", translate("External system log server protocol")) +o:value("udp", "UDP") +o:value("tcp", "TCP") + +o = s:taboption("logging", Value, "log_file", translate("Write system log to file")) +o.optional = true +o.placeholder = "/tmp/system.log" + +o = s:taboption("logging", ListValue, "conloglevel", translate("Log output level")) +o:value(8, translate("Debug")) +o:value(7, translate("Info")) +o:value(6, translate("Notice")) +o:value(5, translate("Warning")) +o:value(4, translate("Error")) +o:value(3, translate("Critical")) +o:value(2, translate("Alert")) +o:value(1, translate("Emergency")) + +o = s:taboption("logging", ListValue, "cronloglevel", translate("Cron Log Level")) +o.default = 8 +o:value(5, translate("Debug")) +o:value(8, translate("Normal")) +o:value(9, translate("Warning")) + + +-- +-- Langauge & Style +-- + +o = s:taboption("language", ListValue, "_lang", translate("Language")) +o:value("auto") + +local i18ndir = luci.i18n.i18ndir .. "base." +for k, v in luci.util.kspairs(conf.languages) do + local file = i18ndir .. k:gsub("_", "-") + if k:sub(1, 1) ~= "." and fs.access(file .. ".lmo") then + o:value(k, v) + end +end + +function o.cfgvalue(...) + return m.uci:get("luci", "main", "lang") +end + +function o.write(self, section, value) + m.uci:set("luci", "main", "lang", value) +end + + +o = s:taboption("language", ListValue, "_mediaurlbase", translate("Design")) +for k, v in pairs(conf.themes) do + if k:sub(1, 1) ~= "." then + o:value(v, k) + end +end + +function o.cfgvalue(...) + return m.uci:get("luci", "main", "mediaurlbase") +end + +function o.write(self, section, value) + m.uci:set("luci", "main", "mediaurlbase", value) +end + + +-- +-- NTP +-- + +if has_ntpd then + + -- timeserver setup was requested, create section and reload page + if m:formvalue("cbid.system._timeserver._enable") then + m.uci:section("system", "timeserver", "ntp", + { + server = { "0.openwrt.pool.ntp.org", "1.openwrt.pool.ntp.org", "2.openwrt.pool.ntp.org", "3.openwrt.pool.ntp.org" } + } + ) + + m.uci:save("system") + luci.http.redirect(luci.dispatcher.build_url("admin/system", arg[1])) + return + end + + local has_section = false + m.uci:foreach("system", "timeserver", + function(s) + has_section = true + return false + end) + + if not has_section then + + s = m:section(TypedSection, "timeserver", translate("Time Synchronization")) + s.anonymous = true + s.cfgsections = function() return { "_timeserver" } end + + x = s:option(Button, "_enable") + x.title = translate("Time Synchronization is not configured yet.") + x.inputtitle = translate("Set up Time Synchronization") + x.inputstyle = "apply" + + else + + s = m:section(TypedSection, "timeserver", translate("Time Synchronization")) + s.anonymous = true + s.addremove = false + + o = s:option(Flag, "enable", translate("Enable NTP client")) + o.rmempty = false + + function o.cfgvalue(self) + return sys.init.enabled("sysntpd") + and self.enabled or self.disabled + end + + function o.write(self, section, value) + if value == self.enabled then + sys.init.enable("sysntpd") + sys.call("env -i /etc/init.d/sysntpd start >/dev/null") + else + sys.call("env -i /etc/init.d/sysntpd stop >/dev/null") + sys.init.disable("sysntpd") + end + end + + + o = s:option(Flag, "enable_server", translate("Provide NTP server")) + o:depends("enable", "1") + + + o = s:option(DynamicList, "server", translate("NTP server candidates")) + o.datatype = "host(0)" + o:depends("enable", "1") + + -- retain server list even if disabled + function o.remove() end + + end +end + +return m diff --git a/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm b/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm new file mode 100644 index 0000000000..e235bd4679 --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/applyreboot.htm @@ -0,0 +1,53 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<html> + <head> + <title><%=luci.sys.hostname()%> - <%= title or translate("Rebooting...") %></title> + <link rel="stylesheet" type="text/css" media="screen" href="<%=media%>/cascade.css" /> + <script type="text/javascript" src="<%=resource%>/xhr.js"></script> + <script type="text/javascript">//<![CDATA[ + var interval = window.setInterval(function() { + var img = new Image(); + var target = ('https:' == document.location.protocol ? 'https://' : 'http://') + <%=addr and "'%s'" % addr or "window.location.host"%>; + + img.onload = function() { + window.clearInterval(interval); + window.location.replace(target); + }; + + img.src = target + '<%=resource%>/icons/loading.gif?' + Math.random(); + + }, 5000); + //]]></script> + </head> + <body> + <header> + <div class="fill"> + <div class="container"> + <p class="brand"><%=luci.sys.hostname() or "?"%></p> + </div> + </div> + </header> +   + <div class="main"> + <div id="maincontainer"> + <div id="maincontent" class="container"> + <h2 name="content" id="applyreboot-container" ><%:System%> - <%= title or translate("Rebooting...") %></h2> + <div class="cbi-section" id="applyreboot-section"> + <div> + <%= msg or translate("Changes applied.") %> + </div> + <div> + <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> + <%:Waiting for changes to be applied...%> + </div> + </div> + </div> + </div> + </div> + </body> +</html>
\ No newline at end of file diff --git a/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm b/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm new file mode 100644 index 0000000000..c1f3361ae2 --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/backupfiles.htm @@ -0,0 +1,10 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<ul class="cbi-tabmenu"> + <li class="cbi-tab-disabled"><a href="<%=url("admin/system/flashops")%>"><%:Actions%></a></li> + <li class="cbi-tab"><a href="#"><%:Configuration%></a></li> +</ul> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/clock_status.htm b/modules/luci-mod-system/luasrc/view/admin_system/clock_status.htm new file mode 100644 index 0000000000..37d8ae0e85 --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/clock_status.htm @@ -0,0 +1,36 @@ +<%+cbi/valueheader%> + +<script type="text/javascript">//<![CDATA[ + XHR.poll(5, '<%=url('admin/system/clock_status')%>', null, + function(x, rv) + { + var s = document.getElementById('<%=self.option%>-clock-status'); + if (s) + { + s.innerHTML = rv.timestring || '?'; + } + } + ); + + function sync_clock(btn) + { + btn.disabled = true; + btn.value = '<%:Synchronizing...%>'; + + (new XHR()).post('<%=url('admin/system/clock_status')%>', + { token: '<%=token%>', set: Math.floor((new Date()).getTime() / 1000) }, + function() + { + btn.disabled = false; + btn.value = '<%:Sync with browser%>'; + } + ); + + return false; + } +//]]></script> + +<span id="<%=self.option%>-clock-status"><em><%:Collecting data...%></em></span> +<input type="button" class="cbi-button cbi-button-apply" value="<%:Sync with browser%>" onclick="return sync_clock(this)" /> + +<%+cbi/valuefooter%> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/flashops.htm b/modules/luci-mod-system/luasrc/view/admin_system/flashops.htm new file mode 100644 index 0000000000..8204d38e34 --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/flashops.htm @@ -0,0 +1,137 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<h2 name="content"><%:Flash operations%></h2> + +<ul class="cbi-tabmenu"> + <li class="cbi-tab"><a href="#"><%:Actions%></a></li> + <li class="cbi-tab-disabled"><a href="<%=url('admin/system/flashops/backupfiles')%>"><%:Configuration%></a></li> +</ul> + +<div class="cbi-section"> + <h3><%:Backup%></h3> + <div class="cbi-section-descr"><%:Click "Generate archive" to download a tar archive of the current configuration files.%></div> + <div class="cbi-section-node"> + <form class="inline" method="post" action="<%=url('admin/system/flashops/backup')%>"> + <input type="hidden" name="token" value="<%=token%>" /> + <div class="cbi-value<% if not reset_avail then %> cbi-value-last<% end %>"> + <label class="cbi-value-title" for="image"><%:Download backup%></label> + <div class="cbi-value-field"> + <input class="cbi-button cbi-button-action important" type="submit" name="backup" value="<%:Generate archive%>" /> + </div> + </div> + </form> + </div> + + <h3><%:Restore%></h3> + <div class="cbi-section-descr"><%:To restore configuration files, you can upload a previously generated backup archive here. To reset the firmware to its initial state, click "Perform reset" (only possible with squashfs images).%></div> + <div class="cbi-section-node"> + <% if reset_avail then %> + <form class="inline" method="post" action="<%=url('admin/system/flashops/reset')%>"> + <input type="hidden" name="token" value="<%=token%>" /> + <div class="cbi-value cbi-value-last"> + <label class="cbi-value-title"><%:Reset to defaults%></label> + <div class="cbi-value-field"> + <input onclick="return confirm('<%:Really reset all changes?%>')" class="cbi-button cbi-button-reset" type="submit" name="reset" value="<%:Perform reset%>" /> + </div> + </div> + </form> + <% end %> + <form class="inline" method="post" action="<%=url('admin/system/flashops/restore')%>" enctype="multipart/form-data"> + <div class="cbi-value cbi-value-last"> + <label class="cbi-value-title" for="archive"><%:Restore backup%></label> + <div class="cbi-value-field"> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="file" name="archive" id="archive" /> + <input type="submit" class="cbi-button cbi-button-action important" name="restore" value="<%:Upload archive...%>" /> + <% if reset_avail then %> + <div class="cbi-value-description"><%:Custom files (certificates, scripts) may remain on the system. To prevent this, perform a factory-reset first.%></div> + <% end %> + </div> + </div> + </form> + <% if backup_invalid then %> + <div class="cbi-section-error"><%:The backup archive does not appear to be a valid gzip file.%></div> + <% end %> + </div> + + <% local mtds = require("luci.sys").mtds(); if #mtds > 0 then -%> + <h3><%:Save mtdblock contents%></h3> + <div class="cbi-section-descr"><%:Click "Save mtdblock" to download specified mtdblock file. (NOTE: THIS FEATURE IS FOR PROFESSIONALS! )%></div> + <div class="cbi-section-node"> + <form class="inline" method="post" action="<%=url('admin/system/flashops/backupmtdblock')%>"> + <input type="hidden" name="token" value="<%=token%>" /> + <div class="cbi-value"> + <label class="cbi-value-title" for="mtdblockname"><%:Choose mtdblock%></label> + <div class="cbi-value-field"> + <select class="cbi-input-select" data-update="change" name="mtdblockname" id="mtdblockname"> + <% for i, key in ipairs(mtds) do + if key and key.name ~= "rootfs_data" then -%> + <option<%= + attr("id", "mtdblockname-" .. key.name) .. + attr("value", key.name .. '/'.. key.size .. '/' .. i - 1) .. + attr("data-index", i) .. + ifattr(key.name == "linux" or key.name == "firmware", "selected", "selected") + %>><%=pcdata(key.name)%></option> + <% end + end -%> + </select> + </div> + </div> + <div class="cbi-value cbi-value-last<% if reset_avail then %> cbi-value-error<% end %>"> + <label class="cbi-value-title" for="image"><%:Download mtdblock%></label> + <div class="cbi-value-field"> + <input type="submit" class="cbi-button cbi-button-action important" value="<%:Save mtdblock%>" /> + </div> + </div> + </form> + </div> + <% end %> + +</div> + +<div class="cbi-section"> + <h3><%:Flash new firmware image%></h3> + <% if upgrade_avail then %> + <form method="post" action="<%=url('admin/system/flashops/sysupgrade')%>" enctype="multipart/form-data"> + <input type="hidden" name="token" value="<%=token%>" /> + <div class="cbi-section-descr"><%:Upload a sysupgrade-compatible image here to replace the running firmware. Check "Keep settings" to retain the current configuration (requires a compatible firmware image).%></div> + <div class="cbi-section-node"> + <div class="cbi-value"> + <label class="cbi-value-title" for="keep"><%:Keep settings%></label> + <div class="cbi-value-field"> + <input type="checkbox" name="keep" id="keep" checked="checked" /> + </div> + </div> + <% if image_invalid then %> + <div class="cbi-value"> + <label class="cbi-value-title" for="force"><%:Force upgrade%></label> + <div class="cbi-value-field"> + <input type="checkbox" name="force" id="force" /> + </div> + <div class="cbi-section-error"> + <%:The uploaded image file does not contain a supported format. Make sure that you choose the generic image format for your platform. %> + <%:Select 'Force upgrade' to flash the image even if the image format check fails. Use only if you are sure that the firmware is correct and meant for your device! %> + </div> + </div> + <% end %> + <div class="cbi-value cbi-value-last<% if image_invalid then %> cbi-value-error<% end %>"> + <label class="cbi-value-title" for="image"><%:Image%></label> + <div class="cbi-value-field"> + <input type="file" name="image" id="image" /> + <input type="submit" class="cbi-button cbi-button-action important" value="<%:Flash image...%>" /> + </div> + </div> + </div> + </form> + <% else %> + <div class="cbi-section-descr"><%:Sorry, there is no sysupgrade support present; a new firmware image must be flashed manually. Please refer to the wiki for device specific install instructions.%></div> + <% end %> +</div> + +<%+footer%> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm b/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm new file mode 100644 index 0000000000..a7ff4e50bd --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/ipkg.htm @@ -0,0 +1,10 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<ul class="cbi-tabmenu"> + <li class="cbi-tab-disabled"><a href="<%=url("admin/system/packages")%>"><%:Actions%></a></li> + <li class="cbi-tab"><a href="#"><%:Configuration%></a></li> +</ul> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/packages.htm b/modules/luci-mod-system/luasrc/view/admin_system/packages.htm new file mode 100644 index 0000000000..280eabb8ea --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/packages.htm @@ -0,0 +1,213 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2010 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<%- +local opkg = require "luci.model.ipkg" +local fs = require "nixio.fs" +local wa = require "luci.tools.webadmin" +local rowcnt = 1 + +function rowstyle() + rowcnt = rowcnt + 1 + return (rowcnt % 2) + 1 +end + +local fstat = fs.statvfs(opkg.overlay_root()) +local space_total = fstat and fstat.blocks or 0 +local space_free = fstat and fstat.bfree or 0 +local space_used = space_total - space_free + +local used_perc = math.floor(0.5 + ((space_total > 0) and ((100 / space_total) * space_used) or 100)) +local free_byte = space_free * fstat.frsize + +local filter = { } + + +local opkg_list = luci.model.ipkg.list_all +local querypat +if query and #query > 0 then + querypat = '*%s*' % query + opkg_list = luci.model.ipkg.find +end + +local letterpat +if letter == 35 then + letterpat = "[^a-z]*" +else + letterpat = string.char(letter, 42) -- 'A' '*' +end + +-%> + +<%+header%> + + +<h2 name="content"><%:Software%></h2> + +<div class="cbi-map"> + + <ul class="cbi-tabmenu"> + <li class="cbi-tab"><a href="#"><%:Actions%></a></li> + <li class="cbi-tab-disabled"><a href="<%=REQUEST_URI%>/ipkg"><%:Configuration%></a></li> + </ul> + + <form method="post" action="<%=REQUEST_URI%>"> + <input type="hidden" name="exec" value="1" /> + <input type="hidden" name="token" value="<%=token%>" /> + + <div class="cbi-section"> + <div class="cbi-section-node"> + <% if (install and next(install)) or (remove and next(remove)) or update or upgrade then %> + <div class="cbi-value"> + <% if #stdout > 0 then %><pre><%=pcdata(stdout)%></pre><% end %> + <% if #stderr > 0 then %><pre class="error"><%=pcdata(stderr)%></pre><% end %> + </div> + <% end %> + + <% if querypat then %> + <div class="cbi-value"> + <%:Displaying only packages containing%> <strong>"<%=pcdata(query)%>"</strong> + <input type="button" onclick="location.href='?display=<%=luci.http.urlencode(display)%>'" href="#" class="cbi-button cbi-button-reset" style="margin-left:1em" value="<%:Reset%>" /> + <br style="clear:both" /> + </div> + <% end %> + + <% if no_lists or old_lists then %> + <div class="cbi-value"> + <% if old_lists then %> + <%:Package lists are older than 24 hours%> + <% else %> + <%:No package lists available%> + <% end %> + <input type="submit" name="update" href="#" class="cbi-button cbi-button-apply" style="margin-left:3em" value="<%:Update lists%>" /> + </div> + <% end %> + + <div class="cbi-value cbi-value-last"> + <%:Free space%>: <strong><%=(100-used_perc)%>%</strong> (<strong><%=wa.byte_format(free_byte)%></strong>) + <div style="margin:3px 0; width:300px; height:10px; border:1px solid #000000; background-color:#80C080"> + <div style="background-color:#F08080; border-right:1px solid #000000; height:100%; width:<%=used_perc%>%"> </div> + </div> + </div> + </div> + + <br /> + + <div class="cbi-section-node"> + <input type="hidden" name="display" value="<%=pcdata(display)%>" /> + + <div class="cbi-value"> + <label class="cbi-value-title"><%:Download and install package%>:</label> + <div class="cbi-value-field"> + <span><input type="text" name="url" size="30" value="" /></span> + <input class="cbi-button cbi-button-save" type="submit" name="go" value="<%:OK%>" /> + </div> + </div> + + <div class="cbi-value cbi-value-last"> + <label class="cbi-value-title"><%:Filter%>:</label> + <div class="cbi-value-field"> + <span><input type="text" name="query" size="20" value="<%=pcdata(query)%>" /></span> + <input type="submit" class="cbi-button cbi-button-action" name="search" value="<%:Find package%>" /> + </div> + </div> + </div> + </div> + </form> + + + <h3><%:Status%></h3> + + + <ul class="cbi-tabmenu"> + <li class="cbi-tab<% if display ~= "available" then %>-disabled<% end %>"><a href="?display=available&query=<%=pcdata(query)%>"><%:Available packages%><% if query then %> (<%=pcdata(query)%>)<% end %></a></li> + <li class="cbi-tab<% if display ~= "installed" then %>-disabled<% end %>"><a href="?display=installed&query=<%=pcdata(query)%>"><%:Installed packages%><% if query then %> (<%=pcdata(query)%>)<% end %></a></li> + </ul> + + <% if display ~= "available" then %> + <div class="cbi-section"> + <div class="cbi-section-node"> + <div class="table"> + <div class="tr cbi-section-table-titles"> + <div class="th left"><%:Package name%></div> + <div class="th left"><%:Version%></div> + <div class="th cbi-section-actions"> </div> + </div> + <% local empty = true; luci.model.ipkg.list_installed(querypat, function(n, v, s, d) empty = false; filter[n] = true %> + <div class="tr cbi-rowstyle-<%=rowstyle()%>"> + <div class="td left"><%=luci.util.pcdata(n)%></div> + <div class="td left"><%=luci.util.pcdata(v)%></div> + <div class="td cbi-section-actions"> + <form method="post" class="inline" action="<%=REQUEST_URI%>"> + <input type="hidden" name="exec" value="1" /> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="hidden" name="remove" value="<%=pcdata(n)%>" /> + <input class="cbi-button cbi-button-remove" type="submit" onclick="window.confirm('<%:Remove%> "<%=luci.util.pcdata(n)%>" ?') && this.parentNode.submit(); return false" value="<%:Remove%>" /> + </form> + </div> + </div> + <% end) %> + <% if empty then %> + <div class="tr cbi-section-table-row"> + <div class="td left"> </div> + <div class="td left"><em><%:none%></em></div> + <div class="td left"><em><%:none%></em></div> + </div> + <% end %> + </div> + </div> + </div> + <% else %> + <div class="cbi-section"> + <% if not querypat then %> + <ul class="cbi-tabmenu" style="flex-wrap:wrap"> + <% local i; for i = 65, 90 do %> + <li class="cbi-tab<% if letter ~= i then %>-disabled<% end %>"><a href="?display=available&letter=<%=string.char(i)%>"><%=string.char(i)%></a></li> + <% end %> + <li class="cbi-tab<% if letter ~= 35 then %>-disabled<% end %>"><a href="?display=available&letter=%23">#</a></li> + </ul> + <% end %> + <div class="cbi-section-node cbi-section-node-tabbed"> + <div class="table"> + <div class="tr cbi-section-table-titles"> + <div class="th col-2 left"><%:Package name%></div> + <div class="th col-2 left"><%:Version%></div> + <div class="th col-1 center"><%:Size (.ipk)%></div> + <div class="th col-10 left"><%:Description%></div> + <div class="th cbi-section-actions"> </div> + </div> + <% local empty = true; opkg_list(querypat or letterpat, function(n, v, s, d) if filter[n] then return end; empty = false %> + <div class="tr cbi-rowstyle-<%=rowstyle()%>"> + <div class="td col-2 left"><%=luci.util.pcdata(n)%></div> + <div class="td col-2 left"><%=luci.util.pcdata(v)%></div> + <div class="td col-1 center"><%=luci.util.pcdata(s)%></div> + <div class="td col-10 left"><%=luci.util.pcdata(d)%></div> + <div class="td cbi-section-actions"> + <form method="post" class="inline" action="<%=REQUEST_URI%>"> + <input type="hidden" name="exec" value="1" /> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="hidden" name="install" value="<%=pcdata(n)%>" /> + <input class="cbi-button cbi-button-apply" type="submit" onclick="window.confirm('<%:Install%> "<%=luci.util.pcdata(n)%>" ?') && this.parentNode.submit(); return false" value="<%:Install%>" /> + </form> + </div> + </div> + <% end) %> + <% if empty then %> + <div class="tr"> + <div class="td left"> </div> + <div class="td left"><em><%:none%></em></div> + <div class="td left"><em><%:none%></em></div> + <div class="td right"><em><%:none%></em></div> + <div class="td left"><em><%:none%></em></div> + </div> + <% end %> + </div> + </div> + </div> + <% end %> +</div> + +<%+footer%> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm b/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm new file mode 100644 index 0000000000..d23664adac --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/reboot.htm @@ -0,0 +1,62 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2015 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<h2 name="content"><%:Reboot%></h2> + +<p><%:Reboots the operating system of your device%></p> + +<%- local c = require("luci.model.uci").cursor():changes(); if c and next(c) then -%> + <p class="alert-message warning"><%:Warning: There are unsaved changes that will get lost on reboot!%></p> +<%- end -%> + +<hr /> + +<input class="cbi-button cbi-button-action important" type="button" value="<%:Perform reboot%>" onclick="reboot(this)" /> + +<p class="alert-message notice reboot-message" style="display:none"> + <img src="<%=resource%>/icons/loading.gif" alt="<%:Loading%>" style="vertical-align:middle" /> + <span><%:Device is rebooting...%></span> +</p> + +<script type="text/javascript">//<![CDATA[ + var tries = 0, + message = document.querySelector('p.reboot-message'), + label = message.querySelector('span'); + + function ok() { + window.location = '<%=url("admin")%>'; + } + + function check() { + window.setTimeout(ping, 5000); + } + + function ping() { + var img = document.createElement('img'); + + img.onload = ok; + img.onerror = check; + img.src = '<%=resource%>/icons/loading.gif?' + Math.random(); + + if (tries++ >= 30) { + message.classList.remove('notice'); + message.classList.add('warning'); + label.innerHTML = '<%:Device unreachable! Still waiting for device...%>'; + } + } + + function reboot(button) { + button.style.display = 'none'; + message.style.display = ''; + label.innerHTML = '<%:Waiting for device...%>'; + + (new XHR()).post('<%=url("admin/system/reboot/call")%>', { token: '<%=token%>' }, check); + } +//]]></script> + +<%+footer%> diff --git a/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm b/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm new file mode 100644 index 0000000000..597ddfd6bf --- /dev/null +++ b/modules/luci-mod-system/luasrc/view/admin_system/upgrade.htm @@ -0,0 +1,65 @@ +<%# + Copyright 2008 Steven Barth <steven@midlink.org> + Copyright 2008-2009 Jo-Philipp Wich <jow@openwrt.org> + Licensed to the public under the Apache License 2.0. +-%> + +<%+header%> + +<h2 name="content"><%:Flash Firmware%> - <%:Verify%></h2> +<p> + <%_ The flash image was uploaded. + Below is the checksum and file size listed, + compare them with the original file to ensure data integrity.<br /> + Click "Proceed" below to start the flash procedure. %> + + <% if storage > 0 and size > storage then %> + <br /><br /> + <div class="error"><%:It appears that you are trying to + flash an image that does not fit into the flash memory, please verify + the image file! %></div> + <% end %> + +</p> + +<div class="cbi-section"> + <ul> + <li><%:Checksum%><br /> + <%:MD5%>: <code><%=checksum%></code><br /> + <%:SHA256%>: <code><%=sha256ch%></code></li> + <li><%:Size%>: <% + local w = require "luci.tools.webadmin" + write(w.byte_format(size)) + + if storage > 0 then + write(luci.i18n.translatef( + " (%s available)", + w.byte_format(storage) + )) + end + %></li> + <li><% if keep then %> + <%:Configuration files will be kept%> + <% else %> + <%:Caution: Configuration files will be erased%> + <% end %></li> + <% if force then %> + <li> + <%:Caution: System upgrade will be forced%> + </li> + <% end %> + </ul> +</div> + +<div class="cbi-page-actions right"> + <form class="inline" action="<%=REQUEST_URI%>" method="post"> + <input type="hidden" name="token" value="<%=token%>" /> + <input type="hidden" name="step" value="2" /> + <input type="hidden" name="keep" value="<%=keep and "1" or ""%>" /> + <input type="hidden" name="force" value="<%=force and "1" or ""%>" /> + <input class="cbi-button cbi-button-reset" name="cancel" type="submit" value="<%:Cancel%>" /> + <input class="cbi-button cbi-button-apply" type="submit" value="<%:Proceed%>" /> + </form> +</div> + +<%+footer%> |