From 7d502cfa86f4174503ae8c48330ce8b047e0a835 Mon Sep 17 00:00:00 2001 From: Nils Schneider Date: Mon, 30 Sep 2013 18:42:47 +0200 Subject: [PATCH] basic admin mode --- gluon/gluon-luci-admin/Makefile | 39 +++ .../lib/lua/luci/controller/admin/index.lua | 52 ++++ .../lib/lua/luci/controller/admin/system.lua | 244 ++++++++++++++++++ .../lib/lua/luci/model/cbi/admin/index.lua | 14 + .../lib/lua/luci/model/cbi/admin/passwd.lua | 45 ++++ .../lib/lua/luci/view/admin/applyreboot.htm | 21 ++ .../usr/lib/lua/luci/view/admin/backup.htm | 40 +++ .../usr/lib/lua/luci/view/admin/index.htm | 21 ++ .../usr/lib/lua/luci/view/admin/reboot.htm | 33 +++ .../usr/lib/lua/luci/view/admin/upgrade.htm | 105 ++++++++ 10 files changed, 614 insertions(+) create mode 100644 gluon/gluon-luci-admin/Makefile create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/system.lua create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/index.lua create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/passwd.lua create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/applyreboot.htm create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/backup.htm create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/index.htm create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/reboot.htm create mode 100644 gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm diff --git a/gluon/gluon-luci-admin/Makefile b/gluon/gluon-luci-admin/Makefile new file mode 100644 index 0000000..45a849d --- /dev/null +++ b/gluon/gluon-luci-admin/Makefile @@ -0,0 +1,39 @@ +# Copyright (C) 2013 Nils Schneider +# This is free software, licensed under the Apache 2.0 license. + +include $(TOPDIR)/rules.mk + +PKG_NAME:=gluon-luci-admin +PKG_VERSION:=0.1 +PKG_RELEASE:=1 + +PKG_BUILD_DIR := $(BUILD_DIR)/$(PKG_NAME) + +include $(INCLUDE_DIR)/package.mk + +define Package/gluon-luci-admin + SECTION:=gluon + CATEGORY:=Gluon + TITLE:=Luci based simple administration interface for mesh nodes + DEPENDS:=+gluon-core +luci-mod-admin-core +luci-theme-openwrt +endef + +define Package/gluon-luci-admin/description + Luci based config mode +endef + +define Build/Prepare + mkdir -p $(PKG_BUILD_DIR) +endef + +define Build/Configure +endef + +define Build/Compile +endef + +define Package/gluon-luci-admin/install + $(CP) ./files/* $(1)/ +endef + +$(eval $(call BuildPackage,gluon-luci-admin)) diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua new file mode 100644 index 0000000..7fbd117 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/index.lua @@ -0,0 +1,52 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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 uci_state = luci.model.uci.cursor_state() + local configmode = uci_state:get_first("configmode", "wizard", "running", "0") == "1" + + local root = node() + if not root.lock then + root.target = alias("admin") + root.index = true + end + + local page = entry({"admin"}, alias("admin", "index"), _("Expertmode"), 10) + page.sysauth = "root" + if configmode then + -- force root to be logged in when running in configmode + page.sysauth_authenticator = function() return "root" end + else + page.sysauth_authenticator = "htmlauth" + end + page.index = true + + entry({"admin", "index"}, form("admin/index"), _("Overview"), 1).ignoreindex = true + entry({"admin", "logout"}, call("action_logout"), _("Logout")) +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/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/system.lua b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/system.lua new file mode 100644 index 0000000..cb0152c --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/controller/admin/system.lua @@ -0,0 +1,244 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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", "passwd"}, form("admin/passwd"), _("Admin Password"), 10) + entry({"admin", "backup"}, call("action_backup"), _("Backup / Restore"), 80) + entry({"admin", "upgrade"}, call("action_upgrade"), _("Flash Firmware"), 90) + entry({"admin", "reboot"}, call("action_reboot"), _("Reboot"), 100) +end + +function action_backup() + local reset_avail = os.execute([[grep '"rootfs_data"' /proc/mtd >/dev/null 2>&1]]) == 0 + local restore_cmd = "gunzip | tar -xC/ >/dev/null 2>&1" + local backup_cmd = "tar -c %s | gzip 2>/dev/null" + + local restore_fpi + luci.http.setfilehandler( + function(meta, chunk, eof) + if not restore_fpi then + restore_fpi = io.popen(restore_cmd, "w") + end + if chunk then + restore_fpi:write(chunk) + end + if eof then + restore_fpi:close() + end + end + ) + + local upload = luci.http.formvalue("archive") + local backup = luci.http.formvalue("backup") + local reset = reset_avail and luci.http.formvalue("reset") + + if upload and #upload > 0 then + luci.template.render("admin/applyreboot") + luci.sys.reboot() + elseif backup then + local reader = ltn12_popen(backup_cmd:format(_keep_pattern())) + 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 reset then + luci.template.render("admin/applyreboot") + luci.util.exec("mtd -r erase rootfs_data") + else + luci.template.render("admin/backup", {reset_avail = reset_avail}) + end +end + +function action_reboot() + local reboot = luci.http.formvalue("reboot") + luci.template.render("admin/reboot", {reboot=reboot}) + if reboot then + luci.sys.reboot() + end +end + +function action_upgrade() + require("luci.model.uci") + + local tmpfile = "/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" + % tmpfile + ) ) + end + + local function image_checksum() + return (luci.sys.exec("md5sum %q" % tmpfile):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" 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 + + + -- Install upload handler + local file + luci.http.setfilehandler( + function(meta, chunk, eof) + if not nixio.fs.access(tmpfile) and not file and chunk and #chunk > 0 then + file = io.open(tmpfile, "w") + end + if file and chunk then + file:write(chunk) + end + if file and eof then + file:close() + end + end + ) + + + -- Determine state + local keep_avail = true + local step = tonumber(luci.http.formvalue("step") or 1) + local has_image = nixio.fs.access(tmpfile) + local has_support = image_supported() + local has_platform = nixio.fs.access("/lib/upgrade/platform.sh") + local has_upload = luci.http.formvalue("image") + + -- This does the actual flashing which is invoked inside an iframe + -- so don't produce meaningful errors here because the the + -- previous pages should arrange the stuff as required. + if step == 4 then + if has_platform and has_image and has_support then + -- Mimetype text/plain + luci.http.prepare_content("text/plain") + luci.http.write("Starting luci-flash...\n") + + -- Now invoke sysupgrade + local keepcfg = keep_avail and luci.http.formvalue("keepcfg") == "1" + local flash = ltn12_popen("/sbin/luci-flash %s %q" %{ + keepcfg and "-k %q" % _keep_pattern() or "", tmpfile + }) + + luci.ltn12.pump.all(flash, luci.http.write) + + -- Make sure the device is rebooted + luci.sys.reboot() + end + + + -- + -- This is step 1-3, which does the user interaction and + -- image upload. + -- + + -- Step 1: file upload, error on unsupported image format + elseif not has_image or not has_support or step == 1 then + -- If there is an image but user has requested step 1 + -- or type is not supported, then remove it. + if has_image then + nixio.fs.unlink(tmpfile) + end + + luci.template.render("admin/upgrade", { + step=1, + bad_image=(has_image and not has_support or false), + keepavail=keep_avail, + supported=has_platform + } ) + + -- Step 2: present uploaded file, show checksum, confirmation + elseif step == 2 then + luci.template.render("admin/upgrade", { + step=2, + checksum=image_checksum(), + filesize=nixio.fs.stat(tmpfile).size, + flashsize=storage_size(), + keepconfig=(keep_avail and luci.http.formvalue("keepcfg") == "1") + } ) + + -- Step 3: load iframe which calls the actual flash procedure + elseif step == 3 then + luci.template.render("admin/upgrade", { + step=3, + keepconfig=(keep_avail and luci.http.formvalue("keepcfg") == "1") + } ) + end +end + +function _keep_pattern() + local kpattern = "" + local files = luci.model.uci.cursor():get_all("luci", "flash_keep") + if files then + kpattern = "" + for k, v in pairs(files) do + if k:sub(1,1) ~= "." and nixio.fs.glob(v)() then + kpattern = kpattern .. " " .. v + end + end + end + return kpattern +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/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/index.lua b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/index.lua new file mode 100644 index 0000000..cd05724 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/index.lua @@ -0,0 +1,14 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth + +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$ +]]-- +return Template("admin/index") diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/passwd.lua b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/passwd.lua new file mode 100644 index 0000000..5b9efc4 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/model/cbi/admin/passwd.lua @@ -0,0 +1,45 @@ +--[[ +LuCI - Lua Configuration Interface + +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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$ +]]-- +f = SimpleForm("password", translate("Admin Password"), translate("Change the password of the system administrator (User root)")) + +pw1 = f:field(Value, "pw1", translate("Password")) +pw1.password = true +pw1.rmempty = false + +pw2 = f:field(Value, "pw2", translate("Confirmation")) +pw2.password = true +pw2.rmempty = false + +function pw2.validate(self, value, section) + return pw1:formvalue(section) == value and value +end + +function f.handle(self, state, data) + if state == FORM_VALID then + local stat = luci.sys.user.setpasswd("root", data.pw1) == 0 + + if stat then + f.message = translate("Password successfully changed") + else + f.errmessage = translate("Unknown Error") + end + + data.pw1 = nil + data.pw2 = nil + end + return true +end + +return f diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/applyreboot.htm b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/applyreboot.htm new file mode 100644 index 0000000..8ff7118 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/applyreboot.htm @@ -0,0 +1,21 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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$ + +-%> +<%+header%> +

<%:System%>

+
+

<% if msg then %><%=msg%><% else %><%:Changes applied.%><% end %>

+

<%:Please wait: Device rebooting...%>

+ +<%+footer%> \ No newline at end of file diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/backup.htm b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/backup.htm new file mode 100644 index 0000000..eb9dc46 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/backup.htm @@ -0,0 +1,40 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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$ + +-%> +<%+header%> +

<%:System%>

+

<%:Backup / Restore%>

+

<%:Here you can backup and restore your configuration and - if possible - reset this device to the default settings.%>

+
+
+ +
+ +
+ +
+
<%:Backup Archive%>:
+
+ +
+
+ +
+
+<%+footer%> diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/index.htm b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/index.htm new file mode 100644 index 0000000..c14d3b0 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/index.htm @@ -0,0 +1,21 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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$ + +-%> +

<%:Hello!%>

+

<%_This is the administration area of LuCI.%>

+

<%_LuCI is a free, flexible, and user friendly graphical interface for configuring OpenWrt.%>
+<%:On the following pages you can adjust all important settings of this device.%>

+

<%:As we always want to improve this interface we are looking forward to your feedback and suggestions.%>

+

<%:And now have fun with your OpenWrt device!%>

+

<%_The LuCI Team%>

diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/reboot.htm b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/reboot.htm new file mode 100644 index 0000000..9e57d89 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/reboot.htm @@ -0,0 +1,33 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008 Jo-Philipp Wich + +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$ + +-%> +<%+header%> +

<%:System%>

+

<%:Reboot%>

+

<%:Reboots the operating system of your device%>

+<%- +local c = require("luci.model.uci").cursor():changes() +if c and next(c) then +-%> +

<%:Warning: There are unsaved changes that will be lost while rebooting!%>

+<%- +end +if not reboot then +-%> +

<%:Perform reboot%>

+<%- else -%> +

<%:Please wait: Device rebooting...%>

+ +<%- end -%> +<%+footer%> \ No newline at end of file diff --git a/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm new file mode 100644 index 0000000..1083a16 --- /dev/null +++ b/gluon/gluon-luci-admin/files/usr/lib/lua/luci/view/admin/upgrade.htm @@ -0,0 +1,105 @@ +<%# +LuCI - Lua Configuration Interface +Copyright 2008 Steven Barth +Copyright 2008-2009 Jo-Philipp Wich + +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$ + +-%> + +<%+header%> + +

<%:System%>

+

<%:Flash Firmware%>

+ +<% if step == 1 then %> + <% if supported then %> +
+

+ <%:Upload an OpenWrt image file to reflash the device.%> + <% if bad_image then %> +

+

<%:The uploaded image file does not + contain a supported format. Make sure that you choose the generic + image format for your platform. %>
+ <% end %> +

+
+ <%:Firmware image%>:
+ + +
+
+ <% if keepavail then -%> + + <%:Keep configuration files%> + <% end -%> + +
+ +
+
+ <% else %> +
<%_ Sorry. + OpenWrt does not support a system upgrade on this platform.
+ You need to manually flash your device. %>
+ <% end %> +<% elseif step == 2 then %> +

+ <%_ The flash image was uploaded. + Below is the checksum and file size listed, + compare them with the original file to ensure data integrity.
+ Click "Proceed" below to start the flash procedure. %> + + <% if flashsize > 0 and filesize > flashsize then %> +

+

<%:It appears that you try to + flash an image that does not fit into the flash memory, please verify + the image file! %>
+ <% end %> + +
+
    +
  • <%:Checksum%>: <%=checksum%>
  • +
  • <%:Size%>: <% + local w = require "luci.tools.webadmin" + write(w.byte_format(filesize)) + + if flashsize > 0 then + write(luci.i18n.translatef( + " (%s available)", + w.byte_format(flashsize) + )) + end + %>
  • +
+

+
+
+ + " /> + +
+
+ + " /> + +
+
+<% elseif step == 3 then %> +

<%_ The system is flashing now.
+ DO NOT POWER OFF THE DEVICE!
+ Wait a few minutes until you try to reconnect. + It might be necessary to renew the address of your computer to reach the device + again, depending on your settings. %>

+ + +<% end %> +<%+footer%> +