diff --git a/luci-base/luasrc/cbi.lua b/luci-base/luasrc/cbi.lua index 218439503..472864211 100644 --- a/luci-base/luasrc/cbi.lua +++ b/luci-base/luasrc/cbi.lua @@ -388,21 +388,21 @@ function Map.parse(self, readinput, ...) if self.save then self:_run_hooks("on_save", "on_before_save") + local i, config for i, config in ipairs(self.parsechain) do self.uci:save(config) end self:_run_hooks("on_after_save") if (not self.proceed and self.flow.autoapply) or luci.http.formvalue("cbi.apply") then self:_run_hooks("on_before_commit") - for i, config in ipairs(self.parsechain) do - self.uci:commit(config) - - -- Refresh data because commit changes section names - self.uci:load(config) + if self.apply_on_parse == false then + for i, config in ipairs(self.parsechain) do + self.uci:commit(config) + end end self:_run_hooks("on_commit", "on_after_commit", "on_before_apply") - if self.apply_on_parse then - self.uci:apply(self.parsechain) + if self.apply_on_parse == true or self.apply_on_parse == false then + self.uci:apply(self.apply_on_parse) self:_run_hooks("on_apply", "on_after_apply") else -- This is evaluated by the dispatcher and delegated to the diff --git a/luci-base/luasrc/controller/admin/servicectl.lua b/luci-base/luasrc/controller/admin/servicectl.lua deleted file mode 100644 index 1d73eb4ec..000000000 --- a/luci-base/luasrc/controller/admin/servicectl.lua +++ /dev/null @@ -1,49 +0,0 @@ --- Copyright 2010 Jo-Philipp Wich --- Licensed to the public under the Apache License 2.0. - -module("luci.controller.admin.servicectl", package.seeall) - -function index() - entry({"servicectl"}, alias("servicectl", "status")).sysauth = "root" - entry({"servicectl", "status"}, call("action_status")).leaf = true - entry({"servicectl", "restart"}, post("action_restart")).leaf = true -end - -function action_status() - local data = nixio.fs.readfile("/var/run/luci-reload-status") - if data then - luci.http.write("/etc/config/") - luci.http.write(data) - else - luci.http.write("finish") - end -end - -function action_restart(args) - local uci = require "luci.model.uci".cursor() - if args then - local service - local services = { } - - for service in args:gmatch("[%w_-]+") do - services[#services+1] = service - end - - local command = uci:apply(services, true) - if nixio.fork() == 0 then - local i = nixio.open("/dev/null", "r") - local o = nixio.open("/dev/null", "w") - - nixio.dup(i, nixio.stdin) - nixio.dup(o, nixio.stdout) - - i:close() - o:close() - - nixio.exec("/bin/sh", unpack(command)) - else - luci.http.write("OK") - os.exit(0) - end - end -end diff --git a/luci-base/luasrc/dispatcher.lua b/luci-base/luasrc/dispatcher.lua index 1984fc4ad..2c58b0ab3 100644 --- a/luci-base/luasrc/dispatcher.lua +++ b/luci-base/luasrc/dispatcher.lua @@ -182,6 +182,7 @@ local function session_retrieve(sid, allowed_users) (not allowed_users or util.contains(allowed_users, sdat.values.username)) then + uci:set_session_id(sid) return sid, sdat.values end @@ -357,7 +358,7 @@ function dispatch(request) elseif key == "REQUEST_URI" then return build_url(unpack(ctx.requestpath)) elseif key == "FULL_REQUEST_URI" then - local url = { http.getenv("SCRIPT_NAME"), http.getenv("PATH_INFO") } + local url = { http.getenv("SCRIPT_NAME") or "" , http.getenv("PATH_INFO") } local query = http.getenv("QUERY_STRING") if query and #query > 0 then url[#url+1] = "?" @@ -428,7 +429,9 @@ function dispatch(request) return end - http.header("Set-Cookie", 'sysauth=%s; path=%s' %{ sid, build_url() }) + http.header("Set-Cookie", 'sysauth=%s; path=%s; HttpOnly%s' %{ + sid, build_url(), http.getenv("HTTPS") == "on" and "; secure" or "" + }) http.redirect(build_url(unpack(ctx.requestpath))) end @@ -882,6 +885,8 @@ local function _cbi(self, ...) local pageaction = true local parsechain = { } + local is_rollback, time_remaining = uci:rollback_pending() + for i, res in ipairs(maps) do if res.apply_needed and res.parsechain then local c @@ -909,6 +914,7 @@ local function _cbi(self, ...) res:render({ firstmap = (i == 1), applymap = applymap, + confirmmap = (is_rollback and time_remaining or nil), redirect = redirect, messages = messages, pageaction = pageaction, diff --git a/luci-base/luasrc/http.lua b/luci-base/luasrc/http.lua index 16fb04c54..f4ede4b8a 100644 --- a/luci-base/luasrc/http.lua +++ b/luci-base/luasrc/http.lua @@ -14,7 +14,7 @@ local table, ipairs, pairs, type, tostring, tonumber, error = module "luci.http" -HTTP_MAX_CONTENT = 1024*8 -- 8 kB maximum content size +HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size context = util.threadlocal() @@ -416,7 +416,7 @@ function mimedecode_message_body(src, msg, file_cb) end return true - end) + end, HTTP_MAX_CONTENT) return ltn12.pump.all(src, function (chunk) len = len + (chunk and #chunk or 0) @@ -460,7 +460,7 @@ function urldecode_message_body(src, msg) end return true - end) + end, HTTP_MAX_CONTENT) return ltn12.pump.all(src, function (chunk) len = len + (chunk and #chunk or 0) diff --git a/luci-base/luasrc/model/network.lua b/luci-base/luasrc/model/network.lua index dfe818bcc..d5029ec90 100644 --- a/luci-base/luasrc/model/network.lua +++ b/luci-base/luasrc/model/network.lua @@ -1273,7 +1273,7 @@ function interface.get_i18n(self) return "%s: %s %q" %{ lng.translate("Wireless Network"), self.wif:active_mode(), - self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id() + self.wif:active_ssid() or self.wif:active_bssid() or self.wif:id() or "?" } else return "%s: %q" %{ self:get_type_i18n(), self:name() } @@ -1428,7 +1428,7 @@ function wifidev.hwmodes(self) end function wifidev.get_i18n(self) - local t = "Generic" + local t = self.iwinfo.hardware_name or "Generic" if self.iwinfo.type == "wl" then t = "Broadcom" end diff --git a/luci-base/luasrc/model/uci.lua b/luci-base/luasrc/model/uci.lua index fc2a605b3..461ba9d5a 100644 --- a/luci-base/luasrc/model/uci.lua +++ b/luci-base/luasrc/model/uci.lua @@ -143,22 +143,85 @@ function commit(self, config) return (err == nil), ERRSTR[err] end ---[[ -function apply(self, configs, command) - local _, config +function apply(self, rollback) + local _, err - assert(not command, "Apply command not supported anymore") + if rollback then + local conf = require "luci.config" + local timeout = tonumber(conf and conf.apply and conf.apply.rollback or "") or 0 - if type(configs) == "table" then - for _, config in ipairs(configs) do - call("service", "event", { - type = "config.change", - data = { package = config } + _, err = call("apply", { + timeout = (timeout > 30) and timeout or 30, + rollback = true + }) + + if not err then + util.ubus("session", "set", { + ubus_rpc_session = session_id, + values = { rollback = os.time() + timeout } }) end + else + _, err = call("changes", {}) + + if not err then + if type(_) == "table" and type(_.changes) == "table" then + local k, v + for k, v in pairs(_.changes) do + _, err = call("commit", { config = k }) + if err then + break + end + end + end + end + + if not err then + _, err = call("apply", { rollback = false }) + end end + + return (err == nil), ERRSTR[err] +end + +function confirm(self) + local _, err = call("confirm", {}) + if not err then + util.ubus("session", "set", { + ubus_rpc_session = session_id, + values = { rollback = 0 } + }) + end + return (err == nil), ERRSTR[err] +end + +function rollback(self) + local _, err = call("rollback", {}) + if not err then + util.ubus("session", "set", { + ubus_rpc_session = session_id, + values = { rollback = 0 } + }) + end + return (err == nil), ERRSTR[err] +end + +function rollback_pending(self) + local deadline, err = util.ubus("session", "get", { + ubus_rpc_session = session_id, + keys = { "rollback" } + }) + + if type(deadline) == "table" and + type(deadline.values) == "table" and + type(deadline.values.rollback) == "number" and + deadline.values.rollback > os.time() + then + return true, deadline.values.rollback - os.time() + end + + return false, ERRSTR[err] end -]] function foreach(self, config, stype, callback) @@ -425,59 +488,3 @@ function delete_all(self, config, stype, comparator) return (err == nil), ERRSTR[err] end - - -function apply(self, configlist, command) - configlist = self:_affected(configlist) - if command then - return { "/sbin/luci-reload", unpack(configlist) } - else - return os.execute("/sbin/luci-reload %s >/dev/null 2>&1" - % util.shellquote(table.concat(configlist, " "))) - end -end - --- Return a list of initscripts affected by configuration changes. -function _affected(self, configlist) - configlist = type(configlist) == "table" and configlist or { configlist } - - -- Resolve dependencies - local reloadlist = { } - - local function _resolve_deps(name) - local reload = { name } - local deps = { } - - self:foreach("ucitrack", name, - function(section) - if section.affects then - for i, aff in ipairs(section.affects) do - deps[#deps+1] = aff - end - end - end) - - local i, dep - for i, dep in ipairs(deps) do - local j, add - for j, add in ipairs(_resolve_deps(dep)) do - reload[#reload+1] = add - end - end - - return reload - end - - -- Collect initscripts - local j, config - for j, config in ipairs(configlist) do - local i, e - for i, e in ipairs(_resolve_deps(config)) do - if not util.contains(reloadlist, e) then - reloadlist[#reloadlist+1] = e - end - end - end - - return reloadlist -end diff --git a/luci-base/luasrc/model/uci.luadoc b/luci-base/luasrc/model/uci.luadoc index ef89d09b9..d798b0033 100644 --- a/luci-base/luasrc/model/uci.luadoc +++ b/luci-base/luasrc/model/uci.luadoc @@ -28,12 +28,63 @@ Create a new Cursor initialized to the state directory. ]] ---[[ -Applies UCI configuration changes +Applies UCI configuration changes. + +If the rollback parameter is set to true, the apply function will invoke the +rollback mechanism which causes the configuration to be automatically reverted +if no confirm() call occurs within a certain timeout. + +The current default timeout is 30s and can be increased using the +"luci.apply.timeout" uci configuration key. @class function @name Cursor.apply -@param configlist List of UCI configurations -@param command Don't apply only return the command +@param rollback Enable rollback mechanism +@return Boolean whether operation succeeded +]] + +---[[ +Confirms UCI apply process. + +If a previous UCI apply with rollback has been invoked using apply(true), +this function confirms the process and cancels the pending rollback timer. + +If no apply with rollback session is active, the function has no effect and +returns with a "No data" error. + +@class function +@name Cursor.confirm +@return Boolean whether operation succeeded +]] + +---[[ +Cancels UCI apply process. + +If a previous UCI apply with rollback has been invoked using apply(true), +this function cancels the process and rolls back the configuration to the +pre-apply state. + +If no apply with rollback session is active, the function has no effect and +returns with a "No data" error. + +@class function +@name Cursor.rollback +@return Boolean whether operation succeeded +]] + +---[[ +Checks whether a pending rollback is scheduled. + +If a previous UCI apply with rollback has been invoked using apply(true), +and has not been confirmed or rolled back yet, this function returns true +and the remaining time until rollback in seconds. If no rollback is pending, +the function returns false. On error, the function returns false and an +additional string describing the error. + +@class function +@name Cursor.rollback_pending +@return Boolean whether rollback is pending +@return Remaining time in seconds ]] ---[[ diff --git a/luci-base/luasrc/view/cbi/apply_widget.htm b/luci-base/luasrc/view/cbi/apply_widget.htm new file mode 100644 index 000000000..543ef0b80 --- /dev/null +++ b/luci-base/luasrc/view/cbi/apply_widget.htm @@ -0,0 +1,181 @@ +<% export("cbi_apply_widget", function(redirect_ok) -%> + + + + +<%- end) %> diff --git a/luci-base/luasrc/view/cbi/apply_xhr.htm b/luci-base/luasrc/view/cbi/apply_xhr.htm deleted file mode 100644 index daa57c1db..000000000 --- a/luci-base/luasrc/view/cbi/apply_xhr.htm +++ /dev/null @@ -1,43 +0,0 @@ -<% export("cbi_apply_xhr", function(id, configs, redirect) -%> -
- <%:Applying changes%> - - - <%:Loading%> - <%:Waiting for changes to be applied...%> -
-<%- end) %> diff --git a/luci-base/luasrc/view/cbi/map.htm b/luci-base/luasrc/view/cbi/map.htm index e3210add6..69ef3615a 100644 --- a/luci-base/luasrc/view/cbi/map.htm +++ b/luci-base/luasrc/view/cbi/map.htm @@ -2,12 +2,23 @@
<%=pcdata(msg)%>
<%- end end -%> -<%-+cbi/apply_xhr-%> -
<% if self.title and #self.title > 0 then %>

<%=self.title%>

<% end %> <% if self.description and #self.description > 0 then %>
<%=self.description%>
<% end %> - <%- if firstmap and applymap then cbi_apply_xhr(self.config, parsechain, redirect) end -%> + <%- if firstmap and (applymap or confirmmap) then -%> + <%+cbi/apply_widget%> + <% cbi_apply_widget(redirect) %> + + + <%- end -%> <% if self.tabbed then %>