diff options
-rw-r--r-- | .gitignore | 7 | ||||
-rwxr-xr-x | build/mkbasepot.sh | 2 | ||||
-rwxr-xr-x | build/zoneinfo2ucode.pl | 2 | ||||
-rw-r--r-- | libs/luci-lib-base/luasrc/http.lua | 464 | ||||
-rw-r--r-- | libs/luci-lib-base/luasrc/util.lua | 27 | ||||
-rw-r--r-- | modules/luci-base-ucode/Makefile | 45 | ||||
-rwxr-xr-x | modules/luci-base-ucode/htdocs/cgi-bin/luci-ucode | 41 | ||||
-rw-r--r-- | modules/luci-base-ucode/luasrc/ucodebridge/luci/http.lua | 144 | ||||
-rw-r--r-- | modules/luci-base-ucode/luasrc/ucodebridge/luci/util.lua | 786 | ||||
-rw-r--r-- | modules/luci-base-ucode/src/Makefile | 28 | ||||
-rw-r--r-- | modules/luci-base/Makefile | 32 | ||||
-rwxr-xr-x | modules/luci-base/htdocs/cgi-bin/luci | 46 | ||||
-rw-r--r-- | modules/luci-base/luasrc/controller/admin/index.lua | 199 | ||||
-rw-r--r-- | modules/luci-base/luasrc/controller/admin/uci.lua | 70 | ||||
-rw-r--r-- | modules/luci-base/luasrc/dispatcher.lua | 1564 | ||||
-rw-r--r-- | modules/luci-base/luasrc/dispatcher.luadoc | 220 | ||||
-rw-r--r-- | modules/luci-base/luasrc/template.lua | 100 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/csrftoken.htm | 24 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/error404.htm | 12 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/error500.htm | 11 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/footer.htm | 27 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/header.htm | 38 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/sysauth.htm | 75 | ||||
-rw-r--r-- | modules/luci-base/luasrc/view/view.htm | 12 | ||||
-rwxr-xr-x | modules/luci-base/root/usr/libexec/rpcd/luci | 682 | ||||
-rw-r--r-- | modules/luci-base/root/usr/share/luci/menu.d/luci-base.json | 16 | ||||
-rw-r--r-- | modules/luci-base/root/usr/share/rpcd/ucode/luci (renamed from modules/luci-base-ucode/root/usr/share/rpcd/ucode/luci) | 0 | ||||
-rw-r--r-- | modules/luci-base/src/Makefile | 30 | ||||
-rw-r--r-- | modules/luci-base/src/lib/lmo.c (renamed from modules/luci-base-ucode/src/lib/lmo.c) | 0 | ||||
-rw-r--r-- | modules/luci-base/src/lib/lmo.h (renamed from modules/luci-base-ucode/src/lib/lmo.h) | 0 | ||||
-rw-r--r-- | modules/luci-base/src/lib/luci.c (renamed from modules/luci-base-ucode/src/lib/luci.c) | 0 | ||||
-rw-r--r-- | modules/luci-base/src/lib/plural_formula.y (renamed from modules/luci-base-ucode/src/lib/plural_formula.y) | 0 | ||||
-rw-r--r-- | modules/luci-base/src/po2lmo.c | 9 | ||||
-rw-r--r-- | modules/luci-base/ucode/controller/admin/index.uc (renamed from modules/luci-base-ucode/ucode/controller/admin/index.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/controller/admin/uci.uc (renamed from modules/luci-base-ucode/ucode/controller/admin/uci.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/dispatcher.uc (renamed from modules/luci-base-ucode/ucode/dispatcher.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/http.uc (renamed from modules/luci-base-ucode/ucode/http.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/runtime.uc (renamed from modules/luci-base-ucode/ucode/runtime.uc) | 1 | ||||
-rw-r--r-- | modules/luci-base/ucode/sys.uc (renamed from modules/luci-base-ucode/ucode/sys.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/csrftoken.ut (renamed from modules/luci-base-ucode/ucode/template/csrftoken.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/error404.ut (renamed from modules/luci-base-ucode/ucode/template/error404.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/error500.ut (renamed from modules/luci-base-ucode/ucode/template/error500.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/footer.ut (renamed from modules/luci-base-ucode/ucode/template/footer.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/header.ut (renamed from modules/luci-base-ucode/ucode/template/header.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/sysauth.ut (renamed from modules/luci-base-ucode/ucode/template/sysauth.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/template/view.ut (renamed from modules/luci-base-ucode/ucode/template/view.ut) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/uhttpd.uc (renamed from modules/luci-base-ucode/ucode/uhttpd.uc) | 0 | ||||
-rw-r--r-- | modules/luci-base/ucode/zoneinfo.uc (renamed from modules/luci-base-ucode/ucode/zoneinfo.uc) | 0 | ||||
-rw-r--r-- | modules/luci-compat/Makefile | 2 | ||||
-rw-r--r-- | modules/luci-lua-runtime/Makefile | 27 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/cacheloader.lua (renamed from modules/luci-base/luasrc/cacheloader.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/ccache.lua (renamed from modules/luci-base/luasrc/ccache.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/config.lua (renamed from modules/luci-base/luasrc/config.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/dispatcher.lua (renamed from modules/luci-base-ucode/luasrc/ucodebridge/luci/dispatcher.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/i18n.lua (renamed from modules/luci-base/luasrc/i18n.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/i18n.luadoc (renamed from modules/luci-base/luasrc/i18n.luadoc) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/model/uci.lua (renamed from modules/luci-base/luasrc/model/uci.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/model/uci.luadoc (renamed from modules/luci-base/luasrc/model/uci.luadoc) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sgi/cgi.lua (renamed from modules/luci-base/luasrc/sgi/cgi.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sgi/uhttpd.lua (renamed from modules/luci-base/luasrc/sgi/uhttpd.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/store.lua (renamed from modules/luci-base/luasrc/store.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sys.lua (renamed from modules/luci-base/luasrc/sys.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sys.luadoc (renamed from modules/luci-base/luasrc/sys.luadoc) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sys/zoneinfo.lua (renamed from modules/luci-base/luasrc/sys/zoneinfo.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzdata.lua (renamed from modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzoffset.lua (renamed from modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/template.lua (renamed from modules/luci-base-ucode/luasrc/ucodebridge/luci/template.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/ucodebridge.lua (renamed from modules/luci-base-ucode/luasrc/ucodebridge/luci/ucodebridge.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/version.lua (renamed from modules/luci-base/luasrc/version.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/view/empty_node_placeholder.htm (renamed from modules/luci-base/luasrc/view/empty_node_placeholder.htm) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/view/indexer.htm (renamed from modules/luci-base/luasrc/view/indexer.htm) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/xml.lua (renamed from modules/luci-base/luasrc/xml.lua) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/luasrc/xml.luadoc (renamed from modules/luci-base/luasrc/xml.luadoc) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/Makefile | 26 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/contrib/lemon.c (renamed from modules/luci-base-ucode/src/contrib/lemon.c) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/contrib/lempar.c (renamed from modules/luci-base-ucode/src/contrib/lempar.c) | 0 | ||||
-rwxr-xr-x | modules/luci-lua-runtime/src/mkversion.sh (renamed from modules/luci-base/src/mkversion.sh) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/plural_formula.y (renamed from modules/luci-base/src/plural_formula.y) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_lmo.c (renamed from modules/luci-base/src/template_lmo.c) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_lmo.h (renamed from modules/luci-base/src/template_lmo.h) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_lualib.c (renamed from modules/luci-base/src/template_lualib.c) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_lualib.h (renamed from modules/luci-base/src/template_lualib.h) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_parser.c (renamed from modules/luci-base/src/template_parser.c) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_parser.h (renamed from modules/luci-base/src/template_parser.h) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_utils.c (renamed from modules/luci-base/src/template_utils.c) | 0 | ||||
-rw-r--r-- | modules/luci-lua-runtime/src/template_utils.h (renamed from modules/luci-base/src/template_utils.h) | 0 |
86 files changed, 189 insertions, 4580 deletions
diff --git a/.gitignore b/.gitignore index 60dd7e18d6..7834b9bce4 100644 --- a/.gitignore +++ b/.gitignore @@ -10,7 +10,10 @@ package-lock.json modules/luci-base/src/po2lmo modules/luci-base/src/jsmin modules/luci-base/src/contrib/lemon -modules/luci-base/src/plural_formula.c -modules/luci-base/src/plural_formula.h +modules/luci-base/src/ucode/plural_formula.c +modules/luci-base/src/ucode/plural_formula.h +modules/luci-compat/src/contrib/lemon +modules/luci-compat/src/plural_formula.c +modules/luci-compat/src/plural_formula.h docs/jsapi/* !docs/jsapi/README.md diff --git a/build/mkbasepot.sh b/build/mkbasepot.sh index 0f9247536b..d59a151d6a 100755 --- a/build/mkbasepot.sh +++ b/build/mkbasepot.sh @@ -8,7 +8,7 @@ echo -n "Updating modules/luci-base/po/templates/base.pot ... " ./build/i18n-scan.pl \ - modules/luci-base/ modules/luci-compat/ modules/luci-mod-admin-full/ \ + modules/luci-base/ modules/luci-compat/ modules/luci-lua-runtime/ \ modules/luci-mod-network modules/luci-mod-status modules/luci-mod-system/ \ protocols/ themes/ \ > modules/luci-base/po/templates/base.pot diff --git a/build/zoneinfo2ucode.pl b/build/zoneinfo2ucode.pl index 35dfac3797..941255f2f4 100755 --- a/build/zoneinfo2ucode.pl +++ b/build/zoneinfo2ucode.pl @@ -7,7 +7,7 @@ use strict; my %TZ; my $tzdin = $ARGV[0] || "/usr/share/zoneinfo"; -my $tzdout = $ARGV[1] || "./modules/luci-base-ucode/ucode/zoneinfo.uc"; +my $tzdout = $ARGV[1] || "./modules/luci-base/ucode/zoneinfo.uc"; local $/ = "\012"; open( ZTAB, "< $tzdin/zone.tab" ) || die "open($tzdin/zone.tab): $!"; diff --git a/libs/luci-lib-base/luasrc/http.lua b/libs/luci-lib-base/luasrc/http.lua index 20b55f2854..06547ae2ce 100644 --- a/libs/luci-lib-base/luasrc/http.lua +++ b/libs/luci-lib-base/luasrc/http.lua @@ -6,234 +6,66 @@ local util = require "luci.util" local coroutine = require "coroutine" local table = require "table" local lhttp = require "lucihttp" -local nixio = require "nixio" -local ltn12 = require "luci.ltn12" -local table, ipairs, pairs, type, tostring, tonumber, error = - table, ipairs, pairs, type, tostring, tonumber, error +local L, table, ipairs, pairs, type, error = _G.L, table, ipairs, pairs, type, error module "luci.http" HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size -context = util.threadlocal() - -Request = util.class() -function Request.__init__(self, env, sourcein, sinkerr) - self.input = sourcein - self.error = sinkerr - - - -- File handler nil by default to let .content() work - self.filehandler = nil - - -- HTTP-Message table - self.message = { - env = env, - headers = {}, - params = urldecode_params(env.QUERY_STRING or ""), - } - - self.parsed_input = false -end - -function Request.formvalue(self, name, noparse) - if not noparse and not self.parsed_input then - self:_parse_input() - end - - if name then - return self.message.params[name] - else - return self.message.params - end -end - -function Request.formvaluetable(self, prefix) - local vals = {} - prefix = prefix and prefix .. "." or "." - - if not self.parsed_input then - self:_parse_input() - end - - local void = self.message.params[nil] - for k, v in pairs(self.message.params) do - if k:find(prefix, 1, true) == 1 then - vals[k:sub(#prefix + 1)] = tostring(v) - end - end - - return vals -end - -function Request.content(self) - if not self.parsed_input then - self:_parse_input() - end - - return self.message.content, self.message.content_length -end - -function Request.getcookie(self, name) - return lhttp.header_attribute("cookie; " .. (self:getenv("HTTP_COOKIE") or ""), name) -end - -function Request.getenv(self, name) - if name then - return self.message.env[name] - else - return self.message.env - end -end - -function Request.setfilehandler(self, callback) - self.filehandler = callback - - if not self.parsed_input then - return - end - - -- If input has already been parsed then uploads are stored as unlinked - -- temporary files pointed to by open file handles in the parameter - -- value table. Loop all params, and invoke the file callback for any - -- param with an open file handle. - local name, value - for name, value in pairs(self.message.params) do - if type(value) == "table" then - while value.fd do - local data = value.fd:read(1024) - local eof = (not data or data == "") - - callback(value, data, eof) - - if eof then - value.fd:close() - value.fd = nil - end - end - end - end -end - -function Request._parse_input(self) - parse_message_body( - self.input, - self.message, - self.filehandler - ) - self.parsed_input = true -end - function close() - if not context.eoh then - context.eoh = true - coroutine.yield(3) - end - - if not context.closed then - context.closed = true - coroutine.yield(5) - end + L.http:close() end function content() - return context.request:content() + return L.http:content() end function formvalue(name, noparse) - return context.request:formvalue(name, noparse) + return L.http:formvalue(name, noparse) end function formvaluetable(prefix) - return context.request:formvaluetable(prefix) + return L.http:formvaluetable(prefix) end function getcookie(name) - return context.request:getcookie(name) + return L.http:getcookie(name) end -- or the environment table itself. function getenv(name) - return context.request:getenv(name) + return L.http:getenv(name) end function setfilehandler(callback) - return context.request:setfilehandler(callback) + return L.http:setfilehandler(callback) end function header(key, value) - if not context.headers then - context.headers = {} - end - context.headers[key:lower()] = value - coroutine.yield(2, key, value) + L.http:header(key, value) end function prepare_content(mime) - if not context.headers or not context.headers["content-type"] then - if mime == "application/xhtml+xml" then - if not getenv("HTTP_ACCEPT") or - not getenv("HTTP_ACCEPT"):find("application/xhtml+xml", nil, true) then - mime = "text/html; charset=UTF-8" - end - header("Vary", "Accept") - end - header("Content-Type", mime) - end + L.http:prepare_content(mime) end function source() - return context.request.input + return L.http.input end function status(code, message) - code = code or 200 - message = message or "OK" - context.status = code - coroutine.yield(1, code, message) + L.http:status(code, message) end -- This function is as a valid LTN12 sink. -- If the content chunk is nil this function will automatically invoke close. function write(content, src_err) - if not content then - if src_err then - error(src_err) - else - close() - end - return true - elseif #content == 0 then - return true - else - if not context.eoh then - if not context.status then - status() - end - if not context.headers or not context.headers["content-type"] then - header("Content-Type", "text/html; charset=utf-8") - end - if not context.headers["cache-control"] then - header("Cache-Control", "no-cache") - header("Expires", "0") - end - if not context.headers["x-frame-options"] then - header("X-Frame-Options", "SAMEORIGIN") - end - if not context.headers["x-xss-protection"] then - header("X-XSS-Protection", "1; mode=block") - end - if not context.headers["x-content-type-options"] then - header("X-Content-Type-Options", "nosniff") - end - - context.eoh = true - coroutine.yield(3) - end - coroutine.yield(4, content) - return true + if src_err then + error(src_err) end + + return L.print(content) end function splice(fd, size) @@ -241,10 +73,7 @@ function splice(fd, size) end function redirect(url) - if url == "" then url = "/" end - status(302, "Found") - header("Location", url) - close() + L.http:redirect(url) end function build_querystring(q) @@ -266,35 +95,7 @@ urldecode = util.urldecode urlencode = util.urlencode function write_json(x) - util.serialize_json(x, write) -end - --- from given url or string. Returns a table with urldecoded values. --- Simple parameters are stored as string values associated with the parameter --- name within the table. Parameters with multiple values are stored as array --- containing the corresponding values. -function urldecode_params(url, tbl) - local parser, name - local params = tbl or { } - - parser = lhttp.urlencoded_parser(function (what, buffer, length) - if what == parser.TUPLE then - name, value = nil, nil - elseif what == parser.NAME then - name = lhttp.urldecode(buffer) - elseif what == parser.VALUE and name then - params[name] = lhttp.urldecode(buffer) or "" - end - - return true - end) - - if parser then - parser:parse((url or ""):match("[^?]*$")) - parser:parse(nil) - end - - return params + L.printf('%J', x) end -- separated by "&". Tables are encoded as parameters with multiple values by @@ -332,223 +133,12 @@ function urlencode_params(tbl) return table.concat(enc, "") end --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table within the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. --- If an optional file callback function is given then it is fed with the --- file contents chunk by chunk and only the extracted file name is stored --- within the params table. The callback function will be called subsequently --- with three arguments: --- o Table containing decoded (name, file) and raw (headers) mime header data --- o String value containing a chunk of the file data --- o Boolean which indicates whether the current chunk is the last one (eof) -function mimedecode_message_body(src, msg, file_cb) - local parser, header, field - local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) - - parser, err = lhttp.multipart_parser(msg.env.CONTENT_TYPE, function (what, buffer, length) - if what == parser.PART_INIT then - field = { } - - elseif what == parser.HEADER_NAME then - header = buffer:lower() - - elseif what == parser.HEADER_VALUE and header then - if header:lower() == "content-disposition" and - lhttp.header_attribute(buffer, nil) == "form-data" - then - field.name = lhttp.header_attribute(buffer, "name") - field.file = lhttp.header_attribute(buffer, "filename") - field[1] = field.file - end - - if field.headers then - field.headers[header] = buffer - else - field.headers = { [header] = buffer } - end - - elseif what == parser.PART_BEGIN then - return not field.file - - elseif what == parser.PART_DATA and field.name and length > 0 then - if field.file then - if file_cb then - file_cb(field, buffer, false) - msg.params[field.name] = msg.params[field.name] or field - else - if not field.fd then - field.fd = nixio.mkstemp(field.name) - end - - if field.fd then - field.fd:write(buffer) - msg.params[field.name] = msg.params[field.name] or field - end - end - else - field.value = buffer - end - - elseif what == parser.PART_END and field.name then - if field.file and msg.params[field.name] then - if file_cb then - file_cb(field, "", true) - elseif field.fd then - field.fd:seek(0, "set") - end - else - local val = msg.params[field.name] - - if type(val) == "table" then - val[#val+1] = field.value or "" - elseif val ~= nil then - msg.params[field.name] = { val, field.value or "" } - else - msg.params[field.name] = field.value or "" - end - end - - field = nil - - elseif what == parser.ERROR then - err = buffer - end - - return true - end, HTTP_MAX_CONTENT) - - return ltn12.pump.all(src, function (chunk) - len = len + (chunk and #chunk or 0) - - if maxlen and len > maxlen + 2 then - return nil, "Message body size exceeds Content-Length" - end - - if not parser or not parser:parse(chunk) then - return nil, err - end - - return true - end) -end - --- Content-Type. Stores all extracted data associated with its parameter name --- in the params table within the given message object. Multiple parameter --- values are stored as tables, ordinary ones as strings. -function urldecode_message_body(src, msg) - local err, name, value, parser - local len, maxlen = 0, tonumber(msg.env.CONTENT_LENGTH or nil) - - parser = lhttp.urlencoded_parser(function (what, buffer, length) - if what == parser.TUPLE then - name, value = nil, nil - elseif what == parser.NAME then - name = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) - elseif what == parser.VALUE and name then - local val = msg.params[name] - - if type(val) == "table" then - val[#val+1] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" - elseif val ~= nil then - msg.params[name] = { val, lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" } - else - msg.params[name] = lhttp.urldecode(buffer, lhttp.DECODE_PLUS) or "" - end - elseif what == parser.ERROR then - err = buffer - end - - return true - end, HTTP_MAX_CONTENT) - - return ltn12.pump.all(src, function (chunk) - len = len + (chunk and #chunk or 0) - - if maxlen and len > maxlen + 2 then - return nil, "Message body size exceeds Content-Length" - elseif len > HTTP_MAX_CONTENT then - return nil, "Message body size exceeds maximum allowed length" - end - - if not parser or not parser:parse(chunk) then - return nil, err - end - - return true - end) -end - --- This function will examine the Content-Type within the given message object --- to select the appropriate content decoder. --- Currently the application/x-www-urlencoded and application/form-data --- mime types are supported. If the encountered content encoding can't be --- handled then the whole message body will be stored unaltered as "content" --- property within the given message object. -function parse_message_body(src, msg, filecb) - if msg.env.CONTENT_LENGTH or msg.env.REQUEST_METHOD == "POST" then - local ctype = lhttp.header_attribute(msg.env.CONTENT_TYPE, nil) - - -- Is it multipart/mime ? - if ctype == "multipart/form-data" then - return mimedecode_message_body(src, msg, filecb) - - -- Is it application/x-www-form-urlencoded ? - elseif ctype == "application/x-www-form-urlencoded" then - return urldecode_message_body(src, msg) - - end - - -- Unhandled encoding - -- If a file callback is given then feed it chunk by chunk, else - -- store whole buffer in message.content - local sink - - -- If we have a file callback then feed it - if type(filecb) == "function" then - local meta = { - name = "raw", - encoding = msg.env.CONTENT_TYPE - } - sink = function( chunk ) - if chunk then - return filecb(meta, chunk, false) - else - return filecb(meta, nil, true) - end - end - -- ... else append to .content - else - msg.content = "" - msg.content_length = 0 - - sink = function( chunk ) - if chunk then - if ( msg.content_length + #chunk ) <= HTTP_MAX_CONTENT then - msg.content = msg.content .. chunk - msg.content_length = msg.content_length + #chunk - return true - else - return nil, "POST data exceeds maximum allowed length" - end - end - return true - end - end - - -- Pump data... - while true do - local ok, err = ltn12.pump.step( src, sink ) - - if not ok and err then - return nil, err - elseif not ok then -- eof - return true - end - end - - return true - end - - return false -end +context = { + request = { + formvalue = function(self, ...) return formvalue(...) end; + formvaluetable = function(self, ...) return formvaluetable(...) end; + content = function(self, ...) return content(...) end; + getcookie = function(self, ...) return getcookie(...) end; + setfilehandler = function(self, ...) return setfilehandler(...) end; + } +} diff --git a/libs/luci-lib-base/luasrc/util.lua b/libs/luci-lib-base/luasrc/util.lua index 89757917ff..80013179aa 100644 --- a/libs/luci-lib-base/luasrc/util.lua +++ b/libs/luci-lib-base/luasrc/util.lua @@ -100,32 +100,8 @@ end -- Scope manipulation routines -- -coxpt = setmetatable({}, { __mode = "kv" }) - -local tl_meta = { - __mode = "k", - - __index = function(self, key) - local t = rawget(self, coxpt[coroutine.running()] - or coroutine.running() or 0) - return t and t[key] - end, - - __newindex = function(self, key, value) - local c = coxpt[coroutine.running()] or coroutine.running() or 0 - local r = rawget(self, c) - if not r then - rawset(self, c, { [key] = value }) - else - r[key] = value - end - end -} - --- the current active coroutine. A thread local store is private a table object --- whose values can't be accessed from outside of the running coroutine. function threadlocal(tbl) - return setmetatable(tbl or {}, tl_meta) + return tbl or {} end @@ -772,7 +748,6 @@ function coxpcall(f, err, ...) co = coroutine.create(newf) end coromap[co] = current - coxpt[co] = coxpt[current] or current or 0 return performResume(err, co, ...) end end diff --git a/modules/luci-base-ucode/Makefile b/modules/luci-base-ucode/Makefile deleted file mode 100644 index 2d5eb84d94..0000000000 --- a/modules/luci-base-ucode/Makefile +++ /dev/null @@ -1,45 +0,0 @@ -# -# Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io> -# -# This is free software, licensed under the Apache License, Version 2.0 . -# - -include $(TOPDIR)/rules.mk - -PKG_NAME:=luci-base-ucode - -LUCI_TYPE:=mod -LUCI_BASENAME:=base-ucode - -LUCI_TITLE:=LuCI core ucode runtime -LUCI_DEPENDS:=\ - +luci-base \ - +ucode \ - +ucode-mod-fs \ - +ucode-mod-uci \ - +ucode-mod-ubus \ - +ucode-mod-math \ - +ucode-mod-lua \ - +ucode-mod-html \ - +rpcd-mod-ucode \ - +liblucihttp-ucode - -PKG_LICENSE:=MIT - -define Package/luci-base-ucode/postinst -#!/bin/sh - -if [ -z "$${PKG_INSTROOT}" ] && [ -f /etc/config/uhttpd ]; then - if ! uci -q get uhttpd.main.ucode_prefix | grep -sq /cgi-bin/luci-ucode; then - uci add_list uhttpd.main.ucode_prefix='/cgi-bin/luci-ucode=/usr/share/ucode/luci/uhttpd.uc' - uci commit uhttpd - service uhttpd reload - fi -fi - -exit 0 -endef - -include ../../luci.mk - -# call BuildPackage - OpenWrt buildroot signature diff --git a/modules/luci-base-ucode/htdocs/cgi-bin/luci-ucode b/modules/luci-base-ucode/htdocs/cgi-bin/luci-ucode deleted file mode 100755 index 442e427d41..0000000000 --- a/modules/luci-base-ucode/htdocs/cgi-bin/luci-ucode +++ /dev/null @@ -1,41 +0,0 @@ -#!/usr/bin/env ucode - -'use strict'; - -import { stdin, stdout } from 'fs'; - -import dispatch from 'luci.dispatcher'; -import request from 'luci.http'; - -const input_bufsize = 4096; -let input_available = +getenv('CONTENT_LENGTH') || 0; - -function read(len) { - if (input_available == 0) { - stdin.close(); - - return null; - } - - let chunk = stdin.read(min(input_available, len ?? input_bufsize, input_bufsize)); - - if (chunk == null) { - input_available = 0; - stdin.close(); - } - else { - input_available -= length(chunk); - } - - return chunk; -} - -function write(data) { - return stdout.write(data); -} - -let req = request(getenv(), read, write); - -dispatch(req); - -req.close(); diff --git a/modules/luci-base-ucode/luasrc/ucodebridge/luci/http.lua b/modules/luci-base-ucode/luasrc/ucodebridge/luci/http.lua deleted file mode 100644 index 06547ae2ce..0000000000 --- a/modules/luci-base-ucode/luasrc/ucodebridge/luci/http.lua +++ /dev/null @@ -1,144 +0,0 @@ --- Copyright 2008 Steven Barth <steven@midlink.org> --- Copyright 2010-2018 Jo-Philipp Wich <jo@mein.io> --- Licensed to the public under the Apache License 2.0. - -local util = require "luci.util" -local coroutine = require "coroutine" -local table = require "table" -local lhttp = require "lucihttp" - -local L, table, ipairs, pairs, type, error = _G.L, table, ipairs, pairs, type, error - -module "luci.http" - -HTTP_MAX_CONTENT = 1024*100 -- 100 kB maximum content size - -function close() - L.http:close() -end - -function content() - return L.http:content() -end - -function formvalue(name, noparse) - return L.http:formvalue(name, noparse) -end - -function formvaluetable(prefix) - return L.http:formvaluetable(prefix) -end - -function getcookie(name) - return L.http:getcookie(name) -end - --- or the environment table itself. -function getenv(name) - return L.http:getenv(name) -end - -function setfilehandler(callback) - return L.http:setfilehandler(callback) -end - -function header(key, value) - L.http:header(key, value) -end - -function prepare_content(mime) - L.http:prepare_content(mime) -end - -function source() - return L.http.input -end - -function status(code, message) - L.http:status(code, message) -end - --- This function is as a valid LTN12 sink. --- If the content chunk is nil this function will automatically invoke close. -function write(content, src_err) - if src_err then - error(src_err) - end - - return L.print(content) -end - -function splice(fd, size) - coroutine.yield(6, fd, size) -end - -function redirect(url) - L.http:redirect(url) -end - -function build_querystring(q) - local s, n, k, v = {}, 1, nil, nil - - for k, v in pairs(q) do - s[n+0] = (n == 1) and "?" or "&" - s[n+1] = util.urlencode(k) - s[n+2] = "=" - s[n+3] = util.urlencode(v) - n = n + 4 - end - - return table.concat(s, "") -end - -urldecode = util.urldecode - -urlencode = util.urlencode - -function write_json(x) - L.printf('%J', x) -end - --- separated by "&". Tables are encoded as parameters with multiple values by --- repeating the parameter name with each value. -function urlencode_params(tbl) - local k, v - local n, enc = 1, {} - for k, v in pairs(tbl) do - if type(v) == "table" then - local i, v2 - for i, v2 in ipairs(v) do - if enc[1] then - enc[n] = "&" - n = n + 1 - end - - enc[n+0] = lhttp.urlencode(k) - enc[n+1] = "=" - enc[n+2] = lhttp.urlencode(v2) - n = n + 3 - end - else - if enc[1] then - enc[n] = "&" - n = n + 1 - end - - enc[n+0] = lhttp.urlencode(k) - enc[n+1] = "=" - enc[n+2] = lhttp.urlencode(v) - n = n + 3 - end - end - - return table.concat(enc, "") -end - -context = { - request = { - formvalue = function(self, ...) return formvalue(...) end; - formvaluetable = function(self, ...) return formvaluetable(...) end; - content = function(self, ...) return content(...) end; - getcookie = function(self, ...) return getcookie(...) end; - setfilehandler = function(self, ...) return setfilehandler(...) end; - } -} diff --git a/modules/luci-base-ucode/luasrc/ucodebridge/luci/util.lua b/modules/luci-base-ucode/luasrc/ucodebridge/luci/util.lua deleted file mode 100644 index d50eb1dd9c..0000000000 --- a/modules/luci-base-ucode/luasrc/ucodebridge/luci/util.lua +++ /dev/null @@ -1,786 +0,0 @@ --- Copyright 2008 Steven Barth <steven@midlink.org> --- Licensed to the public under the Apache License 2.0. - -local io = require "io" -local math = require "math" -local table = require "table" -local debug = require "debug" -local ldebug = require "luci.debug" -local string = require "string" -local coroutine = require "coroutine" -local tparser = require "luci.template.parser" -local json = require "luci.jsonc" -local lhttp = require "lucihttp" - -local _ubus = require "ubus" -local _ubus_connection = nil - -local getmetatable, setmetatable = getmetatable, setmetatable -local rawget, rawset, unpack, select = rawget, rawset, unpack, select -local tostring, type, assert, error = tostring, type, assert, error -local ipairs, pairs, next, loadstring = ipairs, pairs, next, loadstring -local require, pcall, xpcall = require, pcall, xpcall -local collectgarbage, get_memory_limit = collectgarbage, get_memory_limit - -local L = _G.L - -module "luci.util" - --- --- Pythonic string formatting extension --- -getmetatable("").__mod = function(a, b) - local ok, res - - if not b then - return a - elseif type(b) == "table" then - local k, _ - for k, _ in pairs(b) do if type(b[k]) == "userdata" then b[k] = tostring(b[k]) end end - - ok, res = pcall(a.format, a, unpack(b)) - if not ok then - error(res, 2) - end - return res - else - if type(b) == "userdata" then b = tostring(b) end - - ok, res = pcall(a.format, a, b) - if not ok then - error(res, 2) - end - return res - end -end - - --- --- Class helper routines --- - --- Instantiates a class -local function _instantiate(class, ...) - local inst = setmetatable({}, {__index = class}) - - if inst.__init__ then - inst:__init__(...) - end - - return inst -end - --- The class object can be instantiated by calling itself. --- Any class functions or shared parameters can be attached to this object. --- Attaching a table to the class object makes this table shared between --- all instances of this class. For object parameters use the __init__ function. --- Classes can inherit member functions and values from a base class. --- Class can be instantiated by calling them. All parameters will be passed --- to the __init__ function of this class - if such a function exists. --- The __init__ function must be used to set any object parameters that are not shared --- with other objects of this class. Any return values will be ignored. -function class(base) - return setmetatable({}, { - __call = _instantiate, - __index = base - }) -end - -function instanceof(object, class) - local meta = getmetatable(object) - while meta and meta.__index do - if meta.__index == class then - return true - end - meta = getmetatable(meta.__index) - end - return false -end - - --- --- Scope manipulation routines --- - -coxpt = setmetatable({}, { __mode = "kv" }) - -local tl_meta = { - __mode = "k", - - __index = function(self, key) - local t = rawget(self, coxpt[coroutine.running()] - or coroutine.running() or 0) - L.http:write("<!-- __index(%s/%s, %s): %s -->\n" %{ tostring(self), tostring(coxpt[coroutine.running()] or coroutine.running() or 0), key, tostring(t and t[key]) }) - return t and t[key] - end, - - __newindex = function(self, key, value) - L.http:write("<!-- __newindex(%s/%s, %s, %s) -->\n" %{ tostring(self), tostring(coxpt[coroutine.running()] or coroutine.running() or 0), key, tostring(value) }) - local c = coxpt[coroutine.running()] or coroutine.running() or 0 - local r = rawget(self, c) - if not r then - rawset(self, c, { [key] = value }) - else - r[key] = value - end - end -} - --- the current active coroutine. A thread local store is private a table object --- whose values can't be accessed from outside of the running coroutine. -function threadlocal(tbl) - return tbl or {} --setmetatable(tbl or {}, tl_meta) -end - - --- --- Debugging routines --- - -function perror(obj) - return io.stderr:write(tostring(obj) .. "\n") -end - -function dumptable(t, maxdepth, i, seen) - i = i or 0 - seen = seen or setmetatable({}, {__mode="k"}) - - for k,v in pairs(t) do - perror(string.rep("\t", i) .. tostring(k) .. "\t" .. tostring(v)) - if type(v) == "table" and (not maxdepth or i < maxdepth) then - if not seen[v] then - seen[v] = true - dumptable(v, maxdepth, i+1, seen) - else - perror(string.rep("\t", i) .. "*** RECURSION ***") - end - end - end -end - - --- --- String and data manipulation routines --- - --- compatibility wrapper for xml.pcdata -function pcdata(value) - local xml = require "luci.xml" - - perror("luci.util.pcdata() has been replaced by luci.xml.pcdata() - Please update your code.") - return xml.pcdata(value) -end - -function urlencode(value) - if value ~= nil then - local str = tostring(value) - return lhttp.urlencode(str, lhttp.ENCODE_IF_NEEDED + lhttp.ENCODE_FULL) - or str - end - return nil -end - -function urldecode(value, decode_plus) - if value ~= nil then - local flag = decode_plus and lhttp.DECODE_PLUS or 0 - local str = tostring(value) - return lhttp.urldecode(str, lhttp.DECODE_IF_NEEDED + flag) - or str - end - return nil -end - --- compatibility wrapper for xml.striptags -function striptags(value) - local xml = require "luci.xml" - - perror("luci.util.striptags() has been replaced by luci.xml.striptags() - Please update your code.") - return xml.striptags(value) -end - -function shellquote(value) - return string.format("'%s'", string.gsub(value or "", "'", "'\\''")) -end - --- for bash, ash and similar shells single-quoted strings are taken --- literally except for single quotes (which terminate the string) --- (and the exception noted below for dash (-) at the start of a --- command line parameter). -function shellsqescape(value) - local res - res, _ = string.gsub(value, "'", "'\\''") - return res -end - --- bash, ash and other similar shells interpret a dash (-) at the start --- of a command-line parameters as an option indicator regardless of --- whether it is inside a single-quoted string. It must be backlash --- escaped to resolve this. This requires in some funky special-case --- handling. It may actually be a property of the getopt function --- rather than the shell proper. -function shellstartsqescape(value) - res, _ = string.gsub(value, "^%-", "\\-") - return shellsqescape(res) -end - --- containing the resulting substrings. The optional max parameter specifies --- the number of bytes to process, regardless of the actual length of the given --- string. The optional last parameter, regex, specifies whether the separator --- sequence is interpreted as regular expression. --- pattern as regular expression (optional, default is false) -function split(str, pat, max, regex) - pat = pat or "\n" - max = max or #str - - local t = {} - local c = 1 - - if #str == 0 then - return {""} - end - - if #pat == 0 then - return nil - end - - if max == 0 then - return str - end - - repeat - local s, e = str:find(pat, c, not regex) - max = max - 1 - if s and max < 0 then - t[#t+1] = str:sub(c) - else - t[#t+1] = str:sub(c, s and s - 1) - end - c = e and e + 1 or #str + 1 - until not s or max < 0 - - return t -end - -function trim(str) - return (str:gsub("^%s*(.-)%s*$", "%1")) -end - -function cmatch(str, pat) - local count = 0 - for _ in str:gmatch(pat) do count = count + 1 end - return count -end - --- one token per invocation, the tokens are separated by whitespace. If the --- input value is a table, it is transformed into a string first. A nil value --- will result in a valid iterator which aborts with the first invocation. -function imatch(v) - if type(v) == "table" then - local k = nil - return function() - k = next(v, k) - return v[k] - end - - elseif type(v) == "number" or type(v) == "boolean" then - local x = true - return function() - if x then - x = false - return tostring(v) - end - end - - elseif type(v) == "userdata" or type(v) == "string" then - return tostring(v):gmatch("%S+") - end - - return function() end -end - --- value or 0 if the unit is unknown. Upper- or lower case is irrelevant. --- Recognized units are: --- o "y" - one year (60*60*24*366) --- o "m" - one month (60*60*24*31) --- o "w" - one week (60*60*24*7) --- o "d" - one day (60*60*24) --- o "h" - one hour (60*60) --- o "min" - one minute (60) --- o "kb" - one kilobyte (1024) --- o "mb" - one megabyte (1024*1024) --- o "gb" - one gigabyte (1024*1024*1024) --- o "kib" - one si kilobyte (1000) --- o "mib" - one si megabyte (1000*1000) --- o "gib" - one si gigabyte (1000*1000*1000) -function parse_units(ustr) - - local val = 0 - - -- unit map - local map = { - -- date stuff - y = 60 * 60 * 24 * 366, - m = 60 * 60 * 24 * 31, - w = 60 * 60 * 24 * 7, - d = 60 * 60 * 24, - h = 60 * 60, - min = 60, - - -- storage sizes - kb = 1024, - mb = 1024 * 1024, - gb = 1024 * 1024 * 1024, - - -- storage sizes (si) - kib = 1000, - mib = 1000 * 1000, - gib = 1000 * 1000 * 1000 - } - - -- parse input string - for spec in ustr:lower():gmatch("[0-9%.]+[a-zA-Z]*") do - - local num = spec:gsub("[^0-9%.]+$","") - local spn = spec:gsub("^[0-9%.]+", "") - - if map[spn] or map[spn:sub(1,1)] then - val = val + num * ( map[spn] or map[spn:sub(1,1)] ) - else - val = val + num - end - end - - - return val -end - --- also register functions above in the central string class for convenience -string.split = split -string.trim = trim -string.cmatch = cmatch -string.parse_units = parse_units - - -function append(src, ...) - for i, a in ipairs({...}) do - if type(a) == "table" then - for j, v in ipairs(a) do - src[#src+1] = v - end - else - src[#src+1] = a - end - end - return src -end - -function combine(...) - return append({}, ...) -end - -function contains(table, value) - for k, v in pairs(table) do - if value == v then - return k - end - end - return false -end - --- Both table are - in fact - merged together. -function update(t, updates) - for k, v in pairs(updates) do - t[k] = v - end -end - -function keys(t) - local keys = { } - if t then - for k, _ in kspairs(t) do - keys[#keys+1] = k - end - end - return keys -end - -function clone(object, deep) - local copy = {} - - for k, v in pairs(object) do - if deep and type(v) == "table" then - v = clone(v, deep) - end - copy[k] = v - end - - return setmetatable(copy, getmetatable(object)) -end - - --- Serialize the contents of a table value. -function _serialize_table(t, seen) - assert(not seen[t], "Recursion detected.") - seen[t] = true - - local data = "" - local idata = "" - local ilen = 0 - - for k, v in pairs(t) do - if type(k) ~= "number" or k < 1 or math.floor(k) ~= k or ( k - #t ) > 3 then - k = serialize_data(k, seen) - v = serialize_data(v, seen) - data = data .. ( #data > 0 and ", " or "" ) .. - '[' .. k .. '] = ' .. v - elseif k > ilen then - ilen = k - end - end - - for i = 1, ilen do - local v = serialize_data(t[i], seen) - idata = idata .. ( #idata > 0 and ", " or "" ) .. v - end - - return idata .. ( #data > 0 and #idata > 0 and ", " or "" ) .. data -end - --- with loadstring(). -function serialize_data(val, seen) - seen = seen or setmetatable({}, {__mode="k"}) - - if val == nil then - return "nil" - elseif type(val) == "number" then - return val - elseif type(val) == "string" then - return "%q" % val - elseif type(val) == "boolean" then - return val and "true" or "false" - elseif type(val) == "function" then - return "loadstring(%q)" % get_bytecode(val) - elseif type(val) == "table" then - return "{ " .. _serialize_table(val, seen) .. " }" - else - return '"[unhandled data type:' .. type(val) .. ']"' - end -end - -function restore_data(str) - return loadstring("return " .. str)() -end - - --- --- Byte code manipulation routines --- - --- will be stripped before it is returned. -function get_bytecode(val) - local code - - if type(val) == "function" then - code = string.dump(val) - else - code = string.dump( loadstring( "return " .. serialize_data(val) ) ) - end - - return code -- and strip_bytecode(code) -end - --- numbers and debugging numbers will be discarded. Original version by --- Peter Cawley (http://lua-users.org/lists/lua-l/2008-02/msg01158.html) -function strip_bytecode(code) - local version, format, endian, int, size, ins, num, lnum = code:byte(5, 12) - local subint - if endian == 1 then - subint = function(code, i, l) - local val = 0 - for n = l, 1, -1 do - val = val * 256 + code:byte(i + n - 1) - end - return val, i + l - end - else - subint = function(code, i, l) - local val = 0 - for n = 1, l, 1 do - val = val * 256 + code:byte(i + n - 1) - end - return val, i + l - end - end - - local function strip_function(code) - local count, offset = subint(code, 1, size) - local stripped = { string.rep("\0", size) } - local dirty = offset + count - offset = offset + count + int * 2 + 4 - offset = offset + int + subint(code, offset, int) * ins - count, offset = subint(code, offset, int) - for n = 1, count do - local t - t, offset = subint(code, offset, 1) - if t == 1 then - offset = offset + 1 - elseif t == 4 then - offset = offset + size + subint(code, offset, size) - elseif t == 3 then - offset = offset + num - elseif t == 254 or t == 9 then - offset = offset + lnum - end - end - count, offset = subint(code, offset, int) - stripped[#stripped+1] = code:sub(dirty, offset - 1) - for n = 1, count do - local proto, off = strip_function(code:sub(offset, -1)) - stripped[#stripped+1] = proto - offset = offset + off - 1 - end - offset = offset + subint(code, offset, int) * int + int - count, offset = subint(code, offset, int) - for n = 1, count do - offset = offset + subint(code, offset, size) + size + int * 2 - end - count, offset = subint(code, offset, int) - for n = 1, count do - offset = offset + subint(code, offset, size) + size - end - stripped[#stripped+1] = string.rep("\0", int * 3) - return table.concat(stripped), offset - end - - return code:sub(1,12) .. strip_function(code:sub(13,-1)) -end - - --- --- Sorting iterator functions --- - -function _sortiter( t, f ) - local keys = { } - - local k, v - for k, v in pairs(t) do - keys[#keys+1] = k - end - - local _pos = 0 - - table.sort( keys, f ) - - return function() - _pos = _pos + 1 - if _pos <= #keys then - return keys[_pos], t[keys[_pos]], _pos - end - end -end - --- the provided callback function. -function spairs(t,f) - return _sortiter( t, f ) -end - --- The table pairs are sorted by key. -function kspairs(t) - return _sortiter( t ) -end - --- The table pairs are sorted by value. -function vspairs(t) - return _sortiter( t, function (a,b) return t[a] < t[b] end ) -end - - --- --- System utility functions --- - -function bigendian() - return string.byte(string.dump(function() end), 7) == 0 -end - -function exec(command) - local pp = io.popen(command) - local data = pp:read("*a") - pp:close() - - return data -end - -function execi(command) - local pp = io.popen(command) - - return pp and function() - local line = pp:read() - - if not line then - pp:close() - end - - return line - end -end - --- Deprecated -function execl(command) - local pp = io.popen(command) - local line = "" - local data = {} - - while true do - line = pp:read() - if (line == nil) then break end - data[#data+1] = line - end - pp:close() - - return data -end - - -local ubus_codes = { - "INVALID_COMMAND", - "INVALID_ARGUMENT", - "METHOD_NOT_FOUND", - "NOT_FOUND", - "NO_DATA", - "PERMISSION_DENIED", - "TIMEOUT", - "NOT_SUPPORTED", - "UNKNOWN_ERROR", - "CONNECTION_FAILED" -} - -local function ubus_return(...) - if select('#', ...) == 2 then - local rv, err = select(1, ...), select(2, ...) - if rv == nil and type(err) == "number" then - return nil, err, ubus_codes[err] - end - end - - return ... -end - -function ubus(object, method, data, path, timeout) - if not _ubus_connection then - _ubus_connection = _ubus.connect(path, timeout) - assert(_ubus_connection, "Unable to establish ubus connection") - end - - if object and method then - if type(data) ~= "table" then - data = { } - end - return ubus_return(_ubus_connection:call(object, method, data)) - elseif object then - return _ubus_connection:signatures(object) - else - return _ubus_connection:objects() - end -end - -function serialize_json(x, cb) - local js = json.stringify(x) - if type(cb) == "function" then - cb(js) - else - return js - end -end - - -function libpath() - return require "nixio.fs".dirname(ldebug.__file__) -end - -function checklib(fullpathexe, wantedlib) - local fs = require "nixio.fs" - local haveldd = fs.access('/usr/bin/ldd') - local haveexe = fs.access(fullpathexe) - if not haveldd or not haveexe then - return false - end - local libs = exec(string.format("/usr/bin/ldd %s", shellquote(fullpathexe))) - if not libs then - return false - end - for k, v in ipairs(split(libs)) do - if v:find(wantedlib) then - return true - end - end - return false -end - -------------------------------------------------------------------------------- --- Coroutine safe xpcall and pcall versions --- --- Encapsulates the protected calls with a coroutine based loop, so errors can --- be dealed without the usual Lua 5.x pcall/xpcall issues with coroutines --- yielding inside the call to pcall or xpcall. --- --- Authors: Roberto Ierusalimschy and Andre Carregal --- Contributors: Thomas Harning Jr., Ignacio Burgueño, Fabio Mascarenhas --- --- Copyright 2005 - Kepler Project --- --- $Id: coxpcall.lua,v 1.13 2008/05/19 19:20:02 mascarenhas Exp $ -------------------------------------------------------------------------------- - -------------------------------------------------------------------------------- --- Implements xpcall with coroutines -------------------------------------------------------------------------------- -local coromap = setmetatable({}, { __mode = "k" }) - -local function handleReturnValue(err, co, status, ...) - if not status then - return false, err(debug.traceback(co, (...)), ...) - end - if coroutine.status(co) == 'suspended' then - return performResume(err, co, coroutine.yield(...)) - else - return true, ... - end -end - -function performResume(err, co, ...) - return handleReturnValue(err, co, coroutine.resume(co, ...)) -end - -local function id(trace, ...) - return trace -end - -function coxpcall(f, err, ...) - local current = coroutine.running() - if not current then - if err == id then - return pcall(f, ...) - else - if select("#", ...) > 0 then - local oldf, params = f, { ... } - f = function() return oldf(unpack(params)) end - end - return xpcall(f, err) - end - else - local res, co = pcall(coroutine.create, f) - if not res then - local newf = function(...) return f(...) end - co = coroutine.create(newf) - end - coromap[co] = current - coxpt[co] = coxpt[current] or current or 0 - return performResume(err, co, ...) - end -end - -function copcall(f, ...) - return coxpcall(f, id, ...) -end diff --git a/modules/luci-base-ucode/src/Makefile b/modules/luci-base-ucode/src/Makefile deleted file mode 100644 index 8aeb29aee4..0000000000 --- a/modules/luci-base-ucode/src/Makefile +++ /dev/null @@ -1,28 +0,0 @@ -%.o: %.c - $(CC) $(CPPFLAGS) $(CFLAGS) $(FPIC) -DNDEBUG -c -o $@ $< - -contrib/lemon: contrib/lemon.c contrib/lempar.c - cc -o contrib/lemon $< - -lib/plural_formula.c: lib/plural_formula.y contrib/lemon - ./contrib/lemon -q $< - -lib/lmo.c: lib/plural_formula.c - -core.so: lib/luci.o lib/lmo.o lib/plural_formula.o - $(CC) $(LDFLAGS) -shared -o $@ $^ - -version.uc: - echo "export const revision = '$(LUCI_VERSION)', branch = '$(LUCI_GITBRANCH)';" > $@ - -clean: - rm -f contrib/lemon lib/*.o lib/plural_formula.c lib/plural_formula.h core.so version.uc - -compile: core.so version.uc - -install: compile - mkdir -p $(DESTDIR)/usr/lib/ucode/luci - cp core.so $(DESTDIR)/usr/lib/ucode/luci/core.so - - mkdir -p $(DESTDIR)/usr/share/ucode/luci - cp version.uc $(DESTDIR)/usr/share/ucode/luci/version.uc diff --git a/modules/luci-base/Makefile b/modules/luci-base/Makefile index 6cb2b64092..f85f753320 100644 --- a/modules/luci-base/Makefile +++ b/modules/luci-base/Makefile @@ -1,5 +1,5 @@ # -# Copyright (C) 2008-2015 The LuCI Team <luci@lists.subsignal.org> +# Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io> # # This is free software, licensed under the Apache License, Version 2.0 . # @@ -11,8 +11,20 @@ PKG_NAME:=luci-base LUCI_TYPE:=mod LUCI_BASENAME:=base -LUCI_TITLE:=LuCI core libraries -LUCI_DEPENDS:=+lua +luci-lib-nixio +luci-lib-ip +rpcd +libubus-lua +luci-lib-jsonc +liblucihttp-lua +luci-lib-base +rpcd-mod-file +rpcd-mod-luci +cgi-io +LUCI_TITLE:=LuCI core runtime +LUCI_DEPENDS:=\ + +rpcd \ + +rpcd-mod-file \ + +rpcd-mod-luci \ + +rpcd-mod-ucode \ + +cgi-io \ + +ucode \ + +ucode-mod-fs \ + +ucode-mod-uci \ + +ucode-mod-ubus \ + +ucode-mod-math \ + +ucode-mod-html \ + +liblucihttp-ucode PKG_LICENSE:=MIT @@ -26,6 +38,20 @@ define Package/luci-base/conffiles /etc/config/ucitrack endef +define Package/luci-base/postinst +#!/bin/sh + +if [ -z "$${PKG_INSTROOT}" ] && [ -f /etc/config/uhttpd ]; then + if ! uci -q get uhttpd.main.ucode_prefix | grep -sq /cgi-bin/luci; then + uci add_list uhttpd.main.ucode_prefix='/cgi-bin/luci=/usr/share/ucode/luci/uhttpd.uc' + uci commit uhttpd + service uhttpd reload + fi +fi + +exit 0 +endef + include ../../luci.mk define Host/Configure diff --git a/modules/luci-base/htdocs/cgi-bin/luci b/modules/luci-base/htdocs/cgi-bin/luci index c5c9847346..442e427d41 100755 --- a/modules/luci-base/htdocs/cgi-bin/luci +++ b/modules/luci-base/htdocs/cgi-bin/luci @@ -1,5 +1,41 @@ -#!/usr/bin/lua -require "luci.cacheloader" -require "luci.sgi.cgi" -luci.dispatcher.indexcache = "/tmp/luci-indexcache" -luci.sgi.cgi.run() +#!/usr/bin/env ucode + +'use strict'; + +import { stdin, stdout } from 'fs'; + +import dispatch from 'luci.dispatcher'; +import request from 'luci.http'; + +const input_bufsize = 4096; +let input_available = +getenv('CONTENT_LENGTH') || 0; + +function read(len) { + if (input_available == 0) { + stdin.close(); + + return null; + } + + let chunk = stdin.read(min(input_available, len ?? input_bufsize, input_bufsize)); + + if (chunk == null) { + input_available = 0; + stdin.close(); + } + else { + input_available -= length(chunk); + } + + return chunk; +} + +function write(data) { + return stdout.write(data); +} + +let req = request(getenv(), read, write); + +dispatch(req); + +req.close(); diff --git a/modules/luci-base/luasrc/controller/admin/index.lua b/modules/luci-base/luasrc/controller/admin/index.lua deleted file mode 100644 index 8f9b481cce..0000000000 --- a/modules/luci-base/luasrc/controller/admin/index.lua +++ /dev/null @@ -1,199 +0,0 @@ --- Copyright 2008 Steven Barth <steven@midlink.org> --- Licensed to the public under the Apache License 2.0. - -module("luci.controller.admin.index", package.seeall) - -function action_logout() - local dsp = require "luci.dispatcher" - local utl = require "luci.util" - local sid = dsp.context.authsession - - if sid then - utl.ubus("session", "destroy", { ubus_rpc_session = sid }) - - local url = dsp.build_url() - - if luci.http.getenv('HTTPS') == 'on' then - luci.http.header("Set-Cookie", "sysauth_https=; expires=Thu, 01 Jan 1970 01:00:00 GMT; path=%s" % url) - end - - luci.http.header("Set-Cookie", "sysauth_http=; expires=Thu, 01 Jan 1970 01:00:00 GMT; path=%s" % url) - end - - luci.http.redirect(dsp.build_url()) -end - -function action_translations(lang) - local i18n = require "luci.i18n" - local http = require "luci.http" - local fs = require "nixio".fs - - if lang and #lang > 0 then - lang = i18n.setlanguage(lang) - if lang then - local s = fs.stat("%s/base.%s.lmo" %{ i18n.i18ndir, lang }) - if s then - http.header("Cache-Control", "public, max-age=31536000") - http.header("ETag", "%x-%x-%x" %{ s["ino"], s["size"], s["mtime"] }) - end - end - end - - http.prepare_content("application/javascript; charset=utf-8") - http.write("window.TR=") - http.write_json(i18n.dump()) -end - -local function ubus_reply(id, data, code, errmsg) - local reply = { jsonrpc = "2.0", id = id } - if errmsg then - reply.error = { - code = code, - message = errmsg - } - elseif type(code) == "table" then - reply.result = code - else - reply.result = { code, data } - end - - return reply -end - -local ubus_types = { - nil, - "array", - "object", - "string", - nil, -- INT64 - "number", - nil, -- INT16, - "boolean", - "double" -} - -local function ubus_access(sid, obj, fun) - local res, code = luci.util.ubus("session", "access", { - ubus_rpc_session = sid, - scope = "ubus", - object = obj, - ["function"] = fun - }) - - return (type(res) == "table" and res.access == true) -end - -local function ubus_request(req) - if type(req) ~= "table" or type(req.method) ~= "string" or req.jsonrpc ~= "2.0" or req.id == nil then - return ubus_reply(nil, nil, -32600, "Invalid request") - - elseif req.method == "call" then - if type(req.params) ~= "table" or #req.params < 3 then - return ubus_reply(nil, nil, -32600, "Invalid parameters") - end - - local sid, obj, fun, arg = - req.params[1], req.params[2], req.params[3], req.params[4] or {} - if type(arg) ~= "table" or arg.ubus_rpc_session ~= nil then - return ubus_reply(req.id, nil, -32602, "Invalid parameters") - end - - if sid == "00000000000000000000000000000000" and luci.dispatcher.context.authsession then - sid = luci.dispatcher.context.authsession - end - - if not ubus_access(sid, obj, fun) then - return ubus_reply(req.id, nil, -32002, "Access denied") - end - - arg.ubus_rpc_session = sid - - local res, code = luci.util.ubus(obj, fun, arg) - return ubus_reply(req.id, res, code or 0) - - elseif req.method == "list" then - if req.params == nil or (type(req.params) == "table" and #req.params == 0) then - local objs = luci.util.ubus() - return ubus_reply(req.id, nil, objs) - - elseif type(req.params) == "table" then - local n, rv = nil, {} - for n = 1, #req.params do - if type(req.params[n]) ~= "string" then - return ubus_reply(req.id, nil, -32602, "Invalid parameters") - end - - local sig = luci.util.ubus(req.params[n]) - if sig and type(sig) == "table" then - rv[req.params[n]] = {} - - local m, p - for m, p in pairs(sig) do - if type(p) == "table" then - rv[req.params[n]][m] = {} - - local pn, pt - for pn, pt in pairs(p) do - rv[req.params[n]][m][pn] = ubus_types[pt] or "unknown" - end - end - end - end - end - return ubus_reply(req.id, nil, rv) - - else - return ubus_reply(req.id, nil, -32602, "Invalid parameters") - end - end - - return ubus_reply(req.id, nil, -32601, "Method not found") -end - -function action_ubus() - local parser = require "luci.jsonc".new() - - luci.http.context.request:setfilehandler(function(_, s) - if not s then - return nil - end - - local ok, err = parser:parse(s) - return (not err or nil) - end) - - luci.http.context.request:content() - - local json = parser:get() - if json == nil or type(json) ~= "table" then - luci.http.prepare_content("application/json") - luci.http.write_json(ubus_reply(nil, nil, -32700, "Parse error")) - return - end - - local response - if #json == 0 then - response = ubus_request(json) - else - response = {} - - local _, request - for _, request in ipairs(json) do - response[_] = ubus_request(request) - end - end - - luci.http.prepare_content("application/json") - luci.http.write_json(response) -end - -function action_menu() - local dsp = require "luci.dispatcher" - local http = require "luci.http" - - local _, _, acls = dsp.is_authenticated({ methods = { "cookie:sysauth_https", "cookie:sysauth_http" } }) - local menu = dsp.menu_json(acls or {}) or {} - - http.prepare_content("application/json") - http.write_json(menu) -end diff --git a/modules/luci-base/luasrc/controller/admin/uci.lua b/modules/luci-base/luasrc/controller/admin/uci.lua deleted file mode 100644 index 7aad10d58a..0000000000 --- a/modules/luci-base/luasrc/controller/admin/uci.lua +++ /dev/null @@ -1,70 +0,0 @@ --- Copyright 2008 Steven Barth <steven@midlink.org> --- Copyright 2010-2019 Jo-Philipp Wich <jo@mein.io> --- Licensed to the public under the Apache License 2.0. - -module("luci.controller.admin.uci", package.seeall) - -local function ubus_state_to_http(errstr) - local map = { - ["Invalid command"] = 400, - ["Invalid argument"] = 400, - ["Method not found"] = 404, - ["Entry not found"] = 404, - ["No data"] = 204, - ["Permission denied"] = 403, - ["Timeout"] = 504, - ["Not supported"] = 500, - ["Unknown error"] = 500, - ["Connection failed"] = 503 - } - - local code = map[errstr] or 200 - local msg = errstr or "OK" - - luci.http.status(code, msg) - - if code ~= 204 then - luci.http.prepare_content("text/plain") - luci.http.write(msg) - end -end - -function action_apply_rollback() - local uci = require "luci.model.uci" - local token, errstr = uci:apply(true) - if token then - luci.http.prepare_content("application/json") - luci.http.write_json({ token = token }) - else - ubus_state_to_http(errstr) - end -end - -function action_apply_unchecked() - local uci = require "luci.model.uci" - local _, errstr = uci:apply(false) - ubus_state_to_http(errstr) -end - -function action_confirm() - local uci = require "luci.model.uci" - local token = luci.http.formvalue("token") - local _, errstr = uci:confirm(token) - ubus_state_to_http(errstr) -end - -function action_revert() - local uci = require "luci.model.uci" - local changes = uci:changes() - - -- Collect files to be reverted - local _, errstr, r, tbl - for r, tbl in pairs(changes) do - _, errstr = uci:revert(r) - if errstr then - break - end - end - - ubus_state_to_http(errstr or "OK") -end diff --git a/modules/luci-base/luasrc/dispatcher.lua b/modules/luci-base/luasrc/dispatcher.lua deleted file mode 100644 index a3726fb1c1..0000000000 --- a/modules/luci-base/luasrc/dispatcher.lua +++ /dev/null @@ -1,1564 +0,0 @@ --- 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. - -local fs = require "nixio.fs" -local sys = require "luci.sys" -local util = require "luci.util" -local xml = require "luci.xml" -local http = require "luci.http" -local nixio = require "nixio", require "nixio.util" - -module("luci.dispatcher", package.seeall) -context = util.threadlocal() -uci = require "luci.model.uci" -i18n = require "luci.i18n" -_M.fs = fs - --- Index table -local index = nil - -local function check_fs_depends(spec) - local fs = require "nixio.fs" - - for path, kind in pairs(spec) do - if kind == "directory" then - local empty = true - for entry in (fs.dir(path) or function() end) do - empty = false - break - end - if empty then - return false - end - elseif kind == "executable" then - if fs.stat(path, "type") ~= "reg" or not fs.access(path, "x") then - return false - end - elseif kind == "file" then - if fs.stat(path, "type") ~= "reg" then - return false - end - elseif kind == "absent" then - if fs.stat(path, "type") then - return false - end - end - end - - return true -end - -local function check_uci_depends_options(conf, s, opts) - local uci = require "luci.model.uci" - - if type(opts) == "string" then - return (s[".type"] == opts) - elseif opts == true then - for option, value in pairs(s) do - if option:byte(1) ~= 46 then - return true - end - end - elseif type(opts) == "table" then - for option, value in pairs(opts) do - local sval = s[option] - if type(sval) == "table" then - local found = false - for _, v in ipairs(sval) do - if v == value then - found = true - break - end - end - if not found then - return false - end - elseif value == true then - if sval == nil then - return false - end - else - if sval ~= value then - return false - end - end - end - end - - return true -end - -local function check_uci_depends_section(conf, sect) - local uci = require "luci.model.uci" - - for section, options in pairs(sect) do - local stype = section:match("^@([A-Za-z0-9_%-]+)$") - if stype then - local found = false - uci:foreach(conf, stype, function(s) - if check_uci_depends_options(conf, s, options) then - found = true - return false - end - end) - if not found then - return false - end - else - local s = uci:get_all(conf, section) - if not s or not check_uci_depends_options(conf, s, options) then - return false - end - end - end - - return true -end - -local function check_uci_depends(conf) - local uci = require "luci.model.uci" - - for config, values in pairs(conf) do - if values == true then - local found = false - uci:foreach(config, nil, function(s) - found = true - return false - end) - if not found then - return false - end - elseif type(values) == "table" then - if not check_uci_depends_section(config, values) then - return false - end - end - end - - return true -end - -local function check_acl_depends(require_groups, groups) - if type(require_groups) == "table" and #require_groups > 0 then - local writable = false - - for _, group in ipairs(require_groups) do - local read = false - local write = false - if type(groups) == "table" and type(groups[group]) == "table" then - for _, perm in ipairs(groups[group]) do - if perm == "read" then - read = true - elseif perm == "write" then - write = true - end - end - end - if not read and not write then - return nil - elseif write then - writable = true - end - end - - return writable - end - - return true -end - -local function check_depends(spec) - if type(spec.depends) ~= "table" then - return true - end - - if type(spec.depends.fs) == "table" then - local satisfied = false - local alternatives = (#spec.depends.fs > 0) and spec.depends.fs or { spec.depends.fs } - for _, alternative in ipairs(alternatives) do - if check_fs_depends(alternative) then - satisfied = true - break - end - end - if not satisfied then - return false - end - end - - if type(spec.depends.uci) == "table" then - local satisfied = false - local alternatives = (#spec.depends.uci > 0) and spec.depends.uci or { spec.depends.uci } - for _, alternative in ipairs(alternatives) do - if check_uci_depends(alternative) then - satisfied = true - break - end - end - if not satisfied then - return false - end - end - - return true -end - -local function target_to_json(target, module) - local action - - if target.type == "call" then - action = { - ["type"] = "call", - ["module"] = module, - ["function"] = target.name, - ["parameters"] = target.argv - } - elseif target.type == "view" then - action = { - ["type"] = "view", - ["path"] = target.view - } - elseif target.type == "template" then - action = { - ["type"] = "template", - ["path"] = target.view - } - elseif target.type == "cbi" then - action = { - ["type"] = "cbi", - ["path"] = target.model, - ["config"] = target.config - } - elseif target.type == "form" then - action = { - ["type"] = "form", - ["path"] = target.model - } - elseif target.type == "firstchild" then - action = { - ["type"] = "firstchild" - } - elseif target.type == "firstnode" then - action = { - ["type"] = "firstchild", - ["recurse"] = true - } - elseif target.type == "arcombine" then - if type(target.targets) == "table" then - action = { - ["type"] = "arcombine", - ["targets"] = { - target_to_json(target.targets[1], module), - target_to_json(target.targets[2], module) - } - } - end - elseif target.type == "alias" then - action = { - ["type"] = "alias", - ["path"] = table.concat(target.req, "/") - } - elseif target.type == "rewrite" then - action = { - ["type"] = "rewrite", - ["path"] = table.concat(target.req, "/"), - ["remove"] = target.n - } - end - - if target.post and action then - action.post = target.post - end - - return action -end - -local function tree_to_json(node, json) - local fs = require "nixio.fs" - local util = require "luci.util" - - if type(node.nodes) == "table" then - for subname, subnode in pairs(node.nodes) do - local spec = { - title = xml.striptags(subnode.title), - order = subnode.order - } - - if subnode.leaf then - spec.wildcard = true - end - - if subnode.cors then - spec.cors = true - end - - if subnode.setuser then - spec.setuser = subnode.setuser - end - - if subnode.setgroup then - spec.setgroup = subnode.setgroup - end - - if type(subnode.target) == "table" then - spec.action = target_to_json(subnode.target, subnode.module) - end - - if type(subnode.file_depends) == "table" then - for _, v in ipairs(subnode.file_depends) do - spec.depends = spec.depends or {} - spec.depends.fs = spec.depends.fs or {} - - local ft = fs.stat(v, "type") - if ft == "dir" then - spec.depends.fs[v] = "directory" - elseif v:match("/s?bin/") then - spec.depends.fs[v] = "executable" - else - spec.depends.fs[v] = "file" - end - end - end - - if type(subnode.uci_depends) == "table" then - for k, v in pairs(subnode.uci_depends) do - spec.depends = spec.depends or {} - spec.depends.uci = spec.depends.uci or {} - spec.depends.uci[k] = v - end - end - - if type(subnode.acl_depends) == "table" then - for _, acl in ipairs(subnode.acl_depends) do - spec.depends = spec.depends or {} - spec.depends.acl = spec.depends.acl or {} - spec.depends.acl[#spec.depends.acl + 1] = acl - end - end - - if (subnode.sysauth_authenticator ~= nil) or - (subnode.sysauth ~= nil and subnode.sysauth ~= false) - then - if subnode.sysauth_authenticator == "htmlauth" then - spec.auth = { - login = true, - methods = { "cookie:sysauth_https", "cookie:sysauth_http" } - } - elseif subname == "rpc" and subnode.module == "luci.controller.rpc" then - spec.auth = { - login = false, - methods = { "query:auth", "cookie:sysauth_https", "cookie:sysauth_http" } - } - elseif subnode.module == "luci.controller.admin.uci" then - spec.auth = { - login = false, - methods = { "param:sid" } - } - end - elseif subnode.sysauth == false then - spec.auth = {} - end - - if not spec.action then - spec.title = nil - end - - spec.satisfied = check_depends(spec) - json.children = json.children or {} - json.children[subname] = tree_to_json(subnode, spec) - end - end - - return json -end - -function build_url(...) - local path = {...} - local url = { http.getenv("SCRIPT_NAME") or "" } - - local p - for _, p in ipairs(path) do - if p:match("^[a-zA-Z0-9_%-%.%%/,;]+$") then - url[#url+1] = "/" - url[#url+1] = p - end - end - - if #path == 0 then - url[#url+1] = "/" - end - - return table.concat(url, "") -end - - -function error404(message) - http.status(404, "Not Found") - message = message or "Not Found" - - local function render() - local template = require "luci.template" - template.render("error404", {message=message}) - end - - if not util.copcall(render) then - http.prepare_content("text/plain") - http.write(message) - end - - return false -end - -function error500(message) - util.perror(message) - if not context.template_header_sent then - http.status(500, "Internal Server Error") - http.prepare_content("text/plain") - http.write(message) - else - require("luci.template") - if not util.copcall(luci.template.render, "error500", {message=message}) then - http.prepare_content("text/plain") - http.write(message) - end - end - return false -end - -local function determine_request_language() - local conf = require "luci.config" - assert(conf.main, "/etc/config/luci seems to be corrupt, unable to find section 'main'") - - local lang = conf.main.lang or "auto" - if lang == "auto" then - local aclang = http.getenv("HTTP_ACCEPT_LANGUAGE") or "" - for aclang in aclang:gmatch("[%w_-]+") do - local country, culture = aclang:match("^([a-z][a-z])[_-]([a-zA-Z][a-zA-Z])$") - if country and culture then - local cc = "%s_%s" %{ country, culture:lower() } - if conf.languages[cc] then - lang = cc - break - elseif conf.languages[country] then - lang = country - break - end - elseif conf.languages[aclang] then - lang = aclang - break - end - end - end - - if lang == "auto" then - lang = i18n.default - end - - i18n.setlanguage(lang) -end - -function httpdispatch(request, prefix) - http.context.request = request - - local r = {} - context.request = r - - local pathinfo = http.urldecode(request:getenv("PATH_INFO") or "", true) - - if prefix then - for _, node in ipairs(prefix) do - r[#r+1] = node - end - end - - local node - for node in pathinfo:gmatch("[^/%z]+") do - r[#r+1] = node - end - - determine_request_language() - - local stat, err = util.coxpcall(function() - dispatch(context.request) - end, error500) - - http.close() - - --context._disable_memtrace() -end - -local function require_post_security(target, args) - if type(target) == "table" and target.type == "arcombine" and type(target.targets) == "table" then - return require_post_security((type(args) == "table" and #args > 0) and target.targets[2] or target.targets[1], args) - end - - if type(target) == "table" then - if type(target.post) == "table" then - local param_name, required_val, request_val - - for param_name, required_val in pairs(target.post) do - request_val = http.formvalue(param_name) - - if (type(required_val) == "string" and - request_val ~= required_val) or - (required_val == true and request_val == nil) - then - return false - end - end - - return true - end - - return (target.post == true) - end - - return false -end - -function test_post_security() - if http.getenv("REQUEST_METHOD") ~= "POST" then - http.status(405, "Method Not Allowed") - http.header("Allow", "POST") - return false - end - - if http.formvalue("token") ~= context.authtoken then - http.status(403, "Forbidden") - luci.template.render("csrftoken") - return false - end - - return true -end - -local function session_retrieve(sid, allowed_users) - local sdat = util.ubus("session", "get", { ubus_rpc_session = sid }) - local sacl = util.ubus("session", "access", { ubus_rpc_session = sid }) - - if type(sdat) == "table" and - type(sdat.values) == "table" and - type(sdat.values.token) == "string" and - (not allowed_users or - util.contains(allowed_users, sdat.values.username)) - then - uci:set_session_id(sid) - return sid, sdat.values, type(sacl) == "table" and sacl or {} - end - - return nil, nil, nil -end - -local function session_setup(user, pass) - local login = util.ubus("session", "login", { - username = user, - password = pass, - timeout = tonumber(luci.config.sauth.sessiontime) - }) - - local rp = context.requestpath - and table.concat(context.requestpath, "/") or "" - - if type(login) == "table" and - type(login.ubus_rpc_session) == "string" - then - util.ubus("session", "set", { - ubus_rpc_session = login.ubus_rpc_session, - values = { token = sys.uniqueid(16) } - }) - nixio.syslog("info", tostring("luci: accepted login on /%s for %s from %s\n" - %{ rp, user or "?", http.getenv("REMOTE_ADDR") or "?" })) - - return session_retrieve(login.ubus_rpc_session) - end - nixio.syslog("info", tostring("luci: failed login on /%s for %s from %s\n" - %{ rp, user or "?", http.getenv("REMOTE_ADDR") or "?" })) -end - -local function check_authentication(method) - local auth_type, auth_param = method:match("^(%w+):(.+)$") - local sid, sdat - - if auth_type == "cookie" then - sid = http.getcookie(auth_param) - elseif auth_type == "param" then - sid = http.formvalue(auth_param) - elseif auth_type == "query" then - sid = http.formvalue(auth_param, true) - end - - return session_retrieve(sid) -end - -local function merge_trees(node_a, node_b) - for k, v in pairs(node_b) do - if k == "children" then - node_a.children = node_a.children or {} - - for name, spec in pairs(v) do - node_a.children[name] = merge_trees(node_a.children[name] or {}, spec) - end - else - node_a[k] = v - end - end - - if type(node_a.action) == "table" and - node_a.action.type == "firstchild" and - node_a.children == nil - then - node_a.satisfied = false - end - - return node_a -end - -local function apply_tree_acls(node, acl) - if type(node.children) == "table" then - for _, child in pairs(node.children) do - apply_tree_acls(child, acl) - end - end - - local perm - if type(node.depends) == "table" then - perm = check_acl_depends(node.depends.acl, acl["access-group"]) - else - perm = true - end - - if perm == nil then - node.satisfied = false - elseif perm == false then - node.readonly = true - end -end - -function menu_json(acl) - local tree = context.tree or createtree() - local lua_tree = tree_to_json(tree, { - action = { - ["type"] = "firstchild", - ["recurse"] = true - } - }) - - local json_tree = createtree_json() - local menu_tree = merge_trees(lua_tree, json_tree) - - if acl then - apply_tree_acls(menu_tree, acl) - end - - return menu_tree -end - -local function init_template_engine(ctx) - local tpl = require "luci.template" - local media = luci.config.main.mediaurlbase - - if not pcall(tpl.Template, "themes/%s/header" % fs.basename(media)) then - media = nil - for name, theme in pairs(luci.config.themes) do - if name:sub(1,1) ~= "." and pcall(tpl.Template, - "themes/%s/header" % fs.basename(theme)) then - media = theme - end - end - assert(media, "No valid theme found") - end - - local function _ifattr(cond, key, val, noescape) - if cond then - local env = getfenv(3) - local scope = (type(env.self) == "table") and env.self - if type(val) == "table" then - if not next(val) then - return '' - else - val = util.serialize_json(val) - end - end - - val = tostring(val or - (type(env[key]) ~= "function" and env[key]) or - (scope and type(scope[key]) ~= "function" and scope[key]) or "") - - if noescape ~= true then - val = xml.pcdata(val) - end - - return string.format(' %s="%s"', tostring(key), val) - else - return '' - end - end - - tpl.context.viewns = setmetatable({ - write = http.write; - include = function(name) tpl.Template(name):render(getfenv(2)) end; - translate = i18n.translate; - translatef = i18n.translatef; - export = function(k, v) if tpl.context.viewns[k] == nil then tpl.context.viewns[k] = v end end; - striptags = xml.striptags; - pcdata = xml.pcdata; - media = media; - theme = fs.basename(media); - resource = luci.config.main.resourcebase; - ifattr = function(...) return _ifattr(...) end; - attr = function(...) return _ifattr(true, ...) end; - url = build_url; - }, {__index=function(tbl, key) - if key == "controller" then - return build_url() - elseif key == "REQUEST_URI" then - return build_url(unpack(ctx.requestpath)) - elseif key == "FULL_REQUEST_URI" then - 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] = "?" - url[#url+1] = query - end - return table.concat(url, "") - elseif key == "token" then - return ctx.authtoken - else - return rawget(tbl, key) or _G[key] - end - end}) - - return tpl -end - -function is_authenticated(auth) - if type(auth) == "table" and type(auth.methods) == "table" and #auth.methods > 0 then - local sid, sdat, sacl - for _, method in ipairs(auth.methods) do - sid, sdat, sacl = check_authentication(method) - - if sid and sdat and sacl then - return sid, sdat, sacl - end - end - end -end - -local function ctx_append(ctx, name, node) - ctx.path = ctx.path or {} - ctx.path[#ctx.path + 1] = name - - ctx.acls = ctx.acls or {} - - local acls = (type(node.depends) == "table" and type(node.depends.acl) == "table") and node.depends.acl or {} - for _, acl in ipairs(acls) do - ctx.acls[_] = acl - end - - ctx.auth = node.auth or ctx.auth - ctx.cors = node.cors or ctx.cors - ctx.suid = node.setuser or ctx.suid - ctx.sgid = node.setgroup or ctx.sgid - - return ctx -end - -local function node_weight(node) - local weight = node.order or 9999 - - if weight > 9999 then - weight = 9999 - end - - if type(node.auth) == "table" and node.auth.login then - weight = weight + 10000 - end - - return weight -end - -local function resolve_firstchild(node, sacl, login_allowed, ctx) - local candidate = nil - local candidate_ctx = nil - - for name, child in pairs(node.children) do - if child.satisfied then - if not sacl then - local _ - _, _, sacl = is_authenticated(node.auth) - end - - local cacl = (type(child.depends) == "table") and child.depends.acl or nil - local login = login_allowed or (type(child.auth) == "table" and child.auth.login) - if login or check_acl_depends(cacl, sacl and sacl["access-group"]) ~= nil then - if child.title and type(child.action) == "table" then - local child_ctx = ctx_append(util.clone(ctx, true), name, child) - if child.action.type == "firstchild" then - if not candidate or node_weight(candidate) > node_weight(child) then - local have_grandchild = resolve_firstchild(child, sacl, login, child_ctx) - if have_grandchild then - candidate = child - candidate_ctx = child_ctx - end - end - elseif not child.firstchild_ineligible then - if not candidate or node_weight(candidate) > node_weight(child) then - candidate = child - candidate_ctx = child_ctx - end - end - end - end - end - end - - if candidate then - for k, v in pairs(candidate_ctx) do - ctx[k] = v - end - - return true - end - - return false -end - -local function resolve_page(tree, request_path) - local node = tree - local sacl = nil - local login = false - local ctx = {} - - for i, s in ipairs(request_path) do - node = node.children and node.children[s] - - if not node or not node.satisfied then - break - end - - ctx_append(ctx, s, node) - - if not sacl then - local _ - _, _, sacl = is_authenticated(node.auth) - end - - if not login and type(node.auth) == "table" and node.auth.login then - login = true - end - - if node.wildcard then - ctx.request_args = {} - ctx.request_path = util.clone(ctx.path, true) - - for j = i + 1, #request_path do - ctx.request_path[j] = request_path[j] - ctx.request_args[j - i] = request_path[j] - end - - break - end - end - - if node and type(node.action) == "table" and node.action.type == "firstchild" then - resolve_firstchild(node, sacl, login, ctx) - end - - ctx.acls = ctx.acls or {} - ctx.path = ctx.path or {} - ctx.request_args = ctx.request_args or {} - ctx.request_path = ctx.request_path or util.clone(request_path, true) - - node = tree - - for _, s in ipairs(ctx.path or {}) do - node = node.children[s] - assert(node, "Internal node resolve error") - end - - return node, ctx -end - -function dispatch(request) - --context._disable_memtrace = require "luci.debug".trap_memtrace("l") - local ctx = context - - local auth, cors, suid, sgid - local menu = menu_json() - local page, lookup_ctx = resolve_page(menu, request) - local action = (page and type(page.action) == "table") and page.action or {} - - local tpl = init_template_engine(ctx) - - ctx.args = lookup_ctx.request_args - ctx.path = lookup_ctx.path - ctx.dispatched = page - - ctx.requestpath = ctx.requestpath or lookup_ctx.request_path - ctx.requestargs = ctx.requestargs or lookup_ctx.request_args - ctx.requested = ctx.requested or page - - if type(lookup_ctx.auth) == "table" and next(lookup_ctx.auth) then - local sid, sdat, sacl = is_authenticated(lookup_ctx.auth) - - if not (sid and sdat and sacl) and lookup_ctx.auth.login then - local user = http.getenv("HTTP_AUTH_USER") - local pass = http.getenv("HTTP_AUTH_PASS") - - if user == nil and pass == nil then - user = http.formvalue("luci_username") - pass = http.formvalue("luci_password") - end - - if user and pass then - sid, sdat, sacl = session_setup(user, pass) - end - - if not sid then - context.path = {} - - http.status(403, "Forbidden") - http.header("X-LuCI-Login-Required", "yes") - - local scope = { duser = "root", fuser = user } - local ok, res = util.copcall(tpl.render_string, [[<% include("themes/" .. theme .. "/sysauth") %>]], scope) - if ok then - return res - end - return tpl.render("sysauth", scope) - end - - http.header("Set-Cookie", 'sysauth_%s=%s; path=%s; SameSite=Strict; HttpOnly%s' %{ - http.getenv("HTTPS") == "on" and "https" or "http", - sid, build_url(), http.getenv("HTTPS") == "on" and "; secure" or "" - }) - - http.redirect(build_url(unpack(ctx.requestpath))) - return - end - - if not sid or not sdat or not sacl then - http.status(403, "Forbidden") - http.header("X-LuCI-Login-Required", "yes") - return - end - - ctx.authsession = sid - ctx.authtoken = sdat.token - ctx.authuser = sdat.username - ctx.authacl = sacl - end - - if #lookup_ctx.acls > 0 then - local perm = check_acl_depends(lookup_ctx.acls, ctx.authacl and ctx.authacl["access-group"]) - if perm == nil then - http.status(403, "Forbidden") - return - end - - if page then - page.readonly = not perm - end - end - - if action.type == "arcombine" then - action = (#lookup_ctx.request_args > 0) and action.targets[2] or action.targets[1] - end - - if lookup_ctx.cors and http.getenv("REQUEST_METHOD") == "OPTIONS" then - luci.http.status(200, "OK") - luci.http.header("Access-Control-Allow-Origin", http.getenv("HTTP_ORIGIN") or "*") - luci.http.header("Access-Control-Allow-Methods", "GET, POST, OPTIONS") - return - end - - if require_post_security(action) then - if not test_post_security() then - return - end - end - - if lookup_ctx.sgid then - sys.process.setgroup(lookup_ctx.sgid) - end - - if lookup_ctx.suid then - sys.process.setuser(lookup_ctx.suid) - end - - if action.type == "view" then - tpl.render("view", { view = action.path }) - - elseif action.type == "call" then - local ok, mod = util.copcall(require, action.module) - if not ok then - error500(mod) - return - end - - local func = mod[action["function"]] - - assert(func ~= nil, - 'Cannot resolve function "' .. action["function"] .. '". Is it misspelled or local?') - - assert(type(func) == "function", - 'The symbol "' .. action["function"] .. '" does not refer to a function but data ' .. - 'of type "' .. type(func) .. '".') - - local argv = (type(action.parameters) == "table" and #action.parameters > 0) and { unpack(action.parameters) } or {} - for _, s in ipairs(lookup_ctx.request_args) do - argv[#argv + 1] = s - end - - local ok, err = util.copcall(func, unpack(argv)) - if not ok then - error500(err) - end - - --elseif action.type == "firstchild" then - -- tpl.render("empty_node_placeholder", getfenv(1)) - - elseif action.type == "alias" then - local sub_request = {} - for name in action.path:gmatch("[^/]+") do - sub_request[#sub_request + 1] = name - end - - for _, s in ipairs(lookup_ctx.request_args) do - sub_request[#sub_request + 1] = s - end - - dispatch(sub_request) - - elseif action.type == "rewrite" then - local sub_request = { unpack(request) } - for i = 1, action.remove do - table.remove(sub_request, 1) - end - - local n = 1 - for s in action.path:gmatch("[^/]+") do - table.insert(sub_request, n, s) - n = n + 1 - end - - for _, s in ipairs(lookup_ctx.request_args) do - sub_request[#sub_request + 1] = s - end - - dispatch(sub_request) - - elseif action.type == "template" then - tpl.render(action.path, getfenv(1)) - - elseif action.type == "cbi" then - _cbi({ config = action.config, model = action.path }, unpack(lookup_ctx.request_args)) - - elseif action.type == "form" then - _form({ model = action.path }, unpack(lookup_ctx.request_args)) - - else - if not menu.children then - error404("No root node was registered, this usually happens if no module was installed.\n" .. - "Install luci-mod-admin-full and retry. " .. - "If the module is already installed, try removing the /tmp/luci-indexcache file.") - else - error404("No page is registered at '/" .. table.concat(lookup_ctx.request_path, "/") .. "'.\n" .. - "If this url belongs to an extension, make sure it is properly installed.\n" .. - "If the extension was recently installed, try removing the /tmp/luci-indexcache file.") - end - end -end - -local function hash_filelist(files) - local fprint = {} - local n = 0 - - for i, file in ipairs(files) do - local st = fs.stat(file) - if st then - fprint[n + 1] = '%x' % st.ino - fprint[n + 2] = '%x' % st.mtime - fprint[n + 3] = '%x' % st.size - n = n + 3 - end - end - - return nixio.crypt(table.concat(fprint, "|"), "$1$"):sub(5):gsub("/", ".") -end - -local function read_cachefile(file, reader) - local euid = sys.process.info("uid") - local fuid = fs.stat(file, "uid") - local mode = fs.stat(file, "modestr") - - if euid ~= fuid or mode ~= "rw-------" then - return nil - end - - return reader(file) -end - -function createindex() - local controllers = { } - local base = "%s/controller/" % util.libpath() - local _, path - - for path in (fs.glob("%s*.lua" % base) or function() end) do - controllers[#controllers+1] = path - end - - for path in (fs.glob("%s*/*.lua" % base) or function() end) do - controllers[#controllers+1] = path - end - - local cachefile - - if indexcache then - cachefile = "%s.%s.lua" %{ indexcache, hash_filelist(controllers) } - - local res = read_cachefile(cachefile, function(path) return loadfile(path)() end) - if res then - index = res - return res - end - - for file in (fs.glob("%s.*.lua" % indexcache) or function() end) do - fs.unlink(file) - end - end - - index = {} - - for _, path in ipairs(controllers) do - local modname = "luci.controller." .. path:sub(#base+1, #path-4):gsub("/", ".") - local mod = require(modname) - assert(mod ~= true, - "Invalid controller file found\n" .. - "The file '" .. path .. "' contains an invalid module line.\n" .. - "Please verify whether the module name is set to '" .. modname .. - "' - It must correspond to the file path!") - - local idx = mod.index - if type(idx) == "function" then - index[modname] = idx - end - end - - if cachefile then - local f = nixio.open(cachefile, "w", 600) - f:writeall(util.get_bytecode(index)) - f:close() - end -end - -function createtree_json() - local json = require "luci.jsonc" - local tree = {} - - local schema = { - action = "table", - auth = "table", - cors = "boolean", - depends = "table", - order = "number", - setgroup = "string", - setuser = "string", - title = "string", - wildcard = "boolean", - firstchild_ineligible = "boolean" - } - - local files = {} - local cachefile - - for file in (fs.glob("/usr/share/luci/menu.d/*.json") or function() end) do - files[#files+1] = file - end - - if indexcache then - cachefile = "%s.%s.json" %{ indexcache, hash_filelist(files) } - - local res = read_cachefile(cachefile, function(path) return json.parse(fs.readfile(path) or "") end) - if res then - return res - end - - for file in (fs.glob("%s.*.json" % indexcache) or function() end) do - fs.unlink(file) - end - end - - for _, file in ipairs(files) do - local data = json.parse(fs.readfile(file) or "") - if type(data) == "table" then - for path, spec in pairs(data) do - if type(spec) == "table" then - local node = tree - - for s in path:gmatch("[^/]+") do - if s == "*" then - node.wildcard = true - break - end - - node.children = node.children or {} - node.children[s] = node.children[s] or {} - node = node.children[s] - end - - if node ~= tree then - for k, t in pairs(schema) do - if type(spec[k]) == t then - node[k] = spec[k] - end - end - - node.satisfied = check_depends(spec) - end - end - end - end - end - - if cachefile then - local f = nixio.open(cachefile, "w", 600) - f:writeall(json.stringify(tree)) - f:close() - end - - return tree -end - --- Build the index before if it does not exist yet. -function createtree() - if not index then - createindex() - end - - local ctx = context - local tree = {nodes={}, inreq=true} - - ctx.treecache = setmetatable({}, {__mode="v"}) - ctx.tree = tree - - local scope = setmetatable({}, {__index = luci.dispatcher}) - - for k, v in pairs(index) do - scope._NAME = k - setfenv(v, scope) - v() - end - - return tree -end - -function assign(path, clone, title, order) - local obj = node(unpack(path)) - obj.nodes = nil - obj.module = nil - - obj.title = title - obj.order = order - - setmetatable(obj, {__index = _create_node(clone)}) - - return obj -end - -function entry(path, target, title, order) - local c = node(unpack(path)) - - c.target = target - c.title = title - c.order = order - c.module = getfenv(2)._NAME - - return c -end - --- enabling the node. -function get(...) - return _create_node({...}) -end - -function node(...) - local c = _create_node({...}) - - c.module = getfenv(2)._NAME - c.auto = nil - - return c -end - -function lookup(...) - local i, path = nil, {} - for i = 1, select('#', ...) do - local name, arg = nil, tostring(select(i, ...)) - for name in arg:gmatch("[^/]+") do - path[#path+1] = name - end - end - - for i = #path, 1, -1 do - local node = context.treecache[table.concat(path, ".", 1, i)] - if node and (i == #path or node.leaf) then - return node, build_url(unpack(path)) - end - end -end - -function _create_node(path) - if #path == 0 then - return context.tree - end - - local name = table.concat(path, ".") - local c = context.treecache[name] - - if not c then - local last = table.remove(path) - local parent = _create_node(path) - - c = {nodes={}, auto=true, inreq=true} - - parent.nodes[last] = c - context.treecache[name] = c - end - - return c -end - --- Subdispatchers -- - -function firstchild() - return { type = "firstchild" } -end - -function firstnode() - return { type = "firstnode" } -end - -function alias(...) - return { type = "alias", req = { ... } } -end - -function rewrite(n, ...) - return { type = "rewrite", n = n, req = { ... } } -end - -function call(name, ...) - return { type = "call", argv = {...}, name = name } -end - -function post_on(params, name, ...) - return { - type = "call", - post = params, - argv = { ... }, - name = name - } -end - -function post(...) - return post_on(true, ...) -end - - -function template(name) - return { type = "template", view = name } -end - -function view(name) - return { type = "view", view = name } -end - - -function _cbi(self, ...) - local cbi = require "luci.cbi" - local tpl = require "luci.template" - local http = require "luci.http" - local util = require "luci.util" - - local config = self.config or {} - local maps = cbi.load(self.model, ...) - - local state = nil - - local function has_uci_access(config, level) - local rv = util.ubus("session", "access", { - ubus_rpc_session = context.authsession, - scope = "uci", object = config, - ["function"] = level - }) - - return (type(rv) == "table" and rv.access == true) or false - end - - local i, res - for i, res in ipairs(maps) do - if util.instanceof(res, cbi.SimpleForm) then - io.stderr:write("Model %s returns SimpleForm but is dispatched via cbi(),\n" - % self.model) - - io.stderr:write("please change %s to use the form() action instead.\n" - % table.concat(context.request, "/")) - end - - res.flow = config - local cstate = res:parse() - if cstate and (not state or cstate < state) then - state = cstate - end - end - - local function _resolve_path(path) - return type(path) == "table" and build_url(unpack(path)) or path - end - - if config.on_valid_to and state and state > 0 and state < 2 then - http.redirect(_resolve_path(config.on_valid_to)) - return - end - - if config.on_changed_to and state and state > 1 then - http.redirect(_resolve_path(config.on_changed_to)) - return - end - - if config.on_success_to and state and state > 0 then - http.redirect(_resolve_path(config.on_success_to)) - return - end - - if config.state_handler then - if not config.state_handler(state, maps) then - return - end - end - - http.header("X-CBI-State", state or 0) - - if not config.noheader then - tpl.render("cbi/header", {state = state}) - end - - local redirect - local messages - local applymap = false - local pageaction = true - local parsechain = { } - local writable = false - - for i, res in ipairs(maps) do - if res.apply_needed and res.parsechain then - local c - for _, c in ipairs(res.parsechain) do - parsechain[#parsechain+1] = c - end - applymap = true - end - - if res.redirect then - redirect = redirect or res.redirect - end - - if res.pageaction == false then - pageaction = false - end - - if res.message then - messages = messages or { } - messages[#messages+1] = res.message - end - end - - for i, res in ipairs(maps) do - local is_readable_map = has_uci_access(res.config, "read") - local is_writable_map = has_uci_access(res.config, "write") - - writable = writable or is_writable_map - - res:render({ - firstmap = (i == 1), - redirect = redirect, - messages = messages, - pageaction = pageaction, - parsechain = parsechain, - readable = is_readable_map, - writable = is_writable_map - }) - end - - if not config.nofooter then - tpl.render("cbi/footer", { - flow = config, - pageaction = pageaction, - redirect = redirect, - state = state, - autoapply = config.autoapply, - trigger_apply = applymap, - writable = writable - }) - end -end - -function cbi(model, config) - return { - type = "cbi", - post = { ["cbi.submit"] = true }, - config = config, - model = model - } -end - - -function arcombine(trg1, trg2) - return { - type = "arcombine", - env = getfenv(), - targets = {trg1, trg2} - } -end - - -function _form(self, ...) - local cbi = require "luci.cbi" - local tpl = require "luci.template" - local http = require "luci.http" - - local maps = luci.cbi.load(self.model, ...) - local state = nil - - local i, res - for i, res in ipairs(maps) do - local cstate = res:parse() - if cstate and (not state or cstate < state) then - state = cstate - end - end - - http.header("X-CBI-State", state or 0) - tpl.render("header") - for i, res in ipairs(maps) do - res:render() - end - tpl.render("footer") -end - -function form(model) - return { - type = "form", - post = { ["cbi.submit"] = true }, - model = model - } -end - -translate = i18n.translate - --- This function does not actually translate the given argument but --- is used by build/i18n-scan.pl to find translatable entries. -function _(text) - return text -end diff --git a/modules/luci-base/luasrc/dispatcher.luadoc b/modules/luci-base/luasrc/dispatcher.luadoc deleted file mode 100644 index a77f8d8b07..0000000000 --- a/modules/luci-base/luasrc/dispatcher.luadoc +++ /dev/null @@ -1,220 +0,0 @@ ----[[ -LuCI web dispatcher. -]] -module "luci.dispatcher" - ----[[ -Build the URL relative to the server webroot from given virtual path. - -@class function -@name build_url -@param ... Virtual path -@return Relative URL -]] - ----[[ -Check whether a dispatch node shall be visible - -@class function -@name node_visible -@param node Dispatch node -@return Boolean indicating whether the node should be visible -]] - ----[[ -Return a sorted table of visible children within a given node - -@class function -@name node_childs -@param node Dispatch node -@return Ordered table of child node names -]] - ----[[ -Send a 404 error code and render the "error404" template if available. - -@class function -@name error404 -@param message Custom error message (optional) -@return false -]] - ----[[ -Send a 500 error code and render the "error500" template if available. - -@class function -@name error500 -@param message Custom error message (optional)# -@return false -]] - ----[[ -Dispatch an HTTP request. - -@class function -@name httpdispatch -@param request LuCI HTTP Request object -]] - ----[[ -Dispatches a LuCI virtual path. - -@class function -@name dispatch -@param request Virtual path -]] - ----[[ -Generate the dispatching index using the native file-cache based strategy. - - -@class function -@name createindex -]] - ----[[ -Create the dispatching tree from the index. - -Build the index before if it does not exist yet. - -@class function -@name createtree -]] - ----[[ -Clone a node of the dispatching tree to another position. - -@class function -@name assign -@param path Virtual path destination -@param clone Virtual path source -@param title Destination node title (optional) -@param order Destination node order value (optional) -@return Dispatching tree node -]] - ----[[ -Create a new dispatching node and define common parameters. - -@class function -@name entry -@param path Virtual path -@param target Target function to call when dispatched. -@param title Destination node title -@param order Destination node order value (optional) -@return Dispatching tree node -]] - ----[[ -Fetch or create a dispatching node without setting the target module or -enabling the node. - -@class function -@name get -@param ... Virtual path -@return Dispatching tree node -]] - ----[[ -Fetch or create a new dispatching node. - -@class function -@name node -@param ... Virtual path -@return Dispatching tree node -]] - ----[[ -Lookup node in dispatching tree. - -@class function -@name lookup -@param ... Virtual path -@return Node object, canonical url or nil if the path was not found. -]] - ----[[ -Alias the first (lowest order) page automatically - - -@class function -@name firstchild -]] - ----[[ -Create a redirect to another dispatching node. - -@class function -@name alias -@param ... Virtual path destination -]] - ----[[ -Rewrite the first x path values of the request. - -@class function -@name rewrite -@param n Number of path values to replace -@param ... Virtual path to replace removed path values with -]] - ----[[ -Create a function-call dispatching target. - -@class function -@name call -@param name Target function of local controller -@param ... Additional parameters passed to the function -]] - ----[[ -Create a template render dispatching target. - -@class function -@name template -@param name Template to be rendered -]] - ----[[ -Create a CBI model dispatching target. - -@class function -@name cbi -@param model CBI model to be rendered -]] - ----[[ -Create a combined dispatching target for non argv and argv requests. - -@class function -@name arcombine -@param trg1 Overview Target -@param trg2 Detail Target -]] - ----[[ -Create a CBI form model dispatching target. - -@class function -@name form -@param model CBI form model tpo be rendered -]] - ----[[ -Access the luci.i18n translate() api. - -@class function -@name translate -@param text Text to translate -]] - ----[[ -No-op function used to mark translation entries for menu labels. - -This function does not actually translate the given argument but -is used by build/i18n-scan.pl to find translatable entries. - -@class function -@name _ -]] - diff --git a/modules/luci-base/luasrc/template.lua b/modules/luci-base/luasrc/template.lua deleted file mode 100644 index 3955bd76f3..0000000000 --- a/modules/luci-base/luasrc/template.lua +++ /dev/null @@ -1,100 +0,0 @@ --- Copyright 2008 Steven Barth <steven@midlink.org> --- Licensed to the public under the Apache License 2.0. - -local util = require "luci.util" -local config = require "luci.config" -local tparser = require "luci.template.parser" - -local tostring, pairs, loadstring = tostring, pairs, loadstring -local setmetatable, loadfile = setmetatable, loadfile -local getfenv, setfenv, rawget = getfenv, setfenv, rawget -local assert, type, error = assert, type, error - ---- LuCI template library. -module "luci.template" - -config.template = config.template or {} -viewdir = config.template.viewdir or util.libpath() .. "/view" - - --- Define the namespace for template modules -context = util.threadlocal() - ---- Render a certain template. --- @param name Template name --- @param scope Scope to assign to template (optional) -function render(name, scope) - return Template(name):render(scope or getfenv(2)) -end - ---- Render a template from a string. --- @param template Template string --- @param scope Scope to assign to template (optional) -function render_string(template, scope) - return Template(nil, template):render(scope or getfenv(2)) -end - - --- Template class -Template = util.class() - --- Shared template cache to store templates in to avoid unnecessary reloading -Template.cache = setmetatable({}, {__mode = "v"}) - - --- Constructor - Reads and compiles the template on-demand -function Template.__init__(self, name, template) - if name then - self.template = self.cache[name] - self.name = name - else - self.name = "[string]" - end - - -- Create a new namespace for this template - self.viewns = context.viewns - - -- If we have a cached template, skip compiling and loading - if not self.template then - - -- Compile template - local err - local sourcefile - - if name then - sourcefile = viewdir .. "/" .. name .. ".htm" - self.template, _, err = tparser.parse(sourcefile) - else - sourcefile = "[string]" - self.template, _, err = tparser.parse_string(template) - end - - -- If we have no valid template throw error, otherwise cache the template - if not self.template then - error("Failed to load template '" .. self.name .. "'.\n" .. - "Error while parsing template '" .. sourcefile .. "':\n" .. - (err or "Unknown syntax error")) - elseif name then - self.cache[name] = self.template - end - end -end - - --- Renders a template -function Template.render(self, scope) - scope = scope or getfenv(2) - - -- Put our predefined objects in the scope of the template - setfenv(self.template, setmetatable({}, {__index = - function(tbl, key) - return rawget(tbl, key) or self.viewns[key] or scope[key] - end})) - - -- Now finally render the thing - local stat, err = util.copcall(self.template) - if not stat then - error("Failed to execute template '" .. self.name .. "'.\n" .. - "A runtime error occurred: " .. tostring(err or "(nil)")) - end -end diff --git a/modules/luci-base/luasrc/view/csrftoken.htm b/modules/luci-base/luasrc/view/csrftoken.htm deleted file mode 100644 index 57ac03f3bf..0000000000 --- a/modules/luci-base/luasrc/view/csrftoken.htm +++ /dev/null @@ -1,24 +0,0 @@ -<%# - Copyright 2015 Jo-Philipp Wich <jow@openwrt.org> - Licensed to the public under the Apache License 2.0. --%> - -<%+header%> - -<h2 name="content"><%:Form token mismatch%></h2> -<br /> - -<p class="alert-message"><%:The submitted security token is invalid or already expired!%></p> - -<p><%: - In order to prevent unauthorized access to the system, your request has - been blocked. Click "Continue »" below to return to the previous page. -%></p> - -<hr /> - -<p class="right"> - <strong><a href="#" onclick="window.history.back();">Continue »</a></strong> -</p> - -<%+footer%> diff --git a/modules/luci-base/luasrc/view/error404.htm b/modules/luci-base/luasrc/view/error404.htm deleted file mode 100644 index ff151d1834..0000000000 --- a/modules/luci-base/luasrc/view/error404.htm +++ /dev/null @@ -1,12 +0,0 @@ -<%# - 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. --%> - -<%+header%> -<h2 name="content">404 <%:Not Found%></h2> -<p><%:Sorry, the object you requested was not found.%></p> -<p><%=message%></p> -<tt><%:Unable to dispatch%>: <%=url(unpack(luci.dispatcher.context.request))%></tt> -<%+footer%> diff --git a/modules/luci-base/luasrc/view/error500.htm b/modules/luci-base/luasrc/view/error500.htm deleted file mode 100644 index 34a52cda84..0000000000 --- a/modules/luci-base/luasrc/view/error500.htm +++ /dev/null @@ -1,11 +0,0 @@ -<%# - 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. --%> - -<%+header%> -<h2 name="content">500 <%:Internal Server Error%></h2> -<p><%:Sorry, the server encountered an unexpected error.%></p> -<pre class="error500"><%=message%></pre> -<%+footer%> diff --git a/modules/luci-base/luasrc/view/footer.htm b/modules/luci-base/luasrc/view/footer.htm deleted file mode 100644 index ba14ec8678..0000000000 --- a/modules/luci-base/luasrc/view/footer.htm +++ /dev/null @@ -1,27 +0,0 @@ -<%# - Copyright 2008 Steven Barth <steven@midlink.org> - Copyright 2008-2019 Jo-Philipp Wich <jo@mein.io> - Licensed to the public under the Apache License 2.0. --%> - -<% - local is_rollback_pending, rollback_time_remaining, rollback_session, rollback_token = luci.model.uci:rollback_pending() - - if is_rollback_pending or trigger_apply or trigger_revert then -%> - <script type="text/javascript"> - document.addEventListener("luci-loaded", function() { - <% if trigger_apply then -%> - L.ui.changes.apply(true); - <%- elseif trigger_revert then -%> - L.ui.changes.revert(); - <%- else -%> - L.ui.changes.confirm(true, Date.now() + <%=rollback_time_remaining%> * 1000, <%=luci.http.write_json(rollback_token)%>); - <%- end %> - }); - </script> -<% - end - - include("themes/" .. theme .. "/footer") -%> diff --git a/modules/luci-base/luasrc/view/header.htm b/modules/luci-base/luasrc/view/header.htm deleted file mode 100644 index cffe9482ca..0000000000 --- a/modules/luci-base/luasrc/view/header.htm +++ /dev/null @@ -1,38 +0,0 @@ -<%# - Copyright 2008 Steven Barth <steven@midlink.org> - Copyright 2008-2019 Jo-Philipp Wich <jo@mein.io> - Licensed to the public under the Apache License 2.0. --%> - -<% - if not luci.dispatcher.context.template_header_sent then - include("themes/" .. theme .. "/header") - luci.dispatcher.context.template_header_sent = true - end - - local applyconf = luci.config and luci.config.apply -%> - -<script type="text/javascript" src="<%=resource%>/promis.min.js"></script> -<script type="text/javascript" src="<%=resource%>/luci.js"></script> -<script type="text/javascript"> - L = new LuCI(<%= luci.http.write_json({ - token = token, - media = media, - resource = resource, - scriptname = luci.http.getenv("SCRIPT_NAME"), - pathinfo = luci.http.getenv("PATH_INFO"), - documentroot = luci.http.getenv("DOCUMENT_ROOT"), - requestpath = luci.dispatcher.context.requestpath, - dispatchpath = luci.dispatcher.context.path, - pollinterval = luci.config.main.pollinterval or 5, - ubuspath = luci.config.main.ubuspath or '/ubus/', - sessionid = luci.dispatcher.context.authsession, - nodespec = luci.dispatcher.context.dispatched, - apply_rollback = math.max(applyconf and applyconf.rollback or 90, 90), - apply_holdoff = math.max(applyconf and applyconf.holdoff or 4, 1), - apply_timeout = math.max(applyconf and applyconf.timeout or 5, 1), - apply_display = math.max(applyconf and applyconf.display or 1.5, 1), - rollback_token = rollback_token - }) %>); -</script> diff --git a/modules/luci-base/luasrc/view/sysauth.htm b/modules/luci-base/luasrc/view/sysauth.htm deleted file mode 100644 index 797c87a72e..0000000000 --- a/modules/luci-base/luasrc/view/sysauth.htm +++ /dev/null @@ -1,75 +0,0 @@ -<%# - Copyright 2008 Steven Barth <steven@midlink.org> - Copyright 2008-2012 Jo-Philipp Wich <jow@openwrt.org> - Licensed to the public under the Apache License 2.0. --%> - -<%+header%> - -<form method="post" action="<%=pcdata(FULL_REQUEST_URI)%>"> - <%- if fuser then %> - <div class="alert-message warning"> - <p><%:Invalid username and/or password! Please try again.%></p> - </div> - <% end -%> - - <div class="cbi-map"> - <h2 name="content"><%:Authorization Required%></h2> - <div class="cbi-map-descr"> - <%:Please enter your username and password.%> - </div> - <div class="cbi-section"><div class="cbi-section-node"> - <div class="cbi-value"> - <label class="cbi-value-title" for="luci_username"><%:Username%></label> - <div class="cbi-value-field"> - <input class="cbi-input-text" type="text" name="luci_username" id="luci_username" autocomplete="username" value="<%=duser%>" /> - </div> - </div> - <div class="cbi-value cbi-value-last"> - <label class="cbi-value-title" for="luci_password"><%:Password%></label> - <div class="cbi-value-field"> - <input class="cbi-input-text" type="password" name="luci_password" id="luci_password" autocomplete="current-password"/> - </div> - </div> - </div></div> - </div> - - <div class="cbi-page-actions"> - <input type="submit" value="<%:Login%>" class="btn cbi-button cbi-button-apply" /> - <input type="reset" value="<%:Reset%>" class="btn cbi-button cbi-button-reset" /> - </div> -</form> -<script type="text/javascript">//<![CDATA[ - var input = document.getElementsByName('luci_password')[0]; - if (input) - input.focus(); -//]]></script> - -<% -local uci = require "luci.model.uci".cursor() -local fs = require "nixio.fs" -local https_key = uci:get("uhttpd", "main", "key") -local https_port = uci:get("uhttpd", "main", "listen_https") -if type(https_port) == "table" then - https_port = https_port[1] -end - -if https_port and fs.access(https_key) then - https_port = https_port:match("(%d+)$") -%> - -<script type="text/javascript">//<![CDATA[ - if (document.location.protocol != 'https:') { - var url = 'https://' + window.location.hostname + ':' + '<%=https_port%>' + window.location.pathname; - var img=new Image; - img.onload=function(){window.location = url}; - img.src='https://' + window.location.hostname + ':' + '<%=https_port%>' + '<%=resource%>/icons/loading.gif?' + Math.random(); - setTimeout(function(){ - img.src='' - }, 5000); - } -//]]></script> - -<% end %> - -<%+footer%> diff --git a/modules/luci-base/luasrc/view/view.htm b/modules/luci-base/luasrc/view/view.htm deleted file mode 100644 index b451e8cfbf..0000000000 --- a/modules/luci-base/luasrc/view/view.htm +++ /dev/null @@ -1,12 +0,0 @@ -<%+header%> - -<div id="view"> - <div class="spinning"><%:Loading view…%></div> - <script type="text/javascript"> - L.require('ui').then(function(ui) { - ui.instantiateView('<%=view%>'); - }); - </script> -</div> - -<%+footer%> diff --git a/modules/luci-base/root/usr/libexec/rpcd/luci b/modules/luci-base/root/usr/libexec/rpcd/luci deleted file mode 100755 index f124512f59..0000000000 --- a/modules/luci-base/root/usr/libexec/rpcd/luci +++ /dev/null @@ -1,682 +0,0 @@ -#!/usr/bin/env lua - -local json = require "luci.jsonc" -local fs = require "nixio.fs" - -local function readfile(path) - local s = fs.readfile(path) - return s and (s:gsub("^%s+", ""):gsub("%s+$", "")) -end - -local methods = { - getInitList = { - args = { name = "name" }, - call = function(args) - local sys = require "luci.sys" - local _, name, scripts = nil, nil, {} - for _, name in ipairs(args.name and { args.name } or sys.init.names()) do - local index = sys.init.index(name) - if index then - scripts[name] = { index = index, enabled = sys.init.enabled(name) } - else - return { error = "No such init script" } - end - end - return scripts - end - }, - - setInitAction = { - args = { name = "name", action = "action" }, - call = function(args) - local sys = require "luci.sys" - if type(sys.init[args.action]) ~= "function" then - return { error = "Invalid action" } - end - return { result = sys.init[args.action](args.name) } - end - }, - - getLocaltime = { - call = function(args) - return { result = os.time() } - end - }, - - setLocaltime = { - args = { localtime = 0 }, - call = function(args) - local sys = require "luci.sys" - local date = os.date("*t", args.localtime) - if date then - sys.call("date -s '%04d-%02d-%02d %02d:%02d:%02d' >/dev/null" %{ date.year, date.month, date.day, date.hour, date.min, date.sec }) - sys.call("/etc/init.d/sysfixtime restart >/dev/null") - end - return { result = args.localtime } - end - }, - - getTimezones = { - call = function(args) - local util = require "luci.util" - local zones = require "luci.sys.zoneinfo" - - local tz = readfile("/etc/TZ") - local res = util.ubus("uci", "get", { - config = "system", - section = "@system[0]", - option = "zonename" - }) - - local result = {} - local _, zone - for _, zone in ipairs(zones.TZ) do - result[zone[1]] = { - tzstring = zone[2], - active = (res and res.value == zone[1]) and true or nil - } - end - return result - end - }, - - getLEDs = { - call = function() - local iter = fs.dir("/sys/class/leds") - local result = { } - - if iter then - local led - for led in iter do - local m, s - - result[led] = { triggers = {} } - - s = readfile("/sys/class/leds/"..led.."/trigger") - for s in (s or ""):gmatch("%S+") do - m = s:match("^%[(.+)%]$") - result[led].triggers[#result[led].triggers+1] = m or s - result[led].active_trigger = m or result[led].active_trigger - end - - s = readfile("/sys/class/leds/"..led.."/brightness") - if s then - result[led].brightness = tonumber(s) - end - - s = readfile("/sys/class/leds/"..led.."/max_brightness") - if s then - result[led].max_brightness = tonumber(s) - end - end - end - - return result - end - }, - - getUSBDevices = { - call = function() - local fs = require "nixio.fs" - local iter = fs.glob("/sys/bus/usb/devices/[0-9]*/manufacturer") - local result = { } - - if iter then - result.devices = {} - - local p - for p in iter do - local id = p:match("/([^/]+)/manufacturer$") - - result.devices[#result.devices+1] = { - id = id, - vid = readfile("/sys/bus/usb/devices/"..id.."/idVendor"), - pid = readfile("/sys/bus/usb/devices/"..id.."/idProduct"), - vendor = readfile("/sys/bus/usb/devices/"..id.."/manufacturer"), - product = readfile("/sys/bus/usb/devices/"..id.."/product"), - speed = tonumber((readfile("/sys/bus/usb/devices/"..id.."/product"))) - } - end - end - - iter = fs.glob("/sys/bus/usb/devices/*/*-port[0-9]*") - - if iter then - result.ports = {} - - local p - for p in iter do - local port = p:match("([^/]+)$") - local link = fs.readlink(p.."/device") - - result.ports[#result.ports+1] = { - port = port, - device = link and fs.basename(link) - } - end - end - - return result - end - }, - - getConntrackHelpers = { - call = function() - local ok, fd = pcall(io.open, "/usr/share/fw3/helpers.conf", "r") - local rv = {} - - if not (ok and fd) then - ok, fd = pcall(io.open, "/usr/share/firewall4/helpers", "r") - end - - if ok and fd then - local entry - - while true do - local line = fd:read("*l") - if not line then - break - end - - if line:match("^%s*config%s") then - if entry then - rv[#rv+1] = entry - end - entry = {} - else - local opt, val = line:match("^%s*option%s+(%S+)%s+(%S.*)$") - if opt and val then - opt = opt:gsub("^'(.+)'$", "%1"):gsub('^"(.+)"$', "%1") - val = val:gsub("^'(.+)'$", "%1"):gsub('^"(.+)"$', "%1") - entry[opt] = val - end - end - end - - if entry then - rv[#rv+1] = entry - end - - fd:close() - end - - return { result = rv } - end - }, - - getFeatures = { - call = function() - local fs = require "nixio.fs" - local rv = {} - local ok, fd - - rv.firewall = fs.access("/sbin/fw3") - rv.firewall4 = fs.access("/sbin/fw4") - rv.opkg = fs.access("/bin/opkg") - rv.offloading = fs.access("/sys/module/xt_FLOWOFFLOAD/refcnt") or fs.access("/sys/module/nft_flow_offload/refcnt") - rv.br2684ctl = fs.access("/usr/sbin/br2684ctl") - rv.swconfig = fs.access("/sbin/swconfig") - rv.odhcpd = fs.access("/usr/sbin/odhcpd") - rv.zram = fs.access("/sys/class/zram-control") - rv.sysntpd = fs.readlink("/usr/sbin/ntpd") and true - rv.ipv6 = fs.access("/proc/net/ipv6_route") - rv.dropbear = fs.access("/usr/sbin/dropbear") - rv.cabundle = fs.access("/etc/ssl/certs/ca-certificates.crt") - rv.relayd = fs.access("/usr/sbin/relayd") - - local wifi_features = { "eap", "11n", "11ac", "11r", "acs", "sae", "owe", "suiteb192", "wep", "wps" } - - if fs.access("/usr/sbin/hostapd") then - rv.hostapd = { cli = fs.access("/usr/sbin/hostapd_cli") } - - local _, feature - for _, feature in ipairs(wifi_features) do - rv.hostapd[feature] = - (os.execute(string.format("/usr/sbin/hostapd -v%s >/dev/null 2>/dev/null", feature)) == 0) - end - end - - if fs.access("/usr/sbin/wpa_supplicant") then - rv.wpasupplicant = { cli = fs.access("/usr/sbin/wpa_cli") } - - local _, feature - for _, feature in ipairs(wifi_features) do - rv.wpasupplicant[feature] = - (os.execute(string.format("/usr/sbin/wpa_supplicant -v%s >/dev/null 2>/dev/null", feature)) == 0) - end - end - - ok, fd = pcall(io.popen, "dnsmasq --version 2>/dev/null") - if ok then - rv.dnsmasq = {} - - while true do - local line = fd:read("*l") - if not line then - break - end - - local opts = line:match("^Compile time options: (.+)$") - if opts then - local opt - for opt in opts:gmatch("%S+") do - local no = opt:match("^no%-(%S+)$") - rv.dnsmasq[string.lower(no or opt)] = not no - end - break - end - end - - fd:close() - end - - ok, fd = pcall(io.popen, "ipset --help 2>/dev/null") - if ok then - rv.ipset = {} - - local sets = false - - while true do - local line = fd:read("*l") - if not line then - break - elseif line:match("^Supported set types:") then - sets = true - elseif sets then - local set, ver = line:match("^%s+(%S+)%s+(%d+)") - if set and not rv.ipset[set] then - rv.ipset[set] = tonumber(ver) - end - end - end - - fd:close() - end - - return rv - end - }, - - getSwconfigFeatures = { - args = { switch = "switch0" }, - call = function(args) - local util = require "luci.util" - - -- Parse some common switch properties from swconfig help output. - local swc, err = io.popen("swconfig dev %s help 2>/dev/null" % util.shellquote(args.switch)) - if swc then - local is_port_attr = false - local is_vlan_attr = false - local rv = {} - - while true do - local line = swc:read("*l") - if not line then break end - - if line:match("^%s+%-%-vlan") then - is_vlan_attr = true - - elseif line:match("^%s+%-%-port") then - is_vlan_attr = false - is_port_attr = true - - elseif line:match("cpu @") then - rv.switch_title = line:match("^switch%d: %w+%((.-)%)") - rv.num_vlans = tonumber(line:match("vlans: (%d+)")) or 16 - rv.min_vid = 1 - - elseif line:match(": pvid") or line:match(": tag") or line:match(": vid") then - if is_vlan_attr then rv.vid_option = line:match(": (%w+)") end - - elseif line:match(": enable_vlan4k") then - rv.vlan4k_option = "enable_vlan4k" - - elseif line:match(": enable_vlan") then - rv.vlan_option = "enable_vlan" - - elseif line:match(": enable_learning") then - rv.learning_option = "enable_learning" - - elseif line:match(": enable_mirror_rx") then - rv.mirror_option = "enable_mirror_rx" - - elseif line:match(": max_length") then - rv.jumbo_option = "max_length" - end - end - - swc:close() - - if not next(rv) then - return { error = "No such switch" } - end - - return rv - else - return { error = err } - end - end - }, - - getSwconfigPortState = { - args = { switch = "switch0" }, - call = function(args) - local util = require "luci.util" - - local swc, err = io.popen("swconfig dev %s show 2>/dev/null" % util.shellquote(args.switch)) - if swc then - local ports = { } - - while true do - local line = swc:read("*l") - if not line or (line:match("^VLAN %d+:") and #ports > 0) then - break - end - - local pnum = line:match("^Port (%d+):$") - if pnum then - port = { - port = tonumber(pnum), - duplex = false, - speed = 0, - link = false, - auto = false, - rxflow = false, - txflow = false - } - - ports[#ports+1] = port - end - - if port then - local m - - if line:match("full[%- ]duplex") then - port.duplex = true - end - - m = line:match(" speed:(%d+)") - if m then - port.speed = tonumber(m) - end - - m = line:match("(%d+) Mbps") - if m and port.speed == 0 then - port.speed = tonumber(m) - end - - m = line:match("link: (%d+)") - if m and port.speed == 0 then - port.speed = tonumber(m) - end - - if line:match("link: ?up") or line:match("status: ?up") then - port.link = true - end - - if line:match("auto%-negotiate") or line:match("link:.-auto") then - port.auto = true - end - - if line:match("link:.-rxflow") then - port.rxflow = true - end - - if line:match("link:.-txflow") then - port.txflow = true - end - end - end - - swc:close() - - if not next(ports) then - return { error = "No such switch" } - end - - return { result = ports } - else - return { error = err } - end - end - }, - - setPassword = { - args = { username = "root", password = "password" }, - call = function(args) - local util = require "luci.util" - return { - result = (os.execute("(echo %s; sleep 1; echo %s) | /bin/busybox passwd %s >/dev/null 2>&1" %{ - luci.util.shellquote(args.password), - luci.util.shellquote(args.password), - luci.util.shellquote(args.username) - }) == 0) - } - end - }, - - getBlockDevices = { - call = function() - local fs = require "nixio.fs" - - local block = io.popen("/sbin/block info", "r") - if block then - local rv = {} - - while true do - local ln = block:read("*l") - if not ln then - break - end - - local dev = ln:match("^/dev/(.-):") - if dev then - local s = tonumber((fs.readfile("/sys/class/block/" .. dev .."/size"))) - local e = { - dev = "/dev/" .. dev, - size = s and s * 512 - } - - local key, val = { } - for key, val in ln:gmatch([[(%w+)="(.-)"]]) do - e[key:lower()] = val - end - - rv[dev] = e - end - end - - block:close() - - return rv - else - return { error = "Unable to execute block utility" } - end - end - }, - - setBlockDetect = { - call = function() - return { result = (os.execute("/sbin/block detect > /etc/config/fstab") == 0) } - end - }, - - getMountPoints = { - call = function() - local fs = require "nixio.fs" - - local fd, err = io.open("/proc/mounts", "r") - if fd then - local rv = {} - - while true do - local ln = fd:read("*l") - if not ln then - break - end - - local device, mount, fstype, options, freq, pass = ln:match("^(%S*) (%S*) (%S*) (%S*) (%d+) (%d+)$") - if device and mount then - device = device:gsub("\\(%d+)", function(n) return string.char(tonumber(n, 8)) end) - mount = mount:gsub("\\(%d+)", function(n) return string.char(tonumber(n, 8)) end) - - local stat = fs.statvfs(mount) - if stat and stat.blocks > 0 then - rv[#rv+1] = { - device = device, - mount = mount, - size = stat.bsize * stat.blocks, - avail = stat.bsize * stat.bavail, - free = stat.bsize * stat.bfree - } - end - end - end - - fd:close() - - return { result = rv } - else - return { error = err } - end - end - }, - - getRealtimeStats = { - args = { mode = "interface", device = "eth0" }, - call = function(args) - local util = require "luci.util" - - local flags - if args.mode == "interface" then - flags = "-i %s" % util.shellquote(args.device) - elseif args.mode == "wireless" then - flags = "-r %s" % util.shellquote(args.device) - elseif args.mode == "conntrack" then - flags = "-c" - elseif args.mode == "load" then - flags = "-l" - else - return { error = "Invalid mode" } - end - - local fd, err = io.popen("luci-bwc %s" % flags, "r") - if fd then - local parse = json.new() - local done - - parse:parse("[") - - while true do - local ln = fd:read("*l") - if not ln then - break - end - - done, err = parse:parse((ln:gsub("%d+", "%1.0"))) - - if done then - err = "Unexpected JSON data" - end - - if err then - break - end - end - - fd:close() - - done, err = parse:parse("]") - - if err then - return { error = err } - elseif not done then - return { error = "Incomplete JSON data" } - else - return { result = parse:get() } - end - else - return { error = err } - end - end - }, - - getConntrackList = { - call = function() - local sys = require "luci.sys" - return { result = sys.net.conntrack() } - end - }, - - getProcessList = { - call = function() - local sys = require "luci.sys" - local res = {} - for _, v in pairs(sys.process.list()) do - res[#res + 1] = v - end - return { result = res } - end - } -} - -local function parseInput() - local parse = json.new() - local done, err - - while true do - local chunk = io.read(4096) - if not chunk then - break - elseif not done and not err then - done, err = parse:parse(chunk) - end - end - - if not done then - print(json.stringify({ error = err or "Incomplete input" })) - os.exit(1) - end - - return parse:get() -end - -local function validateArgs(func, uargs) - local method = methods[func] - if not method then - print(json.stringify({ error = "Method not found" })) - os.exit(1) - end - - if type(uargs) ~= "table" then - print(json.stringify({ error = "Invalid arguments" })) - os.exit(1) - end - - uargs.ubus_rpc_session = nil - - local k, v - local margs = method.args or {} - for k, v in pairs(uargs) do - if margs[k] == nil or - (v ~= nil and type(v) ~= type(margs[k])) - then - print(json.stringify({ error = "Invalid arguments" })) - os.exit(1) - end - end - - return method -end - -if arg[1] == "list" then - local _, method, rv = nil, nil, {} - for _, method in pairs(methods) do rv[_] = method.args or {} end - print((json.stringify(rv):gsub(":%[%]", ":{}"))) -elseif arg[1] == "call" then - local args = parseInput() - local method = validateArgs(arg[2], args) - local result, code = method.call(args) - print((json.stringify(result):gsub("^%[%]$", "{}"))) - os.exit(code or 0) -end diff --git a/modules/luci-base/root/usr/share/luci/menu.d/luci-base.json b/modules/luci-base/root/usr/share/luci/menu.d/luci-base.json index 605c7ab777..000c368151 100644 --- a/modules/luci-base/root/usr/share/luci/menu.d/luci-base.json +++ b/modules/luci-base/root/usr/share/luci/menu.d/luci-base.json @@ -61,7 +61,7 @@ "admin/translations/*": { "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.index", "function": "action_translations" }, @@ -70,7 +70,7 @@ "admin/ubus/*": { "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.index", "function": "action_ubus" }, @@ -81,7 +81,7 @@ "title": "Logout", "order": 999, "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.index", "function": "action_logout" }, @@ -99,7 +99,7 @@ "admin/uci/revert": { "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.uci", "function": "action_revert", "post": true @@ -109,7 +109,7 @@ "admin/uci/apply_rollback": { "cors": true, "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.uci", "function": "action_apply_rollback", "post": true @@ -122,7 +122,7 @@ "admin/uci/apply_unchecked": { "cors": true, "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.uci", "function": "action_apply_unchecked", "post": true @@ -135,7 +135,7 @@ "admin/uci/confirm": { "cors": true, "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.uci", "function": "action_confirm" }, @@ -144,7 +144,7 @@ "admin/menu": { "action": { - "type": "call", + "type": "function", "module": "luci.controller.admin.index", "function": "action_menu" }, diff --git a/modules/luci-base-ucode/root/usr/share/rpcd/ucode/luci b/modules/luci-base/root/usr/share/rpcd/ucode/luci index 794676abc6..794676abc6 100644 --- a/modules/luci-base-ucode/root/usr/share/rpcd/ucode/luci +++ b/modules/luci-base/root/usr/share/rpcd/ucode/luci diff --git a/modules/luci-base/src/Makefile b/modules/luci-base/src/Makefile index 2a425d5ab7..896aeb0a38 100644 --- a/modules/luci-base/src/Makefile +++ b/modules/luci-base/src/Makefile @@ -4,29 +4,31 @@ contrib/lemon: contrib/lemon.c contrib/lempar.c cc -o contrib/lemon $< -plural_formula.c: plural_formula.y contrib/lemon +lib/plural_formula.c: lib/plural_formula.y contrib/lemon ./contrib/lemon -q $< -template_lmo.c: plural_formula.c +lib/lmo.c: lib/plural_formula.c + +core.so: lib/luci.o lib/lmo.o lib/plural_formula.o + $(CC) $(LDFLAGS) -shared -o $@ $^ + +version.uc: + echo "export const revision = '$(LUCI_VERSION)', branch = '$(LUCI_GITBRANCH)';" > $@ clean: - rm -f contrib/lemon po2lmo parser.so version.lua plural_formula.c plural_formula.h *.o + rm -f contrib/lemon lib/*.o lib/plural_formula.c lib/plural_formula.h core.so version.uc jsmin: jsmin.o $(CC) $(LDFLAGS) -o $@ $^ -po2lmo: po2lmo.o template_lmo.o plural_formula.o +po2lmo: po2lmo.o lib/lmo.o lib/plural_formula.o $(CC) $(LDFLAGS) -o $@ $^ -parser.so: template_parser.o template_utils.o template_lmo.o template_lualib.o plural_formula.o - $(CC) $(LDFLAGS) -shared -o $@ $^ - -version.lua: - ./mkversion.sh $@ $(LUCI_VERSION) "$(LUCI_GITBRANCH)" - -compile: parser.so version.lua +compile: core.so version.uc install: compile - mkdir -p $(DESTDIR)/usr/lib/lua/luci/template - cp parser.so $(DESTDIR)/usr/lib/lua/luci/template/parser.so - cp version.lua $(DESTDIR)/usr/lib/lua/luci/version.lua + mkdir -p $(DESTDIR)/usr/lib/ucode/luci + cp core.so $(DESTDIR)/usr/lib/ucode/luci/core.so + + mkdir -p $(DESTDIR)/usr/share/ucode/luci + cp version.uc $(DESTDIR)/usr/share/ucode/luci/version.uc diff --git a/modules/luci-base-ucode/src/lib/lmo.c b/modules/luci-base/src/lib/lmo.c index da521bc98b..da521bc98b 100644 --- a/modules/luci-base-ucode/src/lib/lmo.c +++ b/modules/luci-base/src/lib/lmo.c diff --git a/modules/luci-base-ucode/src/lib/lmo.h b/modules/luci-base/src/lib/lmo.h index 744209f62c..744209f62c 100644 --- a/modules/luci-base-ucode/src/lib/lmo.h +++ b/modules/luci-base/src/lib/lmo.h diff --git a/modules/luci-base-ucode/src/lib/luci.c b/modules/luci-base/src/lib/luci.c index e6860e727d..e6860e727d 100644 --- a/modules/luci-base-ucode/src/lib/luci.c +++ b/modules/luci-base/src/lib/luci.c diff --git a/modules/luci-base-ucode/src/lib/plural_formula.y b/modules/luci-base/src/lib/plural_formula.y index 1623f8b282..1623f8b282 100644 --- a/modules/luci-base-ucode/src/lib/plural_formula.y +++ b/modules/luci-base/src/lib/plural_formula.y diff --git a/modules/luci-base/src/po2lmo.c b/modules/luci-base/src/po2lmo.c index 5f398c266e..0a04e9ba17 100644 --- a/modules/luci-base/src/po2lmo.c +++ b/modules/luci-base/src/po2lmo.c @@ -16,7 +16,7 @@ * limitations under the License. */ -#include "template_lmo.h" +#include "lib/lmo.h" static void die(const char *msg) { @@ -169,8 +169,11 @@ static void print_msg(struct msg *msg, FILE *out) else snprintf(key, sizeof(key), "%s", msg->id); - key_id = sfh_hash(key, strlen(key)); - val_id = sfh_hash(msg->val[i], strlen(msg->val[i])); + len = strlen(key); + key_id = sfh_hash(key, len, len); + + len = strlen(msg->val[i]); + val_id = sfh_hash(msg->val[i], len, len); if (key_id != val_id) { n_entries++; diff --git a/modules/luci-base-ucode/ucode/controller/admin/index.uc b/modules/luci-base/ucode/controller/admin/index.uc index 16a74abc46..16a74abc46 100644 --- a/modules/luci-base-ucode/ucode/controller/admin/index.uc +++ b/modules/luci-base/ucode/controller/admin/index.uc diff --git a/modules/luci-base-ucode/ucode/controller/admin/uci.uc b/modules/luci-base/ucode/controller/admin/uci.uc index c38a42b10b..c38a42b10b 100644 --- a/modules/luci-base-ucode/ucode/controller/admin/uci.uc +++ b/modules/luci-base/ucode/controller/admin/uci.uc diff --git a/modules/luci-base-ucode/ucode/dispatcher.uc b/modules/luci-base/ucode/dispatcher.uc index 84eff71d3a..84eff71d3a 100644 --- a/modules/luci-base-ucode/ucode/dispatcher.uc +++ b/modules/luci-base/ucode/dispatcher.uc diff --git a/modules/luci-base-ucode/ucode/http.uc b/modules/luci-base/ucode/http.uc index b464497eac..b464497eac 100644 --- a/modules/luci-base-ucode/ucode/http.uc +++ b/modules/luci-base/ucode/http.uc diff --git a/modules/luci-base-ucode/ucode/runtime.uc b/modules/luci-base/ucode/runtime.uc index ee0756efc3..a8b6812e74 100644 --- a/modules/luci-base-ucode/ucode/runtime.uc +++ b/modules/luci-base/ucode/runtime.uc @@ -47,7 +47,6 @@ const Class = { if (!this.L) { this.L = this.env.dispatcher.load_luabridge().create(); this.L.set('L', proto({ write: print }, this.env)); - this.L.eval('package.path = "/usr/lib/lua/luci/ucodebridge/?.lua;" .. package.path'); this.L.invoke('require', 'luci.ucodebridge'); this.env.lua_active = true; diff --git a/modules/luci-base-ucode/ucode/sys.uc b/modules/luci-base/ucode/sys.uc index d4db91a9b9..d4db91a9b9 100644 --- a/modules/luci-base-ucode/ucode/sys.uc +++ b/modules/luci-base/ucode/sys.uc diff --git a/modules/luci-base-ucode/ucode/template/csrftoken.ut b/modules/luci-base/ucode/template/csrftoken.ut index 4e96eebe90..4e96eebe90 100644 --- a/modules/luci-base-ucode/ucode/template/csrftoken.ut +++ b/modules/luci-base/ucode/template/csrftoken.ut diff --git a/modules/luci-base-ucode/ucode/template/error404.ut b/modules/luci-base/ucode/template/error404.ut index 90c3d3784b..90c3d3784b 100644 --- a/modules/luci-base-ucode/ucode/template/error404.ut +++ b/modules/luci-base/ucode/template/error404.ut diff --git a/modules/luci-base-ucode/ucode/template/error500.ut b/modules/luci-base/ucode/template/error500.ut index 39a0eec678..39a0eec678 100644 --- a/modules/luci-base-ucode/ucode/template/error500.ut +++ b/modules/luci-base/ucode/template/error500.ut diff --git a/modules/luci-base-ucode/ucode/template/footer.ut b/modules/luci-base/ucode/template/footer.ut index 22d4f136f0..22d4f136f0 100644 --- a/modules/luci-base-ucode/ucode/template/footer.ut +++ b/modules/luci-base/ucode/template/footer.ut diff --git a/modules/luci-base-ucode/ucode/template/header.ut b/modules/luci-base/ucode/template/header.ut index fb61da5146..fb61da5146 100644 --- a/modules/luci-base-ucode/ucode/template/header.ut +++ b/modules/luci-base/ucode/template/header.ut diff --git a/modules/luci-base-ucode/ucode/template/sysauth.ut b/modules/luci-base/ucode/template/sysauth.ut index 0fe873d440..0fe873d440 100644 --- a/modules/luci-base-ucode/ucode/template/sysauth.ut +++ b/modules/luci-base/ucode/template/sysauth.ut diff --git a/modules/luci-base-ucode/ucode/template/view.ut b/modules/luci-base/ucode/template/view.ut index 11ac824290..11ac824290 100644 --- a/modules/luci-base-ucode/ucode/template/view.ut +++ b/modules/luci-base/ucode/template/view.ut diff --git a/modules/luci-base-ucode/ucode/uhttpd.uc b/modules/luci-base/ucode/uhttpd.uc index df1ecc7865..df1ecc7865 100644 --- a/modules/luci-base-ucode/ucode/uhttpd.uc +++ b/modules/luci-base/ucode/uhttpd.uc diff --git a/modules/luci-base-ucode/ucode/zoneinfo.uc b/modules/luci-base/ucode/zoneinfo.uc index c5e588dd6a..c5e588dd6a 100644 --- a/modules/luci-base-ucode/ucode/zoneinfo.uc +++ b/modules/luci-base/ucode/zoneinfo.uc diff --git a/modules/luci-compat/Makefile b/modules/luci-compat/Makefile index d73ca070a1..4b11f16419 100644 --- a/modules/luci-compat/Makefile +++ b/modules/luci-compat/Makefile @@ -12,7 +12,7 @@ LUCI_TYPE:=mod LUCI_BASENAME:=compat LUCI_TITLE:=LuCI compatibility libraries -LUCI_DEPENDS:=+luci-base +LUCI_DEPENDS:=+luci-lua-runtime include ../../luci.mk diff --git a/modules/luci-lua-runtime/Makefile b/modules/luci-lua-runtime/Makefile new file mode 100644 index 0000000000..2c6f38f08f --- /dev/null +++ b/modules/luci-lua-runtime/Makefile @@ -0,0 +1,27 @@ +# +# Copyright (C) 2022 Jo-Philipp Wich <jo@mein.io> +# +# This is free software, licensed under the Apache License, Version 2.0 . +# + +include $(TOPDIR)/rules.mk + +PKG_NAME:=luci-lua-runtime + +LUCI_TYPE:=mod +LUCI_BASENAME:=lua-runtime + +LUCI_TITLE:=LuCI Lua runtime libraries +LUCI_DEPENDS:= \ + +luci-base \ + +lua \ + +luci-lib-nixio \ + +luci-lib-ip \ + +luci-lib-jsonc \ + +libubus-lua \ + +liblucihttp-lua \ + +ucode-mod-lua + +include ../../luci.mk + +# call BuildPackage - OpenWrt buildroot signature diff --git a/modules/luci-base/luasrc/cacheloader.lua b/modules/luci-lua-runtime/luasrc/cacheloader.lua index 7ef971df8d..7ef971df8d 100644 --- a/modules/luci-base/luasrc/cacheloader.lua +++ b/modules/luci-lua-runtime/luasrc/cacheloader.lua diff --git a/modules/luci-base/luasrc/ccache.lua b/modules/luci-lua-runtime/luasrc/ccache.lua index d3be7cba6c..d3be7cba6c 100644 --- a/modules/luci-base/luasrc/ccache.lua +++ b/modules/luci-lua-runtime/luasrc/ccache.lua diff --git a/modules/luci-base/luasrc/config.lua b/modules/luci-lua-runtime/luasrc/config.lua index d01153f4f5..d01153f4f5 100644 --- a/modules/luci-base/luasrc/config.lua +++ b/modules/luci-lua-runtime/luasrc/config.lua diff --git a/modules/luci-base-ucode/luasrc/ucodebridge/luci/dispatcher.lua b/modules/luci-lua-runtime/luasrc/dispatcher.lua index 8889853b98..8889853b98 100644 --- a/modules/luci-base-ucode/luasrc/ucodebridge/luci/dispatcher.lua +++ b/modules/luci-lua-runtime/luasrc/dispatcher.lua diff --git a/modules/luci-base/luasrc/i18n.lua b/modules/luci-lua-runtime/luasrc/i18n.lua index 323912b650..323912b650 100644 --- a/modules/luci-base/luasrc/i18n.lua +++ b/modules/luci-lua-runtime/luasrc/i18n.lua diff --git a/modules/luci-base/luasrc/i18n.luadoc b/modules/luci-lua-runtime/luasrc/i18n.luadoc index b76c298565..b76c298565 100644 --- a/modules/luci-base/luasrc/i18n.luadoc +++ b/modules/luci-lua-runtime/luasrc/i18n.luadoc diff --git a/modules/luci-base/luasrc/model/uci.lua b/modules/luci-lua-runtime/luasrc/model/uci.lua index 816f6f2053..816f6f2053 100644 --- a/modules/luci-base/luasrc/model/uci.lua +++ b/modules/luci-lua-runtime/luasrc/model/uci.lua diff --git a/modules/luci-base/luasrc/model/uci.luadoc b/modules/luci-lua-runtime/luasrc/model/uci.luadoc index 0189d49aa1..0189d49aa1 100644 --- a/modules/luci-base/luasrc/model/uci.luadoc +++ b/modules/luci-lua-runtime/luasrc/model/uci.luadoc diff --git a/modules/luci-base/luasrc/sgi/cgi.lua b/modules/luci-lua-runtime/luasrc/sgi/cgi.lua index 400db4710d..400db4710d 100644 --- a/modules/luci-base/luasrc/sgi/cgi.lua +++ b/modules/luci-lua-runtime/luasrc/sgi/cgi.lua diff --git a/modules/luci-base/luasrc/sgi/uhttpd.lua b/modules/luci-lua-runtime/luasrc/sgi/uhttpd.lua index 4cd3649c62..4cd3649c62 100644 --- a/modules/luci-base/luasrc/sgi/uhttpd.lua +++ b/modules/luci-lua-runtime/luasrc/sgi/uhttpd.lua diff --git a/modules/luci-base/luasrc/store.lua b/modules/luci-lua-runtime/luasrc/store.lua index a735981137..a735981137 100644 --- a/modules/luci-base/luasrc/store.lua +++ b/modules/luci-lua-runtime/luasrc/store.lua diff --git a/modules/luci-base/luasrc/sys.lua b/modules/luci-lua-runtime/luasrc/sys.lua index e6eb762e48..e6eb762e48 100644 --- a/modules/luci-base/luasrc/sys.lua +++ b/modules/luci-lua-runtime/luasrc/sys.lua diff --git a/modules/luci-base/luasrc/sys.luadoc b/modules/luci-lua-runtime/luasrc/sys.luadoc index c1e088eb23..c1e088eb23 100644 --- a/modules/luci-base/luasrc/sys.luadoc +++ b/modules/luci-lua-runtime/luasrc/sys.luadoc diff --git a/modules/luci-base/luasrc/sys/zoneinfo.lua b/modules/luci-lua-runtime/luasrc/sys/zoneinfo.lua index aa054a246f..aa054a246f 100644 --- a/modules/luci-base/luasrc/sys/zoneinfo.lua +++ b/modules/luci-lua-runtime/luasrc/sys/zoneinfo.lua diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua b/modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzdata.lua index 3ef2f4caf4..3ef2f4caf4 100644 --- a/modules/luci-base/luasrc/sys/zoneinfo/tzdata.lua +++ b/modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzdata.lua diff --git a/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua b/modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzoffset.lua index caee1d2c1c..caee1d2c1c 100644 --- a/modules/luci-base/luasrc/sys/zoneinfo/tzoffset.lua +++ b/modules/luci-lua-runtime/luasrc/sys/zoneinfo/tzoffset.lua diff --git a/modules/luci-base-ucode/luasrc/ucodebridge/luci/template.lua b/modules/luci-lua-runtime/luasrc/template.lua index b7cc56e1cc..b7cc56e1cc 100644 --- a/modules/luci-base-ucode/luasrc/ucodebridge/luci/template.lua +++ b/modules/luci-lua-runtime/luasrc/template.lua diff --git a/modules/luci-base-ucode/luasrc/ucodebridge/luci/ucodebridge.lua b/modules/luci-lua-runtime/luasrc/ucodebridge.lua index fa4943dc99..fa4943dc99 100644 --- a/modules/luci-base-ucode/luasrc/ucodebridge/luci/ucodebridge.lua +++ b/modules/luci-lua-runtime/luasrc/ucodebridge.lua diff --git a/modules/luci-base/luasrc/version.lua b/modules/luci-lua-runtime/luasrc/version.lua index 8af2e80619..8af2e80619 100644 --- a/modules/luci-base/luasrc/version.lua +++ b/modules/luci-lua-runtime/luasrc/version.lua diff --git a/modules/luci-base/luasrc/view/empty_node_placeholder.htm b/modules/luci-lua-runtime/luasrc/view/empty_node_placeholder.htm index b7e276b960..b7e276b960 100644 --- a/modules/luci-base/luasrc/view/empty_node_placeholder.htm +++ b/modules/luci-lua-runtime/luasrc/view/empty_node_placeholder.htm diff --git a/modules/luci-base/luasrc/view/indexer.htm b/modules/luci-lua-runtime/luasrc/view/indexer.htm index 28fc3debc3..28fc3debc3 100644 --- a/modules/luci-base/luasrc/view/indexer.htm +++ b/modules/luci-lua-runtime/luasrc/view/indexer.htm diff --git a/modules/luci-base/luasrc/xml.lua b/modules/luci-lua-runtime/luasrc/xml.lua index 30b37210bd..30b37210bd 100644 --- a/modules/luci-base/luasrc/xml.lua +++ b/modules/luci-lua-runtime/luasrc/xml.lua diff --git a/modules/luci-base/luasrc/xml.luadoc b/modules/luci-lua-runtime/luasrc/xml.luadoc index 58de533966..58de533966 100644 --- a/modules/luci-base/luasrc/xml.luadoc +++ b/modules/luci-lua-runtime/luasrc/xml.luadoc diff --git a/modules/luci-lua-runtime/src/Makefile b/modules/luci-lua-runtime/src/Makefile new file mode 100644 index 0000000000..dcce33dc8c --- /dev/null +++ b/modules/luci-lua-runtime/src/Makefile @@ -0,0 +1,26 @@ +%.o: %.c + $(CC) $(CPPFLAGS) $(CFLAGS) $(FPIC) -DNDEBUG -c -o $@ $< + +contrib/lemon: contrib/lemon.c contrib/lempar.c + cc -o contrib/lemon $< + +plural_formula.c: plural_formula.y contrib/lemon + ./contrib/lemon -q $< + +template_lmo.c: plural_formula.c + +clean: + rm -f contrib/lemon parser.so plural_formula.c plural_formula.h *.o + +parser.so: template_parser.o template_utils.o template_lmo.o template_lualib.o plural_formula.o + $(CC) $(LDFLAGS) -shared -o $@ $^ + +version.lua: + ./mkversion.sh $@ $(LUCI_VERSION) "$(LUCI_GITBRANCH)" + +compile: parser.so version.lua + +install: compile + mkdir -p $(DESTDIR)/usr/lib/lua/luci/template + cp parser.so $(DESTDIR)/usr/lib/lua/luci/template/parser.so + cp version.lua $(DESTDIR)/usr/lib/lua/luci/version.lua diff --git a/modules/luci-base-ucode/src/contrib/lemon.c b/modules/luci-lua-runtime/src/contrib/lemon.c index 85e94f7007..85e94f7007 100644 --- a/modules/luci-base-ucode/src/contrib/lemon.c +++ b/modules/luci-lua-runtime/src/contrib/lemon.c diff --git a/modules/luci-base-ucode/src/contrib/lempar.c b/modules/luci-lua-runtime/src/contrib/lempar.c index a4e3c07ddb..a4e3c07ddb 100644 --- a/modules/luci-base-ucode/src/contrib/lempar.c +++ b/modules/luci-lua-runtime/src/contrib/lempar.c diff --git a/modules/luci-base/src/mkversion.sh b/modules/luci-lua-runtime/src/mkversion.sh index e2d02c1c74..e2d02c1c74 100755 --- a/modules/luci-base/src/mkversion.sh +++ b/modules/luci-lua-runtime/src/mkversion.sh diff --git a/modules/luci-base/src/plural_formula.y b/modules/luci-lua-runtime/src/plural_formula.y index 1623f8b282..1623f8b282 100644 --- a/modules/luci-base/src/plural_formula.y +++ b/modules/luci-lua-runtime/src/plural_formula.y diff --git a/modules/luci-base/src/template_lmo.c b/modules/luci-lua-runtime/src/template_lmo.c index 8634bc4bf3..8634bc4bf3 100644 --- a/modules/luci-base/src/template_lmo.c +++ b/modules/luci-lua-runtime/src/template_lmo.c diff --git a/modules/luci-base/src/template_lmo.h b/modules/luci-lua-runtime/src/template_lmo.h index d6cba7bf49..d6cba7bf49 100644 --- a/modules/luci-base/src/template_lmo.h +++ b/modules/luci-lua-runtime/src/template_lmo.h diff --git a/modules/luci-base/src/template_lualib.c b/modules/luci-lua-runtime/src/template_lualib.c index 4efd9f1de6..4efd9f1de6 100644 --- a/modules/luci-base/src/template_lualib.c +++ b/modules/luci-lua-runtime/src/template_lualib.c diff --git a/modules/luci-base/src/template_lualib.h b/modules/luci-lua-runtime/src/template_lualib.h index ff7746d158..ff7746d158 100644 --- a/modules/luci-base/src/template_lualib.h +++ b/modules/luci-lua-runtime/src/template_lualib.h diff --git a/modules/luci-base/src/template_parser.c b/modules/luci-lua-runtime/src/template_parser.c index 0ef08c63d2..0ef08c63d2 100644 --- a/modules/luci-base/src/template_parser.c +++ b/modules/luci-lua-runtime/src/template_parser.c diff --git a/modules/luci-base/src/template_parser.h b/modules/luci-lua-runtime/src/template_parser.h index 2415e87079..2415e87079 100644 --- a/modules/luci-base/src/template_parser.h +++ b/modules/luci-lua-runtime/src/template_parser.h diff --git a/modules/luci-base/src/template_utils.c b/modules/luci-lua-runtime/src/template_utils.c index 8580405e32..8580405e32 100644 --- a/modules/luci-base/src/template_utils.c +++ b/modules/luci-lua-runtime/src/template_utils.c diff --git a/modules/luci-base/src/template_utils.h b/modules/luci-lua-runtime/src/template_utils.h index 32a79f93bc..32a79f93bc 100644 --- a/modules/luci-base/src/template_utils.h +++ b/modules/luci-lua-runtime/src/template_utils.h |